diff --git a/code/nel/CMakeLists.txt b/code/nel/CMakeLists.txt index 74c8a1902..86a9236cd 100644 --- a/code/nel/CMakeLists.txt +++ b/code/nel/CMakeLists.txt @@ -10,9 +10,9 @@ IF(WIN32) FIND_PACKAGE(DirectXSDK REQUIRED) # On Win32 we can also build the MAX plugins. - IF(WITH_MAXPLUGIN) + IF(WITH_NEL_MAXPLUGIN) FIND_PACKAGE(3dsMaxSDK) - ENDIF(WITH_MAXPLUGIN) + ENDIF(WITH_NEL_MAXPLUGIN) ENDIF(WIN32) IF(WITH_3D) diff --git a/code/nel/include/nel/misc/block_memory.h b/code/nel/include/nel/misc/block_memory.h index 606ff6c32..bdcf617e7 100644 --- a/code/nel/include/nel/misc/block_memory.h +++ b/code/nel/include/nel/misc/block_memory.h @@ -174,7 +174,9 @@ public: _Mutex.enter(); if(NL3D_BlockMemoryAssertOnPurge) + { nlassert(_NAllocatedElts==0); + } while(_Blocks.begin()!=_Blocks.end()) { diff --git a/code/nel/include/nel/misc/config_file.h b/code/nel/include/nel/misc/config_file.h index 159a76f6d..248afacc8 100644 --- a/code/nel/include/nel/misc/config_file.h +++ b/code/nel/include/nel/misc/config_file.h @@ -124,7 +124,7 @@ public: { public: - CVar () : Type(T_UNKNOWN), Root(false), FromLocalFile(true), SaveWrap(6) {} + CVar () : Type(T_UNKNOWN), Root(false), Comp(false), FromLocalFile(true), SaveWrap(6) {} /// \name Access to the variable content. //@{ diff --git a/code/nel/include/nel/misc/eid_translator.h b/code/nel/include/nel/misc/eid_translator.h index 26b296ea1..695f7724e 100644 --- a/code/nel/include/nel/misc/eid_translator.h +++ b/code/nel/include/nel/misc/eid_translator.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "types_nl.h" #include "entity_id.h" diff --git a/code/nel/include/nel/misc/types_nl.h b/code/nel/include/nel/misc/types_nl.h index f2e1c0e6f..313d410b3 100644 --- a/code/nel/include/nel/misc/types_nl.h +++ b/code/nel/include/nel/misc/types_nl.h @@ -283,11 +283,11 @@ typedef uint64_t uint64; typedef int sint; // at least 32bits (depend of processor) typedef unsigned int uint; // at least 32bits (depend of processor) -#if __SIZEOF_LONG__ == 8 +#ifdef _LP64 # define NL_I64 "l" #else # define NL_I64 "ll" -#endif // __SIZEOF_LONG__ == 8 +#endif // _LP64 #endif // NL_OS_UNIX @@ -307,6 +307,8 @@ typedef unsigned int uint; // at least 32bits (depend of processor) # define CHashSet std::tr1::unordered_set # define CHashMultiMap std::tr1::unordered_multimap #elif defined(NL_COMP_VC7) || defined(NL_COMP_VC71) || defined(NL_COMP_VC8) || defined(NL_COMP_VC9) // VC7 through 9 +# include +# include # define CHashMap stdext::hash_map # define CHashSet stdext::hash_set # define CHashMultiMap stdext::hash_multimap diff --git a/code/nel/src/3d/driver/direct3d/stddirect3d.h b/code/nel/src/3d/driver/direct3d/stddirect3d.h index 77551d0f2..07bffc93e 100644 --- a/code/nel/src/3d/driver/direct3d/stddirect3d.h +++ b/code/nel/src/3d/driver/direct3d/stddirect3d.h @@ -38,6 +38,7 @@ #include #include #include +#include #ifdef NL_DEBUG diff --git a/code/nel/src/3d/driver/opengl/driver_opengl.cpp b/code/nel/src/3d/driver/opengl/driver_opengl.cpp index 39017a5b6..147420545 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl.cpp @@ -180,8 +180,6 @@ CDriverGL::CDriverGL() _PBuffer = NULL; _hRC = NULL; _hDC = NULL; - _NeedToRestaureGammaRamp = false; - _Interval = 1; #elif defined(NL_OS_MAC) @@ -192,7 +190,7 @@ CDriverGL::CDriverGL() // autorelease pool for memory management _autoreleasePool = [[NSAutoreleasePool alloc] init]; - + // init the application object [NSApplication sharedApplication]; @@ -201,7 +199,7 @@ CDriverGL::CDriverGL() // finish the application launching [NSApp finishLaunching]; - + #elif defined (NL_OS_UNIX) _cursor = None; @@ -215,6 +213,9 @@ CDriverGL::CDriverGL() #endif // NL_OS_UNIX + _NeedToRestaureGammaRamp = false; + _Interval = 1; + _win = EmptyWindow; _DestroyWindow = false; @@ -312,7 +313,6 @@ CDriverGL::CDriverGL() _VBHardProfiling= false; _CurVBHardLockCount= 0; _NumVBHardProfileFrame= 0; - _Interval = 1; _TexEnvReplace.setDefault(); _TexEnvReplace.Env.OpAlpha = CMaterial::Previous; @@ -354,14 +354,17 @@ bool CDriverGL::setupDisplay() // Driver caps. //============= // Retrieve the extensions for the current context. - NL3D::registerGlExtensions (_Extensions); + registerGlExtensions (_Extensions); vector lines; explode(_Extensions.toString(), string("\n"), lines); for(uint i = 0; i < lines.size(); i++) nlinfo("3D: %s", lines[i].c_str()); #ifdef NL_OS_WINDOWS - NL3D::registerWGlExtensions(_Extensions, _hDC); + registerWGlExtensions(_Extensions, _hDC); +#elif defined(NL_OS_MAC) +#elif defined(NL_OS_UNIX) + registerGlXExtensions(_Extensions, _dpy, DefaultScreen(_dpy)); #endif // NL_OS_WINDOWS // Check required extensions!! @@ -615,10 +618,8 @@ bool CDriverGL::setupDisplay() } } -#ifdef NL_OS_WINDOWS // Reset the vbl interval setSwapVBLInterval(_Interval); -#endif return true; } @@ -876,7 +877,7 @@ bool CDriverGL::swapBuffers() [_autoreleasePool release]; _autoreleasePool = [[NSAutoreleasePool alloc] init]; } - + [_ctx flushBuffer]; [containerView() display]; @@ -1673,12 +1674,12 @@ ATTRIB bump0TexCoord = fragment.texcoord[0]; \n\ ATTRIB bump1TexCoord = fragment.texcoord[1]; \n\ ATTRIB envMapTexCoord = fragment.texcoord[2]; \n\ OUTPUT oCol = result.color; \n\ -TEMP bmValue; \n\ +TEMP bmValue; \n\ #read bump map 0 \n\ TEX bmValue, bump0TexCoord, texture[0], 2D; \n\ #bias result (include scaling) \n\ MAD bmValue, bmValue, bump0ScaleBias.xxxx, bump0ScaleBias.yyzz; \n\ -ADD bmValue, bmValue, bump1TexCoord; \n\ +ADD bmValue, bmValue, bump1TexCoord; \n\ #read bump map 1 \n\ TEX bmValue, bmValue, texture[1], 2D; \n\ #bias result (include scaling) \n\ @@ -1701,14 +1702,14 @@ ATTRIB bump1TexCoord = fragment.texcoord[1]; \n\ ATTRIB envMapTexCoord = fragment.texcoord[2]; \n\ ATTRIB fogValue = fragment.fogcoord; \n\ OUTPUT oCol = result.color; \n\ -TEMP bmValue; \n\ +TEMP bmValue; \n\ TEMP envMap; \n\ TEMP tmpFog; \n\ #read bump map 0 \n\ TEX bmValue, bump0TexCoord, texture[0], 2D; \n\ #bias result (include scaling) \n\ MAD bmValue, bmValue, bump0ScaleBias.xxxx, bump0ScaleBias.yyzz; \n\ -ADD bmValue, bmValue, bump1TexCoord; \n\ +ADD bmValue, bmValue, bump1TexCoord; \n\ #read bump map 1 \n\ TEX bmValue, bmValue, texture[1], 2D; \n\ #bias result (include scaling) \n\ @@ -1735,14 +1736,14 @@ ATTRIB bump1TexCoord = fragment.texcoord[1]; \n\ ATTRIB envMapTexCoord = fragment.texcoord[2]; \n\ ATTRIB diffuseTexCoord = fragment.texcoord[3]; \n\ OUTPUT oCol = result.color; \n\ -TEMP bmValue; \n\ +TEMP bmValue; \n\ TEMP diffuse; \n\ TEMP envMap; \n\ #read bump map 0 \n\ TEX bmValue, bump0TexCoord, texture[0], 2D; \n\ #bias result (include scaling) \n\ MAD bmValue, bmValue, bump0ScaleBias.xxxx, bump0ScaleBias.yyzz; \n\ -ADD bmValue, bmValue, bump1TexCoord; \n\ +ADD bmValue, bmValue, bump1TexCoord; \n\ #read bump map 1 \n\ TEX bmValue, bmValue, texture[1], 2D; \n\ #bias result (include scaling) \n\ @@ -1770,7 +1771,7 @@ ATTRIB envMapTexCoord = fragment.texcoord[2]; \n\ ATTRIB diffuseTexCoord = fragment.texcoord[3]; \n\ ATTRIB fogValue = fragment.fogcoord; \n\ OUTPUT oCol = result.color; \n\ -TEMP bmValue; \n\ +TEMP bmValue; \n\ TEMP diffuse; \n\ TEMP envMap; \n\ TEMP tmpFog; \n\ @@ -1778,7 +1779,7 @@ TEMP tmpFog; \n\ TEX bmValue, bump0TexCoord, texture[0], 2D; \n\ #bias result (include scaling) \n\ MAD bmValue, bmValue, bump0ScaleBias.xxxx, bump0ScaleBias.yyzz; \n\ -ADD bmValue, bmValue, bump1TexCoord; \n\ +ADD bmValue, bmValue, bump1TexCoord; \n\ #read bump map 1 \n\ TEX bmValue, bmValue, texture[1], 2D; \n\ #bias result (include scaling) \n\ @@ -2038,29 +2039,70 @@ void CDriverGL::flush() void CDriverGL::setSwapVBLInterval(uint interval) { H_AUTO_OGL(CDriverGL_setSwapVBLInterval) + + if (!_Initialized) + return; + + bool res = true; + #ifdef NL_OS_WINDOWS - _Interval = interval; - if(_Extensions.WGLEXTSwapControl && _Initialized) + if(_Extensions.WGLEXTSwapControl) { - nwglSwapIntervalEXT(_Interval); + res = nwglSwapIntervalEXT(_Interval) == TRUE; + } +#elif defined(NL_OS_MAC) +#elif defined(NL_OS_UNIX) + if (_win && _Extensions.GLXEXTSwapControl) + { + res = nglXSwapIntervalEXT(_dpy, _win, interval) == 0; + } + else if (_Extensions.GLXSGISwapControl) + { + res = nglXSwapIntervalSGI(interval) == 0; + } + else if (_Extensions.GLXMESASwapControl) + { + res = nglXSwapIntervalMESA(interval) == 0; } #endif + + if (res) + { + _Interval = interval; + } + else + { + nlwarning("Could not set swap interval"); + } } // *************************************************************************** uint CDriverGL::getSwapVBLInterval() { H_AUTO_OGL(CDriverGL_getSwapVBLInterval) + #ifdef NL_OS_WINDOWS if(_Extensions.WGLEXTSwapControl) { - return _Interval; + return nwglGetSwapIntervalEXT(); + } +#elif defined(NL_OS_MAC) +#elif defined(NL_OS_UNIX) + if (_win && _Extensions.GLXEXTSwapControl) + { + uint swap, maxSwap; + glXQueryDrawable(_dpy, _win, GLX_SWAP_INTERVAL_EXT, &swap); + glXQueryDrawable(_dpy, _win, GLX_MAX_SWAP_INTERVAL_EXT, &maxSwap); + nlwarning("The swap interval is %u and the max swap interval is %u", swap, maxSwap); + return swap; + } + else if (_Extensions.GLXMESASwapControl) + { + return nglXGetSwapIntervalMESA(); } - else - return 1; -#else - return 1; #endif + + return _Interval; } // *************************************************************************** @@ -2419,10 +2461,10 @@ void CDriverGL::displayBench (class NLMISC::CLog *log) } #ifdef NL_DEBUG - void CDriverGL::dumpMappedBuffers() - { - _AGPVertexArrayRange->dumpMappedBuffers(); - } +void CDriverGL::dumpMappedBuffers() +{ + _AGPVertexArrayRange->dumpMappedBuffers(); +} #endif // *************************************************************************** diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_extension.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_extension.cpp index 3c775a9a2..191d438cf 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_extension.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_extension.cpp @@ -440,6 +440,18 @@ PFNWGLGETSWAPINTERVALEXTPROC nwglGetSwapIntervalEXT; // WGL_ARB_extensions_string PFNWGLGETEXTENSIONSSTRINGARBPROC nwglGetExtensionsStringARB; + +#elif defined(NL_OS_MAC) +#elif defined(NL_OS_UNIX) + +// Swap control extensions +PFNGLXSWAPINTERVALEXTPROC nglXSwapIntervalEXT; + +PFNGLXSWAPINTERVALSGIPROC nglXSwapIntervalSGI; + +PFNGLXSWAPINTERVALMESAPROC nglXSwapIntervalMESA; +PFNGLXGETSWAPINTERVALMESAPROC nglXGetSwapIntervalMESA; + #endif // *************************************************************************** @@ -1410,6 +1422,46 @@ static bool setupWGLEXTSwapControl(const char *glext) return true; } +// ********************************* +static bool setupGLXEXTSwapControl(const char *glext) +{ + H_AUTO_OGL(setupGLXEXTSwapControl); + CHECK_EXT("GLX_EXT_swap_control"); + +#ifdef NL_OS_UNIX + CHECK_ADDRESS(PFNGLXSWAPINTERVALEXTPROC, glXSwapIntervalEXT); +#endif + + return true; +} + +// ********************************* +static bool setupGLXSGISwapControl(const char *glext) +{ + H_AUTO_OGL(setupGLXSGISwapControl); + CHECK_EXT("GLX_SGI_swap_control"); + +#ifdef NL_OS_UNIX + CHECK_ADDRESS(PFNGLXSWAPINTERVALSGIPROC, glXSwapIntervalSGI); +#endif + + return true; +} + +// ********************************* +static bool setupGLXMESASwapControl(const char *glext) +{ + H_AUTO_OGL(setupGLXMESASwapControl); + CHECK_EXT("GLX_MESA_swap_control"); + +#ifdef NL_OS_UNIX + CHECK_ADDRESS(PFNGLXSWAPINTERVALMESAPROC, glXSwapIntervalMESA); + CHECK_ADDRESS(PFNGLXGETSWAPINTERVALMESAPROC, glXGetSwapIntervalMESA); +#endif + + return true; +} + #ifdef NL_OS_WINDOWS // *************************************************************************** bool registerWGlExtensions(CGlExtensions &ext, HDC hDC) @@ -1452,6 +1504,49 @@ bool registerWGlExtensions(CGlExtensions &ext, HDC hDC) return true; } +#elif defined(NL_OS_MAC) +#elif defined(NL_OS_UNIX) +// *************************************************************************** +bool registerGlXExtensions(CGlExtensions &ext, Display *dpy, sint screen) +{ + H_AUTO_OGL(registerGlXExtensions); + + // Get extension string + const char *glext = glXQueryExtensionsString(dpy, screen); + if (glext == NULL) + { + nlwarning ("glXQueryExtensionsString failed"); + return false; + } + + nldebug("3D: Available GLX Extensions:"); + + if (DebugLog) + { + vector exts; + explode(string(glext), string(" "), exts); + for(uint i = 0; i < exts.size(); i++) + { + if(i%5==0) DebugLog->displayRaw("3D: "); + DebugLog->displayRaw(string(exts[i]+" ").c_str()); + if(i%5==4) DebugLog->displayRaw("\n"); + } + DebugLog->displayRaw("\n"); + } + + // Check for pbuffer +// ext.WGLARBPBuffer= setupWGLARBPBuffer(glext); + + // Check for pixel format +// ext.WGLARBPixelFormat= setupWGLARBPixelFormat(glext); + + // Check for swap control + ext.GLXEXTSwapControl= setupGLXEXTSwapControl(glext); + ext.GLXSGISwapControl= setupGLXSGISwapControl(glext); + ext.GLXMESASwapControl= setupGLXMESASwapControl(glext); + + return true; +} #endif // NL_OS_WINDOWS } diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_extension.h b/code/nel/src/3d/driver/opengl/driver_opengl_extension.h index a4d71ec08..43fb3bc08 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_extension.h +++ b/code/nel/src/3d/driver/opengl/driver_opengl_extension.h @@ -35,6 +35,7 @@ # include # include // Please download it from http://www.opengl.org/registry/ # include +# include #endif // NL_OS_UNIX #ifndef GL_GLEXT_VERSION @@ -94,6 +95,11 @@ struct CGlExtensions bool WGLARBPixelFormat; bool WGLEXTSwapControl; + // GLX extensions, true if supported + bool GLXEXTSwapControl; + bool GLXSGISwapControl; + bool GLXMESASwapControl; + // ATI Extensions. bool ATIVertexArrayObject; bool ATIMapObjectBuffer; @@ -148,6 +154,9 @@ public: WGLARBPBuffer= false; WGLARBPixelFormat= false; WGLEXTSwapControl= false; + GLXEXTSwapControl= false; + GLXSGISwapControl= false; + GLXMESASwapControl= false; EXTBlendColor= false; ATIVertexArrayObject= false; ATIEnvMapBumpMap = false; @@ -226,6 +235,11 @@ public: result += WGLARBPBuffer ? "WGLARBPBuffer " : ""; result += WGLARBPixelFormat ? "WGLARBPixelFormat " : ""; result += WGLEXTSwapControl ? "WGLEXTSwapControl " : ""; +#elif defined(NL_OS_MAC) +#elif defined(NL_OS_UNIX) + result += GLXEXTSwapControl ? "GLXEXTSwapControl " : ""; + result += GLXSGISwapControl ? "GLXSGISwapControl " : ""; + result += GLXMESASwapControl ? "GLXMESASwapControl " : ""; #endif result += "\n Array/VBO: "; @@ -250,6 +264,10 @@ public: #ifdef NL_OS_WINDOWS /// This function will test and register WGL functions before than the gl context is created bool registerWGlExtensions(CGlExtensions &ext, HDC hDC); +#elif defined(NL_OS_MAC) +#elif defined(NL_OS_UNIX) +/// This function will test and register GLX functions before than the gl context is created +bool registerGlXExtensions(CGlExtensions &ext, Display *dpy, sint screen); #endif // NL_OS_WINDOWS /// This function test and register the extensions for the current GL context. @@ -675,6 +693,18 @@ extern PFNWGLGETSWAPINTERVALEXTPROC nwglGetSwapIntervalEXT; // WGL_ARB_extensions_string extern PFNWGLGETEXTENSIONSSTRINGARBPROC nwglGetExtensionsStringARB; +#elif defined(NL_OS_MAC) +#elif defined(NL_OS_UNIX) + +// Swap control extensions +//=========================== +extern PFNGLXSWAPINTERVALEXTPROC nglXSwapIntervalEXT; + +extern PFNGLXSWAPINTERVALSGIPROC nglXSwapIntervalSGI; + +extern PFNGLXSWAPINTERVALMESAPROC nglXSwapIntervalMESA; +extern PFNGLXGETSWAPINTERVALMESAPROC nglXGetSwapIntervalMESA; + #endif // GL_EXT_framebuffer_object diff --git a/code/nel/src/3d/driver/opengl/unix_event_emitter.cpp b/code/nel/src/3d/driver/opengl/unix_event_emitter.cpp index 19b76923e..4ceb88116 100644 --- a/code/nel/src/3d/driver/opengl/unix_event_emitter.cpp +++ b/code/nel/src/3d/driver/opengl/unix_event_emitter.cpp @@ -22,8 +22,7 @@ #include #include #include -#include -#include +#include #include "nel/misc/debug.h" @@ -568,7 +567,7 @@ bool CUnixEventEmitter::processMessage (XEvent &event, CEventServer *server) ucstring ucstr; ucstr.fromUtf8(Text); - CEventChar *charEvent = new CEventChar (ucstr[0], noKeyButton, this); + CEventChar *charEvent = new CEventChar (ucstr[0], getKeyButton(event.xbutton.state), this); // raw if not processed by IME charEvent->setRaw(keyCode != 0); @@ -577,7 +576,7 @@ bool CUnixEventEmitter::processMessage (XEvent &event, CEventServer *server) #else for (int i = 0; i < c; i++) { - CEventChar *charEvent = new CEventChar ((ucchar)(unsigned char)Text[i], noKeyButton, this); + CEventChar *charEvent = new CEventChar ((ucchar)(unsigned char)Text[i], getKeyButton(event.xbutton.state), this); // raw if not processed by IME charEvent->setRaw(keyCode != 0); diff --git a/code/nel/src/3d/driver/opengl/unix_event_emitter.h b/code/nel/src/3d/driver/opengl/unix_event_emitter.h index 1a17ecd1f..b42f45fb4 100644 --- a/code/nel/src/3d/driver/opengl/unix_event_emitter.h +++ b/code/nel/src/3d/driver/opengl/unix_event_emitter.h @@ -24,8 +24,7 @@ #if defined(NL_OS_UNIX) && !defined(NL_OS_MAC) -#include -#include +#include namespace NLMISC { diff --git a/code/nel/src/misc/debug.cpp b/code/nel/src/misc/debug.cpp index 72a5b5a8f..9284217d6 100644 --- a/code/nel/src/misc/debug.cpp +++ b/code/nel/src/misc/debug.cpp @@ -1147,11 +1147,9 @@ void destroyDebug() void createDebug (const char *logPath, bool logInFile, bool eraseLastLog) { - // Do some basic compiler time check on type size nlctassert(sizeof(char) == 1); - // static bool alreadyCreateSharedAmongThreads = false; // if ( !alreadyCreateSharedAmongThreads ) if (!INelContext::getInstance().getAlreadyCreateSharedAmongThreads()) diff --git a/code/nel/src/misc/path.cpp b/code/nel/src/misc/path.cpp index 80911027b..dfc8e6381 100644 --- a/code/nel/src/misc/path.cpp +++ b/code/nel/src/misc/path.cpp @@ -1727,16 +1727,22 @@ std::string CFileContainer::getTemporaryDirectory() static std::string path; if (path.empty()) { - char *tempDir = getenv("TEMP"); + const char *temp = getenv("TEMP"); + const char *tmp = getenv("TMP"); - if (tempDir == NULL) - tempDir = getenv("TMP"); + std::string tempDir; + + if (temp) + tempDir = temp; + + if (tempDir.empty() && tmp) + tempDir = tmp; #ifdef NL_OS_UNIX - if (tempDir == NULL) + if (tempDir.empty()) tempDir = "/tmp"; #else - if (tempDir == NULL) + if (tempDir.empty()) tempDir = "."; #endif diff --git a/code/nel/src/sound/driver/dsound/CMakeLists.txt b/code/nel/src/sound/driver/dsound/CMakeLists.txt index aeef35c8b..f2d13d785 100644 --- a/code/nel/src/sound/driver/dsound/CMakeLists.txt +++ b/code/nel/src/sound/driver/dsound/CMakeLists.txt @@ -1,19 +1,19 @@ -FILE(GLOB SRC *.cpp *.h) +FILE(GLOB SRC *.cpp *.h *.def) -NL_TARGET_DRIVER(nel_drv_dsound ${SRC}) +NL_TARGET_DRIVER(nel_drv_dsound_win ${SRC}) INCLUDE_DIRECTORIES(${DXSDK_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(nel_drv_dsound nelmisc nelsnd_lowlevel ${DXSDK_DSOUND_LIBRARY} ${DXSDK_GUID_LIBRARY}) +TARGET_LINK_LIBRARIES(nel_drv_dsound_win nelmisc nelsnd_lowlevel ${DXSDK_DSOUND_LIBRARY} ${DXSDK_GUID_LIBRARY}) -NL_DEFAULT_PROPS(nel_drv_dsound "NeL, Driver, Sound: DirectSound") -NL_ADD_RUNTIME_FLAGS(nel_drv_dsound) -NL_ADD_LIB_SUFFIX(nel_drv_dsound) +NL_DEFAULT_PROPS(nel_drv_dsound_win "NeL, Driver, Sound: DirectSound") +NL_ADD_RUNTIME_FLAGS(nel_drv_dsound_win) +NL_ADD_LIB_SUFFIX(nel_drv_dsound_win) IF(WITH_PCH) - ADD_NATIVE_PRECOMPILED_HEADER(nel_drv_dsound ${CMAKE_CURRENT_SOURCE_DIR}/stddsound.h ${CMAKE_CURRENT_SOURCE_DIR}/stddsound.cpp) + ADD_NATIVE_PRECOMPILED_HEADER(nel_drv_dsound_win ${CMAKE_CURRENT_SOURCE_DIR}/stddsound.h ${CMAKE_CURRENT_SOURCE_DIR}/stddsound.cpp) ENDIF(WITH_PCH) -INSTALL(TARGETS nel_drv_dsound RUNTIME DESTINATION bin LIBRARY DESTINATION ${NL_DRIVER_PREFIX} ARCHIVE DESTINATION lib COMPONENT driverssound) +INSTALL(TARGETS nel_drv_dsound_win RUNTIME DESTINATION bin LIBRARY DESTINATION ${NL_DRIVER_PREFIX} ARCHIVE DESTINATION lib COMPONENT driverssound) IF(WITH_MAXPLUGIN) - INSTALL(TARGETS nel_drv_dsound RUNTIME DESTINATION maxplugin COMPONENT driverssound) + INSTALL(TARGETS nel_drv_dsound_win RUNTIME DESTINATION maxplugin COMPONENT driverssound) ENDIF(WITH_MAXPLUGIN) diff --git a/code/nel/src/sound/driver/fmod/CMakeLists.txt b/code/nel/src/sound/driver/fmod/CMakeLists.txt index 616b62300..049d8b627 100644 --- a/code/nel/src/sound/driver/fmod/CMakeLists.txt +++ b/code/nel/src/sound/driver/fmod/CMakeLists.txt @@ -1,19 +1,19 @@ -FILE(GLOB SRC *.cpp *.h) +FILE(GLOB SRC *.cpp *.h *.def) -NL_TARGET_DRIVER(nel_drv_fmod ${SRC}) +NL_TARGET_DRIVER(nel_drv_fmod_win ${SRC}) INCLUDE_DIRECTORIES(${FMOD_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(nel_drv_fmod ${FMOD_LIBRARY} nelmisc nelsnd_lowlevel) +TARGET_LINK_LIBRARIES(nel_drv_fmod_win ${FMOD_LIBRARY} nelmisc nelsnd_lowlevel) -NL_DEFAULT_PROPS(nel_drv_fmod "NeL, Driver, Sound: FMOD") -NL_ADD_RUNTIME_FLAGS(nel_drv_fmod) -NL_ADD_LIB_SUFFIX(nel_drv_fmod) +NL_DEFAULT_PROPS(nel_drv_fmod_win "NeL, Driver, Sound: FMOD") +NL_ADD_RUNTIME_FLAGS(nel_drv_fmod_win) +NL_ADD_LIB_SUFFIX(nel_drv_fmod_win) IF(WITH_PCH) - ADD_NATIVE_PRECOMPILED_HEADER(nel_drv_fmod ${CMAKE_CURRENT_SOURCE_DIR}/stdfmod.h ${CMAKE_CURRENT_SOURCE_DIR}/stdfmod.cpp) + ADD_NATIVE_PRECOMPILED_HEADER(nel_drv_fmod_win ${CMAKE_CURRENT_SOURCE_DIR}/stdfmod.h ${CMAKE_CURRENT_SOURCE_DIR}/stdfmod.cpp) ENDIF(WITH_PCH) -INSTALL(TARGETS nel_drv_fmod RUNTIME DESTINATION bin LIBRARY DESTINATION ${NL_DRIVER_PREFIX} ARCHIVE DESTINATION lib COMPONENT driverssound) +INSTALL(TARGETS nel_drv_fmod_win RUNTIME DESTINATION bin LIBRARY DESTINATION ${NL_DRIVER_PREFIX} ARCHIVE DESTINATION lib COMPONENT driverssound) IF(WITH_MAXPLUGIN) - INSTALL(TARGETS nel_drv_fmod RUNTIME DESTINATION maxplugin COMPONENT driverssound) + INSTALL(TARGETS nel_drv_fmod_win RUNTIME DESTINATION maxplugin COMPONENT driverssound) ENDIF(WITH_MAXPLUGIN) diff --git a/code/nel/src/sound/driver/openal/CMakeLists.txt b/code/nel/src/sound/driver/openal/CMakeLists.txt index 626a5cf07..cfdad7910 100644 --- a/code/nel/src/sound/driver/openal/CMakeLists.txt +++ b/code/nel/src/sound/driver/openal/CMakeLists.txt @@ -1,4 +1,10 @@ -FILE(GLOB SRC *.cpp *.h) +FILE(GLOB SRC *.cpp *.h *.def) + +IF(WIN32) + SET(NLDRV_AL_LIB "nel_drv_openal_win") +ELSE(WIN32) + SET(NLDRV_AL_LIB "nel_drv_openal") +ENDIF(WIN32) SOURCE_GROUP(efx FILES effect_al.cpp @@ -18,31 +24,31 @@ SOURCE_GROUP(util FILES ext_al.cpp ext_al.h) -NL_TARGET_DRIVER(nel_drv_openal ${SRC}) +NL_TARGET_DRIVER(${NLDRV_AL_LIB} ${SRC}) INCLUDE_DIRECTORIES(${OPENAL_INCLUDE_DIR}) IF(WITH_STLPORT) - TARGET_LINK_LIBRARIES(nel_drv_openal ${CMAKE_THREAD_LIBS_INIT}) + TARGET_LINK_LIBRARIES(${NLDRV_AL_LIB} ${CMAKE_THREAD_LIBS_INIT}) ENDIF(WITH_STLPORT) -TARGET_LINK_LIBRARIES(nel_drv_openal ${OPENAL_LIBRARY} nelmisc nelsnd_lowlevel) -NL_DEFAULT_PROPS(nel_drv_openal "NeL, Driver, Sound: OpenAL") -NL_ADD_RUNTIME_FLAGS(nel_drv_openal) -NL_ADD_LIB_SUFFIX(nel_drv_openal) +TARGET_LINK_LIBRARIES(${NLDRV_AL_LIB} ${OPENAL_LIBRARY} nelmisc nelsnd_lowlevel) +NL_DEFAULT_PROPS(${NLDRV_AL_LIB} "NeL, Driver, Sound: OpenAL") +NL_ADD_RUNTIME_FLAGS(${NLDRV_AL_LIB}) +NL_ADD_LIB_SUFFIX(${NLDRV_AL_LIB}) IF(WIN32) # Find and include EFX-Util on Windows. FIND_PACKAGE(EFXUtil) INCLUDE_DIRECTORIES(${EFXUTIL_INCLUDE_DIR}) - TARGET_LINK_LIBRARIES(nel_drv_openal ${EFXUTIL_LIBRARY}) + TARGET_LINK_LIBRARIES(${NLDRV_AL_LIB} ${EFXUTIL_LIBRARY}) ENDIF(WIN32) IF(WITH_PCH) - ADD_NATIVE_PRECOMPILED_HEADER(nel_drv_openal ${CMAKE_CURRENT_SOURCE_DIR}/stdopenal.h ${CMAKE_CURRENT_SOURCE_DIR}/stdopenal.cpp) + ADD_NATIVE_PRECOMPILED_HEADER(${NLDRV_AL_LIB} ${CMAKE_CURRENT_SOURCE_DIR}/stdopenal.h ${CMAKE_CURRENT_SOURCE_DIR}/stdopenal.cpp) ENDIF(WITH_PCH) -INSTALL(TARGETS nel_drv_openal RUNTIME DESTINATION bin LIBRARY DESTINATION ${NL_DRIVER_PREFIX} ARCHIVE DESTINATION lib COMPONENT driverssound) +INSTALL(TARGETS ${NLDRV_AL_LIB} RUNTIME DESTINATION bin LIBRARY DESTINATION ${NL_DRIVER_PREFIX} ARCHIVE DESTINATION lib COMPONENT driverssound) IF(WITH_MAXPLUGIN) - INSTALL(TARGETS nel_drv_openal RUNTIME DESTINATION maxplugin COMPONENT driverssound) + INSTALL(TARGETS ${NLDRV_AL_LIB} RUNTIME DESTINATION maxplugin COMPONENT driverssound) ENDIF(WITH_MAXPLUGIN) diff --git a/code/nel/src/sound/driver/xaudio2/CMakeLists.txt b/code/nel/src/sound/driver/xaudio2/CMakeLists.txt index 431d336dd..5e45a9809 100644 --- a/code/nel/src/sound/driver/xaudio2/CMakeLists.txt +++ b/code/nel/src/sound/driver/xaudio2/CMakeLists.txt @@ -1,4 +1,4 @@ -FILE(GLOB SRC *.cpp *.h) +FILE(GLOB SRC *.cpp *.h *.def) SOURCE_GROUP(sfx FILES buffer_xaudio2.cpp @@ -26,21 +26,21 @@ SOURCE_GROUP(efx FILES effect_xaudio2.cpp effect_xaudio2.h) -NL_TARGET_DRIVER(nel_drv_xaudio2 ${SRC}) +NL_TARGET_DRIVER(nel_drv_xaudio2_win ${SRC}) INCLUDE_DIRECTORIES(${DXSDK_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(nel_drv_xaudio2 nelmisc nelsnd_lowlevel ${DXSDK_XAUDIO_LIBRARY} ${DXSDK_GUID_LIBRARY}) +TARGET_LINK_LIBRARIES(nel_drv_xaudio2_win nelmisc nelsnd_lowlevel ${DXSDK_XAUDIO_LIBRARY} ${DXSDK_GUID_LIBRARY}) -NL_DEFAULT_PROPS(nel_drv_xaudio2 "NeL, Driver, Sound: XAudio2") -NL_ADD_RUNTIME_FLAGS(nel_drv_xaudio2) -NL_ADD_LIB_SUFFIX(nel_drv_xaudio2) +NL_DEFAULT_PROPS(nel_drv_xaudio2_win "NeL, Driver, Sound: XAudio2") +NL_ADD_RUNTIME_FLAGS(nel_drv_xaudio2_win) +NL_ADD_LIB_SUFFIX(nel_drv_xaudio2_win) IF(WITH_PCH) - ADD_NATIVE_PRECOMPILED_HEADER(nel_drv_xaudio2 ${CMAKE_CURRENT_SOURCE_DIR}/stdxaudio2.h ${CMAKE_CURRENT_SOURCE_DIR}/stdxaudio2.cpp) + ADD_NATIVE_PRECOMPILED_HEADER(nel_drv_xaudio2_win ${CMAKE_CURRENT_SOURCE_DIR}/stdxaudio2.h ${CMAKE_CURRENT_SOURCE_DIR}/stdxaudio2.cpp) ENDIF(WITH_PCH) -INSTALL(TARGETS nel_drv_xaudio2 RUNTIME DESTINATION bin LIBRARY DESTINATION ${NL_DRIVER_PREFIX} ARCHIVE DESTINATION lib COMPONENT driverssound) +INSTALL(TARGETS nel_drv_xaudio2_win RUNTIME DESTINATION bin LIBRARY DESTINATION ${NL_DRIVER_PREFIX} ARCHIVE DESTINATION lib COMPONENT driverssound) IF(WITH_MAXPLUGIN) - INSTALL(TARGETS nel_drv_xaudio2 RUNTIME DESTINATION maxplugin COMPONENT driverssound) + INSTALL(TARGETS nel_drv_xaudio2_win RUNTIME DESTINATION maxplugin COMPONENT driverssound) ENDIF(WITH_MAXPLUGIN) diff --git a/code/nel/tools/3d/CMakeLists.txt b/code/nel/tools/3d/CMakeLists.txt index 412ef130c..bc21ae69f 100644 --- a/code/nel/tools/3d/CMakeLists.txt +++ b/code/nel/tools/3d/CMakeLists.txt @@ -35,17 +35,18 @@ IF(WIN32) ADD_SUBDIRECTORY(tile_edit) ENDIF(MFC_FOUND) - IF(WITH_MAXPLUGIN) + IF(WITH_NEL_MAXPLUGIN) IF(MAXSDK_FOUND) ADD_SUBDIRECTORY(plugin_max) ADD_SUBDIRECTORY(ligo) ENDIF(MAXSDK_FOUND) - ENDIF(WITH_MAXPLUGIN) + ENDIF(WITH_NEL_MAXPLUGIN) ENDIF(WIN32) IF(WITH_QT) ADD_SUBDIRECTORY(tile_edit_qt) + ADD_SUBDIRECTORY(object_viewer_qt) ENDIF(WITH_QT) IF(SQUISH_FOUND) diff --git a/code/nel/tools/3d/build_interface/main.cpp b/code/nel/tools/3d/build_interface/main.cpp index ae317269b..2e6452f39 100644 --- a/code/nel/tools/3d/build_interface/main.cpp +++ b/code/nel/tools/3d/build_interface/main.cpp @@ -161,7 +161,7 @@ bool putIn (NLMISC::CBitmap *pSrc, NLMISC::CBitmap *pDst, sint32 x, sint32 y, bo // *************************************************************************** string getBaseName (const string &fullname) { - string sTmp2 = ""; + string sTmp2; string::size_type pos = fullname.rfind('_'); if (pos != string::npos) sTmp2 = fullname.substr(0, pos+1); diff --git a/code/nel/tools/3d/cluster_viewer/view_cs.cpp b/code/nel/tools/3d/cluster_viewer/view_cs.cpp index 8db2208fb..bed6a7518 100644 --- a/code/nel/tools/3d/cluster_viewer/view_cs.cpp +++ b/code/nel/tools/3d/cluster_viewer/view_cs.cpp @@ -346,7 +346,7 @@ int main(int argc, char **argv) TextContext.setColor (CRGBA(255,255,255,255)); - string sAllClusters = ""; + string sAllClusters; for( uint32 j = 0; j < vCluster.size(); ++j) { sAllClusters += vCluster[j]->Name; diff --git a/code/nel/tools/3d/lightmap_optimizer/main.cpp b/code/nel/tools/3d/lightmap_optimizer/main.cpp index a2dd5602a..528d85014 100644 --- a/code/nel/tools/3d/lightmap_optimizer/main.cpp +++ b/code/nel/tools/3d/lightmap_optimizer/main.cpp @@ -171,7 +171,7 @@ bool putIn (NLMISC::CBitmap *pSrc, NLMISC::CBitmap *pDst, sint32 x, sint32 y) // --------------------------------------------------------------------------- string getBaseName (const string &fullname) { - string sTmp2 = ""; + string sTmp2; string::size_type pos = fullname.rfind('_'); if (pos != string::npos) sTmp2 = fullname.substr(0, pos+1); diff --git a/code/nel/tools/3d/object_viewer_qt/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/CMakeLists.txt new file mode 100644 index 000000000..9341954ab --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/CMakeLists.txt @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# +# Object Viewer Qt +# Copyright (C) 2010 Dzmitry Kamiahin +# +#----------------------------------------------------------------------------- + +# This tells the application(s) where to fidn the installed data. +ADD_DEFINITIONS(-DDATA_DIR="\\"${NL_SHARE_PREFIX}/object_viewer_qt/\\"") + +ADD_SUBDIRECTORY(src) + +INSTALL(DIRECTORY data/ + DESTINATION share/object_viewer_qt/data + COMPONENT data + PATTERN "CVS" EXCLUDE + PATTERN ".svn" EXCLUDE + PATTERN "Makefile*" EXCLUDE) + diff --git a/code/nel/tools/3d/object_viewer_qt/COPYING b/code/nel/tools/3d/object_viewer_qt/COPYING new file mode 100644 index 000000000..69ec4c052 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/COPYING @@ -0,0 +1 @@ +Put your license here! \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/README b/code/nel/tools/3d/object_viewer_qt/README new file mode 100644 index 000000000..7a4a570a1 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/README @@ -0,0 +1 @@ +Talk about how to use Hello World or who wrote it, that sort of stuff. \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/data/andbasr.ttf b/code/nel/tools/3d/object_viewer_qt/data/andbasr.ttf new file mode 100644 index 000000000..d785cc9df Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/data/andbasr.ttf differ diff --git a/code/nel/tools/3d/object_viewer_qt/data/object_viewer.cfg b/code/nel/tools/3d/object_viewer_qt/data/object_viewer.cfg new file mode 100644 index 000000000..ae0c72e4b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/data/object_viewer.cfg @@ -0,0 +1,29 @@ +RootConfigFilename = "object_viewer_default.cfg"; +SearchPaths = { + "/mnt/disk_d/NEL3D/texture", "/mnt/disk_d/NEL3D/SFX/maps", "/mnt/disk_d/NEL3D/Database_proto/Stuff/fyros/agent/actors/_textures" +}; +GraphicsEnabled = 1; +SoundEnabled = 1; +GraphicsDriver = "OpenGL"; +SoundDriver = "OpenAL"; +SoundDevice = ""; +LanguageCode = "en"; +QtStyle = ""; +FontName = "andbasr.ttf"; +FontShadow = 1; +BackgroundColor = { + 98, 98, 98 +}; +FogStart = 0.0000000000; +FogEnd = 10.0000000000; +FogColor = { + 88, 88, 88 +}; +SoundAutoLoadSample = 1; +SoundMaxTrack = 48; +SoundEnableOccludeObstruct = 1; +SoundEnableReverb = 1; +SoundManualRolloff = 1; +SoundUseADPCM = 0; +SoundForceSoftware = 0; +CameraFocal = 75.0000000000; diff --git a/code/nel/tools/3d/object_viewer_qt/data/object_viewer_default.cfg b/code/nel/tools/3d/object_viewer_qt/data/object_viewer_default.cfg new file mode 100644 index 000000000..350001aeb --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/data/object_viewer_default.cfg @@ -0,0 +1,156 @@ +////////////////////////////////////////////////////////////////////////////// +// Config file for Object Viewer Qt //////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// +// This file is used to setup the Object Viewer tool. +// + + +////////////////////////////////////////////////////////////////////////////// +// NeL Qt //////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// Root directory where we can find the client datas (zones, tiles, maps, ...) +// You must uncomment this line on GNU/Linux and comment the next one +//SearchPaths = { "/usr/local/share/games/nel_qt/" }; +SearchPaths = { "data" }; + +// Which extensions to remap to what if needed (pairs of 2) +RemapExtensions = { "png", "tga", "dds", "tga"}; + + +// The language code of the client +LanguageCode = "en"; + +// If changes to the config should be saved on exit +SaveConfig = 1; + + +////////////////////////////////////////////////////////////////////////////// +// Qt //////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +QtStyle = "Cleanlooks"; +QtPalette = 0; +QtWindowState = ""; +QtWindowGeometry = ""; + +////////////////////////////////////////////////////////////////////////////// +// Graphics ////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// Use OpenGL or Direct3D (Windows) +GraphicsEnabled = 1; +GraphicsDrivers = { "OpenGL", "Direct3D" }; +GraphicsDriver = "OpenGL"; + +// Resolution of the screen +// ScreenWidth = 1360; +// ScreenHeight = 768; +// ScreenDepth = 32; + +// If 1, run in fullscreen mode, 0 for windowed +// Fullscreen = 0; + +// Font name used for all text in the client (it can be a .ttf, .fon, .pfb) +FontName = "andbasr.ttf"; +FontShadow = 1; + +// Background color +BackgroundColor = { 151, 156, 182 }; + +// Bloom effect +BloomEffect = 1; +BloomSquare = 1; +BloomDensity = 120; + +// Path where screenshots are saved +ScreenshotName = "nel_qt"; +ScreenshotJPG = 1; +ScreenshotPNG = 1; +ScreenshotTGA = 0; +ScreenshotPath = "screenshots"; + + +////////////////////////////////////////////////////////////////////////////// +// Environment /////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +CameraFocal = 75.0; + +SunDirection = { -2.935, +0.107, -1.22 }; +SunAmbient = { 190, 170, 150 }; +SunDiffuse = { 255, 248, 255 }; +SunSpecular = { 255, 255, 255}; + +// 1 if you want to see the fog +FogEnable = 1; +FogStart = 100.0; // in meter +FogEnd = 250.0; // in meter +FogColor = { 129, 136, 205 }; // { 147, 125, 114 }; + +///////////////////////////////////////////////////////////// +//// Vegetable Landscape Setup (for vegetable edition) ////// +///////////////////////////////////////////////////////////// + +VegetTileBank = ""; // this is optional, but obligatory for Vegetable Edit to work properly +VegetTileFarBank = ""; // this is optional, but obligatory for Vegetable Edit to work properly +VegetLandscapeZones = // this is optional, but obligatory for Vegetable Edit to work properly +{ +"WARNING: Delete this string" // NOT DELETE +}; + +VegetLandscapeThreshold = 0.01; // this is optional +VegetLandscapeTileNear = 50.0; // this is optional +VegetLandscapeAmbient = {17, 54, 100, 255} ; // this is optional +VegetLandscapeDiffuse = {241, 226, 244, 255} ; // this is optional +VegetLandscapeSnapHeight = 1.70; // this is optional +VegetLandscapeMultiply = 1.5; + +// veget setup +VegetTexture = ""; // this is optional, but important for Vegetable Edit to behave properly +VegetAmbient = {80, 80, 80}; // this is optional +VegetDiffuse = {255, 255, 255}; // this is optional. NB: works like veget_landscape_diffuse (ie maxLightFactor possible) +VegetLightDir = {0.0, 1.0, -1.0}; // this is optional +VegetWindDir = {1.0, 1.0, 0.0}; // this is optional +VegetWindFreq = 0.5; // this is optional +VegetWindPower = 5.0; // this is optional +VegetWindBendMin = 0.5; // this is optional + +////////////////////////////////////////////////////////////////////////////// +// Time ////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +FpsSmoothing = 64; + + +////////////////////////////////////////////////////////////////////////////// +// Sound ///////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// The sound driver, choose between "Auto", "FMod", "DSound" and "OpenAl" +SoundEnabled = 1; +SoundDrivers = { "Auto", "OpenAL", "XAudio2", "FMod", "DSound" }; +SoundDriver = "OpenAL"; +SoundDevice = ""; +SoundMaxTrack = 48; +SoundEnableOccludeObstruct = 1; +SoundEnableReverb = 1; +SoundManualRolloff = 1; +SoundUseADPCM = 0; +SoundForceSoftware = 0; +SoundAutoLoadSample = 1; + +SoundPackedSheetPath = "/home/timon/sound"; +SoundSamplePath = "/home/timon/sound"; + +////////////////////////////////////////////////////////////////////////////// +// Interface ///////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// Debug HUD ///////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// end of file diff --git a/code/nel/tools/3d/object_viewer_qt/doc/html/cdirection_widget.png b/code/nel/tools/3d/object_viewer_qt/doc/html/cdirection_widget.png new file mode 100644 index 000000000..fb8afb297 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/doc/html/cdirection_widget.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/doc/html/cedit_color_widget.png b/code/nel/tools/3d/object_viewer_qt/doc/html/cedit_color_widget.png new file mode 100644 index 000000000..b0e14e569 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/doc/html/cedit_color_widget.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/doc/html/cedit_range_float_widget.png b/code/nel/tools/3d/object_viewer_qt/doc/html/cedit_range_float_widget.png new file mode 100644 index 000000000..3c612633e Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/doc/html/cedit_range_float_widget.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/doc/html/cedit_range_int_widget.png b/code/nel/tools/3d/object_viewer_qt/doc/html/cedit_range_int_widget.png new file mode 100644 index 000000000..26495f969 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/doc/html/cedit_range_int_widget.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/doc/html/gui_struct.png b/code/nel/tools/3d/object_viewer_qt/doc/html/gui_struct.png new file mode 100644 index 000000000..61a85602a Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/doc/html/gui_struct.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/doc/html/object_viewer_qt_window.png b/code/nel/tools/3d/object_viewer_qt/doc/html/object_viewer_qt_window.png new file mode 100644 index 000000000..ecde73d0d Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/doc/html/object_viewer_qt_window.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/doc/make_ovqt_dox.bat b/code/nel/tools/3d/object_viewer_qt/doc/make_ovqt_dox.bat new file mode 100644 index 000000000..5b2ee7a03 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/doc/make_ovqt_dox.bat @@ -0,0 +1,11 @@ +@echo off + +del html\ovqt\*.* /Q +set WORKDIR=%CD% + +cd .. +set CURDIR=%CD% +cd %WORKDIR% +doxygen ovqt.dox -DCURDIR + +pause diff --git a/code/nel/tools/3d/object_viewer_qt/doc/make_ovqt_dox.sh b/code/nel/tools/3d/object_viewer_qt/doc/make_ovqt_dox.sh new file mode 100644 index 000000000..d39c1a548 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/doc/make_ovqt_dox.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +rm -rf html/ovqt +WORKDIR=$(pwd) + +cd .. +export CURDIR=$(pwd) +cd $WORKDIR +doxygen ovqt.dox -DCURDIR diff --git a/code/nel/tools/3d/object_viewer_qt/doc/ovqt.dox b/code/nel/tools/3d/object_viewer_qt/doc/ovqt.dox new file mode 100644 index 000000000..e15e37e5a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/doc/ovqt.dox @@ -0,0 +1,1600 @@ +# Doxyfile 1.6.3 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "Object Viewer Qt" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = r90 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. Note that for custom extensions you also need to set +# FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = YES + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/code/nel/tools/3d/object_viewer_qt/src/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/src/CMakeLists.txt new file mode 100644 index 000000000..107f52775 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/CMakeLists.txt @@ -0,0 +1,63 @@ +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${LIBXML2_INCLUDE_DIR} ${NEL_INCLUDE_DIR} ${QT_INCLUDES}) +INCLUDE( ${QT_USE_FILE} ) + +FILE(GLOB OBJECT_VIEWER_SRC configuration.h entity.h object_viewer.h particle_editor.h modules.h sound_system.h + particle_node.h ps_initial_pos.h dup_ps.h vegetable_editor.h vegetable_node.h *.cpp) +SET(OBJECT_VIEWER_HDR main_window.h graphics_viewport.h animation_dialog.h + animation_set_dialog.h settings_dialog.h setup_fog_dialog.h + slot_manager_dialog.h particle_control_dialog.h particle_workspace_dialog.h + particle_tree_model.h particle_system_page.h particle_workspace_page.h edit_range_widget.h + emitter_page.h attrib_widget.h located_bindable_page.h located_page.h + particle_force_page.h particle_light_page.h particle_zone_page.h particle_sound_page.h + basic_edit_widget.h direction_widget.h color_edit_widget.h particle_property_dialog.h + ps_mover_page.h graphics_info_widget.h value_blender_dialog.h value_gradient_dialog.h + value_from_emitter_dialog.h curve_dialog.h bin_op_dialog.h hoverpoints.h + mesh_widget.h morph_mesh_dialog.h constraint_mesh_widget.h tail_particle_widget.h + auto_lod_dialog.h particle_texture_widget.h particle_texture_anim_widget.h + multi_tex_dialog.h spinner_dialog.h follow_path_dialog.h water_pool_dialog.h + skeleton_scale_dialog.h skeleton_tree_model.h particle_link_skeleton_dialog.h + vegetable_dialog.h global_wind_dialog.h day_night_dialog.h sun_color_dialog.h + vegetable_noise_value_widget.h vegetable_density_page.h vegetable_landscape_page.h + vegetable_scale_page.h vegetable_appearance_page.h vegetable_rotate_page.h) +SET(OBJECT_VIEWER_UIS animation_form.ui animation_set_form.ui settings_form.ui + setup_fog_form.ui slot_form.ui particle_control_form.ui particle_workspace_form.ui + edit_range_float_form.ui edit_range_uint_form.ui particle_system_form.ui workspace_form.ui + attrib_form.ui emitter_form.ui located_bindable_form.ui located_form.ui + particle_force_form.ui particle_light_form.ui particle_zone_form.ui particle_sound_form.ui + basic_edit_form.ui direction_form.ui color_edit_form.ui ps_mover_form.ui curve_form.ui + mesh_form.ui morph_mesh_form.ui constraint_mesh_form.ui tail_form.ui auto_lod_form.ui + particle_texture_form.ui particle_texture_anim_form.ui multi_tex_form.ui skeleton_scale_form.ui + particle_link_skeleton_form.ui water_pool_form.ui vegetable_dialog_form.ui + vegetable_noise_value_form.ui global_wind_form.ui sun_color_form.ui day_night_form.ui + vegetable_density_form.ui vegetable_apperance_form.ui vegetable_landscape_form.ui + vegetable_rotate_form.ui vegetable_scale_form.ui) +SET(OBJECT_VIEWER_RCS object_viewer_qt.qrc) + +SET(QT_USE_QTGUI TRUE) +SET(QT_USE_QTOPENGL TRUE) + +QT4_ADD_RESOURCES( OBJECT_VIEWER_RC_SRCS ${OBJECT_VIEWER_RCS} ) +QT4_WRAP_CPP( OBJECT_VIEWER_MOC_SRCS ${OBJECT_VIEWER_HDR} ) +QT4_WRAP_UI( OBJECT_VIEWER_UI_HDRS ${OBJECT_VIEWER_UIS} ) + +ADD_EXECUTABLE(object_viewer_qt WIN32 ${OBJECT_VIEWER_SRC} ${OBJECT_VIEWER_MOC_SRCS} ${OBJECT_VIEWER_RC_SRCS} ${OBJECT_VIEWER_UI_HDRS}) + +TARGET_LINK_LIBRARIES(object_viewer_qt + nelmisc + nel3d + nelsound + nelligo + nelgeorges + ${QT_LIBRARIES} + ${QT_QTOPENGL_LIBRARY} + ${QT_QTMAIN_LIBRARY}) + +ADD_DEFINITIONS(-DQT_NO_KEYWORDS ${LIBXML2_DEFINITIONS} ${QT_DEFINITIONS}) +NL_DEFAULT_PROPS(object_viewer_qt "NeL, Tools, 3D: Object Viewer Qt") +NL_ADD_RUNTIME_FLAGS(object_viewer_qt) + +IF(WITH_PCH) + ADD_NATIVE_PRECOMPILED_HEADER(object_viewer_qt ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.h ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.cpp) +ENDIF(WITH_PCH) + +INSTALL(TARGETS object_viewer_qt RUNTIME DESTINATION bin COMPONENT runtime) diff --git a/code/nel/tools/3d/object_viewer_qt/src/animation_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/animation_dialog.cpp new file mode 100644 index 000000000..238af812c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/animation_dialog.cpp @@ -0,0 +1,190 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "animation_dialog.h" + +// Qt includes + +// NeL includes + +// Project includes +#include "modules.h" + +using namespace NLMISC; + +namespace NLQT { + +CAnimationDialog::CAnimationDialog(QWidget *parent) + : QDockWidget(parent) +{ + _ui.setupUi(this); + + //setFixedHeight(sizeHint().height()); + + connect(_ui.startPushButton, SIGNAL(clicked()), this, SLOT(start())); + connect(_ui.playPushButton, SIGNAL(clicked()), this, SLOT(play())); + connect(_ui.stopPushButton, SIGNAL(clicked()), this, SLOT(stop())); + connect(_ui.endPushButton, SIGNAL(clicked()), this, SLOT(end())); + connect(_ui.horizontalSlider, SIGNAL(sliderMoved(int)), this, SLOT(changeFrame(int))); + connect(_ui.startSpinBox, SIGNAL(valueChanged(int)), this, SLOT(changeStartAnim(int))); + connect(_ui.endSpinBox, SIGNAL(valueChanged(int)), this, SLOT(changeEndAnim(int))); + + // init QTimeLine + _timeLine = new QTimeLine(_ui.endSpinBox->value() * _frameRate, this); + _timeLine->setCurveShape(QTimeLine::LinearCurve); + _timeLine->setUpdateInterval(25); + _timeLine->setFrameRange(_ui.startSpinBox->value(), _ui.endSpinBox->value()); + + connect(_timeLine, SIGNAL(frameChanged(int)), this, SLOT(updateAnim(int))); + connect(_timeLine, SIGNAL(finished()), this, SLOT(finish())); + + connect(_ui.incPosCheckBox, SIGNAL(toggled(bool)), this, SLOT(setIncPos(bool))); + connect(_ui.inPlaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(setInPlace(bool))); + + // sync horizontalSlider with a timeLine + _ui.endSpinBox->setValue(99); +} + +CAnimationDialog::~CAnimationDialog() +{ +} + +NL3D::TAnimationTime CAnimationDialog::getTime () +{ + return float(_timeLine->currentFrame()) / _frameRate; +} + +void CAnimationDialog::changeAnimLength() +{ + std::string curObj = Modules::objView().getCurrentObject(); + if (curObj.empty()) + return; + CEntity &entity = Modules::objView().getEntity(curObj); + float animLength = entity.getPlayListLength(); + + _ui.startSpinBox->setValue(0); + _ui.endSpinBox->setValue(int(animLength * _frameRate)); +} + +void CAnimationDialog::setCurrentShape(const QString &name) +{ + if (name.isEmpty()) + return; + CEntity &entity = Modules::objView().getEntity(name.toStdString()); + + _ui.inPlaceCheckBox->setChecked(entity.getInPlace()); + _ui.incPosCheckBox->setChecked(entity.getIncPos()); +} + +void CAnimationDialog::start() +{ + _timeLine->setCurrentTime((float(_ui.startSpinBox->value()) / _frameRate) * 1000); +} + +void CAnimationDialog::play() +{ + std::string curObj = Modules::objView().getCurrentObject(); + if (curObj.empty()) + { + _ui.playPushButton->setChecked(false); + return; + } + CEntity &entity = Modules::objView().getEntity(curObj); + entity.playbackAnim(true); + + if (_timeLine->state() == QTimeLine::Running) + _timeLine->setPaused(true); + else if (_timeLine->currentFrame() == _timeLine->endFrame()) _timeLine->start(); + else + _timeLine->resume(); +} + +void CAnimationDialog::stop() +{ + _timeLine->stop(); + _timeLine->setCurrentTime(0); + _ui.playPushButton->setChecked(false); + + std::string curObj = Modules::objView().getCurrentObject(); + if (curObj.empty()) + return; + CEntity &entity = Modules::objView().getEntity(curObj); + entity.playbackAnim(false); +} + +void CAnimationDialog::end() +{ + _timeLine->setCurrentTime((float(_ui.endSpinBox->value()) / _frameRate) * 1000); +} + +void CAnimationDialog::changeFrame(int frame) +{ + if (_timeLine->state() == QTimeLine::Running) + { + _timeLine->setPaused(true); + _timeLine->setCurrentTime((float(frame) / _frameRate) * 1000); + _timeLine->resume(); + } + else _timeLine->setCurrentTime((float(frame) / _frameRate) * 1000); +} + +void CAnimationDialog::changeStartAnim(int start) +{ + _timeLine->setDuration((float(start - _ui.startSpinBox->value()) / _frameRate) * 1000); + _timeLine->setFrameRange(start, _ui.endSpinBox->value()); +} + +void CAnimationDialog::changeEndAnim(int end) +{ + _ui.horizontalSlider->setMaximum(end); + _timeLine->setDuration((float(end - _ui.startSpinBox->value()) / _frameRate) * 1000); + _timeLine->setFrameRange(_ui.startSpinBox->value(), end); +} + +void CAnimationDialog::updateAnim(int frame) +{ + _ui.horizontalSlider->setSliderPosition(frame); +} + +void CAnimationDialog::setInPlace(bool state) +{ + std::string curObj = Modules::objView().getCurrentObject(); + if (curObj.empty()) + return; + CEntity &entity = Modules::objView().getEntity(curObj); + entity.setInPlace(state); +} + +void CAnimationDialog::setIncPos(bool state) +{ + std::string curObj = Modules::objView().getCurrentObject(); + if (curObj.empty()) + return; + CEntity &entity = Modules::objView().getEntity(curObj); + entity.setIncPos(state); +} + +void CAnimationDialog::finish() +{ + if (_ui.loopCheckBox->checkState() == Qt::Checked) play(); + else _ui.playPushButton->setChecked(false); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/animation_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/animation_dialog.h new file mode 100644 index 000000000..e042a2122 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/animation_dialog.h @@ -0,0 +1,91 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef ANIMATION_DIALOG_H +#define ANIMATION_DIALOG_H + +#include +#include "ui_animation_form.h" + +// Qt includes +#include + +// STL includes + +// NeL includes +#include "nel/3d/animation_time.h" + +// Project includes + +namespace NLQT { + +/** +@class CAnimationDialog +@brief Animation model control dialog. +@details The dialogue doesn't affect on the model itself, but only calculates the current time of animations +that can be obtained through a class method getTime(). +The user can influence on the duration of the animation, but he doesn't know the total time for all the animations in the playlist. +Therefore, the class provides a slot that requires a total duration of the animated object animations and set it. +*/ +class CAnimationDialog: public QDockWidget +{ + Q_OBJECT + +public: + /// Constructor, sets the default length of time from 0 to 99 + CAnimationDialog(QWidget *parent = 0); + ~CAnimationDialog(); + + /// Get the current time animations + /// @return Returns the current time animations, which can then be use in class CObjectViewer + NL3D::TAnimationTime getTime (); + +public Q_SLOTS: + /// Find the total time of the playlist and sets its + void changeAnimLength(); + + /// Updates animation status for the selected current object + /// @param name - the name of the selected object + void setCurrentShape(const QString &name); + +private Q_SLOTS: + void start(); + void play(); + void stop(); + void end(); + void changeFrame(int frame); + void changeStartAnim(int start); + void changeEndAnim(int end); + void updateAnim(int frame); + void setInPlace(bool state); + void setIncPos(bool state); + void finish(); + +private: + + static const int _frameRate = 50; + QTimeLine *_timeLine; + Ui::CAnimationDialog _ui; + + friend class CMainWindow; +}; /* CAnimationDialog */ + +} /* namespace NLQT */ + +#endif // ANIMATION_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/animation_form.ui b/code/nel/tools/3d/object_viewer_qt/src/animation_form.ui new file mode 100644 index 000000000..aceb1eaec --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/animation_form.ui @@ -0,0 +1,392 @@ + + + CAnimationDialog + + + + 0 + 0 + 519 + 98 + + + + + 0 + 0 + + + + + 519 + 98 + + + + + 524287 + 524287 + + + + false + + + QDockWidget::AllDockWidgetFeatures + + + Qt::AllDockWidgetAreas + + + Animation + + + + + + + + + 99 + + + 10 + + + Qt::Horizontal + + + false + + + false + + + QSlider::TicksBelow + + + 10 + + + + + + + true + + + QAbstractSpinBox::NoButtons + + + 999999 + + + + + + + + + 0 + + + QLayout::SetMaximumSize + + + 0 + + + + + QAbstractSpinBox::UpDownArrows + + + false + + + 999999 + + + + + + + Loop + + + + + + + true + + + In place + + + + + + + true + + + Increment pos + + + + + + + false + + + 999999 + + + 100 + + + + + + + + + + 25 + 25 + + + + + 25 + 25 + + + + + + + + :/images/skip-backward.png:/images/skip-backward.png + + + + 28 + 28 + + + + true + + + + + + + + 25 + 25 + + + + + 25 + 25 + + + + + + + + :/images/seek-backward.png:/images/seek-backward.png + + + + 28 + 28 + + + + true + + + + + + + + 25 + 25 + + + + + 25 + 25 + + + + + + + + :/images/play.png + :/images/pause.png:/images/play.png + + + + 28 + 28 + + + + true + + + true + + + + + + + + 25 + 25 + + + + + 25 + 25 + + + + + + + + :/images/stop.png:/images/stop.png + + + + 28 + 28 + + + + false + + + true + + + + + + + + 25 + 25 + + + + + 25 + 25 + + + + + + + + :/images/seek-forward.png:/images/seek-forward.png + + + + 28 + 28 + + + + true + + + + + + + + 25 + 25 + + + + + 25 + 25 + + + + + + + + :/images/skip-forward.png:/images/skip-forward.png + + + + 28 + 28 + + + + true + + + + + + + + + + + + currentSpinBox + valueChanged(int) + horizontalSlider + setValue(int) + + + 151 + 55 + + + 163 + 77 + + + + + horizontalSlider + valueChanged(int) + currentSpinBox + setValue(int) + + + 224 + 85 + + + 141 + 55 + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/animation_set_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/animation_set_dialog.cpp new file mode 100644 index 000000000..5ac9c8f3a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/animation_set_dialog.cpp @@ -0,0 +1,293 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "animation_set_dialog.h" + +// Qt includes +#include + +// NeL includes + +// Project includes +#include "modules.h" +#include "entity.h" + +namespace NLQT { + +CAnimationSetDialog::CAnimationSetDialog(QWidget *parent) + : QDockWidget(parent) +{ + ui.setupUi(this); + + connect(ui.addToolButton, SIGNAL(clicked()), this, SLOT(addAnim())); + connect(ui.removeToolButton, SIGNAL(clicked()), this, SLOT(removeAnim())); + connect(ui.upToolButton, SIGNAL(clicked()), this, SLOT(upAnim())); + connect(ui.downToolButton, SIGNAL(clicked()), this, SLOT(downAnim())); + connect(ui.addAnimPushButton, SIGNAL(clicked()), this, SLOT(loadAnim())); + connect(ui.addSwtPushButton, SIGNAL(clicked()), this, SLOT(loadSwt())); + connect(ui.resetPushButton, SIGNAL(clicked()), this, SLOT(resetAnim())); + + connect(ui.listRadioButton, SIGNAL(clicked(bool)), this, SLOT(setModeAnim())); + connect(ui.mixerRadioButton, SIGNAL(clicked(bool)), this, SLOT(setModeAnim())); + + connect(ui.objectsComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(setCurrentShape(QString))); +} + +CAnimationSetDialog::~CAnimationSetDialog() +{ +} + +void CAnimationSetDialog::setCurrentShape(const QString &name) +{ + if (name.isEmpty()) + return; + + Modules::objView().setCurrentObject(name.toStdString()); + + updateListAnim(); + + Q_EMIT changeCurrentShape(name); + +} + +void CAnimationSetDialog::setModeAnim() +{ + std::string curObj = Modules::objView().getCurrentObject(); + if (curObj.empty()) + return; + CEntity &entity = Modules::objView().getEntity(curObj); + + if (ui.mixerRadioButton->isChecked()) + entity.setMode(CEntity::Mode::Mixer); + else + entity.setMode(CEntity::Mode::PlayList); +} + +void CAnimationSetDialog::updateListObject() +{ + ui.objectsComboBox->clear(); + + std::vector listObjects; + Modules::objView().getListObjects(listObjects); + + for (size_t i = 0; i < listObjects.size(); i++) + ui.objectsComboBox->addItem(QString(listObjects[i].c_str())); + + if (listObjects.empty()) + { + ui.addAnimPushButton->setEnabled(false); + ui.addSwtPushButton->setEnabled(false); + ui.resetPushButton->setEnabled(false); + ui.setLengthPushButton->setEnabled(false); + } + else + { + ui.addAnimPushButton->setEnabled(true); + ui.addSwtPushButton->setEnabled(true); + ui.resetPushButton->setEnabled(true); + ui.setLengthPushButton->setEnabled(true); + } +} + +void CAnimationSetDialog::updateListAnim() +{ + ui.animTreeWidget->clear(); + ui.animPlaylistWidget->clear(); + ui.skeletonTreeWidget->clear(); + + std::string curObj = Modules::objView().getCurrentObject(); + if (curObj.empty()) + return; + CEntity &entity = Modules::objView().getEntity(curObj); + + std::vector& animationList = entity.getAnimationList(); + std::vector& swtList = entity.getSWTList(); + std::vector& playListAnimation = entity.getPlayListAnimation(); + + // update animation list widget + for(size_t i = 0; i < animationList.size(); ++i) + { + QTreeWidgetItem *item = new QTreeWidgetItem(ui.animTreeWidget); + item->setText(0,QString(animationList[i].c_str())); + } + + // update skeleton weight template list widget + for(size_t i = 0; i < swtList.size(); ++i) + { + QTreeWidgetItem *item = new QTreeWidgetItem(ui.skeletonTreeWidget); + item->setText(0,QString(swtList[i].c_str())); + } + + // update PlayList animation widget + for(size_t i = 0; i < playListAnimation.size(); ++i) + { + QListWidgetItem *item = new QListWidgetItem(ui.animPlaylistWidget); + item->setText(QString(playListAnimation[i].c_str())); + } + + if (animationList.empty()) + { + // lock buttons + ui.addToolButton->setEnabled(false); + ui.removeToolButton->setEnabled(false); + ui.upToolButton->setEnabled(false); + ui.downToolButton->setEnabled(false); + } + else + { + // unlock buttons + ui.addToolButton->setEnabled(true); + ui.removeToolButton->setEnabled(true); + ui.upToolButton->setEnabled(true); + ui.downToolButton->setEnabled(true); + } +} + +void CAnimationSetDialog::loadAnim() +{ + CEntity &entity = Modules::objView().getEntity(Modules::objView().getCurrentObject()); + + QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Open NeL anim file"), ".", + tr("NeL anim files (*.anim);;")); + + setCursor(Qt::WaitCursor); + + if (!fileNames.isEmpty()) + { + QStringList list = fileNames; + QStringList::Iterator it = list.begin(); + while(it != list.end()) + { + std::string animName = it->toStdString(); + entity.loadAnimation(animName); + ++it; + } + updateListAnim(); + } + + setCursor(Qt::ArrowCursor); +} + +void CAnimationSetDialog::loadSwt() +{ + CEntity &entity = Modules::objView().getEntity(Modules::objView().getCurrentObject()); + + QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Open NeL anim file"), ".", + tr("NeL Skeleton Weight Template files (*.swt);;")); + + setCursor(Qt::WaitCursor); + + if (!fileNames.isEmpty()) + { + QStringList list = fileNames; + QStringList::Iterator it = list.begin(); + while(it != list.end()) + { + std::string swtName = it->toStdString(); + entity.loadSWT(swtName); + ++it; + } + updateListAnim(); + } + + setCursor(Qt::ArrowCursor); +} + +void CAnimationSetDialog::resetAnim() +{ + CEntity &entity = Modules::objView().getEntity(Modules::objView().getCurrentObject()); + entity.reset(); + + updateListAnim(); +} + +void CAnimationSetDialog::addAnim() +{ + CEntity &entity = Modules::objView().getEntity(Modules::objView().getCurrentObject()); + QList list = ui.animTreeWidget->selectedItems(); + + Q_FOREACH(QTreeWidgetItem* item, list) + { + std::string animName = item->text(0).toStdString(); + entity.addAnimToPlayList(animName); + ui.animPlaylistWidget->addItem(item->text(0)); + } +} + +void CAnimationSetDialog::removeAnim() +{ + CEntity &entity = Modules::objView().getEntity(Modules::objView().getCurrentObject()); + QList list = ui.animPlaylistWidget->selectedItems(); + + Q_FOREACH(QListWidgetItem* item, list) + { + int row = ui.animPlaylistWidget->row(item); + QListWidgetItem *removeItem = ui.animPlaylistWidget->takeItem(row); + if (!removeItem) + delete removeItem; + entity.removeAnimToPlayList(row); + } +} + +void CAnimationSetDialog::upAnim() +{ + CEntity &entity = Modules::objView().getEntity(Modules::objView().getCurrentObject()); + QList list = ui.animPlaylistWidget->selectedItems(); + + if (list.empty()) + return; + + int frontRow = ui.animPlaylistWidget->row(list.front()); + int backRow = ui.animPlaylistWidget->row(list.back()); + + if (frontRow == 0) + return; + + QListWidgetItem *item = ui.animPlaylistWidget->takeItem(frontRow - 1); + ui.animPlaylistWidget->insertItem(backRow, item); + + for (int i = frontRow; i <= backRow; ++i) + entity.swapAnimToPlayList(i - 1, i); +} + +void CAnimationSetDialog::downAnim() +{ + CEntity &entity = Modules::objView().getEntity(Modules::objView().getCurrentObject()); + QList list = ui.animPlaylistWidget->selectedItems(); + + if (list.empty()) + return; + + int frontRow = ui.animPlaylistWidget->row(list.front()); + int backRow = ui.animPlaylistWidget->row(list.back()); + + if (backRow == (ui.animPlaylistWidget->count() - 1)) + return; + + QListWidgetItem *item = ui.animPlaylistWidget->takeItem(backRow + 1); + ui.animPlaylistWidget->insertItem(frontRow, item); + + for (int i = backRow; i >= frontRow; --i) + entity.swapAnimToPlayList(i, i + 1); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/animation_set_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/animation_set_dialog.h new file mode 100644 index 000000000..5fb85c5ff --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/animation_set_dialog.h @@ -0,0 +1,86 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef ANIMATION_SET_DIALOG_H +#define ANIMATION_SET_DIALOG_H + +#include "ui_animation_set_form.h" + +// STL includes + +// NeL includes + +// Project includes + +namespace NLQT { + /** +@class CAnimationSetDialog +@brief Dialog - Animations control, loading animation, weight for skeleton and playlist composition. +@details Dialog loads animations files and weight for skeleton animation. Files can also be unloaded. +For loading / unloading and animation control dialog uses the functionality of CEntity class. +But the main opportunity for dialogue is to generating animations playlists. +Also, the dialogue has a control element to select the current shape (emit a signal changeCurrentShape()) +and switch of playlist/mixer (this functionality will soon be transferred to another specialized dialogue). +As each shape has its own list of loaded animations and playlist,when you switch your current shape, +the dialogue should be notified through the slot setCurrentShape (). + */ +class CAnimationSetDialog: public QDockWidget +{ + Q_OBJECT + +public: + CAnimationSetDialog(QWidget *parent = 0); + ~CAnimationSetDialog(); + + /// Update the objects list (this function should be moved to another dialogue) + void updateListObject(); + + /// Update the list of loaded animation files + void updateListAnim(); + +Q_SIGNALS: + /// Signal emitted when changing the current animation object. + void changeCurrentShape(const QString &name); + +public Q_SLOTS: + + /// Updates and displays the list of loaded animations and playlist for the selected current object + /// @param name - the name of the selected object + void setCurrentShape(const QString &name); + +private Q_SLOTS: + void setModeAnim(); + void loadAnim(); + void loadSwt(); + void resetAnim(); + void addAnim(); + void removeAnim(); + void upAnim(); + void downAnim(); + +private: + + Ui::CAnimationSetDialog ui; + + friend class CMainWindow; +}; /* CAnimationDialog */ + +} /* namespace NLQT */ + +#endif // ANIMATION_SET_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/animation_set_form.ui b/code/nel/tools/3d/object_viewer_qt/src/animation_set_form.ui new file mode 100644 index 000000000..9d1a03380 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/animation_set_form.ui @@ -0,0 +1,480 @@ + + + CAnimationSetDialog + + + + 0 + 0 + 300 + 562 + + + + + 0 + 0 + + + + + 300 + 390 + + + + + :/images/animset.png:/images/animset.png + + + Animation set manager + + + + + 0 + 0 + + + + + 100 + 0 + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + Edited object: + + + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + Qt::Vertical + + + + + + + Animations: + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + false + + + QAbstractItemView::NoDragDrop + + + QAbstractItemView::ExtendedSelection + + + 1 + + + false + + + false + + + + 1 + + + + + + + + + + + + Skeleton weight template: + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + + 16777215 + 5646546 + + + + false + + + false + + + + 1 + + + + + + + + + + + + + Animations playlist: + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + false + + + QAbstractItemView::NoDragDrop + + + Qt::IgnoreAction + + + QAbstractItemView::ContiguousSelection + + + + + + + false + + + ... + + + + :/images/list-add.png:/images/list-add.png + + + + 20 + 20 + + + + + + + + false + + + ... + + + + :/images/list-remove.png:/images/list-remove.png + + + + 20 + 20 + + + + + + + + false + + + ... + + + + :/images/go-up.png:/images/go-up.png + + + + 20 + 20 + + + + + + + + false + + + ... + + + + :/images/go-down.png:/images/go-down.png + + + + 20 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + false + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Add anim + + + + + + + false + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Add swt + + + + + + + false + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Reset + + + + + + + false + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Set anim length + + + + + + + + + + + Use the list + + + true + + + + + + + true + + + Use the mixer + + + + + + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/attrib_form.ui b/code/nel/tools/3d/object_viewer_qt/src/attrib_form.ui new file mode 100644 index 000000000..3a3778109 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/attrib_form.ui @@ -0,0 +1,291 @@ + + + CAttribWidget + + + + 0 + 0 + 276 + 273 + + + + GroupBox + + + + + + + + + + Constant + + + + + Scheme + + + + + + + schemeWidget + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + + + + Input mutliplier: + + + + + + + Qt::Horizontal + + + + 108 + 20 + + + + + + + + false + + + Clamp + + + + + + + false + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 1 + + + + + + + + true + + + + + + + + + + 30 + 16777215 + + + + E + + + + + + + + + Src: + + + + + + + + 0 + 0 + + + + + Date + + + + + Position + + + + + Inverse Mass + + + + + Speed + + + + + Random + + + + + User param + + + + + LOD + + + + + Square LOD + + + + + Clamped LOD + + + + + Camped square LOD + + + + + + + + + + false + + + + 30 + 16777215 + + + + U + + + + + + + false + + + + 30 + 16777215 + + + + P + + + + + + + false + + + + 30 + 16777215 + + + + G + + + + + + + + + + + NLQT::CEditRangeUIntWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CBasicEditWidget + QWidget +
basic_edit_widget.h
+ 1 +
+ + NLQT::CColorEditWidget + QWidget +
color_edit_widget.h
+ 1 +
+ + NLQT::CEditRangeIntWidget + QWidget +
edit_range_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/attrib_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/attrib_widget.cpp new file mode 100644 index 000000000..bd8d6c7c0 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/attrib_widget.cpp @@ -0,0 +1,972 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "attrib_widget.h" + +// Qt includes +#include + +// NeL includes +#include +#include +#include +#include +#include +#include + +// Projects includes +#include "value_blender_dialog.h" +#include "value_gradient_dialog.h" +#include "bin_op_dialog.h" +#include "curve_dialog.h" +#include "value_from_emitter_dialog.h" +#include "spinner_dialog.h" +#include "follow_path_dialog.h" + +namespace NLQT { + +CAttribWidget::CAttribWidget(QWidget *parent) + : QGroupBox(parent), + _SrcInputEnabled(true), + _EnableConstantValue(true), + _DisableMemoryScheme(false), + _NbCycleEnabled(true), + _Node(NULL), _SchemeWidget(NULL) +{ + _ui.setupUi(this); + _ui.constRangeUIntWidget->hide(); + _ui.constRangeFloatWidget->hide(); + _ui.constAttribPlaneWidget->hide(); + _ui.constRangeIntWidget->hide(); + _ui.constRGBAWidget->hide(); + _ui.schemeWidget->hide(); + + _ui.inMultiplierWidget->setRange(0.1f, 10.1f); + _ui.inMultiplierWidget->enableLowerBound(0, true);; + _ui.inMultiplierWidget->setWrapper(&_NbCyclesWrapper); + _NbCyclesWrapper.widget = this; +} + +CAttribWidget::~CAttribWidget() +{ +} + +void CAttribWidget::setEnabledConstantValue(bool enableConstantValue) +{ + _EnableConstantValue = enableConstantValue; +} + +void CAttribWidget::init() +{ + connect(_ui.editPushButton, SIGNAL(clicked()), this, SLOT(clickedEdit())); + connect(_ui.clampCheckBox, SIGNAL(toggled(bool)), this, SLOT(setClamp(bool))); + connect(_ui.schemeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeCurrentScheme(int))); + connect(_ui.srcComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentSrc(int))); + connect(_ui.userParamPushButton, SIGNAL(clicked()), this, SLOT(setUserIndex())); + connect(_ui.comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeUseScheme(int))); +} + +void CAttribWidget::updateUi() +{ + if (!_EnableConstantValue) + _ui.comboBox->hide(); + else + _ui.comboBox->show(); + + if (useScheme()) + { + if (_ui.comboBox->currentIndex() == 1) + schemeValueUpdate(); + else + _ui.comboBox->setCurrentIndex(1); + } + else + { + + nlassert(_EnableConstantValue); + if (_ui.comboBox->currentIndex() == 0) + cstValueUpdate(); + else + _ui.comboBox->setCurrentIndex(0); + } +} + +void CAttribWidget::clickedEdit() +{ + QDialog *dialog = editScheme(); + if (dialog != NULL) + { + dialog->setModal(true); + dialog->show(); + dialog->exec(); + delete dialog; + } +} + +void CAttribWidget::setClamp(bool state) +{ + // avoid performance warning + if (state != isSchemeClamped()) + clampScheme(state); +} + +void CAttribWidget::changeCurrentScheme(int index) +{ + if (getCurrentScheme() != index) + setCurrentScheme(uint(index)); + schemeValueUpdate(); +} + +void CAttribWidget::setCurrentSrc(int index) +{ + NL3D::CPSInputType it; + it.InputType = (NL3D::CPSInputType::TInputType) index; + if (it.InputType != getSchemeInput().InputType) + { + if (it.InputType == NL3D::CPSInputType::attrUserParam) + { + it.UserParamNum = 0; + } + setSchemeInput(it); + } + inputValueUpdate(); +} + +void CAttribWidget::setUserIndex() +{ + bool ok; + int i = QInputDialog::getInt(this, tr("Set user param"), tr(""), getSchemeInput().UserParamNum + 1, 1, 4, 1, &ok); + if (ok) + { + NL3D::CPSInputType it = getSchemeInput(); + it.UserParamNum = i - 1; + setSchemeInput(it); + } + inputValueUpdate(); +} + +void CAttribWidget::changeUseScheme(int index) +{ + if (index == 0) + { + if (!useScheme()) + resetCstValue(); // change constant + cstValueUpdate(); // update ui + } + else + { + if (useScheme()) + changeCurrentScheme(getCurrentScheme()); // update ui + else + changeCurrentScheme(0); // change scheme + } +} + +void CAttribWidget::inputValueUpdate(void) +{ + if (useScheme() && getSchemeInput().InputType == NL3D::CPSInputType::attrUserParam) + { + //_ui.userParamPushButton->setText(tr("User param: %1").arg(getSchemeInput().UserParamNum + 1)); + _ui.userParamPushButton->setEnabled(true); + } + else + { + //_ui.userParamPushButton->setText(tr("User param:")); + _ui.userParamPushButton->setEnabled(false); + } +} + +void CAttribWidget::schemeValueUpdate() +{ + if (!useScheme()) return; + + _ui.constRangeUIntWidget->hide(); + _ui.constRangeFloatWidget->hide(); + _ui.constAttribPlaneWidget->hide(); + _ui.constRangeIntWidget->hide(); + _ui.constRGBAWidget->hide(); + + _ui.schemeWidget->show(); + + sint k = getCurrentScheme(); + + if (k == -1) // unknow scheme ... + { + _ui.schemeComboBox->setCurrentIndex(k); + k = 0; + } + + if (k != _ui.schemeComboBox->currentIndex()) + _ui.schemeComboBox->setCurrentIndex(k); + + if (hasSchemeCustomInput() && _SrcInputEnabled) + { + _ui.srcLabel->setEnabled(true); + _ui.srcComboBox->setEnabled(true); + _ui.srcComboBox->setCurrentIndex(int(getSchemeInput().InputType)); + + _ui.clampCheckBox->setEnabled(isClampingSupported()); + _ui.inMultiplierWidget->setEnabled(isClampingSupported()); + _ui.inputLabel->setEnabled(isClampingSupported()); + } + else + { + _ui.srcLabel->setEnabled(false); + _ui.srcComboBox->setEnabled(false); + inputValueUpdate(); + + _ui.clampCheckBox->setEnabled(false); + _ui.inMultiplierWidget->setEnabled(false); + _ui.inputLabel->setEnabled(false); + } + + if (_NbCycleEnabled) + { + _ui.inMultiplierWidget->updateUi(); + _ui.inMultiplierWidget->show(); + _ui.inputLabel->show(); + _ui.inMultiplierWidget->setEnabled(true); + _ui.clampCheckBox->show(); + } + else + { + _ui.inputLabel->hide(); + _ui.inMultiplierWidget->hide(); + _ui.clampCheckBox->hide(); + } + + if (isClampingSupported()) + _ui.clampCheckBox->setChecked(isSchemeClamped()); +} + +void CAttribWidget::enableMemoryScheme(bool enabled) +{ + _DisableMemoryScheme = !enabled; + if (!enabled) + { + _ui.schemeComboBox->removeItem(_ui.schemeComboBox->count() - 1); + _ui.schemeComboBox->removeItem(_ui.schemeComboBox->count() - 1); + } +} + +CAttribFloatWidget::CAttribFloatWidget(QWidget *parent) + : CAttribWidgetT(parent) +{ + _ui.schemeComboBox->addItem(tr("value blender")); + _ui.schemeComboBox->addItem(tr("values gradient")); + _ui.schemeComboBox->addItem(tr("curve")); + _ui.schemeComboBox->addItem(tr("value computed from emitter")); + _ui.schemeComboBox->addItem(tr("binary operator")); +} + +CAttribFloatWidget::~CAttribFloatWidget() +{ +} + +void CAttribFloatWidget::setRange(float minValue, float maxValue) +{ + _MinRange = minValue; + _MaxRange = maxValue; + _ui.constRangeFloatWidget->setRange(_MinRange, _MaxRange); +} + +void CAttribFloatWidget::setWrapper(IPSWrapper *wrapper) +{ + nlassert(wrapper); + _Wrapper = wrapper; + _ui.constRangeFloatWidget->setWrapper(_Wrapper); +} + +QDialog *CAttribFloatWidget::editScheme(void) +{ + NL3D::CPSAttribMaker *scheme = _SchemeWrapper->getScheme(); + + if (dynamic_cast(scheme)) + { + CFloatBlenderDialogClient *myInterface = new CFloatBlenderDialogClient(); + myInterface->MinRange = _MinRange; + myInterface->MaxRange = _MaxRange; + myInterface->SchemeFunc = & ((NL3D::CPSValueBlenderSample *) scheme)->_F; + CValueBlenderDialog *vb = new CValueBlenderDialog(myInterface, _Node, true, this); + return vb; + } + if (dynamic_cast(scheme)) + { + CFloatGradientWrapper *wrapper = new CFloatGradientWrapper; + wrapper->MinRange = _MinRange; + wrapper->MaxRange = _MaxRange; + wrapper->Scheme = &(((NL3D::CPSFloatGradient *) (_SchemeWrapper->getScheme()) )->_F); + CGradientDialog *gd = new CGradientDialog(_Node, wrapper, true, true, 2, this); + wrapper->DefaultValue = 0.f; + return gd; + } + if (dynamic_cast(scheme)) + { + CAttribFloatWidget *adf = new CAttribFloatWidget(); + adf->setRange(_MinRange, _MaxRange); + CValueFromEmitterDialogT *vfe = new CValueFromEmitterDialogT( (NL3D::CPSFloatMemory *)(scheme), + adf, + this); + vfe->init(); + adf->setWorkspaceNode(_Node); + adf->updateUi(); + return vfe; + } + if (dynamic_cast(scheme)) + { + CAttribFloatWidget *ad[2] = { NULL, NULL}; + for (uint k = 0; k <2; ++k) + { + ad[k] = new CAttribFloatWidget(); + ad[k]->setRange(_MinRange, _MaxRange); + } + CBinOpDialogT *bod = new CBinOpDialogT( (NL3D::CPSFloatBinOp *)(scheme), + (CAttribWidgetT **) ad, + this); + bod->init(); + for (uint k = 0; k <2; ++k) + { + ad[k]->setWorkspaceNode(_Node); + ad[k]->updateUi(); + } + return bod; + } + if (dynamic_cast(scheme)) + { + CurveEditDialog *curve = new CurveEditDialog(&(dynamic_cast(scheme)->_F), _Node, this); + return curve; + } + return NULL; +} + +void CAttribFloatWidget::setCurrentScheme(uint index) +{ + nlassert(index < 5); + NL3D::CPSAttribMaker *scheme = NULL; + + switch (index) + { + case 0: + scheme = new NL3D::CPSFloatBlender(_MinRange, _MaxRange); + break; + case 1: + { + static const float values[2] = { 0.1f, 1.f }; + scheme = new NL3D::CPSFloatGradient(values, 2, 16, 1.f); + } + break; + case 2: + { + NL3D::CPSFloatCurve *curve = new NL3D::CPSFloatCurve; + curve->_F.setNumSamples(128); + curve->_F.addControlPoint(NL3D::CPSFloatCurveFunctor::CCtrlPoint(0, 0.5f)); + curve->_F.addControlPoint(NL3D::CPSFloatCurveFunctor::CCtrlPoint(1, 0.5f)); + scheme = curve; + } + break; + case 3: + scheme = new NL3D::CPSFloatMemory; + ((NL3D::CPSAttribMakerMemory *) scheme)->setScheme(new NL3D::CPSFloatBlender(_MinRange, _MaxRange)); + break; + case 4 : + scheme = new NL3D::CPSFloatBinOp; + ((NL3D::CPSFloatBinOp *) scheme)->setArg(0, new NL3D::CPSFloatBlender); + ((NL3D::CPSFloatBinOp *) scheme)->setArg(1, new NL3D::CPSFloatBlender); + break; + default: + break; + } + + if (scheme) + { + _SchemeWrapper->setSchemeAndUpdateModifiedFlag(scheme); + } +} + +sint CAttribFloatWidget::getCurrentScheme(void) const +{ + const NL3D::CPSAttribMaker *scheme = _SchemeWrapper->getScheme(); + + if (dynamic_cast(scheme)) + return 0; + if (dynamic_cast(scheme)) + return 1; + if (dynamic_cast(scheme)) + return 2; + if (dynamic_cast(scheme)) + return 3; + if (dynamic_cast(scheme)) + return 4; + + return -1; +} + +void CAttribFloatWidget::cstValueUpdate() +{ + _ui.schemeWidget->hide(); + _ui.inMultiplierWidget->setEnabled(false); + _ui.clampCheckBox->setEnabled(false); + _ui.inputLabel->setEnabled(false); + _ui.constRangeFloatWidget->show(); + _ui.constRangeFloatWidget->updateUi(); +} + +CAttribUIntWidget::CAttribUIntWidget(QWidget *parent) + : CAttribWidgetT(parent) +{ + _ui.schemeComboBox->addItem(tr("value blender")); + _ui.schemeComboBox->addItem(tr("values gradient")); + _ui.schemeComboBox->addItem(tr("value computed from emitter")); + _ui.schemeComboBox->addItem(tr("binary operator")); +} + +CAttribUIntWidget::~CAttribUIntWidget() +{ +} + +void CAttribUIntWidget::setRange(uint32 minValue, uint32 maxValue) +{ + _MinRange = minValue; + _MaxRange = maxValue; + _ui.constRangeUIntWidget->setRange(_MinRange, _MaxRange); +} + +void CAttribUIntWidget::setWrapper(IPSWrapper *wrapper) +{ + nlassert(wrapper); + _Wrapper = wrapper; + _ui.constRangeUIntWidget->setWrapper(_Wrapper); +} + +QDialog *CAttribUIntWidget::editScheme(void) +{ + const NL3D::CPSAttribMaker *scheme = _SchemeWrapper->getScheme(); + + if (dynamic_cast(scheme)) + { + CUIntBlenderDialogClient *myInterface = new CUIntBlenderDialogClient(); + myInterface->MinRange = _MinRange; + myInterface->MaxRange = _MaxRange; + myInterface->SchemeFunc = & ((NL3D::CPSValueBlenderSample *) scheme)->_F; + CValueBlenderDialog *vb = new CValueBlenderDialog(myInterface, _Node, true, this); + return vb; + } + if (dynamic_cast(scheme)) + { + CUIntGradientWrapper *wrapper = new CUIntGradientWrapper; + wrapper->MinRange = _MinRange; + wrapper->MaxRange = _MaxRange; + wrapper->Scheme = &(((NL3D::CPSUIntGradient *) (_SchemeWrapper->getScheme()) )->_F); + CGradientDialog *gd = new CGradientDialog(_Node, wrapper, true, true, 2, this); + wrapper->DefaultValue = 0; + return gd; + + } + if (dynamic_cast(scheme)) + { + CAttribUIntWidget *adu = new CAttribUIntWidget(); + adu->setRange(_MinRange, _MaxRange); + CValueFromEmitterDialogT *vfe = new CValueFromEmitterDialogT( (NL3D::CPSUIntMemory *)(scheme), + adu, + this); + vfe->init(); + adu->setWorkspaceNode(_Node); + adu->updateUi(); + return vfe; + } + if (dynamic_cast(scheme)) + { + CAttribUIntWidget *ad[2] = { NULL, NULL}; + for (uint k = 0; k <2; ++k) + { + ad[k] = new CAttribUIntWidget(); + ad[k]->setRange(_MinRange, _MaxRange); + } + CBinOpDialogT *bod = new CBinOpDialogT( (NL3D::CPSUIntBinOp *)(scheme), + (CAttribWidgetT **) ad, + this); + bod->init(); + for (uint k = 0; k <2; ++k) + { + ad[k]->setWorkspaceNode(_Node); + ad[k]->updateUi(); + } + return bod; + } + return NULL; +} + +void CAttribUIntWidget::setCurrentScheme(uint index) +{ + nlassert(index < 4); + NL3D::CPSAttribMaker *scheme = NULL; + + switch (index) + { + case 0 : + scheme = new NL3D::CPSUIntBlender(_MinRange, _MaxRange); + break; + case 1 : + scheme = new NL3D::CPSUIntGradient; + break; + case 2 : + scheme = new NL3D::CPSUIntMemory; + ((NL3D::CPSAttribMakerMemory *) scheme)->setScheme(new NL3D::CPSUIntBlender(_MinRange, _MaxRange) ); + break; + case 3 : + scheme = new NL3D::CPSUIntBinOp; + ((NL3D::CPSUIntBinOp *) scheme)->setArg(0, new NL3D::CPSUIntBlender); + ((NL3D::CPSUIntBinOp *) scheme)->setArg(1, new NL3D::CPSUIntBlender); + break; + default: + break; + } + if (scheme) + { + _SchemeWrapper->setSchemeAndUpdateModifiedFlag(scheme); + } +} + +sint CAttribUIntWidget::getCurrentScheme(void) const +{ + const NL3D::CPSAttribMaker *scheme = _SchemeWrapper->getScheme(); + + if (dynamic_cast(scheme)) return 0; + if (dynamic_cast(scheme)) return 1; + if (dynamic_cast(scheme)) return 2; + if (dynamic_cast(scheme)) return 3; + return -1; +} + +void CAttribUIntWidget::cstValueUpdate() +{ + _ui.schemeWidget->hide(); + _ui.inMultiplierWidget->setEnabled(false); + _ui.clampCheckBox->setEnabled(false); + _ui.inputLabel->setEnabled(false); + _ui.constRangeUIntWidget->show(); + _ui.constRangeUIntWidget->updateUi(); +} + +CAttribIntWidget::CAttribIntWidget(QWidget *parent) + : CAttribWidgetT(parent) +{ + _ui.schemeComboBox->addItem(tr("value exact blender")); + _ui.schemeComboBox->addItem(tr("values gradient")); + _ui.schemeComboBox->addItem(tr("value computed from emitter")); + _ui.schemeComboBox->addItem(tr("binary operator")); +} + +CAttribIntWidget::~CAttribIntWidget() +{ +} + +void CAttribIntWidget::setRange(sint32 minValue, sint32 maxValue) +{ + _MinRange = minValue; + _MaxRange = maxValue; + _ui.constRangeIntWidget->setRange(_MinRange, _MaxRange); +} + +void CAttribIntWidget::setWrapper(IPSWrapper *wrapper) +{ + nlassert(wrapper); + _Wrapper = wrapper; + _ui.constRangeIntWidget->setWrapper(_Wrapper); +} + +QDialog *CAttribIntWidget::editScheme(void) +{ + const NL3D::CPSAttribMaker *scheme = _SchemeWrapper->getScheme(); + + if (dynamic_cast(scheme)) + { + CIntBlenderDialogClient *myInterface = new CIntBlenderDialogClient(); + myInterface->MinRange = _MinRange; + myInterface->MaxRange = _MaxRange; + myInterface->SchemeFunc = & ((NL3D::CPSValueBlenderSample *) scheme)->_F; + CValueBlenderDialog *vb = new CValueBlenderDialog(myInterface, _Node, true, this); + return vb; + } + if (dynamic_cast(scheme)) + { + CIntGradientWrapper *wrapper = new CIntGradientWrapper; + wrapper->MinRange = _MinRange; + wrapper->MaxRange = _MaxRange; + wrapper->Scheme = &(((NL3D::CPSIntGradient *) (_SchemeWrapper->getScheme()) )->_F); + CGradientDialog *gd = new CGradientDialog(_Node, wrapper, true, true, 2, this); + wrapper->DefaultValue = 0; + return gd; + } + if (dynamic_cast(scheme)) + { + CAttribIntWidget *adi = new CAttribIntWidget(); + adi->setRange(_MinRange, _MaxRange); + CValueFromEmitterDialogT *vfe = new CValueFromEmitterDialogT((NL3D::CPSIntMemory *) _SchemeWrapper->getScheme(), + adi, this); + vfe->init(); + adi->setWorkspaceNode(_Node); + adi->updateUi(); + return vfe; + } + if (dynamic_cast(scheme)) + { + CAttribIntWidget *ad[2] = { NULL, NULL}; + for (uint k = 0; k <2; ++k) + { + ad[k] = new CAttribIntWidget(); + ad[k]->setRange(_MinRange, _MaxRange); + } + CBinOpDialogT *bod = new CBinOpDialogT( (NL3D::CPSIntBinOp *)(scheme), + (CAttribWidgetT **) ad, + this); + bod->init(); + for (uint k = 0; k <2; ++k) + { + ad[k]->setWorkspaceNode(_Node); + ad[k]->updateUi(); + } + return bod; + } + return NULL; +} + +void CAttribIntWidget::setCurrentScheme(uint index) +{ + nlassert(index < 4); + NL3D::CPSAttribMaker *scheme = NULL; + + switch (index) + { + case 0 : + scheme = new NL3D::CPSIntBlender; + break; + case 1 : + scheme = new NL3D::CPSIntGradient; + break; + case 2 : + scheme = new NL3D::CPSIntMemory; + ((NL3D::CPSAttribMakerMemory *) scheme)->setScheme(new NL3D::CPSIntBlender(_MinRange, _MaxRange)); + break; + case 3 : + scheme = new NL3D::CPSIntBinOp; + ((NL3D::CPSIntBinOp *) scheme)->setArg(0, new NL3D::CPSIntBlender); + ((NL3D::CPSIntBinOp *) scheme)->setArg(1, new NL3D::CPSIntBlender); + break; + default: + break; + } + if (scheme) + { + _SchemeWrapper->setSchemeAndUpdateModifiedFlag(scheme); + } +} + +sint CAttribIntWidget::getCurrentScheme(void) const +{ + const NL3D::CPSAttribMaker *scheme = _SchemeWrapper->getScheme(); + + if (dynamic_cast(scheme)) return 0; + if (dynamic_cast(scheme)) return 1; + if (dynamic_cast(scheme)) return 2; + if (dynamic_cast(scheme)) return 3; + return -1; +} + +void CAttribIntWidget::cstValueUpdate() +{ + _ui.schemeWidget->hide(); + _ui.inMultiplierWidget->setEnabled(false); + _ui.clampCheckBox->setEnabled(false); + _ui.inputLabel->setEnabled(false); + _ui.constRangeIntWidget->show(); + //_ui.constRangeIntWidget->updateUi(); +} + +CAttribRGBAWidget::CAttribRGBAWidget(QWidget *parent) + : CAttribWidgetT(parent) +{ + _ui.schemeComboBox->addItem(tr("color sampled blender")); + _ui.schemeComboBox->addItem(tr("color gradient")); + _ui.schemeComboBox->addItem(tr("color exact blender")); + _ui.schemeComboBox->addItem(tr("values computed from emitter")); + _ui.schemeComboBox->addItem(tr("binary operator")); +} + +CAttribRGBAWidget::~CAttribRGBAWidget() +{ +} + +void CAttribRGBAWidget::setWrapper(IPSWrapper *wrapper) +{ + nlassert(wrapper); + _Wrapper = wrapper; + _ui.constRGBAWidget->setWrapper(_Wrapper); +} + +QDialog *CAttribRGBAWidget::editScheme(void) +{ + const NL3D::CPSAttribMaker *scheme = _SchemeWrapper->getScheme(); + + if (dynamic_cast(scheme)) + { + CRGBABlenderDialogClient *myInterface = new CRGBABlenderDialogClient(); + myInterface->SchemeFunc = & ((NL3D::CPSValueBlenderSample *) scheme)->_F; + CValueBlenderDialog *vb = new CValueBlenderDialog(myInterface, _Node, true, this); + return vb; + } + if (dynamic_cast(scheme)) + { + CColorGradientWrapper *wrapper = new CColorGradientWrapper; + wrapper->Scheme = &(((NL3D::CPSColorGradient *) (_SchemeWrapper->getScheme()) )->_F); + CGradientDialog *gd = new CGradientDialog(_Node, wrapper, true, true, 2, this); + wrapper->DefaultValue = NLMISC::CRGBA::White; + return gd; + } + if (dynamic_cast(scheme)) + { + return NULL; + } + if (dynamic_cast(scheme)) + { + CAttribRGBAWidget *ad = new CAttribRGBAWidget(); + CValueFromEmitterDialogT *vfe = new CValueFromEmitterDialogT( (NL3D::CPSColorMemory *)(scheme), + ad, + this); + vfe->init(); + ad->setWorkspaceNode(_Node); + ad->updateUi(); + return vfe; + } + if (dynamic_cast(scheme)) + { + CAttribRGBAWidget *ad[2] = { NULL, NULL}; + for (uint k = 0; k <2; ++k) + { + ad[k] = new CAttribRGBAWidget(); + } + CBinOpDialogT *bod = new CBinOpDialogT( (NL3D::CPSColorBinOp *)(scheme), + (CAttribWidgetT **) ad, + this); + bod->init(); + for (uint k = 0; k <2; ++k) + { + ad[k]->setWorkspaceNode(_Node); + ad[k]->updateUi(); + } + return bod; + } + return NULL; +} + +void CAttribRGBAWidget::setCurrentScheme(uint index) +{ + nlassert(index < 5); + NL3D::CPSAttribMaker *scheme = NULL; + + switch (index) + { + case 0 : + scheme = new NL3D::CPSColorBlender; + break; + case 1 : + scheme = new NL3D::CPSColorGradient(NL3D::CPSColorGradient::_DefaultGradient, 2, 16, 1.f); + break; + case 2 : + scheme = new NL3D::CPSColorBlenderExact; + break; + case 3 : + scheme = new NL3D::CPSColorMemory; + ((NL3D::CPSAttribMakerMemory *) scheme)->setScheme(new NL3D::CPSColorBlender); + break; + case 4 : + scheme = new NL3D::CPSColorBinOp; + ((NL3D::CPSColorBinOp *) scheme)->setArg(0, new NL3D::CPSColorBlender); + ((NL3D::CPSColorBinOp *) scheme)->setArg(1, new NL3D::CPSColorBlender); + break; + default: + break; + } + if (scheme) + { + _SchemeWrapper->setSchemeAndUpdateModifiedFlag(scheme); + } +} + +sint CAttribRGBAWidget::getCurrentScheme(void) const +{ + const NL3D::CPSAttribMaker *scheme = _SchemeWrapper->getScheme(); + + if (dynamic_cast(scheme)) return 0; + if (dynamic_cast(scheme)) return 1; + if (dynamic_cast(scheme)) return 2; + if (dynamic_cast(scheme)) return 3; + if (dynamic_cast(scheme)) return 4; + return -1; +} + +void CAttribRGBAWidget::cstValueUpdate() +{ + _ui.schemeWidget->hide(); + _ui.inMultiplierWidget->setEnabled(false); + _ui.clampCheckBox->setEnabled(false); + _ui.inputLabel->setEnabled(false); + _ui.constRGBAWidget->show(); + _ui.constRGBAWidget->updateUi(); +} + +CAttribPlaneBasisWidget::CAttribPlaneBasisWidget(QWidget *parent) + : CAttribWidgetT(parent) +{ + _ui.schemeComboBox->addItem(tr("basis gradient")); + _ui.schemeComboBox->addItem(tr("follow path")); + _ui.schemeComboBox->addItem(tr("spinner")); + _ui.schemeComboBox->addItem(tr("values computed from emitter")); + _ui.schemeComboBox->addItem(tr("binary operator")); +} + +CAttribPlaneBasisWidget::~CAttribPlaneBasisWidget() +{ +} + +void CAttribPlaneBasisWidget::setWrapper(IPSWrapper *wrapper) +{ + nlassert(wrapper); + _Wrapper = wrapper; + _ui.constAttribPlaneWidget->setWrapper(_Wrapper); +} + +QDialog *CAttribPlaneBasisWidget::editScheme(void) +{ + NL3D::CPSAttribMaker *scheme = _SchemeWrapper->getScheme(); + if (dynamic_cast(scheme)) + { + CPlaneBasisGradientWrapper *wrapper = new CPlaneBasisGradientWrapper; + wrapper->Scheme = &(((NL3D::CPSPlaneBasisGradient *) (_SchemeWrapper->getScheme()) )->_F); + CGradientDialog *gd = new CGradientDialog(_Node, wrapper, true, true, 2, this); + wrapper->DefaultValue = NL3D::CPlaneBasis(NLMISC::CVector::K); + return gd; + } + if (dynamic_cast(scheme)) + { + CFollowPathDialog *dialog = new CFollowPathDialog(dynamic_cast(scheme), _Node, this); + return dialog; + } + if (dynamic_cast(scheme)) + { + CAttribPlaneBasisWidget *ad = new CAttribPlaneBasisWidget(); + CValueFromEmitterDialogT *vfe = new CValueFromEmitterDialogT + ( (NL3D::CPSPlaneBasisMemory *)(scheme), + ad, this); + vfe->init(); + ad->setWorkspaceNode(_Node); + ad->updateUi(); + return vfe; + } + if (dynamic_cast(scheme)) + { + CAttribPlaneBasisWidget *ad[2] = { NULL, NULL}; + for (uint k = 0; k <2; ++k) + { + ad[k] = new CAttribPlaneBasisWidget(); + } + CBinOpDialogT *bod = new CBinOpDialogT( (NL3D::CPSPlaneBasisBinOp *)(scheme), + (CAttribWidgetT **) ad, + this); + bod->init(); + for (uint k = 0; k <2; ++k) + { + ad[k]->setWorkspaceNode(_Node); + ad[k]->updateUi(); + } + return bod; + } + if (dynamic_cast(scheme)) + { + CSpinnerDialog *dialog = new CSpinnerDialog(dynamic_cast(scheme), _Node, this); + return dialog; + } + return NULL; +} + +void CAttribPlaneBasisWidget::setCurrentScheme(uint index) +{ + nlassert(index < 5); + NL3D::CPSAttribMaker *scheme = NULL; + + switch (index) + { + case 0: + scheme = new NL3D::CPSPlaneBasisGradient; + break; + case 1: + scheme = new NL3D::CPSPlaneBasisFollowSpeed; + break; + case 2: + scheme = new NL3D::CPSBasisSpinner; + static_cast(scheme)->_F.setNumSamples(16); + break; + case 3: + scheme = new NL3D::CPSPlaneBasisMemory; + ((NL3D::CPSAttribMakerMemory *) scheme)->setScheme(new NL3D::CPSPlaneBasisFollowSpeed); + if (_Node) + { + _Node->setModified(true); + } + break; + case 4 : + scheme = new NL3D::CPSPlaneBasisBinOp; + ((NL3D::CPSPlaneBasisBinOp *) scheme)->setArg(0, new NL3D::CPSPlaneBasisFollowSpeed); + ((NL3D::CPSPlaneBasisBinOp *) scheme)->setArg(1, new NL3D::CPSPlaneBasisFollowSpeed); + break; + default: + break; + } + + if (scheme) + { + _SchemeWrapper->setSchemeAndUpdateModifiedFlag(scheme); + } +} + +sint CAttribPlaneBasisWidget::getCurrentScheme(void) const +{ + const NL3D::CPSAttribMaker *scheme = _SchemeWrapper->getScheme(); + + if (dynamic_cast(scheme)) return 0; + if (dynamic_cast(scheme)) return 1; + if (dynamic_cast(scheme)) return 2; + if (dynamic_cast(scheme)) return 3; + if (dynamic_cast(scheme)) return 4; + + return -1; +} + +void CAttribPlaneBasisWidget::cstValueUpdate() +{ + _ui.schemeWidget->hide(); + _ui.inMultiplierWidget->setEnabled(false); + _ui.clampCheckBox->setEnabled(false); + _ui.inputLabel->setEnabled(false); + _ui.constAttribPlaneWidget->show(); + _ui.constAttribPlaneWidget->updateUi(); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/attrib_widget.h b/code/nel/tools/3d/object_viewer_qt/src/attrib_widget.h new file mode 100644 index 000000000..7349bfbd6 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/attrib_widget.h @@ -0,0 +1,362 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef ATTRIB_WIDGET_H +#define ATTRIB_WIDGET_H + +#include +#include "ui_attrib_form.h" + +// Qt includes +#include + +// STL includes + +// NeL includes +#include +#include +#include +#include + +// Project includes +#include "ps_wrapper.h" +#include "particle_node.h" + +namespace NLQT { +/** +@class CAttribWidget +@brief Base attrib maker edition dialog. +*/ +class CAttribWidget: public QGroupBox +{ + Q_OBJECT + +public: + CAttribWidget(QWidget *parent = 0); + ~CAttribWidget(); + + /// @param enableConstantValue - when false, only a scheme is available + void setEnabledConstantValue(bool enableConstantValue = true); + + /// Force to update dialog content + void updateUi(); + + /// Сonnects all the slots with signals + void init(); + + /// Sets the pointer CWorkspaceNode* in the wrappers. + virtual void setWorkspaceNode(CWorkspaceNode *node) = 0; + + /// Private usage (not private because accessed by a static function) : return the nbCycles parameter of the scheme (e.g the input multiplier). + virtual float getSchemeNbCycles(void) const = 0; + + /// Private usage (not private because accessed by a static function) : set the nbCycles parameter of the scheme (e.g the input multiplier) + virtual void setSchemeNbCycles(float nbCycles) = 0; + + /// Enable the srcInput + void enableSrcInput(bool enable = true) { _SrcInputEnabled = enable; } + + bool isSrcInputEnabled() const { return _SrcInputEnabled; } + + /// Disable the possibility to choose a scheme that has memory. (for example, a scheme for lifetime of a located has no sense + /// because located have already some memory to store it) + void enableMemoryScheme(bool enabled = true); + + /// Tells wether memory schemes are enables + /// @see enableMemoryScheme() + bool isMemorySchemeEnabled() const { return !_DisableMemoryScheme; } + + /// Enable Nb Cycle tuning + void enableNbCycles(bool enabled) { _NbCycleEnabled = enabled; } + bool isNbCycleEnabled() const { return _NbCycleEnabled; } + +private Q_SLOTS: + virtual void clickedEdit(); + virtual void setClamp(bool state); + virtual void changeCurrentScheme(int index); + virtual void setCurrentSrc(int index); + virtual void setUserIndex(); + virtual void changeUseScheme(int index); + +protected: + + /// change the dialog for constant values + virtual void cstValueUpdate() = 0; + + /// enable / disable the 'edit input' button, when input can be edited + void inputValueUpdate(void); + + /// toggle back from scheme to cst value + virtual void resetCstValue(void) = 0; + + /// change the dialog for scheme usage + void schemeValueUpdate(); + + /// return true if a scheme is used + virtual bool useScheme(void) const = 0; + + /// edit the current scheme. And return a window on it + virtual QDialog *editScheme(void) = 0; + + /// set the current scheme + virtual void setCurrentScheme(uint index) = 0; + + /// set the current scheme ptr + virtual void setCurrentSchemePtr(NL3D::CPSAttribMakerBase *) = 0; + + /// get the current scheme, -1 if the scheme is unknow (created outside the editor ?) + virtual sint getCurrentScheme(void) const = 0; + + /// get a pointer on the current scheme base class + virtual NL3D::CPSAttribMakerBase *getCurrentSchemePtr(void) const = 0; + + /// tells wether the scheme supports custom input + virtual bool hasSchemeCustomInput(void) const = 0; + + /// retrieve the scheme input id + virtual NL3D::CPSInputType getSchemeInput(void) const = 0; + + /// set the scheme input id + virtual void setSchemeInput(const NL3D::CPSInputType &input) = 0; + + /// tells wether the scheme input value is clamped or not + virtual bool isSchemeClamped(void) const = 0; + + /// clamp / unclamp the scheme + virtual void clampScheme(bool clamped = true) = 0; + + /// return true if clamping is supported + virtual bool isClampingSupported(void) const = 0; + + /// bool : true is src input are allowed + bool _SrcInputEnabled; + + /// true if constant values are allowed + bool _EnableConstantValue; + + /// this is equal to true when memory schemes are not permitted + bool _DisableMemoryScheme; + + /// true to enable 'nb cycles' control + bool _NbCycleEnabled; + + /// wrapper to tune the number of cycles + struct CNbCyclesWrapper : public IPSWrapperFloat + { + CAttribWidget *widget; + float get(void) const { return widget->getSchemeNbCycles(); } + void set(const float &v) { widget->setSchemeNbCycles(v); } + } _NbCyclesWrapper; + + CWorkspaceNode *_Node; + + QDialog *_SchemeWidget; + + Ui::CAttribWidget _ui; +}; /* class CAttribWidget */ + +/** +@class CAttribWidgetT +@brief A template class that helps to specialize the attrib maker edition dialog with various types. +*/ +template class CAttribWidgetT : public CAttribWidget +{ +public: + CAttribWidgetT(QWidget *parent = 0): CAttribWidget(parent), + _Wrapper(NULL), + _SchemeWrapper(NULL) + { + } + virtual void setWrapper(IPSWrapper *wrapper) = 0; + void setSchemeWrapper(IPSSchemeWrapper *schemeWrapper) { nlassert(schemeWrapper); _SchemeWrapper = schemeWrapper; } + + // Inherited from CAttribWidget + virtual QDialog *editScheme(void) = 0; + virtual void setCurrentScheme(uint index) = 0; + virtual sint getCurrentScheme(void) const = 0; + + virtual void resetCstValue(void) + { + _Wrapper->setAndUpdateModifiedFlag(_Wrapper->get()); // reuse current color + } + + virtual bool hasSchemeCustomInput(void) const { return _SchemeWrapper->getScheme()->hasCustomInput(); } + virtual NL3D::CPSInputType getSchemeInput(void) const { return _SchemeWrapper->getScheme()->getInput(); } + virtual void setSchemeInput(const NL3D::CPSInputType &input) { _SchemeWrapper->getScheme()->setInput(input); } + + virtual void setWorkspaceNode(CWorkspaceNode *node) + { + _Node = node; if (_Wrapper != NULL) _Wrapper->OwnerNode = _Node; if (_SchemeWrapper != NULL) _SchemeWrapper->OwnerNode = _Node; + }; + + virtual float getSchemeNbCycles(void) const { return _SchemeWrapper->getScheme()->getNbCycles(); } + virtual void setSchemeNbCycles(float nbCycles) { _SchemeWrapper->getScheme()->setNbCycles(nbCycles); } + + virtual bool isSchemeClamped(void) const { return _SchemeWrapper->getScheme()->getClamping(); } + virtual void clampScheme(bool clamped = true) { _SchemeWrapper->getScheme()->setClamping(clamped); } + virtual bool isClampingSupported(void) const { return _SchemeWrapper->getScheme()->isClampingSupported(); }; + virtual NL3D::CPSAttribMakerBase *getCurrentSchemePtr(void) const { return _SchemeWrapper->getScheme(); } + virtual void setCurrentSchemePtr(NL3D::CPSAttribMakerBase *s) + { + _SchemeWrapper->setSchemeAndUpdateModifiedFlag(NLMISC::safe_cast *>(s)); + } + virtual void cstValueUpdate() = 0; + +protected: + virtual bool useScheme(void) const + { + nlassert(_SchemeWrapper); + return(_SchemeWrapper->getScheme() != NULL); + } +public: + /// Wrapper to set/get a constant float + IPSWrapper *_Wrapper; + /// Wrapper to set/get a scheme + IPSSchemeWrapper *_SchemeWrapper; +}; + +/** +@class CAttribFloatWidget +@brief An attribute editor specialized for float values +*/ +class CAttribFloatWidget: public CAttribWidgetT +{ + Q_OBJECT + +public: + CAttribFloatWidget(QWidget *parent = 0); + ~CAttribFloatWidget(); + + void setRange(float minValue = 0, float maxValue = 10); + void setWrapper(IPSWrapper *wrapper); + + // inherited from CAttribWidget + virtual QDialog *editScheme(void); + virtual void setCurrentScheme(uint index); + virtual sint getCurrentScheme(void) const; + virtual void cstValueUpdate(); + +private: + + float _MinRange, _MaxRange; +}; /* class CAttribFloatWidget */ + +/** +@class CAttribUIntWidget +@brief An attribute editor specialized for unsigned int values +*/ +class CAttribUIntWidget: public CAttribWidgetT +{ + Q_OBJECT + +public: + CAttribUIntWidget(QWidget *parent = 0); + ~CAttribUIntWidget(); + + void setRange(uint32 minValue = 0, uint32 maxValue = 10); + void setWrapper(IPSWrapper *wrapper); + + // inherited from CAttribWidget + virtual QDialog *editScheme(void); + virtual void setCurrentScheme(uint index); + virtual sint getCurrentScheme(void) const; + virtual void cstValueUpdate(); + +private: + + uint32 _MinRange, _MaxRange; +}; /* class CAttribUIntWidget */ + +/** +@class CAttribIntWidget +@brief An attribute editor specialized for signed int values +*/ +class CAttribIntWidget: public CAttribWidgetT +{ + Q_OBJECT + +public: + CAttribIntWidget(QWidget *parent = 0); + ~CAttribIntWidget(); + + void setRange(sint32 minValue = 0, sint32 maxValue = 10); + void setWrapper(IPSWrapper *wrapper); + + // inherited from CAttribWidget + virtual QDialog *editScheme(void); + virtual void setCurrentScheme(uint index); + virtual sint getCurrentScheme(void) const; + virtual void cstValueUpdate(); + +private: + + sint32 _MinRange, _MaxRange; +}; /* class CAttribIntWidget */ + +/** +@class CAttribRGBAWidget +@brief An attribute editor specialized for RGB values +*/ +class CAttribRGBAWidget: public CAttribWidgetT +{ + Q_OBJECT + +public: + CAttribRGBAWidget(QWidget *parent = 0); + ~CAttribRGBAWidget(); + + void setWrapper(IPSWrapper *wrapper); + + // inherited from CAttribWidget + virtual QDialog *editScheme(void); + virtual void setCurrentScheme(uint index); + virtual sint getCurrentScheme(void) const; + virtual void cstValueUpdate(); + +private: + +}; /* class CAttribRGBAWidget */ + +/** +@class CAttribPlaneBasisWidget +@brief An attribute editor specialized for plane basis values +*/ +class CAttribPlaneBasisWidget: public CAttribWidgetT +{ + Q_OBJECT + +public: + CAttribPlaneBasisWidget(QWidget *parent = 0); + ~CAttribPlaneBasisWidget(); + + void setWrapper(IPSWrapper *wrapper); + + // inherited from CAttribWidget + virtual QDialog *editScheme(void); + virtual void setCurrentScheme(uint index); + virtual sint getCurrentScheme(void) const; + virtual void cstValueUpdate(); + +private: + +}; /* class CAttribPlaneBasisWidget */ + +} /* namespace NLQT */ + +#endif // ATTRIB_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/auto_lod_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/auto_lod_dialog.cpp new file mode 100644 index 000000000..7c6fe651b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/auto_lod_dialog.cpp @@ -0,0 +1,88 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "auto_lod_dialog.h" + +// STL includes + +// Qt includes + +// NeL includes + +// Project includes + +namespace NLQT { + +CAutoLODDialog::CAutoLODDialog(CWorkspaceNode *ownerNode, NL3D::CParticleSystem *ps, QWidget *parent) + : QDialog(parent), _Node(ownerNode), _PS(ps) +{ + _ui.setupUi(this); + + setFixedHeight(sizeHint().height()); + + _DistRatioWrapper.PS = _PS; + _MaxDistLODBiasWrapper.PS = _PS; + _DistRatioWrapper.OwnerNode = _Node; + _MaxDistLODBiasWrapper.OwnerNode = _Node; + + // Edit the distance at which LOD starts + _ui.startPercentDistWidget->setRange(0.f, 0.99f); + _ui.startPercentDistWidget->enableUpperBound(1.f, true); + _ui.startPercentDistWidget->enableLowerBound(0.f, false); + _ui.startPercentDistWidget->setWrapper(&_DistRatioWrapper); + _ui.startPercentDistWidget->updateUi(); + + // For non-shared systems only : Set the LOD bias at the max distance, so that some particles are still displayed + _ui.maxDistBiasWidget->setRange(0.f, 1.0f); + _ui.maxDistBiasWidget->enableUpperBound(1.f, false); + _ui.maxDistBiasWidget->enableLowerBound(0.f, false); + _ui.maxDistBiasWidget->setWrapper(&_MaxDistLODBiasWrapper); + _ui.maxDistBiasWidget->updateUi(); + + if (_PS->isSharingEnabled()) + { + _ui.maxDistBiasWidget->setEnabled(false); + _ui.maxDistBiasLabel->setEnabled(false); + } + else + _ui.skipParticlesCheckBox->setEnabled(false); + + _ui.degrdExponentSpinBox->setValue(int(_PS->getAutoLODDegradationExponent()) - 1); + _ui.skipParticlesCheckBox->setChecked(_PS->getAutoLODMode()); + + connect(_ui.degrdExponentSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setDegradationExponent(int))); + connect(_ui.skipParticlesCheckBox, SIGNAL(toggled(bool)), this, SLOT(setSkipParticles(bool))); +} + +CAutoLODDialog::~CAutoLODDialog() +{ +} + +void CAutoLODDialog::setDegradationExponent(int value) +{ + _PS->setupAutoLOD(_PS->getAutoLODStartDistPercent(),value + 1); +} + +void CAutoLODDialog::setSkipParticles(bool state) +{ + _PS->setAutoLODMode(state); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/auto_lod_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/auto_lod_dialog.h new file mode 100644 index 000000000..bc699f2be --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/auto_lod_dialog.h @@ -0,0 +1,73 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef AUTO_LOD_DIALOG_H +#define AUTO_LOD_DIALOG_H + +#include "ui_auto_lod_form.h" + +// STL includes + +// Qt includes + +// NeL includes +#include "nel/3d/particle_system.h" + +// Project includes +#include "ps_wrapper.h" + +namespace NLQT { + +class CAutoLODDialog: public QDialog +{ + Q_OBJECT + +public: + CAutoLODDialog(CWorkspaceNode *ownerNode, NL3D::CParticleSystem *ps, QWidget *parent = 0); + ~CAutoLODDialog(); + +private Q_SLOTS: + void setDegradationExponent(int value); + void setSkipParticles(bool state); + +private: + CWorkspaceNode *_Node; + + NL3D::CParticleSystem *_PS; + + struct CDistRatioWrapper : IPSWrapperFloat + { + NL3D::CParticleSystem *PS; + virtual float get() const { return PS->getAutoLODStartDistPercent(); } + virtual void set(const float &v) { PS->setupAutoLOD(v, PS->getAutoLODDegradationExponent()); } + } _DistRatioWrapper; + + struct CMaxDistLODBiasWrapper : IPSWrapperFloat + { + NL3D::CParticleSystem *PS; + virtual float get() const { return PS->getMaxDistLODBias(); } + virtual void set(const float &v) { PS->setMaxDistLODBias(v); } + } _MaxDistLODBiasWrapper; + + Ui::CAutoLODDialog _ui; +}; /* class CAutoLODDialog */ + +} /* namespace NLQT */ + +#endif // AUTO_LOD_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/auto_lod_form.ui b/code/nel/tools/3d/object_viewer_qt/src/auto_lod_form.ui new file mode 100644 index 000000000..8fd459721 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/auto_lod_form.ui @@ -0,0 +1,151 @@ + + + CAutoLODDialog + + + + 0 + 0 + 543 + 137 + + + + Auto LOD + + + true + + + + + + Start percent DIST: + + + + + + + + + + Max dist BIAS: + + + + + + + + + + Degradation exponent: + + + + + + + 1 + + + 4 + + + + + + + Qt::Horizontal + + + + 331 + 21 + + + + + + + + Skip particles + + + + + + + Qt::Horizontal + + + + 139 + 22 + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+
+ + + + buttonBox + accepted() + CAutoLODDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CAutoLODDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/basic_edit_form.ui b/code/nel/tools/3d/object_viewer_qt/src/basic_edit_form.ui new file mode 100644 index 000000000..ce6cbac40 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/basic_edit_form.ui @@ -0,0 +1,214 @@ + + + CBasicEditWidget + + + + 0 + 0 + 283 + 99 + + + + Form + + + + + + Psi + + + + + + + 359 + + + Qt::Horizontal + + + + + + + 359 + + + + + + + + 0 + 0 + + + + + 75 + 75 + + + + + + + + Theta + + + + + + + 360 + + + Qt::Horizontal + + + + + + + 359 + + + + + + + Phi + + + + + + + 360 + + + Qt::Horizontal + + + + + + + 359 + + + + + + + + NLQT::CGraphicsInfoWidget + QWidget +
graphics_info_widget.h
+ 1 +
+
+ + + + psiHorizontalSlider + valueChanged(int) + psiSpinBox + setValue(int) + + + 126 + 22 + + + 173 + 22 + + + + + thetaHorizontalSlider + valueChanged(int) + thetaSpinBox + setValue(int) + + + 135 + 41 + + + 192 + 41 + + + + + phiHorizontalSlider + valueChanged(int) + phiSpinBox + setValue(int) + + + 134 + 65 + + + 170 + 65 + + + + + phiSpinBox + valueChanged(int) + phiHorizontalSlider + setValue(int) + + + 184 + 77 + + + 138 + 79 + + + + + thetaSpinBox + valueChanged(int) + thetaHorizontalSlider + setValue(int) + + + 179 + 50 + + + 154 + 50 + + + + + psiSpinBox + valueChanged(int) + psiHorizontalSlider + setValue(int) + + + 171 + 9 + + + 155 + 18 + + + + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/basic_edit_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/basic_edit_widget.cpp new file mode 100644 index 000000000..fc0914c84 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/basic_edit_widget.cpp @@ -0,0 +1,192 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "basic_edit_widget.h" + +// Qt includes + +// NeL includes +#include "nel/misc/matrix.h" +#include "nel/misc/vector.h" + +namespace NLQT { + + +// build an euler matrix +NLMISC::CMatrix BuildEulerMatrix(float psi, float theta, float phi) +{ + float ca = cosf(psi), sa = sinf(psi) + , cb = cosf(theta), sb = sinf(theta) + , cc = cosf(phi), sc = sinf(phi); + NLMISC::CMatrix m; + m.identity(); + m.setRot(NLMISC::CVector(ca * cb * cc - sa * sc, -cc * sa - ca * cb *sc, ca * sb) + ,NLMISC::CVector(cb * cc * sa + ca * sc, ca * cc - cb * sa * sc, sa *sb) + ,NLMISC::CVector(-cc * sb, sb * sc, cb) + ); + return m; +} + +// get back the euler angles from a matrix +NLMISC::CVector GetEulerAngles(const NLMISC::CMatrix &mat) +{ + float m[3][3]; + // we got cos theta = m33 + NLMISC::CVector v[3]; + mat.getRot(v[0], v[1], v[2]); + for (uint l = 0; l < 3; ++l) + { + m[0][l] = v[l].x; m[1][l] = v[l].y; m[2][l] = v[l].z; + } + + // there are eight triplet that may satisfy the equation + // we compute them all, and test them against the matrix + + float b0, b1, a0, a1, a2, a3, c0, c1, c2, c3; + b0 = acosf(m[2][2]); + b1 = (float) NLMISC::Pi - b0; + float sb0 = sinf(b0), sb1 = sinf(b1); + if (fabsf(sb0) > 10E-6) + { + a0 = m[2][0] / sb0; + c0 = m[1][2] / sb0; + } + else + { + a0 = c0 = 1.f; + } + if (fabs(sb1) > 10E-6) + { + a1 = m[2][0] / sb1; + c1 = m[1][2] / sb1; + } + else + { + a1 = c1 = 1.f; + } + + + a2 = (float) NLMISC::Pi - a0; + a3 = (float) NLMISC::Pi - a1; + + + c2 = (float) NLMISC::Pi - c0; + c3 = (float) NLMISC::Pi - c1; + + NLMISC::CVector sol[] = + { + NLMISC::CVector(b0, a0, c0) + ,NLMISC::CVector(b0, a2, c0) + ,NLMISC::CVector(b0, a0, c2) + ,NLMISC::CVector(b0, a2, c2) + ,NLMISC::CVector(b1, a1, c1) + ,NLMISC::CVector(b1, a3, c1) + ,NLMISC::CVector(b1, a1, c3) + ,NLMISC::CVector(b1, a3, c3) + }; + + // now we take the triplet that fit best the 6 other equations + + float bestGap = 0.f; + uint bestIndex; + + for (uint k = 0; k < 8; ++k) + { + float ca = cosf(sol[k].x), sa = sinf(sol[k].x) + , cb = cosf(sol[k].y), sb = sinf(sol[k].y) + , cc = cosf(sol[k].z), sc = sinf(sol[k].z); + + float gap = fabsf(m[0][0] - ca * cb * cc + sa * sc); + gap += fabsf(m[1][0] + cc * sa + ca * cb *sc); + gap += fabsf(m[0][1] - cb * cc * sa - ca * sc); + gap += fabsf(m[0][1] - cb * cc * sa - ca * sc); + gap += fabsf(m[1][1] - ca * cc + cb * sa * sc); + gap += fabsf(m[2][1] - sb *ca); + gap += fabsf(m[0][2] + cc * sb); + + if (k == 0 || gap < bestGap) + { + bestGap = gap; + bestIndex = k; + + } + } + return sol[bestIndex]; +} + +CBasicEditWidget::CBasicEditWidget(QWidget *parent) + : QWidget(parent), _Wrapper(NULL) +{ + _ui.setupUi(this); + + connect(_ui.psiSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateGraphics())); + connect(_ui.thetaSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateGraphics())); + connect(_ui.phiSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateGraphics())); +} + +CBasicEditWidget::~CBasicEditWidget() +{ +} + +void CBasicEditWidget::setWrapper(IPSWrapper *wrapper) +{ + _Wrapper = wrapper; +} + +void CBasicEditWidget::updateUi() +{ + if (_Wrapper == NULL) return; + NL3D::CPlaneBasis pb = _Wrapper->get(); + NLMISC::CMatrix mat; + mat.setRot(pb.X, pb.Y, pb.X ^ pb.Y); + NLMISC::CVector angles = GetEulerAngles(mat); + + _ui.psiSpinBox->blockSignals(true); + _ui.thetaSpinBox->blockSignals(true); + _ui.phiSpinBox->blockSignals(true); + + _ui.psiSpinBox->setValue(int(360.f * angles.x / (2.f * (float) NLMISC::Pi))); + _ui.thetaSpinBox->setValue(int(360.f * angles.y / (2.f * (float) NLMISC::Pi))); + _ui.phiSpinBox->setValue(int(360.f * angles.z / (2.f * (float) NLMISC::Pi))); + + _ui.psiSpinBox->blockSignals(false); + _ui.thetaSpinBox->blockSignals(false); + _ui.phiSpinBox->blockSignals(false); + + repaint(); +} + +void CBasicEditWidget::updateGraphics() +{ + if (_Wrapper == NULL) return; + + NLMISC::CVector angles(2.f * (float) NLMISC::Pi * _ui.psiSpinBox->value() / 360.f + , 2.f * (float) NLMISC::Pi * _ui.thetaSpinBox->value() / 360.f + , 2.f * (float) NLMISC::Pi * _ui.phiSpinBox->value() / 360.f + ); + NLMISC::CMatrix mat = BuildEulerMatrix(angles.x, angles.y, angles.z); + NL3D::CPlaneBasis pb; + pb.X = mat.getI(); + pb.Y = mat.getJ(); + _Wrapper->setAndUpdateModifiedFlag(pb); + repaint(); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/basic_edit_widget.h b/code/nel/tools/3d/object_viewer_qt/src/basic_edit_widget.h new file mode 100644 index 000000000..0c9987e05 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/basic_edit_widget.h @@ -0,0 +1,61 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef BASIC_EDIT_WIDGET_H +#define BASIC_EDIT_WIDGET_H + +#include +#include "ui_basic_edit_form.h" + +// STL includes + +// NeL includes +#include "nel/3d/ps_plane_basis.h" +#include "ps_wrapper.h" + +// Project includes + +namespace NLQT { + +class CBasicEditWidget: public QWidget +{ + Q_OBJECT + +public: + CBasicEditWidget(QWidget *parent = 0); + ~CBasicEditWidget(); + + void setWrapper(IPSWrapper *wrapper); + void updateUi(); + +private Q_SLOTS: + void updateGraphics(); + +private: + + // wrapper to the datas + IPSWrapper *_Wrapper ; + + Ui::CBasicEditWidget _ui; + +}; /* class CBasicEditWidget */ + +} /* namespace NLQT */ + +#endif // BASIC_EDIT_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/bin_op_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/bin_op_dialog.cpp new file mode 100644 index 000000000..0093f6aa1 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/bin_op_dialog.cpp @@ -0,0 +1,63 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "bin_op_dialog.h" + +namespace NLQT { + +CBinOpDialog::CBinOpDialog(QWidget *widget1, QWidget *widget2, QWidget *parent) + : QDialog(parent) +{ + resize(350, 330); + _gridLayout = new QGridLayout(this); + _gridLayout->addWidget(widget1, 0, 0, 1, 2); + + _comboBox = new QComboBox(this); + _gridLayout->addWidget(_comboBox, 1, 0, 1, 1); + + _horizontalSpacer = new QSpacerItem(267, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + _gridLayout->addItem(_horizontalSpacer, 1, 1, 1, 1); + + _gridLayout->addWidget(widget2, 2, 0, 1, 2); + + setWindowTitle(tr("Bin operator")); + _comboBox->clear(); + _comboBox->insertItems(0, QStringList() + << tr("SelectArg1") + << tr("SelectArg2") + << tr("Modulate") + << tr("Add") + << tr("Subtract")); + + qobject_cast(widget1)->setTitle(tr("Arg1")); + qobject_cast(widget2)->setTitle(tr("Arg2")); + connect(_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setNewOp(int))); +} + +CBinOpDialog::~CBinOpDialog() +{ +} + +void CBinOpDialog::setNewOp(int index) +{ + newOp(uint32(index)); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/bin_op_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/bin_op_dialog.h new file mode 100644 index 000000000..67de55f6a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/bin_op_dialog.h @@ -0,0 +1,152 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef BIN_OP_DIALOG_H +#define BIN_OP_DIALOG_H + + +#include + +// Qt includes +#include +#include +#include +#include +#include +#include + +// NeL includes +#include "nel/3d/ps_attrib_maker_bin_op.h" + +// Project includes +#include "ps_wrapper.h" +#include "attrib_widget.h" + +namespace NLQT { + +class CBinOpDialog : public QDialog +{ + Q_OBJECT + +public: + CBinOpDialog(QWidget *widget1, QWidget *widget2, QWidget *parent = 0); + ~CBinOpDialog(); + + virtual void init() = 0; + + /// called when a new operator has been selected + virtual void newOp(uint32 op) = 0 ; + +private Q_SLOTS: + void setNewOp(int index); + +protected: + + QGridLayout *_gridLayout; + QWidget *_widget1; + QComboBox *_comboBox; + QSpacerItem *_horizontalSpacer; + QWidget *_widget2; +}; + + +/** +@class CBinOpDialogT +@brief Construct a dialog that allow to edit a binary operator that produce argument of a particle system +*/ +template class CBinOpDialogT : public CBinOpDialog +{ +public: + /// ctruct the given dialog from the given scheme that owns memory + CBinOpDialogT(NL3D::CPSAttribMakerBinOp *editedScheme, CAttribWidgetT **attrbDlg, QWidget *parent = 0) + : CBinOpDialog(attrbDlg[0], attrbDlg[1], parent), _EditedScheme(editedScheme) + { + for (uint k = 0 ; k < 2 ; ++k) + { + nlassert(attrbDlg); + _AttrbDlg[k] = attrbDlg[k]; + _SchemeWrapper[k].S = _EditedScheme ; + _SchemeWrapper[k].Index = k ; + } + } + + void init() + { + uint k ; + for (k = 0 ; k < 2 ; ++k) + { + _AttrbDlg[k]->setEnabledConstantValue(false) ; + _AttrbDlg[k]->setWrapper(&_DummyWrapper) ; + _AttrbDlg[k]->setSchemeWrapper(&_SchemeWrapper[k]) ; + _AttrbDlg[k]->init(); + } + for (k = 0 ; k < (uint) NL3D::CPSBinOp::last ; ++k) + { + if (_EditedScheme->supportOp( (NL3D::CPSBinOp::BinOp) k)) + { + if ((uint) _EditedScheme->getOp() == k) + _comboBox->setCurrentIndex(k); + } + } + } + + ~CBinOpDialogT() + { + for (uint k = 0 ; k < 2 ; ++k) + { + delete _AttrbDlg[k] ; + } + } + +protected: + + NL3D::CPSAttribMakerBinOp *_EditedScheme ; + + /// the dialogs that allow us to edit the schemes + CAttribWidgetT *_AttrbDlg[2] ; + + /// a wrapper to edit the scheme (which himself owns a scheme !!) + struct CSchemeWrapper : public IPSSchemeWrapper + { + NL3D::CPSAttribMakerBinOp *S ; + uint Index ; + virtual NL3D::CPSAttribMaker *getScheme(void) const { return S->getArg(Index) ; } + virtual void setScheme(NL3D::CPSAttribMaker *s) { S->setArg(Index, s) ; } ; + } _SchemeWrapper[2] ; + + /// a dummy wrapper for constant value. This shouldn't be called , however + struct CDummyWrapper : public IPSWrapper + { + T get(void) const { nlassert(false) ; return T() ; } + void set(const T &) { nlassert(false) ; } + } _DummyWrapper ; + + + void newOp(uint32 op) + { + nlassert(_EditedScheme) ; + if (_EditedScheme->getOp() != (NL3D::CPSBinOp::BinOp) op) + _EditedScheme->setOp((NL3D::CPSBinOp::BinOp) op); + } + +} ; + +} /* namespace NLQT */ + +#endif // BIN_OP_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/callback.cpp b/code/nel/tools/3d/object_viewer_qt/src/callback.cpp new file mode 100644 index 000000000..7cf73a296 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/callback.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2010 by authors + * + * This file is part of NEL QT. + * NEL QT is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * NEL QT 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NEL QT; see the file COPYING. If not, see + * . + */ + +#include "stdpch.h" +#include "callback.h" + +namespace NLQT { + +} /* namespace NLQT */ + +/* end of file */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/callback.h b/code/nel/tools/3d/object_viewer_qt/src/callback.h new file mode 100644 index 000000000..822b1ee99 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/callback.h @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2010 by authors + * + * This file is part of NEL QT. + * NEL QT is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * NEL QT 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NEL QT; see the file COPYING. If not, see + * . + */ + +#ifndef NLQT_CALLBACK_H +#define NLQT_CALLBACK_H +#include + +// STL includes + +// NeL includes +#ifdef NL_COMP_GCC +// temporary fix for GCC 4.4 segmentation fault +# undef nlassert +# define nlassert(x) +#else +# include +#endif // NL_COMP_GCC + +// Project includes + +namespace NLQT { + +#define NLQT_CALLBACK_TEMPLATE \ +/** \ + * \brief NLQT_CALLBACK_ARGS_CLASS \ + * \date 2009-03-03 18:09GMT \ + * \author Jan Boon (Kaetemi) \ + * Awesome callback template \ + */ \ +template \ +class NLQT_CALLBACK_ARGS_CLASS \ +{ \ + /* Very simple reference counting callback base */ \ + class CCallbackBase \ + { \ + public: \ + CCallbackBase() : m_RefCount(0) \ + { \ + \ + } \ + \ + virtual ~CCallbackBase() \ + { \ + nlassert(!m_RefCount); \ + } \ + \ + void refAdd() \ + { \ + ++m_RefCount; \ + } \ + \ + void refRemove() \ + { \ + --m_RefCount; \ + if (!m_RefCount) \ + delete this; \ + } \ + \ + virtual TReturn callback(NLQT_CALLBACK_ARGS_DECL) = 0; \ + \ + virtual bool equals(const CCallbackBase *callbackBase) = 0; \ + \ + /* disable copy */ \ + CCallbackBase(const CCallbackBase &); \ + CCallbackBase &operator=(const CCallbackBase &); \ + \ + private: \ + uint m_RefCount; \ + }; \ + \ + typedef TReturn TCallbackFunction(NLQT_CALLBACK_ARGS_DECL); \ + class CCallbackFunction : public CCallbackBase \ + { \ + public: \ + CCallbackFunction(TCallbackFunction *callbackFunction) : m_CallbackFunction(callbackFunction) \ + { \ + nlassert(m_CallbackFunction); \ + } \ + \ + virtual ~CCallbackFunction() \ + { \ + m_CallbackFunction = NULL; \ + } \ + \ + virtual TReturn callback(NLQT_CALLBACK_ARGS_DECL) \ + { \ + return m_CallbackFunction(NLQT_CALLBACK_ARGS_IMPL); \ + } \ + \ + virtual bool equals(const CCallbackBase *callbackBase) \ + { \ + const CCallbackFunction *callbackFunction = \ + dynamic_cast(callbackBase); \ + if (!callbackFunction) return false; \ + return m_CallbackFunction == callbackFunction->m_CallbackFunction; \ + } \ + \ + private: \ + TCallbackFunction *m_CallbackFunction; \ + }; \ + \ + template \ + class CCallbackMethod : public CCallbackBase \ + { \ + typedef TReturn (TClass::*TCallbackMethod)(NLQT_CALLBACK_ARGS_DECL); \ + public: \ + CCallbackMethod(TClass *callbackObject, TCallbackMethod callbackMethod) : m_CallbackObject(callbackObject), m_CallbackMethod(callbackMethod) \ + { \ + nlassert(m_CallbackObject); \ + nlassert(m_CallbackMethod); \ + } \ + \ + virtual ~CCallbackMethod() \ + { \ + m_CallbackObject = NULL; \ + m_CallbackMethod = NULL; \ + } \ + \ + virtual TReturn callback(NLQT_CALLBACK_ARGS_DECL) \ + { \ + return (m_CallbackObject->*m_CallbackMethod)(NLQT_CALLBACK_ARGS_IMPL); \ + } \ + \ + virtual bool equals(const CCallbackBase *callbackBase) \ + { \ + const CCallbackMethod *callbackMethod = \ + dynamic_cast(callbackBase); \ + if (!callbackMethod) return false; \ + return m_CallbackObject == callbackMethod->m_CallbackObject \ + && m_CallbackMethod == callbackMethod->m_CallbackMethod; \ + } \ + \ + private: \ + TClass *m_CallbackObject; \ + TCallbackMethod m_CallbackMethod; \ + }; \ + \ +public: \ + CCallback() : m_CallbackBase(NULL) \ + { \ + \ + } \ + \ + CCallback(TCallbackFunction *callbackFunction) : m_CallbackBase(new CCallbackFunction(callbackFunction)) \ + { \ + nlassert(m_CallbackBase); \ + m_CallbackBase->refAdd(); \ + } \ + \ + template \ + CCallback(TClass *callbackObject, TReturn (TClass::*callbackMethod)(NLQT_CALLBACK_ARGS_DECL)) : m_CallbackBase(new CCallbackMethod(callbackObject, callbackMethod)) \ + { \ + nlassert(m_CallbackBase); \ + m_CallbackBase->refAdd(); \ + } \ + \ + CCallback(const CCallback &callback) \ + { \ + m_CallbackBase = callback.m_CallbackBase; \ + if (m_CallbackBase) \ + m_CallbackBase->refAdd(); \ + } \ + \ + CCallback &operator=(const CCallback &callback) \ + { \ + if (m_CallbackBase != callback.m_CallbackBase) \ + { \ + if (m_CallbackBase) \ + m_CallbackBase->refRemove(); \ + m_CallbackBase = callback.m_CallbackBase; \ + if (m_CallbackBase) \ + m_CallbackBase->refAdd(); \ + } \ + return *this; \ + } \ + \ + ~CCallback() \ + { \ + if (m_CallbackBase) \ + { \ + m_CallbackBase->refRemove(); \ + m_CallbackBase = NULL; \ + } \ + } \ + \ + TReturn callback(NLQT_CALLBACK_ARGS_DECL) \ + { \ + nlassert(m_CallbackBase); \ + return m_CallbackBase->callback(NLQT_CALLBACK_ARGS_IMPL); \ + } \ + \ + TReturn operator()(NLQT_CALLBACK_ARGS_DECL) \ + { \ + nlassert(m_CallbackBase); \ + return m_CallbackBase->callback(NLQT_CALLBACK_ARGS_IMPL); \ + } \ + \ + bool valid() const \ + { \ + return m_CallbackBase != NULL; \ + } \ + \ + operator bool() const \ + { \ + return m_CallbackBase != NULL; \ + } \ + \ + bool operator==(const CCallback &callback) \ + { \ + return m_CallbackBase->equals(callback.m_CallbackBase); \ + } \ + \ +private: \ + CCallbackBase *m_CallbackBase; \ + \ +}; /* class CCallback */ \ + +template +class CCallback; + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME +#define NLQT_CALLBACK_ARGS_DECL +#define NLQT_CALLBACK_ARGS_IMPL +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA +#define NLQT_CALLBACK_ARGS_IMPL argsA +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB +#define NLQT_CALLBACK_ARGS_IMPL argsA, argsB +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC +#define NLQT_CALLBACK_ARGS_IMPL argsA, argsB, argsC +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD +#define NLQT_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE +#define NLQT_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE, typename TArgsF +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE, TArgsF argsF +#define NLQT_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE, argsF +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL + +#define NLQT_CALLBACK_ARGS_CLASS CCallback +#define NLQT_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE, typename TArgsF, typename TArgsG +#define NLQT_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE, TArgsF argsF, TArgsG argsG +#define NLQT_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE, argsF, argsG +NLQT_CALLBACK_TEMPLATE +#undef NLQT_CALLBACK_ARGS_CLASS +#undef NLQT_CALLBACK_ARGS_TYPENAME +#undef NLQT_CALLBACK_ARGS_DECL +#undef NLQT_CALLBACK_ARGS_IMPL +#undef NLQT_CALLBACK_ARGS_CLASSNAME + +#undef NLQT_CALLBACK_TEMPLATE + +typedef CCallback CEmptyCallback; + +} /* namespace NLQT */ + +#endif /* #ifndef NLQT_CALLBACK_H */ + +/* end of file */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/color_edit_form.ui b/code/nel/tools/3d/object_viewer_qt/src/color_edit_form.ui new file mode 100644 index 000000000..14ed81b98 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/color_edit_form.ui @@ -0,0 +1,264 @@ + + + CColorEditWidget + + + + 0 + 0 + 255 + 116 + + + + Form + + + + + + + 0 + 0 + + + + 255 + + + Qt::Horizontal + + + + + + + QAbstractSpinBox::UpDownArrows + + + 255 + + + + + + + Browse + + + + + + + 255 + + + Qt::Horizontal + + + + + + + 255 + + + + + + + + 0 + 0 + + + + + 75 + 75 + + + + + + + + 255 + + + Qt::Horizontal + + + + + + + 255 + + + + + + + 255 + + + 255 + + + Qt::Horizontal + + + + + + + 255 + + + 255 + + + + + + + + NLQT::CGraphicsInfoWidget + QWidget +
graphics_info_widget.h
+ 1 +
+
+ + + + rHorizontalSlider + valueChanged(int) + rSpinBox + setValue(int) + + + 159 + 75 + + + 231 + 75 + + + + + gHorizontalSlider + valueChanged(int) + gSpinBox + setValue(int) + + + 166 + 115 + + + 214 + 116 + + + + + bHorizontalSlider + valueChanged(int) + bSpinBox + setValue(int) + + + 160 + 160 + + + 210 + 164 + + + + + aHorizontalSlider + valueChanged(int) + aSpinBox + setValue(int) + + + 158 + 201 + + + 210 + 201 + + + + + rSpinBox + valueChanged(int) + rHorizontalSlider + setValue(int) + + + 217 + 81 + + + 167 + 81 + + + + + gSpinBox + valueChanged(int) + gHorizontalSlider + setValue(int) + + + 224 + 130 + + + 184 + 130 + + + + + bSpinBox + valueChanged(int) + bHorizontalSlider + setValue(int) + + + 219 + 154 + + + 171 + 153 + + + + + aSpinBox + valueChanged(int) + aHorizontalSlider + setValue(int) + + + 228 + 198 + + + 187 + 199 + + + + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/color_edit_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/color_edit_widget.cpp new file mode 100644 index 000000000..3ee8d2f6b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/color_edit_widget.cpp @@ -0,0 +1,167 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "color_edit_widget.h" + +// Qt includes +#include +#include + +// Nel includes +#include + +namespace NLQT { + +CColorEditWidget::CColorEditWidget(QWidget *parent) + : QWidget(parent), _Wrapper(NULL), _emit(true) +{ + _ui.setupUi(this); + + connect(_ui.rSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setRed(int))); + connect(_ui.gSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setGreen(int))); + connect(_ui.bSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setBlue(int))); + connect(_ui.aSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setAlpha(int))); + connect(_ui.browsePushButton, SIGNAL(clicked()), this, SLOT(browseColor())); + + setColor(QColor(255, 255, 255, 255)); +} + +CColorEditWidget::~CColorEditWidget() +{ +} + +void CColorEditWidget::setWrapper(IPSWrapperRGBA *wrapper) +{ + _Wrapper = wrapper; +} + +void CColorEditWidget::setColor(const NLMISC::CRGBA &color, bool emit) +{ + _emit = false; + _ui.rSpinBox->setValue(color.R); + _ui.gSpinBox->setValue(color.G); + _ui.bSpinBox->setValue(color.B); + _ui.aSpinBox->setValue(color.A); + _emit = true; + if (emit) + Q_EMIT colorChanged(color); +} + +void CColorEditWidget::setColor(const QColor &color, bool emit) +{ + setColor(NLMISC::CRGBA(color.red(), color.green(), color.blue(), color.alpha()), emit); +} + +void CColorEditWidget::updateUi() +{ + if (_Wrapper == NULL) return; + _ui.rSpinBox->setValue(_Wrapper->get().R); + _ui.gSpinBox->setValue(_Wrapper->get().G); + _ui.bSpinBox->setValue(_Wrapper->get().B); + _ui.aSpinBox->setValue(_Wrapper->get().A); + _ui.graphicsWidget->setColor(QColor(_ui.rSpinBox->value(), _ui.gSpinBox->value(), _ui.bSpinBox->value(), _ui.aSpinBox->value())); +} + +void CColorEditWidget::setRed(int r) +{ + _ui.graphicsWidget->setColor(QColor(_ui.rSpinBox->value(), _ui.gSpinBox->value(), _ui.bSpinBox->value(), _ui.aSpinBox->value())); + + if (_emit) + Q_EMIT colorChanged(NLMISC::CRGBA(r, _ui.gSpinBox->value(), _ui.bSpinBox->value(), _ui.aSpinBox->value())); + + if (_Wrapper == NULL) + return; + + NLMISC::CRGBA color = _Wrapper->get(); + + if (r == color.R) + return; + + color.R = r; + _Wrapper->setAndUpdateModifiedFlag(color); + +} + +void CColorEditWidget::setGreen(int g) +{ + _ui.graphicsWidget->setColor(QColor(_ui.rSpinBox->value(), _ui.gSpinBox->value(), _ui.bSpinBox->value(), _ui.aSpinBox->value())); + + if (_emit) + Q_EMIT colorChanged(NLMISC::CRGBA(_ui.rSpinBox->value(), g, _ui.bSpinBox->value(), _ui.aSpinBox->value())); + + if (_Wrapper == NULL) return; + + NLMISC::CRGBA color = _Wrapper->get(); + + if (g == color.G) + return; + + color.G = g; + _Wrapper->setAndUpdateModifiedFlag(color); +} + +void CColorEditWidget::setBlue(int b) +{ + _ui.graphicsWidget->setColor(QColor(_ui.rSpinBox->value(), _ui.gSpinBox->value(), _ui.bSpinBox->value(), _ui.aSpinBox->value())); + + if (_emit) + Q_EMIT colorChanged(NLMISC::CRGBA(_ui.rSpinBox->value(), _ui.gSpinBox->value(), b, _ui.aSpinBox->value())); + + if (_Wrapper == NULL) return; + + NLMISC::CRGBA color = _Wrapper->get(); + + if (b == color.B) + return; + + color.B = b; + _Wrapper->setAndUpdateModifiedFlag(color); +} + +void CColorEditWidget::setAlpha(int a) +{ + _ui.graphicsWidget->setColor(QColor(_ui.rSpinBox->value(), _ui.gSpinBox->value(), _ui.bSpinBox->value(), a)); + + if (_emit) + Q_EMIT colorChanged(NLMISC::CRGBA(_ui.rSpinBox->value(), _ui.gSpinBox->value(), _ui.bSpinBox->value(), a)); + + if (_Wrapper == NULL) return; + + NLMISC::CRGBA color = _Wrapper->get(); + + if (a == color.A) + return; + + color.A = a; + _Wrapper->setAndUpdateModifiedFlag(color); +} + +void CColorEditWidget::browseColor() +{ + QColor color = QColorDialog::getColor(QColor(_ui.rSpinBox->value(), + _ui.gSpinBox->value(), + _ui.bSpinBox->value(), + _ui.aSpinBox->value())); + if (!color.isValid()) return; + + setColor(color); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/color_edit_widget.h b/code/nel/tools/3d/object_viewer_qt/src/color_edit_widget.h new file mode 100644 index 000000000..8cde0a2d3 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/color_edit_widget.h @@ -0,0 +1,101 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef COLOR_EDIT_WIDGET_H +#define COLOR_EDIT_WIDGET_H + +#include "ui_color_edit_form.h" + +// Qt includes + +// Project includes +#include "ps_wrapper.h" + +namespace NLQT { + +/** +@class CColorEditWidget +@brief The widget provides a 4 horizontal slider or color dialog, to set the color. +@details Using this widget you can set the color(RGBA) using the four sliders or through the color selection dialog. +Widget at the same time displays the color in the shaded rectangle at the side of the sliders. +Use this widget, have two ways: Qt Q_SIGNAL/SLOT or wrapper. + +1. Using the Qt Q_SIGNALS/SLOT can be set current color by class methods setColor() and +changes in current color(QSliders or QColorDialog) emits the signal colorChanged(). + +2. Using wrapper, create wpapper struct, example: +@code +struct CAmbientColorWrapper : public IPSWrapperRGBA +{ + NL3D::UScene *S; + void set(const NLMISC::CRGBA &col) { S->setSunAmbient(col); } + NLMISC::CRGBA get() const { return S->getSunAmbient(); } +} _AmbientColorWrapper; +@endcode +to set the current values, need call class methods updateUi(); +*/ +class CColorEditWidget: public QWidget +{ + Q_OBJECT + +public: + /// Constructor, sets the default color (255, 255, 255, 255) + CColorEditWidget(QWidget *parent = 0); + ~CColorEditWidget(); + + /// Sets the current color. + /// @param color - NeL NLMISC::CRGBA color + /// @param emit - will emit colorChanged() if the new value is different from the old one and param emit = true + void setColor(const NLMISC::CRGBA &color, bool emit = true); + + /// Sets the current color. + /// @param color - Qt QColor color + /// @param emit - will emit colorChanged() if the new value is different from the old one and param emit = true + void setColor(const QColor &color, bool emit = true); + + /// Set a wrapper to get/set the datas. + void setWrapper(IPSWrapperRGBA *wrapper); + + /// Update the content of the widget using the wrapper. + void updateUi(); + +Q_SIGNALS: + void colorChanged(NLMISC::CRGBA color); + +private Q_SLOTS: + void setRed(int r); + void setGreen(int g); + void setBlue(int b); + void setAlpha(int a); + void browseColor(); + +private: + + // wrapper to the datas + IPSWrapperRGBA *_Wrapper; + + bool _emit; + + Ui::CColorEditWidget _ui; + +}; /* class CColorEditWidget */ + +} /* namespace NLQT */ + +#endif // COLOR_EDIT_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/configuration.cpp b/code/nel/tools/3d/object_viewer_qt/src/configuration.cpp new file mode 100644 index 000000000..154f0244f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/configuration.cpp @@ -0,0 +1,222 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "configuration.h" + +// NeL includes +#include +#include +#include +#include + +#include "modules.h" + +using namespace std; +using namespace NLMISC; + +namespace NLQT { + +CConfiguration::CConfiguration() +{ + +} + +CConfiguration::~CConfiguration() +{ + +} + +void CConfiguration::init() +{ + nldebug("CConfiguration::init"); + + // verify data + nlassert(!ConfigCallbacks.size()); + + // load config + try + { + ConfigFile.load(NLQT_CONFIG_FILE); + } + catch(...) + { + nlerror("Error opening files object_viewer.cfg or object_viewer_default.cfg. Check this files"); + } + // setup config file callback + Modules::config().setCallback("SearchPaths", CConfigCallback(this, &CConfiguration::cfcbSearchPaths)); + +} + +void CConfiguration::release() +{ + nldebug("CConfiguration::release"); + + Modules::config().dropCallback("SearchPaths"); + + // save and release the config file + if (ConfigFile.exists("SaveConfig") && ConfigFile.getVarPtr("SaveConfig")->asBool()) + { + ConfigFile.save(); + } + ConfigFile.clear(); + + // release the search paths etc + CPath::releaseInstance(); + + // verify data + nlassert(!ConfigCallbacks.size()); +} + +void CConfiguration::updateUtilities() +{ + //H_AUTO2 + CConfigFile::checkConfigFiles(); +} + +void CConfiguration::configSearchPaths() +{ + cfcbSearchPaths(Modules::config().getConfigFile().getVar("SearchPaths")); +} + +void CConfiguration::configRemapExtensions() +{ + CConfigFile::CVar *var; + var = ConfigFile.getVarPtr("RemapExtensions"); + uint varsize = var->size(); + for (uint i = 0; i < varsize; i += 2) + CPath::remapExtension(var->asString(i), var->asString(i + 1), true); +} + +void CConfiguration::setAndCallback(const std::string &varName, CConfigCallback configCallback) +{ + ConfigCallbacks[varName] = configCallback; + ConfigFile.setCallback(varName, cbConfigCallback); + configCallback(*ConfigFile.getVarPtr(varName)); +} + +void CConfiguration::setCallback(const std::string &varName, CConfigCallback configCallback) +{ + ConfigCallbacks[varName] = configCallback; + ConfigFile.setCallback(varName, cbConfigCallback); +} + +void CConfiguration::dropCallback(const std::string &varName) +{ + ConfigFile.setCallback(varName, NULL); + ConfigCallbacks.erase(varName); +} + +float CConfiguration::getValue(const string &varName, float defaultValue) +{ + if (ConfigFile.exists(varName)) return ConfigFile.getVar(varName).asFloat(); + CConfigFile::CVar varToCopy; + varToCopy.forceAsDouble((double)defaultValue); + ConfigFile.insertVar(varName, varToCopy); + return defaultValue; +} + +double CConfiguration::getValue(const string &varName, double defaultValue) +{ + if (ConfigFile.exists(varName)) return ConfigFile.getVar(varName).asDouble(); + CConfigFile::CVar varToCopy; + varToCopy.forceAsDouble(defaultValue); + ConfigFile.insertVar(varName, varToCopy); + return defaultValue; +} + +int CConfiguration::getValue(const string &varName, int defaultValue) +{ + if (ConfigFile.exists(varName)) return ConfigFile.getVar(varName).asInt(); + CConfigFile::CVar varToCopy; + varToCopy.forceAsInt(defaultValue); + ConfigFile.insertVar(varName, varToCopy); + return defaultValue; +} + +string CConfiguration::getValue(const string &varName, const string &defaultValue) +{ + if (ConfigFile.exists(varName)) return ConfigFile.getVar(varName).asString(); + CConfigFile::CVar varToCopy; + varToCopy.forceAsString(defaultValue); + ConfigFile.insertVar(varName, varToCopy); + return defaultValue; +} + +ucstring CConfiguration::getValue(const string &varName, const ucstring &defaultValue) +{ + if (ConfigFile.exists(varName)) return ucstring::makeFromUtf8(ConfigFile.getVar(varName).asString()); + CConfigFile::CVar varToCopy; + varToCopy.forceAsString(defaultValue.toUtf8()); + ConfigFile.insertVar(varName, varToCopy); + return defaultValue; +} + +bool CConfiguration::getValue(const string &varName, bool defaultValue) +{ + if (ConfigFile.exists(varName)) return ConfigFile.getVar(varName).asBool(); + CConfigFile::CVar varToCopy; + varToCopy.forceAsInt(defaultValue ? 1 : 0); + ConfigFile.insertVar(varName, varToCopy); + return defaultValue; +} + +CRGBA CConfiguration::getValue(const string &varName, const CRGBA &defaultValue) +{ + if (ConfigFile.exists(varName)) + { + return getValue(ConfigFile.getVar(varName), defaultValue); + } + else + { + // create a new value only if one doesn't exist + CConfigFile::CVar varToCopy; + varToCopy.forceAsInt(defaultValue.R); + varToCopy.setAsInt(defaultValue.G, 1); + varToCopy.setAsInt(defaultValue.B, 2); + varToCopy.setAsInt(defaultValue.A, 3); + ConfigFile.insertVar(varName, varToCopy); + } + return defaultValue; +} + +CRGBA CConfiguration::getValue(const CConfigFile::CVar &var, const CRGBA &defaultValue) +{ + if (var.size() >= 3) + { + if (var.size() > 4) nlwarning("RGBA value in config value '%s' is too long, ignoring unused values"); + return CRGBA((uint8)var.asInt(0), (uint8)var.asInt(1), (uint8)var.asInt(2), var.size() >= 4 ? (uint8)var.asInt(3) : 255); + } + nlwarning("Invalid RGBA value in config value '%s', reverting to default { %i, %i, %i, %i }", var.Name.c_str(), (sint)defaultValue.R, (sint)defaultValue.G, (sint)defaultValue.B, (sint)defaultValue.A); + return defaultValue; +} + +void CConfiguration::cbConfigCallback(NLMISC::CConfigFile::CVar &var) +{ + Modules::config().ConfigCallbacks[var.Name](var); +} + +void CConfiguration::cfcbSearchPaths(NLMISC::CConfigFile::CVar &var) +{ + uint varsize = var.size(); + for (uint i = 0; i < varsize; ++i) + CPath::addSearchPath(var.asString(i), true, false); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/configuration.h b/code/nel/tools/3d/object_viewer_qt/src/configuration.h new file mode 100644 index 000000000..9e1765b9f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/configuration.h @@ -0,0 +1,93 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +#include + +// STL includes +#include + +// NeL includes +#include +#include +#include + +// Project includes +#include "callback.h" + +#define NLQT_CONFIG_FILE "object_viewer.cfg" + +namespace NLQT { + +typedef CCallback CConfigCallback; + +/** +@class CConfiguration +@date 2010-02-05 15:44GMT +@author Jan Boon (Kaetemi) +@brief Read / write settings from the configuration file +@details Load the configuration file, and then read/write settings. +As well as automatic reading of the search paths and their sets. +*/ +class CConfiguration +{ +public: + CConfiguration(); + virtual ~CConfiguration(); + + void init(); + void release(); + + void updateUtilities(); + void configSearchPaths(); + void configRemapExtensions(); + + void setAndCallback(const std::string &varName, CConfigCallback configCallback); + void setCallback(const std::string &varName, CConfigCallback configCallback); + void dropCallback(const std::string &varName); + + float getValue(const std::string &varName, float defaultValue); + double getValue(const std::string &varName, double defaultValue); + int getValue(const std::string &varName, int defaultValue); + std::string getValue(const std::string &varName, const std::string &defaultValue); + ucstring getValue(const std::string &varName, const ucstring &defaultValue); + bool getValue(const std::string &varName, bool defaultValue); + NLMISC::CRGBA getValue(const std::string &varName, const NLMISC::CRGBA &defaultValue); + NLMISC::CRGBA getValue(const NLMISC::CConfigFile::CVar &var, const NLMISC::CRGBA &defaultValue); + + inline NLMISC::CConfigFile &getConfigFile() { return ConfigFile; } + +private: + static void cbConfigCallback(NLMISC::CConfigFile::CVar &var); + + void cfcbSearchPaths(NLMISC::CConfigFile::CVar &var); + + CConfiguration(const CConfiguration &); + CConfiguration &operator=(const CConfiguration &); + + NLMISC::CConfigFile ConfigFile; + std::map ConfigCallbacks; + +};/* class CConfiguration */ + +} /* namespace NLQT */ + +#endif // CONFIGURATION_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/constraint_mesh_form.ui b/code/nel/tools/3d/object_viewer_qt/src/constraint_mesh_form.ui new file mode 100644 index 000000000..0a6ab1cde --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/constraint_mesh_form.ui @@ -0,0 +1,458 @@ + + + CConstraintMeshWidget + + + + 0 + 0 + 238 + 460 + + + + Form + + + + + + Force stage modulation + + + + + + Stage 0 + + + + + + + Stage 1 + + + + + + + Stage 2 + + + + + + + Stage 3 + + + + + + + + + + Force vertex color lighting + + + + + + + Qt::Horizontal + + + + + + + Texture anim type: + + + + + + + 1 + + + + None + + + + + Global + + + + + + + + Reinit when new element is created + + + + + + + Stage: + + + + + + + 3 + + + + + + + QTabWidget::South + + + 1 + + + true + + + + Translation + + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + + + + + V Start: + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + + + + + U Speed: + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + + + + + V Speed: + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + + + + + U Accel: + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + + + + + V Accel: + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + + + + + U Start: + + + + + + + + + + Scale + + + + + + + + U Start: + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + + + + + V Start: + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + + + + + U Speed: + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + + + + + V Speed: + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + + + + + U Accel: + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + + + + + V Accel: + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + + + + + + + + Rotation + + + + + + Speed: + + + + + + + 3 + + + -999999.000000000000000 + + + 9999999.000000000000000 + + + 1.000000000000000 + + + + + + + Accel: + + + + + + + 3 + + + -999999.000000000000000 + + + 999999.000000000000000 + + + 1.000000000000000 + + + + + + + Qt::Vertical + + + + 20 + 144 + + + + + + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/constraint_mesh_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/constraint_mesh_widget.cpp new file mode 100644 index 000000000..bd98f3329 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/constraint_mesh_widget.cpp @@ -0,0 +1,220 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "constraint_mesh_widget.h" + +// NeL includes +#include "nel/3d/ps_mesh.h" + +namespace NLQT { + +CConstraintMeshWidget::CConstraintMeshWidget(QWidget *parent ) + : QWidget(parent) +{ + _ui.setupUi(this); + + connect(_ui.stageCheckBox_0, SIGNAL(clicked(bool)), this, SLOT(setForceStage0(bool))); + connect(_ui.stageCheckBox_1, SIGNAL(clicked(bool)), this, SLOT(setForceStage1(bool))); + connect(_ui.stageCheckBox_2, SIGNAL(clicked(bool)), this, SLOT(setForceStage2(bool))); + connect(_ui.stageCheckBox_3, SIGNAL(clicked(bool)), this, SLOT(setForceStage3(bool))); + connect(_ui.vertexColorLightingCheckBox, SIGNAL(clicked(bool)), this, SLOT(setForceVertexColorLighting(bool))); + + connect(_ui.texAnimTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setTexAnimType(int))); + connect(_ui.reinitCheckBox, SIGNAL(toggled(bool)), this, SLOT(setReinitWhenNewElementIsCreated(bool))); + connect(_ui.stageSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setStage(int))); + + connectGlobalTexAnim(); +} + +CConstraintMeshWidget::~CConstraintMeshWidget() +{ +} + +void CConstraintMeshWidget::connectGlobalTexAnim() +{ + connect(_ui.transUStartDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + connect(_ui.transVStartDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + connect(_ui.transUSpeedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + connect(_ui.transVSpeedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + connect(_ui.transUAccelDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + connect(_ui.transVAccelDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + + connect(_ui.scaleUStartDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + connect(_ui.scaleVStartDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + connect(_ui.scaleUSpeedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + connect(_ui.scaleVSpeedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + connect(_ui.scaleUAccelDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + connect(_ui.scaleVAccelDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + + connect(_ui.rotSpeedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + connect(_ui.rotAccelDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); +} + +void CConstraintMeshWidget::disconnectGlobalTexAnim() +{ + disconnect(_ui.transUStartDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + disconnect(_ui.transVStartDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + disconnect(_ui.transUSpeedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + disconnect(_ui.transVSpeedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + disconnect(_ui.transUAccelDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + disconnect(_ui.transVAccelDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + + disconnect(_ui.scaleUStartDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + disconnect(_ui.scaleVStartDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + disconnect(_ui.scaleUSpeedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + disconnect(_ui.scaleVSpeedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + disconnect(_ui.scaleUAccelDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + disconnect(_ui.scaleVAccelDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + + disconnect(_ui.rotSpeedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); + disconnect(_ui.rotAccelDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setGlobalTexAnimValue())); +} + +void CConstraintMeshWidget::setCurrentConstraintMesh(CWorkspaceNode *ownerNode, NL3D::CPSConstraintMesh *cm) +{ + _Node = ownerNode; + _CM = cm; + + _ui.stageCheckBox_0->setChecked(_CM->isStageModulationForced(0)); + _ui.stageCheckBox_1->setChecked(_CM->isStageModulationForced(1)); + _ui.stageCheckBox_2->setChecked(_CM->isStageModulationForced(2)); + _ui.stageCheckBox_3->setChecked(_CM->isStageModulationForced(3)); + _ui.vertexColorLightingCheckBox->setChecked(_CM->isVertexColorLightingForced()); + + _ui.texAnimTypeComboBox->setCurrentIndex(_CM->getTexAnimType()); + if (_CM->getTexAnimType() == NL3D::CPSConstraintMesh::GlobalAnim) + { + _ui.reinitCheckBox->setChecked(_CM->isGlobalAnimTimeResetOnNewElementForced()); + updateGlobalTexAnim(0); + } +} + +void CConstraintMeshWidget::setForceStage0(bool state) +{ + _CM->forceStageModulationByColor(0, state); +} + +void CConstraintMeshWidget::setForceStage1(bool state) +{ + _CM->forceStageModulationByColor(1, state); +} + +void CConstraintMeshWidget::setForceStage2(bool state) +{ + _CM->forceStageModulationByColor(2, state); +} + +void CConstraintMeshWidget::setForceStage3(bool state) +{ + _CM->forceStageModulationByColor(3, state); +} + +void CConstraintMeshWidget::setForceVertexColorLighting(bool state) +{ + _CM->forceVertexColorLighting(state); +} + +void CConstraintMeshWidget::setTexAnimType(int index) +{ + switch(index) + { + case 0: // no anim + _CM->setTexAnimType(NL3D::CPSConstraintMesh::NoAnim); + _ui.stageSpinBox->hide(); + _ui.stageLabel->hide(); + _ui.tabWidget->hide(); + _ui.reinitCheckBox->hide(); + break; + case 1: // global anim + _CM->setTexAnimType(NL3D::CPSConstraintMesh::GlobalAnim); + _ui.stageSpinBox->show(); + _ui.stageLabel->show(); + _ui.tabWidget->show(); + _ui.reinitCheckBox->show(); + _ui.stageSpinBox->setValue(0); + _ui.reinitCheckBox->setChecked(_CM->isGlobalAnimTimeResetOnNewElementForced()); + break; + default: + nlstop; + break; + } +} + +void CConstraintMeshWidget::setReinitWhenNewElementIsCreated(bool state) +{ + _CM->forceGlobalAnimTimeResetOnNewElement(state); +} + +void CConstraintMeshWidget::setStage(int value) +{ + updateGlobalTexAnim(value); +} + +void CConstraintMeshWidget::updateGlobalTexAnim(int value) +{ + disconnectGlobalTexAnim(); + + const NL3D::CPSConstraintMesh::CGlobalTexAnim >a = _CM->getGlobalTexAnim(value); + + _ui.transUStartDoubleSpinBox->setValue(gta.TransOffset.x); + _ui.transVStartDoubleSpinBox->setValue(gta.TransOffset.y); + _ui.transUSpeedDoubleSpinBox->setValue(gta.TransSpeed.x); + _ui.transVSpeedDoubleSpinBox->setValue(gta.TransSpeed.y); + _ui.transUAccelDoubleSpinBox->setValue(gta.TransAccel.x); + _ui.transVAccelDoubleSpinBox->setValue(gta.TransAccel.y); + + _ui.scaleUStartDoubleSpinBox->setValue(gta.ScaleStart.x); + _ui.scaleVStartDoubleSpinBox->setValue(gta.ScaleStart.y); + _ui.scaleUSpeedDoubleSpinBox->setValue(gta.ScaleSpeed.x); + _ui.scaleVSpeedDoubleSpinBox->setValue(gta.ScaleSpeed.y); + _ui.scaleUAccelDoubleSpinBox->setValue(gta.ScaleAccel.x); + _ui.scaleVAccelDoubleSpinBox->setValue(gta.ScaleAccel.y); + + _ui.rotSpeedDoubleSpinBox->setValue(gta.WRotSpeed); + _ui.rotAccelDoubleSpinBox->setValue(gta.WRotAccel); + + connectGlobalTexAnim(); +} + +void CConstraintMeshWidget::setGlobalTexAnimValue() +{ + NL3D::CPSConstraintMesh::CGlobalTexAnim gta; + + gta.TransOffset.x = _ui.transUStartDoubleSpinBox->value(); + gta.TransOffset.y = _ui.transVStartDoubleSpinBox->value(); + gta.TransSpeed.x = _ui.transUSpeedDoubleSpinBox->value(); + gta.TransSpeed.y = _ui.transVSpeedDoubleSpinBox->value(); + gta.TransAccel.x = _ui.transUAccelDoubleSpinBox->value(); + gta.TransAccel.y = _ui.transVAccelDoubleSpinBox->value(); + + gta.ScaleStart.x = _ui.scaleUStartDoubleSpinBox->value(); + gta.ScaleStart.y = _ui.scaleVStartDoubleSpinBox->value(); + gta.ScaleSpeed.x = _ui.scaleUSpeedDoubleSpinBox->value(); + gta.ScaleSpeed.y = _ui.scaleVSpeedDoubleSpinBox->value(); + gta.ScaleAccel.x = _ui.scaleUAccelDoubleSpinBox->value(); + gta.ScaleAccel.y = _ui.scaleVAccelDoubleSpinBox->value(); + + gta.WRotSpeed = _ui.rotSpeedDoubleSpinBox->value(); + gta.WRotAccel = _ui.rotAccelDoubleSpinBox->value(); + + _CM->setGlobalTexAnim(_ui.stageSpinBox->value(), gta); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/constraint_mesh_widget.h b/code/nel/tools/3d/object_viewer_qt/src/constraint_mesh_widget.h new file mode 100644 index 000000000..0a7ff91d4 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/constraint_mesh_widget.h @@ -0,0 +1,80 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef CONSTRAINT_MESH_WIDGET_H +#define CONSTRAINT_MESH_WIDGET_H + +#include "ui_constraint_mesh_form.h" + +// STL includes + +// Qt includes + +// NeL includes + +// Project includes +#include "particle_node.h" + +namespace NL3D { + class CPSConstraintMesh; +} + +namespace NLQT { + +/** +@class CConstraintMeshWidget +@brief Widget for setup mesh that have very simple geometry. +*/ +class CConstraintMeshWidget: public QWidget +{ + Q_OBJECT + +public: + CConstraintMeshWidget(QWidget *parent = 0); + ~CConstraintMeshWidget(); + + /// Set the constraint mesh to edit. + void setCurrentConstraintMesh(CWorkspaceNode *ownerNode, NL3D::CPSConstraintMesh *cm); + +private Q_SLOTS: + void setForceStage0(bool state); + void setForceStage1(bool state); + void setForceStage2(bool state); + void setForceStage3(bool state); + void setForceVertexColorLighting(bool state); + void setTexAnimType(int index); + void setReinitWhenNewElementIsCreated(bool state); + void setStage(int value); + void setGlobalTexAnimValue(); + +private: + void connectGlobalTexAnim(); + void disconnectGlobalTexAnim(); + void updateGlobalTexAnim(int value); + + CWorkspaceNode *_Node; + + NL3D::CPSConstraintMesh *_CM; + + Ui::CConstraintMeshWidget _ui; +}; /* class CConstraintMeshWidget */ + +} /* namespace NLQT */ + +#endif // CONSTRAINT_MESH_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/curve_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/curve_dialog.cpp new file mode 100644 index 000000000..a7c008d01 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/curve_dialog.cpp @@ -0,0 +1,158 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "curve_dialog.h" + +// Project includes +#include "particle_node.h" + +namespace NLQT { + +CurveEditDialog::CurveEditDialog(NL3D::CPSFloatCurveFunctor *curve, CWorkspaceNode *ownerNode, QWidget *parent) + : QDialog(parent) , _Curve(curve), _scale(1.0), _pos(0.0), _Node(ownerNode) +{ + _ui.setupUi(this); + + show(); + _hoverPoints = new HoverPoints(_ui.curveWidget, HoverPoints::CircleShape); + + if (_Curve->hasSmoothing()) + _hoverPoints->setConnectionType(HoverPoints::CurveConnection); + else + _hoverPoints->setConnectionType(HoverPoints::LineConnection); + + _ui.smoothingCheckBox->setChecked(_Curve->hasSmoothing()); + + buildPoints(); + + _hoverPoints->setSortType(HoverPoints::XSort); + _hoverPoints->setShapePen(QPen(QColor(0, 0, 100, 127), 1)); + _hoverPoints->setShapeBrush(QBrush(QColor(0, 0, 200, 127))); + _hoverPoints->setConnectionPen(QPen(QColor(0, 0, 0, 127), 1)); + + // FLOAT_CURVE_NB_SAMPLE + _ui.numSamplesWidget->setRange(1, 512); + _ui.numSamplesWidget->enableLowerBound(1, true); + _ui.numSamplesWidget->setValue(_Curve->getNumSamples()); + + connect(_ui.smoothingCheckBox, SIGNAL(toggled(bool)), this, SLOT(setSmoothing(bool))); + connect(_hoverPoints, SIGNAL(pointsChanged(QPolygonF)), this, SLOT(curveChanged(QPolygonF))); + connect(_ui.posVerticalSlider, SIGNAL(valueChanged(int)), this, SLOT(setPosition(int))); + connect(_ui.sizeVerticalSlider, SIGNAL(valueChanged(int)), this, SLOT(setScale(int))); + connect(_ui.firstLastPushButton, SIGNAL(clicked()), this, SLOT(setLastTiFirst())); + connect(_ui.lastFirstPushButton, SIGNAL(clicked()), this, SLOT(setFirstToLast())); + connect(_ui.centerToolButton, SIGNAL(clicked()), this, SLOT(setCenter())); + connect(_ui.numSamplesWidget, SIGNAL(valueChanged(uint32)), this, SLOT(setNumSamples(uint32))); + //setCenter(); +} + +CurveEditDialog::~CurveEditDialog() +{ +} + +void CurveEditDialog::setSmoothing(bool state) +{ + if (state) + _hoverPoints->setConnectionType(HoverPoints::CurveConnection); + else + _hoverPoints->setConnectionType(HoverPoints::LineConnection); + + _Curve->enableSmoothing(state); + + _ui.curveWidget->update(); +} + +void CurveEditDialog::setDisplayInterpolation(bool state) +{ +} + +void CurveEditDialog::curveChanged(const QPolygonF &points) +{ + if (_Curve->getNumCtrlPoints() > uint(points.size())) + _Curve->removeCtrlPoint(0); + else if (_Curve->getNumCtrlPoints() < uint(points.size())) + _Curve->addControlPoint(NL3D::CPSFloatCurveFunctor::CCtrlPoint(1, 0.5f)); + for (int i = 0; i < points.size(); i++) + _Curve->setCtrlPoint(uint(i), NL3D::CPSFloatCurveFunctor::CCtrlPoint(points.at(i).x() / _ui.curveWidget->width(), + (_ui.curveWidget->height() - points.at(i).y() + _pos) / (_ui.curveWidget->height() * _scale))); +} + +void CurveEditDialog::setScale(int value) +{ + _scale = value / float(_ui.sizeVerticalSlider->maximum() / 2); + buildPoints(); + _ui.curveWidget->update(); +} + +void CurveEditDialog::setPosition(int value) +{ + _pos = (value - (_ui.posVerticalSlider->maximum() / 2)); + buildPoints(); + _ui.curveWidget->update(); +} + +void CurveEditDialog::setCenter() +{ + float maxValue = _Curve->getMaxValue(); + float minValue = _Curve->getMinValue(); + float fScale = (maxValue == minValue) ? 1.f : 1.f / (maxValue - minValue); + int iScale = int(fScale * _ui.sizeVerticalSlider->maximum() / 2); + _ui.sizeVerticalSlider->setValue(iScale); + int pos = _ui.curveWidget->height() - (_scale * maxValue * _ui.curveWidget->height()); + _ui.posVerticalSlider->setValue((_ui.posVerticalSlider->maximum() / 2) - pos); +} + +void CurveEditDialog::setLastTiFirst() +{ + NL3D::CPSFloatCurveFunctor::CCtrlPoint pt = _Curve->getControlPoint(_Curve->getNumCtrlPoints() - 1); + pt.Date = _Curve->getControlPoint(0).Date; + _Curve->setCtrlPoint(0, pt); + buildPoints(); + _ui.curveWidget->update(); +} + +void CurveEditDialog::setFirstToLast() +{ + NL3D::CPSFloatCurveFunctor::CCtrlPoint pt = _Curve->getControlPoint(0); + pt.Date = _Curve->getControlPoint(_Curve->getNumCtrlPoints() - 1).Date; + _Curve->setCtrlPoint(_Curve->getNumCtrlPoints() - 1, pt); + buildPoints(); + _ui.curveWidget->update(); +} + +void CurveEditDialog::setNumSamples(uint32 value) +{ + _Curve->setNumSamples(value); +} + +void CurveEditDialog::buildPoints() +{ + QPolygonF points; + for (uint i = 0; i < _Curve->getNumCtrlPoints(); i++) + points << QPointF((_Curve->getControlPoint(i).Date * _ui.curveWidget->width()), + _pos + _ui.curveWidget->height() - (_scale * _Curve->getControlPoint(i).Value * _ui.curveWidget->height())); + + _hoverPoints->setPoints(points); + //_hoverPoints->setPointLock(0, HoverPoints::LockToLeft); + //_hoverPoints->setPointLock(points.size() - 1, HoverPoints::LockToRight); + +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/curve_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/curve_dialog.h new file mode 100644 index 000000000..6f113c843 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/curve_dialog.h @@ -0,0 +1,83 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef CURVE_DIALOG_H +#define CURVE_DIALOG_H + +#include +#include "ui_curve_form.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include + +// Project includes +#include "hoverpoints.h" +#include "ps_wrapper.h" + +namespace NLQT { +/** +@class CurveEditDialog +@brief Dialogue editing graphics curve. +@details Adding / removing control points, scaling and moving graphics curve. +The choice of the interpolation algorithm. +*/ +class CurveEditDialog : public QDialog +{ + Q_OBJECT + +public: + CurveEditDialog(NL3D::CPSFloatCurveFunctor *curve, CWorkspaceNode *ownerNode, QWidget *parent = 0); + ~CurveEditDialog(); + + /// the scheme being edited + NL3D::CPSFloatCurveFunctor *_Curve; + +private Q_SLOTS: + void setSmoothing(bool state); + void setDisplayInterpolation(bool state); + void curveChanged(const QPolygonF &points); + void setScale(int value); + void setPosition(int value); + void setCenter(); + void setLastTiFirst(); + void setFirstToLast(); + void setNumSamples(uint32 value); + +protected: + void buildPoints(); + + float _scale; + float _pos; + + CWorkspaceNode *_Node; + + HoverPoints *_hoverPoints; + + Ui::CurveEditDialog _ui; +}; /* CurveEditDialog */ + +} /* namespace NLQT */ + +#endif // CURVE_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/curve_form.ui b/code/nel/tools/3d/object_viewer_qt/src/curve_form.ui new file mode 100644 index 000000000..5825da66c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/curve_form.ui @@ -0,0 +1,253 @@ + + + CurveEditDialog + + + + 0 + 0 + 528 + 478 + + + + Curve edit + + + true + + + + + + + 0 + 0 + + + + Left click to add points. +Right click to remove points. + + + false + + + + + + + + + Zoom: + + + + + + + Scale curve + + + 10000 + + + 1000 + + + 5000 + + + Qt::Horizontal + + + true + + + false + + + QSlider::TicksBelow + + + 1000 + + + + + + + Translate: + + + + + + + Position curve + + + 5000 + + + 500 + + + 2500 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 500 + + + + + + + + + Num samples: + + + + + + + false + + + + 32 + 32 + + + + + 32 + 32 + + + + + + + + :/images/refresh.png:/images/refresh.png + + + true + + + + + + + + + + + + + 0 + 0 + + + + Last=First + + + + + + + + 0 + 0 + + + + First=Last + + + + + + + false + + + Display interpolation + + + + + + + Smoothing + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + Ok + + + + + + + + + + NLQT::CEditRangeUIntWidget + QWidget +
edit_range_widget.h
+ 1 +
+
+ + + + + + pushButton + clicked() + CurveEditDialog + accept() + + + 463 + 401 + + + 373 + 402 + + + + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/day_night_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/day_night_dialog.cpp new file mode 100644 index 000000000..292e05a14 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/day_night_dialog.cpp @@ -0,0 +1,48 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "day_night_dialog.h" + +// NeL incldes +#include "nel/3d/u_water.h" + +// Project includes +#include "modules.h" + +namespace NLQT { + +CDayNightDialog::CDayNightDialog(QWidget *parent) + : QDockWidget(parent) +{ + _ui.setupUi(this); + + connect(_ui.horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setDayNight(int))); +} + +CDayNightDialog::~CDayNightDialog() +{ +} + +void CDayNightDialog::setDayNight(int value) +{ + NL3D::UWaterHeightMapManager::setBlendFactor(Modules::objView().getDriver(), float(value) / _ui.horizontalSlider->maximum()); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/day_night_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/day_night_dialog.h new file mode 100644 index 000000000..e7f382076 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/day_night_dialog.h @@ -0,0 +1,56 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef DAY_NIGHT_DIALOG_H +#define DAY_NIGHT_DIALOG_H + +#include "ui_day_night_form.h" + +// STL includes + +// NeL includes + +// Project includes + +namespace NLQT { + +/** +@class CDayNightDialog +@brief Dialog set time of day. +@details Dialogue only affects the water shape. +*/ +class CDayNightDialog: public QDockWidget +{ + Q_OBJECT + +public: + CDayNightDialog(QWidget *parent = 0); + ~CDayNightDialog(); + +private Q_SLOTS: + void setDayNight(int value); + +private: + + Ui::CDayNightDialog _ui; +}; /* class CDayNightDialog */ + +} /* namespace NLQT */ + +#endif // DAY_NIGHT_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/day_night_form.ui b/code/nel/tools/3d/object_viewer_qt/src/day_night_form.ui new file mode 100644 index 000000000..c3508db12 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/day_night_form.ui @@ -0,0 +1,47 @@ + + + CDayNightDialog + + + + 0 + 0 + 228 + 59 + + + + Day/Night + + + + + + + Day + + + + + + + 100 + + + Qt::Horizontal + + + + + + + Night + + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/description.h b/code/nel/tools/3d/object_viewer_qt/src/description.h new file mode 100644 index 000000000..f1e3fc8a7 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/description.h @@ -0,0 +1,145 @@ +/** +@mainpage Object Viewer Qt +@author Dzmitry Kamiahin , (C) 2010 + +@section introduce Introduce +@details +The Object Viewer Qt (ovqt) is a tool for working with graphics technology NeL data, +which can be useful durung the development and preparation of the game content. +The tool can be used in different tasks: +- Loading and viewing NeL data (.shape, .ps) files with the ability to set wind power, color light. +- Viewing animation shape (loading .anim, .skel, .swt files) using playlist or slot manager(mixing animation). +- Create and modify NeL particle system. +- Viewing water shape with the ability to set day/night. +- Modify skeleton (.skel files, .scale file). +- Create and modify micro-vegetation material (.vegetset files) +- Viewing landscape (.zonel files) +- Dialog allows to specify graphical, sound, search path and landscape settings. + +@section project_structure Overview of the Object Viewer Qt Project Structure +@details +OVQT - consists of several major subsystems. Each subsystem performs its defined part of the task. +Through Modules:: provides access to all other program subsystems. + +Program has the following subsystems: +- @ref Modules - Main modules aggregated all parts of the program. +- @ref NLQT::CConfiguration - is responsible for loading and saving settings from the configuration file. As well as search path of data. +- @ref NLQT::CObjectViewer - main subsystem of the program, which initializes the driver, creates a scene and other supporting elements. +It is a container for loaded models, which can further be viewed and animated. +- @ref NLQT::CMainWindow - is responsible for the GUI. +- @ref NLQT::CParticleEditor - is responsible for the particle systems and provides access to a container that keeps all the loaded particle systems. +And also allows you to view an animation of particle systems, with the ability to control its parameters. +- @ref NLQT::CVegetableEditor - is responsible for the landscape zones and the editor of vegetation. +Allows you to load and view the landscape. Also has the ability to create and edit the parameters of the micro-vegetation. +- @ref NLQT::CSoundSystem - is responsible for the sound in the program. + + +The structure of the GUI in the editor of the particles. +
+This can be useful for new developers who want to add more new dialogs or to improve the functionality of existing dialogues. +Particle Workspace +ParticleWorkspace dialogue uses the technique of model-view. +Using the signal/slot link QTreeView with QStackWidget, Editor properties dialog. +When you select an item in QTreeView, QStackWidget displays the necessary page(PageWidget) where you can edit the element of the particles system. +Each page is made in the designer and has a separate forms(.ui). +In accordance with the recommendations of dialogues design, with a large number of items,every page uses QTabWidget. +In case when there is a great number of controls, and not everything you want to display, +it's used the dynamic creation of tabs. Moreover, each tab uses a separate forms(.ui). + +@section for_new_developer Guide for new developers of the Object Viewer Qt. +@details + First of all, to begin developing dialogues that add new features ovqt, +it is needed to read the documentation Qt libs (http://doc.qt.nokia.com/) and NeL documentation. + + In order to have convenient using of the tool and its further development, +it is expected to make a unified interface that is why all dialogs should adhere to a standard design, +which will be written further. For this goals program provides some additional widgets, +which are recommended to use. As in the development Qt Designer is actively used. +To get access to founded here widgets from the designer,the technique promotion is used, +which can be found here . +
    +
  1. +CEditRangeUIntWidget / CEditRangeIntWidget / CEditRangeFloatWidget +
    +Widgets provides a slider that allows you to specify an integer (or float, depending on which widget used) number within a set range. +The range is also can be set by the user, or for a more accurate selection of numbers, either for receiving large values. +As there may be situations when the range that a user requests,has to be restricted, and widget provides methods that allow you to do so. +

    +CEditRangeIntWidget +
    +CEditRangeFloatWidget +@see +@ref NLQT::CEditRangeUIntWidget, @ref NLQT::CEditRangeIntWidget, @ref NLQT::CEditRangeFloatWidget + +
  2. +CColorEditWidget +
    +Using this widget you can set the color(RGBA) using the four sliders or through the color selection dialog. +

    +CColorEditWidget +@see +@ref NLQT::CColorEditWidget + +
  3. +CDirectionWidget +
    +This widget helps to choose from several preset directions, or to choose a custom one. +To use it you have to create a wrapper. +

    +CDirectionWidget +@see +@ref NLQT::CDirectionWidget +


+ +To further convinience of instrument using dialogues interface is recommended to make as follows. +The most sophisticated tools of the program, should take the form of three dock windows (example shown in the screenshot). +Object Viewer Qt +
    +
  1. +The first dock window - is a control dock window, it should focus all of the control functions of general purpose +(for example: start/stop/pause animations or particles system). +It is recommended to perform of the horizontal type window and placed in the bottom of the main window. +
  2. +The second dock window - is a list or a tree of items. In which selecting of the current element, +which assumes to modify or viewis possible.Operations "add/remove/insert or other" items are recommended to make as a popur menu. +It is recommended to perform of the vertical type window and placed in the left of the main window. +
  3. +The third dock - is an editor for properties of the element that was selected in the list or in the tree of elements. +As all the controls occupy much space or do not fit at all, you have to use tabs QTabWidget, +which in total can contains quite a lot of elements. +For a small number of tabs it is allowed to use both horizontal and vertical location. +But with a large number of tabs, it is necessary to apply the vertical arrangement. +It is recommended to perform of the vertical type of window and placed in the right of the main window. +
+In the simple dialogues do not necessary to use all three windows, but user has to adhere to the recommendations given above as well. +Also, all dialogs must use the qt layout manager. And if you do not use the designer, +make sure you use the qt tools internationalization applications. +

+In ovqt for most dialogs their owner is NLQT::CMainWindow and in its methods creating and initializing all dependent dialogs occur. +For the convenience of the program using, most dialogues are created in the form of docking windows. +Creating all the dialogues are carried out in a private method NLQT::CMainWindow::createDialogs(). +Hence, it is necessary to add operations in this method to create new dialogues. +But we must take into account that at this moment is fully available only one component of the program CConfiguration, +to read the settings from the configuration file. The remaining components of the program are available only after the main window stays visible. +Calling the dialogues going through the menu or the toolbar, usually it is a checkable item. +Adding of the new menu items or items toolbars is need in methods NLQT::CMainWindow::createMenus(), NLQT::CMainWindow::createToolBars(). + +@section license_ovqt License Object Viewer Qt +@details + Object Viewer Qt +
+ Copyright (C) 2010 Dzmitry Kamiahin +

+ This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. +

+ You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/direction_form.ui b/code/nel/tools/3d/object_viewer_qt/src/direction_form.ui new file mode 100644 index 000000000..f04c7302b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/direction_form.ui @@ -0,0 +1,178 @@ + + + CDirectionWidget + + + + 0 + 0 + 268 + 101 + + + + Form + + + + + + Direction: + + + + + + + + 30 + 16777215 + + + + +I + + + + + + + + 30 + 16777215 + + + + +J + + + + + + + + 30 + 16777215 + + + + +K + + + + + + + + 0 + 0 + + + + + 75 + 75 + + + + + 75 + 75 + + + + + + + + + 0 + 0 + + + + + 75 + 75 + + + + + 75 + 75 + + + + + + + + Qt::Horizontal + + + + 0 + 49 + + + + + + + + + 30 + 16777215 + + + + -I + + + + + + + + 30 + 16777215 + + + + -J + + + + + + + + 30 + 16777215 + + + + -K + + + + + + + Global + + + + + + + + NLQT::CGraphicsInfoWidget + QWidget +
graphics_info_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/direction_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/direction_widget.cpp new file mode 100644 index 000000000..49521fb15 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/direction_widget.cpp @@ -0,0 +1,217 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "direction_widget.h" + +// Qt includes +#include + +// NeL includes +#include +#include + +namespace NLQT { + +CDirectionWidget::CDirectionWidget(QWidget *parent) + : QWidget(parent), _Wrapper(NULL), _DirectionWrapper(NULL) +{ + _ui.setupUi(this); + + _ui.xzWidget->setMode(Mode::Direction); + _ui.yzWidget->setMode(Mode::Direction); + _ui.xzWidget->setText("XZ"); + _ui.yzWidget->setText("YZ"); + _ui.globalPushButton->hide(); + + connect(_ui.globalPushButton ,SIGNAL(clicked()), this, SLOT(setGlobalDirection())); + connect(_ui.incVecIPushButton ,SIGNAL(clicked()), this, SLOT(incVecI())); + connect(_ui.incVecJPushButton ,SIGNAL(clicked()), this, SLOT(incVecJ())); + connect(_ui.incVecKPushButton ,SIGNAL(clicked()), this, SLOT(incVecK())); + connect(_ui.decVecIPushButton ,SIGNAL(clicked()), this, SLOT(decVecI())); + connect(_ui.decVecJPushButton ,SIGNAL(clicked()), this, SLOT(decVecJ())); + connect(_ui.decVecKPushButton ,SIGNAL(clicked()), this, SLOT(decVecK())); + + connect(_ui.xzWidget, SIGNAL(applyNewVector(float,float)), this, SLOT(setNewVecXZ(float,float))); + connect(_ui.yzWidget, SIGNAL(applyNewVector(float,float)), this, SLOT(setNewVecYZ(float,float))); +} + +CDirectionWidget::~CDirectionWidget() +{ +} + + +void CDirectionWidget::setWrapper(IPSWrapper *wrapper) +{ + _Wrapper = wrapper; + _ui.globalPushButton->hide(); +} + +void CDirectionWidget::setDirectionWrapper(NL3D::CPSDirection *wrapper) +{ + _DirectionWrapper = wrapper; + if (_DirectionWrapper && _DirectionWrapper->supportGlobalVectorValue()) + _ui.globalPushButton->show(); + else + _ui.globalPushButton->hide(); +} + +void CDirectionWidget::updateUi() +{ + _ui.xzWidget->setVector(_Wrapper->get().x, _Wrapper->get().z); + _ui.yzWidget->setVector(_Wrapper->get().y, _Wrapper->get().z); + _ui.xzWidget->repaint(); + _ui.yzWidget->repaint(); + + checkEnabledGlobalDirection(); +} + +void CDirectionWidget::setGlobalDirection() +{ + nlassert(_DirectionWrapper); + + bool ok; + QString text = QInputDialog::getText(this, tr("Enter Name"), + "", QLineEdit::Normal, + QString(_DirectionWrapper->getGlobalVectorValueName().c_str()), &ok); + + if (ok) + { + _DirectionWrapper->enableGlobalVectorValue(text.toStdString()); + if (!text.isEmpty()) + { + // take a non NULL value for the direction + NL3D::CParticleSystem::setGlobalVectorValue(text.toStdString(), NLMISC::CVector::I); + } + checkEnabledGlobalDirection(); + } +} + +void CDirectionWidget::incVecI() +{ + _Wrapper->setAndUpdateModifiedFlag(NLMISC::CVector::I); + _ui.xzWidget->setVector(NLMISC::CVector::I.x, NLMISC::CVector::I.z); + _ui.yzWidget->setVector(NLMISC::CVector::I.y, NLMISC::CVector::I.z); +} + +void CDirectionWidget::incVecJ() +{ + _Wrapper->setAndUpdateModifiedFlag(NLMISC::CVector::J); + _ui.xzWidget->setVector(NLMISC::CVector::J.x, NLMISC::CVector::J.z); + _ui.yzWidget->setVector(NLMISC::CVector::J.y, NLMISC::CVector::J.z); +} + +void CDirectionWidget::incVecK() +{ + _Wrapper->setAndUpdateModifiedFlag(NLMISC::CVector::K); + _ui.xzWidget->setVector(NLMISC::CVector::K.x, NLMISC::CVector::K.z); + _ui.yzWidget->setVector(NLMISC::CVector::K.y, NLMISC::CVector::K.z); +} + +void CDirectionWidget::decVecI() +{ + _Wrapper->setAndUpdateModifiedFlag( - NLMISC::CVector::I); + _ui.xzWidget->setVector((-NLMISC::CVector::I).x, (-NLMISC::CVector::I).z); + _ui.yzWidget->setVector((-NLMISC::CVector::I).y, (-NLMISC::CVector::I).z); +} + +void CDirectionWidget::decVecJ() +{ + _Wrapper->setAndUpdateModifiedFlag( - NLMISC::CVector::J); + _ui.xzWidget->setVector((-NLMISC::CVector::J).x, (-NLMISC::CVector::J).z); + _ui.yzWidget->setVector((-NLMISC::CVector::J).y, (-NLMISC::CVector::J).z); +} + +void CDirectionWidget::decVecK() +{ + _Wrapper->setAndUpdateModifiedFlag( - NLMISC::CVector::K); + _ui.xzWidget->setVector((-NLMISC::CVector::K).x, (-NLMISC::CVector::K).z); + _ui.yzWidget->setVector((-NLMISC::CVector::K).y, (-NLMISC::CVector::K).z); +} + +void CDirectionWidget::setNewVecXZ(float x, float y) +{ + const float epsilon = 10E-3f; + NLMISC::CVector v = _Wrapper->get(); + + v.x = x; + v.z = y; + + float d = v.x * v.x + v.z * v.z; + float f; + if (fabs(d) > epsilon) + f = sqrt((1.f - v.y * v.y) / d); + else + f = 1; + + v.x *= f; + v.z *= f; + + v.normalize(); + + _Wrapper->setAndUpdateModifiedFlag(v); + _ui.xzWidget->setVector(_Wrapper->get().x, _Wrapper->get().z); + _ui.yzWidget->setVector(_Wrapper->get().y, _Wrapper->get().z); +} + +void CDirectionWidget::setNewVecYZ(float x, float y) +{ + const float epsilon = 10E-3f; + NLMISC::CVector v = _Wrapper->get(); + + v.y = x; + v.z = y; + + float d = v.y * v.y + v.z * v.z; + float f; + if (fabs(d) > epsilon) + f = sqrt((1.f - v.x * v.x) / d); + else + f = 1; + + v.y *= f; + v.z *= f; + + v.normalize(); + + _Wrapper->setAndUpdateModifiedFlag(v); + _ui.xzWidget->setVector(_Wrapper->get().x, _Wrapper->get().z); + _ui.yzWidget->setVector(_Wrapper->get().y, _Wrapper->get().z); +} + +void CDirectionWidget::checkEnabledGlobalDirection() +{ + bool enableUserDirection = true; + _ui.xzWidget->show(); + _ui.yzWidget->show(); + if (_DirectionWrapper && _DirectionWrapper->supportGlobalVectorValue() && !_DirectionWrapper->getGlobalVectorValueName().empty()) + { + enableUserDirection = false; + _ui.xzWidget->hide(); + _ui.yzWidget->hide(); + } + _ui.incVecIPushButton->setEnabled(enableUserDirection); + _ui.incVecJPushButton->setEnabled(enableUserDirection); + _ui.incVecKPushButton->setEnabled(enableUserDirection); + _ui.decVecIPushButton->setEnabled(enableUserDirection); + _ui.decVecJPushButton->setEnabled(enableUserDirection); + _ui.decVecKPushButton->setEnabled(enableUserDirection); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/direction_widget.h b/code/nel/tools/3d/object_viewer_qt/src/direction_widget.h new file mode 100644 index 000000000..3125bfe38 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/direction_widget.h @@ -0,0 +1,78 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef DIRECTION_WIDGET_H +#define DIRECTION_WIDGET_H + +#include "ui_direction_form.h" + +// STL includes + +// NeL includes +#include + +// Project includes +#include "ps_wrapper.h" + +namespace NLQT { + +/** +@class CDirectionWidget +@brief This widget helps to choose from several preset directions, or to choose a custom one. +@details This also allow to bind the direction to a global variable when it is supported + */ +class CDirectionWidget: public QWidget +{ + Q_OBJECT + +public: + CDirectionWidget(QWidget *parent = 0); + ~CDirectionWidget(); + + void setWrapper(IPSWrapper *wrapper); + + /// The CPSDirection object is used to see if a global variable can be bound to the direction. + /// When set to NULL it has no effect (the default) + void setDirectionWrapper(NL3D::CPSDirection *wrapper); + void updateUi(); + +private Q_SLOTS: + void setGlobalDirection(); + void incVecI(); + void incVecJ(); + void incVecK(); + void decVecI(); + void decVecJ(); + void decVecK(); + void setNewVecXZ(float x, float y); + void setNewVecYZ(float x, float y); + +private: + void checkEnabledGlobalDirection(); + + IPSWrapper *_Wrapper ; + NL3D::CPSDirection *_DirectionWrapper; + + Ui::CDirectionWidget _ui; + +}; /* class CDirectionWidget */ + +} /* namespace NLQT */ + +#endif // DIRECTION_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/dup_ps.cpp b/code/nel/tools/3d/object_viewer_qt/src/dup_ps.cpp new file mode 100644 index 000000000..91e0c1609 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/dup_ps.cpp @@ -0,0 +1,161 @@ +// NeL - MMORPG Framework +// 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 . + +#include "stdpch.h" + +#include "nel/3d/ps_located.h" +#include "nel/3d/particle_system.h" + + +#include "nel/misc/stream.h" +#include "nel/misc/mem_stream.h" + +#include "dup_ps.h" + +#include + +using namespace NL3D; + +//======================================================================= + + + +/** This can duplicate any serializable type by using a serialization policy (polymorphic, non polymorphic ..) + * The serialization policy must have a method to serial a pointer on the object (see example below) + * NB : of course this is slow (but convenient) way of performing a copy + * TODO maybe this could be used elsewhere ? + */ +template +static T *DupSerializable(const T *in) throw(NLMISC::EStream) +{ + NLMISC::CMemStream ms; + nlassert(!ms.isReading()); + T *nonConstIn = const_cast(in); + TSerializePolicy::serial(nonConstIn, ms); + std::vector datas(ms.length()); + std::copy(ms.buffer(), ms.buffer() + ms.length(), datas.begin()); + ms.resetPtrTable(); + ms.invert(); + ms.fill(&datas[0], (uint)datas.size()); + nlassert(ms.isReading()); + T *newObj = NULL; + TSerializePolicy::serial(newObj, ms); + return newObj; +} + +/** A policy to duplicate a non-polymorphic type + */ +struct CDupObjPolicy +{ + template + static void serial(T *&obj, NLMISC::IStream &dest) throw(NLMISC::EStream) + { + dest.serialPtr(obj); + /*if (dest.isReading()) + { + std::auto_ptr newObj(new T); + newObj->serialPtr(dest); + delete obj; + obj = newObj.release(); + } + else + { + obj->serial(dest); + }*/ + } +}; + +/** A policy to duplicate a polymorphic type + */ +struct CDupPolymorphicObjPolicy +{ + template + static void serial(T *&obj, NLMISC::IStream &dest) throw(NLMISC::EStream) + { + dest.serialPolyPtr(obj); + } +}; + + + +//======================================================================= +///////////////////////////////////////// +// temp until there is a clone method // +///////////////////////////////////////// +NL3D::CParticleSystemProcess *DupPSLocated(const CParticleSystemProcess *in) +{ + if (!in) return NULL; + try + { + // if the located doesn't belon to a system, copy it direclty + if (in->getOwner() == NULL) + { + return DupSerializable(in); + } + else + { + uint index = in->getOwner()->getIndexOf(*in); + /** Duplicate the system, and detach. + * We can't duplicate the object direclty (it may be referencing other objects in the system, so these objects will be copied too...) + */ + std::auto_ptr newPS(DupSerializable(in->getOwner())); + // scene pointer is not serialised, but 'detach' may need the scene to be specified + newPS->setScene(in->getOwner()->getScene()); + return newPS->detach(index); + } + } + catch (NLMISC::EStream &e) + { + nlwarning (e.what()); + return NULL; + } +} + +//======================================================================= +///////////////////////////////////////// +// temp until there is a clone method // +///////////////////////////////////////// +NL3D::CPSLocatedBindable *DupPSLocatedBindable(CPSLocatedBindable *in) +{ + if (!in) return NULL; + try + { + // if no owner, can copy the object directy + if (in->getOwner() == NULL) + { + return DupSerializable(in); + } + else + { + CParticleSystem *srcPS = in->getOwner()->getOwner(); + std::auto_ptr newPS(DupSerializable(srcPS)); + // scene pointer is not serialised, but 'detach' may need the scene to be specified + newPS->setScene(in->getOwner()->getOwner()->getScene()); + // + uint index = srcPS->getIndexOf(*(in->getOwner())); + uint subIndex = in->getOwner()->getIndexOf(in); + // + newPS->setScene(in->getOwner()->getScene()); // 'unbind' require the scene to be attached + CPSLocated *loc = NLMISC::safe_cast(newPS->getProcess(index)); + return loc->unbind(subIndex); + } + } + catch (NLMISC::EStream &e) + { + nlwarning (e.what()); + return NULL; + } +} diff --git a/code/nel/tools/3d/object_viewer_qt/src/dup_ps.h b/code/nel/tools/3d/object_viewer_qt/src/dup_ps.h new file mode 100644 index 000000000..da79b6374 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/dup_ps.h @@ -0,0 +1,52 @@ +// NeL - MMORPG Framework +// 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 . + + + + +#ifndef NL_DUP_PS_H +#define NL_DUP_PS_H + + +namespace NL3D +{ + class CParticleSystemProcess; + class CPSLocatedBindable; +} + + +/** For now there is no duplication method in particle system. + * These are needed for edition, though.. + * These functions provide a way to do this (by serializing the system in a memory stream). + * NB this is slow + * These may be removed, but this provide a easy way to accomplish our goal + */ + +/** temp : duplicate a process of a particle system. + * return NULL if the copy failed + */ +NL3D::CParticleSystemProcess *DupPSLocated(const NL3D::CParticleSystemProcess *in); + +/** temp : duplicate a located bindable of a particle system + * return NULL if the copy failed + */ +NL3D::CPSLocatedBindable *DupPSLocatedBindable(NL3D::CPSLocatedBindable *in); + + + + + +#endif \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/edit_range_float_form.ui b/code/nel/tools/3d/object_viewer_qt/src/edit_range_float_form.ui new file mode 100644 index 000000000..7f0a631e7 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/edit_range_float_form.ui @@ -0,0 +1,108 @@ + + + CEditRangeFloatWidget + + + + 0 + 0 + 304 + 32 + + + + Form + + + + + + QAbstractSpinBox::NoButtons + + + false + + + 2 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + + + + + + 50 + 0 + + + + 0 + + + 1000000 + + + Qt::Horizontal + + + + + + + QAbstractSpinBox::NoButtons + + + false + + + 2 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + + + + + true + + + true + + + QAbstractSpinBox::NoButtons + + + false + + + 2 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.000000000000000 + + + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/edit_range_uint_form.ui b/code/nel/tools/3d/object_viewer_qt/src/edit_range_uint_form.ui new file mode 100644 index 000000000..d9878254e --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/edit_range_uint_form.ui @@ -0,0 +1,108 @@ + + + CEditRangeUIntWidget + + + + 0 + 0 + 294 + 32 + + + + Form + + + + + + QAbstractSpinBox::NoButtons + + + false + + + 99998 + + + + + + + 100 + + + Qt::Horizontal + + + + + + + QAbstractSpinBox::NoButtons + + + false + + + 99999 + + + + + + + false + + + QAbstractSpinBox::NoButtons + + + false + + + 99999 + + + + + + + + + + + horizontalSlider + valueChanged(int) + currentSpinBox + setValue(int) + + + 104 + 30 + + + 213 + 34 + + + + + currentSpinBox + valueChanged(int) + horizontalSlider + setValue(int) + + + 206 + 29 + + + 91 + 27 + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/edit_range_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/edit_range_widget.cpp new file mode 100644 index 000000000..27b715d4e --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/edit_range_widget.cpp @@ -0,0 +1,361 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "edit_range_widget.h" + +// NeL includes + +// Project includes +#include "ps_wrapper.h" + +using namespace NL3D; +using namespace NLMISC; + +namespace NLQT { + +const int max_range = 9999; + +CEditRangeUIntWidget::CEditRangeUIntWidget(QWidget *parent) + : QWidget(parent), _Wrapper(NULL), _emit(true) +{ + _ui.setupUi(this); + + _ui.endSpinBox->setMinimum(0); + _ui.startSpinBox->setMinimum(0); + _ui.currentSpinBox->setMinimum(0); + + connect(_ui.startSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setMinimum(int))); + connect(_ui.endSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setMaximum(int))); + connect(_ui.horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(changeSlider(int))); + + setValue(0, false); +} + +CEditRangeUIntWidget::~CEditRangeUIntWidget() +{ +} + +void CEditRangeUIntWidget::setWrapper(IPSWrapperUInt *wrapper) +{ + _Wrapper = wrapper; +} + +void CEditRangeUIntWidget::setRange(uint32 minValue, uint32 maxValue) +{ + setRangeMin(minValue); + setRangeMax(maxValue); +} + +void CEditRangeUIntWidget::setRangeMin(uint32 minValue) +{ + _ui.startSpinBox->setValue(minValue); +} + +void CEditRangeUIntWidget::setRangeMax(uint32 maxValue) +{ + _ui.endSpinBox->setValue(maxValue); +} + +void CEditRangeUIntWidget::setValue(uint32 value, bool emit) +{ + if (value > uint32(_ui.endSpinBox->value())) + _ui.endSpinBox->setValue(value); + if (value < uint32(_ui.startSpinBox->value())) + _ui.startSpinBox->setValue(value); + + _emit = emit; + _ui.horizontalSlider->setValue(value); + _emit = true; +} + +void CEditRangeUIntWidget::enableUpperBound(uint32 upperBound, bool upperBoundExcluded) +{ + if (upperBoundExcluded) + upperBound--; + _ui.endSpinBox->setMaximum(upperBound); + _ui.startSpinBox->setMaximum(upperBound); +} + +void CEditRangeUIntWidget::enableLowerBound(uint32 lowerBound, bool lowerBoundExcluded) +{ + if (lowerBoundExcluded) + lowerBound++; + _ui.endSpinBox->setMinimum(lowerBound); + _ui.startSpinBox->setMinimum(lowerBound); +} + +void CEditRangeUIntWidget::disableUpperBound(void) +{ + _ui.endSpinBox->setMaximum(max_range); + _ui.startSpinBox->setMaximum(max_range); +} + +void CEditRangeUIntWidget::disableLowerBound(void) +{ + _ui.endSpinBox->setMinimum(0); + _ui.startSpinBox->setMinimum(0); +} + +void CEditRangeUIntWidget::setMaximum(int value) +{ + _ui.horizontalSlider->setMaximum(value); + _ui.currentSpinBox->setMaximum(value); +} + +void CEditRangeUIntWidget::setMinimum(int value) +{ + _ui.horizontalSlider->setMinimum(value); + _ui.currentSpinBox->setMinimum(value); +} + +void CEditRangeUIntWidget::changeSlider(int value) +{ + // NeL wrapper + if ((_Wrapper != NULL) && (_Wrapper->get() != uint32(value))) + _Wrapper->setAndUpdateModifiedFlag(value); + + if (_emit) + Q_EMIT valueChanged(value); +} + +void CEditRangeUIntWidget::updateUi() +{ + if (_Wrapper == NULL) return; + _ui.horizontalSlider->setSliderPosition(_Wrapper->get()); +} + +CEditRangeIntWidget::CEditRangeIntWidget(QWidget *parent) + : QWidget(parent), _Wrapper(NULL) +{ + _ui.setupUi(this); + connect(_ui.startSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setMinimum(int))); + connect(_ui.endSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setMaximum(int))); + connect(_ui.horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(changeSlider(int))); + + setValue(0, false); +} + +CEditRangeIntWidget::~CEditRangeIntWidget() +{ +} + +void CEditRangeIntWidget::setWrapper(IPSWrapperInt *wrapper) +{ + _Wrapper = wrapper; +} + +void CEditRangeIntWidget::setRange(sint32 minValue, sint32 maxValue) +{ + setRangeMin(minValue); + setRangeMax(maxValue); +} + +void CEditRangeIntWidget::setRangeMin(sint32 minValue) +{ + _ui.startSpinBox->setValue(minValue); +} + +void CEditRangeIntWidget::setRangeMax(sint32 maxValue) +{ + _ui.endSpinBox->setValue(maxValue); +} + +void CEditRangeIntWidget::setValue(sint32 value, bool emit) +{ + if (value > sint32(_ui.endSpinBox->value())) + _ui.endSpinBox->setValue(value); + if (value < sint32(_ui.startSpinBox->value())) + _ui.startSpinBox->setValue(value); + + _emit = emit; + _ui.horizontalSlider->setValue(value); + _emit = true; +} + +void CEditRangeIntWidget::enableUpperBound(sint32 upperBound, bool upperBoundExcluded) +{ + if (upperBoundExcluded) + upperBound--; + _ui.endSpinBox->setMaximum(upperBound); + _ui.startSpinBox->setMaximum(upperBound); +} + +void CEditRangeIntWidget::enableLowerBound(sint32 lowerBound, bool lowerBoundExcluded) +{ + if (lowerBoundExcluded) + lowerBound++; + _ui.endSpinBox->setMinimum(lowerBound); + _ui.startSpinBox->setMinimum(lowerBound); +} + +void CEditRangeIntWidget::disableUpperBound(void) +{ + _ui.endSpinBox->setMaximum(max_range); + _ui.startSpinBox->setMaximum(max_range); +} + +void CEditRangeIntWidget::disableLowerBound(void) +{ + _ui.endSpinBox->setMinimum(-max_range); + _ui.startSpinBox->setMinimum(-max_range); +} + +void CEditRangeIntWidget::setMaximum(int value) +{ + _ui.horizontalSlider->setMaximum(value); + _ui.currentSpinBox->setMaximum(value); +} + +void CEditRangeIntWidget::setMinimum(int value) +{ + _ui.horizontalSlider->setMinimum(value); + _ui.currentSpinBox->setMinimum(value); +} + +void CEditRangeIntWidget::changeSlider(int value) +{ + // NeL wrapper + if ((_Wrapper != NULL) && (_Wrapper->get() != sint32(value))) + _Wrapper->setAndUpdateModifiedFlag(value); + + if (_emit) + Q_EMIT valueChanged(value); +} + +void CEditRangeIntWidget::updateUi() +{ + if (_Wrapper == NULL) return; + _ui.horizontalSlider->setSliderPosition(_Wrapper->get()); +} + + +CEditRangeFloatWidget::CEditRangeFloatWidget(QWidget *parent ) + : QWidget(parent), _Wrapper(NULL), _emit(true) +{ + _ui.setupUi(this); + + connect(_ui.startSpinBox, SIGNAL(valueChanged(double)), this, SLOT(changeRange())); + connect(_ui.endSpinBox, SIGNAL(valueChanged(double)), this, SLOT(changeRange())); + connect(_ui.horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(changeSlider(int))); + + setValue(0.0, false); +} + +CEditRangeFloatWidget::~CEditRangeFloatWidget() +{ +} + +void CEditRangeFloatWidget::setWrapper(IPSWrapperFloat *wrapper) +{ + _Wrapper = wrapper; +} + +void CEditRangeFloatWidget::setValue(float value, bool emit) +{ + if (value > _ui.endSpinBox->value()) + _ui.endSpinBox->setValue(value); + if (value < _ui.startSpinBox->value()) + _ui.startSpinBox->setValue(value); + + float delta = _ui.endSpinBox->value() - _ui.startSpinBox->value(); + int deltaSlider = _ui.horizontalSlider->maximum() - _ui.horizontalSlider->minimum(); + int newValue = floor((deltaSlider / delta) * (value - _ui.startSpinBox->value())); + _emit = emit; + _ui.horizontalSlider->setSliderPosition(newValue); + _emit = true; +} + +void CEditRangeFloatWidget::setRange(float minValue, float maxValue) +{ + setRangeMax(maxValue); + setRangeMin(minValue); +} + +void CEditRangeFloatWidget::setRangeMin(float minValue) +{ + _ui.startSpinBox->setValue(minValue); +} + +void CEditRangeFloatWidget::setRangeMax(float maxValue) +{ + _ui.endSpinBox->setValue(maxValue); +} + +void CEditRangeFloatWidget::enableUpperBound(float upperBound, bool upperBoundExcluded) +{ + if (upperBoundExcluded) + upperBound -= 0.001f; + _ui.endSpinBox->setMaximum(upperBound); + _ui.startSpinBox->setMaximum(upperBound); +} + +void CEditRangeFloatWidget::enableLowerBound(float lowerBound, bool lowerBoundExcluded) +{ + if (lowerBoundExcluded) + lowerBound += 0.01f; + _ui.endSpinBox->setMinimum(lowerBound); + _ui.startSpinBox->setMinimum(lowerBound); +} + +void CEditRangeFloatWidget::disableUpperBound(void) +{ + _ui.endSpinBox->setMaximum(max_range); + _ui.startSpinBox->setMaximum(max_range); +} + +void CEditRangeFloatWidget::disableLowerBound(void) +{ + _ui.endSpinBox->setMinimum(-max_range); + _ui.startSpinBox->setMinimum(-max_range); +} + +void CEditRangeFloatWidget::changeRange() +{ + if ((_ui.startSpinBox->value() < _ui.currentSpinBox->value()) && + (_ui.endSpinBox->value() > _ui.currentSpinBox->value())) + setValue(_ui.currentSpinBox->value(), false); +} + +void CEditRangeFloatWidget::changeSlider(int value) +{ + float delta = _ui.endSpinBox->value() - _ui.startSpinBox->value(); + int deltaSlider = _ui.horizontalSlider->maximum() - _ui.horizontalSlider->minimum(); + float newValue = _ui.startSpinBox->value() + ((delta / deltaSlider) * value); + _ui.currentSpinBox->setValue(newValue); + + // NeL wrapper + if ((_Wrapper != NULL) && (fabs(newValue - _Wrapper->get()) > 0.0001)) + _Wrapper->setAndUpdateModifiedFlag(newValue); + + if (_emit) + Q_EMIT valueChanged(newValue); +} + +void CEditRangeFloatWidget::updateUi() +{ + if (_Wrapper == NULL) return; + _ui.currentSpinBox->setValue(_Wrapper->get()); + float delta = _ui.endSpinBox->value() - _ui.startSpinBox->value(); + int deltaSlider = _ui.horizontalSlider->maximum() - _ui.horizontalSlider->minimum(); + int newValue = floor((deltaSlider / delta) * (_Wrapper->get() - _ui.startSpinBox->value())); + _ui.horizontalSlider->setSliderPosition(newValue); +} + +} /* namespace NLQT */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/edit_range_widget.h b/code/nel/tools/3d/object_viewer_qt/src/edit_range_widget.h new file mode 100644 index 000000000..32a4e0a98 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/edit_range_widget.h @@ -0,0 +1,290 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef EDIT_RANGE_WIDGET_H +#define EDIT_RANGE_WIDGET_H + +#include "ui_edit_range_float_form.h" +#include "ui_edit_range_uint_form.h" + +// Qt includes + +// Project includes +#include "ps_wrapper.h" + +namespace NLQT { + +/** +@class CEditRangeUIntWidget +@brief The widget provides a horizontal slider and 3 QSpinBox(to set start/end value range and Ñurrent value from this range.). +@details Slider sets the uint32 value within a specified range (start/end QSpinBox). +The values range can be set through the class methods: setRange() or setRangeMin(), setRangeMax(). +Or the user input values in the widgets start/end QSpinBox. +Also the range of start/end values can be restricted through the class methods: enableLowerBound(), enableUpperBound() +this widget can be used by a two ways: Qt Q_SIGNAL/SLOT or wrapper. + +1. Using the Qt Q_SIGNAL/SLOT current value can be set by class methods setValue() and +changes in current value(QSlider or QSpinBox) the signal valueChanged() will be emitted. + +2. Using wrapper, create wpapper struct, example: +@code +struct CMaxNbParticlesWrapper : public IPSWrapperUInt +{ + NL3D::CPSLocated *Located; + uint32 get(void) const { return Located->getMaxSize(); } + void set(const uint32 &v) { Located->setMaxSize(v); } +} _MaxNbParticlesWrapper; +@endcode +to set the current values,it is need to call class methods updateUi(); +*/ + +class CEditRangeUIntWidget: public QWidget +{ + Q_OBJECT + +public: + /// Constructor, sets 0 default current value + CEditRangeUIntWidget(QWidget *parent = 0); + ~CEditRangeUIntWidget(); + + /// Set an interface of a wrapper to read / write values in the particle system + /// NB : The 'OwnerNode' field of the wrapper + void setWrapper(IPSWrapperUInt *wrapper); + + /// Set current value + /// @param value - current value + /// @param emit - will emit valueChanged() if the new value is different from the old one and param emit = true + void setValue(uint32 value, bool emit = true); + + /// Convenience function to set the minimum, and maximum values with a single function call + void setRange(uint32 minValue, uint32 maxValue); + + /// Set the minimum value that can take range(slider) + void setRangeMin(uint32 minValue); + + /// Set the maximum value that can take range(slider) + void setRangeMax(uint32 maxValue); + + /// Enable upper bound use (e.g. value must be < or <= upper bound ) + /// @param upperBound - maximum value of the range + /// @param upperBoundExcluded - if true then the test is <, otherwise its <= + void enableUpperBound(uint32 upperBound, bool upperBoundExcluded); + + /// Enable lower bound use (e.g. value must be < or <= lower bound ) + /// @param lowerBound - minimum value of the range + /// @param lowerBoundExcluded - if true then the test is <, otherwise its <= + void enableLowerBound(uint32 lowerBound, bool lowerBoundExcluded); + + /// Disable upper bound usage + void disableUpperBound(void); + + /// Disable lower bound usage + void disableLowerBound(void); + + /// With changes wrapper to be called for the installation of new range values + void updateUi(); + +Q_SIGNALS: + void valueChanged(uint32 value); + +private Q_SLOTS: + void setMaximum(int value); + void setMinimum(int value); + void changeSlider(int value); + +private: + + IPSWrapperUInt *_Wrapper; + bool _emit; + Ui::CEditRangeUIntWidget _ui; +}; /* class CEditRangeUIntWidget */ + + +/** +@class CEditRangeIntWidget +@brief The widget provides a horizontal slider and 3 QSpinBox(to set start/end value range and Ñurrent value from this range.). +@details Slider sets the sint32 value within a specified range (start/end QSpinBox). +The values range can be set through the class methods: setRange() or setRangeMin(), setRangeMax(). +Or the user input values in the widgets start/end QSpinBox. +Also the range of start/end values can be restricted through the class methods: enableLowerBound(), enableUpperBound() +this widget can be used by a two ways: Qt Q_SIGNAL/SLOT or wrapper. + +1. Using the Qt Q_SIGNAL/SLOT current value can be set by class methods setValue() and +changes in current value(QSlider or QSpinBox) the signal valueChanged() will be emitted. + +2. Using wrapper, create wpapper struct, example: +@code +struct CRadialViscosityWrapper : public IPSWrapperFloat +{ + NL3D::CPSCylindricVortex *V; + sint32 get(void) const { return V->getRadialViscosity(); } + void set(const sint32 &value) { V->setRadialViscosity(value); } +} _RadialViscosityWrapper; +@endcode +to set the current values,it is need to call class methods updateUi(); +*/ + +class CEditRangeIntWidget: public QWidget +{ + Q_OBJECT + +public: + /// Constructor, sets 0 default current value + CEditRangeIntWidget(QWidget *parent = 0); + ~CEditRangeIntWidget(); + + /// set an interface of a wrapper to read / write values in the particle system + /// NB : The 'OwnerNode' field of the wrapper + void setWrapper(IPSWrapperInt *wrapper); + + /// Set current value + /// @param value - current value + /// @param emit - will emit valueChanged() if the new value is different from the old one and param emit = true + void setValue(sint32 value, bool emit = true); + + /// Convenience function to set the minimum, and maximum values with a single function call + void setRange(sint32 minValue, sint32 maxValue); + + /// Set the minimum value that can take range(slider) + void setRangeMin(sint32 minValue); + + /// Set the maximum value that can take range(slider) + void setRangeMax(sint32 maxValue); + + /// Enable upper bound use (e.g. value must be < or <= upper bound ) + /// @param upperBound - maximum value of the range + /// @param upperBoundExcluded - if true then the test is <, otherwise its <= + void enableUpperBound(sint32 upperBound, bool upperBoundExcluded); + + /// Enable lower bound use (e.g. value must be < or <= lower bound ) + /// @param lowerBound - minimum value of the range + /// @param lowerBoundExcluded - if true then the test is <, otherwise its <= + void enableLowerBound(sint32 lowerBound, bool lowerBoundExcluded); + + /// Disable upper bound usage + void disableUpperBound(void); + + /// Disable lower bound usage + void disableLowerBound(void); + + /// With changes wrapper to be called for the installation of new range values + void updateUi(); + +Q_SIGNALS: + void valueChanged(sint32 value); + +private Q_SLOTS: + void setMaximum(int value); + void setMinimum(int value); + void changeSlider(int value); + +private: + + IPSWrapperInt *_Wrapper; + bool _emit; + Ui::CEditRangeUIntWidget _ui; +}; /* class CEditRangeIntWidget */ + + +/** +@class CEditRangeFloatWidget +@brief The widget provides a horizontal slider and 3 QDoubleSpinBox(to set start/end value range and Ñurrent value from this range.). +@details Slider sets the float value within a specified range (start/end QDoubleSpinBox). +The values range can be set through the class methods: setRange() or setRangeMin(), setRangeMax(). +Or the user input values in the widgets start/end QDoubleSpinBox. +Also the range of start/end values can be restricted through the class methods: enableLowerBound(), enableUpperBound() +this widget can be used by a two ways: Qt Q_SIGNAL/SLOT or wrapper. + +1. Using the Qt Q_SIGNAL/SLOT current value can be set by class methods setValue() and +changes in current value(only QSlider) the signal valueChanged()will be emitted. + +2. Using wrapper, create wpapper struct, example: +@code +struct CTangentialViscosityWrapper : public IPSWrapperFloat +{ + NL3D::CPSCylindricVortex *V; + float get(void) const { return V->getTangentialViscosity(); } + void set(const float &value) { V->setTangentialViscosity(value); } +} _TangentialViscosityWrapper; +@endcode +to set the current values,it is need to call class methods updateUi(); +*/ + +class CEditRangeFloatWidget: public QWidget +{ + Q_OBJECT +public: + /// Constructor, sets 0 default current value + CEditRangeFloatWidget(QWidget *parent = 0); + ~CEditRangeFloatWidget(); + + /// Set an interface of a wrapper to read / write values in the particle system + /// NB : The 'OwnerNode' field of the wrapper + void setWrapper(IPSWrapperFloat *wrapper); + + /// Set current value + /// @param value - current value + /// @param emit - will emit valueChanged() if the new value is different from the old one and param emit = true + void setValue(float value, bool emit = true); + + /// Convenience function to set the minimum, and maximum values with a single function call + void setRange(float minValue, float maxValue); + + /// Set the minimum value that can take range(slider) + void setRangeMin(float minValue); + + /// Set the maximum value that can take range(slider) + void setRangeMax(float maxValue); + + /// Enable upper bound use (e.g. value must be < or <= upper bound ) + /// @param upperBound - maximum value of the range + /// @param upperBoundExcluded - if true then the test is <, otherwise its <= + void enableUpperBound(float upperBound, bool upperBoundExcluded); + + /// Enable lower bound use (e.g. value must be < or <= lower bound ) + /// @param lowerBound - minimum value of the range + /// @param lowerBoundExcluded - if true then the test is <, otherwise its <= + void enableLowerBound(float lowerBound, bool lowerBoundExcluded); + + /// Disable upper bound usage + void disableUpperBound(void); + + /// Disable lower bound usage + void disableLowerBound(void); + + /// With changes wrapper to be called for the installation of new range values + void updateUi(); + +Q_SIGNALS: + void valueChanged(float value); + +private Q_SLOTS: + void changeRange(); + void changeSlider(int value); + +private: + + IPSWrapperFloat *_Wrapper; + bool _emit; + Ui::CEditRangeFloatWidget _ui; +}; /* class CEditRangeFloatWidget */ + +} /* namespace NLQT */ + +#endif // EDIT_RANGE_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/emitter_form.ui b/code/nel/tools/3d/object_viewer_qt/src/emitter_form.ui new file mode 100644 index 000000000..ea5f11a8b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/emitter_form.ui @@ -0,0 +1,293 @@ + + + CEmitterPage + + + + 0 + 0 + 382 + 450 + + + + Form + + + + + + true + + + QTabWidget::East + + + 0 + + + true + + + + General + + + + + + + + Emitted type: + + + + + + + + + + Type of emission: + + + + + + + + Regular + + + + + On death + + + + + Once + + + + + On bounce + + + + + External only + + + + + + + + + + Direction: + + + + + + + + Default + + + + + Direction is aligned on the emitter direction + + + + + Direction is in world + + + + + Direction is local to the system + + + + + User + + + + + + + + Force consistent emission + + + + + + + Bypass Auto-LOD + + + + + + + Speed inheritance factor: + + + + + + + + + + Delayed emission: + + + + + + + + + + Max Emission Count: + + + + + + + + + + + + + Radius: + + + + + + + + + + Qt::Vertical + + + + 17 + 143 + + + + + + + + + Emission period + + + + + + Qt::Vertical + + + + 20 + 291 + + + + + + + + Emmision period + + + + + + + + Emmision quantity/Speed + + + + + + Emmision quantity + + + + + + + Strenght modulation + + + + + + + Qt::Vertical + + + + 20 + 275 + + + + + + + + + + + + + NLQT::CEditRangeUIntWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CDirectionWidget + QWidget +
direction_widget.h
+ 1 +
+ + NLQT::CAttribFloatWidget + QGroupBox +
attrib_widget.h
+ 1 +
+ + NLQT::CAttribUIntWidget + QGroupBox +
attrib_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/emitter_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/emitter_page.cpp new file mode 100644 index 000000000..c7e4da53f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/emitter_page.cpp @@ -0,0 +1,372 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "emitter_page.h" + +// Qt includes + #include + +// NeL includes + +// Project includes +#include "edit_range_widget.h" +#include "modules.h" + +namespace NLQT { + + +CEmitterPage::CEmitterPage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + // setup the dialog for the period of emission edition + _ui.periodWidget->setRange(0.f, 2.f); + _ui.periodWidget->setWrapper(&_PeriodWrapper); + _ui.periodWidget->setSchemeWrapper(&_PeriodWrapper); + _ui.periodWidget->init(); + + // setup the dialog that helps tuning the number of particle being emitted at a time + _ui.genNbWidget->setRange(1, 11); + _ui.genNbWidget->setWrapper(&_GenNbWrapper); + _ui.genNbWidget->setSchemeWrapper(&_GenNbWrapper); + _ui.genNbWidget->init(); + + // deals with emitters that have a direction + _ui.strenghtModulateWidget->setRange(0, 10); + _ui.strenghtModulateWidget->setWrapper(&_ModulatedStrenghtWrapper); + _ui.strenghtModulateWidget->setSchemeWrapper(&_ModulatedStrenghtWrapper); + _ui.strenghtModulateWidget->init(); + + // SPEED_INHERITANCE_FACTOR + _ui.speedInherFactorWidget->setRange(-1.f, 1.f); + _ui.speedInherFactorWidget->setWrapper(&_SpeedInheritanceFactorWrapper); + + // DELAYED_EMISSION + _ui.delayedEmissionWidget->setRange(0.f, 10.f); + _ui.delayedEmissionWidget->enableLowerBound(0.f, false); + _ui.delayedEmissionWidget->setWrapper(&_DelayedEmissionWrapper); + + // MAX_EMISSION_COUNT + _ui.maxEmissionCountWidget->setRange(0, 100); + _ui.maxEmissionCountWidget->enableUpperBound(256, false); + _ui.maxEmissionCountWidget->setWrapper(&_MaxEmissionCountWrapper); + _MaxEmissionCountWrapper.widget = _ui.maxEmissionCountWidget; + _MaxEmissionCountWrapper.parent = this; + + // radius for conic emitter + _ui.radiusWidget->setRange(0.1f, 2.1f); + _ui.radiusWidget->setWrapper(&_ConicEmitterRadiusWrapper); + + _ui.directionWidget->setWrapper(&_DirectionWrapper); + + connect(_ui.emittedTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setEmittedType(int))); + connect(_ui.typeEmissionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setTypeOfEmission(int))); + connect(_ui.directionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setDirectionMode(int))); + connect(_ui.bypassAutoLODCheckBox, SIGNAL(toggled(bool)), this, SLOT(setBypassAutoLOD(bool))); + connect(_ui.forceConsistentCheckBox, SIGNAL(toggled(bool)), this, SLOT(setConsistentEmission(bool))); +} + +CEmitterPage::~CEmitterPage() +{ +} + +void CEmitterPage::setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocatedBindable *locatedBindable) +{ + _Emitter = static_cast(locatedBindable); + _Node = ownerNode; + + updateEmittedType(); + + _SpeedInheritanceFactorWrapper.OwnerNode = _Node; + _SpeedInheritanceFactorWrapper.E = _Emitter; + _ui.speedInherFactorWidget->updateUi(); + + _DelayedEmissionWrapper.Node = _Node; + _DelayedEmissionWrapper.OwnerNode = _Node; + _DelayedEmissionWrapper.E = _Emitter; + _ui.delayedEmissionWidget->updateUi(); + + _MaxEmissionCountWrapper.Node = _Node; + _MaxEmissionCountWrapper.OwnerNode = _Node; + _MaxEmissionCountWrapper.E = _Emitter; + _ui.maxEmissionCountWidget->updateUi(); + + _PeriodWrapper.Node = _Node; + _PeriodWrapper.E = _Emitter; + _ui.periodWidget->setWorkspaceNode(_Node); + _ui.periodWidget->updateUi(); + + _GenNbWrapper.Node = _Node; + _GenNbWrapper.E = _Emitter; + _ui.genNbWidget->setWorkspaceNode(_Node); + _ui.genNbWidget->updateUi(); + + if (dynamic_cast(_Emitter)) + { + _ModulatedStrenghtWrapper.E = dynamic_cast(_Emitter); + _ui.strenghtModulateWidget->setWorkspaceNode(_Node); + _ui.strenghtModulateWidget->updateUi(); + _ui.strenghtModulateWidget->show(); + } + else + _ui.strenghtModulateWidget->hide(); + + + // deals with emitters that have a direction + if (dynamic_cast(_Emitter)) + { + _DirectionWrapper.E = dynamic_cast(_Emitter); + _ui.directionWidget->setDirectionWrapper(dynamic_cast(_Emitter)); + _ui.directionWidget->updateUi(); + _ui.directionWidget->show(); + } + else + _ui.directionWidget->hide(); + + + // radius for conic emitter + if (dynamic_cast(_Emitter)) + { + _ConicEmitterRadiusWrapper.E = dynamic_cast(_Emitter); + _ui.radiusWidget->updateUi(); + _ui.radiusWidget->show(); + _ui.radiusLabel->show(); + } + else + { + _ui.radiusWidget->hide(); + _ui.radiusLabel->hide(); + } + + _ui.directionComboBox->blockSignals(true); + if (_Emitter->isSpeedBasisEmissionEnabled()) + { + _ui.directionComboBox->setCurrentIndex(int(AlignOnEmitterDirection)); + } + else if (!_Emitter->isUserMatrixModeForEmissionDirectionEnabled()) + { + _ui.directionComboBox->setCurrentIndex(int(Default)); + } + else if (_Emitter->getUserMatrixModeForEmissionDirection() == NL3D::PSFXWorldMatrix) + { + _ui.directionComboBox->setCurrentIndex(int(LocalToSystem)); + } + else if (_Emitter->getUserMatrixModeForEmissionDirection() == NL3D::PSIdentityMatrix) + { + _ui.directionComboBox->setCurrentIndex(int(InWorld)); + } + else if (_Emitter->getUserMatrixModeForEmissionDirection() == NL3D::PSUserMatrix) + { + _ui.directionComboBox->setCurrentIndex(int(LocalToFatherSkeleton)); + } + else + { + nlassert(0); + } + _ui.directionComboBox->blockSignals(false); + + updatePeriodWidget(); + + _ui.typeEmissionComboBox->setCurrentIndex(int(_Emitter->getEmissionType())); + + // bypass auto LOD + nlassert(_Emitter->getOwner() && _Emitter->getOwner()->getOwner()); + NL3D::CParticleSystem &ps = *_Emitter->getOwner()->getOwner(); + if (ps.isAutoLODEnabled() && !ps.isSharingEnabled()) + { + _ui.bypassAutoLODCheckBox->setEnabled(true); + _ui.bypassAutoLODCheckBox->setChecked(_Emitter->getBypassAutoLOD()); + } + else + _ui.bypassAutoLODCheckBox->setEnabled(true); +} + +void CEmitterPage::setEmittedType(int index) +{ + if (!_Emitter->setEmittedType(_LocatedList[index])) + { + if (_Emitter->getOwner()->getOwner()->getBehaviourType() == NL3D::CParticleSystem::SpellFX || _Emitter->getOwner()->getOwner()->getBypassMaxNumIntegrationSteps()) + { + QMessageBox::critical(this, tr("NeL Particle Editor"), + tr("Can't perform operation : the system is flagged with 'No max nb steps' or uses the preset 'Spell FX'," + "and thus, should have a finite duration. This operation create a loop in the system, and so is forbidden."), + QMessageBox::Ok); + } + else + { + QMessageBox::critical(this, tr("NeL Particle Editor"), + tr("Loops with emitters are forbidden."), + QMessageBox::Ok); + } + updateEmittedType(); + } + + Modules::psEdit().resetAutoCount(_Node); + updateModifiedFlag(); +} + +void CEmitterPage::setTypeOfEmission(int index) +{ + if (_Emitter->getEmissionType() == index) return; + if (!_Emitter->setEmissionType((NL3D::CPSEmitter::TEmissionType) index)) + { + QMessageBox::critical(this, tr("NeL Particle Editor"), + tr("Can't perform operation : the system is flagged with 'No max nb steps' or uses the preset 'Spell FX', " + "and thus, should have a finite duration. Please remove that flag first."), + QMessageBox::Ok); + + _ui.typeEmissionComboBox->setCurrentIndex(int(_Emitter->getEmissionType())); + } + + updatePeriodWidget(); + + Modules::psEdit().resetAutoCount(_Node); + + updateModifiedFlag(); +} + +void CEmitterPage::setConsistentEmission(bool state) +{ + if (_Emitter-> isConsistentEmissionEnabled() == state) return; + _Emitter->enableConsistenEmission(state); + updateModifiedFlag(); +} + +void CEmitterPage::setBypassAutoLOD(bool state) +{ + if (_Emitter->getBypassAutoLOD() == state) return; + _Emitter->setBypassAutoLOD(state); + updateModifiedFlag(); +} + +void CEmitterPage::setDirectionMode(int index) +{ + nlassert(_Emitter); + switch(index) + { + case Default: + _Emitter->enableSpeedBasisEmission(false); + _Emitter->enableUserMatrixModeForEmissionDirection(false); + break; + case AlignOnEmitterDirection: + _Emitter->enableSpeedBasisEmission(true); + _Emitter->enableUserMatrixModeForEmissionDirection(false); + break; + case InWorld: + _Emitter->enableSpeedBasisEmission(false); + _Emitter->enableUserMatrixModeForEmissionDirection(true); + _Emitter->setUserMatrixModeForEmissionDirection(NL3D::PSIdentityMatrix); + break; + case LocalToSystem: + _Emitter->enableSpeedBasisEmission(false); + _Emitter->enableUserMatrixModeForEmissionDirection(true); + _Emitter->setUserMatrixModeForEmissionDirection(NL3D::PSFXWorldMatrix); + break; + case LocalToFatherSkeleton: + _Emitter->enableSpeedBasisEmission(false); + _Emitter->enableUserMatrixModeForEmissionDirection(true); + _Emitter->setUserMatrixModeForEmissionDirection(NL3D::PSUserMatrix); + break; + } + updateModifiedFlag(); +} + +void CEmitterPage::updatePeriodWidget() +{ + bool bEnable = _Emitter->getEmissionType() == NL3D::CPSEmitter::regular; + + _ui.periodWidget->setEnabled(bEnable); + _ui.delayedEmissionWidget->setEnabled(bEnable); + _ui.delayedEmissionLabel->setEnabled(bEnable); + _ui.maxEmissionCountWidget->setEnabled(bEnable); + _ui.maxEmissinCountLabel->setEnabled(bEnable); +} + +void CEmitterPage::updateEmittedType() +{ + disconnect(_ui.emittedTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setEmittedType(int))); + + _ui.emittedTypeComboBox->clear(); + _ui.emittedTypeComboBox->addItem(tr("no emission")); + _LocatedList.clear(); + _LocatedList.push_back(NULL); + NL3D::CParticleSystem *ps = _Emitter->getOwner()->getOwner(); + uint nbLocated = ps->getNbProcess(); + for (uint k = 0; k < nbLocated; ++k) + { + NL3D::CPSLocated *loc = dynamic_cast(ps->getProcess(k)); + if (loc) // is this a located + { + _ui.emittedTypeComboBox->addItem(QString(loc->getName().c_str())); + _LocatedList.push_back(loc); + if (loc == _Emitter->getEmittedType()) + _ui.emittedTypeComboBox->setCurrentIndex(k + 1); + } + } + connect(_ui.emittedTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setEmittedType(int))); +} + +void CEmitterPage::CPeriodWrapper::set(const float &v) +{ + E->setPeriod(v); + Modules::psEdit().resetAutoCount(Node); +} +void CEmitterPage::CPeriodWrapper::setScheme(scheme_type *s) +{ + E->setPeriodScheme(s); + Modules::psEdit().resetAutoCount(Node); +} + +void CEmitterPage::CGenNbWrapper::set(const uint32 &v) +{ + E->setGenNb(v); + Modules::psEdit().resetAutoCount(Node); +} + +void CEmitterPage::CGenNbWrapper::setScheme(scheme_type *s) +{ + E->setGenNbScheme(s); + Modules::psEdit().resetAutoCount(Node); +} + + +void CEmitterPage::CDelayedEmissionWrapper::set(const float &f) +{ + E->setEmitDelay(f); + Modules::psEdit().resetAutoCount(Node); +} + +void CEmitterPage::CMaxEmissionCountWrapper::set(const uint32 &count) +{ + if (!E->setMaxEmissionCount((uint8) count)) + { + + QMessageBox::critical(parent, tr("NeL Particle Editor"), + tr("Can't perform operation : the system is flagged with 'No max nb steps' or uses the preset 'Spell FX', " + "and thus, should have a finite duration. Please remove that flag first."), + QMessageBox::Ok); + + widget->updateUi(); + } + Modules::psEdit().resetAutoCount(Node); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/emitter_page.h b/code/nel/tools/3d/object_viewer_qt/src/emitter_page.h new file mode 100644 index 000000000..855eec324 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/emitter_page.h @@ -0,0 +1,168 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef EMITTER_PAGE_H +#define EMITTER_PAGE_H + +#include +#include "ui_emitter_form.h" + +// STL includes + +// NeL includes +#include "nel/3d/ps_particle.h" +#include "nel/3d/ps_emitter.h" + +// Project includes +#include "particle_node.h" +#include "ps_wrapper.h" + +namespace NLQT { + +/** +@class CEmitterPage +@brief Page for QStackWidget, to edit emitters in a particle system +*/ +class CEmitterPage: public QWidget +{ + Q_OBJECT + +public: + /// This enum match the option in the combo box that allow to choose how the direction of emission is computed. + enum TDirectionMode + { + Default = 0, + AlignOnEmitterDirection, + InWorld, + LocalToSystem, + LocalToFatherSkeleton + }; + + CEmitterPage(QWidget *parent = 0); + ~CEmitterPage(); + + /// Set the emitter to edit. + void setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocatedBindable *locatedBindable); + +private Q_SLOTS: + void setEmittedType(int index); + void setTypeOfEmission(int index); + void setConsistentEmission(bool state); + void setBypassAutoLOD(bool state); + void setDirectionMode(int index); + +private: + + /// period of emission + struct CPeriodWrapper : public IPSWrapperFloat, IPSSchemeWrapperFloat + { + CWorkspaceNode *Node; + NL3D::CPSEmitter *E; + float get(void) const { return E->getPeriod(); } + void set(const float &v); + scheme_type *getScheme(void) const { return E->getPeriodScheme(); } + void setScheme(scheme_type *s); + } _PeriodWrapper; + + /// number of particle to generate each time + struct CGenNbWrapper : public IPSWrapperUInt, IPSSchemeWrapperUInt + { + CWorkspaceNode *Node; + NL3D::CPSEmitter *E; + uint32 get(void) const { return E->getGenNb(); } + void set(const uint32 &v); + scheme_type *getScheme(void) const { return E->getGenNbScheme(); } + void setScheme(scheme_type *s); + } _GenNbWrapper; + + /// wrappers to emitters that have strenght modulation + struct CModulateStrenghtWrapper : public IPSWrapperFloat, IPSSchemeWrapperFloat + { + NL3D::CPSModulatedEmitter *E; + float get(void) const { return E->getEmitteeSpeed(); } + void set(const float &v) { E->setEmitteeSpeed(v); } + scheme_type *getScheme(void) const { return E->getEmitteeSpeedScheme(); } + void setScheme(scheme_type *s) { E->setEmitteeSpeedScheme(s); } + } _ModulatedStrenghtWrapper; + + /// wrappers to set the speed inheritance factor + struct CSpeedInheritanceFactorWrapper : public IPSWrapperFloat + { + NL3D::CPSEmitter *E; + float get(void) const { return E->getSpeedInheritanceFactor(); } + void set(const float &f) { E->setSpeedInheritanceFactor(f); } + } _SpeedInheritanceFactorWrapper; + + /// wrappers to tune the direction of emitters + struct CDirectionWrapper : public IPSWrapper + { + NL3D::CPSDirection *E; + NLMISC::CVector get(void) const { return E->getDir(); } + void set(const NLMISC::CVector &d){ E->setDir(d); } + } _DirectionWrapper; + + /// wrapper to tune the radius of an emitter + struct CConicEmitterRadiusWrapper : public IPSWrapperFloat + { + NL3D::CPSEmitterConic *E; + float get(void) const { return E->getRadius(); } + void set(const float &f) { E->setRadius(f); } + } _ConicEmitterRadiusWrapper; + + /// wrapper to tune delayed emission + struct CDelayedEmissionWrapper : public IPSWrapperFloat + { + CWorkspaceNode *Node; + NL3D::CPSEmitter *E; + float get(void) const { return E->getEmitDelay(); } + void set(const float &f); + } _DelayedEmissionWrapper; + + /// wrapper to tune max number of emissions + struct CMaxEmissionCountWrapper : public IPSWrapperUInt + { + CWorkspaceNode *Node; + CEditRangeUIntWidget *widget; + QWidget *parent; + NL3D::CPSEmitter *E; + uint32 get(void) const { return E->getMaxEmissionCount(); } + void set(const uint32 &count); + } _MaxEmissionCountWrapper; + + + // the emitter being edited + NL3D::CPSEmitter *_Emitter; + + // contains pointers to the located + std::vector _LocatedList; + + void updateEmittedType(); + + void updatePeriodWidget(); + + void updateModifiedFlag() { if (_Node) _Node->setModified(true); } + + CWorkspaceNode *_Node; + + Ui::CEmitterPage _ui; +}; /* class CEmitterPage */ + +} /* namespace NLQT */ + +#endif // EMITTER_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/entity.cpp b/code/nel/tools/3d/object_viewer_qt/src/entity.cpp new file mode 100644 index 000000000..304ff62bf --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/entity.cpp @@ -0,0 +1,430 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "entity.h" + +#include + +// NeL includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Project includes +#include "modules.h" + +using namespace NLMISC; +using namespace NL3D; + +namespace NLQT { + +CSlotInfo& CSlotInfo::operator=(const CSlotInfo & slotInfo) +{ + if ( this != &slotInfo) + { + Animation = slotInfo.Animation; + ClampMode = slotInfo.ClampMode; + Enable = slotInfo.Enable; + EndBlend = slotInfo.EndBlend; + EndTime = slotInfo.EndTime; + Offset = slotInfo.Offset; + Skeleton = slotInfo.Skeleton; + SkeletonInverted = slotInfo.SkeletonInverted; + Smoothness = slotInfo.Smoothness; + SpeedFactor = slotInfo.SpeedFactor; + StartBlend = slotInfo.StartBlend; + StartTime = slotInfo.StartTime; + } + return *this; +} + +CEntity::CEntity(void): + _Name(""), _FileNameShape(""), + _FileNameSkeleton(""), _inPlace(false), _incPos(false), + _Instance(NULL), _Skeleton(NULL), + _PlayList(NULL), _AnimationSet(NULL) +{ + _CharacterScalePos = 1; +} + +CEntity::~CEntity(void) +{ + if (_PlayList != NULL) + { + _PlayList->resetAllChannels(); + Modules::objView().getPlayListManager()->deletePlayList (_PlayList); + _PlayList = NULL; + } + if (_AnimationSet != NULL) + { + Modules::objView().getDriver()->deleteAnimationSet(_AnimationSet); + _AnimationSet = NULL; + } + if (!_Skeleton.empty()) + { + _Skeleton.detachSkeletonSon(_Instance); + Modules::objView().getScene()->deleteSkeleton(_Skeleton); + _Skeleton = NULL; + } + if (!_Instance.empty()) + { + Modules::objView().getScene()->deleteInstance(_Instance); + _Instance = NULL; + } +} + +void CEntity::loadAnimation(std::string &fileName) +{ + uint id = _AnimationSet->addAnimation(fileName.c_str(),CFile::getFilenameWithoutExtension(fileName).c_str()); + _AnimationList.push_back(_AnimationSet->getAnimationName(id)); + _AnimationSet->build(); + if (!_Skeleton.empty()) _PlayList->registerTransform(_Skeleton); + else _PlayList->registerTransform(_Instance); +} + +void CEntity::loadSWT(std::string &fileName) +{ + uint id = _AnimationSet->addSkeletonWeight(fileName.c_str(),CFile::getFilenameWithoutExtension(fileName).c_str()); + _SWTList.push_back(_AnimationSet->getSkeletonWeightName(id)); +} + +void CEntity::addAnimToPlayList(std::string &name) +{ + _PlayListAnimation.push_back(name); + + _AnimationStatus.EndAnim = this->getPlayListLength(); + + _Instance.start(); +} + +void CEntity::removeAnimToPlayList(uint row) +{ + if (row < _PlayListAnimation.size()) + _PlayListAnimation.erase(_PlayListAnimation.begin() + row); + + _AnimationStatus.EndAnim = this->getPlayListLength(); +} + +void CEntity::swapAnimToPlayList(uint row1, uint row2) +{ + if ((row1 < _PlayListAnimation.size()) && (row2 < _PlayListAnimation.size())) + std::swap(_PlayListAnimation[row1], _PlayListAnimation[row2]); +} + +void CEntity::playbackAnim(bool play) +{ + _AnimationStatus.PlayAnim = play; + + if (play) + _Instance.start(); + else + _Instance.freezeHRC(); +} + +void CEntity::reset() +{ + _PlayListAnimation.clear(); + _AnimationList.clear(); + _SWTList.clear(); + + _PlayList->resetAllChannels(); +} + +float CEntity::getPlayListLength() +{ + // Accumul all the time + float time = 0; + for(size_t i = 0; i < _PlayListAnimation.size(); ++i) + time += getAnimLength(_PlayListAnimation[i]); + return time; +} + +float CEntity::getAnimLength(std::string name) +{ + uint id = _AnimationSet->getAnimationIdByName(name.c_str()); + NL3D::UAnimation *anim = _AnimationSet->getAnimation(id); + return anim->getEndTime() - anim->getBeginTime(); +} + +void CEntity::update(NL3D::TAnimationTime time) +{ + this->resetChannel(); + switch (_AnimationStatus.Mode) + { + case Mode::PlayList: + animatePlayList(time); + break; + case Mode::Mixer: + animateChannelMixer(); + break; + } +} + + +void CEntity::resetChannel() +{ + for(uint i = 0; i < NL3D::CChannelMixer::NumAnimationSlot; i++) + _PlayList->setAnimation(i, UPlayList::empty); +} + +void CEntity::addTransformation (CMatrix ¤t, UAnimation *anim, float begin, float end, UTrack *posTrack, UTrack *rotquatTrack, + UTrack *nextPosTrack, UTrack *nextRotquatTrack, bool removeLast) +{ + // In place ? + if (_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 (_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 CEntity::animatePlayList(NL3D::TAnimationTime time) +{ + if (!_PlayListAnimation.empty()) + { + // Animation index + uint id = _AnimationSet->getAnimationIdByName(_PlayListAnimation[0].c_str()); + + // Try channel AnimationSet + NL3D::UAnimation *anim = _AnimationSet->getAnimation(id); + + bool there = false; + + UTrack *posTrack = NULL; + UTrack *rotQuatTrack = NULL; + + // Current matrix + CMatrix current; + current.identity(); + + // read an animation for init matrix + rotQuatTrack = anim->getTrackByName("rotquat"); + posTrack = anim->getTrackByName("pos"); + + there = posTrack || rotQuatTrack; + + // Accumul time + float startTime = 0; + float endTime = anim->getEndTime() - anim->getBeginTime(); + + uint index = 0; + while (time >= endTime) + { + index++; + if (index < _PlayListAnimation.size()) + { + id = _AnimationSet->getAnimationIdByName(_PlayListAnimation[index].c_str()); + NL3D::UAnimation *newAnim = _AnimationSet->getAnimation(id); + + UTrack *newPosTrack = newAnim->getTrackByName ("pos"); + UTrack *newRotquatTrack = newAnim->getTrackByName ("rotquat"); + + // Add the transformation + addTransformation (current, anim, newAnim->getBeginTime(), anim->getEndTime(), posTrack, rotQuatTrack, newPosTrack, newRotquatTrack, true); + + + 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 >= _PlayListAnimation.size()) + { + // Yes + index--; + id = _AnimationSet->getAnimationIdByName(_PlayListAnimation[index].c_str()); + anim = _AnimationSet->getAnimation(id); + + // 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); + + id = _AnimationSet->getAnimationIdByName(_PlayListAnimation[index].c_str()); + anim = _AnimationSet->getAnimation(id); + + // Final time + startTime -= anim->getBeginTime(); + } + + // Set the slot + _PlayList->setAnimation(0, id); + _PlayList->setTimeOrigin(0, startTime); + _PlayList->setSpeedFactor(0, 1.0f); + _PlayList->setWeightSmoothness(0, 1.0f); + _PlayList->setStartWeight(0, 1, 0); + _PlayList->setEndWeight(0, 1, 1); + _PlayList->setWrapMode(0, UPlayList::Clamp); + + // Setup the pos and rot for this shape + if (there) + { + CVector pos = current.getPos(); + + // If a skeleton model + if(!_Skeleton.empty()) + { + // scale animated pos value with the CFG scale + pos *= _CharacterScalePos; + _Skeleton.setPos(pos); + _Skeleton.setRotQuat(current.getRot()); + } + else + { + _Instance.setPos(pos); + _Instance.setRotQuat(current.getRot()); + } + } + } +} + +void CEntity::animateChannelMixer() +{ + for (uint i = 0; i < NL3D::CChannelMixer::NumAnimationSlot; i++) + { + if (_SlotInfo[i].Enable) + { + // Set the animation + uint animId = _AnimationSet->getAnimationIdByName(_SlotInfo[i].Animation); + if (animId == UAnimationSet::NotFound) + _PlayList->setAnimation(i, UPlayList::empty); + else + _PlayList->setAnimation(i, animId); + + // Set the skeleton weight + uint skelId = _AnimationSet->getSkeletonWeightIdByName(_SlotInfo[i].Skeleton); + if (skelId == UAnimationSet::NotFound) + _PlayList->setSkeletonWeight(i, UPlayList::empty, false); + else + _PlayList->setSkeletonWeight(i, skelId, _SlotInfo[i].SkeletonInverted); + + // Set others values + _PlayList->setTimeOrigin(i, _SlotInfo[i].Offset); + _PlayList->setSpeedFactor(i, _SlotInfo[i].SpeedFactor); + _PlayList->setStartWeight(i, _SlotInfo[i].StartBlend, _SlotInfo[i].StartTime); + _PlayList->setEndWeight(i, _SlotInfo[i].EndBlend, _SlotInfo[i].EndTime); + _PlayList->setWeightSmoothness(i, _SlotInfo[i].Smoothness); + + // Switch between wrap modes + switch (_SlotInfo[i].ClampMode) + { + case 0: + _PlayList->setWrapMode (i, UPlayList::Clamp); + break; + case 1: + _PlayList->setWrapMode (i, UPlayList::Repeat); + break; + case 2: + _PlayList->setWrapMode (i, UPlayList::Disable); + break; + } + } + } +} + +} /* namespace NLQT */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/entity.h b/code/nel/tools/3d/object_viewer_qt/src/entity.h new file mode 100644 index 000000000..f37995372 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/entity.h @@ -0,0 +1,259 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef ENTITY_H +#define ENTITY_H + +#include + +// STL includes +#include +#include +#include + +// NeL includes +#include +#include +#include +#include +#include +#include +#include + +namespace NL3D { + class UPlayList; + class UAnimationSet; +} + +namespace NLQT { + +class CSlotInfo +{ +public: + CSlotInfo (): + Animation("empty"), Skeleton("empty"), + Offset(0), StartTime(0), EndTime(0), + StartBlend(1), EndBlend (1), Smoothness(1), + SpeedFactor(1), ClampMode(0), + SkeletonInverted(false), + Enable(true) {} ; + + std::string Animation; + std::string Skeleton; + float Offset; + float StartTime; + float EndTime; + + float StartBlend; + float EndBlend; + float Smoothness; + float SpeedFactor; + sint32 ClampMode; + bool SkeletonInverted; + bool Enable; + + CSlotInfo &operator=(const CSlotInfo &); +}; + + +/** +@class CEntity +@brief Class manage animated shape. +@details +Allows you to load animations for shape and skeleton weight. +Contains a built-in playlist. Has management and playback Playlists or Mixer. +*/ +class CEntity +{ +public: + struct Mode + { + enum List + { + PlayList = 1, + Mixer + }; + }; + + /// Will need for a single or multiple animation shape + struct SAnimationStatus + { + bool LoopAnim; + bool PlayAnim; + float CurrentTimeAnim; + float StartAnim; + float EndAnim; + float SpeedAnim; + int Mode; + + SAnimationStatus(): + LoopAnim(false), PlayAnim(false), + CurrentTimeAnim(0), StartAnim(0), + EndAnim(0), SpeedAnim(1), Mode(Mode::PlayList) {} + }; + + /// Destructor + ~CEntity(void); + + /// Loads a file animations + /// @param fileName - name animation file + void loadAnimation(std::string &fileName); + + /// Loads a file skeleton weight + void loadSWT(std::string &fileName); + + /// Adds an animation to a playlist + /// @param name - name loaded animations + void addAnimToPlayList(std::string &name); + + /// Removes the animation from a playlist + /// @param row - number of animations in the playlist + void removeAnimToPlayList(uint row); + + /// Swaps animations to a playlist + /// @param row1 - first number of animations in the playlist + /// @param row2 - second number of animations in the playlist + void swapAnimToPlayList(uint row1, uint row2); + + /// Playback animation + void playbackAnim(bool play); + + /// Reset playlist and animation + void reset(); + + /// Get the total time of animation playlist + /// @return total time of animation + float getPlayListLength(); + + /// get time length single animation + float getAnimLength(std::string name); + + /// Get slot infomation + void setSlotInfo(uint num, CSlotInfo& slotInfo) { _SlotInfo[num] = slotInfo; } + + /// Set use mode playlist or mixer + void setMode(int mode) { _AnimationStatus.Mode = mode; } + + /// Set in place mode animation + void setInPlace(bool enabled) { _inPlace = enabled; } + + /// Get in place mode + bool getInPlace() { return _inPlace; } + + /// Set inc position + void setIncPos(bool enabled) { _incPos = enabled; } + + /// Get inc position + bool getIncPos() { return _incPos; } + + /// Get information about the current status of playing a playlist + /// @return struct containing current information playback + SAnimationStatus getStatus() { return _AnimationStatus; } + + /// Get name entity + /// @return name entity + std::string getName() { return _Name; } + + /// Get file name shape + /// @return file name shape + std::string getFileNameShape() { return _FileNameShape; } + + /// Get file name skeleton + /// @return file name skeleton + std::string getFileNameSkeleton() { return _FileNameSkeleton; } + + /// Get slot information + CSlotInfo getSlotInfo(uint num) { return _SlotInfo[num]; } + + /// Get list loaded animations files + std::vector& getAnimationList() { return _AnimationList; } + + /// Get playlist animations + std::vector& getPlayListAnimation() { return _PlayListAnimation; } + + /// Get list loaded skeleton weight template files + std::vector& getSWTList() { return _SWTList; } + + /// Get game interface for manipulating Skeleton. + NL3D::USkeleton getSkeleton() const { return _Skeleton; } + +private: + /// Constructor + CEntity(void); + + /// Update the animate from the playlist or channel mixer + /// @param time - current time in second + void update(NL3D::TAnimationTime time); + + void resetChannel(); + + /// Update the animate from the playlist + void animatePlayList(NL3D::TAnimationTime time); + + /// Update the animate from the mixer + void animateChannelMixer(); + void addTransformation (NLMISC::CMatrix ¤t, NL3D::UAnimation *anim, + float begin, float end, + NL3D::UTrack *posTrack, NL3D::UTrack *rotquatTrack, + NL3D::UTrack *nextPosTrack, NL3D::UTrack *nextRotquatTrack, + bool removeLast); + + // The name of the entity + std::string _Name; + std::string _FileNameShape; + std::string _FileNameSkeleton; + + SAnimationStatus _AnimationStatus; + + bool _inPlace; + bool _incPos; + + float _CharacterScalePos; + + // The mesh instance associated to this entity + NL3D::UInstance _Instance; + + // The skeleton binded to the instance + NL3D::USkeleton _Skeleton; + + NL3D::UPlayList *_PlayList; + + NL3D::UAnimationSet *_AnimationSet; + + // Animation input file + std::vector _AnimationList; + + // Skeleton weight input file + std::vector _SWTList; + + // Play list animation + std::vector _PlayListAnimation; + + // Slot info for this object + CSlotInfo _SlotInfo[NL3D::CChannelMixer::NumAnimationSlot]; + + friend class CObjectViewer; +}; /* class CEntity */ + +typedef std::map CEntities; +typedef CEntities::iterator EIT; + +} /* namespace NLQT */ + +#endif // ENTITY_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/follow_path_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/follow_path_dialog.cpp new file mode 100644 index 000000000..3ded7adb7 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/follow_path_dialog.cpp @@ -0,0 +1,81 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "follow_path_dialog.h" + +// NeL include +#include + +// Project includes +#include "particle_node.h" + +namespace NLQT { + +CFollowPathDialog::CFollowPathDialog(NL3D::CPSPlaneBasisFollowSpeed *pbfs, CWorkspaceNode *ownerNode, QWidget *parent) + : QDialog(parent), _FollowPath(pbfs), _Node(ownerNode) +{ + resize(270, 90); + QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(this->sizePolicy().hasHeightForWidth()); + setSizePolicy(sizePolicy); + setMinimumSize(QSize(0, 90)); + setMaximumSize(QSize(16777215, 90)); + gridLayout = new QGridLayout(this); + label = new QLabel(this); + gridLayout->addWidget(label, 0, 0, 1, 1); + comboBox = new QComboBox(this); + gridLayout->addWidget(comboBox, 1, 0, 1, 2); + horizontalSpacer = new QSpacerItem(207, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + gridLayout->addItem(horizontalSpacer, 2, 0, 1, 1); + pushButton = new QPushButton(this); + gridLayout->addWidget(pushButton, 2, 1, 1, 1); + + setWindowTitle(tr("Follow path param")); + label->setText(tr("Projection plane:")); + comboBox->clear(); + comboBox->insertItems(0, QStringList() + << tr("No projection") + << tr("XY plane") + << tr("XZ plane") + << tr("YZ plane")); + pushButton->setText(("Ok")); + + comboBox->setCurrentIndex(_FollowPath->getProjectionPlane()); + + setFixedHeight(sizeHint().height()); + + connect(pushButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setProjectionMode(int))); +} + +CFollowPathDialog::~CFollowPathDialog() +{ +} + +void CFollowPathDialog::setProjectionMode(int index) +{ + nlassert(_FollowPath); + _FollowPath->setProjectionPlane((NL3D::CPSPlaneBasisFollowSpeed::TProjectionPlane) index); + if (_Node) _Node->setModified(true); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/follow_path_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/follow_path_dialog.h new file mode 100644 index 000000000..f9834c5d6 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/follow_path_dialog.h @@ -0,0 +1,63 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef FOLLOW_PATH_DIALOG_H +#define FOLLOW_PATH_DIALOG_H + +#include +#include +#include +#include +#include +#include + +namespace NL3D +{ + class CPSPlaneBasisFollowSpeed; +} + +namespace NLQT { + +class CWorkspaceNode; + +class CFollowPathDialog : public QDialog +{ + Q_OBJECT + +public: + CFollowPathDialog(NL3D::CPSPlaneBasisFollowSpeed *pbfs, CWorkspaceNode *ownerNode, QWidget *parent = 0); + ~CFollowPathDialog(); + +private Q_SLOTS: + void setProjectionMode(int index); + +protected: + QGridLayout *gridLayout; + QLabel *label; + QComboBox *comboBox; + QSpacerItem *horizontalSpacer; + QPushButton *pushButton; + + NL3D::CPSPlaneBasisFollowSpeed *_FollowPath; + CWorkspaceNode *_Node; +}; /* class CFollowPathDialog */ + +} /* namespace NLQT */ + +#endif // FOLLOW_PATH_DIALOG_H \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/global_wind_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/global_wind_dialog.cpp new file mode 100644 index 000000000..764aa6329 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/global_wind_dialog.cpp @@ -0,0 +1,70 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "global_wind_dialog.h" + +// Project includes +#include "modules.h" +#include + +namespace NLQT { + +CGlobalWindDialog::CGlobalWindDialog(QWidget *parent) + : QDockWidget(parent) +{ + _ui.setupUi(this); + + //_ui.directionWidget->setWrapper(&_DirectionWrapper); + + connect(_ui.horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setWndPower(int))); + connect(this, SIGNAL(visibilityChanged(bool)), this, SLOT(updateWnd(bool))); +} + +CGlobalWindDialog::~CGlobalWindDialog() +{ +} + +void CGlobalWindDialog::setWndPower(int value) +{ + float fValue = float(value) / _ui.horizontalSlider->maximum(); + _ui.doubleSpinBox->setValue(fValue); + Modules::objView().getScene()->setGlobalWindPower(fValue); +} + +void CGlobalWindDialog::updateWnd(bool visible) +{ + if (!visible) + return; + + _ui.horizontalSlider->setValue(int(Modules::objView().getScene()->getGlobalWindPower() * _ui.horizontalSlider->maximum())); +// _ui.directionWidget->updateUi(); +} +/* +NLMISC::CVector CGlobalWindDialog::CDirectionWrapper::get(void) const +{ + return Modules::objView().getScene()->getGlobalWindDirection(); +} + +void CGlobalWindDialog::CDirectionWrapper::set(const NLMISC::CVector &d) +{ + Modules::objView().getScene()->setGlobalWindDirection(d); +} +*/ +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/global_wind_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/global_wind_dialog.h new file mode 100644 index 000000000..717e1a22f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/global_wind_dialog.h @@ -0,0 +1,59 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef GLOBAL_WIND_DIALOG_H +#define GLOBAL_WIND_DIALOG_H + +#include "ui_global_wind_form.h" + +// STL includes + +// NeL includes + +// Project includes + +namespace NLQT { + +class CGlobalWindDialog: public QDockWidget +{ + Q_OBJECT + +public: + CGlobalWindDialog(QWidget *parent = 0); + ~CGlobalWindDialog(); + +private Q_SLOTS: + void setWndPower(int value); + void updateWnd(bool visible); + +private: + /// wrappers to tune the direction of wind +/* struct CDirectionWrapper : public IPSWrapper + { + NLMISC::CVector get(void) const; + void set(const NLMISC::CVector &d); + } _DirectionWrapper;*/ + + Ui::CGlobalWindDialog _ui; + +}; /* class CGlobalWindDialog */ + +} /* namespace NLQT */ + +#endif // GLOBAL_WIND_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/global_wind_form.ui b/code/nel/tools/3d/object_viewer_qt/src/global_wind_form.ui new file mode 100644 index 000000000..971d16c60 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/global_wind_form.ui @@ -0,0 +1,71 @@ + + + CGlobalWindDialog + + + + 0 + 0 + 195 + 64 + + + + + 524287 + 200 + + + + Weather + + + + + + + 100 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + + + + + + 80 + 16777215 + + + + QAbstractSpinBox::NoButtons + + + 1.000000000000000 + + + + + + + + 0 + 0 + + + + Power: + + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/graphics_info_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/graphics_info_widget.cpp new file mode 100644 index 000000000..7ef711435 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/graphics_info_widget.cpp @@ -0,0 +1,142 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "graphics_info_widget.h" + +// Qt includes +#include +#include +#include + +// STL includes + +namespace NLQT { + +const int directionSize = 35; + +CGraphicsInfoWidget::CGraphicsInfoWidget(QWidget *parent) + : QWidget(parent) +{ + _color = Qt::white; + _mode = Mode::Color; + _x = 0.0; + _y = 0.0; + _text = ""; + _braceMode = false; +} + +CGraphicsInfoWidget::~CGraphicsInfoWidget() +{ +} + +void CGraphicsInfoWidget::setMode(int mode) +{ + _mode = mode; +} + +void CGraphicsInfoWidget::setColor(const QColor &color) +{ + _color = color; + repaint(); +} + +void CGraphicsInfoWidget::setVector(float x, float y) +{ + _mode = Mode::Direction; + _x = x; + _y = y; + repaint(); +} + +void CGraphicsInfoWidget::setText(const QString &text) +{ + _text = text; +} + +void CGraphicsInfoWidget::setRibbonShape(const std::vector &verts, bool braceMode) +{ + _mode = Mode::RibbonShape; + _braceMode = braceMode; + _verts = verts; + repaint(); +} + +void CGraphicsInfoWidget::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.setBrush(QBrush(_color)); + painter.setPen(QPen(Qt::black, 2, Qt::SolidLine)); + painter.drawRoundedRect(QRect(3, 3, width() - 6, height() - 6), 3.0, 3.0); + if (_mode == Mode::Direction) + { + painter.setPen(QPen(Qt::gray, 1, Qt::SolidLine)); + painter.drawLine(width() / 2, 4, width() / 2, height() - 4); + painter.drawLine(4, height() / 2, width() - 4, height() / 2); + painter.drawText( 10, 15, _text); + + painter.setPen(QPen(Qt::red, 2, Qt::SolidLine)); + painter.drawLine(width() / 2, height() / 2, + int((width() / 2) + _x * 0.9f * directionSize), int((height() / 2) - _y * 0.9f * directionSize)); + } + if (_mode == Mode::PlaneBasic) + { + } + if (_mode == Mode::RibbonShape) + { + painter.setPen(QPen(Qt::red, 2, Qt::SolidLine)); + painter.scale(0.86, 0.86); + painter.translate(6, 6); + if (_braceMode) + { + for(uint k = 0; k < _verts.size() / 2; ++k) + { + painter.drawLine(int((width() / 2.0) * (1 + _verts[2 * k].x)), + int((height() / 2.0) * (1 - _verts[2 * k].y)), + int((width() / 2.0) * (1 + _verts[2 * k + 1].x)), + int((height() / 2.0) * (1 - _verts[2 * k + 1].y))); + } + } + else + { + for(uint k = 1; k < _verts.size(); k++) + { + painter.drawLine(int((width() / 2.0) * (1 + _verts[k - 1].x)), + int((height() / 2.0) * (1 - _verts[k - 1].y)), + int((width() / 2.0) * (1 + _verts[ k].x)), + int((height() / 2.0) * (1 - _verts[k].y))); + } + painter.drawLine(int((width() / 2.0) * (1 + _verts[0].x)), + int((height() / 2.0) * (1 - _verts[0].y)), + int((width() / 2.0) * (1 + _verts[_verts.size() - 1].x)), + int((height() / 2.0) * (1 - _verts[_verts.size() - 1].y))); + } + } +} + +void CGraphicsInfoWidget::mouseDoubleClickEvent(QMouseEvent *event) +{ + float vx = (event->x() - (width() / 2)) / 0.9f; + float vy = ((height() / 2) - event->y()) / 0.9f; + + Q_EMIT applyNewVector(vx, vy); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/graphics_info_widget.h b/code/nel/tools/3d/object_viewer_qt/src/graphics_info_widget.h new file mode 100644 index 000000000..39411590a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/graphics_info_widget.h @@ -0,0 +1,79 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef GRAPHICS_INFO_WIDGET_H +#define GRAPHICS_INFO_WIDGET_H + +// Qt includes +#include + +// STL includes + +// NeL includes +#include + +// Project includes + +namespace NLQT { + +struct Mode +{ + enum List + { + Color = 0, + Direction, + PlaneBasic, + RibbonShape + }; +}; + +class CGraphicsInfoWidget: public QWidget +{ + Q_OBJECT + +public: + CGraphicsInfoWidget(QWidget *parent = 0); + ~CGraphicsInfoWidget(); + + void setMode(int mode); + void setColor(const QColor &color); + void setVector(float x, float y); + void setText(const QString &text); + void setRibbonShape(const std::vector &verts, bool braceMode); + +Q_SIGNALS: + void applyNewVector(float x, float y); + +protected: + virtual void paintEvent(QPaintEvent *event); + virtual void mouseDoubleClickEvent(QMouseEvent *event); + + int _mode; + QColor _color; + float _x; + float _y; + QString _text; + std::vector _verts; + bool _braceMode; + +}; /* class CGraphicsInfoWidget */ + +} /* namespace NLQT */ + +#endif // GRAPHICS_INFO_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/graphics_viewport.cpp b/code/nel/tools/3d/object_viewer_qt/src/graphics_viewport.cpp new file mode 100644 index 000000000..daccaa876 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/graphics_viewport.cpp @@ -0,0 +1,157 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "graphics_viewport.h" + +// STL includes + +// Qt includes +#include +#include +#include +#include + +// NeL includes +#include + +#include +#include + +#include +#include + +// Project includes +#include "modules.h" + +using namespace std; +using namespace NL3D; + +namespace NLQT { + +CGraphicsViewport::CGraphicsViewport(QWidget *parent) + : QNLWidget(parent) +{ +} + +CGraphicsViewport::~CGraphicsViewport() +{ + +} + +void CGraphicsViewport::init() +{ + //H_AUTO2 + nldebug("CGraphicsViewport::init"); + +#ifdef NL_OS_UNIX + makeCurrent(); +#endif // NL_OS_UNIX + + Modules::objView().init(winId(), width(), height()); + Modules::psEdit().init(); + + setMouseTracking(true); +} + +void CGraphicsViewport::release() +{ + //H_AUTO2 + nldebug("CGraphicsViewport::release"); + + Modules::psEdit().release(); + Modules::objView().release(); +} + + +QAction *CGraphicsViewport::createSaveScreenshotAction(QObject *parent) +{ + QAction *action = new QAction(parent); + connect(action, SIGNAL(triggered()), this, SLOT(saveScreenshot())); + return action; +} + +QAction *CGraphicsViewport::createSetBackgroundColor(QObject *parent) +{ + QAction *action = new QAction(parent); + connect(action, SIGNAL(triggered()), this, SLOT(setBackgroundColor())); + return action; +} + +void CGraphicsViewport::saveScreenshot() +{ + Modules::objView().saveScreenshot("screenshot", false, true, false); +} + +void CGraphicsViewport::setBackgroundColor() +{ + QColor color = QColorDialog::getColor(QColor(Modules::objView().getBackgroundColor().R, + Modules::objView().getBackgroundColor().G, + Modules::objView().getBackgroundColor().B)); + if (color.isValid()) + Modules::objView().setBackgroundColor(NLMISC::CRGBA(color.red(), color.green(), color.blue())); +} + +void CGraphicsViewport::resizeEvent(QResizeEvent *resizeEvent) +{ + QWidget::resizeEvent(resizeEvent); + if (Modules::objView().getDriver()) + Modules::objView().setSizeViewport(resizeEvent->size().width(), resizeEvent->size().height()); +} + +#ifdef NL_OS_WINDOWS + +typedef bool (*winProc)(NL3D::IDriver *driver, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + +bool CGraphicsViewport::winEvent(MSG * message, long * result) +{ + if (Modules::objView().getDriver() && Modules::objView().getDriver()->isActive()) + { + NL3D::IDriver *driver = dynamic_cast(Modules::objView().getDriver())->getDriver(); + if (driver) + { + winProc proc = (winProc)driver->getWindowProc(); + return proc(driver, message->hwnd, message->message, message->wParam, message->lParam); + } + } + + return false; +} +#else // NL_OS_UNIX + +typedef bool (*x11Proc)(NL3D::IDriver *drv, XEvent *e); + +bool CGraphicsViewport::x11Event(XEvent *event) +{ + if (Modules::objView().getDriver() && Modules::objView().getDriver()->isActive()) + { + NL3D::IDriver *driver = dynamic_cast(Modules::objView().getDriver())->getDriver(); + if (driver) + { + x11Proc proc = (x11Proc)driver->getWindowProc(); + return proc(driver, event); + } + } + + return false; +} +#endif + +} /* namespace NLQT */ + diff --git a/code/nel/tools/3d/object_viewer_qt/src/graphics_viewport.h b/code/nel/tools/3d/object_viewer_qt/src/graphics_viewport.h new file mode 100644 index 000000000..1c30012ed --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/graphics_viewport.h @@ -0,0 +1,91 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef GRAPHICS_VIEWPORT_H +#define GRAPHICS_VIEWPORT_H + +#include +#include + +// STL includes + +// Qt includes +#include +#include + +// NeL includes + +// Project includes + +#ifdef NL_OS_WINDOWS +typedef QWidget QNLWidget; +#else // NL_OS_UNIX +typedef QGLWidget QNLWidget; +#endif // NL_OS_UNIX + +class QAction; + +namespace NLQT { + +/** +@class CGraphicsViewport +@brief Responsible for interaction between Qt and NeL. Initializes CObjectViewer, CParticleEditor and CVegetableEditor subsystem. +*/ +class CGraphicsViewport : public QNLWidget +{ + Q_OBJECT + +public: + CGraphicsViewport(QWidget *parent); + virtual ~CGraphicsViewport(); + + virtual QPaintEngine* paintEngine() const { return NULL; } + + void init(); + void release(); + + QAction *createSaveScreenshotAction(QObject *parent); + QAction *createSetBackgroundColor(QObject *parent); + +private Q_SLOTS: + void saveScreenshot(); + void setBackgroundColor(); + + void submitEvents(NLMISC::CEventServer &server, bool allWindows) { } + void emulateMouseRawMode(bool) { } + +protected: + virtual void resizeEvent(QResizeEvent *resizeEvent); + +#ifdef NL_OS_WINDOWS + virtual bool winEvent(MSG * message, long * result); +#else // NL_OS_UNIX + virtual bool x11Event(XEvent *event); +#endif + +private: + CGraphicsViewport(const CGraphicsViewport &); + CGraphicsViewport &operator=(const CGraphicsViewport &); + +}; /* class CGraphicsViewport */ + +} /* namespace NLQT */ + + +#endif // GRAPHICS_VIEWPORT_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/hoverpoints.cpp b/code/nel/tools/3d/object_viewer_qt/src/hoverpoints.cpp new file mode 100644 index 000000000..ac5de8f10 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/hoverpoints.cpp @@ -0,0 +1,408 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "stdpch.h" +#include "hoverpoints.h" + +#define printf + +HoverPoints::HoverPoints(QWidget *widget, PointShape shape) + : QObject(widget) +{ + m_widget = widget; + widget->installEventFilter(this); + widget->setAttribute(Qt::WA_AcceptTouchEvents); + + m_connectionType = CurveConnection; + m_sortType = NoSort; + m_shape = shape; + m_pointPen = QPen(QColor(255, 255, 255, 191), 1); + m_connectionPen = QPen(QColor(255, 255, 255, 127), 2); + m_pointBrush = QBrush(QColor(191, 191, 191, 127)); + m_pointSize = QSize(11, 11); + m_currentIndex = -1; + m_editable = true; + m_enabled = true; + m_minCountPoints = 2; + + createGradient(); + + connect(this, SIGNAL(pointsChanged(QPolygonF)), + m_widget, SLOT(update())); +} + + +void HoverPoints::setEnabled(bool enabled) +{ + if (m_enabled != enabled) { + m_enabled = enabled; + m_widget->update(); + } +} + + +bool HoverPoints::eventFilter(QObject *object, QEvent *event) +{ + if (object == m_widget && m_enabled) { + switch (event->type()) { + + case QEvent::MouseButtonPress: + { + if (!m_fingerPointMapping.isEmpty()) + return true; + QMouseEvent *me = (QMouseEvent *) event; + + QPointF clickPos = me->pos(); + int index = -1; + for (int i=0; ibutton() == Qt::LeftButton) { + if (index == -1) { + if (!m_editable) + return false; + int pos = 0; + // Insert sort for x or y + if (m_sortType == XSort) { + for (int i=0; i clickPos.x()) { + pos = i; + break; + } + } else if (m_sortType == YSort) { + for (int i=0; i clickPos.y()) { + pos = i; + break; + } + } + + m_points.insert(pos, clickPos); + m_locks.insert(pos, 0); + m_currentIndex = pos; + firePointChange(); + + } else { + m_currentIndex = index; + } + return true; + + } else if (me->button() == Qt::RightButton) { + if (index >= 0 && m_editable) { + if ((m_points.size() - 1) < m_minCountPoints) + return true; + if (m_locks[index] == 0) { + m_locks.remove(index); + m_points.remove(index); + } + firePointChange(); + return true; + } + } + + } + break; + + case QEvent::MouseButtonRelease: + if (!m_fingerPointMapping.isEmpty()) + return true; + m_currentIndex = -1; + break; + + case QEvent::MouseMove: + if (!m_fingerPointMapping.isEmpty()) + return true; + if (m_currentIndex >= 0) + movePoint(m_currentIndex, ((QMouseEvent *)event)->pos()); + break; + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + { + const QTouchEvent *const touchEvent = static_cast(event); + const QList points = touchEvent->touchPoints(); + const qreal pointSize = qMax(m_pointSize.width(), m_pointSize.height()); + Q_FOREACH (const QTouchEvent::TouchPoint &touchPoint, points) { + const int id = touchPoint.id(); + switch (touchPoint.state()) { + case Qt::TouchPointPressed: + { + // find the point, move it + QSet activePoints = QSet::fromList(m_fingerPointMapping.values()); + int activePoint = -1; + qreal distance = -1; + const int pointsCount = m_points.size(); + const int activePointCount = activePoints.size(); + if (pointsCount == 2 && activePointCount == 1) { // only two points + activePoint = activePoints.contains(0) ? 1 : 0; + } else { + for (int i=0; i::iterator it = m_fingerPointMapping.find(id); + movePoint(it.value(), touchPoint.pos()); + m_fingerPointMapping.erase(it); + } + break; + case Qt::TouchPointMoved: + { + // move the point + const int pointIdx = m_fingerPointMapping.value(id, -1); + if (pointIdx >= 0) // do we track this point? + movePoint(pointIdx, touchPoint.pos()); + } + break; + default: + break; + } + } + if (m_fingerPointMapping.isEmpty()) { + event->ignore(); + return false; + } else { + return true; + } + } + break; + case QEvent::TouchEnd: + if (m_fingerPointMapping.isEmpty()) { + event->ignore(); + return false; + } + return true; + break; + + case QEvent::Resize: + { + QResizeEvent *e = (QResizeEvent *) event; + if (e->oldSize().width() == 0 || e->oldSize().height() == 0) + break; + qreal stretch_x = e->size().width() / qreal(e->oldSize().width()); + qreal stretch_y = e->size().height() / qreal(e->oldSize().height()); + for (int i=0; iwidth() - 2, m_widget->height() - 2), 4.0, 4.0); + + p.setBrush(QBrush()); + + if (m_connectionPen.style() != Qt::NoPen && m_connectionType != NoConnection) { + p.setPen(m_connectionPen); + + if (m_connectionType == CurveConnection) { + QPainterPath path; + path.moveTo(m_points.at(0)); + for (int i=1; i right || (lock & HoverPoints::LockToRight)) p.setX(right); + +/* if (p.y() < top || (lock & HoverPoints::LockToTop)) p.setY(top); + else if (p.y() > bottom || (lock & HoverPoints::LockToBottom)) p.setY(bottom); +*/ + + return p; +} + +void HoverPoints::setPoints(const QPolygonF &points) +{ + if (points.size() != m_points.size()) + m_fingerPointMapping.clear(); + m_points.clear(); + for (int i=0; i 0) { + m_locks.resize(m_points.size()); + + m_locks.fill(0); + } +} + + +void HoverPoints::movePoint(int index, const QPointF &point, bool emitUpdate) +{ + m_points[index] = bound_point(point, boundingRect(), m_locks.at(index)); + if (emitUpdate) + firePointChange(); +} + +void HoverPoints::createGradient() +{ + m_gradient.setCoordinateMode(QGradient::ObjectBoundingMode); + m_gradient.setCenter(0.45, 0.50); + m_gradient.setFocalPoint(0.40, 0.45); + m_gradient.setColorAt(0.0, QColor(175, 216, 252)); + m_gradient.setColorAt(0.4, QColor(151, 183, 220)); + m_gradient.setColorAt(0.8, QColor(86, 126, 191)); +} + +inline static bool x_less_than(const QPointF &p1, const QPointF &p2) +{ + return p1.x() < p2.x(); +} + + +inline static bool y_less_than(const QPointF &p1, const QPointF &p2) +{ + return p1.y() < p2.y(); +} + +void HoverPoints::firePointChange() +{ + if (m_sortType != NoSort) { + + QPointF oldCurrent; + if (m_currentIndex != -1) { + oldCurrent = m_points[m_currentIndex]; + } + + if (m_sortType == XSort) + qSort(m_points.begin(), m_points.end(), x_less_than); + else if (m_sortType == YSort) + qSort(m_points.begin(), m_points.end(), y_less_than); + + // Compensate for changed order... + if (m_currentIndex != -1) { + for (int i=0; i + +QT_FORWARD_DECLARE_CLASS(QBypassWidget) + +class HoverPoints : public QObject +{ + Q_OBJECT +public: + enum PointShape { + CircleShape, + RectangleShape + }; + + enum LockType { + LockToLeft = 0x01, + LockToRight = 0x02, + LockToTop = 0x04, + LockToBottom = 0x08 + }; + + enum SortType { + NoSort, + XSort, + YSort + }; + + enum ConnectionType { + NoConnection, + LineConnection, + CurveConnection + }; + + HoverPoints(QWidget *widget, PointShape shape); + + bool eventFilter(QObject *object, QEvent *event); + + void paintPoints(); + + inline QRectF boundingRect() const; + void setBoundingRect(const QRectF &boundingRect) { m_bounds = boundingRect; } + + QPolygonF points() const { return m_points; } + void setPoints(const QPolygonF &points); + + QSizeF pointSize() const { return m_pointSize; } + void setPointSize(const QSizeF &size) { m_pointSize = size; } + + SortType sortType() const { return m_sortType; } + void setSortType(SortType sortType) { m_sortType = sortType; } + + ConnectionType connectionType() const { return m_connectionType; } + void setConnectionType(ConnectionType connectionType) { m_connectionType = connectionType; } + + void setConnectionPen(const QPen &pen) { m_connectionPen = pen; } + void setShapePen(const QPen &pen) { m_pointPen = pen; } + void setShapeBrush(const QBrush &brush) { m_pointBrush = brush; } + + void setPointLock(int pos, LockType lock) { m_locks[pos] = lock; } + + void setEditable(bool editable) { m_editable = editable; } + bool editable() const { return m_editable; } + +public Q_SLOTS: + void setEnabled(bool enabled); + void setDisabled(bool disabled) { setEnabled(!disabled); } + +Q_SIGNALS: + void pointsChanged(const QPolygonF &points); + +public: + void firePointChange(); + +private: + inline QRectF pointBoundingRect(int i) const; + void movePoint(int i, const QPointF &newPos, bool emitChange = true); + void createGradient(); + + QWidget *m_widget; + + QPolygonF m_points; + QRectF m_bounds; + PointShape m_shape; + SortType m_sortType; + ConnectionType m_connectionType; + + QVector m_locks; + + QSizeF m_pointSize; + int m_currentIndex; + int m_minCountPoints; + bool m_editable; + bool m_enabled; + + QHash m_fingerPointMapping; + + QPen m_pointPen; + QBrush m_pointBrush; + QPen m_connectionPen; + QRadialGradient m_gradient; +}; + + +inline QRectF HoverPoints::pointBoundingRect(int i) const +{ + QPointF p = m_points.at(i); + qreal w = m_pointSize.width(); + qreal h = m_pointSize.height(); + qreal x = p.x() - w / 2; + qreal y = p.y() - h / 2; + return QRectF(x, y, w, h); +} + +inline QRectF HoverPoints::boundingRect() const +{ + if (m_bounds.isEmpty()) + return m_widget->rect(); + else + return m_bounds; +} + +#endif // HOVERPOINTS_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/.directory b/code/nel/tools/3d/object_viewer_qt/src/images/.directory new file mode 100644 index 000000000..8bcdbc317 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/images/.directory @@ -0,0 +1,3 @@ +[Dolphin] +ShowPreview=true +Timestamp=2010,8,4,0,59,20 diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/CollisionZone.bmp b/code/nel/tools/3d/object_viewer_qt/src/images/CollisionZone.bmp new file mode 100644 index 000000000..570c14348 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/CollisionZone.bmp differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/Emitter.bmp b/code/nel/tools/3d/object_viewer_qt/src/images/Emitter.bmp new file mode 100644 index 000000000..c78596918 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/Emitter.bmp differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/Force.bmp b/code/nel/tools/3d/object_viewer_qt/src/images/Force.bmp new file mode 100644 index 000000000..8627ba0db Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/Force.bmp differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/Light.bmp b/code/nel/tools/3d/object_viewer_qt/src/images/Light.bmp new file mode 100644 index 000000000..ec622e009 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/Light.bmp differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/Located.bmp b/code/nel/tools/3d/object_viewer_qt/src/images/Located.bmp new file mode 100644 index 000000000..32b5b1582 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/Located.bmp differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/LocatedInstance.bmp b/code/nel/tools/3d/object_viewer_qt/src/images/LocatedInstance.bmp new file mode 100644 index 000000000..b44267a71 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/LocatedInstance.bmp differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/Particle.bmp b/code/nel/tools/3d/object_viewer_qt/src/images/Particle.bmp new file mode 100644 index 000000000..53326694b Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/Particle.bmp differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/ParticleSystem.bmp b/code/nel/tools/3d/object_viewer_qt/src/images/ParticleSystem.bmp new file mode 100644 index 000000000..19345172e Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/ParticleSystem.bmp differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/ParticleSystemNotLoaded.bmp b/code/nel/tools/3d/object_viewer_qt/src/images/ParticleSystemNotLoaded.bmp new file mode 100644 index 000000000..23bc58d42 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/ParticleSystemNotLoaded.bmp differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/Sound.bmp b/code/nel/tools/3d/object_viewer_qt/src/images/Sound.bmp new file mode 100644 index 000000000..7c379927a Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/Sound.bmp differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/Workspace.bmp b/code/nel/tools/3d/object_viewer_qt/src/images/Workspace.bmp new file mode 100644 index 000000000..3215fe757 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/Workspace.bmp differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/anim.png b/code/nel/tools/3d/object_viewer_qt/src/images/anim.png new file mode 100644 index 000000000..a617d2397 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/anim.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/animset.png b/code/nel/tools/3d/object_viewer_qt/src/images/animset.png new file mode 100644 index 000000000..e16e70346 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/animset.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/clear.png b/code/nel/tools/3d/object_viewer_qt/src/images/clear.png new file mode 100644 index 000000000..551ce7c96 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/clear.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/dqynight.png b/code/nel/tools/3d/object_viewer_qt/src/images/dqynight.png new file mode 100644 index 000000000..ef7c38684 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/dqynight.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/go-down.png b/code/nel/tools/3d/object_viewer_qt/src/images/go-down.png new file mode 100644 index 000000000..780714b8f Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/go-down.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/go-up.png b/code/nel/tools/3d/object_viewer_qt/src/images/go-up.png new file mode 100644 index 000000000..7174fa8be Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/go-up.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/ico_bgcolor.png b/code/nel/tools/3d/object_viewer_qt/src/images/ico_bgcolor.png new file mode 100644 index 000000000..49eac810a Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/ico_bgcolor.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/ico_framedelay.png b/code/nel/tools/3d/object_viewer_qt/src/images/ico_framedelay.png new file mode 100644 index 000000000..c72969a20 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/ico_framedelay.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/ico_skelscale.png b/code/nel/tools/3d/object_viewer_qt/src/images/ico_skelscale.png new file mode 100644 index 000000000..9d6455da2 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/ico_skelscale.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/insert-horizontal.png b/code/nel/tools/3d/object_viewer_qt/src/images/insert-horizontal.png new file mode 100644 index 000000000..247889d4a Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/insert-horizontal.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/insert.png b/code/nel/tools/3d/object_viewer_qt/src/images/insert.png new file mode 100644 index 000000000..4143a38b6 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/insert.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/list-add.png b/code/nel/tools/3d/object_viewer_qt/src/images/list-add.png new file mode 100644 index 000000000..af5b56e3c Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/list-add.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/list-remove.png b/code/nel/tools/3d/object_viewer_qt/src/images/list-remove.png new file mode 100644 index 000000000..678b34df7 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/list-remove.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/mixer.png b/code/nel/tools/3d/object_viewer_qt/src/images/mixer.png new file mode 100644 index 000000000..90a4109cd Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/mixer.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/nel.png b/code/nel/tools/3d/object_viewer_qt/src/images/nel.png new file mode 100644 index 000000000..d2139bb25 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/nel.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/nel_ide_load.png b/code/nel/tools/3d/object_viewer_qt/src/images/nel_ide_load.png new file mode 100644 index 000000000..217259d04 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/nel_ide_load.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/new.png b/code/nel/tools/3d/object_viewer_qt/src/images/new.png new file mode 100644 index 000000000..61db97ae4 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/new.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/open-file.png b/code/nel/tools/3d/object_viewer_qt/src/images/open-file.png new file mode 100644 index 000000000..7422ad333 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/open-file.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/pause.png b/code/nel/tools/3d/object_viewer_qt/src/images/pause.png new file mode 100644 index 000000000..5c7d128ee Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/pause.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/play.png b/code/nel/tools/3d/object_viewer_qt/src/images/play.png new file mode 100644 index 000000000..71906857c Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/play.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/pqrticles.png b/code/nel/tools/3d/object_viewer_qt/src/images/pqrticles.png new file mode 100644 index 000000000..ed1d41f5b Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/pqrticles.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/preferences.png b/code/nel/tools/3d/object_viewer_qt/src/images/preferences.png new file mode 100644 index 000000000..729bc0393 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/preferences.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/refresh.png b/code/nel/tools/3d/object_viewer_qt/src/images/refresh.png new file mode 100644 index 000000000..0b08b2388 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/refresh.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/save-as.png b/code/nel/tools/3d/object_viewer_qt/src/images/save-as.png new file mode 100644 index 000000000..ed2453d9f Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/save-as.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/save.png b/code/nel/tools/3d/object_viewer_qt/src/images/save.png new file mode 100644 index 000000000..cc380a03a Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/save.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/seek-backward.png b/code/nel/tools/3d/object_viewer_qt/src/images/seek-backward.png new file mode 100644 index 000000000..644d3e2d0 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/seek-backward.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/seek-forward.png b/code/nel/tools/3d/object_viewer_qt/src/images/seek-forward.png new file mode 100644 index 000000000..51881ea8d Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/seek-forward.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/skip-backward.png b/code/nel/tools/3d/object_viewer_qt/src/images/skip-backward.png new file mode 100644 index 000000000..bcf2376d6 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/skip-backward.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/skip-forward.png b/code/nel/tools/3d/object_viewer_qt/src/images/skip-forward.png new file mode 100644 index 000000000..843660679 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/skip-forward.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/sound.png b/code/nel/tools/3d/object_viewer_qt/src/images/sound.png new file mode 100644 index 000000000..2862fa399 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/sound.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/stop.png b/code/nel/tools/3d/object_viewer_qt/src/images/stop.png new file mode 100644 index 000000000..650874f67 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/stop.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/time.png b/code/nel/tools/3d/object_viewer_qt/src/images/time.png new file mode 100644 index 000000000..09ef0c6c6 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/time.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/veget.png b/code/nel/tools/3d/object_viewer_qt/src/images/veget.png new file mode 100644 index 000000000..4767f2ea2 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/veget.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/water.png b/code/nel/tools/3d/object_viewer_qt/src/images/water.png new file mode 100644 index 000000000..0b3be8795 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/water.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/images/wind.png b/code/nel/tools/3d/object_viewer_qt/src/images/wind.png new file mode 100644 index 000000000..f16d38931 Binary files /dev/null and b/code/nel/tools/3d/object_viewer_qt/src/images/wind.png differ diff --git a/code/nel/tools/3d/object_viewer_qt/src/located_bindable_form.ui b/code/nel/tools/3d/object_viewer_qt/src/located_bindable_form.ui new file mode 100644 index 000000000..8af23ac48 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/located_bindable_form.ui @@ -0,0 +1,776 @@ + + + CLocatedBindablePage + + + + 0 + 0 + 352 + 494 + + + + + 0 + 0 + + + + Form + + + + + + + 0 + 0 + + + + QTabWidget::East + + + 0 + + + Qt::ElideNone + + + false + + + true + + + + + 0 + 0 + + + + + + + + + + + + Blending mode: + + + + + + + + Add + + + + + Modulate + + + + + Alpha blend + + + + + Alpha test + + + + + + + + + + Global color lighting + + + + + + + Z-Test + + + + + + + + + ZBias: + + + + + + + -9999.000000000000000 + + + 9999.000000000000000 + + + + + + + + + Qt::Vertical + + + + 20 + 21 + + + + + + + + No AutoLOD + + + + + + + Color + + + + + + + + + 0 + 0 + + + + + + + + + + Independant size + + + + + + + false + + + + + + + + + Width + + + true + + + + + + + Height + + + + + + + + + + Qt::Vertical + + + + 31 + 354 + + + + + + + + Size + + + + + + + Angle 2D + + + + + + + + + 0 + 0 + + + + + + + + + + hint / precomputed rotations + + + + + + + false + + + + + + + + + Rot speed min: + + + + + + + + + + Rot speed max: + + + + + + + + + + Nb models: + + + + + + + 1 + + + 32 + + + + + + + + + + Qt::Vertical + + + + 17 + 184 + + + + + + + + Rotation + + + + + + + + + 0 + 0 + + + + + + + + + + Align on motion + + + + + + + Z-Align + + + + + + + Fake motion blur coeff.: + + + + + + + + + + Fake motion blur treshold: + + + + + + + + + + Qt::Vertical + + + + 20 + 203 + + + + + + + + + + 0 + 0 + + + + + + + + + + Radius cut: + + + + + + + + + + Number of segs: + + + + + + + + + + Texture U factor: + + + + + + + + + + Qt::Vertical + + + + 20 + 251 + + + + + + + + + + 0 + 0 + + + + + + + + + + Number fan light: + + + + + + + + + + Phase smoothnes: + + + + + + + + + + Fan light speed: + + + + + + + + + + Fan light intensity: + + + + + + + + + + Qt::Vertical + + + + 20 + 229 + + + + + + + + + + 0 + 0 + + + + + + + + + + Nb segs: + + + + + + + + + + Seg duration: + + + + + + + + + + Texture U factor: + + + + + + + + + + Texture V factor: + + + + + + + + + + + + + + + + Non parametric anim only + + + Force constant length + + + + + + + Use hermitte interpolation + + + + + + + Trail coord. system: + + + + + + + + Local + + + + + World + + + + + User + + + + + Father coord. system + + + + + + + + Length(m): + + + + + + + false + + + + + + + LOD degradation: + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 133 + + + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 407 + + + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 463 + + + + + + + + + + + + + NLQT::CParticleTextureWidget + QWidget +
particle_texture_widget.h
+ 1 +
+ + NLQT::CEditRangeUIntWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CAttribFloatWidget + QGroupBox +
attrib_widget.h
+ 1 +
+ + NLQT::CMeshWidget + QWidget +
mesh_widget.h
+ 1 +
+ + NLQT::CConstraintMeshWidget + QWidget +
constraint_mesh_widget.h
+ 1 +
+ + NLQT::CTailParticleWidget + QWidget +
tail_particle_widget.h
+ 1 +
+ + NLQT::CParticleTextureAnimWidget + QWidget +
particle_texture_anim_widget.h
+ 1 +
+ + NLQT::CAttribRGBAWidget + QGroupBox +
attrib_widget.h
+ 1 +
+ + NLQT::CAttribPlaneBasisWidget + QGroupBox +
attrib_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/located_bindable_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/located_bindable_page.cpp new file mode 100644 index 000000000..dfafa7a64 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/located_bindable_page.cpp @@ -0,0 +1,686 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "located_bindable_page.h" + +// Qt includes + +// NeL includes +#include +#include "nel/3d/ps_mesh.h" + +// Project includes +#include "modules.h" + +namespace NLQT { + +CLocatedBindablePage::CLocatedBindablePage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + // Particle color + _ui.colorWidget->setWrapper(&_ColorWrapper); + _ui.colorWidget->setSchemeWrapper(&_ColorWrapper); + _ui.colorWidget->init(); + + // Particle angle 2d + _ui.angle2DWidget->setRange(0.f, 256.f); + _ui.angle2DWidget->setWrapper(&_Angle2DWrapper); + _ui.angle2DWidget->setSchemeWrapper(&_Angle2DWrapper); + _ui.angle2DWidget->init(); + + // Particle size + _ui.sizeWidget->setRange(0.0, 1.0); + _ui.sizeWidget->setWrapper(&_SizeWrapper); + _ui.sizeWidget->setSchemeWrapper(&_SizeWrapper); + _ui.sizeWidget->init(); + + // Particle plane bias + _ui.particlePlaneBasicWidget->setWrapper(&_PlaneBasisWrapper); + _ui.particlePlaneBasicWidget->setSchemeWrapper(&_PlaneBasisWrapper); + _ui.particlePlaneBasicWidget->init(); + + // Fake motion blur coeff + _ui.blurCoeffWidget->setRange(0.0, 5.0); + _ui.blurCoeffWidget->setWrapper(&_MotionBlurCoeffWrapper); + + // Fake motion blur threshold + _ui.blurTresholdWidget->setRange(0.0, 5.0); + _ui.blurTresholdWidget->setWrapper(&_MotionBlurThresholdWrapper); + + // Shock wave radius cut + _ui.radiusCutWidget->setRange(0, 1); + _ui.radiusCutWidget->setWrapper(&_RadiusCutWrapper); + + // Shock wave number segment + _ui.shockWaveNbSegWidget->setRange(3, 24); + _ui.shockWaveNbSegWidget->enableLowerBound(3, false); + _ui.shockWaveNbSegWidget->setWrapper(&_ShockWaveNbSegWrapper); + + // Shock wave texture U factor + _ui.shockWaveUFactorWidget->setRange(0, 5); + _ui.shockWaveUFactorWidget->setWrapper(&_ShockWaveUFactorWrapper); + + // Num fan light + _ui.nbFanLightWidget->setRange(3, 127); + _ui.nbFanLightWidget->enableLowerBound(3, false); + _ui.nbFanLightWidget->enableUpperBound(128, true); + _ui.nbFanLightWidget->setWrapper(&_FanLightWrapper); + + // Fan light phase smoothnes + _ui.phaseSmoothnesWidget->setRange(0, 31); + _ui.phaseSmoothnesWidget->enableUpperBound(32, true); + _ui.phaseSmoothnesWidget->setWrapper(&_FanLightSmoothnessWrapper); + + // Fan light speed + _ui.fanLightSpeedWidget->setRange(0, 4.f); + _ui.fanLightSpeedWidget->setWrapper(&_FanLightPhaseWrapper); + + // Fan light intensity + _ui.fanLightIntensityWidget->setRange(0, 4.f); + _ui.fanLightIntensityWidget->setWrapper(&_FanLightIntensityWrapper); + + // Tail number segs / Look At ribbon tail nb segs + _ui.tailNbSegsWidget->setRange(2, 16); + _ui.tailNbSegsWidget->enableLowerBound(1, true); + _ui.tailNbSegsWidget->setWrapper(&_TailParticleWrapper); + + // Ribbon texture U factor + _ui.ribbonTexUfactorWidget->setRange(0, 5); + _ui.ribbonTexUfactorWidget->setWrapper(&_RibbonUFactorWrapper); + + // Ribbon texture V factor + _ui.ribbonTexVfactorWidget->setRange(0, 5); + _ui.ribbonTexVfactorWidget->setWrapper(&_RibbonVFactorWrapper); + + // Ribbon segment duration + _ui.segDurationWidget->setRange(0.05f, 0.5f); + _ui.segDurationWidget->enableLowerBound(0, true); + _ui.segDurationWidget->setWrapper(&_SegDurationWrapper); + + // Length + _ui.ribbonLengthWidget->setRange(0.1f, 10.1f); + _ui.ribbonLengthWidget->setWrapper(&_RibbonLengthWrapper); + _ui.ribbonLengthWidget->enableLowerBound(0.f, true); + + // Lod degradation + _ui.lodDegradationWidget->setRange(0.f, 1.f); + _ui.lodDegradationWidget->setWrapper(&_LODDegradationWrapper); + _ui.lodDegradationWidget->enableLowerBound(0.f, false); + _ui.lodDegradationWidget->enableUpperBound(1.f, false); + + _ui.particleTextureWidget->setWrapper(&_TextureNoAnimWrapper); + _ui.particleTextureWidget->enableRemoveButton(true); + + hideAllWidget(); + + connect(_ui.autoLodCheckBox, SIGNAL(toggled(bool)), this, SLOT(setAutoLOD(bool))); + connect(_ui.globalColorLightingCheckBox, SIGNAL(toggled(bool)), this, SLOT(setGlobalColorLight(bool))); + connect(_ui.independantSizeCheckBox, SIGNAL(toggled(bool)), this, SLOT(setIndependantSize(bool))); + connect(_ui.alignCheckBox, SIGNAL(toggled(bool)), this, SLOT(setAlignOnMotion(bool))); + connect(_ui.ztestCheckBox, SIGNAL(toggled(bool)), this, SLOT(setZTest(bool))); + connect(_ui.zalignCheckBox, SIGNAL(toggled(bool)), this, SLOT(setZAlign(bool))); + connect(_ui.rotationPCCheckBox, SIGNAL(toggled(bool)), this, SLOT(setHint(bool))); + connect(_ui.blendModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setBlendMode(int))); + connect(_ui.zbiasDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setZBias(double))); + connect(_ui.widthRadioButton, SIGNAL(clicked()), this, SLOT(setSizeWidth())); + connect(_ui.heightRadioButton, SIGNAL(clicked()), this, SLOT(setSizeWidth())); + connect(_ui.rotSpeedMaxDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setRotSpeedMax(double))); + connect(_ui.rotSpeedMinDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setRotSpeedMin(double))); + connect(_ui.numModelsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setNumModels(int))); + connect(_ui.useHermitteCheckBox, SIGNAL(toggled(bool)), this, SLOT(setUseHermitteInterpolation(bool))); + connect(_ui.constantLengthCheckBox, SIGNAL(toggled(bool)), this, SLOT(setConstantLength(bool))); + connect(_ui.coordSystemComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setTrailCoordSystem(int))); +} + +CLocatedBindablePage::~CLocatedBindablePage() +{ +} + +void CLocatedBindablePage::setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocatedBindable *locatedBindable) +{ + _Node = ownerNode; + _Bindable = locatedBindable; + + hideAllWidget(); + + // No Auto LOD + NL3D::CParticleSystem *ps = _Bindable->getOwner()->getOwner(); + if (ps->isSharingEnabled()) + { + _ui.autoLodCheckBox->show(); + if (ps->isAutoLODEnabled() == false) + _ui.autoLodCheckBox->setChecked(false); + else + _ui.autoLodCheckBox->setChecked(NLMISC::safe_cast(_Bindable)->isAutoLODDisabled()); + } + else + _ui.autoLodCheckBox->hide(); + + // has the particle a material ? + bool isMaterial = dynamic_cast(_Bindable) != NULL; + + _ui.blendModeComboBox->setVisible(isMaterial); + _ui.blendModeLabel->setVisible(isMaterial); + _ui.zbiasDoubleSpinBox->setVisible(isMaterial); + _ui.zbiasLabel->setVisible(isMaterial); + _ui.ztestCheckBox->setVisible(isMaterial); + + if (isMaterial) + { + NL3D::CPSMaterial *material = dynamic_cast(_Bindable); + // blending mode + _ui.blendModeComboBox->setCurrentIndex(material->getBlendingMode()); + // z-test + _ui.ztestCheckBox->setChecked(material->isZTestEnabled()); + // z-bias + _ui.zbiasDoubleSpinBox->setValue(-material->getZBias()); + } + + if (dynamic_cast(_Bindable)) + { + NL3D::CPSParticle *p = (NL3D::CPSParticle *) _Bindable; + + // check support for lighting + if (p->supportGlobalColorLighting()) + { + _ui.globalColorLightingCheckBox->show(); + // if global color lighting is forced for all objects, don't allow to modify + _ui.globalColorLightingCheckBox->setEnabled(!ps->getForceGlobalColorLightingFlag()); + _ui.globalColorLightingCheckBox->setChecked(p->usesGlobalColorLighting()); + } + else + _ui.globalColorLightingCheckBox->hide(); + + // check support for color + if (dynamic_cast(_Bindable)) + { + _ColorWrapper.S = dynamic_cast(_Bindable); + _ui.colorWidget->setWorkspaceNode(_Node); + _ui.colorWidget->updateUi(); + + // Add material page in tabWidget + _ui.tabWidget->addTab(_ui.materialPage, tr("Material")); + } + + if (dynamic_cast(_Bindable)) + { + updateSizeControl(); + + // Size/Angle2D page in tabWidget + _ui.tabWidget->addTab(_ui.sizeAnglePage, tr("Size/Angle 2D")); + } + + // check support for angle 2D + if (dynamic_cast(_Bindable)) + { + _Angle2DWrapper.S = dynamic_cast(_Bindable); + _ui.angle2DWidget->setWorkspaceNode(_Node); + _ui.angle2DWidget->updateUi(); + _ui.angle2DWidget->show(); + } + else + _ui.angle2DWidget->hide(); + + // check support for plane basis + if (dynamic_cast(_Bindable)) + { + _PlaneBasisWrapper.S = dynamic_cast(_Bindable); + _ui.particlePlaneBasicWidget->setWorkspaceNode(_Node); + _ui.particlePlaneBasicWidget->updateUi(); + _ui.particlePlaneBasicWidget->setEnabled(true); + + // Add material page in tabWidget + _ui.tabWidget->addTab(_ui.rotatePage, tr("Rotations")); + } + + // check support for precomputed rotations + bool isHintParticle = dynamic_cast(_Bindable) != NULL; + _ui.rotationPCCheckBox->setVisible(isHintParticle); + _ui.rotGroupBox->setVisible(isHintParticle); + if (isHintParticle) + { + NL3D::CPSHintParticleRotateTheSame *rotatedParticle = dynamic_cast(_Bindable); + float minValue, maxValue; + uint32 nbModels = rotatedParticle->checkHintRotateTheSame(minValue, maxValue); + _ui.rotationPCCheckBox->setChecked(nbModels != 0); + } + + // if we're dealing with a face look at, motion blur can be tuned + if (dynamic_cast(_Bindable)) + { + NL3D::CPSFaceLookAt *fla = static_cast(_Bindable); + _MotionBlurCoeffWrapper.P = fla; + _MotionBlurCoeffWrapper.OwnerNode = _Node; + _ui.blurCoeffWidget->updateUi(); + + _MotionBlurThresholdWrapper.P = fla; + _MotionBlurThresholdWrapper.OwnerNode = _Node; + _ui.blurTresholdWidget->updateUi(); + + _ui.zalignCheckBox->show(); + _ui.alignCheckBox->show(); + _ui.alignCheckBox->setChecked(fla->getAlignOnMotion()); + _ui.zalignCheckBox->setChecked(fla->getAlignOnZAxis()); + + // 'look at' independant sizes + _ui.independantSizeCheckBox->setChecked(fla->hasIndependantSizes()); + + _ui.independantSizeCheckBox->show(); + _ui.independantGroupBox->show(); + + // Add Look at page in tabWidget + _ui.tabWidget->addTab(_ui.lookAtPage, tr("Look At param")); + } + else + { + _ui.independantSizeCheckBox->hide(); + _ui.independantGroupBox->hide(); + } + + // Shock wave page setup + if (dynamic_cast(_Bindable)) + { + NL3D::CPSShockWave *sw = static_cast(_Bindable); + + _RadiusCutWrapper.OwnerNode = _Node; + _RadiusCutWrapper.S = sw; + _ui.radiusCutWidget->updateUi(); + + _ShockWaveNbSegWrapper.OwnerNode = _Node; + _ShockWaveNbSegWrapper.S = sw; + _ui.shockWaveNbSegWidget->updateUi(); + + _ShockWaveUFactorWrapper.OwnerNode = _Node; + _ShockWaveUFactorWrapper.S = sw; + _ui.shockWaveUFactorWidget->updateUi(); + + // Add Shock wave page in tabWidget + _ui.tabWidget->addTab(_ui.shockWavePage, tr("Shock wave param")); + } + + // Fan Light page setup + if (dynamic_cast(_Bindable)) + { + _FanLightWrapper.OwnerNode = _Node; + _FanLightWrapper.P = dynamic_cast(_Bindable); + _ui.nbFanLightWidget->updateUi(); + + _FanLightSmoothnessWrapper.OwnerNode = _Node; + _FanLightSmoothnessWrapper.P = static_cast(_Bindable); + _ui.phaseSmoothnesWidget->updateUi(); + + _FanLightPhaseWrapper.OwnerNode = _Node; + _FanLightPhaseWrapper.P = static_cast(_Bindable); + _ui.fanLightSpeedWidget->updateUi(); + + _FanLightIntensityWrapper.OwnerNode = _Node; + _FanLightIntensityWrapper.P = static_cast(_Bindable); + _ui.fanLightIntensityWidget->updateUi(); + + // Add Fan Light page in tabWidget + _ui.tabWidget->addTab(_ui.fanLightPage, tr("Fan Light param")); + } + + // tail particle + if (dynamic_cast(_Bindable)) + { + if (dynamic_cast(_Bindable)) + _ui.tailNbSegsWidget->enableUpperBound(256, true); + + _TailParticleWrapper.OwnerNode = _Node; + _TailParticleWrapper.P = dynamic_cast(_Bindable); + _ui.tailNbSegsWidget->updateUi(); + + _ui.tailWidget->setCurrentTailParticle(_Node, dynamic_cast(_Bindable)); + + _ui.ribbonTexUfactorWidget->hide(); + _ui.ribbonTexVfactorWidget->hide(); + _ui.tailTexUflabel->hide(); + _ui.tailTexVflabel->hide(); + + // Add tail page in tabWidget + _ui.tabWidget->addTab(_ui.ribbonTailPage, tr("Tail param")); + } + + // shape particle + if (dynamic_cast(_Bindable)) + { + _ui.meshWidget->setCurrentShape(_Node, dynamic_cast(_Bindable)); + + // Add mesh page in tabWidget + _ui.tabWidget->addTab(_ui.meshPage, tr("Mesh param")); + } + + // constraint mesh particle + if (dynamic_cast(_Bindable)) + { + _ui.constraintMeshWidget->setCurrentConstraintMesh(_Node, dynamic_cast(_Bindable)); + _ui.constraintMeshWidget->show(); + } + else + _ui.constraintMeshWidget->hide(); + + + // check support for animated texture + if (dynamic_cast(_Bindable)) + { + _ui.texAnimWidget->setCurrentTextureAnim(dynamic_cast(_Bindable), + dynamic_cast(_Bindable), + _Node); + _ui.texAnimWidget->show(); + + _ui.tabWidget->addTab(_ui.texturePage, tr("Texture param")); + } + else + _ui.texAnimWidget->hide(); + + // unanimated texture + if (dynamic_cast(_Bindable)) + { + _TextureNoAnimWrapper.TP = dynamic_cast(_Bindable); + _TextureNoAnimWrapper.OwnerNode = _Node; + + _ui.particleTextureWidget->updateUi(); + _ui.particleTextureWidget->show(); + + _ui.tabWidget->addTab(_ui.texturePage, tr("Texture param")); + } + else + _ui.particleTextureWidget->hide(); + + // ribbon texture (doesn't support texture animation for now) + if (dynamic_cast(_Bindable)) + { + _RibbonUFactorWrapper.OwnerNode = _Node; + _RibbonUFactorWrapper.R = static_cast(_Bindable); + _ui.ribbonTexUfactorWidget->updateUi(); + + _RibbonVFactorWrapper.OwnerNode = _Node; + _RibbonVFactorWrapper.R = static_cast(_Bindable); + _ui.ribbonTexVfactorWidget->updateUi(); + + _ui.ribbonTexUfactorWidget->show(); + _ui.ribbonTexVfactorWidget->show(); + _ui.tailTexUflabel->show(); + _ui.tailTexVflabel->show(); + + } + + if (dynamic_cast(_Bindable)) + { + NL3D::CPSRibbonBase *ribbon = static_cast(_Bindable); + + _SegDurationWrapper.R = ribbon; + _ui.segDurationWidget->updateUi(); + + // Length + _RibbonLengthWrapper.OwnerNode = _Node; + _RibbonLengthWrapper.R = ribbon; + _ui.ribbonLengthWidget->updateUi(); + + // Lod degradation + _LODDegradationWrapper.OwnerNode = _Node; + _LODDegradationWrapper.R = ribbon; + _ui.lodDegradationWidget->updateUi(); + + // Coord system + _ui.coordSystemComboBox->setCurrentIndex(ribbon->getMatrixMode()); + _ui.useHermitteCheckBox->setChecked(ribbon->getInterpolationMode() == NL3D::CPSRibbonBase::Hermitte); + _ui.constantLengthCheckBox->setChecked(ribbon->getRibbonMode() == NL3D::CPSRibbonBase::FixedSize); + } + } +} + +void CLocatedBindablePage::setAutoLOD(bool state) +{ + NL3D::CPSParticle *p = NLMISC::safe_cast(_Bindable); + nlassert(p); + if (state != p->isAutoLODDisabled()) + { + p->disableAutoLOD(state); + updateModifiedFlag(); + } +} + +void CLocatedBindablePage::setBlendMode(int index) +{ + NL3D::CPSMaterial *m = dynamic_cast(_Bindable); + nlassert(m); + if (index != m->getBlendingMode()) + { + m->setBlendingMode( (NL3D::CPSMaterial::TBlendingMode)index); + touchPSState(); + updateModifiedFlag(); + } +} + +void CLocatedBindablePage::setGlobalColorLight(bool state) +{ + NL3D::CPSParticle *p = NLMISC::safe_cast(_Bindable); + nlassert(p); + if (state != p->usesGlobalColorLighting()) + { + p->enableGlobalColorLighting(state); + touchPSState(); + updateModifiedFlag(); + } +} + +void CLocatedBindablePage::setIndependantSize(bool state) +{ + NL3D::CPSFaceLookAt *la = static_cast(_Bindable); + nlassert(la); + if (state != la->hasIndependantSizes()) + { + la->setIndependantSizes(state); + updateModifiedFlag(); + } + _ui.independantGroupBox->setEnabled(state); + updateSizeControl(); +} + +void CLocatedBindablePage::setAlignOnMotion(bool state) +{ + NL3D::CPSFaceLookAt *fla = NLMISC::safe_cast(_Bindable); + nlassert(fla); + if (state != fla->getAlignOnMotion()) + { + fla->setAlignOnMotion(state); + updateModifiedFlag(); + } + updateValidWidgetForAlignOnMotion(!state); +} + +void CLocatedBindablePage::setZTest(bool state) +{ + NL3D::CPSMaterial *mat = dynamic_cast(_Bindable); + nlassert(mat); + if (state != mat->isZTestEnabled()) + { + mat->enableZTest(state); + updateModifiedFlag(); + } +} + +void CLocatedBindablePage::setZAlign(bool state) +{ + NL3D::CPSFaceLookAt *fla = NLMISC::safe_cast(_Bindable); + nlassert(fla); + if (state != fla->getAlignOnZAxis()) + { + fla->setAlignOnZAxis(state); + updateModifiedFlag(); + } +} + +void CLocatedBindablePage::setZBias(double value) +{ + NLMISC::safe_cast(_Bindable)->setZBias(-value); +} + +void CLocatedBindablePage::setSizeWidth() +{ + updateSizeControl(); +} + +void CLocatedBindablePage::setHint(bool state) +{ + NL3D::CPSHintParticleRotateTheSame *rotatedParticle = dynamic_cast(_Bindable); + float minVelocity, maxVelocity; + uint32 nbModels = rotatedParticle->checkHintRotateTheSame(minVelocity, maxVelocity); + nlassert(rotatedParticle); + if ((nbModels != 0) != state) + { + if (state) + _ui.numModelsSpinBox->setValue(32); + else + rotatedParticle->disableHintRotateTheSame(); + updateModifiedFlag(); + } + _ui.rotGroupBox->setEnabled(state); + _ui.particlePlaneBasicWidget->setEnabled(!state); + rotatedParticle->checkHintRotateTheSame(minVelocity, maxVelocity); + _ui.rotSpeedMaxDoubleSpinBox->setValue(maxVelocity); + _ui.rotSpeedMinDoubleSpinBox->setValue(minVelocity); +} + +void CLocatedBindablePage::setRotSpeedMax(double value) +{ + NL3D::CPSHintParticleRotateTheSame *rotatedParticle = dynamic_cast(_Bindable); + nlassert(rotatedParticle); + float valueMin, valueMax; + uint32 nbModels = rotatedParticle->checkHintRotateTheSame(valueMin, valueMax); + if (valueMax != value) + { + rotatedParticle->hintRotateTheSame(nbModels, valueMin, value); + updateModifiedFlag(); + } +} + +void CLocatedBindablePage::setRotSpeedMin(double value) +{ + NL3D::CPSHintParticleRotateTheSame *rotatedParticle = dynamic_cast(_Bindable); + nlassert(rotatedParticle); + float valueMin, valueMax; + uint32 nbModels = rotatedParticle->checkHintRotateTheSame(valueMin, valueMax); + if (valueMin != value) + { + rotatedParticle->hintRotateTheSame(nbModels, value, valueMax); + updateModifiedFlag(); + } +} + +void CLocatedBindablePage::setNumModels(int value) +{ + NL3D::CPSHintParticleRotateTheSame *rotatedParticle = dynamic_cast(_Bindable); + nlassert(rotatedParticle); + float valueMin, valueMax; + sint32 nbModels; + + nbModels = rotatedParticle->checkHintRotateTheSame(valueMin, valueMax); + if (nbModels != value) + { + rotatedParticle->hintRotateTheSame((uint32) value, valueMin, valueMax); + updateModifiedFlag(); + } +} + +void CLocatedBindablePage::setUseHermitteInterpolation(bool state) +{ + NL3D::CPSRibbonBase *ribbon = dynamic_cast(_Bindable); + ribbon->setInterpolationMode(state ? NL3D::CPSRibbonBase::Hermitte : NL3D::CPSRibbonBase::Linear); +} + +void CLocatedBindablePage::setConstantLength(bool state) +{ + NL3D::CPSRibbonBase *ribbon = dynamic_cast(_Bindable); + ribbon->setRibbonMode(state ? NL3D::CPSRibbonBase::FixedSize : NL3D::CPSRibbonBase::VariableSize); + _ui.ribbonLengthWidget->setEnabled(state); + _ui.ribbonLengthLabel->setEnabled(state); +} + +void CLocatedBindablePage::setTrailCoordSystem(int index) +{ + NL3D::CPSRibbonBase *ribbon = dynamic_cast(_Bindable); + if (index != ribbon->getMatrixMode()) + { + ribbon->setMatrixMode((NL3D::CPSRibbonBase::TMatrixMode) index); + updateModifiedFlag(); + } +} + +void CLocatedBindablePage::updateValidWidgetForAlignOnMotion(bool align) +{ + _ui.blurCoeffLabel->setEnabled(align); + _ui.blurCoeffWidget->setEnabled(align); + _ui.blurTreshholdLabel->setEnabled(align); + _ui.blurTresholdWidget->setEnabled(align); + _ui.zalignCheckBox->setEnabled(align); +} + +void CLocatedBindablePage::updateSizeControl() +{ + if (!dynamic_cast(_Bindable)) return; + + NL3D::CPSFaceLookAt *fla = dynamic_cast(_Bindable); + // LookAt case + if (fla && fla->hasIndependantSizes()) + { + if (_ui.widthRadioButton->isChecked()) + _ui.sizeWidget->setTitle(tr("Width")); + else + _ui.sizeWidget->setTitle(tr("Height")); + + if (_ui.widthRadioButton->isChecked()) // wrap to the wanted size + _SizeWrapper.S = fla; + else + _SizeWrapper.S = &fla->getSecondSize(); + } + else // general case. Wrap to the size interface and the appropriate dialog + { + _SizeWrapper.S = dynamic_cast(_Bindable); + _ui.sizeWidget->setTitle(tr("Size")); + } + + _ui.sizeWidget->setWorkspaceNode(_Node); + _ui.sizeWidget->updateUi(); +} + +void CLocatedBindablePage::hideAllWidget() +{ + for (int i = 0; i < _ui.tabWidget->count(); i++) + _ui.tabWidget->widget(i)->hide(); + + while (_ui.tabWidget->count() != 0) + _ui.tabWidget->removeTab(_ui.tabWidget->count() - 1); +} + +void CLocatedBindablePage::touchPSState() +{ + if (_Node && _Node->getPSModel()) + { + _Node->getPSModel()->touchTransparencyState(); + _Node->getPSModel()->touchLightableState(); + } +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/located_bindable_page.h b/code/nel/tools/3d/object_viewer_qt/src/located_bindable_page.h new file mode 100644 index 000000000..cde2bc254 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/located_bindable_page.h @@ -0,0 +1,260 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef LOCATED_BINDABLE_PAGE_H +#define LOCATED_BINDABLE_PAGE_H + +#include +#include "ui_located_bindable_form.h" + +// STL includes + +// NeL includes +#include "nel/misc/rgba.h" +#include "nel/3d/texture.h" +#include "nel/3d/ps_plane_basis.h" +#include "nel/3d/particle_system.h" +#include "nel/3d/ps_particle.h" +#include "nel/3d/ps_particle2.h" + +// Project includes +#include "ps_wrapper.h" +#include "particle_node.h" + +namespace NLQT { + +/** +@class CLocatedBindablePage +@brief Page for QStackWidget, to edit located bindables in a particle system +*/ +class CLocatedBindablePage: public QWidget +{ + Q_OBJECT + +public: + CLocatedBindablePage(QWidget *parent = 0); + ~CLocatedBindablePage(); + + /// Set the located bindable to edit. + void setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocatedBindable *locatedBindable); + +private Q_SLOTS: + void setAutoLOD(bool state); + void setBlendMode(int index); + void setGlobalColorLight(bool state); + void setIndependantSize(bool state); + void setAlignOnMotion(bool state); + void setZTest(bool state); + void setZAlign(bool state); + void setZBias(double value); + void setSizeWidth(); + void setHint(bool state); + void setRotSpeedMax(double value); + void setRotSpeedMin(double value); + void setNumModels(int value); + void setUseHermitteInterpolation(bool state); + void setConstantLength(bool state); + void setTrailCoordSystem(int index); + +private: + + /// Wrappers to various element of bindables + + /// Size + struct CSizeWrapper : public IPSWrapperFloat, IPSSchemeWrapperFloat + { + NL3D::CPSSizedParticle *S; + float get(void) const { return S->getSize(); } + void set(const float &v) { S->setSize(v); } + scheme_type *getScheme(void) const { return S->getSizeScheme(); } + void setScheme(scheme_type *s) { S->setSizeScheme(s); } + } _SizeWrapper; + + /// Color + struct CColorWrapper : public IPSWrapperRGBA, IPSSchemeWrapperRGBA + { + NL3D::CPSColoredParticle *S; + NLMISC::CRGBA get(void) const { return S->getColor(); } + void set(const NLMISC::CRGBA &v) { S->setColor(v); } + scheme_type *getScheme(void) const { return S->getColorScheme(); } + void setScheme(scheme_type *s) { S->setColorScheme(s); } + } _ColorWrapper; + + /// Angle 2D + struct CAngle2DWrapper : public IPSWrapperFloat, IPSSchemeWrapperFloat + { + NL3D::CPSRotated2DParticle *S; + float get(void) const { return S->getAngle2D(); } + void set(const float &v) { S->setAngle2D(v); } + scheme_type *getScheme(void) const { return S->getAngle2DScheme(); } + void setScheme(scheme_type *s) { S->setAngle2DScheme(s); } + } _Angle2DWrapper; + + /// Plane basis + struct CPlaneBasisWrapper : public IPSWrapper, IPSSchemeWrapper + { + NL3D::CPSRotated3DPlaneParticle *S; + NL3D::CPlaneBasis get(void) const { return S->getPlaneBasis(); } + void set(const NL3D::CPlaneBasis &p) { S->setPlaneBasis(p); } + scheme_type *getScheme(void) const { return S->getPlaneBasisScheme(); } + void setScheme(scheme_type *s) { S->setPlaneBasisScheme(s); } + } _PlaneBasisWrapper; + + /// Motion blur coeff + struct CMotionBlurCoeffWrapper : public IPSWrapperFloat + { + NL3D::CPSFaceLookAt *P; + float get(void) const { return P->getMotionBlurCoeff(); } + void set(const float &v) { P->setMotionBlurCoeff(v); } + } _MotionBlurCoeffWrapper; + struct CMotionBlurThresholdWrapper : public IPSWrapperFloat + { + NL3D::CPSFaceLookAt *P; + float get(void) const { return P->getMotionBlurThreshold(); } + void set(const float &v) { P->setMotionBlurThreshold(v); } + } _MotionBlurThresholdWrapper; + + /// Fanlight + struct CFanLightWrapper : public IPSWrapperUInt + { + NL3D::CPSFanLight *P; + uint32 get(void) const { return P->getNbFans(); } + void set(const uint32 &v) { P->setNbFans(v); } + } _FanLightWrapper; + + struct CFanLightSmoothnessWrapper : public IPSWrapperUInt + { + NL3D::CPSFanLight *P; + uint32 get(void) const { return P->getPhaseSmoothness(); } + void set(const uint32 &v) { P->setPhaseSmoothness(v); } + } _FanLightSmoothnessWrapper; + + struct CFanLightPhase : public IPSWrapperFloat + { + NL3D::CPSFanLight *P; + float get(void) const { return P->getPhaseSpeed(); } + void set(const float &v) { P->setPhaseSpeed(v); } + } _FanLightPhaseWrapper; + + struct CFanLightIntensityWrapper : public IPSWrapperFloat + { + NL3D::CPSFanLight *P; + float get(void) const { return P->getMoveIntensity(); } + void set(const float &v) { P->setMoveIntensity(v); } + } _FanLightIntensityWrapper; + + /// Ribbon / tail dot + struct CTailParticleWrapper : public IPSWrapperUInt + { + NL3D::CPSTailParticle *P; + uint32 get(void) const { return P->getTailNbSeg(); } + void set(const uint32 &v) { P->setTailNbSeg(v); } + } _TailParticleWrapper; + + /// Duration of segment for a ribbon + struct CSegDurationWrapper : public IPSWrapperFloat + { + NL3D::CPSRibbonBase *R; + float get(void) const { return R->getSegDuration(); } + void set(const float &v) { R->setSegDuration(v); } + } _SegDurationWrapper; + + /// Shockwave + struct CRadiusCutWrapper : public IPSWrapperFloat + { + NL3D::CPSShockWave *S; + float get(void) const { return S->getRadiusCut(); } + void set(const float &v) { S->setRadiusCut(v); } + } _RadiusCutWrapper; + + struct CShockWaveNbSegWrapper : public IPSWrapperUInt + { + NL3D::CPSShockWave *S; + uint32 get(void) const { return S->getNbSegs(); } + void set(const uint32 &v) { S->setNbSegs(v); } + } _ShockWaveNbSegWrapper; + + struct CShockWaveUFactorWrapper : public IPSWrapperFloat + { + NL3D::CPSShockWave *S; + float get(void) const { return S->getUFactor(); } + void set(const float &v) { S->setUFactor(v); } + } _ShockWaveUFactorWrapper; + + /// Unanimated texture + struct CTextureNoAnimWrapper : public IPSWrapperTexture + { + NL3D::CPSTexturedParticleNoAnim *TP; + virtual NL3D::ITexture *get(void) { return TP->getTexture(); } + virtual void set(NL3D::ITexture *t) { TP->setTexture(t); } + } _TextureNoAnimWrapper; + + /// u / v factors for ribbon + struct CRibbonUFactorWrapper : public IPSWrapperFloat + { + NL3D::CPSRibbon *R; + float get(void) const { return R->getUFactor(); } + void set(const float &u) { R->setTexFactor(u, R->getVFactor()); } + } _RibbonUFactorWrapper; + + struct CRibbonVFactorWrapper : public IPSWrapperFloat + { + NL3D::CPSRibbon *R; + float get(void) const { return R->getVFactor(); } + void set(const float &v) { R->setTexFactor(R->getUFactor(), v); } + } _RibbonVFactorWrapper; + + struct CRibbonLengthWrapper : IPSWrapperFloat + { + NL3D::CPSRibbonBase *R; + float get() const { return R->getRibbonLength(); } + void set(const float &v) { R->setRibbonLength(v); } + } _RibbonLengthWrapper; + + + struct CLODDegradationWrapper : IPSWrapperFloat + { + NL3D::CPSRibbonBase *R; + float get() const { return R->getLODDegradation(); } + void set(const float &v) { R->setLODDegradation(v); } + } _LODDegradationWrapper; + + void updateValidWidgetForAlignOnMotion(bool align); + + void updateSizeControl(); + + void updateModifiedFlag() { if (_Node) _Node->setModified(true); } + + void hideAllWidget(); + + void touchPSState(); + + CWorkspaceNode *_Node; + + /// The bindable being edited + NL3D::CPSLocatedBindable *_Bindable; + + Ui::CLocatedBindablePage _ui; + +}; /* class CLocatedBindablePage */ + +} /* namespace NLQT */ + + +#endif // LOCATED_BINDABLE_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/located_form.ui b/code/nel/tools/3d/object_viewer_qt/src/located_form.ui new file mode 100644 index 000000000..106b1bebd --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/located_form.ui @@ -0,0 +1,233 @@ + + + CLocatedPage + + + + 0 + 0 + 291 + 410 + + + + Form + + + + + + QTabWidget::East + + + 0 + + + + General + + + + + + Coord system: + + + + + + + + Particles are local to the system + + + + + Particles are in world + + + + + User + + + + + + + + Disgrade with lod + + + + + + + Parametric motion + + + + + + + Max number of particles: + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Set current count particles + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 61 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 224 + + + + + + + + + Life time + + + + + + Limited life time + + + + + + + + + + + + + Triger on death + + + + + + + Edit + + + + + + + + + + Qt::Vertical + + + + 20 + 251 + + + + + + + + + + + + Particle mass + + + + + + Qt::Vertical + + + + 20 + 274 + + + + + + + + + + + + + + + + NLQT::CEditRangeUIntWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CAttribFloatWidget + QGroupBox +
attrib_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/located_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/located_page.cpp new file mode 100644 index 000000000..7956a66c8 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/located_page.cpp @@ -0,0 +1,265 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "located_page.h" + +// Qt includes +#include +#include + +// NeL includes +#include + +// Project includes +#include "modules.h" + +namespace NLQT { + +CLocatedPage::CLocatedPage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + _ui.lifeWidget->setRange(0, 10); + _ui.lifeWidget->setWrapper(&_LifeWrapper); + _ui.lifeWidget->setSchemeWrapper(&_LifeWrapper); + /// WARNING:// 0 is disallowed + ///_ui.lifeWidget->enableLowerBound(0, true); + _ui.lifeWidget->enableMemoryScheme(false); + _ui.lifeWidget->init(); + + _ui.massWidget->setRange(0.001f, 10); + _ui.massWidget->setWrapper(&_MassWrapper); + _ui.massWidget->setSchemeWrapper(&_MassWrapper); + /// WARNING:// 0 is disallowed + ///_ui.massWidget->enableLowerBound(0, true); + _ui.massWidget->enableMemoryScheme(false); + _ui.massWidget->init(); + + _ui.maxNumParticleWidget->setRange(1, 501); + _ui.maxNumParticleWidget->enableUpperBound(1 << 16, true); + _ui.maxNumParticleWidget->setWrapper(&_MaxNbParticlesWrapper); + + connect(_ui.coordSystemComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setMatrixMode(int))); + connect(_ui.disgradeWithLODCheckBox, SIGNAL(toggled(bool)), this, SLOT(setDisgradeWithLod(bool))); + connect(_ui.parametricMotionCheckBox, SIGNAL(toggled(bool)), this, SLOT(setParametricMotion(bool))); + connect(_ui.trigerOnDeathCheckBox, SIGNAL(toggled(bool)), this, SLOT(setTriggerOnDeath(bool))); + connect(_ui.editPushButton, SIGNAL(clicked()), this, SLOT(editTriggerOnDeath())); + connect(_ui.limitedLifeTimeCheckBox, SIGNAL(toggled(bool)), this, SLOT(setLimitedLifeTime(bool))); + connect(_ui.setCurrentCountPushButton, SIGNAL(clicked()), this, SLOT(setCount())); +} + +CLocatedPage::~CLocatedPage() +{ +} + +void CLocatedPage::setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocated *located) +{ + _Located = located; + _Node = ownerNode; + + _LifeWrapper.Located = _Located; + _LifeWrapper.Node = _Node; + _ui.lifeWidget->setWorkspaceNode(_Node); + _ui.lifeWidget->updateUi(); + + if (_Located->getLastForever()) + _ui.lifeWidget->setEnabled(false); + + + _MassWrapper.Located = _Located; + _ui.massWidget->setWorkspaceNode(_Node); + _ui.massWidget->updateUi(); + + if (_Located->getOwner()) + _ui.maxNumParticleWidget->setEnabled(!_Located->getOwner()->getAutoCountFlag()); + + _MaxNbParticlesWrapper.Located = _Located; + _MaxNbParticlesWrapper.Node = _Node; + _ui.maxNumParticleWidget->updateUi(); + + _ui.coordSystemComboBox->setCurrentIndex(int(_Located->getMatrixMode())); + _ui.limitedLifeTimeCheckBox->setChecked(!_Located->getLastForever()); + _ui.lifeWidget->setEnabled(!_Located->getLastForever()); + _ui.trigerOnDeathCheckBox->setChecked(_Located->isTriggerOnDeathEnabled()); + updateTriggerOnDeath(); + + _ui.disgradeWithLODCheckBox->setChecked(_Located->hasLODDegradation()); + updateIntegrable(); + updateTriggerOnDeath(); +} + +void CLocatedPage::setDisabledCountPS(bool state) +{ + _ui.setCurrentCountPushButton->setEnabled(!state); + _ui.maxNumParticleWidget->setEnabled(!state); +} + +void CLocatedPage::setLimitedLifeTime(bool state) +{ + if (state != _Located->getLastForever()) return; + if (!state) + { + bool forceApplied = false; + // check that no force are applied on the located + std::vector targeters; + _Located->getOwner()->getTargeters(_Located, targeters); + for(uint k = 0; k < targeters.size(); ++k) + { + if (targeters[k]->getType() == NL3D::PSForce) + { + forceApplied = true; + break; + } + } + if (forceApplied) + { + int ret = QMessageBox::critical(this, tr("NeL particle system editor"), + tr("The object has force(s) applied on it. If it last forever, " + "its motion can become instable after a while. Continue anyway ? (clue : you've been warned ..)"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) + { + _ui.limitedLifeTimeCheckBox->setChecked(true); + return; + } + } + if (_Located->setLastForever()) + { + _ui.lifeWidget->setEnabled(false); + } + else + { + QMessageBox::critical(this, tr("NeL particle system editor"), + tr("Can't perform operation : the system is flagged with 'No max nb steps' or uses the preset 'Spell FX', " + "and thus, should have a finite duration. Please remove that flag first."), + QMessageBox::Ok); + _ui.limitedLifeTimeCheckBox->setChecked(true); + } + } + else + { + _Located->setInitialLife(_Located->getInitialLife()); + _ui.lifeWidget->setEnabled(true); + } + updateTriggerOnDeath(); + Modules::psEdit().resetAutoCount(_Node); + updateModifiedFlag(); +} + +void CLocatedPage::setDisgradeWithLod(bool state) +{ + if (state != _Located->hasLODDegradation()) + { + _Located->forceLODDegradation(state); + updateModifiedFlag(); + } +} + +void CLocatedPage::setParametricMotion(bool state) +{ + if (state != _Located->isParametricMotionEnabled()) + { + _Located->enableParametricMotion(state); + updateModifiedFlag(); + } +} + +void CLocatedPage::editTriggerOnDeath() +{ + bool ok; + int i = QInputDialog::getInt(this, tr("Set the extern ID"), + tr("0 means no extern access."), + _Located->getTriggerEmitterID(), 0, 9999, 1, &ok); + if (ok) + { + _Located->setTriggerEmitterID(uint32(i)); + updateModifiedFlag(); + } +} + +void CLocatedPage::setTriggerOnDeath(bool state) +{ + if (state != _Located->isTriggerOnDeathEnabled()) + { + _Located->enableTriggerOnDeath(state); + updateTriggerOnDeath(); + updateModifiedFlag(); + } +} + +void CLocatedPage::setMatrixMode(int index) +{ + nlassert(_Located); + if (index != _Located->getMatrixMode()) + { + _Located->setMatrixMode((NL3D::TPSMatrixMode) index); + updateIntegrable(); + updateModifiedFlag(); + } +} + +void CLocatedPage::setCount() +{ + _Located->resize(_Located->getSize()); // set new max size + _ui.maxNumParticleWidget->updateUi(); + updateModifiedFlag(); +} + +void CLocatedPage::updateIntegrable(void) +{ + _ui.parametricMotionCheckBox->setChecked(_Located->isParametricMotionEnabled()); + _ui.parametricMotionCheckBox->setEnabled(_Located->supportParametricMotion()); +} + +void CLocatedPage::updateTriggerOnDeath(void) +{ + nlassert(_Located); + bool enable = !_Located->getLastForever(); + _ui.trigerOnDeathCheckBox->setEnabled(enable); + _ui.editPushButton->setEnabled(enable && _Located->isTriggerOnDeathEnabled()); +} + +void CLocatedPage::CMaxNbParticlesWrapper::set(const uint32 &v) +{ + // if the max new size is lower than the current number of instance, we must suppress item + // in the the CParticleTreeCtrl + if (v < Located->getSize()) + { + nlassert(Node); + /// WARNING: + ///TreeCtrl->suppressLocatedInstanceNbItem(*Node, v); + } + Located->resize(v); +} + +void CLocatedPage::CLifeWrapper::set(const float &v) +{ + Located->setInitialLife(v); + Modules::psEdit().resetAutoCount(Node); +} +void CLocatedPage::CLifeWrapper::setScheme(scheme_type *s) +{ + Located->setLifeScheme(s); + Modules::psEdit().resetAutoCount(Node); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/located_page.h b/code/nel/tools/3d/object_viewer_qt/src/located_page.h new file mode 100644 index 000000000..ba5100114 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/located_page.h @@ -0,0 +1,117 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef LOCATED_PAGE_H +#define LOCATED_PAGE_H + +#include +#include "ui_located_form.h" + +// Qt includes + +// STL includes + +// NeL includes + +// Project includes + +namespace NL3D +{ + class CPSLocated; +} + +namespace NLQT { + +/** +@class CLocatedPage +@brief Page for QStackWidget, to edit located in a particle system +*/ +class CLocatedPage: public QWidget +{ + Q_OBJECT + +public: + CLocatedPage(QWidget *parent = 0); + ~CLocatedPage(); + + /// Set the located to edit. + void setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocated *located); + +private Q_SLOTS: + void setDisabledCountPS(bool state); + void setLimitedLifeTime(bool state); + void setDisgradeWithLod(bool state); + void setParametricMotion(bool state); + void editTriggerOnDeath(); + void setTriggerOnDeath(bool state); + void setMatrixMode(int index); + void setCount(); + +private: + + /// wrapper to tune the max number of particles + struct CMaxNbParticlesWrapper : public IPSWrapperUInt + { + CWorkspaceNode *Node; + NL3D::CPSLocated *Located; + uint32 get(void) const { return Located->getMaxSize(); } + void set(const uint32 &v); + } _MaxNbParticlesWrapper; + + + /// wrapper to tune the mass of particles + struct CMassWrapper : public IPSWrapperFloat, IPSSchemeWrapperFloat + { + NL3D::CPSLocated *Located; + float get(void) const { return Located->getInitialMass(); } + void set(const float &v) { Located->setInitialMass(v); } + virtual scheme_type *getScheme(void) const { return Located->getMassScheme(); } + virtual void setScheme(scheme_type *s) { Located->setMassScheme(s); } + } _MassWrapper; + + struct CLifeWrapper : public IPSWrapperFloat, IPSSchemeWrapperFloat + { + NL3D::CPSLocated *Located; + CWorkspaceNode *Node; + float get(void) const { return Located->getInitialLife(); } + void set(const float &v); + virtual scheme_type *getScheme(void) const { return Located->getLifeScheme(); } + virtual void setScheme(scheme_type *s); + } _LifeWrapper; + + /// the located this dialog is editing + NL3D::CPSLocated *_Located; + + CWorkspaceNode *_Node; + + /// update the integrable check box + void updateIntegrable(void); + + /// update the 'trigger on death' control + void updateTriggerOnDeath(void); + + void updateModifiedFlag() { if (_Node) _Node->setModified(true); } + + Ui::CLocatedPage _ui; +}; /* class CLocatedPage */ + +} /* namespace NLQT */ + + +#endif // LOCATED_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/main.cpp b/code/nel/tools/3d/object_viewer_qt/src/main.cpp new file mode 100644 index 000000000..3e11d0648 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/main.cpp @@ -0,0 +1,101 @@ +#include "stdpch.h" +#include +#include + +// Qt includes +#include +#include + +// NeL includes +#include +#include +#include +#include +#include + +// Project includes +#include "modules.h" + +// nel_qt log file name +#define NLQT_LOG_FILE "nel_qt.log" + +// clear nel_qt log before use +#define NLQT_ERASE_LOG true + +#if !defined (NLQT_USE_LOG_LOG) +# define NLQT_USE_LOG_LOG true +#endif +#if !defined (NLQT_USE_LOG) +# define NLQT_USE_LOG 1 +#endif + +using namespace std; +using namespace NLMISC; + +namespace NLQT { + +namespace { + +CFileDisplayer *s_FileDisplayer = NULL; + +} /* anonymous namespace */ + +} /* namespace NLQT */ + +#ifndef DATA_DIR +# define DATA_DIR "." +#endif + + +#ifdef NL_OS_WINDOWS +# ifdef _UNICODE +# define tstring wstring +# else +# define tstring string +# endif +#endif + +sint main(int argc, char **argv) +{ + // go nel! + { + // use log.log if NEL_LOG_IN_FILE and NLQT_USE_LOG_LOG defined as 1 + createDebug(NULL, NLQT_USE_LOG_LOG, false); +#if NLQT_USE_LOG + // create toverhex_client.log + // filedisplayer only deletes the 001 etc + if (NLQT_ERASE_LOG && CFile::isExists(NLQT_LOG_FILE)) + CFile::deleteFile(NLQT_LOG_FILE); + // initialize the log file + NLQT::s_FileDisplayer = new CFileDisplayer(); + NLQT::s_FileDisplayer->setParam(NLQT_LOG_FILE, NLQT_ERASE_LOG); + DebugLog->addDisplayer(NLQT::s_FileDisplayer); + InfoLog->addDisplayer(NLQT::s_FileDisplayer); + WarningLog->addDisplayer(NLQT::s_FileDisplayer); + AssertLog->addDisplayer(NLQT::s_FileDisplayer); + ErrorLog->addDisplayer(NLQT::s_FileDisplayer); +#endif + + nlinfo("Welcome to NeL!"); + + NLMISC::CPath::remapExtension("tga", "png", true); + } + + QApplication app(argc, argv); + QSplashScreen *splash = new QSplashScreen(); + splash->setPixmap(QPixmap(":/images/nel_ide_load.png")); + splash->show(); + + Modules::init(); + + // load and set remap extensions from config + Modules::config().configRemapExtensions(); + // load and set search paths from config + Modules::config().configSearchPaths(); + + Modules::mainWin().showMaximized(); + splash->finish(&Modules::mainWin()); + int result = app.exec(); + Modules::release(); + return result; +} diff --git a/code/nel/tools/3d/object_viewer_qt/src/main_window.cpp b/code/nel/tools/3d/object_viewer_qt/src/main_window.cpp new file mode 100644 index 000000000..85fd0c099 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/main_window.cpp @@ -0,0 +1,636 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "main_window.h" + +// STL includes + +// Qt includes +#include + +// NeL includes +#include + +// Project includes +#include "modules.h" +#include "settings_dialog.h" +#include "graphics_viewport.h" +#include "animation_dialog.h" +#include "animation_set_dialog.h" +#include "particle_control_dialog.h" +#include "particle_workspace_dialog.h" +#include "slot_manager_dialog.h" +#include "setup_fog_dialog.h" +#include "skeleton_scale_dialog.h" +#include "skeleton_tree_model.h" +#include "water_pool_dialog.h" +#include "vegetable_dialog.h" +#include "global_wind_dialog.h" +#include "day_night_dialog.h" +#include "sun_color_dialog.h" + +using namespace std; +using namespace NLMISC; + +namespace NLQT { + +CMainWindow::CMainWindow(QWidget *parent) + : QMainWindow(parent), + _isGraphicsInitialized(false), _isGraphicsEnabled(false), + _isSoundInitialized(false), _isSoundEnabled(false), + _isLandscapeInitialized(false), _isLandscapeEnabled(false), + _GraphicsViewport(NULL), _lastDir(".") +{ + nldebug("CMainWindow::CMainWindow:"); + + // create NeL viewport + _GraphicsViewport = new CGraphicsViewport(this); + setCentralWidget(_GraphicsViewport); + + setDockNestingEnabled(true); + + // setup Qt style and palette from config file + _originalPalette = QApplication::palette(); + Modules::config().setAndCallback("QtStyle", CConfigCallback(this, &CMainWindow::cfcbQtStyle)); + Modules::config().setAndCallback("QtPalette", CConfigCallback(this, &CMainWindow::cfcbQtPalette)); + + _SkeletonTreeModel = new CSkeletonTreeModel(this); + + createDialogs(); + createActions(); + createMenus(); + createToolBars(); + createStatusBar(); + + setWindowIcon(QIcon(":/images/nel.png")); + + QSettings settings("object_viewer_qt.ini", QSettings::IniFormat); + settings.beginGroup("WindowSettings"); + restoreState(settings.value("QtWindowState").toByteArray()); + restoreGeometry(settings.value("QtWindowGeometry").toByteArray()); + settings.endGroup(); + + _isGraphicsEnabled = true; + _isLandscapeEnabled = true; + + // As a special case, a QTimer with a timeout of 0 will time out as soon as all the events in the window system's event queue have been processed. + // This can be used to do heavy work while providing a snappy user interface. + _mainTimer = new QTimer(this); + connect(_mainTimer, SIGNAL(timeout()), this, SLOT(updateRender())); + // timer->start(); // <- timeout 0 + // it's heavy on cpu, though, when no 3d driver initialized :) + _mainTimer->start(25); // 25fps + + _statusBarTimer = new QTimer(this); + connect(_statusBarTimer, SIGNAL(timeout()), this, SLOT(updateStatusBar())); + _statusBarTimer->start(5000); + + Modules::config().setAndCallback("SoundEnabled", CConfigCallback(this, &CMainWindow::cfcbSoundEnabled)); +} + +CMainWindow::~CMainWindow() +{ + nldebug("CMainWindow::~CMainWindow:"); + + // save state & geometry of window and widgets + QSettings settings("object_viewer_qt.ini", QSettings::IniFormat); + settings.beginGroup("WindowSettings"); + settings.setValue("QtWindowState", saveState()); + settings.setValue("QtWindowGeometry", saveGeometry()); + settings.endGroup(); + + Modules::config().dropCallback("SoundEnabled"); + Modules::config().dropCallback("QtPalette"); + Modules::config().dropCallback("QtStyle"); + + _mainTimer->stop(); + _statusBarTimer->stop(); + + delete _AnimationDialog; + delete _AnimationSetDialog; + delete _SlotManagerDialog; + delete _SetupFog; + delete _ParticleControlDialog; + delete _ParticleWorkspaceDialog; + delete _GraphicsViewport; +} + +void CMainWindow::setVisible(bool visible) +{ + // called by show() + // code assuming visible window needed to init the 3d driver + if (visible != isVisible()) + { + if (visible) + { + QMainWindow::setVisible(true); + updateInitialization(true); + } + else + { + updateInitialization(false); + QMainWindow::setVisible(false); + } + } +} + +int CMainWindow::getFrameRate() +{ + return _AnimationDialog->_frameRate; +} + +void CMainWindow::open() +{ + QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Open NeL data file"), _lastDir, + tr("All NeL files (*.shape *.ps);;" + "NeL shape files (*.shape);;" + "NeL particle system files (*.ps)")); + + setCursor(Qt::WaitCursor); + if (!fileNames.isEmpty()) + { + QStringList list = fileNames; + _lastDir = QFileInfo(list.front()).absolutePath(); + + QString skelFileName = QFileDialog::getOpenFileName(this, + tr("Open skeleton file"), _lastDir, + tr("NeL skeleton file (*.skel)")); + + Q_FOREACH(QString fileName, list) + loadFile(fileName, skelFileName); + + _AnimationSetDialog->updateListObject(); + _AnimationSetDialog->updateListAnim(); + _SlotManagerDialog->updateUiSlots(); + } + setCursor(Qt::ArrowCursor); +} + +void CMainWindow::resetScene() +{ + Modules::objView().resetScene(); + _AnimationSetDialog->updateListObject(); + _AnimationSetDialog->updateListAnim(); + _SlotManagerDialog->updateUiSlots(); + _SkeletonTreeModel->resetTreeModel(); +} + +void CMainWindow::settings() +{ + CSettingsDialog _settingsDialog(this); + _settingsDialog.show(); + _settingsDialog.exec(); +} + +void CMainWindow::about() +{ + QMessageBox::about(this, tr("About Object Viewer Qt"), + tr("

Object Viewer Qt 8-)

" + "

Authors: dnk-88, sfb, Kaetemi, kervala

Compiled on %1 %2").arg(__DATE__).arg(__TIME__)); +} + +void CMainWindow::updateStatusBar() +{ + if (_isGraphicsInitialized) + statusBar()->showMessage(QString(Modules::objView().getDriver()->getVideocardInformation())); +} + +void CMainWindow::updateInitialization(bool visible) +{ + bool done; + do + { + done = true; // set false whenever change + bool wantSound = _isSoundEnabled && visible; + bool wantGraphics = _isGraphicsEnabled && visible; + // TODO WARNING: made Landscape stuff + bool wantLandscape = wantGraphics && _isGraphicsInitialized && _isLandscapeEnabled; + + // .. stuff that depends on other stuff goes on top to prioritize deinitialization + + // Landscape + if (_isLandscapeInitialized) + { + if (!wantLandscape) + { + _isLandscapeInitialized = false; +// if (_isGraphicsInitialized) +// Modules::veget().releaseGraphics(); + Modules::veget().release(); + done = false; + } + } + else + { + if (wantLandscape) + { + Modules::veget().init(); +// if (_isGraphicsInitialized) +// Modules::veget().initGraphics(); + _isLandscapeInitialized = true; + done = false; + } + } + + // Graphics (Driver) + if (_isGraphicsInitialized) + { + if (!wantGraphics) + { + _isGraphicsInitialized = false; + if (_isSoundInitialized) + Modules::sound().releaseGraphics(); + _GraphicsViewport->release(); + done = false; + } + } + else + { + if (wantGraphics) + { + _GraphicsViewport->init(); + if (_isSoundInitialized) + Modules::sound().initGraphics(); + _isGraphicsInitialized = true; + done = false; + } + } + + // Sound (AudioMixer) + if (_isSoundInitialized) + { + if (!wantSound) + { + _isSoundInitialized = false; + if (_isGraphicsInitialized) + Modules::sound().releaseGraphics(); + Modules::sound().release(); + done = false; + } + } + else + { + if (wantSound) + { + Modules::sound().init(); + if (_isGraphicsInitialized) + Modules::sound().initGraphics(); + _isSoundInitialized = true; + done = false; + } + } + + } while (!done); +} + +void CMainWindow::createActions() +{ + _openAction = new QAction(tr("&Open..."), this); + _openAction->setIcon(QIcon(":/images/open-file.png")); + _openAction->setShortcut(QKeySequence::Open); + _openAction->setStatusTip(tr("Open an existing file")); + connect(_openAction, SIGNAL(triggered()), this, SLOT(open())); + + _exitAction = new QAction(tr("E&xit"), this); + _exitAction->setShortcut(tr("Ctrl+Q")); + _exitAction->setStatusTip(tr("Exit the application")); + connect(_exitAction, SIGNAL(triggered()), this, SLOT(close())); + + _setBackColorAction = _GraphicsViewport->createSetBackgroundColor(this); + _setBackColorAction->setText(tr("Set &background color")); + _setBackColorAction->setIcon(QIcon(":/images/ico_bgcolor.png")); + _setBackColorAction->setStatusTip(tr("Set background color")); + + _resetSceneAction = new QAction(tr("&Reset scene"), this); + _resetSceneAction->setStatusTip(tr("Reset current scene")); + connect(_resetSceneAction, SIGNAL(triggered()), this, SLOT(resetScene())); + + _saveScreenshotAction = _GraphicsViewport->createSaveScreenshotAction(this); + _saveScreenshotAction->setText(tr("Save &Screenshot")); + _saveScreenshotAction->setStatusTip(tr("Make a screenshot of the current viewport and save")); + + _settingsAction = new QAction(tr("&Settings"), this); + _settingsAction->setIcon(QIcon(":/images/preferences.png")); + _settingsAction->setStatusTip(tr("Settings")); + connect(_settingsAction, SIGNAL(triggered()), this, SLOT(settings())); + + _aboutAction = new QAction(tr("&About"), this); + _aboutAction->setStatusTip(tr("Show the application's About box")); + connect(_aboutAction, SIGNAL(triggered()), this, SLOT(about())); + + _aboutQtAction = new QAction(tr("About &Qt"), this); + _aboutQtAction->setStatusTip(tr("Show the Qt library's About box")); + connect(_aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); +} + +void CMainWindow::createMenus() +{ + _fileMenu = menuBar()->addMenu(tr("&File")); + _fileMenu->addAction(_openAction); + _fileMenu->addSeparator(); + _fileMenu->addAction(_exitAction); + + _viewMenu = menuBar()->addMenu(tr("&View")); + _viewMenu->addAction(_setBackColorAction); + _viewMenu->addAction(_SetupFog->toggleViewAction()); + + _sceneMenu = menuBar()->addMenu(tr("&Scene")); + _sceneMenu->addAction(_resetSceneAction); + _sceneMenu->addAction(_saveScreenshotAction); + + _toolsMenu = menuBar()->addMenu(tr("&Tools")); + + _toolsMenu->addAction(_AnimationDialog->toggleViewAction()); + _AnimationDialog->toggleViewAction()->setIcon(QIcon(":/images/anim.png")); + + _toolsMenu->addAction(_AnimationSetDialog->toggleViewAction()); + _AnimationSetDialog->toggleViewAction()->setIcon(QIcon(":/images/animset.png")); + + _toolsMenu->addAction(_SlotManagerDialog->toggleViewAction()); + _SlotManagerDialog->toggleViewAction()->setIcon(QIcon(":/images/mixer.png")); + + _toolsMenu->addAction(_ParticleControlDialog->toggleViewAction()); + _ParticleControlDialog->toggleViewAction()->setIcon(QIcon(":/images/pqrticles.png")); + + _toolsMenu->addAction(_DayNightDialog->toggleViewAction()); + _DayNightDialog->toggleViewAction()->setIcon(QIcon(":/images/dqynight.png")); + + _toolsMenu->addAction(_WaterPoolDialog->toggleViewAction()); + _WaterPoolDialog->toggleViewAction()->setIcon(QIcon(":/images/water.png")); + _WaterPoolDialog->toggleViewAction()->setEnabled(false); + + _toolsMenu->addAction(_VegetableDialog->toggleViewAction()); + _VegetableDialog->toggleViewAction()->setIcon(QIcon(":/images/veget.png")); + + _toolsMenu->addAction(_GlobalWindDialog->toggleViewAction()); + _GlobalWindDialog->toggleViewAction()->setIcon(QIcon(":/images/wind.png")); + + _toolsMenu->addAction(_SkeletonScaleDialog->toggleViewAction()); + _SkeletonScaleDialog->toggleViewAction()->setIcon(QIcon(":/images/ico_skelscale.png")); + + _toolsMenu->addAction(_SunColorDialog->toggleViewAction()); + + connect(_ParticleControlDialog->toggleViewAction(), SIGNAL(triggered(bool)), + _ParticleWorkspaceDialog, SLOT(setVisible(bool))); + + connect(_ParticleControlDialog->toggleViewAction(), SIGNAL(triggered(bool)), + _ParticleWorkspaceDialog->_PropertyDialog, SLOT(setVisible(bool))); + + _toolsMenu->addSeparator(); + + _toolsMenu->addAction(_settingsAction); + + menuBar()->addSeparator(); + + _helpMenu = menuBar()->addMenu(tr("&Help")); + _helpMenu->addAction(_aboutAction); + _helpMenu->addAction(_aboutQtAction); +} + +void CMainWindow::createToolBars() +{ + _fileToolBar = addToolBar(tr("&File")); + _fileToolBar->addAction(_openAction); + + //_editToolBar = addToolBar(tr("&Edit")); + //_editToolBar->addSeparator(); + _toolsBar = addToolBar(tr("&Tools")); + _toolsBar->addAction(_AnimationDialog->toggleViewAction()); + _toolsBar->addAction(_AnimationSetDialog->toggleViewAction()); + _toolsBar->addAction(_SlotManagerDialog->toggleViewAction()); + _toolsBar->addAction(_ParticleControlDialog->toggleViewAction()); + _toolsBar->addAction(_DayNightDialog->toggleViewAction()); + _toolsBar->addAction(_WaterPoolDialog->toggleViewAction()); + _toolsBar->addAction(_VegetableDialog->toggleViewAction()); + _toolsBar->addAction(_GlobalWindDialog->toggleViewAction()); + _toolsBar->addAction(_SkeletonScaleDialog->toggleViewAction()); +} + +void CMainWindow::createStatusBar() +{ + statusBar()->showMessage(tr("StatusReady")); +} + +void CMainWindow::createDialogs() +{ + // create animation dialog + _AnimationDialog = new CAnimationDialog(this); + addDockWidget(Qt::BottomDockWidgetArea, _AnimationDialog); + _AnimationDialog->setVisible(false); + + // create animation set manager dialog + _AnimationSetDialog = new CAnimationSetDialog(this); + addDockWidget(Qt::LeftDockWidgetArea, _AnimationSetDialog); + _AnimationSetDialog->setVisible(false); + + // create animation slot manager dialog + _SlotManagerDialog = new CSlotManagerDialog(this); + addDockWidget(Qt::RightDockWidgetArea, _SlotManagerDialog); + _SlotManagerDialog->setVisible(false); + + // create particle control dialog + _ParticleControlDialog = new CParticleControlDialog(_SkeletonTreeModel ,this); + addDockWidget(Qt::BottomDockWidgetArea, _ParticleControlDialog); + _ParticleControlDialog->setVisible(false); + + // create particle workspace dialog + _ParticleWorkspaceDialog = new CParticleWorkspaceDialog(this); + addDockWidget(Qt::LeftDockWidgetArea, _ParticleWorkspaceDialog); + _ParticleWorkspaceDialog->setVisible(false); + + // create day night (water) dialog + _DayNightDialog = new CDayNightDialog(this); + addDockWidget(Qt::BottomDockWidgetArea, _DayNightDialog); + _DayNightDialog->setVisible(false); + + // create water pool editor dialog + _WaterPoolDialog = new CWaterPoolDialog(this); + addDockWidget(Qt::RightDockWidgetArea, _WaterPoolDialog); + _WaterPoolDialog->setVisible(false); + + // create vegetable editor dialog + _VegetableDialog = new CVegetableDialog(this); + addDockWidget(Qt::RightDockWidgetArea, _VegetableDialog); + _VegetableDialog->setVisible(false); + + // create global wind power/direction dialog + _GlobalWindDialog = new CGlobalWindDialog(this); + addDockWidget(Qt::TopDockWidgetArea, _GlobalWindDialog); + _GlobalWindDialog->setVisible(false); + + // create sun color dialog + _SunColorDialog = new CSunColorDialog(this); + addDockWidget(Qt::LeftDockWidgetArea, _SunColorDialog); + _SunColorDialog->setVisible(false); + + // add property editor in widget area + addDockWidget(Qt::RightDockWidgetArea, _ParticleWorkspaceDialog->_PropertyDialog); + _ParticleWorkspaceDialog->_PropertyDialog->setVisible(false); + + // create skeleton scale dialog + _SkeletonScaleDialog = new CSkeletonScaleDialog(_SkeletonTreeModel, this); + addDockWidget(Qt::RightDockWidgetArea, _SkeletonScaleDialog); + _SkeletonScaleDialog->setVisible(false); + + // create setup fog dialog + _SetupFog = new CSetupFog(this); + addDockWidget(Qt::RightDockWidgetArea, _SetupFog); + _SetupFog->setVisible(false); + + connect(_ParticleControlDialog, SIGNAL(changeState()), _ParticleWorkspaceDialog, SLOT(setNewState())); + connect(_ParticleWorkspaceDialog, SIGNAL(changeActiveNode()), _ParticleControlDialog, SLOT(updateActiveNode())); + connect(_AnimationSetDialog->ui.setLengthPushButton, SIGNAL(clicked()), _AnimationDialog, SLOT(changeAnimLength())); + connect(_AnimationSetDialog, SIGNAL(changeCurrentShape(QString)), _SkeletonTreeModel, SLOT(rebuildModel())); + connect(_AnimationSetDialog, SIGNAL(changeCurrentShape(QString)), _SkeletonScaleDialog, SLOT(setCurrentShape(QString))); + connect(_AnimationSetDialog, SIGNAL(changeCurrentShape(QString)), _AnimationDialog, SLOT(setCurrentShape(QString))); + connect(_AnimationSetDialog, SIGNAL(changeCurrentShape(QString)), _SlotManagerDialog, SLOT(updateUiSlots())); + connect(_ParticleControlDialog, SIGNAL(changeAutoCount(bool)), _ParticleWorkspaceDialog->getPropertyDialog()->getLocatedPage(), SLOT(setDisabledCountPS(bool))); +} + +bool CMainWindow::loadFile(const QString &fileName, const QString &skelName) +{ + if (!Modules::objView().loadMesh(fileName.toStdString(), skelName.toStdString())) + { + statusBar()->showMessage(tr("Loading canceled"),2000); + return false; + } + statusBar()->showMessage(tr("File loaded"),2000); + return true; +} + +void CMainWindow::cfcbQtStyle(NLMISC::CConfigFile::CVar &var) +{ + QApplication::setStyle(QStyleFactory::create(var.asString().c_str())); +} + +void CMainWindow::cfcbQtPalette(NLMISC::CConfigFile::CVar &var) +{ + if (var.asBool()) QApplication::setPalette(QApplication::style()->standardPalette()); + else QApplication::setPalette(_originalPalette); +} + +void CMainWindow::cfcbSoundEnabled(NLMISC::CConfigFile::CVar &var) +{ + _isSoundEnabled = var.asBool(); // update loop inits +} + +void CMainWindow::updateRender() +{ + updateInitialization(isVisible()); + + if (isVisible()) + { + + // call all update functions + // 01. Update Utilities (configuration etc) + + // 02. Update Time (deltas) + // ... + + // 03. Update Receive (network, servertime, receive messages) + // ... + + // 04. Update Input (keyboard controls, etc) + if (_isGraphicsInitialized) + Modules::objView().updateInput(); + + // 05. Update Weather (sky, snow, wind, fog, sun) + // ... + + // 06. Update Entities (movement, do after possible tp from incoming messages etc) + // - Move other entities + // - Update self entity + // - Move bullets + // ... + + // 07. Update Landscape (async zone loading near entity) + + + // 08. Update Collisions (entities) + // - Update entities + // - Update move container (swap with Update entities? todo: check code!) + // - Update bullets + Modules::veget().update(); + + // 09. Update Animations (playlists) + // - Needs to be either before or after entities, not sure, + // there was a problem with wrong order a while ago!!! + Modules::objView().updateAnimatePS(); + + Modules::objView().updateAnimation(_AnimationDialog->getTime()); + + // 09.2 Update Particle system editor + Modules::psEdit().update(); + + // 10. Update Camera (depends on entities) + // ... + + // 11. Update Interface (login, ui, etc) + // ... + + // 12. Update Sound (sound driver) + if (_isSoundInitialized) + { + Modules::sound().setListenerMatrix(Modules::objView().get3dMouseListener()->getViewMatrix()); + Modules::sound().update(); + } + // 13. Update Send (network, send new position etc) + // ... + + // 14. Update Debug (stuff for dev) + // ... + + if (_isGraphicsInitialized && !Modules::objView().getDriver()->isLost()) + { + // 01. Render Driver (background color) + Modules::objView().renderDriver(); // clear all buffers + + // 02. Render Sky (sky scene) + // ... + + // 04. Render Scene (entity scene) + Modules::objView().renderScene(); + + // 05. Render Effects (flare) + // ... + + // 06. Render Interface 3D (player names) + // ... + + // 07. Render Debug 3D + // ... + + // 08. Render Interface 2D (chatboxes etc, optionally does have 3d) + // ... + + // 09. Render Debug 2D (stuff for dev) + Modules::objView().renderDebug2D(); + + // swap 3d buffers + Modules::objView().getDriver()->swapBuffers(); + } + } +} + + +} /* namespace NLQT */ + +/* end of file */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/main_window.h b/code/nel/tools/3d/object_viewer_qt/src/main_window.h new file mode 100644 index 000000000..31b279efe --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/main_window.h @@ -0,0 +1,136 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef MAIN_WINDOW_H +#define MAIN_WINDOW_H + +// STL includes + +// Qt includes +#include + +// NeL includes +#include + +// Project includes + +namespace NLMISC { + class CConfigFile; +} + +namespace NLQT { + +class CGraphicsViewport; +class CAnimationDialog; +class CAnimationSetDialog; +class CSlotManagerDialog; +class CParticleControlDialog; +class CParticleWorkspaceDialog; +class CSetupFog; +class CSkeletonScaleDialog; +class CSkeletonTreeModel; +class CWaterPoolDialog; +class CVegetableDialog; +class CGlobalWindDialog; +class CDayNightDialog; +class CSunColorDialog; + +class CMainWindow : public QMainWindow +{ + Q_OBJECT + +public: + CMainWindow(QWidget *parent = 0); + ~CMainWindow(); + + virtual void setVisible(bool visible); + + int getFrameRate(); + CSkeletonTreeModel *getSkeletonModel() const + { return _SkeletonTreeModel; } + +private Q_SLOTS: + void open(); + void resetScene(); + void settings(); + void about(); + void updateStatusBar(); + void updateRender(); + +private: + void createActions(); + void createMenus(); + void createToolBars(); + void createStatusBar(); + void createDialogs(); + + void updateInitialization(bool visible); + bool loadFile(const QString &fileName, const QString &skelName); + + void cfcbQtStyle(NLMISC::CConfigFile::CVar &var); + void cfcbQtPalette(NLMISC::CConfigFile::CVar &var); + void cfcbSoundEnabled(NLMISC::CConfigFile::CVar &var); + + bool _isGraphicsInitialized, _isGraphicsEnabled; + bool _isSoundInitialized, _isSoundEnabled; + bool _isLandscapeInitialized, _isLandscapeEnabled; + + CGraphicsViewport *_GraphicsViewport; + CAnimationDialog *_AnimationDialog; + CAnimationSetDialog *_AnimationSetDialog; + CSlotManagerDialog *_SlotManagerDialog; + CParticleControlDialog *_ParticleControlDialog; + CParticleWorkspaceDialog *_ParticleWorkspaceDialog; + CVegetableDialog *_VegetableDialog; + CWaterPoolDialog *_WaterPoolDialog; + CGlobalWindDialog *_GlobalWindDialog; + CSetupFog *_SetupFog; + CSkeletonScaleDialog *_SkeletonScaleDialog; + CDayNightDialog *_DayNightDialog; + CSunColorDialog *_SunColorDialog; + + CSkeletonTreeModel *_SkeletonTreeModel; + + QPalette _originalPalette; + QString _lastDir; + + QTimer *_mainTimer; + QTimer *_statusBarTimer; + + QMenu *_fileMenu; + QMenu *_viewMenu; + QMenu *_sceneMenu; + QMenu *_toolsMenu; + QMenu *_helpMenu; + QToolBar *_fileToolBar; + QToolBar *_editToolBar; + QToolBar *_toolsBar; + QAction *_openAction; + QAction *_exitAction; + QAction *_setBackColorAction; + QAction *_resetSceneAction; + QAction *_saveScreenshotAction; + QAction *_settingsAction; + QAction *_aboutAction; + QAction *_aboutQtAction; +};/* class CMainWindow */ + +} /* namespace NLQT */ + +#endif // MAIN_WINDOW_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/mesh_form.ui b/code/nel/tools/3d/object_viewer_qt/src/mesh_form.ui new file mode 100644 index 000000000..ef44c2c3a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/mesh_form.ui @@ -0,0 +1,104 @@ + + + CMeshWidget + + + + 0 + 0 + 195 + 118 + + + + GroupBox + + + + + + + + + Shape: + + + + + + + true + + + + + + + Browse + + + + + + + Shape not loaded + + + false + + + false + + + 1 + + + + + + + + + + + + + Morph + + + + + + + false + + + Edit + + + + + + + + + + + + morphCheckBox + toggled(bool) + editPushButton + setEnabled(bool) + + + 60 + 85 + + + 135 + 86 + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/mesh_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/mesh_widget.cpp new file mode 100644 index 000000000..1c84c5e6f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/mesh_widget.cpp @@ -0,0 +1,206 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" + +// Qt include +#include +#include +#include + +// NeL include +#include +#include +#include +#include + +// Project includes +#include "mesh_widget.h" +#include "morph_mesh_dialog.h" + +namespace NLQT { + +CMeshWidget::CMeshWidget(QWidget *parent) + : QGroupBox(parent) +{ + _ui.setupUi(this); + + connect(_ui.browsePushButton, SIGNAL(clicked(bool)), this, SLOT(browseShape())); + connect(_ui.editPushButton, SIGNAL(clicked(bool)), this, SLOT(editMorph())); + connect(_ui.morphCheckBox, SIGNAL(toggled(bool)), this, SLOT(setMorphMesh(bool))); +} + +CMeshWidget::~CMeshWidget() +{ +} + +void CMeshWidget::setCurrentShape(CWorkspaceNode *ownerNode, NL3D::CPSShapeParticle *sp) +{ + _Node = ownerNode; + _ShapeParticle = sp; + + if (!dynamic_cast(_ShapeParticle)) + { + _ui.groupBox->hide(); + _ui.browsePushButton->setEnabled(true); + _ui.meshLineEdit->setEnabled(true); + _ui.label->setEnabled(true); + _ui.meshLineEdit->setText(_ShapeParticle->getShape().c_str()); + } + else + { + _ui.groupBox->show(); + NL3D::CPSConstraintMesh *cm = NLMISC::safe_cast(_ShapeParticle); + if (cm->getNumShapes() > 1) + _ui.morphCheckBox->setChecked(true); + else + _ui.morphCheckBox->setChecked(false); + + updateForMorph(); + } +} + +void CMeshWidget::browseShape() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open NeL data file"), ".", + tr("NeL shape file (*.shape)")); + + setCursor(Qt::WaitCursor); + if (!fileName.isEmpty()) + { + NLMISC::CPath::addSearchPath(NLMISC::CFile::getPath(fileName.toStdString())); + try + { + std::string shapeName = NLMISC::CFile::getFilename(fileName.toStdString()); + _ShapeParticle->setShape(shapeName); + _ui.meshLineEdit->setText(shapeName.c_str()); + touchPSState(); + } + catch (NLMISC::Exception &e) + { + QMessageBox::critical(this, tr("Shape loading error"), e.what(), QMessageBox::Ok); + } + updateMeshErrorString(); + } + setCursor(Qt::ArrowCursor); +} + +void CMeshWidget::setMorphMesh(bool state) +{ + NL3D::CPSConstraintMesh *cm = NLMISC::safe_cast(_ShapeParticle); + if (!cm) return; + if (state != (cm->getNumShapes() > 1)) + { + if (state) + { + // morphing enabled + std::string currName[2] = { cm->getShape(), cm->getShape() }; + cm->setShapes(currName, 2); + } + else + { + // morphing disabled + std::string currName = cm->getShape(0); + cm->setShape(currName); + } + updateModifiedFlag(); + } + updateForMorph(); +} + +void CMeshWidget::editMorph() +{ + NL3D::CPSConstraintMesh *cm = NLMISC::safe_cast(_ShapeParticle); + CMorphMeshDialog *dialog = new CMorphMeshDialog(_Node, cm, this); + dialog->show(); + dialog->exec(); + delete dialog; + updateMeshErrorString(); +} + +void CMeshWidget::updateForMorph() +{ + NL3D::CPSConstraintMesh *cm = NLMISC::safe_cast(_ShapeParticle); + if (cm) + { + bool enable = cm->getNumShapes() > 1; + _ui.browsePushButton->setEnabled(!enable); + _ui.meshLineEdit->setEnabled(!enable); + _ui.label->setEnabled(!enable); + if (!enable) + _ui.meshLineEdit->setText(cm->getShape().c_str()); + else + _ui.meshLineEdit->setText(""); + } + updateMeshErrorString(); +} + +void CMeshWidget::updateMeshErrorString() +{ + _ui.infoLabel->setText(""); + NL3D::CPSConstraintMesh *cm = dynamic_cast(_ShapeParticle); + if (!cm) return; + // Update mesh error label + std::vector numVerts; + cm->getShapeNumVerts(numVerts); + if (numVerts.empty()) return; + if (numVerts.size() == 1) + _ui.infoLabel->setText(getShapeErrorString(numVerts[0])); + + else + { + // display error msg for morphed meshs + bool hasError = false; + for(uint k = 0; k < numVerts.size(); ++k) + { + if (numVerts[k] < 0) + { + hasError = true; + break; + } + } + if (hasError) + _ui.infoLabel->setText(tr("Error in morph meshes")); + } +} + +QString CMeshWidget::getShapeErrorString(sint errorCode) +{ + switch(errorCode) + { + case NL3D::CPSConstraintMesh::ShapeFileIsNotAMesh: return tr("Not a mesh"); + case NL3D::CPSConstraintMesh::ShapeFileNotLoaded: return tr("Shape not loaded"); + case NL3D::CPSConstraintMesh::ShapeHasTooMuchVertices: return tr("Too much vertices"); + default: + break; + }; + return QString(); +} + +void CMeshWidget::touchPSState() +{ + if (_Node && _Node->getPSModel()) + { + _Node->getPSModel()->touchTransparencyState(); + _Node->getPSModel()->touchLightableState(); + } +} + +} /* namespace NLQT */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/mesh_widget.h b/code/nel/tools/3d/object_viewer_qt/src/mesh_widget.h new file mode 100644 index 000000000..f0cf1b921 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/mesh_widget.h @@ -0,0 +1,76 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef MESH_WIDGET_H +#define MESH_WIDGET_H + +#include "ui_mesh_form.h" + +// STL includes + +// Qt includes + +// NeL includes + +// Project includes +#include "particle_node.h" + +namespace NL3D +{ + struct CPSShapeParticle; +} + +namespace NLQT { + +class CMeshWidget: public QGroupBox +{ + Q_OBJECT + +public: + CMeshWidget(QWidget *parent = 0); + ~CMeshWidget(); + + void setCurrentShape(CWorkspaceNode *ownerNode, NL3D::CPSShapeParticle *sp); + + QString getShapeErrorString(sint errorCode); + +private Q_SLOTS: + void browseShape(); + void setMorphMesh(bool state); + void editMorph(); + +private: + CWorkspaceNode *_Node; + + NL3D::CPSShapeParticle *_ShapeParticle; + + void updateForMorph(); + + void updateMeshErrorString(); + + void updateModifiedFlag() { if (_Node) _Node->setModified(true); } + + void touchPSState(); + + Ui::CMeshWidget _ui; +}; /* class CMeshWidget */ + +} /* namespace NLQT */ + +#endif // MESH_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/modules.cpp b/code/nel/tools/3d/object_viewer_qt/src/modules.cpp new file mode 100644 index 000000000..b473d4ba9 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/modules.cpp @@ -0,0 +1,52 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "modules.h" + +NLQT::CConfiguration *Modules::_configuration = NULL; +NLQT::CObjectViewer *Modules::_objectViewer = NULL; +NLQT::CMainWindow *Modules::_mainWindow = NULL; +NLQT::CParticleEditor *Modules::_particleEditor = NULL; +NLQT::CSoundSystem *Modules::_soundSystem = NULL; +NLQT::CVegetableEditor *Modules::_vegetableEditor = NULL; + +void Modules::init() +{ + if (_configuration == NULL) _configuration = new NLQT::CConfiguration; + config().init(); + + if (_objectViewer == NULL) _objectViewer = new NLQT::CObjectViewer; + if (_soundSystem == NULL) _soundSystem = new NLQT::CSoundSystem; + if (_particleEditor == NULL) _particleEditor = new NLQT::CParticleEditor; + if (_vegetableEditor == NULL) _vegetableEditor = new NLQT::CVegetableEditor; + if (_mainWindow == NULL) _mainWindow = new NLQT::CMainWindow; +} + +void Modules::release() +{ + delete _mainWindow; _mainWindow = NULL; + delete _particleEditor; _particleEditor = NULL; + delete _vegetableEditor; _vegetableEditor = NULL; + delete _soundSystem; _soundSystem = NULL; + delete _objectViewer; _objectViewer = NULL; + + config().release(); + delete _configuration; _configuration = NULL; +} diff --git a/code/nel/tools/3d/object_viewer_qt/src/modules.h b/code/nel/tools/3d/object_viewer_qt/src/modules.h new file mode 100644 index 000000000..2ddd8a7dc --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/modules.h @@ -0,0 +1,55 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef MODULES_H +#define MODULES_H + +#include "configuration.h" +#include "object_viewer.h" +#include "particle_editor.h" +#include "main_window.h" +#include "sound_system.h" +#include "vegetable_editor.h" + +/** +@class Modules +@brief Main modules aggregated all parts of the program. +*/ +class Modules +{ +public: + static void init(); + static void release(); + + static NLQT::CConfiguration &config() { return *_configuration; } + static NLQT::CObjectViewer &objView() { return *_objectViewer; } + static NLQT::CMainWindow &mainWin() { return *_mainWindow; } + static NLQT::CParticleEditor &psEdit() { return *_particleEditor; } + static NLQT::CSoundSystem &sound() { return *_soundSystem; } + static NLQT::CVegetableEditor &veget() { return *_vegetableEditor; } +private: + static NLQT::CConfiguration *_configuration; + static NLQT::CObjectViewer *_objectViewer; + static NLQT::CMainWindow *_mainWindow; + static NLQT::CParticleEditor *_particleEditor; + static NLQT::CSoundSystem *_soundSystem; + static NLQT::CVegetableEditor *_vegetableEditor; +}; + +#endif // MODULES_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/morph_mesh_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/morph_mesh_dialog.cpp new file mode 100644 index 000000000..f4cb868a4 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/morph_mesh_dialog.cpp @@ -0,0 +1,241 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "morph_mesh_dialog.h" + +// Qt include +#include + +// NeL includes +#include "nel/3d/ps_mesh.h" +#include "nel/3d/particle_system_model.h" + +// Projects includes +#include "mesh_widget.h" + +namespace NLQT { + +CMorphMeshDialog::CMorphMeshDialog(CWorkspaceNode *ownerNode, NL3D::CPSConstraintMesh *cm, QWidget *parent) + : QDialog(parent), _Node(ownerNode), _CM(cm) +{ + _ui.setupUi(this); + + _ui.morphValueWidget->setRange(0, 10); + _ui.morphValueWidget->setWrapper(&_MorphSchemeWrapper); + _ui.morphValueWidget->setSchemeWrapper(&_MorphSchemeWrapper); + _ui.morphValueWidget->init(); + + _MorphSchemeWrapper.CM = _CM; + _ui.morphValueWidget->setWorkspaceNode(_Node); + _ui.morphValueWidget->updateUi(); + + updateMeshList(); + + _ui.infoLabel->setVisible(!_CM->isValidBuild()); + + connect(_ui.addPushButton, SIGNAL(clicked()), this, SLOT(add())); + connect(_ui.removePushButton, SIGNAL(clicked()), this, SLOT(remove())); + connect(_ui.insertPushButton, SIGNAL(clicked()), this, SLOT(insert())); + connect(_ui.changePushButton, SIGNAL(clicked()), this, SLOT(change())); + connect(_ui.upPushButton, SIGNAL(clicked()), this, SLOT(up())); + connect(_ui.downPushButton, SIGNAL(clicked()), this, SLOT(down())); +} + +CMorphMeshDialog::~CMorphMeshDialog() +{ +} + +void CMorphMeshDialog::updateMeshList() +{ + nlassert(_CM); + std::vector numVerts; + _CM->getShapeNumVerts(numVerts); + _ui.listWidget->clear(); + for (uint k = 0; k < _CM->getNumShapes(); ++k) + _ui.listWidget->addItem(getShapeDescStr(k, numVerts[k])); + + _ui.listWidget->setCurrentRow(0); + if (_CM->getNumShapes() < 2) + _ui.removePushButton->setEnabled(false); + else + _ui.removePushButton->setEnabled(true); +} + +QString CMorphMeshDialog::getShapeDescStr(uint shapeIndex, sint numVerts) const +{ + if (numVerts >= 0) + { + QString verts(tr("vertices")); + QString msg = _CM->getShape(shapeIndex).c_str() + tr(" (%1 vertices)").arg(numVerts); + return msg; + } + else + { + QString error = qobject_cast(QObject::parent())->getShapeErrorString(numVerts); + QString result = _CM->getShape(shapeIndex).c_str() + QString(" (%1)").arg(error); + return result; + } +} + +void CMorphMeshDialog::add() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open NeL data file"), ".", + tr("NeL shape files (*.shape)")); + + setCursor(Qt::WaitCursor); + if (!fileName.isEmpty()) + { + std::vector shapeNames; + shapeNames.resize(_CM->getNumShapes() + 1); + _CM->getShapesNames(&shapeNames[0]); + uint index = (uint)shapeNames.size() - 1; + shapeNames[index] = fileName.toStdString(); + _CM->setShapes(&shapeNames[0], (uint)shapeNames.size()); + std::vector numVerts; + _CM->getShapeNumVerts(numVerts); + _ui.listWidget->addItem(getShapeDescStr(index, numVerts[index])); + _ui.removePushButton->setEnabled(true); + touchPSState(); + } + setCursor(Qt::ArrowCursor); + _ui.infoLabel->setVisible(!_CM->isValidBuild()); +} + +void CMorphMeshDialog::remove() +{ + sint row = _ui.listWidget->currentRow(); + std::vector shapeNames; + shapeNames.resize(_CM->getNumShapes()); + _CM->getShapesNames(&shapeNames[0]); + shapeNames.erase(shapeNames.begin() + row); + _CM->setShapes(&shapeNames[0], (uint)shapeNames.size()); + + if (_CM->getNumShapes() < 2) + _ui.removePushButton->setEnabled(false); + + touchPSState(); + updateMeshList(); + _ui.infoLabel->setVisible(!_CM->isValidBuild()); +} + +void CMorphMeshDialog::insert() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open NeL data file"), ".", + tr("NeL shape files (*.shape)")); + + setCursor(Qt::WaitCursor); + if (!fileName.isEmpty()) + { + sint row = _ui.listWidget->currentRow(); + std::vector shapeNames; + shapeNames.resize(_CM->getNumShapes()); + _CM->getShapesNames(&shapeNames[0]); + shapeNames.insert(shapeNames.begin() + row, fileName.toStdString()); + _CM->setShapes(&shapeNames[0], (uint)shapeNames.size()); + touchPSState(); + updateMeshList(); + _ui.listWidget->setCurrentRow(row); + } + setCursor(Qt::ArrowCursor); + _ui.infoLabel->setVisible(!_CM->isValidBuild()); +} + +void CMorphMeshDialog::change() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open NeL data file"), ".", + tr("NeL shape files (*.shape)")); + + setCursor(Qt::WaitCursor); + if (!fileName.isEmpty()) + { + sint row = _ui.listWidget->currentRow(); + _CM->setShape(row, fileName.toStdString()); + updateMeshList(); + touchPSState(); + } + setCursor(Qt::ArrowCursor); + _ui.infoLabel->setVisible(!_CM->isValidBuild()); +} + +void CMorphMeshDialog::up() +{ + sint row = _ui.listWidget->currentRow(); + if (row == 0) return; + std::vector shapeNames; + shapeNames.resize(_CM->getNumShapes()); + _CM->getShapesNames(&shapeNames[0]); + std::swap(shapeNames[row - 1], shapeNames[row]); + _CM->setShapes(&shapeNames[0], (uint)shapeNames.size()); + updateMeshList(); + _ui.listWidget->setCurrentRow(row - 1); + _ui.infoLabel->setVisible(!_CM->isValidBuild()); +} + +void CMorphMeshDialog::down() +{ + sint row = _ui.listWidget->currentRow(); + if (row == (sint) (_CM->getNumShapes() - 1)) return; + std::vector shapeNames; + shapeNames.resize(_CM->getNumShapes()); + _CM->getShapesNames(&shapeNames[0]); + std::swap(shapeNames[row + 1], shapeNames[row]); + _CM->setShapes(&shapeNames[0], (uint)shapeNames.size()); + updateMeshList(); + _ui.listWidget->setCurrentRow(row + 1); + _ui.infoLabel->setVisible(!_CM->isValidBuild()); +} + +void CMorphMeshDialog::touchPSState() +{ + if (_Node && _Node->getPSModel()) + { + _Node->getPSModel()->touchTransparencyState(); + _Node->getPSModel()->touchLightableState(); + } +} + +float CMorphMeshDialog::CMorphSchemeWrapper::get(void) const +{ + nlassert(CM); + return CM->getMorphValue(); +} + +void CMorphMeshDialog::CMorphSchemeWrapper::set(const float &v) +{ + nlassert(CM); + CM->setMorphValue(v); +} + +CMorphMeshDialog::CMorphSchemeWrapper::scheme_type *CMorphMeshDialog::CMorphSchemeWrapper::getScheme(void) const +{ + nlassert(CM); + return CM->getMorphScheme(); +} + +void CMorphMeshDialog::CMorphSchemeWrapper::setScheme(scheme_type *s) +{ + nlassert(CM); + CM->setMorphScheme(s); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/morph_mesh_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/morph_mesh_dialog.h new file mode 100644 index 000000000..8b700932d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/morph_mesh_dialog.h @@ -0,0 +1,85 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef MORPH_MESH_DIALOG_H +#define MORPH_MESH_DIALOG_H + +#include "ui_morph_mesh_form.h" + +// STL includes + +// Qt includes + +// NeL includes + +// Project includes +#include "ps_wrapper.h" + +namespace NL3D +{ + class CPSConstraintMesh; +} + +namespace NLQT { + +class CMorphMeshDialog: public QDialog +{ + Q_OBJECT + +public: + CMorphMeshDialog(CWorkspaceNode *ownerNode, NL3D::CPSConstraintMesh *cm, QWidget *parent = 0); + ~CMorphMeshDialog(); + +private Q_SLOTS: + void add(); + void remove(); + void insert(); + void change(); + void up(); + void down(); + +private: + /// fill the mesh list with the mesh names in the object being edited + void updateMeshList(); + + QString getShapeDescStr(uint shapeIndex, sint numVerts) const; + + /// wrapper for the morph scheme + struct CMorphSchemeWrapper : IPSSchemeWrapperFloat, IPSWrapperFloat + { + NL3D::CPSConstraintMesh *CM; + virtual float get(void) const; + virtual void set(const float &); + virtual scheme_type *getScheme(void) const; + virtual void setScheme(scheme_type *s); + } _MorphSchemeWrapper; + + void touchPSState(); + + CWorkspaceNode *_Node; + + // the constraint mesh being edited + NL3D::CPSConstraintMesh *_CM; + + Ui::CMorphMeshDialog _ui; +}; /* class CMorphMeshDialog */ + +} /* namespace NLQT */ + +#endif // MORPH_MESH_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/morph_mesh_form.ui b/code/nel/tools/3d/object_viewer_qt/src/morph_mesh_form.ui new file mode 100644 index 000000000..aa6992d93 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/morph_mesh_form.ui @@ -0,0 +1,256 @@ + + + CMorphMeshDialog + + + + 0 + 0 + 413 + 516 + + + + Morph mesh edit + + + true + + + + + + + 0 + 0 + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Add + + + + :/images/list-add.png:/images/list-add.png + + + + + + + Change + + + + :/images/refresh.png:/images/refresh.png + + + + + + + Insert + + + + + + + Remove + + + + :/images/list-remove.png:/images/list-remove.png + + + + + + + Up + + + + :/images/go-up.png:/images/go-up.png + + + + + + + Down + + + + :/images/go-down.png:/images/go-down.png + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 40 + + + + + + + + + + + + + + + + + + + 192 + 0 + 0 + + + + + + + + + 192 + 0 + 0 + + + + + + + + + 146 + 145 + 144 + + + + + + + + Warning: Shapes not found and incompatibles !! + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + NLQT::CAttribFloatWidget + QGroupBox +

attrib_widget.h
+ 1 + + + + + + + + buttonBox + rejected() + CMorphMeshDialog + reject() + + + 440 + 420 + + + 286 + 274 + + + + + buttonBox + accepted() + CMorphMeshDialog + accept() + + + 440 + 414 + + + 157 + 274 + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/multi_tex_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/multi_tex_dialog.cpp new file mode 100644 index 000000000..28168a0df --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/multi_tex_dialog.cpp @@ -0,0 +1,197 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "multi_tex_dialog.h" + +// NeL includes +#include "nel/3d/ps_particle_basic.h" +#include "nel/3d/texture_bump.h" + +// Project includes +#include "particle_node.h" + +namespace NLQT { + +CMultiTexDialog::CMultiTexDialog(CWorkspaceNode *ownerNode, NL3D::CPSMultiTexturedParticle *mtp, QWidget *parent) + : QDialog(parent), _Node(ownerNode), _MTP(mtp) +{ + _ui.setupUi(this); + + nlassert(_MTP); + + _ui.basicCapsCheckBox->setChecked(NL3D::CPSMultiTexturedParticle::areBasicCapsForced()); + _ui.useParticleDataCheckBox->setChecked(_MTP->getUseLocalDateAlt()); + _ui.useParticleDataCheckBox_2->setChecked(_MTP->getUseLocalDate()); + + bool bEnvBumpMapUsed = _MTP->getMainTexOp() == NL3D::CPSMultiTexturedParticle::EnvBumpMap ? true : false; + _ui.bumpFactorLabel->setEnabled(bEnvBumpMapUsed); + _ui.bumpFactorDoubleSpinBox->setEnabled(bEnvBumpMapUsed); + + _TexWrapper.OwnerNode = _Node; + _AlternateTexWrapper.OwnerNode = _Node; + _TexWrapper.MTP = _MTP; + _AlternateTexWrapper.MTP = _MTP; + + _ui.texWidget->setWrapper(&_TexWrapper); + _ui.texWidget->updateUi(); + + _ui.texWidget_2->setWrapper(&_AlternateTexWrapper); + _ui.texWidget_2->updateUi(); + + readValues(); + + _ui.enableAlternateCheckBox->setChecked(_MTP->isAlternateTexEnabled()); + _ui.alternateTab->setEnabled(_MTP->isAlternateTexEnabled()); + + _ui.texOpComboBox->setCurrentIndex(int(_MTP->getMainTexOp())); + _ui.texOpComboBox_2->setCurrentIndex(int(_MTP->getAlternateTexOp())); + + connect(_ui.bumpFactorDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateValues())); + connect(_ui.enableAlternateCheckBox, SIGNAL(toggled(bool)), this, SLOT(setEnabledAlternate(bool))); + connect(_ui.basicCapsCheckBox, SIGNAL(toggled(bool)), this, SLOT(setForceBasicCaps(bool))); + connect(_ui.texOpComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setMainOp(int))); + connect(_ui.texOpComboBox_2, SIGNAL(currentIndexChanged(int)), this, SLOT(setAlternateOp(int))); + connect(_ui.useParticleDataCheckBox, SIGNAL(toggled(bool)), this, SLOT(setUseParticleDate(bool))); + connect(_ui.useParticleDataCheckBox_2, SIGNAL(toggled(bool)), this, SLOT(setUseParticleDateAlt(bool))); + connect(_ui.uSpeed1DoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateValues())); + connect(_ui.vSpeed1DoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateValues())); + connect(_ui.uSpeed2DoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateValues())); + connect(_ui.vSpeed2DoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateValues())); + connect(_ui.uSpeed1DoubleSpinBox_2, SIGNAL(valueChanged(double)), this, SLOT(updateValuesAlternate())); + connect(_ui.vSpeed1DoubleSpinBox_2, SIGNAL(valueChanged(double)), this, SLOT(updateValuesAlternate())); + connect(_ui.uSpeed2DoubleSpinBox_2, SIGNAL(valueChanged(double)), this, SLOT(updateValuesAlternate())); + connect(_ui.vSpeed2DoubleSpinBox_2, SIGNAL(valueChanged(double)), this, SLOT(updateValuesAlternate())); +} + +CMultiTexDialog::~CMultiTexDialog() +{ +} + +void CMultiTexDialog::setEnabledAlternate(bool state) +{ + if (state != _MTP->isAlternateTexEnabled()) + { + _MTP->enableAlternateTex(state); + updateModifiedFlag(); + } + _ui.alternateTab->setEnabled(state); +} + +void CMultiTexDialog::updateValues() +{ + NLMISC::CVector2f vs1, vs2; + + vs1.x = _ui.uSpeed1DoubleSpinBox->value(); + vs1.y = _ui.vSpeed1DoubleSpinBox->value(); + + vs2.x = _ui.uSpeed2DoubleSpinBox->value(); + vs2.y = _ui.vSpeed2DoubleSpinBox->value(); + + _MTP->setScrollSpeed(0, vs1); + _MTP->setScrollSpeed(1, vs2); + + _MTP->setBumpFactor(_ui.bumpFactorDoubleSpinBox->value()); + + updateModifiedFlag(); +} + +void CMultiTexDialog::updateValuesAlternate() +{ + NLMISC::CVector2f vs1, vs2; + + vs1.x = _ui.uSpeed1DoubleSpinBox_2->value(); + vs1.y = _ui.vSpeed1DoubleSpinBox_2->value(); + + vs2.x = _ui.uSpeed2DoubleSpinBox_2->value(); + vs2.y = _ui.vSpeed2DoubleSpinBox_2->value(); + + _MTP->setAlternateScrollSpeed(0, vs1); + _MTP->setAlternateScrollSpeed(1, vs2); + + updateModifiedFlag(); +} + +void CMultiTexDialog::setAlternateOp(int index) +{ + _MTP->setAlternateTexOp((NL3D::CPSMultiTexturedParticle::TOperator) index); + updateModifiedFlag(); +} + +void CMultiTexDialog::setMainOp(int index) +{ + _MTP->setMainTexOp((NL3D::CPSMultiTexturedParticle::TOperator) index); + updateModifiedFlag(); + + bool bEnvBumpMapUsed = _MTP->getMainTexOp() == NL3D::CPSMultiTexturedParticle::EnvBumpMap ? true : false; + _ui.bumpFactorLabel->setEnabled(bEnvBumpMapUsed); + _ui.bumpFactorDoubleSpinBox->setEnabled(bEnvBumpMapUsed); +} + +void CMultiTexDialog::setForceBasicCaps(bool state) +{ + NL3D::CPSMultiTexturedParticle::forceBasicCaps(state); +} + +void CMultiTexDialog::setUseParticleDate(bool state) +{ + _MTP->setUseLocalDate(state); + updateModifiedFlag(); +} + +void CMultiTexDialog::setUseParticleDateAlt(bool state) +{ + _MTP->setUseLocalDateAlt(state); + updateModifiedFlag(); +} + +void CMultiTexDialog::readValues() +{ + _ui.uSpeed1DoubleSpinBox->setValue(_MTP->getScrollSpeed(0).x); + _ui.vSpeed1DoubleSpinBox->setValue(_MTP->getScrollSpeed(0).y); + _ui.uSpeed2DoubleSpinBox->setValue(_MTP->getScrollSpeed(1).x); + _ui.vSpeed2DoubleSpinBox->setValue(_MTP->getScrollSpeed(1).y); + _ui.uSpeed1DoubleSpinBox_2->setValue(_MTP->getAlternateScrollSpeed(0).x); + _ui.vSpeed1DoubleSpinBox_2->setValue(_MTP->getAlternateScrollSpeed(0).y); + _ui.uSpeed2DoubleSpinBox_2->setValue(_MTP->getAlternateScrollSpeed(1).x); + _ui.vSpeed2DoubleSpinBox_2->setValue(_MTP->getAlternateScrollSpeed(1).y); + _ui.bumpFactorDoubleSpinBox->setValue(_MTP->getBumpFactor()); +} + +NL3D::ITexture *CMultiTexDialog::CMainTexWrapper::get(void) +{ + return MTP->getTexture2(); +} + +void CMultiTexDialog::CMainTexWrapper::set(NL3D::ITexture *tex) +{ + MTP->setTexture2(tex); +} + +NL3D::ITexture *CMultiTexDialog::CAlternateTexWrapper::get(void) +{ + return MTP->getTexture2Alternate(); +} + +void CMultiTexDialog::CAlternateTexWrapper::set(NL3D::ITexture *tex) +{ + MTP->setTexture2Alternate(tex); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/multi_tex_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/multi_tex_dialog.h new file mode 100644 index 000000000..1d4997e2b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/multi_tex_dialog.h @@ -0,0 +1,89 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef MULTI_TEX_DIALOG_H +#define MULTI_TEX_DIALOG_H + +#include "ui_multi_tex_form.h" + + +// STL includes + +// Qt includes + +// NeL includes + +// Project includes +#include "ps_wrapper.h" + +namespace NL3D +{ + class CPSMultiTexturedParticle; +} + +namespace NLQT { + +class CWorkspaceNode; + +class CMultiTexDialog: public QDialog +{ + Q_OBJECT + +public: + CMultiTexDialog(CWorkspaceNode *ownerNode, NL3D::CPSMultiTexturedParticle *mtp, QWidget *parent = 0); + ~CMultiTexDialog(); + +private Q_SLOTS: + void setEnabledAlternate(bool state); + void updateValues(); + void updateValuesAlternate(); + void setAlternateOp(int index); + void setMainOp(int index); + void setForceBasicCaps(bool state); + void setUseParticleDate(bool state); + void setUseParticleDateAlt(bool state); + +private: + struct CMainTexWrapper : IPSWrapperTexture + { + NL3D::CPSMultiTexturedParticle *MTP; + virtual NL3D::ITexture *get(void); + virtual void set(NL3D::ITexture *); + } _TexWrapper; + + struct CAlternateTexWrapper : IPSWrapperTexture + { + NL3D::CPSMultiTexturedParticle *MTP; + virtual NL3D::ITexture *get(void); + virtual void set(NL3D::ITexture *); + } _AlternateTexWrapper; + + CWorkspaceNode *_Node; + + NL3D::CPSMultiTexturedParticle *_MTP; + + void readValues(); + void updateModifiedFlag() { if (_Node) _Node->setModified(true); } + + Ui::CMultiTexDialog _ui; +}; /* class CMultiTexDialog */ + +} /* namespace NLQT */ + +#endif // MULTI_TEX_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/multi_tex_form.ui b/code/nel/tools/3d/object_viewer_qt/src/multi_tex_form.ui new file mode 100644 index 000000000..55fb83375 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/multi_tex_form.ui @@ -0,0 +1,290 @@ + + + CMultiTexDialog + + + + 0 + 0 + 360 + 269 + + + + Multitexturing + + + true + + + + + + true + + + 0 + + + + Main tex + + + + + + U speed 1: + + + + + + + + + + + + + V speed 1: + + + + + + + + + + U speed 2: + + + + + + + + + + V speed 2: + + + + + + + + + + false + + + Bump factor: + + + + + + + false + + + + + + + Use particle data + + + + + + + Tex op: + + + + + + + + Add + + + + + Modulate + + + + + Decal + + + + + EnvBumpMap + + + + + + + + + false + + + Alternate tex + + + + + + U speed 1: + + + + + + + + + + + + + V speed 1: + + + + + + + + + + U speed 2: + + + + + + + + + + V speed 2: + + + + + + + + + + Tex op: + + + + + + + + Add + + + + + Modulate + + + + + Decal + + + + + + + + Use particle data all + + + + + + + + + + + Force basic caps + + + + + + + Enable alternate + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + NLQT::CParticleTextureWidget + QWidget +
particle_texture_widget.h
+ 1 +
+
+ + + + buttonBox + accepted() + CMultiTexDialog + accept() + + + 250 + 264 + + + 157 + 268 + + + + + buttonBox + rejected() + CMultiTexDialog + reject() + + + 276 + 264 + + + 286 + 268 + + + + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/object_viewer.cpp b/code/nel/tools/3d/object_viewer_qt/src/object_viewer.cpp new file mode 100644 index 000000000..db410ed43 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/object_viewer.cpp @@ -0,0 +1,452 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "object_viewer.h" + +// STL includes + +// NeL includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Project includes +#include "modules.h" +#include "configuration.h" + +using namespace std; +using namespace NLMISC; +using namespace NL3D; + +namespace NLQT { + +CObjectViewer::CObjectViewer() + : _Driver(NULL), _TextContext(NULL), + _phi(0), _psi(0),_dist(20), + _CameraFocal(75), + _CurrentInstance(""), + _BloomEffect(false) +{ + +} + +CObjectViewer::~CObjectViewer() +{ +} + +void CObjectViewer::init(nlWindow wnd, uint16 w, uint16 h) +{ + //H_AUTO2 + nldebug("CObjectViewert::init"); + + loadConfig(); + + // create the driver + nlassert(!_Driver); + + _Driver = UDriver::createDriver(0, _Direct3D, 0); + nlassert(_Driver); + + // initialize the window with config file values + _Driver->setDisplay(wnd, NL3D::UDriver::CMode(w, h, 32)); + + _Light = ULight::createLight(); + + // set mode of the light + _Light->setMode(ULight::DirectionalLight); + + // set position of the light + _Light->setPosition(CVector(-20.f, 30.f, 10.f)); + + // white light + _Light->setAmbiant(CRGBA(255, 255, 255)); + + // set and enable the light + _Driver->setLight(0, *_Light); + _Driver->enableLight(0); + + // Create a scene + _Scene = _Driver->createScene(true); + + _PlayListManager = _Scene->createPlayListManager(); + + _Scene->enableLightingSystem(true); + + // create the camera + UCamera camera = _Scene->getCam(); + camera.setTransformMode (UTransformable::DirectMatrix); + + setSizeViewport(w, h); + + // camera will look at entities + updateCamera(0,0,0); + + NLMISC::CVector hotSpot=NLMISC::CVector(0,0,0); + + _MouseListener = _Driver->create3dMouseListener(); + _MouseListener->setMatrix(Modules::objView().getScene()->getCam().getMatrix()); + _MouseListener->setFrustrum(Modules::objView().getScene()->getCam().getFrustum()); + _MouseListener->setHotSpot(hotSpot); + _MouseListener->setMouseMode(U3dMouseListener::edit3d); + + // set the cache size for the font manager(in bytes) + _Driver->setFontManagerMaxMemory(2097152); + + // create the text context + nlassert(!_TextContext); + _TextContext = _Driver->createTextContext(_FontName); + nlassert(_TextContext); + + NL3D::CBloomEffect::instance().setDriver(_Driver); + NL3D::CBloomEffect::instance().setScene(_Scene); + NL3D::CBloomEffect::instance().init(!_Direct3D); + NL3D::CBloomEffect::instance().setDensityBloom(Modules::config().getConfigFile().getVar("BloomDensity").asInt()); + NL3D::CBloomEffect::instance().setSquareBloom(Modules::config().getConfigFile().getVar("BloomSquare").asBool()); +} + +void CObjectViewer::release() +{ + //H_AUTO2 + nldebug("CObjectViewer::release"); + + saveConfig(); + + // release text context + nlassert(_TextContext); + _Driver->deleteTextContext(_TextContext); + _TextContext = NULL; + + _Driver->delete3dMouseListener(_MouseListener); + + // delete all entities + deleteEntities(); + + _Scene->deletePlayListManager(_PlayListManager); + + // delete the scene + _Driver->deleteScene(_Scene); + + // delete the light + delete _Light; + + // release driver + nlassert(_Driver); + _Driver->release(); + delete _Driver; + _Driver = NULL; +} + +void CObjectViewer::updateInput() +{ + _Driver->EventServer.pump(); + + // New matrix from camera + _Scene->getCam().setTransformMode(NL3D::UTransformable::DirectMatrix); + _Scene->getCam().setMatrix (_MouseListener->getViewMatrix()); +} + +void CObjectViewer::renderDriver() +{ + // Render the scene. + if((NL3D::CBloomEffect::instance().getDriver() != NULL) && (_BloomEffect)) + { + NL3D::CBloomEffect::instance().initBloom(); + } + _Driver->clearBuffers(_BackgroundColor); +} + +void CObjectViewer::renderScene() +{ + // render the scene + _Scene->render(); + + if((NL3D::CBloomEffect::instance().getDriver() != NULL) && (_BloomEffect)) + { + NL3D::CBloomEffect::instance().endBloom(); + NL3D::CBloomEffect::instance().endInterfacesDisplayBloom(); + } +} + +void CObjectViewer::renderDebug2D() +{ +} + +void CObjectViewer::saveScreenshot(const std::string &nameFile, bool jpg, bool png, bool tga) +{ + //H_AUTO2 + + // FIXME: create screenshot path if it doesn't exist! + + // empty bitmap + CBitmap bitmap; + // copy the driver buffer to the bitmap + _Driver->getBuffer(bitmap); + // create the file name + string filename = std::string("./") + nameFile; + // write the bitmap as a jpg, png or tga to the file + if (jpg) + { + string newfilename = CFile::findNewFile(filename + ".jpg"); + COFile outputFile(newfilename); + bitmap.writeJPG(outputFile, 100); + nlinfo("Screenshot '%s' saved", newfilename.c_str()); + } + if (png) + { + string newfilename = CFile::findNewFile(filename + ".png"); + COFile outputFile(newfilename); + bitmap.writePNG(outputFile, 24); + nlinfo("Screenshot '%s' saved", newfilename.c_str()); + } + if (tga) + { + string newfilename = CFile::findNewFile(filename + ".tga"); + COFile outputFile(newfilename); + bitmap.writeTGA(outputFile, 24, false); + nlinfo("Screenshot '%s' saved", newfilename.c_str()); + } +} + +bool CObjectViewer::loadMesh(const std::string &meshFileName, const std::string &skelFileName) +{ + std::string fileName = CFile::getFilenameWithoutExtension(meshFileName); + if ( _Entities.count(fileName) != 0) + return false; + + CPath::addSearchPath(CFile::getPath(meshFileName), false, false); + + // create instance of the mesh character + UInstance Entity = _Scene->createInstance(meshFileName); + + USkeleton Skeleton = _Scene->createSkeleton(skelFileName); + + // if we can't create entity, skip it + if (Entity.empty()) return false; + + // TODO: remade at typedef std::map CEntities; + EIT eit = (_Entities.insert (make_pair (fileName, CEntity()))).first; + CEntity &entity = (*eit).second; + + // set the entity up + entity._Name = fileName; + entity._FileNameShape = meshFileName; + entity._FileNameSkeleton = skelFileName; + entity._Instance = Entity; + if (!Skeleton.empty()) + { + entity._Skeleton = Skeleton; + entity._Skeleton.bindSkin (entity._Instance); + } + entity._AnimationSet = _Driver->createAnimationSet(false); + entity._PlayList = _PlayListManager->createPlayList(entity._AnimationSet); + return true; +} + +void CObjectViewer::resetScene() +{ + deleteEntities(); + + // Reset camera. + //.. + + // to load files with the same name but located in different directories + CPath::clearMap(); + + // load and set search paths from config + Modules::config().configSearchPaths(); + + _CurrentInstance = ""; + + nlinfo("Scene cleared"); +} + +void CObjectViewer::updateCamera(float deltaPsi, float deltaPhi, float deltaDist) +{ + _phi += deltaPhi; + _psi += deltaPsi; + _dist += deltaDist; + + if(_phi < -NLMISC::Pi/2) _phi -= deltaPhi; + if(_phi > NLMISC::Pi/2) _phi -= deltaPsi; + if (_dist < 1) _dist = 1; + + NLMISC::CQuat q0,q1,q2; + NLMISC::CVector up(0,0,1); + NLMISC::CVector v(0,0,1); + + q0.setAngleAxis(v,_psi); + v = NLMISC::CVector(0,1,0); + q1.setAngleAxis(v,_phi); + q2 = q0 * q1; + NLMISC::CMatrix m0; + m0.setRot(q2); + NLMISC::CVector camera = m0 * NLMISC::CVector(_dist,0,0); + + _Scene->getCam().lookAt(camera, up); +} + +void CObjectViewer::updateAnimatePS(uint64 deltaTime) +{ + 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); + _Scene->animate ( fdelta); +} + +void CObjectViewer::updateAnimation(NL3D::TAnimationTime time) +{ + for (EIT eit = _Entities.begin(); eit != _Entities.end(); ++eit) + { + CEntity &entity = (*eit).second; + entity.update(time); + } + + // Animate scene animation + Modules::objView().getPlayListManager()->setup(time); +} + +void CObjectViewer::setBackgroundColor(NLMISC::CRGBA backgroundColor) +{ + _BackgroundColor = backgroundColor; + + // config file variable changes + Modules::config().getConfigFile().getVar("BackgroundColor").setAsInt(_BackgroundColor.R, 0); + Modules::config().getConfigFile().getVar("BackgroundColor").setAsInt(_BackgroundColor.G, 1); + Modules::config().getConfigFile().getVar("BackgroundColor").setAsInt(_BackgroundColor.B, 2); +} + +void CObjectViewer::setGraphicsDriver(bool Direct3D) +{ + _Direct3D = Direct3D; + + if (_Direct3D) Modules::config().getConfigFile().getVar("GraphicsDriver").setAsString("Direct3D"); + else Modules::config().getConfigFile().getVar("GraphicsDriver").setAsString("OpenGL"); +} + +void CObjectViewer::setSizeViewport(uint16 w, uint16 h) +{ + _Scene->getCam().setPerspective(_CameraFocal * (float)Pi/180.f, (float)w/h, 0.1f, 1000); +} + +void CObjectViewer::setCurrentObject(const std::string &name) +{ + if ((_Entities.count(name) != 0) || ( name.empty() )) _CurrentInstance = name; + else nlerror ("Entity %s not found", name.c_str()); + nlinfo("set current entity %s", _CurrentInstance.c_str()); +} + +CEntity& CObjectViewer::getEntity(const std::string &name) +{ + if ( _Entities.count(name) == 0) nlerror("Entity %s not found", name.c_str()); + EIT eit = _Entities.find (name); + return (*eit).second; +} + +void CObjectViewer::getListObjects(std::vector &listObj) +{ + listObj.clear(); + for (EIT eit = _Entities.begin(); eit != _Entities.end(); ++eit) + listObj.push_back((*eit).second._Name); +} + +void CObjectViewer::loadConfig() +{ + // set background color from config + Modules::config().setAndCallback("BackgroundColor", CConfigCallback(this, &CObjectViewer::cfcbBackgroundColor)); + + // set graphics driver from config + Modules::config().setAndCallback("GraphicsDriver",CConfigCallback(this,&CObjectViewer::cfcbGraphicsDriver)); + + Modules::config().setAndCallback("CameraFocal",CConfigCallback(this,&CObjectViewer::cfcbCameraFocal)); + + Modules::config().setAndCallback("FontName",CConfigCallback(this,&CObjectViewer::cfcbFontName)); + + Modules::config().setAndCallback("BloomEffect",CConfigCallback(this,&CObjectViewer::cfcbBloomEffect)); +} + +void CObjectViewer::saveConfig() +{ + Modules::config().dropCallback("BackgroundColor"); + Modules::config().dropCallback("GraphicsDriver"); + Modules::config().dropCallback("CameraFocal"); + Modules::config().dropCallback("FontName"); + Modules::config().dropCallback("BloomEffect"); +} + +void CObjectViewer::deleteEntities() +{ + _Entities.clear(); +} + +void CObjectViewer::cfcbBackgroundColor(NLMISC::CConfigFile::CVar &var) +{ + // read variable from config file + _BackgroundColor = CRGBA(var.asInt(0), var.asInt(1), var.asInt(2)); +} + +void CObjectViewer::cfcbGraphicsDriver(NLMISC::CConfigFile::CVar &var) +{ + // Choose driver opengl to work correctly under Linux example + _Direct3D = false; //_Driver = OpenGL; + +#ifdef NL_OS_WINDOWS + std::string driver = var.asString(); + if (driver == "Direct3D") _Direct3D = true; //m_Driver = Direct3D; + else if (driver == "OpenGL") _Direct3D = false; //m_Driver = OpenGL; + else nlwarning("Invalid driver specified, defaulting to OpenGL"); +#endif +} + +void CObjectViewer::cfcbCameraFocal(NLMISC::CConfigFile::CVar &var) +{ + _CameraFocal = var.asFloat(); +} + +void CObjectViewer::cfcbFontName(NLMISC::CConfigFile::CVar &var) +{ + _FontName = var.asString(); +} + +void CObjectViewer::cfcbBloomEffect(NLMISC::CConfigFile::CVar &var) +{ + _BloomEffect = var.asBool(); +} + +} /* namespace NLQT */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/object_viewer.h b/code/nel/tools/3d/object_viewer_qt/src/object_viewer.h new file mode 100644 index 000000000..cdd10b648 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/object_viewer.h @@ -0,0 +1,227 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef OBJECT_VIEWER_H +#define OBJECT_VIEWER_H + +#include + +// STL includes +#include +#include + +// NeL includes +#include +#include +#include + +// Project includes +#include "entity.h" + +namespace NL3D { + class UDriver; + class UScene; + class ULight; + class UInstance; + class UCamera; + class USkeleton; + class UTextContext; + class UPlayListManager; + class U3dMouseListener; +} + +namespace NLQT { + +/** +@class CObjectViewer +@brief The class initializes the driver and creates a scene, provides basic control functions over the stage driver. +@details The class initializes the driver (by choosing OpenGL or Direct3D), and creates a scene (set an aspect), respectively +creates a light as well, load the font that is available further for +all other subsystems (eg: the signature of the coordinate axes) and Mouse Listener. +Settings are loaded from the configuration file. +Also, the class provides the following features to scene control: +- Loading and displaying of the shape, water shape and the particle system(loadMesh()). As well as the scene reset. (resetScene()) +- Provides access to a animation object (getEntity(), getListObjects()). +- Select of current object for various operation (mainly related to the animation and editing skeleton):setCurrentObject(), getCurrentObject(). +- Operations with the viewport, setting the correct perspective and creating of a screenshot. +- Function's updating keyboard and mouse (acts on the camera updateInput()), update(updateAnimatePS(), updateAnimation()) +and render the scene (renderDriver(), renderScene()). +- Provides access to a general NeL systems (getDriver(), getScene(), getPlayListManager(), getTextContext(), get3dMouseListener()). +*/ +class CObjectViewer +{ +public: + /// Default constructor. + CObjectViewer(); + + virtual ~CObjectViewer(); + + /// Init a driver and create scene. + /// @param wnd - handle window. + /// @param w - width window. + /// @param h - height window. + void init(nlWindow wnd, uint16 w, uint16 h); + + /// Release class. + void release(); + + /// Update mouse and keyboard events. And update camera matrix. + void updateInput(); + + /// Render Driver (clear all buffers and set background color). + void renderDriver(); + + /// Render current scene. + void renderScene(); + + /// Render Debug 2D (stuff for dev). + void renderDebug2D(); + + /// Make a screenshot of the current scene and save. + void saveScreenshot(const std::string &nameFile, bool jpg, bool png, bool tga); + + /// Load a mesh or particle system and add to current scene. + /// @param meshFileName - name loading shape or ps file. + /// @param skelFileName - name loading skeletin file. + /// @return true if file have been loaded, false if file have not been loaded. + bool loadMesh (const std::string &meshFileName, const std::string &skelFileName); + + /// Reset current scene. + void resetScene(); + + /// Update the navigation camera.(Note: deprecated) + /// @param deltaPsi - delta angle horizontal (radians). + /// @param deltaPhi - delta angle vertical (radians). + /// @param deltaDist - delta distance. + void updateCamera(float deltaPsi, float deltaPhi, float deltaDist); + + /// Update the animation time for Particle System animation. + /// @param deltaTime - set the manual animation time. + void updateAnimatePS(uint64 deltaTime = 0); + + /// Update animation from the scene + /// @param time - current time in second + void updateAnimation(NL3D::TAnimationTime time); + + /// Set the background color. + /// @param backgroundColor - background color. + void setBackgroundColor(NLMISC::CRGBA backgroundColor); + + /// Set type driver. + /// @param Direct3D - type driver (true - Direct3D) or (false -OpenGL) + void setGraphicsDriver(bool Direct3D); + + /// Set size viewport for correct set perspective + /// @param w - width window. + /// @param h - height window. + void setSizeViewport(uint16 w, uint16 h); + + void setBloomEffect(bool enabled) { _BloomEffect = enabled; } + + /// Select instance from the scene + /// @param name - name instance, "" if no instance edited + void setCurrentObject(const std::string &name); + + /// Get current instance from the scene + /// @return name current instance, "" if no instance edited + const std::string& getCurrentObject() { return _CurrentInstance; } + + /// Get entity from the scene + /// @return ref Entity + CEntity& getEntity(const std::string &name); + + /// Get full list instances from the scene + /// @param listObj - ref of return list instances + void getListObjects(std::vector &listObj); + + /// Get value background color. + /// @return background color. + inline NLMISC::CRGBA getBackgroundColor() const { return _BackgroundColor; } + + /// Get type driver. + /// @return true if have used Direct3D driver, false OpenGL driver. + inline bool getDirect3D() const { return _Direct3D; } + + inline bool getBloomEffect() const { return _BloomEffect; } + + /// Get a game interface for window driver. + /// @return pointer to the driver. + inline NL3D::UDriver *getDriver() const { return _Driver; } + + /// Get a game interface for scene. + /// @return pointer to the scene. + inline NL3D::UScene *getScene() const { return _Scene; } + + /// Get a manager of playlist + /// @return pointer to the UPlayListManager + inline NL3D::UPlayListManager *getPlayListManager() const { return _PlayListManager; } + + /// Get a game interface to render string + /// @return pointer to the UPlayListManager + inline NL3D::UTextContext *getTextContext() const { return _TextContext; } + + /// Get a 3d mouse listener + /// @return pointer to the U3dMouseListener + inline NL3D::U3dMouseListener *get3dMouseListener() const { return _MouseListener; } + +private: + void loadConfig(); + + void saveConfig(); + + // Delete all entities + void deleteEntities(); + + // Load background color from config file, intended for CConfiguration. + void cfcbBackgroundColor(NLMISC::CConfigFile::CVar &var); + void cfcbGraphicsDriver(NLMISC::CConfigFile::CVar &var); + void cfcbCameraFocal(NLMISC::CConfigFile::CVar &var); + void cfcbFontName(NLMISC::CConfigFile::CVar &var); + void cfcbBloomEffect(NLMISC::CConfigFile::CVar &var); + + NLMISC::CRGBA _BackgroundColor; + + NL3D::UDriver *_Driver; + NL3D::UScene *_Scene; + NL3D::UPlayListManager *_PlayListManager; + NL3D::ULight *_Light; + NL3D::UCamera *_Camera; + NL3D::UTextContext *_TextContext; + NL3D::U3dMouseListener *_MouseListener; + + // The entities storage + CEntities _Entities; + + /// Camera parameters. + float _phi, _psi, _dist; + + float _CameraFocal; + + std::string _FontName; + + bool _Direct3D; + bool _BloomEffect; + + std::string _CurrentInstance; + +};/* class CObjectViewer */ + +} /* namespace NLQT */ + +#endif // OBJECT_VIEWER_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/object_viewer_qt.qrc b/code/nel/tools/3d/object_viewer_qt/src/object_viewer_qt.qrc new file mode 100644 index 000000000..908cf78c2 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/object_viewer_qt.qrc @@ -0,0 +1,52 @@ + + + images/nel.png + images/open-file.png + images/go-down.png + images/go-up.png + images/list-add.png + images/list-remove.png + images/play.png + images/pause.png + images/stop.png + images/seek-backward.png + images/seek-forward.png + images/skip-backward.png + images/skip-forward.png + images/preferences.png + images/time.png + images/anim.png + images/animset.png + images/dqynight.png + images/mixer.png + images/pqrticles.png + images/sound.png + images/veget.png + images/water.png + images/wind.png + images/ico_bgcolor.png + images/ico_framedelay.png + images/ico_skelscale.png + images/clear.png + images/insert.png + images/new.png + images/refresh.png + images/save-as.png + images/save.png + images/insert-horizontal.png + + images/Workspace.bmp + images/ParticleSystem.bmp + images/Emitter.bmp + images/Sound.bmp + images/Light.bmp + images/Force.bmp + images/Particle.bmp + images/Located.bmp + images/LocatedInstance.bmp + images/CollisionZone.bmp + images/ParticleSystemNotLoaded.bmp + + images/nel_ide_load.png + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_control_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_control_dialog.cpp new file mode 100644 index 000000000..cbec8578f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_control_dialog.cpp @@ -0,0 +1,216 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_control_dialog.h" + +// Qt includes +#include + +// NeL includes +#include "nel/3d/scene.h" +#include + +// Project includes +#include "skeleton_tree_model.h" +#include "particle_link_skeleton_dialog.h" +#include "modules.h" + +namespace NLQT { + +CParticleControlDialog::CParticleControlDialog(CSkeletonTreeModel *model, QWidget *parent) + : QDockWidget(parent) +{ + _ui.setupUi(this); + + _timer = new QTimer(this); + + _particleLinkDialog = new CParticleLinkDialog(model, parent); + _particleLinkDialog->setVisible(false); + + _ui.numParticlesLabel->setMinimumWidth(_ui.numParticlesLabel->sizeHint().width()); + _ui.numWantedFacesLabel->setMinimumWidth(_ui.numWantedFacesLabel->sizeHint().width()); + _ui.systemTimesLabel->setMinimumWidth(_ui.systemTimesLabel->sizeHint().width()); + + stop(); + + connect(_timer, SIGNAL(timeout()), this, SLOT(updateCount())); + + connect(_ui.playToolButton, SIGNAL(clicked()), this, SLOT(play())); + connect(_ui.stopToolButton, SIGNAL(clicked()), this, SLOT(stop())); + connect(_ui.horizontalSlider, SIGNAL(sliderMoved(int)), this, SLOT(sliderMoved(int))); + connect(_ui.helpersCheckBox, SIGNAL(toggled(bool)), this, SLOT(displayHelpers(bool))); + connect(_ui.displayBoxCheckBox, SIGNAL(toggled(bool)), this, SLOT(displayBBox(bool))); + connect(_ui.loopCheckBox, SIGNAL(toggled(bool)), this, SLOT(autoRepeat(bool))); + connect(_ui.autoCountCheckBox, SIGNAL(toggled(bool)), this, SLOT(setEnabledAutoCount(bool))); + connect(_ui.resetAutoCountPushButton, SIGNAL(clicked()), this, SLOT(resetAutoCount())); + + connect(_ui.linkSkelPushButton, SIGNAL(clicked()), this, SLOT(linkSceleton())); + connect(_ui.unlinkSkelPushButton, SIGNAL(clicked()), this, SLOT(unlink())); + connect(_ui.setAnimPushButton, SIGNAL(clicked()), this, SLOT(setAnim())); + connect(_ui.clearAnimPushButton, SIGNAL(clicked()), this, SLOT(clearAnim())); + connect(_ui.restickPushButton, SIGNAL(clicked()), this, SLOT(restickObjects())); + + connect(_ui.generalToolButton, SIGNAL(clicked()), this, SLOT(setGeneralWidget())); + connect(_ui.additionalToolButton, SIGNAL(clicked()), this, SLOT(setAddtitionalWidget())); +} + +CParticleControlDialog::~CParticleControlDialog() +{ +} + +void CParticleControlDialog::updateActiveNode() +{ + _ui.skelLineEdit->setText(Modules::psEdit().getActiveNode()->getParentSkelName().c_str()); + _ui.animLineEdit->setText(Modules::psEdit().getActiveNode()->getTriggerAnim().c_str()); + _ui.autoCountCheckBox->setChecked(Modules::psEdit().getActiveNode()->getPSPointer()->getAutoCountFlag()); +} + +void CParticleControlDialog::play() +{ + if (Modules::psEdit().getActiveNode() == NULL) + { + _ui.playToolButton->setChecked(false); + return; + } + if (Modules::psEdit().isRunning()) + Modules::psEdit().pause(); + else if (_ui.multipleCheckBox->checkState() == Qt::Checked) + Modules::psEdit().startMultiple(); + else + Modules::psEdit().start(); + + _timer->start(200); + _ui.multipleCheckBox->setEnabled(false); + Q_EMIT changeState(); +} + +void CParticleControlDialog::stop() +{ + _timer->stop(); + _ui.playToolButton->setChecked(false); + Modules::psEdit().stop(); + _ui.multipleCheckBox->setEnabled(true); + + _ui.numParticlesLabel->setText(tr("Num particles:")); + _ui.numWantedFacesLabel->setText(tr("Num wanted faces:")); + _ui.systemTimesLabel->setText(tr("System time:")); + + Q_EMIT changeState(); +} + +void CParticleControlDialog::sliderMoved(int value) +{ + Modules::psEdit().setSpeed(float(value) / 100); +} + +void CParticleControlDialog::displayHelpers(bool state) +{ + Modules::psEdit().setDisplayHelpers(state); +} + +void CParticleControlDialog::displayBBox(bool state) +{ + Modules::psEdit().setDisplayBBox(state); +} + +void CParticleControlDialog::autoRepeat(bool state) +{ + Modules::psEdit().setAutoRepeat(state); +} + +void CParticleControlDialog::setEnabledAutoCount(bool state) +{ + resetAutoCount(); + Modules::psEdit().enableAutoCount(state); + _ui.resetAutoCountPushButton->setEnabled(state); + + Q_EMIT changeAutoCount(state); +} + +void CParticleControlDialog::resetAutoCount() +{ + stop(); + Modules::psEdit().resetAutoCount(Modules::psEdit().getActiveNode()); +} + +void CParticleControlDialog::updateCount() +{ + if (Modules::psEdit().getActiveNode() == NULL) + return; + + NL3D::CParticleSystem *ps = Modules::psEdit().getActiveNode()->getPSPointer(); + sint currNumParticles = (sint) ps->getCurrNumParticles(); + + // display number of particles for the currently active node + _ui.numParticlesLabel->setText(tr("Num particles: %1").arg(currNumParticles)); + + // display max number of wanted faces + NLMISC::CMatrix camMat = ps->getScene()->getCam()->getMatrix(); + sint numWantedFaces = (uint) ps->getWantedNumTris((ps->getSysMat().getPos() - camMat.getPos()).norm()); + _ui.numWantedFacesLabel->setText(tr("Num wanted faces: %1").arg(numWantedFaces)); + + // display system date + _ui.systemTimesLabel->setText(tr("System time: %1").arg(ps->getSystemDate(),0,'f',2)); + + Q_EMIT changeCount(); +} + +void CParticleControlDialog::linkSceleton() +{ + _particleLinkDialog->show(); +} + +void CParticleControlDialog::unlink() +{ + CWorkspaceNode *node = Modules::psEdit().getActiveNode(); + if (node == NULL) + return; + + node->unstickPSFromSkeleton(); +} + +void CParticleControlDialog::setAnim() +{ +} + +void CParticleControlDialog::clearAnim() +{ +} + +void CParticleControlDialog::restickObjects() +{ + CParticleWorkspace *pw = Modules::psEdit().getParticleWorkspace(); + if (pw == NULL) + return; + + pw->restickAllObjects(); +} + +void CParticleControlDialog::setGeneralWidget() +{ + _ui.stackedWidget->setCurrentWidget(_ui.pageGeneral); +} + +void CParticleControlDialog::setAddtitionalWidget() +{ + _ui.stackedWidget->setCurrentWidget(_ui.pageAdditional); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_control_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/particle_control_dialog.h new file mode 100644 index 000000000..7715f307f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_control_dialog.h @@ -0,0 +1,79 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_CONTROL_DIALOG_H +#define PARTICLE_CONTROL_DIALOG_H + +#include +#include "ui_particle_control_form.h" + +// Project includes + +namespace NLQT { + +class CSkeletonTreeModel; +class CParticleLinkDialog; + +class CParticleControlDialog: public QDockWidget +{ + Q_OBJECT +public: + CParticleControlDialog(CSkeletonTreeModel *model, QWidget *parent = 0); + ~CParticleControlDialog(); + +Q_SIGNALS: + void changeState(); + void changeCount(); + void changeAutoCount(bool state); + +public Q_SLOTS: + void updateActiveNode(); + +private Q_SLOTS: + void play(); + void stop(); + void sliderMoved(int value); + void displayHelpers(bool state); + void displayBBox(bool state); + void autoRepeat(bool state); + void setEnabledAutoCount(bool state); + void resetAutoCount(); + void updateCount(); + + void linkSceleton(); + void unlink(); + void setAnim(); + void clearAnim(); + void restickObjects(); + + void setGeneralWidget(); + void setAddtitionalWidget(); + +private: + + QTimer *_timer; + + CParticleLinkDialog *_particleLinkDialog; + + Ui::CParticleControlDialog _ui; +}; /* class CParticleControlDialog */ + +} /* namespace NLQT */ + +#endif // PARTICLE_CONTROL_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_control_form.ui b/code/nel/tools/3d/object_viewer_qt/src/particle_control_form.ui new file mode 100644 index 000000000..e85d030ff --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_control_form.ui @@ -0,0 +1,401 @@ + + + CParticleControlDialog + + + + 0 + 0 + 941 + 111 + + + + + 941 + 111 + + + + + 524287 + 524287 + + + + Particles system control + + + + + + + + 0 + 0 + + + + + 16777215 + 40 + + + + + + + + :/images/play.png + :/images/pause.png:/images/play.png + + + + 32 + 32 + + + + true + + + true + + + + + + + + 0 + 0 + + + + + 16777215 + 40 + + + + + + + + :/images/stop.png:/images/stop.png + + + + 32 + 32 + + + + true + + + + + + + + 0 + 0 + + + + 0 + + + + + + + + + + 0 + 0 + + + + Loop + + + + + + + + 0 + 0 + + + + Display helpers + + + + + + + + 0 + 0 + + + + Enable auto count + + + + + + + + 0 + 0 + + + + Display box + + + + + + + + 0 + 0 + + + + All particle system + + + + + + + false + + + + 0 + 0 + + + + Reset auto count + + + + + + + + + + + + + + + false + + + Link play to scene play + + + + + + + true + + + Link to skeleton + + + false + + + + + + + true + + + Unlink + + + + + + + true + + + true + + + + + + + false + + + Restick all objects + + + + + + + false + + + Set anim + + + + + + + false + + + Clear anim + + + + + + + false + + + + + + + + + + + + + + + + 0 + 0 + + + + General + + + + + + + + 0 + 0 + + + + Additional + + + + + + + + + + 0 + 0 + + + + Num particles:9999999 + + + + + + + + 0 + 0 + + + + Num wanted faces:9999999 + + + + + + + + 0 + 0 + + + + System time:99999999999 + + + + + + + + 0 + 0 + + + + 100 + + + 100 + + + 100 + + + true + + + Qt::Horizontal + + + false + + + false + + + QSlider::TicksBelow + + + 20 + + + + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_editor.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_editor.cpp new file mode 100644 index 000000000..767694313 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_editor.cpp @@ -0,0 +1,575 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_editor.h" + +// NeL includes +#include +#include +#include +#include +#include +#include + +// Project includes +#include "modules.h" + +namespace NLQT { + +CParticleEditor::CParticleEditor(void): + _ActiveNode(NULL), _State(State::Stopped), _Speed(1.0f), + _AutoRepeat(false), _DisplayBBox(false), + _DisplayHelpers(false), _AutoUpdateBBox(false), + _EmptyBBox(true), _PW(NULL), + _Driver(NULL), _Scene(NULL), + _FontManager(NULL), _FontGen(NULL) +{ +} + +CParticleEditor::~CParticleEditor(void) +{ +} + +void CParticleEditor::init() +{ + NL3D::CDriverUser *driver = dynamic_cast(Modules::objView().getDriver()); + _Driver = driver->getDriver(); + + NL3D::CSceneUser *scene = dynamic_cast(Modules::objView().getScene()); + _Scene = &scene->getScene(); + + NL3D::CTextContextUser *textContext = dynamic_cast(Modules::objView().getTextContext()); + _FontManager = textContext->getTextContext().getFontManager(); + _FontGen = textContext->getTextContext().getFontGenerator(); + NL3D::CParticleSystem::setSerializeIdentifierFlag(true); +} + +void CParticleEditor::release() +{ + stop(); + closeWorkspace(); +} + +void CParticleEditor::setActiveNode(CWorkspaceNode *node) +{ + if (node == _ActiveNode) return; + _ActiveNode = node; + + bool wasRunning = _State == State::RunningSingle; + if (wasRunning) + { + stop(); + } + if (wasRunning && _ActiveNode) + { + start(); + } +} + +NL3D::CParticleSystemModel *CParticleEditor::getModelFromPS(NL3D::CParticleSystem *ps) const +{ + if (!ps) return NULL; + CWorkspaceNode *node = _PW->getNodeFromPS(ps); + if (!node) return NULL; + return node->getPSModel(); +} + +void CParticleEditor::loadWorkspace(const std::string &fullPath) +{ + // Add to the path + std::auto_ptr newPW(new CParticleWorkspace); + newPW->init(fullPath); + + // save empty workspace + try + { + newPW->load(); + } + catch(NLMISC::EStream &e) + { + nlerror(e.what()); + return; + } + + // try to load each ps + CWorkspaceNode *firstLoadedNode = NULL; + TPWNodeItr itr = newPW->getNodeList().begin(); + while(itr != newPW->getNodeList().end()) + { + CWorkspaceNode *node = (*itr); + try + { + node->loadPS(); + } + catch(NLMISC::EStream &e) + { + nlwarning(e.what()); + } + if (node->isLoaded() && !firstLoadedNode) + firstLoadedNode = node; + itr++; + } + closeWorkspace(); + _PW = newPW.release(); + setActiveNode(firstLoadedNode); +} + +void CParticleEditor::createNewWorkspace(const std::string &fullPath) +{ + CParticleWorkspace *newPW = new CParticleWorkspace; + newPW->init(fullPath); + // save empty workspace + try + { + newPW->save(); + } + catch(NLMISC::EStream &e) + { + nlerror(e.what()); + } + closeWorkspace(); + _PW = newPW; +} + +void CParticleEditor::saveWorkspaceStructure() +{ + nlassert(_PW); + try + { + _PW->save(); + } + catch(NLMISC::EStream &e) + { + nlerror(e.what()); + } +} + + +void CParticleEditor::saveWorkspaceContent() +{ + TPWNodeItr itr = _PW->getNodeList().begin(); + while(itr != _PW->getNodeList().end()) + { + CWorkspaceNode *node = (*itr); + if (node->isModified()) + node->savePS(); + node->setModified(false); + itr++; + } +} + +void CParticleEditor::closeWorkspace() +{ + setActiveNode(NULL); + delete _PW; + _PW = NULL; +} + +void CParticleEditor::start() +{ + switch(_State) + { + case State::Stopped: + if (_ActiveNode) + { + if (checkHasLoop(*_ActiveNode)) return; + play(*_ActiveNode); + nlassert(_PlayingNodes.empty()); + _PlayingNodes.push_back(_ActiveNode); + } + break; + case State::RunningSingle: + // no-op + return; + break; + case State::RunningMultiple: + stop(); + start(); + break; + case State::PausedSingle: + if (_ActiveNode) + { + unpause(*_ActiveNode); + } + break; + case State::PausedMultiple: + for(uint k = 0; k < _PlayingNodes.size(); ++k) + { + if (_PlayingNodes[k]) + { + unpause(*_PlayingNodes[k]); + } + } + stop(); + start(); + break; + default: + nlassert(0); + break; + } + _State = State::RunningSingle; +} + +void CParticleEditor::startMultiple() +{ + switch(_State) + { + case State::Stopped: + { + if (!_PW) return; + nlassert(_PlayingNodes.empty()); + TPWNodeItr itr = _PW->getNodeList().begin(); + while(itr != _PW->getNodeList().end()) + { + CWorkspaceNode *node = (*itr); + if (node->isLoaded()) + if (checkHasLoop(*node)) return; + itr++; + } + + itr = _PW->getNodeList().begin(); + while(itr != _PW->getNodeList().end()) + { + CWorkspaceNode *node = (*itr); + if (node->isLoaded()) + { + // really start the node only if there's no trigger anim + if (node->getTriggerAnim().empty()) + play(*node); + + _PlayingNodes.push_back(node); + } + itr++; + } + } + break; + case State::PausedSingle: + case State::RunningSingle: + stop(); + startMultiple(); + break; + case State::RunningMultiple: + // no-op + return; + break; + case State::PausedMultiple: + for(uint k = 0; k < _PlayingNodes.size(); ++k) + { + if (_PlayingNodes[k]) + { + unpause(*_PlayingNodes[k]); + } + } + break; + default: + nlassert(0); + break; + } + _State = State::RunningMultiple; +} + +void CParticleEditor::pause() +{ + switch(_State) + { + case State::Stopped: + // no-op + return; + case State::RunningSingle: + if (_ActiveNode) + { + pause(*_ActiveNode); + } + _State = State::PausedSingle; + break; + case State::RunningMultiple: + for(uint k = 0; k < _PlayingNodes.size(); ++k) + { + if (_PlayingNodes[k]) + { + pause(*_PlayingNodes[k]); + } + } + _State = State::PausedMultiple; + break; + case State::PausedSingle: + case State::PausedMultiple: + // no-op + return; + default: + nlassert(0); + break; + } +} + +void CParticleEditor::stop() +{ + switch(_State) + { + case State::Stopped: + // no-op + return; + case State::RunningSingle: + case State::RunningMultiple: + case State::PausedSingle: + case State::PausedMultiple: + for(uint k = 0; k < _PlayingNodes.size(); ++k) + { + if (_PlayingNodes[k]) + { + stop(*_PlayingNodes[k]); + } + } + _PlayingNodes.clear(); + break; + default: + nlassert(0); + break; + } + _State = State::Stopped; +} + +void CParticleEditor::update() +{ + if (!_ActiveNode) return; + if (_PW == NULL) return; + + NL3D::CParticleSystem *currPS = _ActiveNode->getPSPointer(); + + // compute BBox + if (_DisplayBBox) + { + if (_AutoUpdateBBox) + { + NLMISC::CAABBox currBBox; + currPS->forceComputeBBox(currBBox); + if (_EmptyBBox) + { + _EmptyBBox = false; + _CurrBBox = currBBox; + } + else + { + _CurrBBox = NLMISC::CAABBox::computeAABBoxUnion(currBBox, _CurrBBox); + } + currPS->setPrecomputedBBox(_CurrBBox); + } + } + + // auto repeat feature + if (_AutoRepeat) + { + if (isRunning()) + { + bool allFXFinished = true; + bool fxStarted = false; + TPWNodeItr itr = _PlayingNodes.begin(); + while(itr != _PlayingNodes.end()) + { + CWorkspaceNode *node = (*itr); + if (node->isLoaded()) + { + if (isRunning(node)) + { + fxStarted = true; + if (node->getPSPointer()->getSystemDate() <= node->getPSPointer()->evalDuration()) + { + allFXFinished = false; + break; + } + else + { + if (node->getPSPointer()->getCurrNumParticles() != 0) + { + allFXFinished = false; + break; + } + } + } + } + itr++; + } + if (fxStarted && allFXFinished) + restartAllFX(); + } + } + + // draw PSmodel + TPWNodeItr itr = _PW->getNodeList().begin(); + while(itr != _PW->getNodeList().end()) + { + CWorkspaceNode *node = (*itr); + if (node->isLoaded()) + { + if (node == _ActiveNode) + node->getPSModel()->enableDisplayTools(!isRunning(node) || _DisplayHelpers); + else + node->getPSModel()->enableDisplayTools(false); + + // hide / show the node + if (_State == State::RunningMultiple || _State == State::PausedMultiple) + { + if (isRunning(node)) + node->getPSModel()->show(); + else + node->getPSModel()->hide(); + } + else + { + if (node == _ActiveNode) + node->getPSModel()->show(); + else + node->getPSModel()->hide(); + } + } + itr++; + } +} + +void CParticleEditor::restartAllFX() +{ + if (_State == State::RunningMultiple || _State == State::PausedMultiple) + { + for(uint k = 0; k < _PlayingNodes.size(); ++k) + { + if (_PlayingNodes[k]) + { + stop(*_PlayingNodes[k]); + } + } + } + else + { + for(uint k = 0; k < _PlayingNodes.size(); ++k) + { + if (_PlayingNodes[k]) + { + stop(*_PlayingNodes[k]); + play(*_PlayingNodes[k]); + } + } + } +} + +void CParticleEditor::setSpeed(float value) +{ + _Speed = value; + + if (!isRunning()) return; + + TPWNodeItr itr = _PW->getNodeList().begin(); + while(itr != _PW->getNodeList().end()) + { + CWorkspaceNode *node = (*itr); + if (node->isLoaded()) + node->getPSModel()->setEllapsedTimeRatio(value); + itr++; + } +} + +void CParticleEditor::setDisplayBBox(bool enable) +{ + _DisplayBBox = enable; + NL3D::CParticleSystem::forceDisplayBBox(enable); +} + +void CParticleEditor::enableAutoCount(bool enable) +{ + if (!_ActiveNode) return; + if (enable == _ActiveNode->getPSPointer()->getAutoCountFlag()) return; + _ActiveNode->getPSPointer()->setAutoCountFlag(enable); + _ActiveNode->setModified(true); +} + + +void CParticleEditor::resetAutoCount(CWorkspaceNode *node, bool reset /* = true */) +{ + if (!node) return; + if (node->getResetAutoCountFlag() == reset) return; + node->setResetAutoCountFlag(reset); + node->setModified(true); +} + +bool CParticleEditor::isRunning(CWorkspaceNode *node) +{ + nlassert(node); + return node->isStateMemorized(); +} + +bool CParticleEditor::checkHasLoop(CWorkspaceNode &node) +{ + nlassert(node.isLoaded()); + if (!node.getPSPointer()->hasLoop()) return false; + return true; +} + +void CParticleEditor::play(CWorkspaceNode &node) +{ + if (isRunning(&node)) return; + // NB : node must be stopped, no check is done + nlassert(node.isLoaded()); + // if node not started, start it + node.memorizeState(); + // enable the system to take the right date from the scene + node.getPSModel()->enableAutoGetEllapsedTime(true); + node.getPSPointer()->setSystemDate(0.f); + node.getPSPointer()->reactivateSound(); + node.getPSModel()->activateEmitters(true); + if (node.getPSPointer()->getAutoCountFlag()) + { + if (node.getResetAutoCountFlag()) + { + // reset particle size arrays + node.getPSPointer()->matchArraySize(); + } + resetAutoCount(&node, false); + } + + // Set speed playback particle system + node.getPSModel()->setEllapsedTimeRatio(_Speed); +} + +void CParticleEditor::unpause(CWorkspaceNode &node) +{ + if (!isRunning(&node)) return; + nlassert(node.isLoaded()); + node.getPSModel()->enableAutoGetEllapsedTime(true); +} + +void CParticleEditor::pause(CWorkspaceNode &node) +{ + if (!isRunning(&node)) return; + nlassert(node.isLoaded()); + node.getPSModel()->enableAutoGetEllapsedTime(false); + node.getPSModel()->setEllapsedTime(0.f); +} + +void CParticleEditor::stop(CWorkspaceNode &node) +{ + if (!isRunning(&node)) return; + nlassert(node.isLoaded()); + node.restoreState(); + node.getPSModel()->enableAutoGetEllapsedTime(false); + node.getPSModel()->setEllapsedTime(0.f); + node.getPSModel()->activateEmitters(true); + node.getPSPointer()->stopSound(); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_editor.h b/code/nel/tools/3d/object_viewer_qt/src/particle_editor.h new file mode 100644 index 000000000..98a20ff41 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_editor.h @@ -0,0 +1,220 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_EDITOR_H +#define PARTICLE_EDITOR_H + +#include + +// STL includes +#include +#include +#include + +// NeL includes +#include +#include + +// Projects includes +#include "particle_node.h" + +namespace NL3D { + class CParticleSystem; + class CParticleSystemModel; + class CShapeBank; + class CScene; + class IDriver; + class CFontManager; + class CFontGenerator; +} + +namespace NLQT { +/** +@class CParticleEditor +@brief The main class of the particles editor. +@details - Provides access to a container containing all of the particles systems (getParticleWorkspace()) +and also allows you to create an empty container (createNewWorkspace()) load / save from the file +and unload (loadWorkspace(), saveWorkspaceStructure(), saveWorkspaceContent()) +- Has basic operations management system to control a particles systems (start(), stop(), pause(), setSpeed() / setAutoRepeat()) +as in single mode, and in the multiple (start(), startMultiple()). +- Additional functions of particle systems: display / hide the assistanse elements (setDisplayHelpers()), +the calculation of bounding box (setAutoBBox(), getAutoBBox()), switching on the autoCount mode (setAutoBBox(), getAutoBBox()). +- Selection of the current system of particles for making various operations (setActiveNode(), getActiveNode()). +*/ +class CParticleEditor +{ +public: + struct State + { + enum List + { + Stopped = 1, + RunningSingle, + RunningMultiple, + PausedSingle, + PausedMultiple + }; + }; + CParticleEditor(void); + ~CParticleEditor(void); + + void init(); + + void release(); + + /// Active a new node of the workspace + /// Current active node is ready for edition. + /// Its bbox is displayed. + void setActiveNode(CWorkspaceNode *node); + + /// Get the node of the workspace that is currently active + CWorkspaceNode *getActiveNode() const { return _ActiveNode; } + + /// Get the particle system model that is currently active + NL3D::CParticleSystemModel *getActivePSM() const { return _ActiveNode ? _ActiveNode->getPSModel() : NULL; } + + /// Get a model from a ps pointer. The ps must belong to the workspace + NL3D::CParticleSystemModel *getModelFromPS(NL3D::CParticleSystem *ps) const; + + /// Load a new particle workspace (without asking if current workspace has been modified) + void loadWorkspace(const std::string &fullPath); + + void createNewWorkspace(const std::string &fullPath); + + /// Save the workspace structure + void saveWorkspaceStructure(); + + /// Save the workspace content + void saveWorkspaceContent(); + + /// Cloase the workspace without saving or asking the user + void closeWorkspace(); + + /// Force the active system to start + void start(); + + /// Start all systems + void startMultiple(); + + /// Pause the playing systems + void pause(); + + /// Force the playing systems to stop + void stop(); + + /// Update display of number of particles + void update(); + + /// Sets the animation speed particles system + void setSpeed(float value); + + void setDisplayBBox(bool enable); + + void setDisplayHelpers(bool enable) { _DisplayHelpers = enable; } + + void setAutoRepeat(bool enable) { _AutoRepeat = enable; } + + /// Auto bbox for fx + void setAutoBBox(bool enable) { _AutoUpdateBBox = enable; } + + bool getAutoBBox() const { return _AutoUpdateBBox; } + + /// Enable / disbale auto-count + void enableAutoCount(bool enable); + + /// Reset the autocount the next time the system will be started + void resetAutoCount(CWorkspaceNode *node, bool reset = true); + + /// Reset the auto compute bbox + void resetAutoBBox() { _EmptyBBox = true; } + + /// Get current state + int getState() const { return _State; } + + /// Return true if one or several system are being played + bool isRunning() const { return _State == State::RunningSingle || _State == State::RunningMultiple; } + + /// Return true if a system is paused. + /// Must call only if running + bool isPaused() const + { + return _State == State::PausedSingle || _State == State::PausedMultiple; + } + + CParticleWorkspace *getParticleWorkspace() const { return _PW; } + + NL3D::IDriver *getDriver() const { return _Driver; } + + NL3D::CScene *getScene() const { return _Scene; } + + /// Get the fontManager + NL3D::CFontManager *getFontManager() const {return _FontManager;} + + /// Get the fontGenerator + NL3D::CFontGenerator *getFontGenerator () const { return _FontGen; } + +private: + // Check if a node is inserted in the running list (it may be paused) + bool isRunning(CWorkspaceNode *node); + + // Check is a node has loops + bool checkHasLoop(CWorkspaceNode &node); + + void play(CWorkspaceNode &node); + void unpause(CWorkspaceNode &node); + void pause(CWorkspaceNode &node); + void stop(CWorkspaceNode &node); + void restartAllFX(); + + // Currently active node of the workspace + CWorkspaceNode *_ActiveNode; + + // List of fxs that are currently playing + TNodeVect _PlayingNodes; + + // Current state + int _State; + float _Speed; + bool _AutoRepeat; + bool _DisplayBBox; + bool _DisplayHelpers; + + // The system bbox must be updated automatically + bool _AutoUpdateBBox; + + // The last computed bbox for the system + bool _EmptyBBox; + NLMISC::CAABBox _CurrBBox; + + + CParticleWorkspace *_PW; + NL3D::IDriver *_Driver; + NL3D::CScene *_Scene; + + // Font manager + NL3D::CFontManager *_FontManager; + + // Font generator + NL3D::CFontGenerator *_FontGen; + +}; /* class CParticleEditor */ + +} /* namespace NLQT */ + +#endif // PARTICLE_EDITOR_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_force_form.ui b/code/nel/tools/3d/object_viewer_qt/src/particle_force_form.ui new file mode 100644 index 000000000..e645fd3b0 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_force_form.ui @@ -0,0 +1,199 @@ + + + CForcePage + + + + 0 + 0 + 298 + 458 + + + + Form + + + + + + QTabWidget::East + + + 0 + + + + Target + + + + + + Targets: + + + + + + + Avaible targets: + + + + + + + + + + Qt::Vertical + + + + 20 + 57 + + + + + + + + + + + + 30 + 16777215 + + + + < + + + + + + + + 30 + 16777215 + + + + > + + + + + + + Qt::Vertical + + + + 20 + 56 + + + + + + + + + + + Parametric factor: + + + + + + + + + + Radial viscosity: + + + + + + + + + + Tangential viscosity: + + + + + + + + + + Qt::Vertical + + + + 20 + 36 + + + + + + + + + Force intensity + + + + + + + + + Qt::Vertical + + + + 20 + 349 + + + + + + + + + + + + + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CDirectionWidget + QWidget +
direction_widget.h
+ 1 +
+ + NLQT::CAttribFloatWidget + QGroupBox +
attrib_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_force_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_force_page.cpp new file mode 100644 index 000000000..b2d516022 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_force_page.cpp @@ -0,0 +1,223 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_force_page.h" + +// Qt includes + #include + +// NeL includes +#include + +// Project includes + +namespace NLQT { + +CForcePage::CForcePage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + _ui.forceIntensityWidget->setRange(0, 10); + _ui.forceIntensityWidget->setWrapper(&_ForceIntensityWrapper); + _ui.forceIntensityWidget->setSchemeWrapper(&_ForceIntensityWrapper); + _ui.forceIntensityWidget->init(); + + _ui.parametricFactorWidget->setRange(0.0, 64.0); + _ui.parametricFactorWidget->setWrapper(&_ParamFactorWrapper); + + _ui.radialViscosityWidget->setRange(0.0, 1.0); + _ui.radialViscosityWidget->setWrapper(&_RadialViscosityWrapper); + + _ui.tangentialViscosityWidget->setRange(0, 1); + _ui.tangentialViscosityWidget->setWrapper(&_TangentialViscosityWrapper); + + _ui.directionWidget->setWrapper(&_DirectionWrapper); + + connect(_ui.toTargetsPushButton, SIGNAL(clicked()), this, SLOT(addTarget())); + connect(_ui.toAvaibleTargetsPushButton, SIGNAL(clicked()), this, SLOT(removeTarget())); +} + +CForcePage::~CForcePage() +{ +} + +void CForcePage::setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocatedBindable *locatedBindable) +{ + hideWrappersWidget(); + _Node = ownerNode; + _LBTarget = static_cast(locatedBindable); + + updateTargets(); + + // force with intensity case + if (dynamic_cast(_LBTarget)) + { + _ForceIntensityWrapper.F = dynamic_cast(_LBTarget); + + _ui.forceIntensityWidget->setWorkspaceNode(_Node); + _ui.forceIntensityWidget->updateUi(); + } + + // vortex (to tune viscosity) + if (dynamic_cast(_LBTarget)) + { + _RadialViscosityWrapper.OwnerNode = _Node; + _RadialViscosityWrapper.V = dynamic_cast(_LBTarget); + + _ui.radialViscosityWidget->updateUi(); + _ui.radialViscosityLabel->show(); + _ui.radialViscosityWidget->show(); + + _TangentialViscosityWrapper.OwnerNode = _Node; + _TangentialViscosityWrapper.V = dynamic_cast(_LBTarget); + + _ui.tangentialViscosityWidget->updateUi(); + _ui.tangentialViscosityLabel->show(); + _ui.tangentialViscosityWidget->show(); + } + + // deals with emitters that have a direction + if (dynamic_cast(_LBTarget)) + { + _DirectionWrapper.OwnerNode = _Node; + _DirectionWrapper.E = dynamic_cast(_LBTarget); + _ui.directionWidget->setDirectionWrapper(dynamic_cast(_LBTarget)); + + _ui.directionWidget->updateUi(); + _ui.directionWidget->show(); + } + + // Brownian (to tune parametric factor) + if (dynamic_cast(_LBTarget)) + { + _ParamFactorWrapper.OwnerNode = _Node; + _ParamFactorWrapper.F = static_cast(_LBTarget); + + _ui.parametricFactorWidget->updateUi(); + _ui.parametricFactorLabel->show(); + _ui.parametricFactorWidget->show(); + } +} + +void CForcePage::addTarget() +{ + // TODO: multiple add items + int totalCount = _ui.avaibleTargetsListWidget->count(); + if ((totalCount == 0) || (_ui.avaibleTargetsListWidget->currentRow() == -1)) return; + + CLocatedItem *item = dynamic_cast(_ui.avaibleTargetsListWidget->currentItem()); + + NL3D::CPSLocated *loc = item->getUserData(); + nlassert(loc); + + // check that force isn't applied on a forever lasting object + if (dynamic_cast(_LBTarget)) + { + if (loc->getLastForever()) + { + int ret = QMessageBox::warning(this, tr("NeL particle system editor"), + tr("The target object last forever. Applying a force on such an object may result in instability in the system after a while. " + "Continue ? (clue : you've been warned..)"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) + return; + } + + } + // + _LBTarget->attachTarget(loc); + + _ui.avaibleTargetsListWidget->takeItem(_ui.avaibleTargetsListWidget->currentRow()); + _ui.targetsListWidget->addItem(item); + + updateModifiedFlag(); +} + +void CForcePage::removeTarget() +{ + // TODO: multiple remove items + int totalCount = _ui.targetsListWidget->count(); + if ((totalCount == 0) || (_ui.targetsListWidget->currentRow() == -1)) return; + + CLocatedItem *item = dynamic_cast(_ui.targetsListWidget->takeItem(_ui.targetsListWidget->currentRow())); + + NL3D::CPSLocated *loc = item->getUserData(); + nlassert(loc); + + _LBTarget->detachTarget(loc); + + _ui.avaibleTargetsListWidget->addItem(item); + updateModifiedFlag(); +} + +void CForcePage::hideWrappersWidget() +{ + _ui.directionWidget->hide(); + _ui.parametricFactorLabel->hide(); + _ui.parametricFactorWidget->hide(); + _ui.radialViscosityLabel->hide(); + _ui.radialViscosityWidget->hide(); + _ui.tangentialViscosityLabel->hide(); + _ui.tangentialViscosityWidget->hide(); +} + +void CForcePage::updateTargets() +{ + uint k; + uint nbTarg = _LBTarget->getNbTargets(); + + _ui.targetsListWidget->clear(); + + std::set targetSet; + + // fill the box thta tells us what the target are + for(k = 0; k < nbTarg; ++k) + { + CLocatedItem *item = new CLocatedItem(QString(_LBTarget->getTarget(k)->getName().c_str()), + _ui.targetsListWidget); + item->setUserData(_LBTarget->getTarget(k)); + targetSet.insert(_LBTarget->getTarget(k)); + }; + + // fill abox with the available targets + NL3D::CParticleSystem *ps = _LBTarget->getOwner()->getOwner(); + + uint nbLocated = ps->getNbProcess(); + + _ui.avaibleTargetsListWidget->clear(); + + for (k = 0; k < nbLocated; ++k) + { + NL3D::CPSLocated *loc = dynamic_cast(ps->getProcess(k)); + if (loc) + { + if (targetSet.find(loc) == targetSet.end()) + { + CLocatedItem *item = new CLocatedItem(QString(loc->getName().c_str()), + _ui.avaibleTargetsListWidget); + item->setUserData(loc); + } + } + } +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_force_page.h b/code/nel/tools/3d/object_viewer_qt/src/particle_force_page.h new file mode 100644 index 000000000..80c1f541a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_force_page.h @@ -0,0 +1,137 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_FORCE_PAGE_H +#define PARTICLE_FORCE_PAGE_H + +#include +#include "ui_particle_force_form.h" + +// Qt includes + +// NeL includes +#include +#include + +// Project includes +#include "particle_node.h" +#include "ps_wrapper.h" + +namespace NLQT { + +/** +@class CLocatedItem +@brief Contain pointer to CPSLocated. +*/ +class CLocatedItem: public QListWidgetItem +{ +public: + CLocatedItem ( const QString & text, QListWidget * parent = 0, int type = UserType ): + QListWidgetItem(text, parent, type), _loc(NULL) {} + + void setUserData(NL3D::CPSLocated *loc) { _loc = loc;} + NL3D::CPSLocated *getUserData() const { return _loc;} + +private: + + NL3D::CPSLocated *_loc; +}; /* class CLocatedItem */ + +/** +@class CForcePage +@brief Page for QStackWidget, to edit forces in a particle system +*/ +class CForcePage: public QWidget +{ + Q_OBJECT + +public: + CForcePage(QWidget *parent = 0); + virtual ~CForcePage(); + + /// Set the force to edit. + void setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocatedBindable *locatedBindable); + +private Q_SLOTS: + void addTarget(); + void removeTarget(); + +private: + + /// wrapper to tune the intensity of a force + struct CForceIntensityWrapper : public IPSWrapperFloat, IPSSchemeWrapperFloat + { + NL3D::CPSForceIntensity *F; + float get(void) const { return F->getIntensity(); } + void set(const float &value) {F->setIntensity(value); } + scheme_type *getScheme(void) const { return F->getIntensityScheme(); } + void setScheme(scheme_type *s) {F->setIntensityScheme(s); } + } _ForceIntensityWrapper; + + /// wrapper to tune the radial viscosity for vortices + struct CRadialViscosityWrapper : public IPSWrapperFloat + { + NL3D::CPSCylindricVortex *V; + float get(void) const { return V->getRadialViscosity(); } + void set(const float &value) { V->setRadialViscosity(value); } + } _RadialViscosityWrapper; + + /// wrapper to tune the tangential viscosity for vortices + struct CTangentialViscosityWrapper : public IPSWrapperFloat + { + NL3D::CPSCylindricVortex *V; + float get(void) const { return V->getTangentialViscosity(); } + void set(const float &value) { V->setTangentialViscosity(value); } + } _TangentialViscosityWrapper; + + /// wrappers to tune the direction + struct CDirectionWrapper : public IPSWrapper + { + NL3D::CPSDirection *E; + NLMISC::CVector get(void) const { return E->getDir(); } + void set(const NLMISC::CVector &d){ E->setDir(d); } + } _DirectionWrapper; + + /// wrappers to tune the parametric factor of brownian force + struct CParamFactorWrapper : public IPSWrapperFloat + { + NL3D::CPSBrownianForce *F; + float get(void) const { return F->getParametricFactor(); } + void set(const float &f){ F->setParametricFactor(f); } + } _ParamFactorWrapper; + + + void hideWrappersWidget(); + + void updateTargets(); + + void updateModifiedFlag() { if (_Node) _Node->setModified(true); } + + // the target we're focusing on + NL3D::CPSTargetLocatedBindable *_LBTarget; + + CWorkspaceNode *_Node; + + Ui::CForcePage _ui; + +}; /* class CForcePage */ + +} /* namespace NLQT */ + +#endif // PARTICLE_FORCE_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_light_form.ui b/code/nel/tools/3d/object_viewer_qt/src/particle_light_form.ui new file mode 100644 index 000000000..fbdf789b9 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_light_form.ui @@ -0,0 +1,114 @@ + + + CLightPage + + + + 0 + 0 + 317 + 364 + + + + Form + + + + + + QTabWidget::East + + + 0 + + + + Light color + + + + + + + + + Qt::Vertical + + + + 20 + 228 + + + + + + + + + Attenuation start + + + + + + + + + Qt::Vertical + + + + 20 + 228 + + + + + + + + + Attenuation end + + + + + + + + + Qt::Vertical + + + + 20 + 228 + + + + + + + + + + + + + NLQT::CAttribFloatWidget + QGroupBox +
attrib_widget.h
+ 1 +
+ + NLQT::CAttribRGBAWidget + QGroupBox +
attrib_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_light_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_light_page.cpp new file mode 100644 index 000000000..45bb1e63b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_light_page.cpp @@ -0,0 +1,74 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_light_page.h" + +// Qt includes + +// NeL includes + +// Project includes +#include "modules.h" + +namespace NLQT { + +CLightPage::CLightPage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + _ui.lightColorWidget->setWrapper(&_ColorWrapper); + _ui.lightColorWidget->setSchemeWrapper(&_ColorWrapper); + _ui.lightColorWidget->init(); + + _ui.attenStartWidget->setRange(0.01f, 5.f); + _ui.attenStartWidget->setWrapper(&_AttenStartWrapper); + _ui.attenStartWidget->setSchemeWrapper(&_AttenStartWrapper); + _ui.attenStartWidget->init(); + + _ui.attenEndWidget->setRange(0.01f, 5.f); + _ui.attenEndWidget->setWrapper(&_AttenEndWrapper); + _ui.attenEndWidget->setSchemeWrapper(&_AttenEndWrapper); + _ui.attenEndWidget->init(); +} + +CLightPage::~CLightPage() +{ +} + +void CLightPage::setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocatedBindable *locatedBindable) +{ + _Node = ownerNode; + _Light = static_cast(locatedBindable); + + _ColorWrapper.L = _Light; + _ui.lightColorWidget->setWorkspaceNode(_Node); + _ui.lightColorWidget->updateUi(); + + _AttenStartWrapper.L = _Light; + _ui.attenStartWidget->setWorkspaceNode(_Node); + _ui.attenStartWidget->updateUi(); + + _AttenEndWrapper.L = _Light; + _ui.attenEndWidget->setWorkspaceNode(_Node); + _ui.attenEndWidget->updateUi(); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_light_page.h b/code/nel/tools/3d/object_viewer_qt/src/particle_light_page.h new file mode 100644 index 000000000..bdfaca7a7 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_light_page.h @@ -0,0 +1,94 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_LIGHT_PAGE_H +#define PARTICLE_LIGHT_PAGE_H + +#include +#include "ui_particle_light_form.h" + +// STL includes + +// NeL includes +#include +#include "nel/3d/ps_light.h" + +// Project includes +#include "ps_wrapper.h" + +namespace NLQT { + +/** +@class CLightPage +@brief Page for QStackWidget, to edit lights in a particle system +*/ +class CLightPage: public QWidget +{ + Q_OBJECT + +public: + CLightPage(QWidget *parent = 0); + ~CLightPage(); + + /// Set the light to edit. + void setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocatedBindable *locatedBindable); + +private Q_SLOTS: +private: + + /// wrapper to set the color of light + struct CColorWrapper : public IPSWrapperRGBA, IPSSchemeWrapperRGBA + { + NL3D::CPSLight *L; + NLMISC::CRGBA get(void) const { return L->getColor(); } + void set(const NLMISC::CRGBA &v) { L->setColor(v); } + scheme_type *getScheme(void) const { return L->getColorScheme(); } + void setScheme(scheme_type *s) { L->setColorScheme(s); } + } _ColorWrapper; + + /// wrapper to set start atten radius + struct CAttenStartWrapper : public IPSWrapperFloat, IPSSchemeWrapperFloat + { + NL3D::CPSLight *L; + float get(void) const { return L->getAttenStart(); } + void set(const float &v) { L->setAttenStart(v); } + scheme_type *getScheme(void) const { return L->getAttenStartScheme(); } + void setScheme(scheme_type *s) { L->setAttenStartScheme(s); } + } _AttenStartWrapper; + + /// wrapper to set end atten radius + struct CAttenEndWrapper : public IPSWrapperFloat, IPSSchemeWrapperFloat + { + NL3D::CPSLight *L; + float get(void) const { return L->getAttenEnd(); } + void set(const float &v) { L->setAttenEnd(v); } + scheme_type *getScheme(void) const { return L->getAttenEndScheme(); } + void setScheme(scheme_type *s) { L->setAttenEndScheme(s); } + } _AttenEndWrapper; + + NL3D::CPSLight *_Light; + + CWorkspaceNode *_Node; + + Ui::CLightPage _ui; +}; /* class CLightPage */ + +} /* namespace NLQT */ + +#endif // PARTICLE_LIGHT_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_link_skeleton_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_link_skeleton_dialog.cpp new file mode 100644 index 000000000..003d89a50 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_link_skeleton_dialog.cpp @@ -0,0 +1,93 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_link_skeleton_dialog.h" + +// Qt includes +#include + +// Project includes +#include "modules.h" +#include "particle_node.h" + +namespace NLQT { + +CParticleLinkDialog::CParticleLinkDialog(CSkeletonTreeModel *model, QWidget *parent) + : QDockWidget(parent) +{ + _ui.setupUi(this); + + qobject_cast< QMainWindow* >(parent)->addDockWidget(Qt::RightDockWidgetArea, this); + + _ui.treeView->setModel(model); + + connect(model, SIGNAL(modelReset()), this, SLOT(resetModel())); + connect(_ui.linkPushButton, SIGNAL(clicked()), this, SLOT(setLink())); + connect(_ui.unlinkPushButton, SIGNAL(clicked()), this, SLOT(setUnlink())); + connect(_ui.treeView, SIGNAL(clicked(QModelIndex)), this, SLOT(clickedItem(QModelIndex))); +} + +CParticleLinkDialog::~CParticleLinkDialog() +{ +} + +void CParticleLinkDialog::setLink() +{ + CWorkspaceNode *node = Modules::psEdit().getActiveNode(); + if (node == NULL) + return; + + std::string curObj = Modules::objView().getCurrentObject(); + if (curObj.empty()) + return; + + CSkeletonTreeItem *item = static_cast(_ui.treeView->currentIndex().internalPointer()); + + NL3D::CSkeletonModel *skel = Modules::objView().getEntity(curObj).getSkeleton().getObjectPtr(); + uint boneIndex = item->getId(); + std::string parentSkelName = Modules::objView().getEntity(curObj).getFileNameSkeleton(); + std::string parentBoneName = skel->Bones[boneIndex].getBoneName(); + + node->stickPSToSkeleton(skel, boneIndex, parentSkelName, parentBoneName); +} + +void CParticleLinkDialog::setUnlink() +{ + CWorkspaceNode *node = Modules::psEdit().getActiveNode(); + if (node == NULL) + return; + + node->unstickPSFromSkeleton(); +} + +void CParticleLinkDialog::resetModel() +{ + _ui.treeView->expandAll(); + _ui.linkPushButton->setEnabled(false); + _ui.unlinkPushButton->setEnabled(false); +} + +void CParticleLinkDialog::clickedItem(const QModelIndex & index) +{ + _ui.linkPushButton->setEnabled(true); + _ui.unlinkPushButton->setEnabled(true); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_link_skeleton_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/particle_link_skeleton_dialog.h new file mode 100644 index 000000000..5b7591ecd --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_link_skeleton_dialog.h @@ -0,0 +1,57 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_LINK_SKELETON_DIALOG_H +#define PARTICLE_LINK_SKELETON_DIALOG_H + +#include "ui_particle_link_skeleton_form.h" + +// STL includes + +// NeL includes + +// Project includes +#include "skeleton_tree_model.h" + +namespace NLQT { + +class CParticleLinkDialog: public QDockWidget +{ + Q_OBJECT + +public: + CParticleLinkDialog(CSkeletonTreeModel *model, QWidget *parent = 0); + ~CParticleLinkDialog(); + +private Q_SLOTS: + void setLink(); + void setUnlink(); + void resetModel(); + void clickedItem(const QModelIndex & index); + +private: + + Ui::CParticleLinkDialog _ui; + +}; /* class CParticleLinkDialog */ + +} /* namespace NLQT */ + + +#endif // PARTICLE_LINK_SKELETON_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_link_skeleton_form.ui b/code/nel/tools/3d/object_viewer_qt/src/particle_link_skeleton_form.ui new file mode 100644 index 000000000..4e629a6e5 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_link_skeleton_form.ui @@ -0,0 +1,50 @@ + + + CParticleLinkDialog + + + + 0 + 0 + 411 + 556 + + + + Link to skeleton + + + + + + + Choose bone to stick particle system + + + + + + + false + + + Link + + + + + + + false + + + Unlink + + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_node.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_node.cpp new file mode 100644 index 000000000..828f75ec1 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_node.cpp @@ -0,0 +1,523 @@ +// NeL - MMORPG Framework +// 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 . + + +#include "stdpch.h" +#include "particle_node.h" + +// NeL includes +#include +#include +#include + +#include +#include +#include +#include + +// Project includes +#include "modules.h" + +using namespace NLMISC; +using namespace NL3D; + +namespace NLQT { + +CWorkspaceNode::CWorkspaceNode() +{ + _PS = NULL; + _PSM = NULL; + _ShapeBank = NULL; + _Modified = false; + _ParentSkel = NULL; + _ResetAutoCount = false; + _WS = NULL; +} + +CWorkspaceNode::~CWorkspaceNode() +{ + unload(); +} + +void CWorkspaceNode::memorizeState() +{ + nlassert(_WS); + if (!_PS) return; + _InitialPos.copySystemInitialPos(_PS); +} + +void CWorkspaceNode::restoreState() +{ + nlassert(_WS); + if (!_PS) return; + _InitialPos.restoreSystem(); +} + +bool CWorkspaceNode::isStateMemorized() const +{ + return _InitialPos.isStateMemorized(); +} + +void CWorkspaceNode::stickPSToSkeleton(NL3D::CSkeletonModel *skel, + uint bone, + const std::string &parentSkelName, + const std::string &parentBoneName) +{ + nlassert(_WS); + if (!_PSM) return; + unstickPSFromSkeleton(); + _ParentSkelName = parentSkelName; + _ParentBoneName = parentBoneName; + if (skel) + { + skel->stickObject(_PSM, bone); + _PSM->setMatrix(NLMISC::CMatrix::Identity); + _ParentSkel = skel; + } + if (_WS->getModificationCallback()) + { + _WS->getModificationCallback()->nodeSkelParentChanged(*this); + } +} + +void CWorkspaceNode::unstickPSFromSkeleton() +{ + nlassert(_WS); + _ParentSkelName = ""; + _ParentBoneName = ""; + if (!_PSM) return; + if (_ParentSkel) + { + _ParentSkel->detachSkeletonSon(_PSM); + _ParentSkel = NULL; + } +} + +void CWorkspaceNode::removeLocated(NL3D::CPSLocated *loc) +{ + nlassert(_WS); + if (_InitialPos.isStateMemorized()) + { + _InitialPos.removeLocated(loc); + } +} + +void CWorkspaceNode::removeLocatedBindable(NL3D::CPSLocatedBindable *lb) +{ + nlassert(_WS); + if (_InitialPos.isStateMemorized()) + { + _InitialPos.removeLocatedBindable(lb); + } +} + +void CWorkspaceNode::setModified(bool modified) +{ + nlassert(_WS); + if (_Modified == modified) return; + _Modified = modified; + _WS->nodeModified(*this); +} + +void CWorkspaceNode::unload() +{ + nlassert(_WS); + if (_PSM) + { + NL3D::CShapeBank *oldSB = Modules::psEdit().getScene()->getShapeBank(); + Modules::psEdit().getScene()->setShapeBank(_ShapeBank); + Modules::psEdit().getScene()->deleteInstance(_PSM); + Modules::psEdit().getScene()->setShapeBank(oldSB); + _PSM = NULL; + } + delete _ShapeBank; + _ShapeBank = NULL; + _PS = NULL; + _ParentSkel = NULL; +} + +void CWorkspaceNode::setup(NL3D::CParticleSystemModel &psm) +{ + nlassert(_WS); + psm.setTransformMode(NL3D::CTransform::DirectMatrix); + psm.setMatrix(NLMISC::CMatrix::Identity); + psm.setEditionMode(true); // this also force the system instanciation + for(uint k = 0; k < NL3D::MaxPSUserParam; ++k) + { + psm.bypassGlobalUserParamValue(k); + } + psm.enableAutoGetEllapsedTime(false); + psm.setEllapsedTime(0.f); // system is paused + // initialy, the ps is hidden + psm.hide(); + // link to the root for manipulation + // !!!!!!!!!!!!!!!!!!! + //_WS->getObjectViewer()->getSceneRoot()->hrcLinkSon(&psm); + NL3D::CParticleSystem *ps = psm.getPS(); + nlassert(ps); + ps->setFontManager(Modules::psEdit().getFontManager()); + ps->setFontGenerator(Modules::psEdit().getFontGenerator()); + ps->stopSound(); + // flush textures + psm.Shape->flushTextures(*Modules::psEdit().getDriver(), 0); +} + +void CWorkspaceNode::setTriggerAnim(const std::string &anim) +{ + nlassert(_WS); + if (anim == _TriggerAnim) return; + _WS->touch(); + _TriggerAnim = anim; +} + +void CWorkspaceNode::createEmptyPS() +{ + nlassert(_WS); + NL3D::CParticleSystem emptyPS; + NL3D::CParticleSystemShape *pss = new NL3D::CParticleSystemShape; + pss->buildFromPS(emptyPS); + std::auto_ptr sb(new NL3D::CShapeBank); + std::string shapeName = NLMISC::CFile::getFilename(_RelativePath); + sb->add(shapeName, pss); + NL3D::CShapeBank *oldSB = Modules::psEdit().getScene()->getShapeBank(); + Modules::psEdit().getScene()->setShapeBank(sb.get()); + NL3D::CParticleSystemModel *psm = NLMISC::safe_cast(Modules::psEdit().getScene()->createInstance(shapeName)); + nlassert(psm); + Modules::psEdit().getScene()->setShapeBank(oldSB); + setup(*psm); + unload(); + // commit new values + _PS = psm->getPS(); + _PSM = psm; + _ShapeBank = sb.release(); + _Modified = false; +} + +void CWorkspaceNode::init(CParticleWorkspace *ws) +{ + nlassert(ws); + _WS = ws; +} + +void CWorkspaceNode::setRelativePath(const std::string &relativePath) +{ + nlassert(_WS); + _RelativePath = relativePath; +} + +void CWorkspaceNode::serial(NLMISC::IStream &f) +{ + nlassert(_WS); + f.xmlPush("PROJECT_FILE"); + sint version = f.serialVersion(2); + f.xmlSerial(_RelativePath, "RELATIVE_PATH"); + if (version >= 1) + { + f.xmlSerial(_TriggerAnim, "TRIGGER_ANIMATION"); + } + if (version >= 2) + { + f.xmlSerial(_ParentSkelName, "PARENT_SKEL_NAME"); + f.xmlSerial(_ParentBoneName, "PARENT_BONE_NAME"); + } + f.xmlPop(); +} + +void CWorkspaceNode::savePS() throw(NLMISC::EStream) +{ + savePSAs(getFullPath()); +} + +void CWorkspaceNode::savePSAs(const std::string &fullPath) throw(NLMISC::EStream) +{ + nlassert(_WS); + if (!_PS) return; + // build a shape from our system, and save it + NL3D::CParticleSystemShape psc; + psc.buildFromPS(*_PS); + NL3D::CShapeStream st(&psc); + NLMISC::COFile oFile(fullPath); + oFile.serial(st); +} + +std::string CWorkspaceNode::getFullPath() const +{ + nlassert(_WS); + return _WS->getPath() + _RelativePath.c_str(); +} + +bool CWorkspaceNode::loadPS() throw(NLMISC::EStream) +{ + nlassert(_WS); + // manually load the PS shape (so that we can deal with exceptions) + NL3D::CShapeStream ss; + NLMISC::CIFile inputFile; + // collapse name + inputFile.open(getFullPath()); + ss.serial(inputFile); + std::auto_ptr sb(new NL3D::CShapeBank); + std::string shapeName = NLMISC::CFile::getFilename(_RelativePath); + sb->add(shapeName, ss.getShapePointer()); + NL3D::CShapeBank *oldSB = Modules::psEdit().getScene()->getShapeBank(); + Modules::psEdit().getScene()->setShapeBank(sb.get()); + NL3D::CTransformShape *trs = Modules::psEdit().getScene()->createInstance(shapeName); + if (!trs) + { + Modules::psEdit().getScene()->setShapeBank(oldSB); + return false; + } + NL3D::CParticleSystemModel *psm = dynamic_cast(trs); + if (!psm) + { + // Not a particle system + Modules::psEdit().getScene()->deleteInstance(trs); + return false; + } + Modules::psEdit().getScene()->setShapeBank(oldSB); + setup(*psm); + unload(); + // commit new values + _PS = psm->getPS(); + _PSM = psm; + _ShapeBank = sb.release(); + _Modified = false; + return true; +} + + +//*********************************************************************************************** +CParticleWorkspace::CParticleWorkspace() +{ + _Modified = false; + _ModificationCallback = NULL; +} + +CParticleWorkspace::~CParticleWorkspace() +{ + for (size_t i = 0; i < _Nodes.size(); i++) + delete _Nodes[i]; + _Nodes.clear(); +} + +void CParticleWorkspace::init(const std::string &filename) +{ + _Filename = filename; +} + +void CParticleWorkspace::setName(const std::string &name) +{ + _Name = name; + touch(); +} + +void CParticleWorkspace::setFileName(const std::string &fileName) +{ + _Filename = fileName; +} + +std::string CParticleWorkspace::getFilename() const +{ + return CFile::getFilename(_Filename); +} + +CWorkspaceNode *CParticleWorkspace::addNode(const std::string &filenameWithFullPath) throw( NLMISC::Exception) +{ + // Check that file is not already inserted + std::string fileName = NLMISC::CFile::getFilename(filenameWithFullPath); + for(uint k = 0; k < _Nodes.size(); ++k) + { + if (NLMISC::nlstricmp(_Nodes[k]->getFilename(), fileName) == 0) return NULL; + } +// char resultPath[MAX_PATH]; +// std::string dosPath = NLMISC::CPath::standardizeDosPath(getPath()); + std::string relativePath; +// if (!PathRelativePathTo(resultPath, dosPath.c_str(), FILE_ATTRIBUTE_DIRECTORY, filenameWithFullPath.c_str(), 0)) +// { + relativePath = filenameWithFullPath; +// } +// else +// { +// relativePath = resultPath; +// } + if (relativePath.size() >= 2) + { + if (relativePath[0] == '\\' && relativePath[1] != '\\') + { + relativePath = relativePath.substr(1); + } + } + CWorkspaceNode *newNode = new CWorkspaceNode(); + newNode->init(this); + newNode->setRelativePath(relativePath); + _Nodes.push_back(newNode); + setModifiedFlag(true); + return newNode; +} + +void CParticleWorkspace::removeNode(uint index) +{ + nlassert(index < _Nodes.size()); + _Nodes[index] = NULL; // delete the smart-ptr target + _Nodes.erase(_Nodes.begin() + index); + touch(); +} + +void CParticleWorkspace::removeNode(CWorkspaceNode *ptr) +{ + sint index = getIndexFromNode(ptr); + nlassert(index != -1); + removeNode((uint) index); +} + +void CParticleWorkspace::save() throw(NLMISC::EStream) +{ + NLMISC::COFile stream; + stream.open(_Filename); + NLMISC::COXml xmlStream; + xmlStream.init(&stream); + this->serial(xmlStream); + clearModifiedFlag(); +} + +void CParticleWorkspace::load() throw(NLMISC::EStream) +{ + NLMISC::CIFile stream; + stream.open(_Filename); + NLMISC::CIXml xmlStream; + xmlStream.init(stream); + this->serial(xmlStream); + clearModifiedFlag(); +} + +void CParticleWorkspace::serial(NLMISC::IStream &f) throw(NLMISC::EStream) +{ + f.xmlPush("PARTICLE_WORKSPACE"); + f.serialVersion(0); + f.xmlSerial(_Name, "NAME"); + f.xmlPush("PS_LIST"); + uint32 numNodes = (uint32)_Nodes.size(); + // TODO : avoid to store the number of nodes + f.xmlSerial(numNodes, "NUM_NODES"); + if (f.isReading()) + { + for(uint k = 0; k < numNodes; ++k) + { + _Nodes.push_back(new CWorkspaceNode()); + _Nodes.back()->init(this); + f.serial(*_Nodes.back()); + } + } + else + { + for(uint k = 0; k < numNodes; ++k) + { + f.serial(*_Nodes[k]); + } + } + f.xmlPop(); + f.xmlPop(); +} + +std::string CParticleWorkspace::getPath() const +{ + return NLMISC::CPath::standardizePath(NLMISC::CFile::getPath(_Filename)); +} + +sint CParticleWorkspace::getIndexFromNode(CWorkspaceNode *node) const +{ + nlassert(node); + nlassert(node->getWorkspace() == this); + for(uint k = 0; k < _Nodes.size(); ++k) + { + if (node == _Nodes[k]) return (sint) k; + } + return -1; +} + +bool CParticleWorkspace::containsFile(std::string filename) const +{ + for(uint k = 0; k < _Nodes.size(); ++k) + { + if (NLMISC::nlstricmp(filename, _Nodes[k]->getFilename()) == 0) return true; + } + return false; +} + +void CParticleWorkspace::nodeModified(CWorkspaceNode &node) +{ + nlassert(node.getWorkspace() == this); + if (_ModificationCallback) + { + _ModificationCallback->nodeModifiedFlagChanged(node); + } +} + +CWorkspaceNode *CParticleWorkspace::getNodeFromPS(NL3D::CParticleSystem *ps) const +{ + for(uint k = 0; k < _Nodes.size(); ++k) + { + if (_Nodes[k]->getPSPointer() == ps) return _Nodes[k]; + } + return NULL; +} + +void CParticleWorkspace::setModifiedFlag(bool modified) +{ + if (_Modified == modified) return; + _Modified = modified; + if (_ModificationCallback) _ModificationCallback->workspaceModifiedFlagChanged(*this); +} + +bool CParticleWorkspace::isContentModified() const +{ + for(uint k = 0; k < _Nodes.size(); ++k) + { + if (_Nodes[k]->isModified()) return true; + } + return false; +} + +void CParticleWorkspace::restickAllObjects() +{ +/* for(uint k = 0; k < _Nodes.size(); ++k) + { + std::string parentSkelName = _Nodes[k]->getParentSkelName(); + std::string parentBoneName = _Nodes[k]->getParentBoneName(); + // + _Nodes[k]->unstickPSFromSkeleton(); + if (!parentSkelName.empty()) + // find instance to stick to in the scene + for(uint l = 0; l < ov->getNumInstance(); ++l) + { + CInstanceInfo *ii = ov->getInstance(l); + if (ii->TransformShape && ii->Saved.ShapeFilename == parentSkelName) + { + NL3D::CSkeletonModel *skel = dynamic_cast(ii->TransformShape); + if (skel) + { + sint boneID = skel->getBoneIdByName(parentBoneName); + if (boneID != -1) + { + _Nodes[k]->stickPSToSkeleton(skel, (uint) boneID, parentSkelName, parentBoneName); + break; + } + } + } + } + }*/ +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_node.h b/code/nel/tools/3d/object_viewer_qt/src/particle_node.h new file mode 100644 index 000000000..85293d432 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_node.h @@ -0,0 +1,295 @@ +// NeL - MMORPG Framework +// 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 . + + +#ifndef PARTICLE_NODE_H +#define PARTICLE_NODE_H + +// STL includes +#include +#include + +// NeL includes +#include "nel/misc/smart_ptr.h" +#include "nel/misc/stream.h" +#include +#include "nel/3d/skeleton_model.h" + +// Projects includes +#include "ps_initial_pos.h" + + +namespace NL3D { + class CParticleSystem; + class CParticleSystemModel; + class CShapeBank; +} + +namespace NLQT { + +class CParticleWorkspace; + +/** +@class CWorkspaceNode +@author Nicolas Vizerie +@author Nevrax France +@date 2004 +@brief A node in the workspace particles system editor. +@details Contains NeL system of particles and allows them to perform the following operations: +- Creating a new empty particle system (createEmptyPS()). +- Loading and saving the existing system of particles. +- Linking / unlinking of the system of particles to any bone of the skeleton model. +- Operations with the name and directory location of the particles system file. +- Has a flag indicating if the particles system changed or not (intended for the editor) +*/ +class CWorkspaceNode : public NLMISC::CRefCount +{ +public: + void init(CParticleWorkspace *ws); + + void setRelativePath(const std::string &relativePath); + + const std::string &getRelativePath() const { return _RelativePath; } + + std::string getFullPath() const; + + std::string getFilename() const { return NLMISC::CFile::getFilename(_RelativePath); } + + /// Serial node information into workspace stream. This does not save the particle system shape, only a reference to its file + void serial(NLMISC::IStream &f); + + /// Save the particle system target file + void savePS() throw(NLMISC::EStream); + + /// Save particle system with an arbitrary filename + void savePSAs(const std::string &fullPath) throw(NLMISC::EStream); + + /// put back in the unloaded state + void unload(); + + /// Load the particle system target file + /// @return true if loading succeed (false means that loading was ok, but this is not a particle system). Other cases throw an exception. + bool loadPS() throw(NLMISC::EStream); + + /// Create an empty particle system + void createEmptyPS(); + + /// Helper flag to know if a ps has been modified + /// @{ + bool isModified() const { return _Modified; } + void setModified(bool modified); + /// @} + NL3D::CParticleSystem *getPSPointer() const { return _PS; } + NL3D::CParticleSystemModel *getPSModel() const { return _PSM; } + + /// See if this node ps has been loaded + bool isLoaded() const { return _PS != NULL; } + + /// Get the workspace in which this node is inserted + CParticleWorkspace *getWorkspace() const { return _WS; } + + /// Memorize current position of object in the system. Useful to play the system because instances can be created / deleted + void memorizeState(); + + /// Restore state previously memorize. Is usually called when the user stops a particle system + void restoreState(); + + /// Test if state is currenlty memorized + bool isStateMemorized() const; + + /// For edition : If the state of the system has been memorized, keep it on par with the system when it is modified + void removeLocated(NL3D::CPSLocated *loc); + + /// For edition : If the state of the system has been memorized, keep it on par with the system when it is modified + void removeLocatedBindable(NL3D::CPSLocatedBindable *lb); + + /// Returns the skeleton to which the ps is currently sticked + NL3D::CSkeletonModel *getParentSkel() const { return _ParentSkel; } + + const std::string &getParentSkelName() const { return _ParentSkelName; } + + const std::string &getParentBoneName() const { return _ParentBoneName; } + + std::string getTriggerAnim() { return _TriggerAnim; } + + void setTriggerAnim(const std::string &anim); + +private: + std::string _TriggerAnim; + NL3D::CParticleSystem *_PS; + NL3D::CParticleSystemModel *_PSM; + + // Keep a shape bank per node because we want the whole path to identify the ps, not just its filename + // (shape bank keeps the filename only) + NL3D::CShapeBank *_ShapeBank; + + // Relative path from which the ps was inserted + // relative path is also a unique identifier for this ps in the workspace + std::string _RelativePath; + + // initial pos of system. Allow to restore the initial instances of the system when doing start / stop + CPSInitialPos _InitialPos; + bool _Modified; + CParticleWorkspace *_WS; + NLMISC::CRefPtr _ParentSkel; + bool _ResetAutoCount; + // + std::string _ParentSkelName; + std::string _ParentBoneName; +private: + void setup(NL3D::CParticleSystemModel &psm); +public: + bool getResetAutoCountFlag() const { return _ResetAutoCount; } + void setResetAutoCountFlag(bool reset) { _ResetAutoCount = reset; } + + /// Stick to a skeleton + void stickPSToSkeleton(NL3D::CSkeletonModel *skel, + uint bone, + const std::string &parentSkelName, // for callback after loading + const std::string &parentBoneName + ); + void unstickPSFromSkeleton(); +private: + friend class CParticleWorkspace; + // Ctor + CWorkspaceNode(); +public: + // DTor + ~CWorkspaceNode(); +}; /* class CWorkspaceNode */ + +typedef std::vector > TNodeVect; +typedef TNodeVect::iterator TPWNodeItr; + +/** +@class CParticleWorkspace +@author Nicolas Vizerie +@author Nevrax France +@date 2004 +@brief A container containing all the loaded particle system. +@details Allows you to load \ save in xml file list of systems of particles (the path to each file as well) +and additional parameters (skeleton model, and to which bone it is attached) +There is a feedback mechanism showed changes are being made with the container,with a particle system or connection to the skeleton. +*/ +class CParticleWorkspace +{ +public: + /// callback to know when a workspace node has been modified + struct IModificationCallback + { + virtual void workspaceModifiedFlagChanged(CParticleWorkspace &pw) = 0; + virtual void nodeModifiedFlagChanged(CWorkspaceNode &node) = 0; + virtual void nodeSkelParentChanged(CWorkspaceNode &node) = 0; // called when fx has been linked / unlinked from a skeleton parent + }; + /// Сonstructor + CParticleWorkspace(); + /// Destructor + ~CParticleWorkspace(); + + /// Init the workspace for the given object viewer + /// must be called prior to other methods + void init(const std::string &filename); + + /// Set a new name for the workspace (not its filename) + void setName(const std::string &name); + + /// Set a new file name for the workspace + void setFileName(const std::string &fileName); + + std::string getName() const { return _Name; } + + /// Get the path in which workpsace is located with a trailing slash + std::string getPath() const; + std::string getFilename() const; + + /// Get Number of nodes in the workspace + uint getNumNode() const { return (uint)_Nodes.size(); } + + /// Get a node in workspace + /// Can keep pointer safely as long as the node is not deleted + CWorkspaceNode *getNode(uint index) const { return _Nodes[index]; } + + /// Get a node from a pointer on a particle system + CWorkspaceNode *getNodeFromPS(NL3D::CParticleSystem *ps) const; + + /// Test if the workspace already contains a node with the given filename name + /// NB : 2 node with the same name re not allowed, even if their path is different + bool containsFile(std::string filename) const; + + /// Add a node in the workspace. Will succeed only if fx filename does not already exist in the workspace. + /// The node is in the 'unloaded' state, so caller must load it afterward. + /// NB : no lookup is done, full path must be provided. + /// @return pointer to new node, or NULL if already inserted + CWorkspaceNode *addNode(const std::string &filenameWithFullPath) throw( NLMISC::Exception); + + /// Remove a node by it's index + void removeNode(uint index); + + /// Remove a node by it's pointer + void removeNode(CWorkspaceNode *ptr); + + /// Get index of a node from its pointer, or -1 if not found + sint getIndexFromNode(CWorkspaceNode *node) const; + + /// Save the workspace structure. The target file is the one given when this object was created + /// NB : ps shape are not saved, only the structure is. To save the shapes, call CNode::save() + void save() throw(NLMISC::EStream); + + /// Load the workspace structure. The target file is the one given when this object was created + /// All nodes are in the 'unloaded" state, so it is to the caller to load them by calling load() on their node + void load() throw(NLMISC::EStream); + + /// Test wether the structure of the workspace has been modified (does not test if ps inside the workspace have been modified) + bool isModified() const { return _Modified; } + + /// Test wether the content of the workspace has ben modified + bool isContentModified() const; + void touch() { setModifiedFlag(true); } + void clearModifiedFlag() { setModifiedFlag(false); } + + /// Set a callback to know when a node is modified + void setModificationCallback(IModificationCallback *cb) { _ModificationCallback = cb; } + IModificationCallback *getModificationCallback() const { return _ModificationCallback; } + + /// Restick all objects, useful after loading + void restickAllObjects(); + + TNodeVect& getNodeList() { return _Nodes; } + +private: + // use smart ptr to avoir prb wih resize + TNodeVect _Nodes; + // path + name of workspace + std::string _Filename; + bool _Modified; + IModificationCallback *_ModificationCallback; + // workspace user name + std::string _Name; + + /// serial the object + void serial(NLMISC::IStream &f) throw(NLMISC::EStream); + + /// set the 'modified flag' and call the callback + void setModifiedFlag(bool modified); + +public: + void nodeModified(CWorkspaceNode &node); +}; /* class CParticleWorkspace */ + + +} /* namespace NLQT */ + +#endif // PARTICLE_NODE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_property_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_property_dialog.cpp new file mode 100644 index 000000000..1c54ec21e --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_property_dialog.cpp @@ -0,0 +1,139 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_property_dialog.h" + +// Qt includes + +// Project includes +#include "modules.h" + +namespace NLQT { + +CPropertyDialog::CPropertyDialog(CParticleTreeModel *treeModel, QWidget *parent) + : QDockWidget(parent) +{ + _treeModel = treeModel; + + setupUi(); +} +CPropertyDialog::~CPropertyDialog() +{ +} + +void CPropertyDialog::setupUi() +{ + setObjectName(QString::fromUtf8("CPropertyDialog")); + + QIcon icon; + icon.addFile(QString::fromUtf8(":/images/pqrticles.png"), QSize(), QIcon::Normal, QIcon::Off); + setWindowIcon(icon); + + _dockWidgetContents = new QWidget(); + _gridLayout = new QGridLayout(_dockWidgetContents); + _scrollArea = new QScrollArea(_dockWidgetContents); + _scrollArea->setWidgetResizable(true); + _scrollAreaWidgetContents = new QWidget(); + + _pagesGridLayout = new QGridLayout(_scrollAreaWidgetContents); + + _stackedWidget = new QStackedWidget(_scrollAreaWidgetContents); + + _wpPage = new CWorkspacePage(_treeModel); + _stackedWidget->addWidget(_wpPage); + _psPage = new CParticleSystemPage(_stackedWidget); + _stackedWidget->addWidget(_psPage); + _locatedBindablePage = new CLocatedBindablePage(_stackedWidget); + _stackedWidget->addWidget(_locatedBindablePage); + _locatedPage = new CLocatedPage(_stackedWidget); + _stackedWidget->addWidget(_locatedPage); + _forcePage = new CForcePage(_stackedWidget); + _stackedWidget->addWidget(_forcePage); + _lightPage = new CLightPage(_stackedWidget); + _stackedWidget->addWidget(_lightPage); + _zonePage = new CZonePage(_stackedWidget); + _stackedWidget->addWidget(_zonePage); + _soundPage = new CSoundPage(_stackedWidget); + _stackedWidget->addWidget(_soundPage); + _emitterPage = new CEmitterPage(_stackedWidget); + _stackedWidget->addWidget(_emitterPage); + _psMoverPage = new CPSMoverPage(_stackedWidget); + _stackedWidget->addWidget(_psMoverPage); + + _pagesGridLayout->addWidget(_stackedWidget, 0, 0, 1, 1); + + _scrollArea->setWidget(_scrollAreaWidgetContents); + + _gridLayout->addWidget(_scrollArea, 0, 0, 1, 1); + + setWidget(_dockWidgetContents); + setWindowTitle(tr("Property editor")); +} + +void CPropertyDialog::setCurrentEditedElement(CParticleTreeItem *editedItem) +{ + // Update ui property editor + switch (editedItem->itemType()) + { + case ItemType::ParticleSystem: + _psPage->setEditedParticleSystem(editedItem->getNode()); + _stackedWidget->setCurrentWidget(_psPage); + break; + case ItemType::Particle: + _locatedBindablePage->setEditedItem(_treeModel->getOwnerNode(editedItem) ,editedItem->getBind()); + _stackedWidget->setCurrentWidget(_locatedBindablePage); + break; + case ItemType::Emitter: + _emitterPage->setEditedItem(_treeModel->getOwnerNode(editedItem) ,editedItem->getBind()); + _stackedWidget->setCurrentWidget(_emitterPage); + break; + case ItemType::Force: + _forcePage->setEditedItem(_treeModel->getOwnerNode(editedItem) ,editedItem->getBind()); + _stackedWidget->setCurrentWidget(_forcePage); + break; + case ItemType::Light: + _lightPage->setEditedItem(_treeModel->getOwnerNode(editedItem) ,editedItem->getBind()); + _stackedWidget->setCurrentWidget(_lightPage); + break; + case ItemType::Sound: + _soundPage->setEditedItem(_treeModel->getOwnerNode(editedItem) ,editedItem->getBind()); + _stackedWidget->setCurrentWidget(_soundPage); + break; + case ItemType::Located: + _locatedPage->setEditedItem(_treeModel->getOwnerNode(editedItem) ,editedItem->getLoc()); + _stackedWidget->setCurrentWidget(_locatedPage); + break; + case ItemType::CollisionZone: + _zonePage->setEditedItem(_treeModel->getOwnerNode(editedItem) ,editedItem->getBind()); + _stackedWidget->setCurrentWidget(_zonePage); + break; + case ItemType::LocatedInstance: + _psMoverPage->setEditedItem(_treeModel->getOwnerNode(editedItem) ,editedItem->getLoc(), editedItem->getLocatedInstanceIndex()); + _stackedWidget->setCurrentWidget(_psMoverPage); + _treeModel->getOwnerNode(editedItem)->getPSPointer()->setCurrentEditedElement(editedItem->getLoc(), + editedItem->getLocatedInstanceIndex(), + _psMoverPage->getLocatedBindable()); + break; + default: + _stackedWidget->setCurrentWidget(_wpPage); + } +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_property_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/particle_property_dialog.h new file mode 100644 index 000000000..a3b8b8f0b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_property_dialog.h @@ -0,0 +1,89 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_PROPERTY_DIALOG_H +#define PARTICLE_PROPERTY_DIALOG_H + +// Qt includes +#include +#include +#include +#include +#include + +// NeL includes +#include "nel/misc/smart_ptr.h" + +// Projects includes +#include "particle_system_page.h" +#include "emitter_page.h" +#include "located_page.h" +#include "located_bindable_page.h" +#include "particle_force_page.h" +#include "particle_light_page.h" +#include "particle_zone_page.h" +#include "particle_sound_page.h" +#include "particle_workspace_page.h" +#include "ps_mover_page.h" +#include "particle_tree_model.h" +#include "particle_node.h" + +namespace NLQT { + +class CPropertyDialog: public QDockWidget +{ + Q_OBJECT +public: + CPropertyDialog(CParticleTreeModel *treeModel, QWidget *parent = 0); + ~CPropertyDialog(); + + void setCurrentEditedElement(CParticleTreeItem *editedItem); + + CLocatedPage *getLocatedPage() const { return _locatedPage; }; + CPSMoverPage *getMoverPage() const { return _psMoverPage; }; + +private: + void setupUi(); + + QWidget *_dockWidgetContents; + QGridLayout *_gridLayout; + QGridLayout *_pagesGridLayout; + QScrollArea *_scrollArea; + QWidget *_scrollAreaWidgetContents; + + QStackedWidget *_stackedWidget; + CWorkspacePage *_wpPage; + CParticleSystemPage *_psPage; + CLocatedBindablePage *_locatedBindablePage; + CLocatedPage *_locatedPage; + CForcePage *_forcePage; + CLightPage *_lightPage; + CZonePage *_zonePage; + CSoundPage *_soundPage; + CEmitterPage *_emitterPage; + CPSMoverPage *_psMoverPage; + + CParticleTreeModel *_treeModel; + + friend class CParticleWorkspaceDialog; +}; /* class CPropertyDialog */ + +} /* namespace NLQT */ + +#endif // PARTICLE_PROPERTY_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_sound_form.ui b/code/nel/tools/3d/object_viewer_qt/src/particle_sound_form.ui new file mode 100644 index 000000000..783126540 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_sound_form.ui @@ -0,0 +1,189 @@ + + + CSoundPage + + + + 0 + 0 + 314 + 334 + + + + Form + + + + + + QTabWidget::East + + + 0 + + + + General + + + + + + Sound name + + + + + + true + + + + + + + Browse + + + + + + + Qt::Horizontal + + + + 93 + 20 + + + + + + + + Play + + + + + + + + + + + + Spawn + + + + + + + Mute + + + + + + + + + Keep original pitch + + + + + + + Emission percent: + + + + + + + + + + Qt::Vertical + + + + 20 + 51 + + + + + + + + + Sound volume + + + + + + + + + Qt::Vertical + + + + 20 + 209 + + + + + + + + + Sound pitch + + + + + + + + + Qt::Vertical + + + + 20 + 208 + + + + + + + + + + + + + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CAttribFloatWidget + QGroupBox +
attrib_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_sound_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_sound_page.cpp new file mode 100644 index 000000000..daa9896e7 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_sound_page.cpp @@ -0,0 +1,168 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_sound_page.h" + +// Qt includes +#include + +// NeL includes +#include "nel/3d/ps_located.h" +#include "nel/3d/u_particle_system_sound.h" +#include "nel/3d/particle_system.h" + +// Project includes +#include "modules.h" +#include "sound_system.h" + +namespace NLQT { + +CSoundPage::CSoundPage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + // setup dialog the sounds gain + _ui.gainWidget->setRange(0.f, 1.f); + _ui.gainWidget->setWrapper(&_GainWrapper); + _ui.gainWidget->setSchemeWrapper(&_GainWrapper); + _ui.gainWidget->init(); + + // setup dialog the sounds pitch + _ui.pitchWidget->setRange(0.001f, 5.f); + _ui.pitchWidget->setWrapper(&_PitchWrapper); + _ui.pitchWidget->setSchemeWrapper(&_PitchWrapper); + _ui.pitchWidget->init(); + + // setup dialog the percent of sound emissions + _ui.emissionWidget->setRange(0.f, 1.f); + _ui.emissionWidget->setWrapper(&_EmissionPercentWrapper); + + connect(_ui.browsePushButton ,SIGNAL(clicked()), this, SLOT(browse())); + connect(_ui.playPushButton ,SIGNAL(clicked()), this, SLOT(play())); + connect(_ui.spawnCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setSpawn(bool))); + connect(_ui.muteCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setMute(bool))); + connect(_ui.keepPitchCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setKeepPitch(bool))); + connect(_ui.soundNameLineEdit ,SIGNAL(textChanged(QString)), this, SLOT(setSoundName(QString))); +} + +CSoundPage::~CSoundPage() +{ +} + +void CSoundPage::setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocatedBindable *locatedBindable) +{ + _Sound = static_cast(locatedBindable); + _Node = ownerNode; + + nlassert(_Sound); + + _EmissionPercentWrapper.OwnerNode = _Node; + _EmissionPercentWrapper.S = _Sound; + _ui.emissionWidget->updateUi(); + + _GainWrapper.S = _Sound; + _ui.gainWidget->setWorkspaceNode(_Node); + _ui.gainWidget->updateUi(); + + _PitchWrapper.S = _Sound; + _ui.pitchWidget->setWorkspaceNode(_Node); + _ui.pitchWidget->updateUi(); + + _ui.soundNameLineEdit->setText(QString(NLMISC::CStringMapper::unmap(_Sound->getSoundName()).c_str())); + + _ui.spawnCheckBox->setChecked(_Sound->getSpawn()); + _ui.muteCheckBox->setChecked(_Sound->getMute()); + _ui.keepPitchCheckBox->setChecked(_Sound->getUseOriginalPitchFlag()); +} + +void CSoundPage::browse() +{ + std::vector names; + + + NLSOUND::UAudioMixer *audioMixer = Modules::sound().getAudioMixer(); + if (audioMixer) + { + audioMixer->getSoundNames(names); + } + + // TODO: create CPickSound dialog + QStringList items; + items << tr(""); + for(size_t i = 0; i < names.size(); ++i) + items << QString(names[i]->c_str()); + + bool ok; + QString item = QInputDialog::getItem(this, tr("Select your sound"), + tr("Sound:"), items, 0, false, &ok); + if (ok) + { + _ui.soundNameLineEdit->setText(item); + updateModifiedFlag(); + } +} + +void CSoundPage::play() +{ + Modules::sound().play(_ui.soundNameLineEdit->text().toStdString()); +} + +void CSoundPage::setSpawn(bool state) +{ + if (state != _Sound->getSpawn()) + { + _Sound->setSpawn(state); + updateModifiedFlag(); + } +} + +void CSoundPage::setMute(bool state) +{ + if (state != _Sound->getMute()) + { + _Sound->setMute(state); + updateModifiedFlag(); + } +} + +void CSoundPage::setKeepPitch(bool state) +{ + bool hadScheme = _PitchWrapper.getScheme() != NULL; + if (state != _Sound->getUseOriginalPitchFlag()) + { + _Sound->setUseOriginalPitchFlag(state); + updateModifiedFlag(); + } + if (state) + { + if (hadScheme) _ui.pitchWidget->updateUi(); + ///!!!!! + ///_PitchDlg->closeEditWindow(); + } + _ui.pitchWidget->setEnabled(!state); +} + +void CSoundPage::setSoundName(const QString &text) +{ + _Sound->setSoundName(NLMISC::CStringMapper::map(text.toStdString())); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_sound_page.h b/code/nel/tools/3d/object_viewer_qt/src/particle_sound_page.h new file mode 100644 index 000000000..825bdb7c6 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_sound_page.h @@ -0,0 +1,109 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_SOUND_PAGE_H +#define PARTICLE_SOUND_PAGE_H + +#include +#include "ui_particle_sound_form.h" + +// STL includes + +// NeL includes +#include "nel/3d/ps_sound.h" + +// Project includes + +#include "ps_wrapper.h" +#include "particle_node.h" + +namespace NLSOUND +{ + class UAudioMixer; +} + +namespace NLQT { + +/** +@class CSoundPage +@brief Page for QStackWidget, to edit sounds in a particle system +*/ +class CSoundPage: public QWidget +{ + Q_OBJECT + +public: + CSoundPage(QWidget *parent = 0); + ~CSoundPage(); + + /// Set the sounds to edit. + void setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocatedBindable *locatedBindable); + +private Q_SLOTS: + void browse(); + void play(); + void setSpawn(bool state); + void setMute(bool state); + void setKeepPitch(bool state); + void setSoundName(const QString &text); + +private: + + /// wrapper to set the gain of sounds + struct CGainWrapper : public IPSWrapperFloat, IPSSchemeWrapperFloat + { + NL3D::CPSSound *S; + float get(void) const { return S->getGain(); } + void set(const float &v) { S->setGain(v); } + scheme_type *getScheme(void) const { return S->getGainScheme(); } + void setScheme(scheme_type *s) { S->setGainScheme(s); } + } _GainWrapper; + + /// wrapper to set the pitch of sounds + struct CPitchWrapper : public IPSWrapperFloat, IPSSchemeWrapperFloat + { + NL3D::CPSSound *S; + float get(void) const { return S->getPitch(); } + void set(const float &v) { S->setPitch(v); } + scheme_type *getScheme(void) const { return S->getPitchScheme(); } + void setScheme(scheme_type *s) { S->setPitchScheme(s); } + } _PitchWrapper; + + /// wrapper to set the percentage of sound emissions + struct CEmissionPercentWrapper : public IPSWrapperFloat + { + NL3D::CPSSound *S; + float get(void) const { return S->getEmissionPercent(); } + void set(const float &v) { S->setEmissionPercent(v); } + } _EmissionPercentWrapper; + + void updateModifiedFlag() { if (_Node) _Node->setModified(true); } + + /// the sound being edited + NL3D::CPSSound *_Sound; + + CWorkspaceNode *_Node; + + Ui::CSoundPage _ui; + +}; /* class CSoundPage */ + +} /* namespace NLQT */ + +#endif // PARTICLE_SOUND_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_system_form.ui b/code/nel/tools/3d/object_viewer_qt/src/particle_system_form.ui new file mode 100644 index 000000000..6e898a7ec --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_system_form.ui @@ -0,0 +1,909 @@ + + + CParticleSystemPage + + + + 0 + 0 + 334 + 495 + + + + Form + + + + + + QTabWidget::East + + + 0 + + + true + + + + Integration + + + + + + + 0 + 0 + + + + Enable load balancing + + + + + + + + 0 + 0 + + + + Accurate integration + + + + + + + Enable motion slowDown + + + + + + + Time threshold: + + + + + + + + + + Max steps: + + + + + + + + + + + 0 + 0 + + + + Lock + + + true + + + + + + + Qt::Vertical + + + + 20 + 112 + + + + + + + + + User param + + + + + + + + User param1: + + + + + + + Qt::Horizontal + + + + 146 + 20 + + + + + + + + + 0 + 0 + + + + Global + + + + + + + + + + + + + + User param2: + + + + + + + Qt::Horizontal + + + + 146 + 20 + + + + + + + + + 0 + 0 + + + + Global + + + + + + + + + + + + + + User param3: + + + + + + + Qt::Horizontal + + + + 146 + 20 + + + + + + + + Global + + + + + + + + + + + + + + User param4: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Global + + + + + + + + + + + + Qt::Vertical + + + + 20 + 131 + + + + + + + + + PBBox / LOD param + + + + + + + 0 + 0 + + + + Enable Precomputed Bounding Box + + + + + + + false + + + + + + + + + Auto + + + + + + + Qt::Horizontal + + + + 93 + 20 + + + + + + + + Reset + + + + + + + + + X: + + + + + + + + 0 + 0 + + + + false + + + QAbstractSpinBox::NoButtons + + + 999.000000000000000 + + + + + + + Y: + + + + + + + + 0 + 0 + + + + true + + + QAbstractSpinBox::NoButtons + + + 999.000000000000000 + + + + + + + + 0 + 0 + + + + Z: + + + + + + + + 0 + 0 + + + + QAbstractSpinBox::NoButtons + + + 999.000000000000000 + + + + + + + + + + 0 + 0 + + + + + 40 + 23 + + + + + 40 + 23 + + + + +10 % + + + + + + + + 0 + 0 + + + + + 40 + 23 + + + + + 40 + 23 + + + + -10 % + + + + + + + Qt::Horizontal + + + + 107 + 20 + + + + + + + + + + + Qt::Horizontal + + + + + + + + + Sharable + + + + + + + Auto-LOD + + + + + + + false + + + + 0 + 0 + + + + + 53454 + 16777215 + + + + Settings + + + + + + + + + Max view dist: + + + + + + + + + + LOD Ratio: + + + + + + + + + + Qt::Vertical + + + + 20 + 132 + + + + + + + + + Global color + + + + + + + 0 + 0 + + + + Force global lighting + + + + + + + + + + + + + + + + Edit global color + + + + + + + true + + + + + + + + + + Wrn: Bypass multitex, not supported by all types + + + + + + + Qt::Vertical + + + + 20 + 237 + + + + + + + + + Life mgt param + + + + + + Life mgt presets: + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + Environment FX + + + + + Running Environment FX + + + + + Spell FX + + + + + Looping Spell FX + + + + + Minor transitory FX + + + + + User defined + + + + + Moving Looping FX + + + + + Spawned Environment FX + + + + + Ground FX + + + + + Projectile FX + + + + + + + + + + + + + + Model removed when out of range + + + + + + + PS resource removed when not visible + + + + + + + Force life time update + + + + + + + No max nb steps + + + + + + + + + Anim type: + + + + + + + + 0 + 0 + + + + Die on event: + + + + + + + + + + + + 0 + 0 + + + + + When visible + + + + + When in visible clusters + + + + + Always + + + + + + + + + 0 + 0 + + + + + Disabled + + + + + No more particles + + + + + No more particles/emitters + + + + + + + + + + + + + 0 + 0 + + + + Apply after delay: + + + + + + + + 0 + 0 + + + + s + + + + + + + + + Auto delay + + + + + + + + + + Qt::Vertical + + + + 20 + 13 + + + + + + + + + + + + + NLQT::CEditRangeUIntWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CAttribRGBAWidget + QGroupBox +
attrib_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_system_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_system_page.cpp new file mode 100644 index 000000000..2b806fdfb --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_system_page.cpp @@ -0,0 +1,667 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_system_page.h" + +// Qt includes +#include +#include +#include +#include + +// NeL includes +#include +#include +#include + +// Project includes +#include "modules.h" +#include "auto_lod_dialog.h" + +using namespace NL3D; +using namespace NLMISC; + +namespace NLQT { + +// WRAPPERS IMPLEMENTATION + +float CTimeThresholdWrapper::get(void) const +{ + NL3D::TAnimationTime t; + uint32 max; + bool csd; + bool klt; + PS->getAccurateIntegrationParams(t, max, csd, klt); + return t; +} + +void CTimeThresholdWrapper::set(const float &tt) +{ + NL3D::TAnimationTime t; + uint32 max; + bool csd; + bool klt; + PS->getAccurateIntegrationParams(t, max, csd, klt); + PS->setAccurateIntegrationParams(tt, max, csd, klt); +} + +uint32 CMaxNbIntegrationWrapper::get(void) const +{ + NL3D::TAnimationTime t; + uint32 max; + bool csd; + bool klt; + PS->getAccurateIntegrationParams(t, max, csd, klt); + return max; +} + +void CMaxNbIntegrationWrapper::set(const uint32 &nmax) +{ + NL3D::TAnimationTime t; + uint32 max; + bool csd; + bool klt; + PS->getAccurateIntegrationParams(t, max, csd, klt); + PS->setAccurateIntegrationParams(t, nmax, csd, klt); +} + +float CUserParamWrapper::get(void) const +{ + return PS->getUserParam(Index); +} + +void CUserParamWrapper::set(const float &v) +{ + PS->setUserParam(Index, v); +} + +float CMaxViewDistWrapper::get(void) const +{ + return PS->getMaxViewDist(); +} + +void CMaxViewDistWrapper::set(const float &d) +{ + PS->setMaxViewDist(d); +} + +float CLODRatioWrapper::get(void) const +{ + return PS->getLODRatio(); +} + +void CLODRatioWrapper::set(const float &v) +{ + PS->setLODRatio(v); +} + +static void chooseGlobalUserParam(uint userParam, NL3D::CParticleSystem *ps, QWidget *parent) +{ + nlassert(ps); + bool ok; + QString text = QInputDialog::getText(parent, "Choose Global User Param", + "User name:", QLineEdit::Normal, + QString(ps->getGlobalValueName(userParam).c_str()), &ok); + + if (ok) + ps->bindGlobalValueToUserParam(text.toStdString(), userParam); +} + +CParticleSystemPage::CParticleSystemPage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + _ui.timeThresholdWidget->setRange(0.005f, 0.3f); + _ui.timeThresholdWidget->enableLowerBound(0, true); + _ui.timeThresholdWidget->setWrapper(&_TimeThresholdWrapper); + + _ui.maxStepsWidget->setRange(0, 4); + _ui.maxStepsWidget->enableLowerBound(0, true); + _ui.maxStepsWidget->setWrapper(&_MaxNbIntegrationWrapper); + + _ui.userParamWidget_1->setRange(0, 1.0f); + _ui.userParamWidget_1->enableLowerBound(0, false); + _ui.userParamWidget_1->enableUpperBound(1, false); + _ui.userParamWidget_1->setWrapper(&_UserParamWrapper[0]); + + _ui.userParamWidget_2->setRange(0, 1.0f); + _ui.userParamWidget_2->enableLowerBound(0, false); + _ui.userParamWidget_2->enableUpperBound(1, false); + _ui.userParamWidget_2->setWrapper(&_UserParamWrapper[1]); + + _ui.userParamWidget_3->setRange(0, 1.0f); + _ui.userParamWidget_3->enableLowerBound(0, false); + _ui.userParamWidget_3->enableUpperBound(1, false); + _ui.userParamWidget_3->setWrapper(&_UserParamWrapper[2]); + + _ui.userParamWidget_4->setRange(0, 1.0f); + _ui.userParamWidget_4->enableLowerBound(0, false); + _ui.userParamWidget_4->enableUpperBound(1, false); + _ui.userParamWidget_4->setWrapper(&_UserParamWrapper[3]); + + _ui.maxViewDistWidget->setRange(0, 400.f); + _ui.maxViewDistWidget->enableLowerBound(0, true); + _ui.maxViewDistWidget->setWrapper(&_MaxViewDistWrapper); + + _ui.lodRatioWidget->setRange(0, 1.f); + _ui.lodRatioWidget->enableLowerBound(0, true); + _ui.lodRatioWidget->enableUpperBound(1, true); + _ui.lodRatioWidget->setWrapper(&_LODRatioWrapper); + + _ui.colorWidget->setSchemeWrapper(&_GlobalColorWrapper); + _ui.colorWidget->enableMemoryScheme(false); + _ui.colorWidget->enableNbCycles(false); + _ui.colorWidget->enableSrcInput(false); + _ui.colorWidget->setEnabledConstantValue(false); + _ui.colorWidget->init(); + _ui.colorWidget->hide(); + + for (uint k = 0; k < NL3D::MaxPSUserParam; ++k) + _UserParamWrapper[k].Index = k; + + connect(_ui.globalLightCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setGlobalLight(bool))); + connect(_ui.loadBalancingCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setLoadBalancing(bool))); + connect(_ui.integrationCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setIntegration(bool))); + connect(_ui.motionSlowDownCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setMotionSlowDown(bool))); + connect(_ui.lockPushButton ,SIGNAL(toggled(bool)), this, SLOT(setLock(bool))); + connect(_ui.globalPushButton_1 ,SIGNAL(clicked()), this, SLOT(setGloabal1())); + connect(_ui.globalPushButton_2 ,SIGNAL(clicked()), this, SLOT(setGloabal2())); + connect(_ui.globalPushButton_3 ,SIGNAL(clicked()), this, SLOT(setGloabal3())); + connect(_ui.globalPushButton_4 ,SIGNAL(clicked()), this, SLOT(setGloabal4())); + connect(_ui.enablePBBCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setEnableBbox(bool))); + connect(_ui.autoCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setAutoBbox(bool))); + connect(_ui.resetPushButton ,SIGNAL(clicked()), this, SLOT(resetBbox())); + connect(_ui.incBboxPushButton ,SIGNAL(clicked()), this, SLOT(incBbox())); + connect(_ui.decBboxPushButton ,SIGNAL(clicked()), this, SLOT(decBbox())); + connect(_ui.xDoubleSpinBox ,SIGNAL(valueChanged(double)), this, SLOT(setXBbox(double))); + connect(_ui.yDoubleSpinBox ,SIGNAL(valueChanged(double)), this, SLOT(setYBbox(double))); + connect(_ui.zDoubleSpinBox ,SIGNAL(valueChanged(double)), this, SLOT(setZBbox(double))); + connect(_ui.editGlobalColorCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setEditGlobalColor(bool))); + connect(_ui.presetBehaviourComboBox ,SIGNAL(currentIndexChanged(int)), this, SLOT(setPresetBehaviour(int))); + connect(_ui.sharableCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setSharable(bool))); + connect(_ui.autoLODCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setAutoLOD(bool))); + connect(_ui.settingsPushButton ,SIGNAL(clicked()), this, SLOT(settings())); + connect(_ui.modelRemovedCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setModelRemoved(bool))); + connect(_ui.psResourceCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setPSResource(bool))); + connect(_ui.lifeTimeUpdateCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setLifeTimeUpdate(bool))); + connect(_ui.noMaxNBStepsCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setNoMaxNBSteps(bool))); + connect(_ui.autoDelayCheckBox ,SIGNAL(toggled(bool)), this, SLOT(setAutoDelay(bool))); + connect(_ui.animTypeComboBox ,SIGNAL(currentIndexChanged(int)), this, SLOT(setAnimType(int))); + connect(_ui.dieComboBox ,SIGNAL(currentIndexChanged(int)), this, SLOT(setDie(int))); + connect(_ui.afterDelaySpinBox ,SIGNAL(valueChanged(double)), this, SLOT(setAfterDelay(double))); +} + +CParticleSystemPage::~CParticleSystemPage() +{ +} + +void CParticleSystemPage::setEditedParticleSystem(CWorkspaceNode *node) +{ + _Node = node; + // load settings Time threshold. + _TimeThresholdWrapper.OwnerNode = _Node; + _TimeThresholdWrapper.PS = _Node->getPSPointer(); + _ui.timeThresholdWidget->updateUi(); + + // load settings Max steps. + _MaxNbIntegrationWrapper.OwnerNode = _Node; + _MaxNbIntegrationWrapper.PS = _Node->getPSPointer(); + _ui.maxStepsWidget->updateUi(); + + // load settings User Param + for (uint k = 0; k < NL3D::MaxPSUserParam; ++k) + { + _UserParamWrapper[k].OwnerNode = _Node; + _UserParamWrapper[k].PS = _Node->getPSPointer(); + } + + _ui.userParamWidget_1->updateUi(); + _ui.userParamWidget_2->updateUi(); + _ui.userParamWidget_3->updateUi(); + _ui.userParamWidget_4->updateUi(); + + // load settings Max view dist. + _MaxViewDistWrapper.OwnerNode = _Node; + _MaxViewDistWrapper.PS = _Node->getPSPointer(); + _ui.maxViewDistWidget->updateUi(); + + // load settings LOD Ratio. + _LODRatioWrapper.OwnerNode = _Node; + _LODRatioWrapper.PS = _Node->getPSPointer(); + _ui.lodRatioWidget->updateUi(); + + // Integration + _ui.integrationCheckBox->setChecked(_Node->getPSPointer()->isAccurateIntegrationEnabled()); + _ui.loadBalancingCheckBox->setChecked(_Node->getPSPointer()->isLoadBalancingEnabled()); + _ui.globalLightCheckBox->setChecked(_Node->getPSPointer()->getForceGlobalColorLightingFlag()); + + NL3D::TAnimationTime t; + uint32 max; + bool csd; + bool klt; + _Node->getPSPointer()->getAccurateIntegrationParams(t, max, csd, klt); + _ui.motionSlowDownCheckBox->setChecked(csd); + + // Precomputed Bbox + _ui.enablePBBCheckBox->setChecked(!_Node->getPSPointer()->getAutoComputeBBox()); + + // global color + _GlobalColorWrapper.PS = _Node->getPSPointer(); + _ui.colorWidget->setWorkspaceNode(_Node); + int bGlobalColor = _Node->getPSPointer()->getColorAttenuationScheme() != NULL ? 1 : 0; + _ui.editGlobalColorCheckBox->setChecked(bGlobalColor); + if (bGlobalColor) + _ui.colorWidget->updateUi(); + + // Life mgt parameters + _ui.presetBehaviourComboBox->setCurrentIndex(_Node->getPSPointer()->getBehaviourType()); + _ui.sharableCheckBox->setChecked(_Node->getPSPointer()->isSharingEnabled()); + _ui.autoLODCheckBox->setChecked(_Node->getPSPointer()->isAutoLODEnabled()); + + _ui.modelRemovedCheckBox->setChecked(_Node->getPSPointer()->getDestroyModelWhenOutOfRange()); + _ui.psResourceCheckBox->setChecked(_Node->getPSPointer()->doesDestroyWhenOutOfFrustum()); + _ui.noMaxNBStepsCheckBox->setChecked(_Node->getPSPointer()->getBypassMaxNumIntegrationSteps()); + + _ui.lifeTimeUpdateCheckBox->setChecked(klt); + _ui.dieComboBox->setCurrentIndex(_Node->getPSPointer()->getDestroyCondition()); + _ui.animTypeComboBox->setCurrentIndex(_Node->getPSPointer()->getAnimType()); + _ui.autoDelayCheckBox->setChecked(_Node->getPSPointer()->getAutoComputeDelayBeforeDeathConditionTest()); +} + +void CParticleSystemPage::updatePrecomputedBBoxParams() +{ + NLMISC::CAABBox b; + _Node->getPSPointer()->computeBBox(b); + _ui.xDoubleSpinBox->setValue(b.getHalfSize().x); + _ui.yDoubleSpinBox->setValue(b.getHalfSize().y); + _ui.zDoubleSpinBox->setValue(b.getHalfSize().z); +} + +void CParticleSystemPage::updateDieOnEventParams() +{ + bool ew = _Node->getPSPointer()->getDestroyCondition() == NL3D::CParticleSystem::none ? false : true; + _ui.autoDelayCheckBox->setEnabled(ew); + bool autoDelay = _Node->getPSPointer()->getAutoComputeDelayBeforeDeathConditionTest(); + if (autoDelay) + ew = false; + _ui.afterDelaySpinBox->setEnabled(ew); + _ui.afterDelaySpinBox->setValue(_Node->getPSPointer()->getDelayBeforeDeathConditionTest()); +} + +void CParticleSystemPage::updateLifeMgtPresets() +{ + bool bEnable = _Node->getPSPointer()->getBehaviourType() == NL3D::CParticleSystem::UserBehaviour ? true : false; + + _ui.modelRemovedCheckBox->setEnabled(bEnable); + _ui.psResourceCheckBox->setEnabled(bEnable); + _ui.lifeTimeUpdateCheckBox->setEnabled(bEnable); + _ui.noMaxNBStepsCheckBox->setEnabled(bEnable); + _ui.animTypeComboBox->setEnabled(bEnable); + _ui.dieComboBox->setEnabled(bEnable); + updateDieOnEventParams(); +} + +void CParticleSystemPage::setGlobalLight(bool state) +{ + if (state == _Node->getPSPointer()->getForceGlobalColorLightingFlag()) return; + _Node->getPSPointer()->setForceGlobalColorLightingFlag(state); + if (_Node && _Node->getPSModel()) + { + _Node->getPSModel()->touchLightableState(); + } + updateModifiedFlag(); +} + +void CParticleSystemPage::setLoadBalancing(bool state) +{ + if (state == _Node->getPSPointer()->isLoadBalancingEnabled()) return; + if (state == false) + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, tr("Are you sure?"), + tr("Load balancing on/off"), + QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) + _Node->getPSPointer()->enableLoadBalancing(false); + else + _ui.loadBalancingCheckBox->setChecked(true); + } + else + { + _Node->getPSPointer()->enableLoadBalancing(true); + } + updateModifiedFlag(); +} + +void CParticleSystemPage::setIntegration(bool state) +{ + // enable/disable accurate integration. + if (state != _Node->getPSPointer()->isAccurateIntegrationEnabled()) + { + _Node->getPSPointer()->enableAccurateIntegration(state); + updateModifiedFlag(); + } + _ui.timeThresholdWidget->setEnabled(state); + _ui.maxStepsWidget->setEnabled(state); + _ui.motionSlowDownCheckBox->setEnabled(state); +} + +void CParticleSystemPage::setMotionSlowDown(bool state) +{ + NL3D::TAnimationTime t; + uint32 max; + bool csd; + bool klt; + _Node->getPSPointer()->getAccurateIntegrationParams(t, max, csd, klt); + if (state == csd) return; + _Node->getPSPointer()->setAccurateIntegrationParams(t, max, state, klt); + updateModifiedFlag(); +} + +void CParticleSystemPage::setLock(bool checked) +{ + // Need frame delay dialog. +} + +void CParticleSystemPage::setGloabal1() +{ + nlassert(_Node->getPSPointer()); + chooseGlobalUserParam(0, _Node->getPSPointer(), this); + updateModifiedFlag(); +} + +void CParticleSystemPage::setGloabal2() +{ + chooseGlobalUserParam(1, _Node->getPSPointer(), this); + updateModifiedFlag(); +} + +void CParticleSystemPage::setGloabal3() +{ + chooseGlobalUserParam(2, _Node->getPSPointer(), this); + updateModifiedFlag(); +} + +void CParticleSystemPage::setGloabal4() +{ + chooseGlobalUserParam(3, _Node->getPSPointer(), this); + updateModifiedFlag(); +} + +void CParticleSystemPage::setEnableBbox(bool state) +{ + if (state == _Node->getPSPointer()->getAutoComputeBBox()) + { + _Node->getPSPointer()->setAutoComputeBBox(!state); + updateModifiedFlag(); + } + + if (state) + updatePrecomputedBBoxParams(); + else + Modules::psEdit().setAutoBBox(false); + _ui.bboxGroupBox->setEnabled(state); +} + +void CParticleSystemPage::setAutoBbox(bool state) +{ + Modules::psEdit().setAutoBBox(state); + _ui.xDoubleSpinBox->setEnabled(!state); + _ui.yDoubleSpinBox->setEnabled(!state); + _ui.zDoubleSpinBox->setEnabled(!state); + _ui.incBboxPushButton->setEnabled(!state); + _ui.decBboxPushButton->setEnabled(!state); + updateModifiedFlag(); +} + +void CParticleSystemPage::resetBbox() +{ + Modules::psEdit().resetAutoBBox(); + updateModifiedFlag(); +} + +void CParticleSystemPage::incBbox() +{ + NLMISC::CAABBox b; + _Node->getPSPointer()->computeBBox(b); + b.setHalfSize(1.1f * b.getHalfSize()); + _Node->getPSPointer()->setPrecomputedBBox(b); + updatePrecomputedBBoxParams(); +} + +void CParticleSystemPage::decBbox() +{ + NLMISC::CAABBox b; + _Node->getPSPointer()->computeBBox(b); + b.setHalfSize(0.9f * b.getHalfSize()); + _Node->getPSPointer()->setPrecomputedBBox(b); + updatePrecomputedBBoxParams(); +} + +void CParticleSystemPage::setXBbox(double value) +{ + NLMISC::CAABBox b; + _Node->getPSPointer()->computeBBox(b); + NLMISC::CVector h; + h.x = value; + h.y = b.getHalfSize().y; + h.z = b.getHalfSize().z; + b.setHalfSize(h); + _Node->getPSPointer()->setPrecomputedBBox(b); +} + +void CParticleSystemPage::setYBbox(double value) +{ + NLMISC::CAABBox b; + _Node->getPSPointer()->computeBBox(b); + NLMISC::CVector h; + h.x = b.getHalfSize().x; + h.y = value; + h.z = b.getHalfSize().z; + b.setHalfSize(h); + _Node->getPSPointer()->setPrecomputedBBox(b); +} + +void CParticleSystemPage::setZBbox(double value) +{ + NLMISC::CAABBox b; + _Node->getPSPointer()->computeBBox(b); + NLMISC::CVector h; + h.x = b.getHalfSize().x; + h.y = b.getHalfSize().y; + h.z = value; + b.setHalfSize(h); + _Node->getPSPointer()->setPrecomputedBBox(b); +} + +void CParticleSystemPage::setEditGlobalColor(bool state) +{ + bool bGlobalColor = _Node->getPSPointer()->getColorAttenuationScheme() != NULL ? true : false; + if (state != bGlobalColor) + { + // if the system hasn't a global color scheme, add one. + if (_Node->getPSPointer()->getColorAttenuationScheme() == NULL) + { + static const NLMISC::CRGBA grad[] = { NLMISC::CRGBA::White, NLMISC::CRGBA::Black }; + _Node->getPSPointer()->setColorAttenuationScheme(new NL3D::CPSColorGradient(grad, 2, 64, 1.f)); + _ui.colorWidget->updateUi(); + } + else + { + _Node->getPSPointer()->setColorAttenuationScheme(NULL); + } + updateModifiedFlag(); + } + _ui.colorWidget->setVisible(state); +} + +void CParticleSystemPage::setPresetBehaviour(int index) +{ + updateLifeMgtPresets(); + if (index == _Node->getPSPointer()->getBehaviourType()) return; + if (index == NL3D::CParticleSystem::SpellFX || + index == NL3D::CParticleSystem::SpawnedEnvironmentFX) + { + NL3D::CPSLocatedBindable *lb; + if (!_Node->getPSPointer()->canFinish(&lb)) + { + _ui.presetBehaviourComboBox->setCurrentIndex(_Node->getPSPointer()->getBehaviourType()); + QErrorMessage *errorMessage = new QErrorMessage(); + errorMessage->setModal(true); + if (!lb) + { + errorMessage->showMessage(tr("Can't perform operation : the system is flagged with 'No max nb steps' or uses the preset 'Spell FX', " + "and thus, should have a finite duration. Please remove that flag first.")); + errorMessage->exec(); + } + else + { + errorMessage->showMessage(tr("The system must have a finite duration for this setting! Please check that the following object " + "doesn't live forever or doesn't create a loop in the system :") + QString(lb->getName().c_str())); + errorMessage->exec(); + } + delete errorMessage; + return; + } + } + _Node->getPSPointer()->activatePresetBehaviour((NL3D::CParticleSystem::TPresetBehaviour) index); + updateLifeMgtPresets(); + updateModifiedFlag(); +} + +void CParticleSystemPage::setSharable(bool state) +{ + if (state == _Node->getPSPointer()->isSharingEnabled()) return; + _Node->getPSPointer()->enableSharing(state); + updateModifiedFlag(); +} + +void CParticleSystemPage::setAutoLOD(bool state) +{ + _ui.settingsPushButton->setEnabled(state); + // performance warning + if (state == _Node->getPSPointer()->isAutoLODEnabled()) return; + _Node->getPSPointer()->enableAutoLOD(state); + updateModifiedFlag(); +} + +void CParticleSystemPage::settings() +{ + CAutoLODDialog *dialog = new CAutoLODDialog(_Node, _Node->getPSPointer(), this); + dialog->show(); + dialog->exec(); + delete dialog; +} + +void CParticleSystemPage::setModelRemoved(bool state) +{ + if (state == _Node->getPSPointer()->getDestroyModelWhenOutOfRange()) return; + _Node->getPSPointer()->setDestroyModelWhenOutOfRange(state); + updateModifiedFlag(); +} + +void CParticleSystemPage::setPSResource(bool state) +{ + if (state != _Node->getPSPointer()->doesDestroyWhenOutOfFrustum()) + { + _Node->getPSPointer()->destroyWhenOutOfFrustum(state); + updateModifiedFlag(); + } + _ui.animTypeComboBox->setEnabled(!state); +} + +void CParticleSystemPage::setLifeTimeUpdate(bool state) +{ + NL3D::TAnimationTime t; + uint32 max; + bool csd; + bool klt; + _Node->getPSPointer()->getAccurateIntegrationParams(t, max, csd, klt); + if (klt == state) return; + _Node->getPSPointer()->setAccurateIntegrationParams(t, max, csd, state); + updateModifiedFlag(); +} + +void CParticleSystemPage::setNoMaxNBSteps(bool state) +{ + _ui.maxStepsWidget->setEnabled(!state); + if (state == _Node->getPSPointer()->getBypassMaxNumIntegrationSteps()) return; + if (state && !_Node->getPSPointer()->canFinish()) + { + QErrorMessage *errorMessage = new QErrorMessage(); + errorMessage->setModal(true); + errorMessage->showMessage(tr("The system must have a finite duration for this setting! Please check that.")); + errorMessage->exec(); + delete errorMessage; + _ui.maxStepsWidget->setEnabled(state); + _ui.noMaxNBStepsCheckBox->setChecked(!state); + return; + } + _Node->getPSPointer()->setBypassMaxNumIntegrationSteps(state); + updateModifiedFlag(); +} + +void CParticleSystemPage::setAutoDelay(bool state) +{ + _ui.afterDelaySpinBox->setEnabled(!state); + if (state == _Node->getPSPointer()->getAutoComputeDelayBeforeDeathConditionTest()) return; + _Node->getPSPointer()->setAutoComputeDelayBeforeDeathConditionTest(state); + updateModifiedFlag(); +} + +void CParticleSystemPage::setAnimType(int index) +{ + if (index == _Node->getPSPointer()->getAnimType()) return; + _Node->getPSPointer()->setAnimType((NL3D::CParticleSystem::TAnimType) index); + updateModifiedFlag(); +} + +void CParticleSystemPage::setDie(int index) +{ + if (index != _Node->getPSPointer()->getDestroyCondition()) + { + _Node->getPSPointer()->setDestroyCondition((NL3D::CParticleSystem::TDieCondition) index); + updateModifiedFlag(); + } + updateDieOnEventParams(); +} + +void CParticleSystemPage::setAfterDelay(double value) +{ + if (_Node->getPSPointer()->getDelayBeforeDeathConditionTest() != value) + { + _Node->getPSPointer()->setDelayBeforeDeathConditionTest(value); + updateModifiedFlag(); + } +} + +CParticleSystemPage::CGlobalColorWrapper::scheme_type *CParticleSystemPage::CGlobalColorWrapper::getScheme(void) const +{ + nlassert(PS); + return PS->getColorAttenuationScheme(); +} + +void CParticleSystemPage::CGlobalColorWrapper::setScheme(CParticleSystemPage::CGlobalColorWrapper::scheme_type *s) +{ + PS->setColorAttenuationScheme(s); +} + +} /* namespace NLQT */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_system_page.h b/code/nel/tools/3d/object_viewer_qt/src/particle_system_page.h new file mode 100644 index 000000000..9680b2508 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_system_page.h @@ -0,0 +1,156 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_SYSTEM_PAGE_H +#define PARTICLE_SYSTEM_PAGE_H + +#include +#include "ui_particle_system_form.h" + +// STL includes + +// NeL includes +#include +#include +#include "ps_wrapper.h" + +// Project includes +#include "edit_range_widget.h" + +namespace NLQT { + +class CUserParamWrapper : public IPSWrapperFloat +{ +public: + NL3D::CParticleSystem *PS; + uint32 Index; + float get(void) const; + void set(const float &v); +}; + +class CTimeThresholdWrapper : public IPSWrapperFloat +{ +public: + NL3D::CParticleSystem *PS; + float get(void) const; + void set(const float &); +}; + +class CMaxNbIntegrationWrapper : public IPSWrapperUInt +{ +public: + NL3D::CParticleSystem *PS; + uint32 get(void) const; + void set(const uint32 &); +}; + +class CMaxViewDistWrapper : public IPSWrapperFloat +{ +public: + NL3D::CParticleSystem *PS; + float get(void) const; + void set(const float &); +}; + +class CLODRatioWrapper : public IPSWrapperFloat +{ +public: + NL3D::CParticleSystem *PS; + float get(void) const; + void set(const float &); +}; + +/** +@class CParticleSystemPage +@brief Page for QStackWidget, to edit workspace node in a particle system +*/ +class CParticleSystemPage: public QWidget +{ + Q_OBJECT + +public: + CParticleSystemPage(QWidget *parent = 0); + ~CParticleSystemPage(); + + /// Set the workspace node to edit. + void setEditedParticleSystem(CWorkspaceNode *node); + +private Q_SLOTS: + void setGlobalLight(bool state); + void setLoadBalancing(bool state); + void setIntegration(bool state); + void setMotionSlowDown(bool state); + void setLock(bool checked); + void setGloabal1(); + void setGloabal2(); + void setGloabal3(); + void setGloabal4(); + void setEnableBbox(bool state); + void setAutoBbox(bool state); + void resetBbox(); + void incBbox(); + void decBbox(); + void setXBbox(double value); + void setYBbox(double value); + void setZBbox(double value); + void setEditGlobalColor(bool state); + void setPresetBehaviour(int index); + void setSharable(bool state); + void setAutoLOD(bool state); + void settings(); + void setModelRemoved(bool state); + void setPSResource(bool state); + void setLifeTimeUpdate(bool state); + void setNoMaxNBSteps(bool state); + void setAutoDelay(bool state); + void setAnimType(int index); + void setDie(int index); + void setAfterDelay(double value); + +private: + void updatePrecomputedBBoxParams(); + void updateDieOnEventParams(); + void updateLifeMgtPresets(); + + void updateModifiedFlag() { if (_Node) _Node->setModified(true); } + + CWorkspaceNode *_Node; + CTimeThresholdWrapper _TimeThresholdWrapper; + CMaxViewDistWrapper _MaxViewDistWrapper; + CMaxNbIntegrationWrapper _MaxNbIntegrationWrapper; + CLODRatioWrapper _LODRatioWrapper; + + /// wrapper to tune user parameters + CUserParamWrapper _UserParamWrapper[NL3D::MaxPSUserParam]; + + struct CGlobalColorWrapper : public IPSSchemeWrapperRGBA + { + NL3D::CParticleSystem *PS; + virtual scheme_type *getScheme(void) const; + virtual void setScheme(scheme_type *s); + } + _GlobalColorWrapper; + + Ui::CParticleSystemPage _ui; + +}; /* class CParticleSystemPage */ + +} /* namespace NLQT */ + +#endif // PARTICLE_SYSTEM_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_texture_anim_form.ui b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_anim_form.ui new file mode 100644 index 000000000..139d5b2d3 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_anim_form.ui @@ -0,0 +1,142 @@ + + + CParticleTextureAnimWidget + + + + 0 + 0 + 306 + 186 + + + + Form + + + + + + Enable texture animation + + + + + + + + 0 + 0 + + + + + + + + + + Multitexturing + + + + + + + false + + + Edit + + + + + + + + + + + + + + + + false + + + Texture grouped + + + true + + + + + + + + NLQT::CParticleTextureWidget + QWidget +
particle_texture_widget.h
+ 1 +
+ + NLQT::CAttribIntWidget + QWidget +
attrib_widget.h
+ 1 +
+
+ + + + multitexturingCheckBox + toggled(bool) + editPushButton + setEnabled(bool) + + + 100 + 67 + + + 285 + 70 + + + + + texAnimCheckBox + toggled(bool) + multitexturingGroupBox + setDisabled(bool) + + + 77 + 24 + + + 86 + 72 + + + + + texAnimCheckBox + toggled(bool) + textureGroupedPushButton + setEnabled(bool) + + + 138 + 17 + + + 174 + 17 + + + + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_texture_anim_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_anim_widget.cpp new file mode 100644 index 000000000..73ebe4107 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_anim_widget.cpp @@ -0,0 +1,153 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_texture_anim_widget.h" + +// NeL includes +#include +#include +#include +#include +#include + +// Projects includes +#include "value_gradient_dialog.h" +#include "multi_tex_dialog.h" + +namespace NLQT { + +CParticleTextureAnimWidget::CParticleTextureAnimWidget(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + _ui.texIndexWidget->setRange(0, 1); + _ui.texIndexWidget->setWrapper(&_TextureIndexWrapper ); + _ui.texIndexWidget->setSchemeWrapper(&_TextureIndexWrapper ); + _ui.texIndexWidget->init(); + + _ui.texWidget->setWrapper(&_TextureWrapper); + + connect(_ui.texAnimCheckBox, SIGNAL(toggled(bool)), this, SLOT(setEnabledTexAnim(bool))); + connect(_ui.multitexturingCheckBox, SIGNAL(toggled(bool)), this, SLOT(setMultitexturing(bool))); + connect(_ui.editPushButton, SIGNAL(clicked()), this, SLOT(editMultitexturing())); + connect(_ui.textureGroupedPushButton, SIGNAL(clicked()), this, SLOT(chooseGroupedTexture())); +} + +CParticleTextureAnimWidget::~CParticleTextureAnimWidget() +{ +} + +void CParticleTextureAnimWidget::setCurrentTextureAnim(NL3D::CPSTexturedParticle *tp, NL3D::CPSMultiTexturedParticle *mtp,CWorkspaceNode *ownerNode) +{ + _Node = ownerNode; + _EditedParticle = tp; + _MTP = mtp; + + disconnect(_ui.texAnimCheckBox, SIGNAL(toggled(bool)), this, SLOT(setEnabledTexAnim(bool))); + + bool isAnimTex = _EditedParticle->getTextureGroup() ? true : false; + _ui.texAnimCheckBox->setChecked(isAnimTex); + updateTexAnimState(isAnimTex); + + if (_MTP) + { + _ui.multitexturingCheckBox->setChecked(_MTP->isMultiTextureEnabled()); + _ui.multitexturingGroupBox->show(); + } + else + _ui.multitexturingGroupBox->hide(); + + connect(_ui.texAnimCheckBox, SIGNAL(toggled(bool)), this, SLOT(setEnabledTexAnim(bool))); +} + +void CParticleTextureAnimWidget::setEnabledTexAnim(bool state) +{ + if (state) + { + if (_MTP) + _ui.multitexturingCheckBox->setChecked(false); + + // When you try to load a dummy texture, remove alternative paths, an assertion is thrown otherwise + NLMISC::CPath::removeAllAlternativeSearchPath(); + + // put a dummy texture as a first texture + NLMISC::CSmartPtr tex = (NL3D::ITexture *) new NL3D::CTextureFile(std::string("")); + NL3D::CTextureGrouped *tg = new NL3D::CTextureGrouped; + tg->setTextures(&tex, 1); + _EditedParticle->setTextureGroup(tg); + _EditedParticle->setTextureIndex(0); + } + else + { + _EditedParticle->setTexture(NULL); + } + updateTexAnimState(state); + updateModifiedFlag(); +} + +void CParticleTextureAnimWidget::chooseGroupedTexture() +{ + CTextureGradientInterface *texInterface = new CTextureGradientInterface(_EditedParticle, _Node); + CGradientDialog *gd = new CGradientDialog(_Node, texInterface, true, false, 1, this); + gd->setModal(true); + gd->show(); + gd->exec(); + delete gd; +} + +void CParticleTextureAnimWidget::setMultitexturing(bool enabled) +{ + if (_MTP->isMultiTextureEnabled() != enabled) + { + _MTP->enableMultiTexture(enabled); + updateModifiedFlag(); + } +} + +void CParticleTextureAnimWidget::editMultitexturing() +{ + CMultiTexDialog *multiTexDialog = new CMultiTexDialog(_Node, _MTP, this); + multiTexDialog->show(); + multiTexDialog->exec(); + delete multiTexDialog; +} + +void CParticleTextureAnimWidget::updateTexAnimState(bool state) +{ + if (state) + { + _ui.texIndexWidget->setRange( 0, _EditedParticle->getTextureGroup()->getNbTextures() - 1); + _TextureIndexWrapper.P = _EditedParticle; + _ui.texIndexWidget->setWorkspaceNode(_Node); + _ui.texIndexWidget->updateUi(); + } + else + { + _TextureWrapper.P = _EditedParticle; + _TextureWrapper.OwnerNode = _Node; + + _ui.texWidget->updateUi(); + } + _ui.texWidget->setVisible(!state); + _ui.texIndexWidget->setVisible(state); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_texture_anim_widget.h b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_anim_widget.h new file mode 100644 index 000000000..cf8cfe693 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_anim_widget.h @@ -0,0 +1,93 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_TEXTURE_ANIM_WIDGET_H +#define PARTICLE_TEXTURE_ANIM_WIDGET_H + +#include "ui_particle_texture_anim_form.h" + +// STL includes + +// Qt includes + +// NeL includes +#include "nel/3d/ps_particle.h" + +// Project includes +#include "ps_wrapper.h" + +namespace NL3D +{ + class CPSTexturedParticle; + class CPSMultiTexturedParticle; +} + +namespace NLQT { + +class CParticleTextureAnimWidget: public QWidget +{ + Q_OBJECT + +public: + CParticleTextureAnimWidget(QWidget *parent = 0); + ~CParticleTextureAnimWidget(); + + void setCurrentTextureAnim(NL3D::CPSTexturedParticle *tp, NL3D::CPSMultiTexturedParticle *mtp,CWorkspaceNode *ownerNode); + +private Q_SLOTS: + void chooseGroupedTexture(); + void setEnabledTexAnim(bool state); + void setMultitexturing(bool enabled); + void editMultitexturing(); + +private: + void updateTexAnimState(bool state); + + /// Wrapper for single texture + struct CTextureWrapper : public IPSWrapperTexture + { + NL3D::CPSTexturedParticle *P; + NL3D::ITexture *get(void) { return P->getTexture(); } + void set(NL3D::ITexture *t) { P->setTexture(t); } + } _TextureWrapper; + + /// Wrapper for texture anim sequence + struct CTextureIndexWrapper : public IPSWrapper, IPSSchemeWrapper + { + NL3D::CPSTexturedParticle *P; + sint32 get(void) const { return P->getTextureIndex(); } + void set(const sint32 &v) { P->setTextureIndex(v); } + scheme_type *getScheme(void) const { return P->getTextureIndexScheme(); } + void setScheme(scheme_type *s) { P->setTextureIndexScheme(s); } + } _TextureIndexWrapper; + + void updateModifiedFlag() { if (_Node) _Node->setModified(true); } + + NL3D::CPSTexturedParticle *_EditedParticle; + + NL3D::CPSMultiTexturedParticle *_MTP; + + CWorkspaceNode *_Node; + + Ui::CParticleTextureAnimWidget _ui; +}; /* class CParticleTextureAnimWidget */ + +} /* namespace NLQT */ + +#endif // PARTICLE_TEXTURE_ANIM_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_texture_form.ui b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_form.ui new file mode 100644 index 000000000..76a89ec9b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_form.ui @@ -0,0 +1,107 @@ + + + CParticleTextureWidget + + + + 0 + 0 + 191 + 176 + + + + Form + + + + + + + 105 + 105 + + + + + 100 + 100 + + + + true + + + + + 0 + 0 + 103 + 103 + + + + + + + + 85 + 85 + + + + + + + + + + + + + + + + 0 + 0 + + + + Choose texture + + + + + + + + 0 + 0 + + + + Remove + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 7 + 20 + + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_texture_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_widget.cpp new file mode 100644 index 000000000..1f40900f2 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_widget.cpp @@ -0,0 +1,126 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_texture_widget.h" + +// Qt include +#include +#include + +// NeL includes +#include "nel/3d/texture_file.h" +#include "nel/3d/texture_bump.h" +#include "nel/3d/ps_particle_basic.h" +#include "nel/misc/path.h" + +namespace NLQT { + +CParticleTextureWidget::CParticleTextureWidget(QWidget *parent) + : QWidget(parent), _Wrapper(NULL) +{ + _ui.setupUi(this); + + _ui.imageLabel->setScaledContents(true); + _ui.removePushButton->setVisible(false); + + connect(_ui.chooseTexPushButton, SIGNAL(clicked()), this, SLOT(chooseTexture())); + connect(_ui.removePushButton, SIGNAL(clicked()), this, SLOT(removeTexture())); +} + +CParticleTextureWidget::~CParticleTextureWidget() +{ +} + +void CParticleTextureWidget::updateUi() +{ + nlassert(_Wrapper); + + _Texture = _Wrapper->get(); + + updateTexture(); +} + +void CParticleTextureWidget::chooseTexture() +{ + std::string texName; + /// get the name of the previously set texture if there is one + if (dynamic_cast(_Wrapper->get())) + { + if (!texName.empty()) + texName = NLMISC::CPath::lookup((static_cast(_Wrapper->get()))->getFileName()); + } + + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open texture file"), texName.c_str(), + tr("Image file (*.tga *.png)")); + + setCursor(Qt::WaitCursor); + if (!fileName.isEmpty()) + { + // Add search path for the texture + NLMISC::CPath::addSearchPath(NLMISC::CFile::getPath(fileName.toStdString())); + try + { + texName = NLMISC::CFile::getFilename(fileName.toStdString()); + NL3D::CTextureFile *tf = new NL3D::CTextureFile(texName); + _Wrapper->setAndUpdateModifiedFlag(tf); + _Texture = tf; + Q_EMIT textureChanged(QString(texName.c_str())); + updateTexture(); + } + catch (NLMISC::Exception &e) + { + QMessageBox::critical(this, tr("Texture loading error"), e.what(), QMessageBox::Ok); + } + + } + setCursor(Qt::ArrowCursor); +} + +void CParticleTextureWidget::removeTexture() +{ + if (_Texture) + { + _Texture->release(); + _Texture = NULL; + } + _Wrapper->setAndUpdateModifiedFlag(NULL); + Q_EMIT textureChanged(""); + updateTexture(); +} + +void CParticleTextureWidget::updateTexture() +{ + if (!_Texture) + { + _ui.imageLabel->setPixmap(QPixmap()); + return; + } + if (dynamic_cast(_Wrapper->get())) + { + std::string texName = (static_cast(_Wrapper->get()))->getFileName().c_str(); + if (!NLMISC::CFile::getFilename(texName).empty()) + _ui.imageLabel->setPixmap(QPixmap(NLMISC::CPath::lookup(texName).c_str())); + else + _ui.imageLabel->setPixmap(QPixmap()); + } +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_texture_widget.h b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_widget.h new file mode 100644 index 000000000..f1950a46f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_widget.h @@ -0,0 +1,74 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_TEXTURE_WIDGET_H +#define PARTICLE_TEXTURE_WIDGET_H + +#include "ui_particle_texture_form.h" + +// STL includes + +// Qt includes + +// NeL includes +#include +#include +#include + +// Project includes +#include "ps_wrapper.h" + +namespace NLQT { + +class CParticleTextureWidget: public QWidget +{ + Q_OBJECT + +public: + CParticleTextureWidget(QWidget *parent = 0); + ~CParticleTextureWidget(); + + void updateUi(); + + // set a wrapper to get the datas, called before setCurrentTextureNoAnim + void setWrapper(IPSWrapperTexture *wrapper) { _Wrapper = wrapper ; } + + void enableRemoveButton(bool enabled) { _ui.removePushButton->setVisible(enabled); } + +Q_SIGNALS: + void textureChanged(const QString &texName); + +private Q_SLOTS: + void chooseTexture(); + void removeTexture(); + +private: + void updateTexture(); + + IPSWrapperTexture *_Wrapper ; + + // the current texture + NLMISC::CSmartPtr _Texture ; + + Ui::CParticleTextureWidget _ui; +}; /* class CParticleTextureWidget */ + +} /* namespace NLQT */ + +#endif // PARTICLE_TEXTURE_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_tree_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_tree_model.cpp new file mode 100644 index 000000000..b12d03624 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_tree_model.cpp @@ -0,0 +1,537 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_tree_model.h" + +// Qt includes + +// NeL includes +#include "nel/3d/particle_system.h" + +// Project includes +#include "modules.h" + +namespace NLQT { + +CParticleTreeItem::CParticleTreeItem(const QList &data, const int typeItem, CParticleTreeItem *parent): + _itemData(data), _itemIconType(typeItem), _parentItem(parent) +{ + +} + +CParticleTreeItem::CParticleTreeItem(CParticleWorkspace *ws, const QList &data, const int typeItem, CParticleTreeItem *parent): + _itemData(data), _itemIconType(typeItem), _parentItem(parent) +{ + nlassert(ws); + _WS = ws; +} + +CParticleTreeItem::CParticleTreeItem(NL3D::CPSLocated *loc, const QList &data, const int typeItem, CParticleTreeItem *parent): + _itemData(data), _itemIconType(typeItem), _parentItem(parent) +{ + nlassert(loc); + _Loc = loc; +} + +CParticleTreeItem::CParticleTreeItem(NL3D::CPSLocated *loc, uint32 index, const QList &data, const int typeItem, CParticleTreeItem *parent): + _itemData(data), _itemIconType(typeItem), _parentItem(parent) +{ + nlassert(loc); + _Loc = loc; + _LocatedInstanceIndex = index; +} + +CParticleTreeItem::CParticleTreeItem(CWorkspaceNode *node, const QList &data, const int typeItem, CParticleTreeItem *parent): + _itemData(data), _itemIconType(typeItem), _parentItem(parent) +{ + _PS = node; +} + +CParticleTreeItem::CParticleTreeItem(NL3D::CPSLocatedBindable *lb, const QList &data, const int typeItem, CParticleTreeItem *parent): + _itemData(data), _itemIconType(typeItem), _parentItem(parent) +{ + _Bind = lb; +} + +CParticleTreeItem::~CParticleTreeItem() +{ + qDeleteAll(_childItems); +} + +void CParticleTreeItem::appendChild(CParticleTreeItem *child) +{ + _childItems.append(child); +} + +CParticleTreeItem *CParticleTreeItem::child(int row) +{ + return _childItems.value(row); +} + +int CParticleTreeItem::childCount() const +{ + return _childItems.count(); +} + +int CParticleTreeItem::columnCount() const +{ + return _itemData.count(); +} + +int CParticleTreeItem::itemType() const +{ + return _itemIconType; +} + +QVariant CParticleTreeItem::data(int column) const +{ + return _itemData.value(column); +} + +CParticleTreeItem *CParticleTreeItem::parent() +{ + return _parentItem; +} + +int CParticleTreeItem::row() const +{ + if (_parentItem) + return _parentItem->_childItems.indexOf(const_cast(this)); + return 0; +} + +bool CParticleTreeItem::replace(const QList &data) +{ + _itemData = data; + return true; +} + +bool CParticleTreeItem::deleteChild(int row) +{ + _childItems.removeAt(row); + return true; +} + +CParticleWorkspace *CParticleTreeItem::getPW() const +{ + return _WS; +} + +NL3D::CPSLocated *CParticleTreeItem::getLoc() const +{ + return _Loc; +} + +NL3D::CPSLocatedBindable *CParticleTreeItem::getBind() const +{ + return _Bind; +} + +CWorkspaceNode *CParticleTreeItem::getNode() const +{ + return _PS; +} + +uint32 CParticleTreeItem::getLocatedInstanceIndex() const +{ + return _LocatedInstanceIndex; +} + +void CParticleTreeItem::setLocatedInstanceIndex(uint32 index) +{ + _LocatedInstanceIndex = index; +} + +CParticleTreeModel::CParticleTreeModel(QObject *parent) + : QAbstractItemModel(parent) +{ + QList rootData; + rootData << "Name"; + _rootItem = new CParticleTreeItem(rootData, ItemType::Root); +} + +CParticleTreeModel::~CParticleTreeModel() +{ + delete _rootItem; +} + +int CParticleTreeModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return static_cast(parent.internalPointer())->columnCount(); + else + return _rootItem->columnCount(); +} + +QVariant CParticleTreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role == Qt::DisplayRole) + { + CParticleTreeItem *item = static_cast(index.internalPointer()); + if (item->itemType() == ItemType::ParticleSystem) + { + if (item->getNode()->isModified()) + return "*" + item->data(index.column()).toString(); + } + if (item->itemType() == ItemType::Workspace) + { + if (item->getPW()->isModified()) + return "*" + item->data(index.column()).toString(); + } + return item->data(index.column()); + } + if (role == Qt::FontRole) + { + CParticleTreeItem *item = static_cast(index.internalPointer()); + if (Modules::psEdit().getActiveNode() != NULL) + { + if (item->data(0) == QString(Modules::psEdit().getActiveNode()->getFilename().c_str())) + return QFont("SansSerif", 9, QFont::Bold); + } + return QFont("SansSerif", 9, QFont::Normal); + } + if (role == Qt::DecorationRole) + return qVariantFromValue(getIcon(index)); + + return QVariant(); +} + +Qt::ItemFlags CParticleTreeModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags itmFlags = Qt::NoItemFlags; + + if (!index.isValid()) + return itmFlags; + + CParticleTreeItem *item = static_cast(index.internalPointer()); + switch (item->itemType()) + { + case ItemType::Particle: + case ItemType::Emitter: + case ItemType::Force: + case ItemType::Light: + case ItemType::Sound: + case ItemType::Located: + case ItemType::CollisionZone: + itmFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; + break; + case ItemType::LocatedInstance: + if (Modules::psEdit().isRunning()) + itmFlags = Qt::NoItemFlags; + else + itmFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + break; + default: + itmFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + break; + } + + //CParticleWorkspaceDialog *pwsd = qobject_cast(QObject::parent()); + //pwsd->updateTreeView(); + + return itmFlags; +} + +QVariant CParticleTreeModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return _rootItem->data(section); + + return QVariant(); +} + +QModelIndex CParticleTreeModel::index(int row, int column, const QModelIndex &parent) + const +{ + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + CParticleTreeItem *parentItem; + + if (!parent.isValid()) + parentItem = _rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + CParticleTreeItem *childItem = parentItem->child(row); + if (childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} + +QModelIndex CParticleTreeModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + CParticleTreeItem *childItem = static_cast(index.internalPointer()); + CParticleTreeItem *parentItem = childItem->parent(); + + if (parentItem == _rootItem) + return QModelIndex(); + + return createIndex(parentItem->row(), 0, parentItem); +} + +int CParticleTreeModel::rowCount(const QModelIndex &parent) const +{ + CParticleTreeItem *parentItem; + if (parent.column() > 0) + return 0; + + if (!parent.isValid()) + parentItem = _rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + return parentItem->childCount(); +} + +bool CParticleTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid() && role == Qt::EditRole) + { + CParticleTreeItem *item = static_cast(index.internalPointer()); + QList listData; + listData << value; + item->replace(listData); + std::string name = value.toString().toStdString(); + if (item->itemType() == ItemType::Located) + item->getLoc()->setName(name); + else + item->getBind()->setName(name); + Q_EMIT dataChanged(index, index); + return true; + } + return false; +} + +QIcon CParticleTreeModel::getIcon(const QModelIndex &index) const +{ + CParticleTreeItem *item = static_cast(index.internalPointer()); + switch (item->itemType()) + { + case ItemType::Root: + break; + case ItemType::Workspace: + return QIcon(":/images/Workspace.bmp"); + case ItemType::ParticleSystem: + return QIcon(":/images/ParticleSystem.bmp"); + case ItemType::Particle: + return QIcon(":/images/Particle.bmp"); + case ItemType::Emitter: + return QIcon(":/images/Emitter.bmp"); + case ItemType::Force: + return QIcon(":/images/Force.bmp"); + case ItemType::Light: + return QIcon(":/images/Light.bmp"); + case ItemType::Sound: + return QIcon(":/images/Sound.bmp"); + case ItemType::Located: + return QIcon(":/images/Located.bmp"); + case ItemType::CollisionZone: + return QIcon(":/images/CollisionZone.bmp"); + case ItemType::LocatedInstance: + return QIcon(":/images/LocatedInstance.bmp"); + case ItemType::ParticleSystemNotLoaded: + return QIcon(":/images/ParticleSystemNotLoaded.bmp"); + } + return QIcon(); +} + +bool CParticleTreeModel::insertRows(CWorkspaceNode *node, int position, const QModelIndex &parent) +{ + CParticleTreeItem *item = static_cast(parent.internalPointer()); + + beginInsertRows(parent, position, position); + setupModelFromPS(node, item); + endInsertRows(); + + if (node->isLoaded()) + { + QModelIndex indexPS = index(item->childCount() - 1, 0, parent); + for (uint k = 0; k < node->getPSPointer()->getNbProcess(); k++) + { + NL3D::CPSLocated *loc = dynamic_cast(node->getPSPointer()->getProcess(k)); + insertRows(loc, k, indexPS); + } + } + return true; +} + +bool CParticleTreeModel::insertRows(NL3D::CPSLocated *loc, int position, const QModelIndex &parent) +{ + CParticleTreeItem *item = static_cast(parent.internalPointer()); + + beginInsertRows(parent, position, position); + createItemFromLocated(loc, item); + endInsertRows(); + + QModelIndex indexLocated = index(item->childCount() - 1, 0, parent); + for (uint l = 0; l < loc->getNbBoundObjects(); ++l) + insertRow(loc->getBoundObject(l), l, indexLocated); + + for (uint k = 0; k < loc->getSize(); ++k) + insertRow(loc, k, k + loc->getNbBoundObjects(), indexLocated); + + return true; +} + +bool CParticleTreeModel::insertRow(NL3D::CPSLocated *loc, uint32 index, int position, const QModelIndex &parent) +{ + beginInsertRows(parent, position, position); + createItemFromLocatedInstance(loc, index, static_cast(parent.internalPointer())); + endInsertRows(); + return true; +} + +bool CParticleTreeModel::insertRow(NL3D::CPSLocatedBindable *lb, int position, const QModelIndex &parent) +{ + beginInsertRows(parent, position, position); + createItemFromLocatedBindable(lb, static_cast(parent.internalPointer())); + endInsertRows(); + return true; +} + +bool CParticleTreeModel::removeRows(int position, const QModelIndex &parent) +{ + CParticleTreeItem *item = static_cast(parent.internalPointer())->child(position); + while (item->childCount() != 0) + removeRows(0, parent.child(position, 0)); + + beginRemoveRows(parent, position, position); + static_cast(parent.internalPointer())->deleteChild(position); + endRemoveRows(); + return false; +} + +CWorkspaceNode *CParticleTreeModel::getOwnerNode(CParticleTreeItem *item) const +{ + CWorkspaceNode *node = NULL; + switch (item->itemType()) + { + case ItemType::ParticleSystem: + node = item->getNode(); + break; + case ItemType::Located: + node = item->parent()->getNode(); + break; + case ItemType::LocatedInstance: + case ItemType::Particle: + case ItemType::Emitter: + case ItemType::Force: + case ItemType::Light: + case ItemType::Sound: + case ItemType::CollisionZone: + node = item->parent()->parent()->getNode(); + break; + } + return node; +} + +void CParticleTreeModel::rebuildLocatedInstance(const QModelIndex &parent) +{ + CParticleTreeItem *item = static_cast(parent.internalPointer()); + int k = 0; + for (int i = 0; i < item->childCount(); i++) + { + if (item->child(i)->itemType() == ItemType::LocatedInstance) + { + item->child(i)->setLocatedInstanceIndex(k); + k++; + } + } +} + +void CParticleTreeModel::setupModelFromWorkSpace() +{ + beginResetModel(); + delete _rootItem; + + QList rootData; + rootData << "Name"; + _rootItem = new CParticleTreeItem(rootData, ItemType::Root); + + QList workspaceData; + CParticleWorkspace *workspace = Modules::psEdit().getParticleWorkspace(); + + if (workspace == NULL) + { + endResetModel(); + return; + } + + workspaceData << workspace->getFilename().c_str(); + CParticleTreeItem *parent = new CParticleTreeItem(workspace ,workspaceData, ItemType::Workspace, _rootItem); + _rootItem->appendChild(parent); + endResetModel(); + + QModelIndex rootIndex = index(0, 0); + uint numNode = workspace->getNumNode(); + for (uint i = 0; i < numNode; i++) + insertRows(workspace->getNode(i), i, rootIndex); +} + +void CParticleTreeModel::setupModelFromPS(CWorkspaceNode *node, CParticleTreeItem *parent) +{ + QList particleSystemData; + particleSystemData << node->getFilename().c_str(); + CParticleTreeItem *child; + if (node->isLoaded()) + { + child = new CParticleTreeItem(node, particleSystemData, ItemType::ParticleSystem, parent); + parent->appendChild(child); + } + else + { + child = new CParticleTreeItem(node, particleSystemData, ItemType::ParticleSystemNotLoaded, parent); + parent->appendChild(child); + } +} + +void CParticleTreeModel::createItemFromLocated(NL3D::CPSLocated *loc, CParticleTreeItem *parent) +{ + QList locatedData; + locatedData << QString(loc->getName().c_str()); + CParticleTreeItem *child = new CParticleTreeItem(loc, locatedData, ItemType::Located, parent); + parent->appendChild(child); +} + +void CParticleTreeModel::createItemFromLocatedInstance(NL3D::CPSLocated *loc, uint32 index, CParticleTreeItem *parent) +{ + QList locatedData; + locatedData << QString("instance"); + CParticleTreeItem *child = new CParticleTreeItem(loc, index, locatedData, ItemType::LocatedInstance, parent); + parent->appendChild(child); +} + +void CParticleTreeModel::createItemFromLocatedBindable(NL3D::CPSLocatedBindable *lb, CParticleTreeItem *parent) +{ + QList forceData; + forceData << lb->getName().c_str(); + parent->appendChild(new CParticleTreeItem(lb, forceData, lb->getType(), parent)); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_tree_model.h b/code/nel/tools/3d/object_viewer_qt/src/particle_tree_model.h new file mode 100644 index 000000000..ae8d82984 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_tree_model.h @@ -0,0 +1,184 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_TREE_MODEL_H +#define PARTICLE_TREE_MODEL_H + +// Qt includes +#include +#include +#include +#include +#include + +// NeL includes +#include "nel/misc/types_nl.h" +#include "nel/3d/ps_located.h" + +// Projects includes +#include "particle_node.h" + +namespace NLQT { + +struct ItemType +{ + enum List + { + Force = 0, + Particle, + Emitter, + Light, + CollisionZone, + Sound, + Root, + Workspace, + ParticleSystem, + Located, + LocatedInstance, + ParticleSystemNotLoaded + }; +}; + +/** +@class CParticleTreeItem +@brief Basic elements tree model particles workspace. +Сontains pointer to items particle workspace and type icons. +*/ +class CParticleTreeItem +{ +public: + CParticleTreeItem(const QList &data, const int typeItem, CParticleTreeItem *parent = 0); + + CParticleTreeItem(CParticleWorkspace *ws, const QList &data, const int typeItem, CParticleTreeItem *parent ); + + CParticleTreeItem(NL3D::CPSLocated *loc, const QList &data, const int typeItem, CParticleTreeItem *parent); + + CParticleTreeItem(NL3D::CPSLocated *loc, uint32 index, const QList &data, const int typeItem, CParticleTreeItem *parent); + + CParticleTreeItem(CWorkspaceNode *node, const QList &data, const int typeItem, CParticleTreeItem *parent); + + CParticleTreeItem(NL3D::CPSLocatedBindable *lb, const QList &data, const int typeItem, CParticleTreeItem *parent); + + ~CParticleTreeItem(); + + void appendChild(CParticleTreeItem *child); + + CParticleTreeItem *child(int row); + int childCount() const; + int columnCount() const; + int itemType() const; + QVariant data(int column) const; + int row() const; + CParticleTreeItem *parent(); + bool replace(const QList &data); + bool deleteChild(int row); + CParticleWorkspace *getPW() const; + NL3D::CPSLocated *getLoc() const; + NL3D::CPSLocatedBindable *getBind() const; + CWorkspaceNode *getNode() const; + uint32 getLocatedInstanceIndex() const; + void setLocatedInstanceIndex(uint32 index); + +private: + union + { + CParticleWorkspace *_WS; + NL3D::CPSLocated *_Loc; + NL3D::CPSLocatedBindable *_Bind; + CWorkspaceNode *_PS; + }; + + // for the located instance type, this is the index of the instance + uint32 _LocatedInstanceIndex; + + QList _childItems; + QList _itemData; + int _itemIconType; + CParticleTreeItem *_parentItem; +}; + +/** +@class CParticleTreeModel +@brief Tree model particles workspace. +*/ +class CParticleTreeModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + CParticleTreeModel(QObject *parent = 0); + ~CParticleTreeModel(); + + QVariant data(const QModelIndex &index, int role) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + QIcon getIcon(const QModelIndex &index) const; + + /// Insert WorkspaceNode in model and add all its sub-item. + bool insertRows(CWorkspaceNode *node, int position, const QModelIndex &parent = QModelIndex()); + + /// Insert Located item in model and add all its sub-item. + bool insertRows(NL3D::CPSLocated *loc, int position, const QModelIndex &parent = QModelIndex()); + + /// Insert Located item in model. + bool insertRow(NL3D::CPSLocated *loc, uint32 index, int position, const QModelIndex &parent = QModelIndex()); + + /// Insert LocatedBindable item in model. + bool insertRow(NL3D::CPSLocatedBindable *lb, int position, const QModelIndex &parent = QModelIndex()); + + /// Deletes a tree item and all its children. + bool removeRows(int position, const QModelIndex &parent = QModelIndex()); + + /// Get the parent node in the workspace for the given element in the tree + CWorkspaceNode *getOwnerNode(CParticleTreeItem *item) const; + + /// Rebuild the located instance in the tree (after loading for example) + void rebuildLocatedInstance(const QModelIndex &parent); + + /// Build the whole tree from a workspace + void setupModelFromWorkSpace(); + +private: + /// Build a portion of the tree using the given particle system + void setupModelFromPS(CWorkspaceNode *node, CParticleTreeItem *parent); + + /// Add item from the given located + void createItemFromLocated(NL3D::CPSLocated *loc, CParticleTreeItem *parent); + + /// Add item from the given located instance + void createItemFromLocatedInstance(NL3D::CPSLocated *loc, uint32 index, CParticleTreeItem *parent); + + /// Add item from the given located bindable + void createItemFromLocatedBindable(NL3D::CPSLocatedBindable *lb, CParticleTreeItem *parent); + + CParticleTreeItem *_rootItem; +}; + +} /* namespace NLQT */ + +#endif // PARTICLE_TREE_MODEL_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_dialog.cpp new file mode 100644 index 000000000..ed5135852 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_dialog.cpp @@ -0,0 +1,776 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_workspace_dialog.h" + +// NeL includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Qt includes +#include +#include +#include +#include + +// Project includes +#include "dup_ps.h" +#include "modules.h" + +namespace NLQT { + +static const char * const LocatedBindable[] = { + QT_TR_NOOP("Point"), + QT_TR_NOOP("LookAt"), + QT_TR_NOOP("FanLight"), + QT_TR_NOOP("Ribbon"), + QT_TR_NOOP("TailDot"), + QT_TR_NOOP("Mesh"), + QT_TR_NOOP("ConstraintMesh"), + QT_TR_NOOP("Face"), + QT_TR_NOOP("ShockWave"), + QT_TR_NOOP("Ribbon look at"), + QT_TR_NOOP("Gravity"), + QT_TR_NOOP("Directional force"), + QT_TR_NOOP("Spring"), + QT_TR_NOOP("Flyid friction"), + QT_TR_NOOP("Central gravity"), + QT_TR_NOOP("Cylindric vortex"), + QT_TR_NOOP("Brownian move"), + QT_TR_NOOP("Magnetic force"), + QT_TR_NOOP("Plane"), + QT_TR_NOOP("Sphere"), + QT_TR_NOOP("Rectangle"), + QT_TR_NOOP("Disc"), + QT_TR_NOOP("Cylinder"), + QT_TR_NOOP("Directional"), + QT_TR_NOOP("Omni directional"), + QT_TR_NOOP("Rectangle"), + QT_TR_NOOP("Conic"), + QT_TR_NOOP("Spherical"), + QT_TR_NOOP("Radial"), + QT_TR_NOOP("Bind sound"), + QT_TR_NOOP("Bind light"), + 0 +}; + +struct Action +{ + enum List + { + ParticlePoint = 0, + ParticleLookAt, + ParticleFanLight, + ParticleRibbon, + ParticleTailDot, + ParticleMesh, + ParticleConstraintMesh, + ParticleFace, + ParticleShockWave, + ParticleRibbonLookAt, + ForceGravity, + ForceDirectional, + ForceSpring, + ForceFlyidFriction, + ForceCentralGravity, + ForceCylindricVortex, + ForceBrownianMove, + ForceMagnetic, + ZonePlane, + ZoneSphere, + ZoneRectangle, + ZoneDisc, + ZoneCylinder, + EmitterDirectional, + EmitterOmniDirectional, + EmitterRectangle, + EmitterConic, + EmitterSpherical, + EmitterRadial, + Sound, + Light + }; +}; + +// this map is used to create increasing names +static std::map _PSElementIdentifiers; + +CParticleWorkspaceDialog::CParticleWorkspaceDialog(QWidget *parent) + : QDockWidget(parent), _currentItem(NULL) +{ + _ui.setupUi(this); + + connect(_ui.treeView, SIGNAL(clicked(QModelIndex)), this, SLOT(clickedItem(QModelIndex))); + connect(_ui.treeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenu())); + + // Init tree model + _treeModel = new CParticleTreeModel(this); + _ui.treeView->setModel(_treeModel); + _ui.treeView->setContextMenuPolicy(Qt::CustomContextMenu); + + _PropertyDialog = new CPropertyDialog(_treeModel, this); + + _signalMapper = new QSignalMapper(this); + + _setActivePSAction = new QAction(tr("Set as active particle system"), this); + _savePSAction = new QAction(tr("Save"), this); + _saveAsPSAction = new QAction(tr("Save as"), this); + _clearContentAction = new QAction(tr("Clear content"), this); + _removeFromWSAction = new QAction(tr("Remove from workspace"), this); + _mergeAction = new QAction(tr("Merge"), this); + + _newLocatedAction = new QAction(tr("New located"), this); + _pasteLocatedAction = new QAction(tr("Paste located"), this); + + for(int i = 0; LocatedBindable[i]; ++i) + _bindNewLocatedBindable[i] = new QAction(tr(LocatedBindable[i]), this); + + _forceZBiasAction = new QAction(tr("Force ZBias"), this); + + _instanciateAction = new QAction(tr("Instanciate"), this); + _copyLocatedAction = new QAction(tr("Copy located"), this); + _copyBindableAction = new QAction(tr("Copy bindable"), this); + _pasteBindableAction = new QAction(tr("Paste bindable"), this); + _deleteAction = new QAction(tr("Delete"), this); + + _allLODAction = new QAction(tr("All LOD"), this); + _allLODAction->setCheckable(true); + _lod1Action = new QAction(tr("LOD 1"), this); + _lod1Action->setCheckable(true); + _lod2Action = new QAction(tr("LOD 2"), this); + _lod2Action->setCheckable(true); + _externIDAction = new QAction(tr("extern ID"), this); + + connect(_setActivePSAction, SIGNAL(triggered()), this, SLOT(setActiveNode())); + connect(_savePSAction, SIGNAL(triggered()), this, SLOT(savePS())); + connect(_saveAsPSAction, SIGNAL(triggered()), this, SLOT(saveAsPS())); + connect(_clearContentAction, SIGNAL(triggered()), this, SLOT(clearContent())); + connect(_removeFromWSAction, SIGNAL(triggered()), this, SLOT(removePS())); + connect(_mergeAction, SIGNAL(triggered()), this, SLOT(mergePS())); + connect(_newLocatedAction, SIGNAL(triggered()), this, SLOT(newLocated())); + connect(_pasteLocatedAction, SIGNAL(triggered()), this, SLOT(pasteLocated())); + + connect(_signalMapper, SIGNAL(mapped(int)), this, SLOT(bindNewLocatedBindable(int))); + for(int i = 0; LocatedBindable[i]; ++i) + { + _signalMapper->setMapping(_bindNewLocatedBindable[i], i); + connect(_bindNewLocatedBindable[i], SIGNAL(triggered()), _signalMapper, SLOT(map())); + } + + connect(_forceZBiasAction, SIGNAL(triggered()), this, SLOT(forceZBias())); + + connect(_copyLocatedAction, SIGNAL(triggered()), this, SLOT(copyLocated())); + connect(_copyBindableAction, SIGNAL(triggered()), this, SLOT(copyBindable())); + connect(_pasteBindableAction, SIGNAL(triggered()), this, SLOT(pasteBindable())); + connect(_deleteAction, SIGNAL(triggered()), this, SLOT(deleteItem())); + + connect(_instanciateAction, SIGNAL(triggered()), this, SLOT(setInstanciate())); + connect(_allLODAction, SIGNAL(triggered()), this, SLOT(setAllLOD())); + connect(_lod1Action, SIGNAL(triggered()), this, SLOT(setLOD1())); + connect(_lod2Action, SIGNAL(triggered()), this, SLOT(setLOD2())); + connect(_externIDAction, SIGNAL(triggered()), this, SLOT(setExternID())); +} + +CParticleWorkspaceDialog::~CParticleWorkspaceDialog() +{ +} + +void CParticleWorkspaceDialog::touchPSState(CParticleTreeItem *item) +{ + if (item == NULL) return; + CWorkspaceNode *ownerNode = _treeModel->getOwnerNode(item); + if (ownerNode && ownerNode->getPSModel()) + { + ownerNode->getPSModel()->touchLightableState(); + ownerNode->getPSModel()->touchTransparencyState(); + } +} + +void CParticleWorkspaceDialog::clickedItem(const QModelIndex & index) +{ + if (_currentItem != NULL) + _treeModel->getOwnerNode(_currentItem)->getPSPointer()->setCurrentEditedElement(NULL); + + _currentItem = static_cast(index.internalPointer()); + + if (index.flags() != Qt::NoItemFlags) + _PropertyDialog->setCurrentEditedElement(_currentItem); + + if ((_currentItem->itemType() == ItemType::Workspace) || + (_currentItem->itemType() == ItemType::ParticleSystemNotLoaded)) + _currentItem = NULL; +} + +void CParticleWorkspaceDialog::customContextMenu() +{ + if (!Modules::psEdit().getParticleWorkspace()) return; + clickedItem(_ui.treeView->currentIndex()); + if (_currentItem == NULL) return; + QMenu *popurMenu = new QMenu(this); + switch (_currentItem->itemType()) + { + case ItemType::ParticleSystem: + popurMenu->addAction(_setActivePSAction); + popurMenu->addAction(_savePSAction); + popurMenu->addAction(_saveAsPSAction); + popurMenu->addAction(_clearContentAction); + popurMenu->addAction(_removeFromWSAction); + popurMenu->addAction(_mergeAction); + popurMenu->addSeparator(); + popurMenu->addAction(_newLocatedAction); + popurMenu->addAction(_pasteLocatedAction); + popurMenu->addSeparator(); + buildMenu(popurMenu); + popurMenu->addSeparator(); + popurMenu->addAction(_forceZBiasAction); + break; + case ItemType::Located: + popurMenu->addAction(_instanciateAction); + popurMenu->addSeparator(); + buildMenu(popurMenu); + popurMenu->addSeparator(); + popurMenu->addAction(_copyLocatedAction); + popurMenu->addAction(_pasteBindableAction); + popurMenu->addAction(_deleteAction); + break; + case ItemType::Force: + case ItemType::Particle: + case ItemType::Emitter: + case ItemType::Light: + case ItemType::CollisionZone: + case ItemType::Sound: + popurMenu->addAction(_copyBindableAction); + popurMenu->addAction(_deleteAction); + popurMenu->addSeparator(); + popurMenu->addAction(_allLODAction); + popurMenu->addAction(_lod1Action); + popurMenu->addAction(_lod2Action); + popurMenu->addSeparator(); + popurMenu->addAction(_externIDAction); + + // check the menu to tell which lod is used for this located bindable + if (_currentItem->getBind()->getLOD() == NL3D::PSLod1n2) _allLODAction->setChecked(true); + else _allLODAction->setChecked(false); + if (_currentItem->getBind()->getLOD() == NL3D::PSLod1) _lod1Action->setChecked(true); + else _lod1Action->setChecked(false); + if (_currentItem->getBind()->getLOD() == NL3D::PSLod2) _lod2Action->setChecked(true); + else _lod2Action->setChecked(false); + break; + case ItemType::LocatedInstance: + popurMenu->addAction(_deleteAction); + break; + } + + bool stopped = Modules::psEdit().getState() == CParticleEditor::State::Stopped ? true : false; + _copyLocatedAction->setEnabled(stopped); + _copyBindableAction->setEnabled(stopped); + _pasteLocatedAction->setEnabled(stopped); + _instanciateAction->setEnabled(stopped); + _savePSAction->setEnabled(stopped); + _saveAsPSAction->setEnabled(stopped); + + popurMenu->exec(QCursor::pos()); + delete popurMenu; +} + +void CParticleWorkspaceDialog::setActiveNode() +{ + QModelIndex index = _ui.treeView->currentIndex(); + CParticleTreeItem *item = static_cast(index.internalPointer()); + nlassert(item->getNode()); + Modules::psEdit().setActiveNode(item->getNode()); + Q_EMIT changeActiveNode(); +} + +void CParticleWorkspaceDialog::savePS() +{ + _currentItem->getNode()->savePS(); + _currentItem->getNode()->setModified(false); +} + +void CParticleWorkspaceDialog::saveAsPS() +{ + CWorkspaceNode *node = _treeModel->getOwnerNode(_currentItem); + //if (nt->PS->getResetAutoCountFlag() && nt->PS->getPSPointer()->getAutoCountFlag()) + if (node->getPSPointer()->getAutoCountFlag()) + { + QMessageBox::critical(this, tr("NeL particle system editor"), + QString(node->getFilename().c_str()) + tr(" uses auto count feature, and it has been modified. " + "You should run the system entirely at least once at full detail before saving so that the editor can compute the number of particles in the system. " + "If user params are used to modify system aspect, you should run the system for extreme cases before saving. "), + QMessageBox::Ok); + } + else + { + Modules::psEdit().stop(); + + QString fileName = QFileDialog::getSaveFileName(this, tr("Save as ps file"), + ".", + tr("ps files (*.ps)")); + // after check + if (!fileName.isEmpty()) + node->savePSAs(fileName.toStdString()); + } +} + +void CParticleWorkspaceDialog::clearContent() +{ + int ret = QMessageBox::question(this, tr("NeL particle system editor"), + tr("Clear content ?"), QMessageBox::Yes | QMessageBox::No); + + if (ret == QMessageBox::Yes) + { + CWorkspaceNode *node = _treeModel->getOwnerNode(_currentItem); + nlassert(node); + node->setResetAutoCountFlag(false); + while (_currentItem->childCount() != 0) + _treeModel->removeRows(0, _ui.treeView->currentIndex()); + node->createEmptyPS(); + node->setModified(true); + } +} + +void CParticleWorkspaceDialog::removePS() +{ + if (_treeModel->getOwnerNode(_currentItem) == Modules::psEdit().getActiveNode()) + Modules::psEdit().setActiveNode(NULL); + + QModelIndex index = _ui.treeView->currentIndex(); + _ui.treeView->setCurrentIndex(index.parent()); + clickedItem(index.parent()); + Modules::psEdit().getParticleWorkspace()->removeNode(static_cast(index.internalPointer())->getNode()); + _treeModel->removeRows(index.row(), index.parent()); +} + +void CParticleWorkspaceDialog::mergePS() +{ +} + +void CParticleWorkspaceDialog::newLocated() +{ + _treeModel->getOwnerNode(_currentItem)->setModified(true); + createLocated(_treeModel->getOwnerNode(_currentItem)->getPSPointer()); +} + +void CParticleWorkspaceDialog::pasteLocated() +{ + nlassert(_currentItem->getNode()); + _treeModel->getOwnerNode(_currentItem)->setModified(true); + + Modules::psEdit().resetAutoCount(_treeModel->getOwnerNode(_currentItem)); + + NL3D::CPSLocated *copy = dynamic_cast(::DupPSLocated(_LocatedCopy.get())); + if (!copy) return; + if (_currentItem->getNode()->getPSPointer()->attach(copy)) + _treeModel->insertRows(copy, _currentItem->childCount(), _ui.treeView->currentIndex()); + else + { + delete copy; + QMessageBox::critical(this, tr("NeL particle system editor"), + tr("Can't perform operation : the system is flagged with 'No max nb steps' or uses the preset 'Spell FX', " + "and thus, should have a finite duration. Please remove that flag first."), + QMessageBox::Ok); + } +} + +void CParticleWorkspaceDialog::bindNewLocatedBindable(int id) +{ + NL3D::CPSLocatedBindable *toCreate = NULL; + switch (id) + { + case Action::ParticlePoint: + toCreate = new NL3D::CPSDot; + break; + case Action::ParticleLookAt: + toCreate = new NL3D::CPSFaceLookAt; + break; + case Action::ParticleFanLight: + toCreate = new NL3D::CPSFanLight; + break; + case Action::ParticleRibbon: + toCreate = new NL3D::CPSRibbon; + break; + case Action::ParticleTailDot: + toCreate = new NL3D::CPSTailDot; + break; + case Action::ParticleMesh: + toCreate = new NL3D::CPSMesh; + break; + case Action::ParticleConstraintMesh: + toCreate = new NL3D::CPSConstraintMesh; + break; + case Action::ParticleFace: + toCreate = new NL3D::CPSFace; + break; + case Action::ParticleShockWave: + toCreate = new NL3D::CPSShockWave; + break; + case Action::ParticleRibbonLookAt: + toCreate = new NL3D::CPSRibbonLookAt; + break; + case Action::ForceGravity: + toCreate = new NL3D::CPSGravity; + break; + case Action::ForceDirectional: + toCreate = new NL3D::CPSDirectionnalForce; + break; + case Action::ForceSpring: + toCreate = new NL3D::CPSSpring; + break; + case Action::ForceFlyidFriction: + toCreate = new NL3D::CPSFluidFriction; + break; + case Action::ForceCentralGravity: + toCreate = new NL3D::CPSCentralGravity; + break; + case Action::ForceCylindricVortex: + toCreate = new NL3D::CPSCylindricVortex; + break; + case Action::ForceBrownianMove: + toCreate = new NL3D::CPSBrownianForce; + break; + case Action::ForceMagnetic: + toCreate = new NL3D::CPSMagneticForce; + break; + case Action::ZonePlane: + toCreate = new NL3D::CPSZonePlane; + break; + case Action::ZoneSphere: + toCreate = new NL3D::CPSZoneSphere; + break; + case Action::ZoneRectangle: + toCreate = new NL3D::CPSZoneRectangle; + break; + case Action::ZoneDisc: + toCreate = new NL3D::CPSZoneDisc; + break; + case Action::ZoneCylinder: + toCreate = new NL3D::CPSZoneCylinder; + break; + case Action::EmitterDirectional: + toCreate = new NL3D::CPSEmitterDirectionnal; + break; + case Action::EmitterOmniDirectional: + toCreate = new NL3D::CPSEmitterOmni; + break; + case Action::EmitterRectangle: + toCreate = new NL3D::CPSEmitterRectangle; + break; + case Action::EmitterConic: + toCreate = new NL3D::CPSEmitterConic; + break; + case Action::EmitterSpherical: + toCreate = new NL3D::CPSSphericalEmitter; + break; + case Action::EmitterRadial: + toCreate = new NL3D::CPSRadialEmitter; + break; + case Action::Sound: + toCreate = new NL3D::CPSSound; + if (!Modules::psEdit().isRunning()) + (static_cast(toCreate))->stopSound(); + break; + case Action::Light: + toCreate = new NL3D::CPSLight; + break; + } + + _treeModel->getOwnerNode(_currentItem)->setModified(true); + + NL3D::CPSLocated *loc; + + if (_currentItem->itemType() == ItemType::ParticleSystem) + { + loc = createLocated(_treeModel->getOwnerNode(_currentItem)->getPSPointer()); + if (_treeModel->getOwnerNode(_currentItem)->getPSPointer()->getBypassMaxNumIntegrationSteps()) + { + if (toCreate->getType() == NL3D::PSParticle || toCreate->getType() == NL3D::PSEmitter) + loc->setInitialLife(1.f); + // object must have finite duration with that flag + } + } + else + loc = _currentItem->getLoc(); + + if (!loc->bind(toCreate)) + { + QMessageBox::critical(this, tr("NeL particle system editor"), + tr("The system is flagged with 'No max Nb steps', or uses the preset 'Spell FX'." + "System must have finite duration. Can't add object. To solve this, set a limited life time for the father."), + QMessageBox::Ok); + delete toCreate; + return; + } + + // complete the name + std::string name = toCreate->getName(); + if (_PSElementIdentifiers.count(name)) + { + name += (QString("%1").arg(++_PSElementIdentifiers[name])).toStdString(); + toCreate->setName(name); + } + else + { + _PSElementIdentifiers[toCreate->getName()] = 0; + toCreate->setName(name + "0"); + } + + touchPSState(_currentItem); + + Modules::psEdit().resetAutoCount(_treeModel->getOwnerNode(_currentItem)); + + // update treeView + if (_currentItem->itemType() == ItemType::ParticleSystem) + { + QModelIndex index = _treeModel->index(_currentItem->childCount() - 1, 0, _ui.treeView->currentIndex()); + _treeModel->insertRow(toCreate, 0, index); + } + else + _treeModel->insertRow(toCreate, _currentItem->childCount(), _ui.treeView->currentIndex()); +} + +void CParticleWorkspaceDialog::forceZBias() +{ + bool ok; + double d = QInputDialog::getDouble(this, tr("All object force ZBias"), tr(""), 0.0, -999999.0, 999999.0, 2, &ok); + if (!ok) return; + + nlassert(_treeModel->getOwnerNode(_currentItem)->getPSPointer()); + + _treeModel->getOwnerNode(_currentItem)->getPSPointer()->setZBias(-float(d)); + _treeModel->getOwnerNode(_currentItem)->setModified(true); +} + +void CParticleWorkspaceDialog::copyLocated() +{ + nlassert(_currentItem->getLoc()); + _LocatedCopy.reset(NLMISC::safe_cast(::DupPSLocated(_currentItem->getLoc()))); +} + +void CParticleWorkspaceDialog::copyBindable() +{ + nlassert(_currentItem->getBind()); + _LocatedBindableCopy.reset(::DupPSLocatedBindable(_currentItem->getBind())); +} + +void CParticleWorkspaceDialog::pasteBindable() +{ + nlassert(_currentItem->getLoc()); + _treeModel->getOwnerNode(_currentItem)->setModified(true); + + Modules::psEdit().resetAutoCount(_treeModel->getOwnerNode(_currentItem)); + + NL3D::CPSLocatedBindable *copy = ::DupPSLocatedBindable(_LocatedBindableCopy.get()); + if (!copy) return; + if (_currentItem->getLoc()->bind(copy)) + _treeModel->insertRow(copy, _currentItem->childCount(), _ui.treeView->currentIndex()); + else + { + delete copy; + QMessageBox::critical(this, tr("NeL particle system editor"), + tr("Can't perform operation : the system is flagged with 'No max nb steps' or uses the preset 'Spell FX', " + "and thus, should have a finite duration. Please remove that flag first."), + QMessageBox::Ok); + } +} + +void CParticleWorkspaceDialog::deleteItem() +{ + _treeModel->getOwnerNode(_currentItem)->setModified(true); + QModelIndex index = _ui.treeView->currentIndex(); + CParticleTreeItem *item = static_cast(index.internalPointer()); + CWorkspaceNode *ownerNode = _treeModel->getOwnerNode(item); + nlassert(ownerNode); + _ui.treeView->setCurrentIndex(index.parent()); + clickedItem(index.parent()); + switch(item->itemType()) + { + case ItemType::Located: + { + NL3D::CPSLocated *loc = item->getLoc(); + touchPSState(item); + ownerNode->setModified(true); + // if the system is running, we must destroy initial infos about the located, + // as they won't need to be restored when the stop button will be pressed + ownerNode->removeLocated(loc); + + Modules::psEdit().resetAutoCount(ownerNode); + + ownerNode->getPSPointer()->remove(loc); + _treeModel->removeRows(index.row(), index.parent()); + } + break; + case ItemType::LocatedInstance: + { + Modules::psEdit().resetAutoCount(ownerNode); + NL3D::CPSEmitter::setBypassEmitOnDeath(true); + item->getLoc()->deleteElement(item->getLocatedInstanceIndex()); + NL3D::CPSEmitter::setBypassEmitOnDeath(false); + _treeModel->removeRows(index.row(), index.parent()); + _treeModel->rebuildLocatedInstance(_ui.treeView->currentIndex()); + } + break; + case ItemType::Particle: + case ItemType::Emitter: + case ItemType::Force: + case ItemType::Light: + case ItemType::Sound: + case ItemType::CollisionZone: + { + NL3D::CPSLocatedBindable *lb = item->getBind(); + touchPSState(item); + // if the system is running, we must destroy initial infos + // that what saved about the located bindable, when the start button was pressed, as they won't need + // to be restored + ownerNode->removeLocatedBindable(lb); + ownerNode->setModified(true); + Modules::psEdit().resetAutoCount(ownerNode); + lb->getOwner()->remove(lb); + _treeModel->removeRows(index.row(), index.parent()); + } + break; + } +} + +void CParticleWorkspaceDialog::setInstanciate() +{ + _treeModel->getOwnerNode(_currentItem)->setModified(true); + + Modules::psEdit().resetAutoCount(_treeModel->getOwnerNode(_currentItem)); + + if (_currentItem->getLoc()->getSize() == _currentItem->getLoc()->getMaxSize()) + _currentItem->getLoc()->resize(_currentItem->getLoc()->getMaxSize() + 1); + + sint32 objIndex = _currentItem->getLoc()->newElement(NLMISC::CVector::Null, NLMISC::CVector::Null, + NULL, 0, _currentItem->getLoc()->getMatrixMode(), 0.f); + + _treeModel->insertRow(_currentItem->getLoc(), objIndex, _currentItem->childCount(), _ui.treeView->currentIndex()); +} + +void CParticleWorkspaceDialog::setAllLOD() +{ + _currentItem->getBind()->setLOD(NL3D::PSLod1n2); + _treeModel->getOwnerNode(_currentItem)->setModified(true); +} + +void CParticleWorkspaceDialog::setLOD1() +{ + _currentItem->getBind()->setLOD(NL3D::PSLod1); + _treeModel->getOwnerNode(_currentItem)->setModified(true); +} + +void CParticleWorkspaceDialog::setLOD2() +{ + _currentItem->getBind()->setLOD(NL3D::PSLod2); + _treeModel->getOwnerNode(_currentItem)->setModified(true); +} + +void CParticleWorkspaceDialog::setExternID() +{ + bool ok; + int i = QInputDialog::getInt(this, tr("Set the extern ID"), + tr("0 means no extern access."), + _currentItem->getBind()->getExternID(), 0, 9999, 1, &ok); + if (ok) + { + _currentItem->getBind()->setExternID(uint32(i)); + _treeModel->getOwnerNode(_currentItem)->setModified(true); + } +} + +void CParticleWorkspaceDialog::setNewState() +{ + if ((_currentItem != NULL) && (_currentItem->itemType() == ItemType::LocatedInstance)) + { + QModelIndex index = _ui.treeView->currentIndex(); + _ui.treeView->setCurrentIndex(_ui.treeView->currentIndex().parent()); + clickedItem(index.parent()); + } + _ui.treeView->update(); + _ui.treeView->repaint(); +} + +void CParticleWorkspaceDialog::updateTreeView() +{ + _ui.treeView->update(); + _ui.treeView->repaint(); +} + +void CParticleWorkspaceDialog::buildMenu(QMenu *menu) +{ + QMenu *bindParticleMenu = new QMenu(tr("Bind particle..."), menu); + menu->addAction(bindParticleMenu->menuAction()); + for(int i = Action::ParticlePoint; i <= Action::ParticleRibbonLookAt; ++i) + bindParticleMenu->addAction(_bindNewLocatedBindable[i]); + + QMenu *bindForceMenu = new QMenu(tr("Bind force..."), menu); + menu->addAction(bindForceMenu->menuAction()); + for(int i = Action::ForceGravity; i <= Action::ForceMagnetic; ++i) + bindForceMenu->addAction(_bindNewLocatedBindable[i]); + + QMenu *bindZoneMenu = new QMenu(tr("Bind zone..."), menu); + menu->addAction(bindZoneMenu->menuAction()); + for(int i = Action::ZonePlane; i <= Action::ZoneCylinder; ++i) + bindZoneMenu->addAction(_bindNewLocatedBindable[i]); + + QMenu *bindEmitterMenu = new QMenu(tr("Bind emitter..."), menu); + menu->addAction(bindEmitterMenu->menuAction()); + for(int i = Action::EmitterDirectional; i <= Action::EmitterRadial; ++i) + bindEmitterMenu->addAction(_bindNewLocatedBindable[i]); + + menu->addAction(_bindNewLocatedBindable[Action::Sound]); + menu->addAction(_bindNewLocatedBindable[Action::Light]); +} + +NL3D::CPSLocated *CParticleWorkspaceDialog::createLocated(NL3D::CParticleSystem *ps) +{ + // build new name + std::string name; + if (_PSElementIdentifiers.count(std::string("located"))) + name = (QString("located %1").arg(++_PSElementIdentifiers[std::string("located")])).toStdString(); + + else + { + name = std::string("located 0"); + _PSElementIdentifiers["located"] = 0; + } + NL3D::CPSLocated *loc = new NL3D::CPSLocated; + + loc->setName(name); + loc->setMatrixMode(NL3D::PSFXWorldMatrix); + ps->attach(loc); + + touchPSState(_currentItem); + + // update treeView + _treeModel->insertRows(loc, _currentItem->childCount(), _ui.treeView->currentIndex()); + + return loc; +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_dialog.h new file mode 100644 index 000000000..825f9f05b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_dialog.h @@ -0,0 +1,133 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_WORKSPACE_DIALOG_H +#define PARTICLE_WORKSPACE_DIALOG_H + +#include +#include "ui_particle_workspace_form.h" + +// Qt includes +#include + +// NeL includes +#include "nel/misc/smart_ptr.h" + +// Projects includes +#include "particle_property_dialog.h" +#include "particle_tree_model.h" +#include "particle_node.h" + +namespace NLQT { + +/** +@class ParticleWorkspaceDialog +@brief Displays particles workspace in QTreeView, build popur menu (operations with particles system sub-items). +*/ +class CParticleWorkspaceDialog: public QDockWidget +{ + Q_OBJECT +public: + CParticleWorkspaceDialog(QWidget *parent = 0); + ~CParticleWorkspaceDialog(); + + void touchPSState(CParticleTreeItem *item); + CPropertyDialog *getPropertyDialog() const { return _PropertyDialog; } + +Q_SIGNALS: + /// Emits change active particle system node. + void changeActiveNode(); + +private Q_SLOTS: + void clickedItem(const QModelIndex & index); + void customContextMenu(); + + void setActiveNode(); + void savePS(); + void saveAsPS(); + void clearContent(); + void removePS(); + void mergePS(); + + void newLocated(); + void pasteLocated(); + + void bindNewLocatedBindable(int id); + + void forceZBias(); + + void copyLocated(); + void copyBindable(); + void pasteBindable(); + void deleteItem(); + + void setInstanciate(); + void setAllLOD(); + void setLOD1(); + void setLOD2(); + + void setExternID(); + + void setNewState(); + + void updateTreeView(); + +private: + void buildMenu(QMenu *menu); + NL3D::CPSLocated *createLocated(NL3D::CParticleSystem *ps); + + CPropertyDialog *_PropertyDialog; + CParticleTreeModel *_treeModel; + + QSignalMapper *_signalMapper; + + QAction *_setActivePSAction; + QAction *_savePSAction; + QAction *_saveAsPSAction; + QAction *_clearContentAction; + QAction *_removeFromWSAction; + QAction *_mergeAction; + QAction *_newLocatedAction; + QAction *_pasteLocatedAction; + QAction *_bindNewLocatedBindable[32]; + QAction *_forceZBiasAction; + + QAction *_instanciateAction; + QAction *_copyLocatedAction; + QAction *_copyBindableAction; + QAction *_pasteBindableAction; + QAction *_deleteAction; + + QAction *_allLODAction; + QAction *_lod1Action; + QAction *_lod2Action; + QAction *_externIDAction; + + std::auto_ptr _LocatedCopy; + std::auto_ptr _LocatedBindableCopy; + + CParticleTreeItem *_currentItem; + + Ui::CParticleWorkspaceDialog _ui; + friend class CMainWindow; +}; /* class CParticleWorkspaceDialog */ + +} /* namespace NLQT */ + +#endif // PARTICLE_WORKSPACE_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_form.ui b/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_form.ui new file mode 100644 index 000000000..d44d74c31 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_form.ui @@ -0,0 +1,36 @@ + + + CParticleWorkspaceDialog + + + + 0 + 0 + 270 + 293 + + + + Tree workspace + + + + + + + true + + + false + + + false + + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_page.cpp new file mode 100644 index 000000000..211a9712f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_page.cpp @@ -0,0 +1,197 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_workspace_page.h" + +// Qt includes +#include +#include +#include + +// NeL includes + +// Project includes +#include "modules.h" + +namespace NLQT { + +CWorkspacePage::CWorkspacePage(CParticleTreeModel *treeModel, QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + _treeModel = treeModel; + + connect(_ui.newToolButton, SIGNAL(clicked()), this, SLOT(newWP())); + connect(_ui.loadToolButton, SIGNAL(clicked()), this, SLOT(loadWP())); + connect(_ui.saveToolButton, SIGNAL(clicked()), this, SLOT(saveWP())); + connect(_ui.saveAsToolButton, SIGNAL(clicked()), this, SLOT(saveAsWP())); + connect(_ui.insertToolButton, SIGNAL(clicked()), this, SLOT(insertPS())); + connect(_ui.createToolButton, SIGNAL(clicked()), this, SLOT(createPS())); + connect(_ui.resetToolButton, SIGNAL(clicked()), this, SLOT(removeAllPS())); +} + +CWorkspacePage::~CWorkspacePage() +{ +} + +void CWorkspacePage::newWP() +{ + //checkModifiedWorkSpace(); + // ask name of the new workspace to create + QString fileName = QFileDialog::getSaveFileName(this, tr("Create new pws file"), + ".", + tr("pws files (*.pws)")); + if (!fileName.isEmpty()) + { + Modules::psEdit().createNewWorkspace(fileName.toStdString()); + _treeModel->setupModelFromWorkSpace(); + _ui.saveToolButton->setEnabled(true); + _ui.saveAsToolButton->setEnabled(true); + _ui.insertToolButton->setEnabled(true); + _ui.resetToolButton->setEnabled(true); + _ui.createToolButton->setEnabled(true); + } +} + +void CWorkspacePage::loadWP() +{ + //checkModifiedWorkSpace(); + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open NeL data file"), ".", + tr("Particle Workspace file (*.pws);;")); + + setCursor(Qt::WaitCursor); + if (!fileName.isEmpty()) + { + Modules::psEdit().loadWorkspace(fileName.toStdString()); + _treeModel->setupModelFromWorkSpace(); + _ui.saveToolButton->setEnabled(true); + _ui.saveAsToolButton->setEnabled(true); + _ui.insertToolButton->setEnabled(true); + _ui.resetToolButton->setEnabled(true); + _ui.createToolButton->setEnabled(true); + } + setCursor(Qt::ArrowCursor); +} + +void CWorkspacePage::saveWP() +{ + //checkModifiedWorkSpace(); + Modules::psEdit().saveWorkspaceStructure(); + Modules::psEdit().saveWorkspaceContent(); +} + +void CWorkspacePage::saveAsWP() +{ + QString fileName = QFileDialog::getSaveFileName(this, tr("Save as pws file"), + ".", + tr("pws files (*.pws)")); + if (!fileName.isEmpty()) + { + Modules::psEdit().getParticleWorkspace()->setFileName(fileName.toStdString()); + Modules::psEdit().saveWorkspaceStructure(); + Modules::psEdit().saveWorkspaceContent(); + _treeModel->setupModelFromWorkSpace(); + } +} + +void CWorkspacePage::insertPS() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open NeL data file"), ".", + tr("Particle System file (*.ps);;")); + + if (!fileName.isEmpty()) + { + // TODO: create method particle editor insertNewPS and multiple add + CWorkspaceNode *node = Modules::psEdit().getParticleWorkspace()->addNode(NLMISC::CFile::getFilename(fileName.toStdString())); + if (node != NULL) + { + try + { + node->loadPS(); + } + catch(NLMISC::EStream &e) + { + QMessageBox::critical(this, tr("NeL particle system editor"), + QString(e.what()), + QMessageBox::Ok); + } + if (!node->isLoaded()) + Modules::psEdit().getParticleWorkspace()->removeNode(Modules::psEdit().getParticleWorkspace()->getNumNode() - 1); + else + { + QModelIndex index = _treeModel->index(0, 0); + _treeModel->insertRows(node, static_cast(index.internalPointer())->childCount(), index); + } + } + } +} + +void CWorkspacePage::createPS() +{ + QString fileName = QFileDialog::getSaveFileName(this, tr("Create new particle system file"), + ".", + tr("ps files (*.ps)")); + if (!fileName.isEmpty()) + { + + // TODO: create method particle editor createNewPS + if (Modules::psEdit().getParticleWorkspace()->containsFile(NLMISC::CFile::getFilename(fileName.toStdString()))) + { + QMessageBox::critical(this, tr("NeL particle system editor"), + tr("Failed to create new particle system"), + QMessageBox::Ok); + return; + } + CWorkspaceNode *node = Modules::psEdit().getParticleWorkspace()->addNode(NLMISC::CFile::getFilename(fileName.toStdString())); + // should always succeed because we tested if file already exists + nlassert(node); + node->createEmptyPS(); + try + { + node->savePS(); + node->setModified(false); + } + catch (NLMISC::Exception &e) + { + QMessageBox::critical(this, tr("NeL particle system editor"), + QString(e.what()), + QMessageBox::Ok); + return; + } + QModelIndex index = _treeModel->index(0, 0); + _treeModel->insertRows(node, static_cast(index.internalPointer())->childCount(), index); + } +} + +void CWorkspacePage::removeAllPS() +{ + Modules::psEdit().setActiveNode(NULL); + // TODO: create method particle editor clearParticleWorkspace + uint numNodes = Modules::psEdit().getParticleWorkspace()->getNumNode(); + for(uint k = 0; k < numNodes; ++k) + Modules::psEdit().getParticleWorkspace()->removeNode((uint) 0); + + _treeModel->setupModelFromWorkSpace(); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_page.h b/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_page.h new file mode 100644 index 000000000..29504e490 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_page.h @@ -0,0 +1,68 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_WORKSPACE_PAGE_H +#define PARTICLE_WORKSPACE_PAGE_H + +#include +#include "ui_workspace_form.h" + +// STL includes + +// NeL includes +#include + +// Project includes +#include "particle_tree_model.h" + +namespace NLQT { + +/** +@class CWorkspacePage +@brief Page for QStackWidget, to particles workspace operation (new/load/save workspace, create/insert/remove all particles system to workspace) +*/ +class CWorkspacePage: public QWidget +{ + Q_OBJECT + +public: + CWorkspacePage(CParticleTreeModel *treeModel, QWidget *parent = 0); + ~CWorkspacePage(); + +private Q_SLOTS: + void newWP(); + void loadWP(); + void saveWP(); + void saveAsWP(); + void insertPS(); + void createPS(); + void removeAllPS(); + +private: + + Ui::CWorkspacePage _ui; + + CParticleTreeModel *_treeModel; + friend class CPropertyDialog; + friend class CParticleWorkspaceDialog; +}; /* class CWorkspacePage */ + +} /* namespace NLQT */ + +#endif // PARTICLE_WORKSPACE_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_zone_form.ui b/code/nel/tools/3d/object_viewer_qt/src/particle_zone_form.ui new file mode 100644 index 000000000..09a2b8540 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_zone_form.ui @@ -0,0 +1,151 @@ + + + CZonePage + + + + 0 + 0 + 246 + 350 + + + + Form + + + + + + Targets: + + + + + + + Avaible targets: + + + + + + + + + + Qt::Vertical + + + + 20 + 58 + + + + + + + + + + + + 30 + 16777215 + + + + < + + + + + + + + 30 + 16777215 + + + + > + + + + + + + Qt::Vertical + + + + 20 + 84 + + + + + + + + + Bounce + + + + + Destroy + + + + + + + + Qt::Horizontal + + + + 78 + 20 + + + + + + + + Bounce factor: + + + + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_zone_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/particle_zone_page.cpp new file mode 100644 index 000000000..0a1187602 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_zone_page.cpp @@ -0,0 +1,151 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "particle_zone_page.h" + +// Qt includes + +// NeL includes + +// Project includes +#include "particle_force_page.h" +#include "modules.h" + +namespace NLQT { + +CZonePage::CZonePage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + _ui.bounceFactorWidget->setRange(0.f, 1.f); + _ui.bounceFactorWidget->setWrapper(&_BounceFactorWrapper); + + connect(_ui.toTargetsPushButton, SIGNAL(clicked()), this, SLOT(addTarget())); + connect(_ui.toAvaibleTargetsPushButton, SIGNAL(clicked()), this, SLOT(removeTarget())); + connect(_ui.bounceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setBounce(int))); +} + +CZonePage::~CZonePage() +{ +} + +void CZonePage::setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocatedBindable *locatedBindable) +{ + _Node = ownerNode; + _LBTarget = static_cast(locatedBindable); + _Zone = dynamic_cast(_LBTarget); + + updateTargets(); + + _BounceFactorWrapper.OwnerNode = _Node; + _BounceFactorWrapper.Z = _Zone; + + _ui.bounceFactorWidget->updateUi(); + + _ui.bounceComboBox->setCurrentIndex( _Zone->getCollisionBehaviour()); +} + +void CZonePage::addTarget() +{ + // TODO: multiple add items + int totalCount = _ui.avaibleTargetsListWidget->count(); + if ((totalCount == 0) || (_ui.avaibleTargetsListWidget->currentRow() == -1)) return; + + CLocatedItem *item = dynamic_cast(_ui.avaibleTargetsListWidget->currentItem()); + + NL3D::CPSLocated *loc = item->getUserData(); + nlassert(loc); + + _LBTarget->attachTarget(loc); + + _ui.avaibleTargetsListWidget->takeItem(_ui.avaibleTargetsListWidget->currentRow()); + _ui.targetsListWidget->addItem(item); + + updateModifiedFlag(); +} + +void CZonePage::removeTarget() +{ + // TODO: multiple remove items + int totalCount = _ui.targetsListWidget->count(); + if ((totalCount == 0) || (_ui.targetsListWidget->currentRow() == -1)) return; + + CLocatedItem *item = dynamic_cast(_ui.targetsListWidget->takeItem(_ui.targetsListWidget->currentRow())); + + NL3D::CPSLocated *loc = item->getUserData(); + nlassert(loc); + + _LBTarget->detachTarget(loc); + + _ui.avaibleTargetsListWidget->addItem(item); + updateModifiedFlag(); +} + +void CZonePage::setBounce(int index) +{ + if (_Zone->getCollisionBehaviour() != index) + _Zone->setCollisionBehaviour( (NL3D::CPSZone::TCollisionBehaviour) index); + + _ui.bounceFactorWidget->setEnabled(_Zone->getCollisionBehaviour() == NL3D::CPSZone::bounce ? true : false); + Modules::psEdit().resetAutoCount(_Node); +} + +void CZonePage::updateTargets() +{ + uint k; + uint nbTarg = _LBTarget->getNbTargets(); + + _ui.targetsListWidget->clear(); + + std::set targetSet; + + // fill the box thta tells us what the target are + for(k = 0; k < nbTarg; ++k) + { + CLocatedItem *item = new CLocatedItem(QString(_LBTarget->getTarget(k)->getName().c_str()), + _ui.targetsListWidget); + item->setUserData(_LBTarget->getTarget(k)); + targetSet.insert(_LBTarget->getTarget(k)); + }; + + // fill abox with the available targets + NL3D::CParticleSystem *ps = _LBTarget->getOwner()->getOwner(); + + uint nbLocated = ps->getNbProcess(); + + _ui.avaibleTargetsListWidget->clear(); + + for (k = 0; k < nbLocated; ++k) + { + NL3D::CPSLocated *loc = dynamic_cast(ps->getProcess(k)); + if (loc) + { + if (targetSet.find(loc) == targetSet.end()) + { + CLocatedItem *item = new CLocatedItem(QString(loc->getName().c_str()), + _ui.avaibleTargetsListWidget); + item->setUserData(loc); + } + } + } +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/particle_zone_page.h b/code/nel/tools/3d/object_viewer_qt/src/particle_zone_page.h new file mode 100644 index 000000000..ffbc0c32a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_zone_page.h @@ -0,0 +1,80 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PARTICLE_ZONE_PAGE_H +#define PARTICLE_ZONE_PAGE_H + +#include +#include "ui_particle_zone_form.h" + +// STL includes + +// NeL includes +#include "nel/3d/ps_zone.h" + +// Project includes +#include "particle_node.h" + +namespace NLQT { + +class CZonePage: public QWidget +{ + Q_OBJECT + +public: + CZonePage(QWidget *parent = 0); + virtual ~CZonePage(); + + void setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocatedBindable *locatedBindable); + +private Q_SLOTS: + void addTarget(); + void removeTarget(); + void setBounce(int index); + +private: + + /// wrapper to set the bounce factor of a collision zone + struct CBounceFactorWrapper : public IPSWrapperFloat + { + // the zone being wrapped + NL3D::CPSZone *Z ; + float get(void) const { return Z->getBounceFactor() ; } + void set(const float &v) { Z->setBounceFactor(v) ; } + } _BounceFactorWrapper ; + + void updateTargets(); + + void updateModifiedFlag() { if (_Node) _Node->setModified(true); } + + /// the target we're focusing on + NL3D::CPSTargetLocatedBindable *_LBTarget; + + /// the collision zone being edited + NL3D::CPSZone *_Zone ; + + CWorkspaceNode *_Node; + + Ui::CZonePage _ui; + +}; /* class CZonePage */ + +} /* namespace NLQT */ + +#endif // PARTICLE_ZONE_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/ps_initial_pos.cpp b/code/nel/tools/3d/object_viewer_qt/src/ps_initial_pos.cpp new file mode 100644 index 000000000..222cd498a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/ps_initial_pos.cpp @@ -0,0 +1,209 @@ +// NeL - MMORPG Framework +// 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 . + + +#include "stdpch.h" +#include "ps_initial_pos.h" + +#include "nel/3d/particle_system.h" +#include "nel/3d/ps_located.h" +#include "nel/3d/ps_edit.h" +#include "nel/3d/ps_emitter.h" + +namespace NLQT { + +void CPSInitialPos::reset() +{ + _InitInfoVect.clear(); + _RotScaleInfoVect.clear(); + _InitialSizeVect.clear(); +} + +void CPSInitialPos::copySystemInitialPos(NL3D::CParticleSystem *ps) +{ + nlassert(!_PS); + reset(); + uint32 nbLocated = ps->getNbProcess(); + + _PS = ps; + for(uint32 k = 0; k < nbLocated; ++k) + { + + NL3D::CPSLocated *loc = dynamic_cast(ps->getProcess(k)); + if (loc) + { + + _InitialSizeVect.push_back(std::make_pair(loc, loc->getSize()) ); + for (uint32 l = 0; l < loc->getSize(); ++l) + { + + CInitPSInstanceInfo ii; + ii.Index = l; + ii.Loc = loc; + ii.Pos = loc->getPos()[l]; + ii.Speed = loc->getSpeed()[l]; + _InitInfoVect.push_back(ii); + + for (uint32 m = 0; m < loc->getNbBoundObjects(); ++m) + { + + if (dynamic_cast(loc->getBoundObject(m))) + { + CRotScaleInfo rsi; + rsi.Loc = loc; + rsi.LB = loc->getBoundObject(m); + rsi.Index = l; + rsi.Psm = dynamic_cast(loc->getBoundObject(m)); + rsi.Scale = rsi.Psm->getScale(l); + rsi.Rot = rsi.Psm->getMatrix(l); + _RotScaleInfoVect.push_back(rsi); + } + } + } + } + } +} + + +// PRIVATE : a predicate used in CPSInitialPos::removeLocated +struct CRemoveLocatedPred +{ + NL3D::CPSLocated *Loc ; +}; + +// private : predicate to remove located from a CPSInitialPos::TInitialLocatedSizeVect vector +struct CRemoveLocatedFromLocatedSizePred : public CRemoveLocatedPred +{ + bool operator()(const std::pair &value) { return Loc == value.first; } +}; + +// private : predicate to remove located from a PSInitialPos::CInitPSInstanceInfo vector +struct CRemoveLocatedFromInitPSInstanceInfoVectPred : public CRemoveLocatedPred +{ + bool operator()(const CPSInitialPos::CInitPSInstanceInfo &value) { return value.Loc == Loc; } +}; + +// private : predicate to remove located from a PSInitialPos::CRotScaleInfo vector +struct CRemoveLocatedFromRotScaleInfoVectPred : public CRemoveLocatedPred +{ + bool operator()(const CPSInitialPos::CRotScaleInfo &value) { return value.Loc == Loc; } +}; + +// private : predicate to remove located bindable pointers in a TRotScaleInfoVect vect +struct CRemoveLocatedBindableFromRotScaleInfoVectPred +{ + // the located bindable taht has been removed + NL3D::CPSLocatedBindable *LB; + bool operator()(const CPSInitialPos::CRotScaleInfo &value) { return value.LB == LB; } +}; + +void CPSInitialPos::removeLocated(NL3D::CPSLocated *loc) +{ + // in each container, we delete every element that has a pointer over lthe located loc + // , by using the dedicated predicate. + + CRemoveLocatedFromLocatedSizePred p; + p.Loc = loc; + _InitialSizeVect.erase(std::remove_if(_InitialSizeVect.begin(), _InitialSizeVect.end(), p) + , _InitialSizeVect.end() ); + + CRemoveLocatedFromInitPSInstanceInfoVectPred p2; + p2.Loc = loc; + _InitInfoVect.erase(std::remove_if(_InitInfoVect.begin(), _InitInfoVect.end(), p2) + , _InitInfoVect.end()); + + CRemoveLocatedFromRotScaleInfoVectPred p3; + p3.Loc = loc; + _RotScaleInfoVect.erase(std::remove_if(_RotScaleInfoVect.begin(), _RotScaleInfoVect.end(), p3) + , _RotScaleInfoVect.end()); + +} + +void CPSInitialPos::removeLocatedBindable(NL3D::CPSLocatedBindable *lb) +{ + CRemoveLocatedBindableFromRotScaleInfoVectPred p; + p.LB = lb; + _RotScaleInfoVect.erase(std::remove_if(_RotScaleInfoVect.begin(), _RotScaleInfoVect.end(), p), _RotScaleInfoVect.end() ); +} + +// reinitialize the system with its initial instances positions +void CPSInitialPos::restoreSystem() +{ + nlassert(_PS); // no system has been memorized yet + _PS->stopSound(); + // delete all the instance of the system + NL3D::CPSEmitter::setBypassEmitOnDeath(true); + for (uint k = 0; k < _PS->getNbProcess(); ++k) + { + NL3D::CPSLocated *loc = dynamic_cast(_PS->getProcess(k)); + if (loc) + { + while (loc->getSize()) + { + loc->deleteElement(0); + } + + nlassert(loc->getSize() == 0); + } + } + // recreate the initial number of instances + for (TInitialLocatedSizeVect ::iterator itSize = _InitialSizeVect.begin(); itSize != _InitialSizeVect.end(); ++itSize) + { + // nlassert(itSize->first->getSize() == 0) + for (uint l = 0; l < itSize->second; ++l) + { + itSize->first->newElement(NLMISC::CVector::Null, NLMISC::CVector::Null, NULL, 0, itSize->first->getMatrixMode(), 0.f); + } + + uint realSize = itSize->first->getSize(); + uint size = itSize->second; + + } + NL3D::CPSEmitter::setBypassEmitOnDeath(false); + for (TInitInfoVect::iterator it = _InitInfoVect.begin(); it != _InitInfoVect.end(); ++it) + { + if (it->Index < it->Loc->getSize()) + { + it->Loc->getPos()[it->Index] = it->Pos; + it->Loc->getSpeed()[it->Index] = it->Speed; + // If the particle has parametric infos attach, restore them too + if (it->Loc->isParametricMotionEnabled()) + { + it->Loc->getParametricInfos()[it->Index].Pos = it->Pos; + it->Loc->getParametricInfos()[it->Index].Speed = it->Speed; + it->Loc->getParametricInfos()[it->Index].Date = 0.f; + } + } + } + for (TRotScaleInfoVect::iterator it2 = _RotScaleInfoVect.begin(); it2 != _RotScaleInfoVect.end(); ++it2) + { + if (it2->Index < it2->Loc->getSize()) + { + it2->Psm->setMatrix(it2->Index, it2->Rot); + if (it2->Psm->supportNonUniformScaling()) + { + it2->Psm->setScale(it2->Index, it2->Scale); + } + else if (it2->Psm->supportUniformScaling()) + { + it2->Psm->setScale(it2->Index, it2->Scale.x); + } + } + } + _PS = NULL; +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/ps_initial_pos.h b/code/nel/tools/3d/object_viewer_qt/src/ps_initial_pos.h new file mode 100644 index 000000000..131305cbc --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/ps_initial_pos.h @@ -0,0 +1,101 @@ +// NeL - MMORPG Framework +// 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 . + +#ifndef NL_PS_INITIAL_POS +#define NL_PS_INITIAL_POS + +#include +//#include +#include +#include + +namespace NL3D +{ + class CParticleSystem; + class CPSLocated; + class CPSLocatedBindable; + struct IPSMover; +} + +namespace NLQT { +/** + @class CPSInitialPos + This class helps to copy the position of initial instances in a particle + system. This enable a system to run, and have its parameter modified. + When the user press stop, he will find the system at t = 0, with the new parameters +*/ +class CPSInitialPos +{ +public: + CPSInitialPos() : _PS(NULL) {} + + /// construct this by copying the datas of the system + void copySystemInitialPos(NL3D::CParticleSystem *ps); + + /// reinitialize the system with its initial instances positions + /// Works only once per copySystemInitialPos() call + void restoreSystem(); + + /// send back true when bbox display is enabled + bool isBBoxDisplayEnabled(); + + /// update data when a located in a particle system has been removed + void removeLocated(NL3D::CPSLocated *loc); + + /// update data when a located bindable in a particle system has been removed + void removeLocatedBindable(NL3D::CPSLocatedBindable *lb); + + /// initial position and speed of a located instance in a particle system + struct CInitPSInstanceInfo + { + uint32 Index; + NL3D::CPSLocated *Loc; + NLMISC::CVector Speed; + NLMISC::CVector Pos; + }; + + /// rotation and scale of an element + struct CRotScaleInfo + { + uint32 Index; + NL3D::CPSLocated *Loc; + NL3D::CPSLocatedBindable *LB; + NL3D::IPSMover *Psm; + NLMISC::CMatrix Rot; + NLMISC::CVector Scale; + }; + NL3D::CParticleSystem *getPS() { return _PS; } + const NL3D::CParticleSystem *getPS() const { return _PS; } + bool isStateMemorized() const { return _PS != NULL; } + +private: + typedef std::vector TInitInfoVect; + typedef std::vector TRotScaleInfoVect; + typedef std::vector< std::pair > TInitialLocatedSizeVect; + TInitInfoVect _InitInfoVect; + TRotScaleInfoVect _RotScaleInfoVect; + + /// initial number of instances for each located + TInitialLocatedSizeVect _InitialSizeVect; + NL3D::CParticleSystem *_PS; + + /// reset all initial infos + void reset(); +}; + +} /* namespace NLQT */ + +#endif \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/ps_mover_form.ui b/code/nel/tools/3d/object_viewer_qt/src/ps_mover_form.ui new file mode 100644 index 000000000..ba461eb5c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/ps_mover_form.ui @@ -0,0 +1,193 @@ + + + CPSMoverPage + + + + 0 + 0 + 332 + 575 + + + + Form + + + + + + Position: + + + + + + + + X: + + + + + + + + 0 + 0 + + + + -9999.000000000000000 + + + 9999.000000000000000 + + + + + + + + + + + Y: + + + + + + + + 0 + 0 + + + + -9999.000000000000000 + + + 9999.000000000000000 + + + + + + + + + + + Z: + + + + + + + + 0 + 0 + + + + -9999.000000000000000 + + + 9999.000000000000000 + + + + + + + + + + + + Sub component: + + + + + + + + + + + + Scale X: + + + + + + + + + + Scale Y: + + + + + + + + + + Scale Z: + + + + + + + + + + Scale: + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 106 + + + + + + + + + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CDirectionWidget + QWidget +
direction_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/ps_mover_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/ps_mover_page.cpp new file mode 100644 index 000000000..fa717591f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/ps_mover_page.cpp @@ -0,0 +1,245 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "ps_mover_page.h" + +// Qt includes + +// NeL includes + +// Project includes +#include "modules.h" + +namespace NLQT { + +const float epsilon = 10E-3f; + +CPSMoverPage::CPSMoverPage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + _ui.scaleWidget->setRange(0.f, 4.f); + _ui.scaleWidget->setWrapper(&_UniformScaleWrapper); + + _ui.scaleXWidget->setRange(0.f, 4.f); + _ui.scaleXWidget->setWrapper(&_XScaleWrapper); + + _ui.scaleYWidget->setRange(0.f, 4.f); + _ui.scaleYWidget->setWrapper(&_YScaleWrapper); + + _ui.scaleZWidget->setRange(0.f, 4.f); + _ui.scaleZWidget->setWrapper(&_ZScaleWrapper); + + _ui.directionWidget->setWrapper(&_DirectionWrapper); + + connect(_ui.xDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setXPosition(double))); + connect(_ui.yDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setYPosition(double))); + connect(_ui.zDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setZPosition(double))); + + connect(_ui.listWidget, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(changeSubComponent())); +} + +CPSMoverPage::~CPSMoverPage() +{ +} + +void CPSMoverPage::setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocated *located, uint32 editedLocatedIndex) +{ + _Node = ownerNode; + _EditedLocated = located; + _EditedLocatedIndex = editedLocatedIndex; + + updatePosition(); + + _ui.listWidget->clear(); + hideWrappersWidget(); + + uint numBound = _EditedLocated->getNbBoundObjects(); + + uint nbCandidates = 0; + + for (uint k = 0; k < numBound; ++k) + { + if (dynamic_cast(_EditedLocated->getBoundObject(k))) + { + CLocatedBindableItem *item = new CLocatedBindableItem(QString(_EditedLocated->getBoundObject(k)->getName().c_str()), + _ui.listWidget); + item->setUserData(_EditedLocated->getBoundObject(k)); + ++nbCandidates; + } + } + if (nbCandidates > 0) + _ui.listWidget->setCurrentRow(0); +} + +void CPSMoverPage::updatePosition(void) +{ + const NLMISC::CVector &pos = _EditedLocated->getPos()[_EditedLocatedIndex]; + + _ui.xDoubleSpinBox->setValue(pos.x); + _ui.yDoubleSpinBox->setValue(pos.y); + _ui.zDoubleSpinBox->setValue(pos.z); + +} + +void CPSMoverPage::hideWrappersWidget() +{ + _ui.scaleLabel->hide(); + _ui.scaleXLabel->hide(); + _ui.scaleYLabel->hide(); + _ui.scaleZLabel->hide(); + _ui.scaleWidget->hide(); + _ui.scaleXWidget->hide(); + _ui.scaleYWidget->hide(); + _ui.scaleZWidget->hide(); + _ui.directionWidget->hide(); +} + +void CPSMoverPage::updateListener(void) +{ +/* if(_ParticleDlg->MainFrame->isMoveElement()) + { + const NLMISC::CVector &pos = _EditedLocated->getPos()[_EditedLocatedIndex]; + NLMISC::CMatrix m; + m = _MouseListener->getModelMatrix(); + m.setPos(pos); + _MouseListener->setModelMatrix(m); + _Node->setModified(true); + }*/ +} + +void CPSMoverPage::setXPosition(double value) +{ + NLMISC::CVector &pos = _EditedLocated->getPos()[_EditedLocatedIndex]; + if (fabs(pos.x - _ui.xDoubleSpinBox->value()) > epsilon) + { + pos.x = value; + updateListener(); + _Node->setModified(true); + } +} + +void CPSMoverPage::setYPosition(double value) +{ + NLMISC::CVector &pos = _EditedLocated->getPos()[_EditedLocatedIndex]; + if (fabs(pos.y - _ui.yDoubleSpinBox->value()) > epsilon) + { + pos.y = value; + updateListener(); + _Node->setModified(true); + } +} + +void CPSMoverPage::setZPosition(double value) +{ + NLMISC::CVector &pos = _EditedLocated->getPos()[_EditedLocatedIndex]; + if (fabs(pos.z - _ui.zDoubleSpinBox->value()) > epsilon) + { + pos.z = value; + updateListener(); + _Node->setModified(true); + } +} + +void CPSMoverPage::changeSubComponent() +{ + hideWrappersWidget(); + NL3D::IPSMover *m = getMoverInterface(); + if (!m) return; + + _Node->getPSPointer()->setCurrentEditedElement(NULL); + _Node->getPSPointer()->setCurrentEditedElement(_EditedLocated, _EditedLocatedIndex, getLocatedBindable()); + + + if (m->supportUniformScaling() && ! m->supportNonUniformScaling() ) + { + _UniformScaleWrapper.OwnerNode = _Node; + _UniformScaleWrapper.M = m; + _UniformScaleWrapper.Index = _EditedLocatedIndex; + + _ui.scaleWidget->updateUi(); + _ui.scaleLabel->show(); + _ui.scaleWidget->show(); + } + else if (m->supportNonUniformScaling()) + { + // dialog for edition of x scale + _XScaleWrapper.OwnerNode = _Node; + _XScaleWrapper.M = m; + _XScaleWrapper.Index = _EditedLocatedIndex; + + _ui.scaleXWidget->updateUi(); + _ui.scaleXLabel->show(); + _ui.scaleXWidget->show(); + + // dialog for edition of y scale + _YScaleWrapper.OwnerNode = _Node; + _YScaleWrapper.M = m; + _YScaleWrapper.Index = _EditedLocatedIndex; + + _ui.scaleYWidget->updateUi(); + _ui.scaleYLabel->show(); + _ui.scaleYWidget->show(); + + // dialog for edition of x scale + _ZScaleWrapper.OwnerNode = _Node; + _ZScaleWrapper.M = m; + _ZScaleWrapper.Index = _EditedLocatedIndex; + + _ui.scaleZWidget->updateUi(); + _ui.scaleZLabel->show(); + _ui.scaleZWidget->show(); + } + + + if (m->onlyStoreNormal()) + { + _DirectionWrapper.OwnerNode = _Node; + _DirectionWrapper.M = m; + _DirectionWrapper.Index = _EditedLocatedIndex; + + _ui.directionWidget->updateUi(); + _ui.directionWidget->show(); + } +} + +NL3D::IPSMover *CPSMoverPage::getMoverInterface(void) +{ + nlassert(_EditedLocated); + sint currIndex = _ui.listWidget->currentRow(); + if (currIndex == -1) return NULL; + + CLocatedBindableItem *item = dynamic_cast(_ui.listWidget->currentItem()); + return dynamic_cast(item->getUserData()); +} + +NL3D::CPSLocatedBindable *CPSMoverPage::getLocatedBindable(void) +{ + nlassert(_EditedLocated); + sint currIndex = _ui.listWidget->currentRow(); + if (currIndex == -1) return NULL; + + CLocatedBindableItem *item = dynamic_cast(_ui.listWidget->currentItem()); + return item->getUserData(); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/ps_mover_page.h b/code/nel/tools/3d/object_viewer_qt/src/ps_mover_page.h new file mode 100644 index 000000000..f2403ca7f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/ps_mover_page.h @@ -0,0 +1,174 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef PS_MOVER_PAGE_H +#define PS_MOVER_PAGE_H + + +#include +#include "ui_ps_mover_form.h" + +// STL includes + +// NeL includes +#include +#include +#include +#include + +// Project includes +#include "ps_wrapper.h" + +namespace NLQT { + +/** +@class CLocatedBindableItem +@brief Contain pointer to CPSLocatedBindable. +*/ +class CLocatedBindableItem: public QListWidgetItem +{ +public: + CLocatedBindableItem ( const QString & text, QListWidget * parent = 0, int type = UserType ): + QListWidgetItem(text, parent, type), _lb(NULL) {} + + void setUserData(NL3D::CPSLocatedBindable *loc) { _lb = loc;} + NL3D::CPSLocatedBindable *getUserData() const { return _lb;} + +private: + + NL3D::CPSLocatedBindable *_lb; +}; /* class CTargetItem */ + +/** +@class CPSMoverPage +@brief Page for QStackWidget, to edit instance in a particle system. +*/ +class CPSMoverPage: public QWidget +{ + Q_OBJECT + +public: + CPSMoverPage(QWidget *parent = 0); + ~CPSMoverPage(); + + /// Set the instance to edit. + void setEditedItem(CWorkspaceNode *ownerNode, NL3D::CPSLocated *located, uint32 editedLocatedIndex); + + /// position has to be updated (for mouse edition) + void updatePosition(void) ; + + /// get the current moving interface, or NULL, if the selected object has no IPSMover interface + NL3D::IPSMover *getMoverInterface(void) ; + + /// get the located being edited + NL3D::CPSLocated *getLocated(void) { return _EditedLocated ; } + const NL3D::CPSLocated *getLocated(void) const { return _EditedLocated ; } + + /// get the index of the current edited item + uint32 getLocatedIndex(void) const { return _EditedLocatedIndex ; } + + /// ghet the current located bindable being edited, or null + NL3D::CPSLocatedBindable *getLocatedBindable(void) ; + +private Q_SLOTS: + void setXPosition(double value); + void setYPosition(double value); + void setZPosition(double value); + void changeSubComponent(); + +private: + + /// wrappers to scale objects + struct CUniformScaleWrapper : public IPSWrapperFloat + { + uint32 Index ; + NL3D::IPSMover *M ; + float get(void) const { return M->getScale(Index).x ; } + void set(const float &v) { M->setScale(Index, v) ; } + } _UniformScaleWrapper ; + + /// wrapper to scale the X coordinate + struct CXScaleWrapper : public IPSWrapperFloat + { + uint32 Index ; + NL3D::IPSMover *M ; + float get(void) const { return M->getScale(Index).x ; } + void set(const float &s) + { + NLMISC::CVector v = M->getScale(Index) ; + M->setScale(Index, NLMISC::CVector(s, v.y, v.z)) ; + } + } _XScaleWrapper ; + + /// wrapper to scale the Y coordinate + struct CYScaleWrapper : public IPSWrapperFloat + { + uint32 Index ; + NL3D::IPSMover *M ; + float get(void) const { return M->getScale(Index).y ; } + void set(const float &s) + { + NLMISC::CVector v = M->getScale(Index) ; + M->setScale(Index, NLMISC::CVector(v.x, s, v.z) ) ; + } + } _YScaleWrapper ; + + /// wrapper to scale the Z coordinate + struct CZScaleWrapper : public IPSWrapperFloat + { + uint32 Index ; + NL3D::IPSMover *M ; + float get(void) const { return M->getScale(Index).z ; } + void set(const float &s) + { + NLMISC::CVector v = M->getScale(Index) ; + M->setScale(Index, NLMISC::CVector(v.x, v.y, s) ) ; + } + } _ZScaleWrapper ; + + /// wrapper for direction + struct CDirectionWrapper : public IPSWrapper + { + uint32 Index ; + NL3D::IPSMover *M ; + NLMISC::CVector get(void) const { return M->getNormal(Index) ; } + void set(const NLMISC::CVector &v) { M->setNormal(Index, v) ; } + + + } _DirectionWrapper ; + + void hideWrappersWidget(); + + /// update the mouse listener position when the user entered a value with the keyboard + void updateListener(void) ; + + CWorkspaceNode *_Node; + + NL3D::CPSLocated *_EditedLocated ; + + uint32 _EditedLocatedIndex ; + + Ui::CPSMoverPage _ui; + +}; /* class CPSMoverPage */ + +} /* namespace NLQT */ + + +#endif // PS_MOVER_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/ps_wrapper.h b/code/nel/tools/3d/object_viewer_qt/src/ps_wrapper.h new file mode 100644 index 000000000..70c1a5aa4 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/ps_wrapper.h @@ -0,0 +1,118 @@ +// NeL - MMORPG Framework +// 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 . + + + +#ifndef _PS_WRAPPER_H +#define _PS_WRAPPER_H + + + + +#include "nel/misc/rgba.h" +#include "nel/misc/vector.h" +// +#include "nel/3d/ps_attrib_maker.h" +#include "nel/3d/texture.h" +// +#include "particle_node.h" + +namespace NLQT { + +/// Wrapper to read/write a value of type T +template class IPSWrapper +{ +public: + NLQT::CWorkspaceNode *OwnerNode; // Owner node of the property. When the property is modified, then the node will be marked as 'modified' +public: + IPSWrapper() : OwnerNode(NULL) + { + } + // for derivers : get a value + virtual T get(void) const = 0; + void setAndUpdateModifiedFlag(const T &value) + { + if (OwnerNode) + { + OwnerNode->setModified(true); + } + set(value); + } +protected: + // for derivers : set a value + virtual void set(const T &) = 0; +}; + + +/// Wrapper to read/write a scheme of type T +template class IPSSchemeWrapper +{ +public: + NLQT::CWorkspaceNode *OwnerNode; // Owner node of the property. When the property is modified, then the node will be marked as 'modified' +public: + IPSSchemeWrapper() : OwnerNode(NULL) {} + typedef NL3D::CPSAttribMaker scheme_type; + virtual scheme_type *getScheme(void) const = 0; + void setSchemeAndUpdateModifiedFlag(scheme_type *s) + { + if (OwnerNode) + { + OwnerNode->setModified(true); + } + setScheme(s); + } +protected: + virtual void setScheme(scheme_type *s) = 0; +}; + + + +/// RGBA wrapper +typedef IPSWrapper IPSWrapperRGBA; +typedef IPSSchemeWrapper IPSSchemeWrapperRGBA; + +/// float wrapper +typedef IPSWrapper IPSWrapperFloat; +typedef IPSSchemeWrapper IPSSchemeWrapperFloat; + +/// uint wrapper +typedef IPSWrapper IPSWrapperUInt; +typedef IPSSchemeWrapper IPSSchemeWrapperUInt; + +/// sint wrapper +typedef IPSWrapper IPSWrapperInt; + +/// texture wrapper +class IPSWrapperTexture +{ +public: + NLQT::CWorkspaceNode *OwnerNode; +public: + // ctor + IPSWrapperTexture() : OwnerNode(NULL) {} + virtual NL3D::ITexture *get(void) = 0; + virtual void setAndUpdateModifiedFlag(NL3D::ITexture *tex) + { + if (OwnerNode) OwnerNode->setModified(true); + set(tex); + } +protected: + virtual void set(NL3D::ITexture *) = 0; +}; + +} /* namespace NLQT */ + +#endif \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/settings_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/settings_dialog.cpp new file mode 100644 index 000000000..a0df72c2c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/settings_dialog.cpp @@ -0,0 +1,373 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "settings_dialog.h" + +// Qt includes +#include +#include +#include + +// NeL includes +#include +#include + +// Project includes +#include "modules.h" + +using namespace NLMISC; + +namespace NLQT { + +CSettingsDialog::CSettingsDialog(QWidget *parent) + : QDialog(parent) +{ + ui.setupUi(this); + + loadGraphicsSettings(); + loadSoundSettings(); + loadPathsSettings(); + loadVegetableSettings(); + + connect(ui.enableBloomCheckBox, SIGNAL(toggled(bool)), this, SLOT(setEnableBloom(bool))); + connect(ui.squareBloomCheckBox, SIGNAL(toggled(bool)), this, SLOT(setEnableSquareBloon(bool))); + connect(ui.bloomDensityHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setDensityBloom(int))); + + connect(ui.addToolButton, SIGNAL(clicked()), this, SLOT(addPath())); + connect(ui.removeToolButton, SIGNAL(clicked()), this, SLOT(removePath())); + connect(ui.upToolButton, SIGNAL(clicked()), this, SLOT(upPath())); + connect(ui.downToolButton, SIGNAL(clicked()), this, SLOT(downPath())); + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(applyPressed())); + + connect(ui.tileBankToolButton, SIGNAL(clicked()), this, SLOT(setTileBank())); + connect(ui.tileFarBankToolButton, SIGNAL(clicked()), this, SLOT(setTileFarBank())); + connect(ui.vegetTexToolButton, SIGNAL(clicked()), this, SLOT(setTextureVegetable())); + connect(ui.addZoneToolButton, SIGNAL(clicked()), this, SLOT(addZone())); + connect(ui.removeZoneToolButton, SIGNAL(clicked()), this, SLOT(removeZone())); + +#ifdef NL_OS_UNIX + ui.driverGraphComboBox->setEnabled(false); +#endif + +} + +CSettingsDialog::~CSettingsDialog() +{ + Modules::config().dropCallback("GraphicsDrivers"); + Modules::config().dropCallback("SoundDrivers"); + Modules::config().dropCallback("SearchPaths"); +} + +void CSettingsDialog::addPath() +{ + QListWidgetItem *newItem = new QListWidgetItem; + QString newPath = QFileDialog::getExistingDirectory(this); + if (!(newPath == "")) + { + newItem->setText(newPath); + newItem->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); + ui.pathsListWidget->addItem(newItem); + } +} + +void CSettingsDialog::removePath() +{ + QListWidgetItem *removeItem = ui.pathsListWidget->takeItem(ui.pathsListWidget->currentRow()); + if (!removeItem) delete removeItem; +} + +void CSettingsDialog::upPath() +{ + sint currentRow = ui.pathsListWidget->currentRow(); + if (!(currentRow == 0)) + { + QListWidgetItem *item = ui.pathsListWidget->takeItem(currentRow); + ui.pathsListWidget->insertItem(--currentRow, item); + ui.pathsListWidget->setCurrentRow(currentRow); + } +} + +void CSettingsDialog::downPath() +{ + sint currentRow = ui.pathsListWidget->currentRow(); + if (!(currentRow == ui.pathsListWidget->count()-1)) + { + QListWidgetItem *item = ui.pathsListWidget->takeItem(currentRow); + ui.pathsListWidget->insertItem(++currentRow, item); + ui.pathsListWidget->setCurrentRow(currentRow); + } +} + +void CSettingsDialog::applyPressed() +{ + + // settings take after restart the program + QMessageBox::warning(this, tr("Settings"), + tr("Graphics and sound settings " + "take after restart the program"), + QMessageBox::Ok); + + saveGraphicsSettings(); + saveSoundSettings(); + savePathsSettings(); + saveVegetableSettings(); + + // save config file + Modules::config().getConfigFile().save(); + + // reload search paths + Modules::config().configSearchPaths(); +} + +void CSettingsDialog::setTileBank() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Set new tile bank"), + ui.tileBankLineEdit->text(), + tr("Tile Bank file (*.smallbank *.bank);;")); + if (!fileName.isEmpty()) + { + ui.tileBankLineEdit->setText(fileName); + } +} + +void CSettingsDialog::setTileFarBank() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Set new tile far bank"), + ui.tileFarBankLineEdit->text(), + tr("Tile Far Bank file (*.farbank);;")); + if (!fileName.isEmpty()) + { + ui.tileFarBankLineEdit->setText(fileName); + } +} + +void CSettingsDialog::setTextureVegetable() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Set MicroVegetable texture"), + ui.vegetTextureLineEdit->text(), + tr("Texture file (*.tga *.png *.jpg *.dds);;")); + if (!fileName.isEmpty()) + { + ui.vegetTextureLineEdit->setText(fileName); + } +} + +void CSettingsDialog::addZone() +{ + QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Add zone files"), ".", + tr("Zonel files (*.zonel);;")); + + if (!fileNames.isEmpty()) + { + QStringList list = fileNames; + QStringList::Iterator it = list.begin(); + while(it != list.end()) + { + QListWidgetItem *newItem = new QListWidgetItem; + newItem->setText(*it); + newItem->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); + ui.zonesListWidget->addItem(newItem); + ++it; + } + } +} + +void CSettingsDialog::removeZone() +{ + QListWidgetItem *removeItem = ui.zonesListWidget->takeItem(ui.zonesListWidget->currentRow()); + if (!removeItem) delete removeItem; +} + +void CSettingsDialog::setEnableBloom(bool state) +{ + Modules::objView().setBloomEffect(state); +} + +void CSettingsDialog::setEnableSquareBloon(bool state) +{ + NL3D::CBloomEffect::instance().setSquareBloom(state); +} + +void CSettingsDialog::setDensityBloom(int density) +{ + NL3D::CBloomEffect::instance().setDensityBloom(density); +} + +void CSettingsDialog::cfcbGraphicsDrivers(NLMISC::CConfigFile::CVar &var) +{ + while (ui.driverGraphComboBox->count()) + ui.driverGraphComboBox->removeItem(0); + + // load types graphics driver from the config file + for (uint i = 0; i < var.size(); ++i) + ui.driverGraphComboBox->addItem(var.asString(i).c_str()); + + // set graphics driver from the config file + QString value = Modules::config().getValue("GraphicsDriver",std::string("OpenGL")).c_str(); + QString dn = value.toLower(); + for (sint i = 0; i < ui.driverGraphComboBox->count(); ++i) + { + if (dn == ui.driverGraphComboBox->itemText(i).toLower()) + { + ui.driverGraphComboBox->setCurrentIndex(i); + return; + } + } +} + +void CSettingsDialog::cfcbSoundDrivers(NLMISC::CConfigFile::CVar& var) +{ + while (ui.driverSndComboBox->count()) + ui.driverSndComboBox->removeItem(0); + + // load types sound driver from the config file + for (uint i = 0; i < var.size(); ++i) + ui.driverSndComboBox->addItem(var.asString(i).c_str()); + + // set sound driver from the config file + QString value = Modules::config().getValue("SoundDriver",std::string("Auto")).c_str(); + QString dn = value.toLower(); + for (sint i = 0; i < ui.driverSndComboBox->count(); ++i) + { + if (dn == ui.driverSndComboBox->itemText(i).toLower()) + { + ui.driverSndComboBox->setCurrentIndex(i); + return; + } + } +} + +void CSettingsDialog::cfcbSearchPaths(NLMISC::CConfigFile::CVar &var) +{ + /// TODO: create custom widget add/insert/del/up/down paths (also this is use landscape zones) + + ui.pathsListWidget->clear(); + + // load search paths from the config file + for (uint i = 0; i < var.size(); ++i) + { + ui.pathsListWidget->addItem(var.asString(i).c_str()); + ui.pathsListWidget->item(i)->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); + } +} + +void CSettingsDialog::loadGraphicsSettings() +{ + // setup config file callbacks and initialize values + Modules::config().setAndCallback("GraphicsDrivers", CConfigCallback(this, &CSettingsDialog::cfcbGraphicsDrivers)); + + ui.enableBloomCheckBox->setChecked(Modules::objView().getBloomEffect()); + ui.squareBloomCheckBox->setChecked(NL3D::CBloomEffect::instance().getSquareBloom()); + ui.bloomDensityHorizontalSlider->setValue(NL3D::CBloomEffect::instance().getDensityBloom()); +} + +void CSettingsDialog::loadSoundSettings() +{ + // setup config file callbacks and initialize values + Modules::config().setAndCallback("SoundDrivers", CConfigCallback(this, &CSettingsDialog::cfcbSoundDrivers)); + + // load settings from the config file + ui.autoLoadSampleCheckBox->setChecked(Modules::config().getValue("SoundAutoLoadSample", true)); + ui.enableOccludeObstructCheckBox->setChecked(Modules::config().getValue("SoundEnableOccludeObstruct", true)); + ui.enableReverbCheckBox->setChecked(Modules::config().getValue("SoundEnableReverb", true)); + ui.manualRolloffCheckBox->setChecked(Modules::config().getValue("SoundManualRolloff", true)); + ui.forceSoftwareCheckBox->setChecked(Modules::config().getValue("SoundForceSoftware", false)); + ui.useADPCMCheckBox->setChecked(Modules::config().getValue("SoundUseADPCM", false)); + ui.maxTrackSpinBox->setValue(Modules::config().getValue("SoundMaxTrack", 48)); +} + +void CSettingsDialog::loadPathsSettings() +{ + // setup config file callbacks and initialize values + Modules::config().setAndCallback("SearchPaths", CConfigCallback(this, &CSettingsDialog::cfcbSearchPaths)); +} + +void CSettingsDialog::loadVegetableSettings() +{ + ui.tileBankLineEdit->setText(Modules::config().getConfigFile().getVar("VegetTileBank").asString().c_str()); + ui.tileFarBankLineEdit->setText(Modules::config().getConfigFile().getVar("VegetTileFarBank").asString().c_str()); + ui.vegetTextureLineEdit->setText(Modules::config().getConfigFile().getVar("VegetTexture").asString().c_str()); + + ui.zonesListWidget->clear(); + + // load vegetable landscape zone paths from config file + NLMISC::CConfigFile::CVar &var = Modules::config().getConfigFile().getVar("VegetLandscapeZones"); + for (uint i = 0; i < var.size(); ++i) + { + ui.zonesListWidget->addItem(var.asString(i).c_str()); + ui.zonesListWidget->item(i)->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); + } +} + +void CSettingsDialog::saveGraphicsSettings() +{ + // save graphics settings to config file + Modules::config().getConfigFile().getVar("GraphicsDriver").setAsString(ui.driverGraphComboBox->currentText().toStdString()); + + Modules::config().getConfigFile().getVar("BloomEffect").setAsInt(ui.enableBloomCheckBox->isChecked()); + Modules::config().getConfigFile().getVar("BloomSquare").setAsInt(ui.squareBloomCheckBox->isChecked()); + Modules::config().getConfigFile().getVar("BloomDensity").setAsInt(ui.bloomDensityHorizontalSlider->value()); +} + +void CSettingsDialog::saveSoundSettings() +{ + // save sound settings to config file + Modules::config().getConfigFile().getVar("SoundDriver").setAsString(ui.driverSndComboBox->currentText().toStdString()); + Modules::config().getConfigFile().getVar("SoundAutoLoadSample").setAsInt(ui.autoLoadSampleCheckBox->isChecked()); + Modules::config().getConfigFile().getVar("SoundEnableOccludeObstruct").setAsInt(ui.enableOccludeObstructCheckBox->isChecked()); + Modules::config().getConfigFile().getVar("SoundEnableReverb").setAsInt(ui.enableReverbCheckBox->isChecked()); + Modules::config().getConfigFile().getVar("SoundManualRolloff").setAsInt(ui.manualRolloffCheckBox->isChecked()); + Modules::config().getConfigFile().getVar("SoundForceSoftware").setAsInt(ui.forceSoftwareCheckBox->isChecked()); + Modules::config().getConfigFile().getVar("SoundUseADPCM").setAsInt(ui.useADPCMCheckBox->isChecked()); + Modules::config().getConfigFile().getVar("SoundMaxTrack").setAsInt(ui.maxTrackSpinBox->value()); +} + +void CSettingsDialog::savePathsSettings() +{ + std::vector list; + for (sint i = 0; i < ui.pathsListWidget->count(); ++i) + { + std::string str = ui.pathsListWidget->item(i)->text().toStdString(); + list.push_back(str); + } + if (ui.pathsListWidget->count() == 0) + list.push_back("WARNING: Delete this string"); + Modules::config().getConfigFile().getVar("SearchPaths").setAsString(list); +} + +void CSettingsDialog::saveVegetableSettings() +{ + Modules::config().getConfigFile().getVar("VegetTileBank").setAsString(ui.tileBankLineEdit->text().toStdString()); + Modules::config().getConfigFile().getVar("VegetTileFarBank").setAsString(ui.tileFarBankLineEdit->text().toStdString()); + Modules::config().getConfigFile().getVar("VegetTexture").setAsString(ui.vegetTextureLineEdit->text().toStdString()); + + std::vector list; + for (sint i = 0; i < ui.zonesListWidget->count(); ++i) + { + std::string str = ui.zonesListWidget->item(i)->text().toStdString(); + list.push_back(str); + } + if (ui.zonesListWidget->count() == 0) + list.push_back("WARNING: Delete this string"); + Modules::config().getConfigFile().getVar("VegetLandscapeZones").setAsString(list); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/settings_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/settings_dialog.h new file mode 100644 index 000000000..258ebb96f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/settings_dialog.h @@ -0,0 +1,84 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef SETTINGS_DIALOG_H +#define SETTINGS_DIALOG_H + +#include +#include "ui_settings_form.h" + +// STL includes + +// NeL includes +#include + +// Project includes + +namespace NLQT { + +/** +@class CSettingsDialog +@brief Settings dialog (graphics/sound/search path/vegetable). +*/ +class CSettingsDialog: public QDialog +{ + Q_OBJECT + +public: + CSettingsDialog(QWidget *parent = 0); + ~CSettingsDialog(); + +private Q_SLOTS: + void addPath(); + void removePath(); + void upPath(); + void downPath(); + void applyPressed(); + + void setTileBank(); + void setTileFarBank(); + void setTextureVegetable(); + void addZone(); + void removeZone(); + + void setEnableBloom(bool state); + void setEnableSquareBloon(bool state); + void setDensityBloom(int density); + +private: + void cfcbGraphicsDrivers(NLMISC::CConfigFile::CVar &var); + void cfcbSoundDrivers(NLMISC::CConfigFile::CVar &var); + void cfcbSearchPaths(NLMISC::CConfigFile::CVar &var); + + void loadGraphicsSettings(); + void loadSoundSettings(); + void loadPathsSettings(); + void loadVegetableSettings(); + void saveGraphicsSettings(); + void saveSoundSettings(); + void savePathsSettings(); + void saveVegetableSettings(); + + Ui::CSettingsDialog ui; + +}; /* class CSettingsDialog */ + +} /* namespace NLQT */ + +#endif // SETTINGS_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/settings_form.ui b/code/nel/tools/3d/object_viewer_qt/src/settings_form.ui new file mode 100644 index 000000000..b836a7301 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/settings_form.ui @@ -0,0 +1,657 @@ + + + CSettingsDialog + + + Qt::NonModal + + + + 0 + 0 + 684 + 557 + + + + Settings + + + + :/images/preferences.png:/images/preferences.png + + + true + + + + + + + 0 + 0 + + + + + 120 + 16777215 + + + + + Graphics + + + + + Sound + + + + + Paths + + + + + Vegetable + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + + + + + Graphics settings + + + + + + + + Driver + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + + + + + + + + + Bloom effect + + + + + + + + Bloom density + + + + + + + 255 + + + Qt::Horizontal + + + + + + + + + Square bloom + + + + + + + Enable bloom effect + + + + + + + + + + Qt::Vertical + + + + 20 + 283 + + + + + + + + + + + + Sound settings + + + + + + + + + + Driver + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + + + + + + SoundAutoLoadSample + + + + + + + SoundEnableOccludeObstruct + + + + + + + SoundEnableReverb + + + + + + + SoundManualRolloff + + + + + + + SoundForceSoftware + + + + + + + SoundUseADPCM + + + + + + + + + SoundMaxTrack + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 89 + + + + + + + + + + + + Search paths + + + + + + + + + + + + 0 + 0 + + + + ... + + + + :/images/list-add.png:/images/list-add.png + + + + 16 + 16 + + + + + + + + ... + + + + :/images/list-remove.png:/images/list-remove.png + + + + + + + ... + + + + :/images/go-up.png:/images/go-up.png + + + + + + + ... + + + + :/images/go-down.png:/images/go-down.png + + + + + + + + + Qt::Vertical + + + + 20 + 195 + + + + + + + + + + + + + + + Setup Landscape + + + + + + Tile bank: + + + + + + + + 0 + 0 + + + + + + + + ... + + + + + + + Tile far bank: + + + + + + + + 0 + 0 + + + + + + + + ... + + + + + + + Vegetable texture: + + + + + + + + 0 + 0 + + + + + + + + ... + + + + + + + Landscape zones: + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 118 + 20 + + + + + + + + QLayout::SetMinimumSize + + + + + + 0 + 0 + + + + ... + + + + :/images/list-add.png:/images/list-add.png + + + + 16 + 16 + + + + + + + + ... + + + + :/images/list-remove.png:/images/list-remove.png + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + listWidget + driverGraphComboBox + driverSndComboBox + autoLoadSampleCheckBox + enableOccludeObstructCheckBox + enableReverbCheckBox + manualRolloffCheckBox + forceSoftwareCheckBox + useADPCMCheckBox + maxTrackSpinBox + pathsListWidget + addToolButton + removeToolButton + upToolButton + downToolButton + buttonBox + + + + + + + buttonBox + accepted() + CSettingsDialog + accept() + + + 222 + 385 + + + 157 + 274 + + + + + buttonBox + rejected() + CSettingsDialog + reject() + + + 290 + 391 + + + 286 + 274 + + + + + listWidget + currentRowChanged(int) + stackedWidget + setCurrentIndex(int) + + + 69 + 96 + + + 226 + 360 + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/setup_fog_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/setup_fog_dialog.cpp new file mode 100644 index 000000000..8da2d799d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/setup_fog_dialog.cpp @@ -0,0 +1,80 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "setup_fog_dialog.h" + +// Qt includes +#include +#include + +// NeL includes +#include +#include + +// Project includes +#include "modules.h" + +using namespace NL3D; +using namespace NLMISC; + +namespace NLQT { + +CSetupFog::CSetupFog(QWidget *parent) + : QDockWidget(parent) +{ + ui.setupUi(this); + + // load fog value from config file + ui.startDoubleSpinBox->setValue(Modules::config().getValue("FogStart", 0.0)); + ui.endDoubleSpinBox->setValue(Modules::config().getValue("FogEnd", 0.0)); + colorFog = Modules::config().getValue("FogColor",CRGBA(0.0, 0.0, 0.0)); + + connect(ui.applyPushButton, SIGNAL(clicked()), this, SLOT(apply())); + connect(ui.colorPushButton, SIGNAL(clicked()), this, SLOT(setColor())); +} + +CSetupFog::~CSetupFog() +{ + // save fog value from config file + Modules::config().getConfigFile().getVar("FogStart").setAsFloat(ui.startDoubleSpinBox->value()); + Modules::config().getConfigFile().getVar("FogEnd").setAsFloat(ui.endDoubleSpinBox->value()); + Modules::config().getConfigFile().getVar("FogColor").setAsInt(colorFog.R, 0); + Modules::config().getConfigFile().getVar("FogColor").setAsInt(colorFog.G, 1); + Modules::config().getConfigFile().getVar("FogColor").setAsInt(colorFog.B, 2); + +} + +void CSetupFog::apply() +{ + Modules::objView().getDriver()->setupFog(ui.startDoubleSpinBox->value(), + ui.endDoubleSpinBox->value(), + colorFog); + Modules::objView().getDriver()->enableFog(ui.enableFogCheckBox->isChecked()); +} + +void CSetupFog::setColor() +{ + QColor color = QColorDialog::getColor(QColor(colorFog.R, + colorFog.G, + colorFog.B)); + colorFog.set(color.red(), color.green(), color.blue()); +} + +} /* namespace NLQT */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/setup_fog_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/setup_fog_dialog.h new file mode 100644 index 000000000..d14ff8d51 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/setup_fog_dialog.h @@ -0,0 +1,60 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef SETUP_FOG_DIALOG_H +#define SETUP_FOG_DIALOG_H + +#include +#include "ui_setup_fog_form.h" + +// STL includes + +// NeL includes +#include +#include + +// Project includes + +namespace NLQT { + +/** +@class CSetupFog +@brief Dialog to edit the fog in a 3D scene. +*/ +class CSetupFog: public QDockWidget +{ + Q_OBJECT + +public: + CSetupFog(QWidget *parent = 0); + ~CSetupFog(); + +private Q_SLOTS: + void apply(); + void setColor(); +private: + NLMISC::CRGBA colorFog; + + Ui::CSetupFog ui; + +}; /* class CSetupFog */ + +} /* namespace NLQT */ + +#endif // SETUP_FOG_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/setup_fog_form.ui b/code/nel/tools/3d/object_viewer_qt/src/setup_fog_form.ui new file mode 100644 index 000000000..463cf114a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/setup_fog_form.ui @@ -0,0 +1,242 @@ + + + CSetupFog + + + + 0 + 0 + 135 + 200 + + + + + 135 + 200 + + + + QDockWidget::AllDockWidgetFeatures + + + Setup fog + + + + + + + true + + + + + 0 + 0 + 115 + 159 + + + + + + + + + Start: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + 10000.000000000000000 + + + + + + + + + + + End: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + 2 + + + 100000.000000000000000 + + + 100.000000000000000 + + + + + + + + + Enable fog + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Color + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Apply + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 17 + 62 + + + + + + + + + + + + + + + enableFogCheckBox + toggled(bool) + applyPushButton + click() + + + 24 + 103 + + + 106 + 164 + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/skeleton_scale_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/skeleton_scale_dialog.cpp new file mode 100644 index 000000000..b40a0752f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/skeleton_scale_dialog.cpp @@ -0,0 +1,771 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "skeleton_scale_dialog.h" + +// Qt include +#include +#include + +// NeL includes +#include +#include +#include +#include + +// Project includes +#include "modules.h" +#include "skeleton_tree_model.h" + +namespace NLQT { + +const int ssd_scale_precision = 1000; + +CSkeletonScaleDialog::CSkeletonScaleDialog(CSkeletonTreeModel *model, QWidget *parent) + : QDockWidget(parent), _Skeleton(NULL) +{ + _ui.setupUi(this); + + _SaveDirty= false; + + // avoid realloc + _UndoQueue.resize(MaxUndoRedo); + _RedoQueue.resize(MaxUndoRedo); + _UndoQueue.clear(); + _RedoQueue.clear(); + + _BoneBBoxNeedRecompute= false; + + _ui.treeView->setModel(model); + + connect(model, SIGNAL(modelReset()), this, SLOT(resetSkeleton())); + + connect(_ui.treeView, SIGNAL(clicked(QModelIndex)), this, SLOT(setCurrentBone(QModelIndex))); + connect(_ui.xBoneHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setBoneSliderX(int))); + connect(_ui.yBoneHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setBoneSliderY(int))); + connect(_ui.zBoneHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setBoneSliderZ(int))); + connect(_ui.xSkinHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setSkinSliderX(int))); + connect(_ui.ySkinHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setSkinSliderY(int))); + connect(_ui.zSkinHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setSkinSliderZ(int))); + + connect(_ui.xBoneHorizontalSlider, SIGNAL(sliderReleased()), this, SLOT(sliderReleased())); + connect(_ui.yBoneHorizontalSlider, SIGNAL(sliderReleased()), this, SLOT(sliderReleased())); + connect(_ui.zBoneHorizontalSlider, SIGNAL(sliderReleased()), this, SLOT(sliderReleased())); + connect(_ui.xSkinHorizontalSlider, SIGNAL(sliderReleased()), this, SLOT(sliderReleased())); + connect(_ui.ySkinHorizontalSlider, SIGNAL(sliderReleased()), this, SLOT(sliderReleased())); + connect(_ui.zSkinHorizontalSlider, SIGNAL(sliderReleased()), this, SLOT(sliderReleased())); + + connect(_ui.undoPushButton, SIGNAL(clicked()), this, SLOT(clickUndo())); + connect(_ui.redoPushButton, SIGNAL(clicked()), this, SLOT(clickRedo())); + connect(_ui.mirrorPushButton, SIGNAL(clicked()), this, SLOT(clickMirrorSelected())); + connect(_ui.saveAsSkelPushButton, SIGNAL(clicked()), this, SLOT(clickSaveAsSkel())); + connect(_ui.saveSkelPushButton, SIGNAL(clicked()), this, SLOT(clickSaveSkel())); + connect(_ui.saveScalePushButton, SIGNAL(clicked()), this, SLOT(clickSaveScale())); + connect(_ui.loadScalePushButton, SIGNAL(clicked()), this, SLOT(clickLoadScale())); +} + +CSkeletonScaleDialog::~CSkeletonScaleDialog() +{ +} + +void CSkeletonScaleDialog::setCurrentShape(const QString &name) +{ + _ui.treeView->expandAll(); + + if (name.isEmpty()) + return; + + _Skeleton = Modules::objView().getEntity(name.toStdString()).getSkeleton(); + _SkeletonFileName = Modules::objView().getEntity(name.toStdString()).getFileNameSkeleton(); + + // Setup Bone mirror + _Bones.clear(); + if(!_Skeleton.empty()) + { + _Bones.resize(_Skeleton.getNumBones()); + + // copy from skel to mirror + applySkeletonToMirror(); + + _ui.boneGroupBox->setEnabled(true); + _ui.skinGroupBox->setEnabled(true); + _ui.buttonsGroupBox->setEnabled(true); + } + + // reset bone bbox here + _BoneBBoxes.clear(); + _BoneBBoxes.resize(_Bones.size()); + + // delegate to drawSelection(), cause skins not still bound + _BoneBBoxNeedRecompute= true; + + // clean undo/redo + _UndoQueue.clear(); + _RedoQueue.clear(); + refreshUndoRedoView(); + + // clear save button + _SaveDirty= false; + refreshSaveButton(); + _BkupBones = _Bones; +} + +void CSkeletonScaleDialog::setCurrentBone(const QModelIndex & index) +{ + CSkeletonTreeItem *currentItem = static_cast(index.internalPointer()); + + // bkup for undo + static TBoneMirrorArray precState; + precState = _Bones; + + // TODO: multiple selection + for(size_t i = 0; i < _Bones.size(); i++) + _Bones[i].Selected= false; + + _Bones[currentItem->getId()].Selected = true; + + // undo-redo + // selection change => no need to dirt save + pushUndoState(precState, false); + + // refresh text views + updateBoneValues(); +} + +void CSkeletonScaleDialog::setBoneSliderX(int value) +{ + applyScaleSlider(value, SidBoneX); +} + +void CSkeletonScaleDialog::setBoneSliderY(int value) +{ + applyScaleSlider(value, SidBoneY); +} + +void CSkeletonScaleDialog::setBoneSliderZ(int value) +{ + applyScaleSlider(value, SidBoneZ); +} + +void CSkeletonScaleDialog::setSkinSliderX(int value) +{ + applyScaleSlider(value, SidSkinX); +} + +void CSkeletonScaleDialog::setSkinSliderY(int value) +{ + applyScaleSlider(value, SidSkinY); +} + +void CSkeletonScaleDialog::setSkinSliderZ(int value) +{ + applyScaleSlider(value, SidSkinZ); +} + +void CSkeletonScaleDialog::sliderReleased() +{ + // Bkup all scales (dont bother selected bones or which scale is edited...) + _BkupBones = _Bones; + + // push an undo/redo only at release of slide. push the value of scale before slide + // change => must save + pushUndoState(_BkupBones, true); + _SaveDirty = true; + refreshSaveButton(); + + _ui.xBoneHorizontalSlider->setValue(100); + _ui.yBoneHorizontalSlider->setValue(100); + _ui.zBoneHorizontalSlider->setValue(100); + _ui.xSkinHorizontalSlider->setValue(100); + _ui.ySkinHorizontalSlider->setValue(100); + _ui.zSkinHorizontalSlider->setValue(100); +} + +void CSkeletonScaleDialog::clickMirrorSelected() +{ + // bkup for undo + static TBoneMirrorArray precState; + precState = _Bones; + nlassert(!_Skeleton.empty()); + + // for each bone selected + bool change= false; + for(uint i=0;i<_Bones.size();i++) + { + CBoneMirror &bone= _Bones[i]; + if(bone.Selected) + { + // get the bone side and mirrored name + std::string mirrorName; + sint side = getBoneForMirror(i, mirrorName); + // if not a "centered" bone + if(side!=0) + { + // get the bone with mirrored name + sint mirrorId = _Skeleton.getBoneIdByName(mirrorName); + if(mirrorId<0) + { + nlinfo("MirrorScale: Didn't found %s", mirrorName.c_str()); + } + else + { + // copy setup from the dest bone + nlassert(mirrorId<(sint)_Bones.size()); + _Bones[mirrorId].BoneScale= bone.BoneScale; + _Bones[mirrorId].SkinScale= bone.SkinScale; + } + } + } + } + + // refresh display + applyMirrorToSkeleton(); + updateBoneValues(); + + // if some change, bkup for undo/redo + pushUndoState(precState, true); +} + +void CSkeletonScaleDialog::clickUndo() +{ + undo(); +} + +void CSkeletonScaleDialog::clickRedo() +{ + redo(); +} + +void CSkeletonScaleDialog::clickSaveSkel() +{ + // if no skeleton edited, quit + if(_Skeleton.empty()) + return; + + // save the file + NLMISC::COFile f; + if( f.open(_SkeletonFileName) ) + { + if(saveCurrentInStream(f)) + { + // no more need to save (done) + _SaveDirty= false; + refreshSaveButton(); + } + } + else + { + QMessageBox::critical(this, tr("Skeleton scale editor"), tr("Failed to open file for write!"), QMessageBox::Ok); + } +} + +void CSkeletonScaleDialog::clickSaveAsSkel() +{ + // if no skeleton edited, quit + if(_Skeleton.empty()) + return; + + QString fileName = QFileDialog::getSaveFileName(this, tr("Save As Skeleton File"), + ".", + tr("Skeleton files (*.skel);;")); + if (!fileName.isEmpty()) + { + NLMISC::COFile f; + + if( f.open(fileName.toStdString()) ) + { + if(saveCurrentInStream(f)) + { + // no more need to save (done) + _SaveDirty= false; + refreshSaveButton(); + } + + // bkup the valid fileName (new file edited) + _SkeletonFileName = fileName.toStdString(); + } + else + { + QMessageBox::critical(this, tr("Skeleton scale editor"), tr("Failed to open file for write!"), QMessageBox::Ok); + } + } +} + +void CSkeletonScaleDialog::clickLoadScale() +{ + // if no skeleton edited, quit + if(_Skeleton.empty()) + return; + + // choose the file + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open Skeleton Scale File"), ".", + tr("SkelScale files (*.scale);;")); + + setCursor(Qt::WaitCursor); + if (!fileName.isEmpty()) + { + NLMISC::CIFile f; + if( f.open(fileName.toStdString()) ) + loadSkelScaleFromStream(f); + else + QMessageBox::critical(this, tr("Skeleton scale editor"), tr("Failed to open file for read!"), QMessageBox::Ok); + } + setCursor(Qt::ArrowCursor); +} + +void CSkeletonScaleDialog::clickSaveScale() +{ + // if no skeleton edited, quit + if(_Skeleton.empty()) + return; + + // choose the file + QString fileName = QFileDialog::getSaveFileName(this, tr("Save As Skeleton Scale File"), + ".", + tr("SkelScale files (*.scale);;")); + if (!fileName.isEmpty()) + { + NLMISC::COFile f; + if( f.open(fileName.toStdString()) ) + saveSkelScaleInStream(f); + else + QMessageBox::critical(this, tr("Skeleton scale editor"), tr("Failed to open file for write!"), QMessageBox::Ok); + } +} + +void CSkeletonScaleDialog::resetSkeleton() +{ + _ui.boneGroupBox->setEnabled(false); + _ui.skinGroupBox->setEnabled(false); + _ui.buttonsGroupBox->setEnabled(false); + _Skeleton = NULL; +} + +void CSkeletonScaleDialog::updateBoneValues() +{ + // 1.f for each component if multiple selection is different, else 0.f + NLMISC::CVector boneScaleDiff = NLMISC::CVector::Null; + NLMISC::CVector skinScaleDiff = NLMISC::CVector::Null; + + // valid if scale of each bone component is same + NLMISC::CVector boneScaleAll = NLMISC::CVector::Null; + NLMISC::CVector skinScaleAll = NLMISC::CVector::Null; + bool someSelected = false; + + // For all bones selected + for(uint i = 0; i < _Bones.size(); i++) + { + CBoneMirror &bone= _Bones[i]; + if(bone.Selected) + { + if(!someSelected) + { + someSelected= true; + // just bkup + boneScaleAll= bone.BoneScale; + skinScaleAll= bone.SkinScale; + } + else + { + // compare each component, if different, flag + if(boneScaleAll.x!= bone.BoneScale.x) boneScaleDiff.x= 1.f; + if(boneScaleAll.y!= bone.BoneScale.y) boneScaleDiff.y= 1.f; + if(boneScaleAll.z!= bone.BoneScale.z) boneScaleDiff.z= 1.f; + if(skinScaleAll.x!= bone.SkinScale.x) skinScaleDiff.x= 1.f; + if(skinScaleAll.y!= bone.SkinScale.y) skinScaleDiff.y= 1.f; + if(skinScaleAll.z!= bone.SkinScale.z) skinScaleDiff.z= 1.f; + } + } + } + + // if none selected, force empty text + if(!someSelected) + { + boneScaleDiff.set(1.f,1.f,1.f); + skinScaleDiff.set(1.f,1.f,1.f); + } + + // All component refresh or only one refresh? + refreshTextViewWithScale(_ui.xBoneDoubleSpinBox, boneScaleAll.x, boneScaleDiff.x); + refreshTextViewWithScale(_ui.yBoneDoubleSpinBox, boneScaleAll.y, boneScaleDiff.y); + refreshTextViewWithScale(_ui.zBoneDoubleSpinBox, boneScaleAll.z, boneScaleDiff.z); + refreshTextViewWithScale(_ui.xSkinDoubleSpinBox, skinScaleAll.x, skinScaleDiff.x); + refreshTextViewWithScale(_ui.ySkinDoubleSpinBox, skinScaleAll.y, skinScaleDiff.y); + refreshTextViewWithScale(_ui.zSkinDoubleSpinBox, skinScaleAll.z, skinScaleDiff.z); +} + +void CSkeletonScaleDialog::refreshTextViewWithScale(QDoubleSpinBox *spinBox, float scale, float diff) +{ + // if different values selected, diff + if(diff) + spinBox->setValue(0); + // else display text + else + spinBox->setValue(scale * 100 / ssd_scale_precision); +} + +void CSkeletonScaleDialog::applyScaleSlider(int scale, int idSelect) +{ + float factor = scale / 100.0; + // Apply the noise to each selected bones + for(uint i = 0; i < _Bones.size(); i++) + { + if( _Bones[i].Selected) + { + switch(idSelect) + { + case SidBoneX: _Bones[i].BoneScale.x = _BkupBones[i].BoneScale.x * factor; break; + case SidBoneY: _Bones[i].BoneScale.y = _BkupBones[i].BoneScale.y * factor; break; + case SidBoneZ: _Bones[i].BoneScale.z = _BkupBones[i].BoneScale.z * factor; break; + case SidSkinX: _Bones[i].SkinScale.x = _BkupBones[i].SkinScale.x * factor; break; + case SidSkinY: _Bones[i].SkinScale.y = _BkupBones[i].SkinScale.y * factor; break; + case SidSkinZ: _Bones[i].SkinScale.z = _BkupBones[i].SkinScale.z * factor; break; + }; + roundClampScale(_Bones[i].BoneScale); + roundClampScale(_Bones[i].SkinScale); + } + } + // update the skeleton view + applyMirrorToSkeleton(); + + // refresh text views + updateBoneValues(); +} + +void CSkeletonScaleDialog::applyMirrorToSkeleton() +{ + if(!_Skeleton.empty()) + { + nlassert(_Skeleton.getNumBones() == _Bones.size()); + for(uint i = 0; i < _Bones.size(); i++) + { + // unmul from precision + NLMISC::CVector boneScale = _Bones[i].BoneScale / ssd_scale_precision; + NLMISC::CVector skinScale = _Bones[i].SkinScale / ssd_scale_precision; + _Skeleton.getBone(i).setScale(boneScale); + _Skeleton.getBone(i).setSkinScale(skinScale); + } + } +} + +void CSkeletonScaleDialog::applySkeletonToMirror() +{ + if(!_Skeleton.empty()) + { + nlassert(_Skeleton.getNumBones() == _Bones.size()); + for(uint i = 0; i < _Skeleton.getNumBones(); i++) + { + // mul by precision, and round + _Bones[i].SkinScale = _Skeleton.getBone(i).getSkinScale() * ssd_scale_precision; + _Bones[i].BoneScale = _Skeleton.getBone(i).getScale() * ssd_scale_precision; + roundClampScale(_Bones[i].SkinScale); + roundClampScale(_Bones[i].BoneScale); + } + } +} + +void CSkeletonScaleDialog::roundClampScale(NLMISC::CVector &v) const +{ + v.x+= 0.5f; + v.y+= 0.5f; + v.z+= 0.5f; + v.x= (float)floor(v.x); + v.y= (float)floor(v.y); + v.z= (float)floor(v.z); + // Minimum is 1 (avoid 0 scale) + v.maxof(v, NLMISC::CVector(1.f,1.f,1.f)); +} + +void CSkeletonScaleDialog::refreshUndoRedoView() +{ + _ui.undoPushButton->setEnabled(!_UndoQueue.empty()); + _ui.redoPushButton->setEnabled(!_RedoQueue.empty()); +} + +void CSkeletonScaleDialog::applySelectionToView() +{ + _ui.treeView->blockSignals(true); + CSkeletonTreeModel *model = Modules::mainWin().getSkeletonModel(); + for(uint i = 0; i < _Bones.size(); i++) + { + if (_Bones[i].Selected) + _ui.treeView->setCurrentIndex(model->getIndexFromId(i, model->index(0, 0))); + } + _ui.treeView->blockSignals(false); +} + +sint CSkeletonScaleDialog::getBoneForMirror(uint boneId, std::string &mirrorName) +{ + sint side= 0; + std::string::size_type pos; + nlassert(!_Skeleton.empty() && (boneId < _Skeleton.getNumBones())); + mirrorName= _Skeleton.getBone(boneId).getObjectPtr()->getBoneName(); + + if((pos= mirrorName.find(" R "))!=std::string::npos) + { + side= 1; + mirrorName[pos+1]= 'L'; + } + else if((pos= mirrorName.find(" L "))!=std::string::npos) + { + side= -1; + mirrorName[pos+1]= 'R'; + } + + return side; +} + +void CSkeletonScaleDialog::refreshSaveButton() +{ + // SaveAs is always available + _ui.saveSkelPushButton->setEnabled(_SaveDirty); +} + +bool CSkeletonScaleDialog::saveCurrentInStream(NLMISC::IStream &f) +{ + try + { + nlassert(!_Skeleton.empty()); + nlassert(_Skeleton.getObjectPtr()->Shape); + + // Retrieve boneBase definition from the current skeleton + std::vector boneBases; + (NLMISC::safe_cast((NL3D::IShape*)_Skeleton.getObjectPtr()->Shape))->retrieve(boneBases); + + // Copies bone scales from the model + nlassert(boneBases.size() == _Skeleton.getNumBones()); + for(uint i = 0; i < _Skeleton.getNumBones(); i++) + { + NL3D::UBone bone = _Skeleton.getBone(i); + NL3D::CBoneBase &boneBase = boneBases[i]; + + boneBase.SkinScale = bone.getSkinScale(); + boneBase.DefaultScale = bone.getScale(); + } + + // build a new Skeleton shape + NL3D::CSkeletonShape *skelShape= new NL3D::CSkeletonShape; + skelShape->build(boneBases); + + // save + NL3D::CShapeStream ss; + ss.setShapePointer(skelShape); + ss.serial(f); + delete skelShape; + } + catch(NLMISC::EStream &) + { + QMessageBox::critical(this, tr("Skeleton scale editor"), tr("Failed to save file!"), QMessageBox::Ok); + return false; + } + + return true; +} + +struct CBoneScaleInfo +{ + std::string Name; + NLMISC::CVector Scale; + NLMISC::CVector SkinScale; + + void serial(NLMISC::IStream &f) + { + sint32 ver= f.serialVersion(0); + f.serial(Name, Scale, SkinScale); + } +}; + +bool CSkeletonScaleDialog::saveSkelScaleInStream(NLMISC::IStream &f) +{ + try + { + nlassert(!_Skeleton.empty()); + + // Copies bone scales from the model + std::vector boneScales; + boneScales.resize(_Skeleton.getNumBones()); + for(uint i = 0; i < boneScales.size(); i++) + { + NL3D::CBone *bone= _Skeleton.getBone(i).getObjectPtr(); + CBoneScaleInfo &boneScale= boneScales[i]; + + // get scale info from current edited skeleton + boneScale.Name = bone->getBoneName(); + boneScale.Scale = bone->getScale(); + boneScale.SkinScale = bone->getSkinScale(); + } + + // save the file + sint32 ver= f.serialVersion(0); + f.serialCont(boneScales); + } + catch(NLMISC::EStream &) + { + QMessageBox::critical(this, tr("Skeleton scale editor"), tr("Failed to save file!"), QMessageBox::Ok); + return false; + } + + return true; +} + +bool CSkeletonScaleDialog::loadSkelScaleFromStream(NLMISC::IStream &f) +{ + try + { + nlassert(!_Skeleton.empty()); + + // load the file + sint32 ver= f.serialVersion(0); + std::vector boneScales; + f.serialCont(boneScales); + + // apply to the current skeleton + for(uint i = 0; i < boneScales.size(); i++) + { + sint32 boneId = _Skeleton.getBoneIdByName(boneScales[i].Name); + if(boneId >= 0 && boneId < (sint32)_Skeleton.getNumBones()) + { + CBoneScaleInfo &boneScale= boneScales[i]; + _Skeleton.getBone(boneId).setScale(boneScale.Scale); + _Skeleton.getBone(boneId).setSkinScale(boneScale.SkinScale); + } + } + + // Bkup _Bones, for undo + static TBoneMirrorArray precState; + precState = _Bones; + + // Then reapply to the mirror + applySkeletonToMirror(); + + // change => must save + pushUndoState(precState, true); + + // and update display + updateBoneValues(); + } + catch(NLMISC::EStream &) + { + QMessageBox::critical(this, tr("Skeleton scale editor"), tr("Failed to load file!"), QMessageBox::Ok); + return false; + } + + return true; +} + +void CSkeletonScaleDialog::pushUndoState(const TBoneMirrorArray &precState, bool dirtSave) +{ + // test if real change + nlassert(precState.size() == _Bones.size()); + bool change = false; + for(uint i = 0; i < _Bones.size(); i++) + { + if( _Bones[i].BoneScale!=precState[i].BoneScale || + _Bones[i].SkinScale!=precState[i].SkinScale || + _Bones[i].Selected!=precState[i].Selected) + { + change= true; + break; + } + } + // no change? no op + if(!change) + return; + + // then bkup for undo + // change => the redo list is lost + _RedoQueue.clear(); + + // if not enough space, the last undo is lost + if(_UndoQueue.size() == size_t(MaxUndoRedo)) + _UndoQueue.pop_front(); + + // add the precedent state to the undo queue + _UndoQueue.push_back(precState); + + // refresh buttons + refreshUndoRedoView(); + + // refresh save button + if(dirtSave && !_SaveDirty) + { + _SaveDirty = true; + refreshSaveButton(); + } +} + +void CSkeletonScaleDialog::undo() +{ + nlassert(_UndoQueue.size() + _RedoQueue.size() <= size_t(MaxUndoRedo)); + + // is some undoable + if(_UndoQueue.size()) + { + // current goes into the redo queue + _RedoQueue.push_front(_Bones); + // restore + _Bones= _UndoQueue.back(); + // pop + _UndoQueue.pop_back(); + + // refresh display + applyMirrorToSkeleton(); + updateBoneValues(); + applySelectionToView(); + + // refresh buttons + refreshUndoRedoView(); + + // change => must save + _SaveDirty= true; + refreshSaveButton(); + } +} + +void CSkeletonScaleDialog::redo() +{ + nlassert(_UndoQueue.size() + _RedoQueue.size() <= size_t(MaxUndoRedo)); + + // is some redoable + if(_RedoQueue.size()) + { + // current goes into the undo queue + _UndoQueue.push_back(_Bones); + // restore + _Bones= _RedoQueue.front(); + // pop + _RedoQueue.pop_front(); + + // refresh display + applyMirrorToSkeleton(); + updateBoneValues(); + applySelectionToView(); + + // refresh buttons + refreshUndoRedoView(); + + // change => must save + _SaveDirty= true; + refreshSaveButton(); + } +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/skeleton_scale_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/skeleton_scale_dialog.h new file mode 100644 index 000000000..91a9b7c96 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/skeleton_scale_dialog.h @@ -0,0 +1,159 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef SKELETON_SCALE_DIALOG_H +#define SKELETON_SCALE_DIALOG_H + +#include "ui_skeleton_scale_form.h" + +// STL includes + +// NeL includes +#include "nel/misc/smart_ptr.h" +#include "nel/misc/stream.h" +#include "nel/misc/vector.h" +#include "nel/misc/aabbox.h" +#include + +// Project includes +#include "skeleton_tree_model.h" + +namespace NLQT { + +/// A mirror to the list of bone +struct CBoneMirror +{ + CBoneMirror() + { + SkinScale= BoneScale= NLMISC::CVector(1.f,1.f,1.f); + Selected= false; + } + + /// Current Scale * ssd_scale_precision, and rounded + NLMISC::CVector SkinScale; + NLMISC::CVector BoneScale; + + /// If the bone is selected in the multi List + bool Selected; +}; + +typedef std::vector TBoneMirrorArray; + +/** +@class CSkeletonScaleDialog +@brief Dialog to edit the skeleton. +*/ +class CSkeletonScaleDialog: public QDockWidget +{ + Q_OBJECT + +public: + CSkeletonScaleDialog(CSkeletonTreeModel *model, QWidget *parent = 0); + ~CSkeletonScaleDialog(); + + /// call each frame to display scaled bboxes around selected bones + void drawSelection(); + +public Q_SLOTS: + /// needs called when the changes current edited skeleton + void setCurrentShape(const QString &name); + +private Q_SLOTS: + void setCurrentBone(const QModelIndex & index); + void setBoneSliderX(int value); + void setBoneSliderY(int value); + void setBoneSliderZ(int value); + void setSkinSliderX(int value); + void setSkinSliderY(int value); + void setSkinSliderZ(int value); + void sliderReleased(); + void clickMirrorSelected(); + void clickUndo(); + void clickRedo(); + void clickSaveSkel(); + void clickSaveAsSkel(); + void clickLoadScale(); + void clickSaveScale(); + void resetSkeleton(); + +private: + void updateBoneValues(); + void refreshTextViewWithScale(QDoubleSpinBox *spinBox, float scale, float diff); + void applyScaleSlider(int scale, int idSelect); + void applyMirrorToSkeleton(); + void applySkeletonToMirror(); + void roundClampScale(NLMISC::CVector &v) const; + void refreshUndoRedoView(); + void applySelectionToView(); + sint getBoneForMirror(uint boneId, std::string &mirrorName); + bool saveCurrentInStream(NLMISC::IStream &f); + void refreshSaveButton(); + bool saveSkelScaleInStream(NLMISC::IStream &f); + bool loadSkelScaleFromStream(NLMISC::IStream &f); + + /// bkup the current _Bones in the undo queue, and clear the redo. dirtSave indicate the skel need saving + /// NB: compare precState with _Bones. if same, then no-op! + void pushUndoState(const TBoneMirrorArray &precState, bool dirtSave); + + /// undo the last change, and store it in the redo queue + void undo(); + + /// redo the last undoed change, and restore it in the undo queue + void redo(); + + enum TScaleId + { + SidBoneX = 0, + SidBoneY, + SidBoneZ, + SidSkinX, + SidSkinY, + SidSkinZ, + SidCount, + SidNone = SidCount + }; + + NL3D::USkeleton _Skeleton; + + std::string _SkeletonFileName; + + // The current bones + TBoneMirrorArray _Bones; + + // Backup of bones when slider start moving + TBoneMirrorArray _BkupBones; + + bool _SaveDirty; + + // For selection drawing, the local bbox + std::vector _BoneBBoxes; + bool _BoneBBoxNeedRecompute; + + std::deque _UndoQueue; + std::deque _RedoQueue; + + static const int MaxUndoRedo = 100; + + Ui::CSkeletonScaleDialog _ui; + +}; /* class CSkeletonScaleDialog */ + +} /* namespace NLQT */ + +#endif // SKELETON_SCALE_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/skeleton_scale_form.ui b/code/nel/tools/3d/object_viewer_qt/src/skeleton_scale_form.ui new file mode 100644 index 000000000..28fed61de --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/skeleton_scale_form.ui @@ -0,0 +1,633 @@ + + + CSkeletonScaleDialog + + + + 0 + 0 + 306 + 694 + + + + Skeleton scale edition + + + + + + + true + + + true + + + + + + + false + + + Bone scale + + + + + + X: + + + + + + + true + + + QAbstractSpinBox::NoButtons + + + % + + + 10000.000000000000000 + + + + + + + 50 + + + 200 + + + 100 + + + Qt::Horizontal + + + false + + + + + + + + 16777215 + 16777215 + + + + true + + + QAbstractSpinBox::NoButtons + + + % + + + 50 + + + 200 + + + 100 + + + + + + + Y: + + + + + + + true + + + QAbstractSpinBox::NoButtons + + + % + + + 10000.000000000000000 + + + + + + + 50 + + + 200 + + + 100 + + + Qt::Horizontal + + + + + + + + 16777215 + 16777215 + + + + true + + + QAbstractSpinBox::NoButtons + + + % + + + 50 + + + 200 + + + 100 + + + + + + + Z: + + + + + + + false + + + true + + + QAbstractSpinBox::NoButtons + + + % + + + 10000.000000000000000 + + + + + + + 50 + + + 200 + + + 100 + + + Qt::Horizontal + + + + + + + + 16777215 + 16777215 + + + + true + + + QAbstractSpinBox::NoButtons + + + % + + + 50 + + + 200 + + + 100 + + + + + + + + + + false + + + Skin scale (slower) + + + + + + X: + + + + + + + true + + + QAbstractSpinBox::NoButtons + + + % + + + 10000.000000000000000 + + + + + + + 50 + + + 200 + + + 100 + + + Qt::Horizontal + + + false + + + + + + + + 16777215 + 16777215 + + + + true + + + QAbstractSpinBox::NoButtons + + + % + + + 50 + + + 200 + + + 100 + + + + + + + + 16777215 + 16777215 + + + + true + + + QAbstractSpinBox::NoButtons + + + % + + + 50 + + + 200 + + + 100 + + + + + + + Y: + + + + + + + true + + + QAbstractSpinBox::NoButtons + + + % + + + 10000.000000000000000 + + + + + + + 50 + + + 200 + + + 100 + + + Qt::Horizontal + + + + + + + Z: + + + + + + + false + + + true + + + QAbstractSpinBox::NoButtons + + + % + + + 10000.000000000000000 + + + + + + + 50 + + + 200 + + + 100 + + + Qt::Horizontal + + + + + + + + 16777215 + 16777215 + + + + true + + + QAbstractSpinBox::NoButtons + + + % + + + 50 + + + 200 + + + 100 + + + + + + + + + + false + + + + + + + + + + + Mirror selected + + + + + + + Undo + + + + + + + Redo + + + + + + + Save .skel + + + + + + + Save as + + + + + + + Load .scale + + + + + + + Save .scale + + + + + + + + + + + + + + + xBoneHorizontalSlider + valueChanged(int) + spinBox_4 + setValue(int) + + + 188 + 312 + + + 231 + 320 + + + + + yBoneHorizontalSlider + valueChanged(int) + spinBox_5 + setValue(int) + + + 207 + 337 + + + 240 + 340 + + + + + zBoneHorizontalSlider + valueChanged(int) + spinBox_6 + setValue(int) + + + 207 + 358 + + + 240 + 366 + + + + + xSkinHorizontalSlider + valueChanged(int) + spinBox + setValue(int) + + + 207 + 431 + + + 272 + 438 + + + + + ySkinHorizontalSlider + valueChanged(int) + spinBox_2 + setValue(int) + + + 207 + 462 + + + 267 + 467 + + + + + zSkinHorizontalSlider + valueChanged(int) + spinBox_3 + setValue(int) + + + 207 + 491 + + + 233 + 493 + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/skeleton_tree_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/skeleton_tree_model.cpp new file mode 100644 index 000000000..591ff59c1 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/skeleton_tree_model.cpp @@ -0,0 +1,197 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "skeleton_tree_model.h" + +// NeL include +#include +#include + +// Project includes +#include "modules.h" + +namespace NLQT { + +CSkeletonTreeModel::CSkeletonTreeModel(QObject *parent) + : QAbstractItemModel(parent) +{ + QList rootData; + rootData << "Skeleton"; + _rootItem = new CSkeletonTreeItem(rootData, -1); +} + +CSkeletonTreeModel::~CSkeletonTreeModel() +{ + delete _rootItem; +} + +int CSkeletonTreeModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return static_cast(parent.internalPointer())->columnCount(); + else + return _rootItem->columnCount(); +} + +QVariant CSkeletonTreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role != Qt::DisplayRole) + return QVariant(); + + CSkeletonTreeItem *item = static_cast(index.internalPointer()); + + return item->data(index.column()); +} + +Qt::ItemFlags CSkeletonTreeModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +QVariant CSkeletonTreeModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return _rootItem->data(section); + + return QVariant(); +} + +QModelIndex CSkeletonTreeModel::index(int row, int column, const QModelIndex &parent) + const +{ + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + CSkeletonTreeItem *parentItem; + + if (!parent.isValid()) + parentItem = _rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + CSkeletonTreeItem *childItem = parentItem->child(row); + if (childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} + +QModelIndex CSkeletonTreeModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + CSkeletonTreeItem *childItem = static_cast(index.internalPointer()); + CSkeletonTreeItem *parentItem = childItem->parent(); + + if (parentItem == _rootItem) + return QModelIndex(); + + return createIndex(parentItem->row(), 0, parentItem); +} + +int CSkeletonTreeModel::rowCount(const QModelIndex &parent) const +{ + CSkeletonTreeItem *parentItem; + if (parent.column() > 0) + return 0; + + if (!parent.isValid()) + parentItem = _rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + return parentItem->childCount(); +} + +void CSkeletonTreeModel::rebuildModel() +{ + std::string curObj = Modules::objView().getCurrentObject(); + + NL3D::USkeleton skel = Modules::objView().getEntity(curObj).getSkeleton(); + + if (skel.empty()) + { + resetTreeModel(); + return; + } + + beginResetModel(); + delete _rootItem; + + QList rootData; + rootData << curObj.c_str(); + + _rootItem = new CSkeletonTreeItem(rootData, -1); + + CSkeletonTreeItem *parentItem = _rootItem; + + for (uint i = 0; i < skel.getNumBones(); i++) + { + NL3D::UBone bone = skel.getBone(i); + sint32 parentId = bone.getObjectPtr()->getFatherId(); + + while(parentId != parentItem->getId()) + parentItem = parentItem->parent(); + + QList boneData; + boneData << bone.getObjectPtr()->getBoneName().c_str(); + CSkeletonTreeItem *item = new CSkeletonTreeItem(boneData, i, parentItem); + parentItem->appendChild(item); + parentItem = item; + } + + endResetModel(); +} + +void CSkeletonTreeModel::resetTreeModel() +{ + beginResetModel(); + delete _rootItem; + QList rootData; + rootData << "Skeleton"; + _rootItem = new CSkeletonTreeItem(rootData, -1); + endResetModel(); +} + +QModelIndex CSkeletonTreeModel::getIndexFromId(sint id, const QModelIndex &parent) +{ + QModelIndex currentIndex = parent; + CSkeletonTreeItem *item = static_cast(parent.internalPointer()); + if (item->getId() != id) + for (int i = 0; i < item->childCount(); i++) + { + currentIndex = getIndexFromId(id, index(i, 0, parent)); + CSkeletonTreeItem *item = static_cast(currentIndex.internalPointer()); + if (item->getId() == id) + return currentIndex; + } + return currentIndex; +} + + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/skeleton_tree_model.h b/code/nel/tools/3d/object_viewer_qt/src/skeleton_tree_model.h new file mode 100644 index 000000000..ad038cef6 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/skeleton_tree_model.h @@ -0,0 +1,109 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef SKELETON_TREE_MODEL_H +#define SKELETON_TREE_MODEL_H + + +// Qt includes +#include +#include +#include +#include +#include + +// NeL includes +#include "nel/misc/types_nl.h" + +// Projects includes + +namespace NLQT { + +/** +@class CSkeletonTreeItem +@brief Basic elements tree model skeleton. +*/ +class CSkeletonTreeItem +{ +public: + CSkeletonTreeItem(const QList &data, const sint32 id, CSkeletonTreeItem *parent = 0) + : _itemData(data), _id(id), _parentItem(parent) {} + + ~CSkeletonTreeItem() { qDeleteAll(_childItems); } + + void appendChild(CSkeletonTreeItem *child) { _childItems.append(child); } + + CSkeletonTreeItem *child(int row) { return _childItems.value(row); } + int childCount() const { return _childItems.count(); } + int columnCount() const { return _itemData.count(); } + QVariant data(int column) const { return _itemData.value(column); } + + int row() const { if (_parentItem) + return _parentItem->_childItems.indexOf(const_cast(this)); + return 0; } + + CSkeletonTreeItem *parent() { return _parentItem; } + sint32 getId() { return _id; } + +private: + + QList _childItems; + QList _itemData; + sint32 _id; + CSkeletonTreeItem *_parentItem; +}; + +/** +@class CSkeletonTreeModel +@brief Tree model skeleton. +*/ +class CSkeletonTreeModel : public QAbstractItemModel +{ + Q_OBJECT +public: + CSkeletonTreeModel(QObject *parent = 0); + ~CSkeletonTreeModel(); + + QVariant data(const QModelIndex &index, int role) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QModelIndex getIndexFromId(sint id, const QModelIndex &parent); + + /// Clear tree model skeleton + void resetTreeModel(); + +public Q_SLOTS: + + /// Update tree model skeleton + void rebuildModel(); + +private: + + CSkeletonTreeItem *_rootItem; +}; + +} /* namespace NLQT */ + +#endif // SKELETON_TREE_MODEL_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/slot_form.ui b/code/nel/tools/3d/object_viewer_qt/src/slot_form.ui new file mode 100644 index 000000000..e058d5145 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/slot_form.ui @@ -0,0 +1,249 @@ + + + CSlotGroupBox + + + + 0 + 0 + 265 + 358 + + + + + 99999 + 9999 + + + + GroupBox + + + Slot _:empty + + + false + + + + + + + + QFrame::NoFrame + + + Start blend + + + + + + + 1 + + + + + + + End blend + + + + + + + 1 + + + + + + + Offset frame + + + + + + + 99999 + + + + + + + Speed x + + + + + + + 0.010000000000000 + + + 100.000000000000000 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + Start frame + + + + + + + 999999 + + + + + + + End frame + + + + + + + 999999 + + + + + + + Smooth + + + + + + + 1 + + + + + + + + + + + Wrap mode: + + + + + + + Clamp + + + true + + + + + + + Repeat + + + + + + + Disable + + + + + + + + + + + + 0 + 0 + + + + Set anim + + + + + + + + 0 + 0 + + + + Set skel + + + + + + + true + + + + 0 + 0 + + + + Align blend + + + + + + + + + + + Enable + + + true + + + + + + + Invert skeleton weight + + + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/slot_manager_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/slot_manager_dialog.cpp new file mode 100644 index 000000000..9cf6a50ca --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/slot_manager_dialog.cpp @@ -0,0 +1,284 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "slot_manager_dialog.h" + +// Qt includes +#include + +// NeL includes + +// Project includes +#include "modules.h" + +namespace NLQT { + +CSlotGroupBox::CSlotGroupBox(QWidget *parent) + : QGroupBox(parent), + _animName("empty"), _skelName("empty"), _numSlot(0) +{ + _ui.setupUi(this); + + connect(_ui.animPushButton, SIGNAL(clicked()), this, SLOT(selectAnim())); + connect(_ui.skelPushButton, SIGNAL(clicked()), this, SLOT(selectSkel())); + connect(_ui.alignBlendPushButton, SIGNAL(clicked()), this, SLOT(alignAblend())); + connect(_ui.clampRadioButton, SIGNAL(clicked()), this, SLOT(saveSlotInfo())); + connect(_ui.repeatRadioButton, SIGNAL(clicked()), this, SLOT(saveSlotInfo())); + connect(_ui.disableRadioButton, SIGNAL(clicked()), this, SLOT(saveSlotInfo())); + connect(_ui.invSkelWeightCheckBox, SIGNAL(clicked()), this, SLOT(saveSlotInfo())); + connect(_ui.endBlendSpinBox, SIGNAL(valueChanged(int)), this, SLOT(saveSlotInfo())); + connect(_ui.endFrameSpinBox, SIGNAL(valueChanged(int)), this, SLOT(saveSlotInfo())); + connect(_ui.offsetSpinBox, SIGNAL(valueChanged(int)), this, SLOT(saveSlotInfo())); + connect(_ui.smoothSpinBox, SIGNAL(valueChanged(int)), this, SLOT(saveSlotInfo())); + connect(_ui.speedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(saveSlotInfo())); + connect(_ui.startBlendSpinBox, SIGNAL(valueChanged(int)), this, SLOT(saveSlotInfo())); + connect(_ui.startFrameSpinBox, SIGNAL(valueChanged(int)), this, SLOT(saveSlotInfo())); + connect(_ui.enableCheckBox, SIGNAL(clicked()), this, SLOT(saveSlotInfo())); +} + +CSlotGroupBox::~CSlotGroupBox() +{ +} + +void CSlotGroupBox::updateUi() +{ + std::string curObj = Modules::objView().getCurrentObject(); + if (curObj.empty()) + { + resetUi(); + return; + } + CEntity &entity = Modules::objView().getEntity(curObj); + CSlotInfo slotInfo = entity.getSlotInfo(_numSlot); + + _ui.offsetSpinBox->setValue(slotInfo.Offset * Modules::mainWin().getFrameRate()); + _ui.startBlendSpinBox->setValue(int(slotInfo.StartBlend)); + _ui.endBlendSpinBox->setValue(int(slotInfo.EndBlend)); + _ui.startFrameSpinBox->setValue(int(slotInfo.StartTime * Modules::mainWin().getFrameRate())); + _ui.endFrameSpinBox->setValue(int(slotInfo.EndTime * Modules::mainWin().getFrameRate())); + _ui.speedDoubleSpinBox->setValue(slotInfo.SpeedFactor); + _ui.smoothSpinBox->setValue(int(slotInfo.Smoothness)); + + if (slotInfo.SkeletonInverted) + _ui.invSkelWeightCheckBox->setCheckState(Qt::Checked); + else + _ui.invSkelWeightCheckBox->setCheckState(Qt::Unchecked); + + if (slotInfo.Enable) + _ui.enableCheckBox->setCheckState(Qt::Checked); + else + _ui.enableCheckBox->setCheckState(Qt::Unchecked); + + switch (slotInfo.ClampMode) + { + case 0: + _ui.clampRadioButton->setChecked(true); + break; + case 1: + _ui.repeatRadioButton->setChecked(true); + break; + case 2: + _ui.disableRadioButton->setChecked(true); + break; + } + + _animName = QString(slotInfo.Animation.c_str()); + _skelName = QString(slotInfo.Skeleton.c_str()); + QString title = tr("Slot %1 : ").arg(_numSlot) + _animName + " : " + _skelName; + this->setTitle(title); +} + +void CSlotGroupBox::saveSlotInfo() +{ + CSlotInfo slotInfo; + slotInfo.Animation = _animName.toStdString(); + slotInfo.Skeleton = _skelName.toStdString(); + slotInfo.EndBlend = _ui.endBlendSpinBox->value(); + slotInfo.EndTime = float(_ui.endFrameSpinBox->value()) / Modules::mainWin().getFrameRate(); + slotInfo.Offset = float(_ui.offsetSpinBox->value()) / Modules::mainWin().getFrameRate(); + slotInfo.Smoothness = _ui.smoothSpinBox->value(); + slotInfo.SpeedFactor = _ui.speedDoubleSpinBox->value(); + slotInfo.StartBlend = _ui.startBlendSpinBox->value(); + slotInfo.StartTime = float(_ui.startFrameSpinBox->value()) / Modules::mainWin().getFrameRate(); + + if (_ui.invSkelWeightCheckBox->checkState() == Qt::Checked) + slotInfo.SkeletonInverted = true; + else + slotInfo.SkeletonInverted = false; + + if (_ui.enableCheckBox->checkState() == Qt::Checked) + slotInfo.Enable = true; + else + slotInfo.Enable = false; + + if (_ui.clampRadioButton->isChecked()) + slotInfo.ClampMode = 0; + else if (_ui.repeatRadioButton->isChecked()) + slotInfo.ClampMode = 1; + else + slotInfo.ClampMode = 2; + + std::string curObj = Modules::objView().getCurrentObject(); + if (curObj.empty()) + return; + CEntity &entity = Modules::objView().getEntity(curObj); + entity.setSlotInfo(_numSlot, slotInfo); +} + +void CSlotGroupBox::resetUi() +{ + _ui.offsetSpinBox->setValue(0); + _ui.startBlendSpinBox->setValue(0); + _ui.endBlendSpinBox->setValue(0); + _ui.startFrameSpinBox->setValue(0); + _ui.endFrameSpinBox->setValue(0); + _ui.speedDoubleSpinBox->setValue(0); + _ui.smoothSpinBox->setValue(0); + _ui.disableRadioButton->setChecked(true); + _ui.invSkelWeightCheckBox->setCheckState(Qt::Unchecked); + _ui.enableCheckBox->setCheckState(Qt::Unchecked); +} + +void CSlotGroupBox::selectAnim() +{ + std::string curObj = Modules::objView().getCurrentObject(); + if (curObj.empty()) + return; + CEntity &entity = Modules::objView().getEntity(curObj); + std::vector& animationList = entity.getAnimationList(); + + if (animationList.empty()) return; + + QStringList items; + items << tr("empty"); + for(size_t i = 0; i < animationList.size(); ++i) + items << QString(animationList[i].c_str()); + + bool ok; + QString item = QInputDialog::getItem(this, tr("Select your anim"), + tr("Animation:"), items, 0, false, &ok); + if (ok) + { + _animName = item; + QString title = tr("Slot %1 : ").arg(_numSlot) + _animName + " : " + _skelName; + this->setTitle(title); + _ui.endFrameSpinBox->setValue(int(entity.getAnimLength(_animName.toStdString()) * Modules::mainWin().getFrameRate())); + saveSlotInfo(); + } +} + +void CSlotGroupBox::selectSkel() +{ + std::string curObj = Modules::objView().getCurrentObject(); + if (curObj.empty()) + return; + CEntity &entity = Modules::objView().getEntity(curObj); + std::vector& swtList = entity.getSWTList(); + + if (swtList.empty()) return; + + QStringList items; + items << tr("empty"); + for(size_t i = 0; i < swtList.size(); ++i) + items << QString(swtList[i].c_str()); + + bool ok; + QString item = QInputDialog::getItem(this, tr("Select your skel"), + tr("Skeleton weight template:"), items, 0, false, &ok); + if (ok) + { + _skelName = item; + QString title = tr("Slot %1 : ").arg(_numSlot) + _animName + " : " + _skelName; + this->setTitle(title); + saveSlotInfo(); + } +} + +void CSlotGroupBox::alignAblend() +{ + float deltaTime = _ui.endFrameSpinBox->value() - _ui.startFrameSpinBox->value(); + _ui.startFrameSpinBox->setValue(_ui.offsetSpinBox->value()); + _ui.endFrameSpinBox->setValue(int(float(_ui.offsetSpinBox->value()) + deltaTime / _ui.speedDoubleSpinBox->value())); +} + +CSlotManagerDialog::CSlotManagerDialog(QWidget *parent) + : QDockWidget(parent) +{ + setObjectName(QString::fromUtf8("CSlotManagerDialog")); + QIcon icon; + icon.addFile(QString::fromUtf8(":/images/mixer.png"), QSize(), QIcon::Normal, QIcon::Off); + setWindowIcon(icon); + setMinimumSize(QSize(310, 100)); + _dockWidgetContents = new QWidget(); + _gridLayout = new QGridLayout(_dockWidgetContents); + _scrollArea = new QScrollArea(_dockWidgetContents); + _scrollArea->setWidgetResizable(true); + _scrollAreaWidgetContents = new QWidget(); + + _slotGridLayout = new QGridLayout(_scrollAreaWidgetContents); + + _tabWidget = new QTabWidget(_scrollAreaWidgetContents); + _tabWidget->setObjectName(QString::fromUtf8("_tabWidget")); + _tabWidget->setTabPosition(QTabWidget::East); + + for (int i = 0; i < NL3D::CChannelMixer::NumAnimationSlot; i++) + { + _tabs[i] = new QWidget(); + _tabs[i]->setObjectName(QString::fromUtf8("_tab%1").arg(i)); + _gridLayouts[i] = new QGridLayout(_tabs[i]); + _gridLayouts[i]->setObjectName(QString::fromUtf8("_gridLayouts%1").arg(i)); + + _slotGroupBoxs[i] = new CSlotGroupBox(_tabs[i]); + _slotGroupBoxs[i]->setTitle(tr("Slot %1 : empty : empty").arg(i)); + _slotGroupBoxs[i]->_numSlot = i; + _gridLayouts[i]->addWidget(_slotGroupBoxs[i], 0, 0, 1, 1); + _verticalSpacers[i] = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + _gridLayouts[i]->addItem(_verticalSpacers[i], 1, 0, 1, 1); + + _tabWidget->addTab(_tabs[i], QString()); + _tabWidget->setTabText(i, tr("Slot %1").arg(i)); + + + } + + _slotGridLayout->addWidget(_tabWidget); + + _scrollArea->setWidget(_scrollAreaWidgetContents); + + _gridLayout->addWidget(_scrollArea, 0, 0, 1, 1); + + setWidget(_dockWidgetContents); + setWindowTitle(tr("Slot manager")); +} + +CSlotManagerDialog::~CSlotManagerDialog() +{ +} + +void CSlotManagerDialog::updateUiSlots() +{ + for (int i = 0; i < NL3D::CChannelMixer::NumAnimationSlot; i++) + { + _slotGroupBoxs[i]->updateUi(); + } +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/slot_manager_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/slot_manager_dialog.h new file mode 100644 index 000000000..adbc4f83e --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/slot_manager_dialog.h @@ -0,0 +1,86 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef SLOT_MANAGER_DIALOG_H +#define SLOT_MANAGER_DIALOG_H + +#include +#include "ui_slot_form.h" + +#include +#include + +#include "nel/3d/channel_mixer.h" + +namespace NLQT { + +class CSlotGroupBox: public QGroupBox +{ + Q_OBJECT +public: + CSlotGroupBox(QWidget *parent = 0); + ~CSlotGroupBox(); + void resetUi(); + void updateUi(); + +public Q_SLOTS: + void saveSlotInfo(); + +private Q_SLOTS: + void selectAnim(); + void selectSkel(); + void alignAblend(); + +private: + + QString _animName, _skelName; + int _numSlot; + Ui::CSlotGroupBox _ui; + + friend class CSlotManagerDialog; +}; + +class CSlotManagerDialog: public QDockWidget +{ + Q_OBJECT + +public: + CSlotManagerDialog(QWidget *parent = 0); + ~CSlotManagerDialog(); + +public Q_SLOTS: + void updateUiSlots(); + +private: + QWidget *_dockWidgetContents; + QGridLayout *_gridLayout; + QGridLayout *_slotGridLayout; + QScrollArea *_scrollArea; + QWidget *_scrollAreaWidgetContents; + QTabWidget *_tabWidget; + QSpacerItem *_verticalSpacers[NL3D::CChannelMixer::NumAnimationSlot]; + QGridLayout *_gridLayouts[NL3D::CChannelMixer::NumAnimationSlot]; + QWidget *_tabs[NL3D::CChannelMixer::NumAnimationSlot]; + CSlotGroupBox *_slotGroupBoxs[NL3D::CChannelMixer::NumAnimationSlot]; + +}; /* CSlotManager */ + +} /* namespace NLQT */ + +#endif // SLOT_MANAGER_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/sound_system.cpp b/code/nel/tools/3d/object_viewer_qt/src/sound_system.cpp new file mode 100644 index 000000000..ad907f275 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/sound_system.cpp @@ -0,0 +1,224 @@ +// NeL - MMORPG Framework +// 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 . + + +#include "stdpch.h" +#include "sound_system.h" + +// NeL includes +#include +#include +#include +#include +#include +#include + +// Project includes +#include "modules.h" + +namespace NLQT { + +CSoundSystem::CSoundSystem() + :_AudioMixer(NULL), + _AnimManager(NULL), + _Zero(NLMISC::CVector::Null) +{ + +} + +CSoundSystem::~CSoundSystem() +{ +} + +void CSoundSystem::setListenerMatrix(const NLMISC::CMatrix &m) +{ + if (_AudioMixer) + { + if(m.getPos() != oldMatrix.getPos() || m.getJ() != oldMatrix.getJ() || m.getK() != oldMatrix.getK()) + { + NLSOUND::UListener *l = _AudioMixer->getListener(); + l->setPos(m.getPos()); + l->setOrientation(m.getJ(), m.getK()); + oldMatrix = m; + } + } +} + +void CSoundSystem::init () +{ + //H_AUTO2 + nldebug("CSoundSystem::init"); + + // create audiomixer + _AudioMixer = NULL; + _AnimManager = NULL; + NL3D::UParticleSystemSound::setPSSound(NULL); + _AudioMixer = NLSOUND::UAudioMixer::createAudioMixer(); + nlassert(_AudioMixer); + + try + { + // init audiomixer + _PackedSheetPath = Modules::config().getValue("SoundPackedSheetPath", std::string("")); + _SamplePath = Modules::config().getValue("SoundSamplePath", std::string("")); + _AudioMixer->setSamplePath(_SamplePath); + _AudioMixer->setPackedSheetOption(_PackedSheetPath, true); + std::vector devices; + _AudioMixer->initDriver(Modules::config().getValue("SoundDriver", std::string("Auto"))); + _AudioMixer->getDevices(devices); + NLSOUND::UAudioMixer::CInitInfo audioInfo; + audioInfo.AutoLoadSample = Modules::config().getValue("SoundAutoLoadSample", true); + audioInfo.EnableOccludeObstruct = Modules::config().getValue("SoundEnableOccludeObstruct", true); + audioInfo.EnableReverb = Modules::config().getValue("SoundEnableReverb", true); + audioInfo.ManualRolloff = Modules::config().getValue("SoundManualRolloff", true); + audioInfo.ForceSoftware = Modules::config().getValue("SoundForceSoftware", false); + audioInfo.MaxTrack = Modules::config().getValue("SoundMaxTrack", 48); + audioInfo.UseADPCM = Modules::config().getValue("SoundUseADPCM", false); + _AudioMixer->initDevice(Modules::config().getValue("SoundDevice", std::string("")), audioInfo, NULL); + _AudioMixer->setLowWaterMark(1); + } + catch(NLMISC::Exception &e) + { + // in case of exeption during mixer init, the mixer is destroyed ! + std::string mess = std::string("Unable to init sound :") + e.what(); + nlwarning ("Init sound: %s", mess.c_str()); + _AudioMixer = NULL; + return; + } + + // ok for the mixer, now create the sound anim manager + try + { + // TODO : boris : Hum, as far as I know, throwing exeption in constructor is a very BAD idea... + _AnimManager = new NLSOUND::CSoundAnimManager(_AudioMixer); + } + catch (NLMISC::Exception &e) + { + std::string mess = std::string("Unable to init sound :") + e.what(); + nlwarning ("Init sound: %s", mess.c_str()); + delete _AudioMixer; + _AudioMixer = NULL; + + return; + } + NL3D::UParticleSystemSound::setPSSound(_AudioMixer); +} + +void CSoundSystem::release(void) +{ + //H_AUTO2 + nldebug("CSoundSystem::release"); + + NL3D::UParticleSystemSound::setPSSound(NULL); + if (_AnimManager) + { + delete _AnimManager; + _AnimManager = NULL; + } + if (_AudioMixer) + { + delete _AudioMixer; + _AudioMixer = NULL; + } +} + +void CSoundSystem::play(const std::string &soundName) +{ + if (_AudioMixer) + { + NLSOUND::USource *src = _AudioMixer->createSource(NLMISC::CStringMapper::map(soundName), true); + if (src) + { + src->setLooping(false); + const NLMISC::CVector &pos = _AudioMixer->getListener()->getPos(); + src->setPos(pos); + src->play(); + } + else + { + nlwarning("Can't play the sound (perhaps it's contextual sound)"); + } + } +} + +NLSOUND::USource *CSoundSystem::create(const std::string &soundName) +{ + if (_AudioMixer) + { + NLSOUND::USource *src = _AudioMixer->createSource(NLMISC::CStringMapper::map(soundName), false); + if (src) + { + src->setLooping(false); + const NLMISC::CVector &pos = _AudioMixer->getListener()->getPos(); + src->setPos(pos); + src->play(); + return src; + } + else + { + nlwarning("Can't play the sound (perhaps it's contextual sound)"); + } return NULL; + } + return NULL; +} + +void CSoundSystem::playAnimation(std::string& name, float lastTime, float curTime, NLSOUND::CSoundContext &context) +{ + if (_AnimManager == NULL) + { + return; + } + + NLSOUND::TSoundAnimId id = _AnimManager->getAnimationFromName(name); + + if (id != NLSOUND::CSoundAnimationNoId) + { + _AnimManager->playAnimation(id, lastTime, curTime, NULL, context); + } +} + +void CSoundSystem::update() +{ + if (_AudioMixer) + { + _AudioMixer->update(); + } +} + +void CSoundSystem::initGraphics() +{ + //H_AUTO2 + nldebug("CSoundSystem::initGraphics"); + + // set particle system sound + NL3D::UParticleSystemSound::setPSSound(_AudioMixer); + + // ... + // todo: displayers for all the test sound sources :) +} + +void CSoundSystem::releaseGraphics() +{ + //H_AUTO2 + nldebug("CSoundSystem::releaseGraphics"); + + // .. + + // clear particle system sound + NL3D::UParticleSystemSound::setPSSound(NULL); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/sound_system.h b/code/nel/tools/3d/object_viewer_qt/src/sound_system.h new file mode 100644 index 000000000..b5022257d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/sound_system.h @@ -0,0 +1,119 @@ +// NeL - MMORPG Framework +// 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 . + + +#ifndef SOUND_SYSTEM_H +#define SOUND_SYSTEM_H + +#include + +// NeL includes +#include +#include +#include +#include + +// STL includes +#include +#include + +namespace NLSOUND +{ + class UAudioMixer; + class USource; +} + +namespace NLMISC +{ + class CMatrix; +} + +namespace NLQT { + +/** +@class CSoundSystem +@brief This class init the sound system used by the object viewer +*/ +class CSoundSystem +{ +public: + CSoundSystem(); + virtual ~CSoundSystem(); + + /// Set the name of the file containing the sample bank + void addSampleBank(const std::string &sampleBankFileName) + { + _SampleBanksFileName.insert(sampleBankFileName); + } + + /// Sets the path which contains samples + void setSamplePath(std::string& path) { _SamplePath = NLMISC::CPath::standardizePath(path, true); } + + /// Sets the path which contains packed sheet + void setPackedSheetPath(std::string& path) { _PackedSheetPath = NLMISC::CPath::standardizePath(path, true); } + + /// Init the sound system this also load the sound bank. See setSoundBank + void init(void); + + /// Release the sound system + void release(void); + + /// Set the listener matrix. + void setListenerMatrix(const NLMISC::CMatrix &m); + + /// Spawn a sound at the user position + void play(const std::string &soundName); + + /// Create a sound at the user position (don't spawn it) + NLSOUND::USource *create(const std::string &soundName); + + /// Load the sound animation with the specified name + void loadAnimation(std::string& name) { _AnimManager->loadAnimation(name); } + + /// Start playing a sound animation. + void playAnimation(std::string& name, float lastTime, float curTime, NLSOUND::CSoundContext &context); + + // Update the sound animations. + //static void updateAnimations(float lastTime, float curTime) { _AnimManager->update(lastTime, curTime); }; + + /// Get the audio mixer, or null if init failed + NLSOUND::UAudioMixer *getAudioMixer(void) { return _AudioMixer; } + + /// Returns a reference to the animation manager + NLSOUND::CSoundAnimManager* getSoundAnimManager() { return _AnimManager; } + + /// Init the particle system sound with the given AudioMixer + void initGraphics(); + + /// Release the particle system sound with the given AudioMixer + void releaseGraphics(); + + /// Update sound. Must be called periodically + void update(); + +private: + NLSOUND::UAudioMixer *_AudioMixer; + std::set _SampleBanksFileName; + NLSOUND::CSoundAnimManager *_AnimManager; + NLMISC::CVector _Zero; + std::string _SamplePath; + std::string _PackedSheetPath; + NLMISC::CMatrix oldMatrix; +}; /* class CSoundSystem */ + +} /* namespace NLQT */ + +#endif // SOUND_SYSTEM_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/spinner_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/spinner_dialog.cpp new file mode 100644 index 000000000..9915e1fda --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/spinner_dialog.cpp @@ -0,0 +1,68 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "spinner_dialog.h" + +namespace NLQT { + +CSpinnerDialog::CSpinnerDialog(NL3D::CPSBasisSpinner *sf, CWorkspaceNode *ownerNode, QWidget *parent) + : QDialog(parent) +{ + _verticalLayout = new QVBoxLayout(this); + _nbSamplesLabel = new QLabel(this); + _verticalLayout->addWidget(_nbSamplesLabel); + + _nbSamplesWidget = new NLQT::CEditRangeUIntWidget(this); + QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(_nbSamplesWidget->sizePolicy().hasHeightForWidth()); + _nbSamplesWidget->setSizePolicy(sizePolicy); + _verticalLayout->addWidget(_nbSamplesWidget); + + _dirWidget = new NLQT::CDirectionWidget(this); + sizePolicy.setHeightForWidth(_dirWidget->sizePolicy().hasHeightForWidth()); + _dirWidget->setSizePolicy(sizePolicy); + _verticalLayout->addWidget(_dirWidget); + + setWindowTitle(tr("Edit spinner")); + _nbSamplesLabel->setText(tr("Nb samples:")); + + _AxisWrapper.OwnerNode = ownerNode; + _NbSampleWrapper.OwnerNode = ownerNode; + _NbSampleWrapper.S = sf; + _AxisWrapper.S = sf; + + _nbSamplesWidget->setRange(1, 512); + _nbSamplesWidget->setWrapper(&_NbSampleWrapper); + _nbSamplesWidget->enableLowerBound(0, true); + _nbSamplesWidget->updateUi(); + + _dirWidget->setWrapper(&_AxisWrapper); + _dirWidget->updateUi(); + + setFixedHeight(sizeHint().height()); +} + +CSpinnerDialog::~CSpinnerDialog() +{ +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/spinner_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/spinner_dialog.h new file mode 100644 index 000000000..62497b8bc --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/spinner_dialog.h @@ -0,0 +1,73 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef SPINNER_DIALOG_H +#define SPINNER_DIALOG_H + +// Qt includes +#include +#include +#include + +// Nel include +#include "nel/3d/ps_plane_basis_maker.h" + +// Project includes +#include "direction_widget.h" +#include "edit_range_widget.h" +#include "ps_wrapper.h" + +namespace NLQT { + +class CSpinnerDialog : public QDialog +{ + Q_OBJECT + +public: + CSpinnerDialog(NL3D::CPSBasisSpinner *sf, CWorkspaceNode *ownerNode, QWidget *parent = 0); + ~CSpinnerDialog(); + +protected: + + /// Wrapper to set the number of samples in the spinner + struct CNbSampleWrapper : public IPSWrapperUInt + { + NL3D::CPSBasisSpinner *S; + uint32 get(void) const { return S->_F.getNumSamples(); } + void set(const uint32 &val) { S->_F.setNumSamples(val); } + } _NbSampleWrapper; + + + /// Wrapper to set the axis of the spinner + struct CAxisWrapper : public IPSWrapper + { + NL3D::CPSBasisSpinner *S; + NLMISC::CVector get(void) const { return S->_F.getAxis(); } + void set(const NLMISC::CVector &axis) { S->_F.setAxis(axis); } + } _AxisWrapper; + + QLabel *_nbSamplesLabel; + QVBoxLayout *_verticalLayout; + CEditRangeUIntWidget *_nbSamplesWidget; + CDirectionWidget *_dirWidget; +}; + +} /* namespace NLQT */ + +#endif // SPINNER_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/stdpch.cpp b/code/nel/tools/3d/object_viewer_qt/src/stdpch.cpp new file mode 100644 index 000000000..eb84ced4d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/stdpch.cpp @@ -0,0 +1,20 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" diff --git a/code/nel/tools/3d/object_viewer_qt/src/stdpch.h b/code/nel/tools/3d/object_viewer_qt/src/stdpch.h new file mode 100644 index 000000000..0ef614792 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/stdpch.h @@ -0,0 +1,33 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef NL_STDPCH_H +#define NL_STDPCH_H + +#include + +#include +#include +#include +#include +#include + +#include + +#endif diff --git a/code/nel/tools/3d/object_viewer_qt/src/sun_color_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/sun_color_dialog.cpp new file mode 100644 index 000000000..c3637191e --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/sun_color_dialog.cpp @@ -0,0 +1,71 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "sun_color_dialog.h" + +// NeL includes +#include "nel/3d/u_scene.h" + +// Project includes +#include "modules.h" + +namespace NLQT { + +CSunColorDialog::CSunColorDialog(QWidget *parent) + : QDockWidget(parent) +{ + _ui.setupUi(this); + + connect(this, SIGNAL(visibilityChanged(bool)), this, SLOT(updateSunColor(bool))); + connect(_ui.ambientWidget, SIGNAL(colorChanged(NLMISC::CRGBA)), this, SLOT(setAmbientSunColor(NLMISC::CRGBA))); + connect(_ui.diffuseWidget, SIGNAL(colorChanged(NLMISC::CRGBA)), this, SLOT(setDiffuseSunColor(NLMISC::CRGBA))); + connect(_ui.specularWidget, SIGNAL(colorChanged(NLMISC::CRGBA)), this, SLOT(setSpecularSunColor(NLMISC::CRGBA))); +} + +CSunColorDialog::~CSunColorDialog() +{ +} + +void CSunColorDialog::updateSunColor(bool visible) +{ + if (!visible) + return; + + _ui.ambientWidget->setColor(Modules::objView().getScene()->getSunAmbient()); + _ui.diffuseWidget->setColor(Modules::objView().getScene()->getSunDiffuse()); + _ui.specularWidget->setColor(Modules::objView().getScene()->getSunSpecular()); +} + +void CSunColorDialog::setAmbientSunColor(NLMISC::CRGBA color) +{ + Modules::objView().getScene()->setSunAmbient(color); +} + +void CSunColorDialog::setDiffuseSunColor(NLMISC::CRGBA color) +{ + Modules::objView().getScene()->setSunDiffuse(color); +} + +void CSunColorDialog::setSpecularSunColor(NLMISC::CRGBA color) +{ + Modules::objView().getScene()->setSunSpecular(color); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/sun_color_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/sun_color_dialog.h new file mode 100644 index 000000000..790fd8b20 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/sun_color_dialog.h @@ -0,0 +1,58 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef SUN_COLOR_DIALOG_H +#define SUN_COLOR_DIALOG_H + +#include "ui_sun_color_form.h" + +// STL includes + +// NeL includes + +// Project includes + +namespace NLQT { + +/** +@class CSunColorDialog +@brief Dialog to choose the sun color in a 3D scene +*/ +class CSunColorDialog: public QDockWidget +{ + Q_OBJECT + +public: + CSunColorDialog(QWidget *parent = 0); + ~CSunColorDialog(); + +private Q_SLOTS: + void updateSunColor(bool visible); + void setAmbientSunColor(NLMISC::CRGBA color); + void setDiffuseSunColor(NLMISC::CRGBA color); + void setSpecularSunColor(NLMISC::CRGBA color); + +private: + + Ui::CSunColorDialog _ui; +}; /* class CSunColorDialog */ + +} /* namespace NLQT */ + +#endif // SUN_COLOR_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/sun_color_form.ui b/code/nel/tools/3d/object_viewer_qt/src/sun_color_form.ui new file mode 100644 index 000000000..d8aadc2b0 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/sun_color_form.ui @@ -0,0 +1,74 @@ + + + CSunColorDialog + + + + 0 + 0 + 120 + 132 + + + + Sun color + + + + + + + Diffuse: + + + + + + + + + + Ambient + + + + + + + + + + Specular: + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + + NLQT::CColorEditWidget + QWidget +
color_edit_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/tail_form.ui b/code/nel/tools/3d/object_viewer_qt/src/tail_form.ui new file mode 100644 index 000000000..476dbfc53 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/tail_form.ui @@ -0,0 +1,121 @@ + + + CTailParticleWidget + + + + 0 + 0 + 206 + 90 + + + + Form + + + + + + Ribbon orientation + + + + Follow Path + + + + + Follow Path XY + + + + + Identity + + + + + + + + + 72 + 72 + + + + + 72 + 72 + + + + + + + + Tail shape + + + + Triangle + + + + + Quad + + + + + Octogon + + + + + Pentagram + + + + + Simple segment X + + + + + Simple segment Y + + + + + Simple segment Z + + + + + Simple brace + + + + + + + + Tail fading + + + + + + + + NLQT::CGraphicsInfoWidget + QWidget +
graphics_info_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/tail_particle_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/tail_particle_widget.cpp new file mode 100644 index 000000000..515a1927c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/tail_particle_widget.cpp @@ -0,0 +1,134 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "tail_particle_widget.h" + +// NeL includes +#include "nel/3d/ps_particle.h" + +// Projects includes + +namespace NLQT { + +CTailParticleWidget::CTailParticleWidget(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + _ui.pathWidget->setMode(Mode::RibbonShape); + connect(_ui.tailFadingCheckBox, SIGNAL(toggled(bool)), this, SLOT(setTailFading(bool))); + connect(_ui.ribbonOrientationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setRibbonOrientation(int))); + connect(_ui.tailShapeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setTailShape(int))); +} + +CTailParticleWidget::~CTailParticleWidget() +{ +} + +void CTailParticleWidget::setCurrentTailParticle(CWorkspaceNode *ownerNode, NL3D::CPSTailParticle *tp) +{ + _Node = ownerNode; + + _TailParticle = tp; + + _ui.tailFadingCheckBox->setChecked(tp->getColorFading()); + + if (!dynamic_cast(_TailParticle)) + { + _ui.pathWidget->hide(); + _ui.ribbonOrientationComboBox->hide(); + _ui.tailShapeComboBox->hide(); + } + else + { + _ui.pathWidget->show(); + _ui.ribbonOrientationComboBox->show(); + _ui.tailShapeComboBox->show(); + NL3D::CPSRibbon *r = dynamic_cast(_TailParticle); + _ui.ribbonOrientationComboBox->setCurrentIndex(r->getOrientation()); + + // Update graphics widget + std::vector verts; + verts.resize(r->getNbVerticesInShape()); + r->getShape(&verts[0]); + _ui.pathWidget->setRibbonShape(verts, r->getBraceMode()); + } +} + +void CTailParticleWidget::setTailFading(bool state) +{ + if (state != _TailParticle->getColorFading()) + { + _TailParticle->setColorFading(state); + _Node->setModified(true); + } +} + +void CTailParticleWidget::setTailShape(int index) +{ + NL3D::CPSRibbon *r = dynamic_cast(_TailParticle); + nlassert(r); + switch (index) + { + case 0: // triangle + r->setShape(NL3D::CPSRibbon::Triangle, NL3D::CPSRibbon::NbVerticesInTriangle); + break; + case 1: // quad + r->setShape(NL3D::CPSRibbon::Losange, NL3D::CPSRibbon::NbVerticesInLosange); + break; + case 2: // octogon + r->setShape(NL3D::CPSRibbon::HeightSides, NL3D::CPSRibbon::NbVerticesInHeightSide); + break; + case 3: // pentagram + r->setShape(NL3D::CPSRibbon::Pentagram, NL3D::CPSRibbon::NbVerticesInPentagram); + break; + case 4: // simple segment x + r->setShape(NL3D::CPSRibbon::SimpleSegmentX, NL3D::CPSRibbon::NbVerticesInSimpleSegmentX, true); + break; + case 5: // simple segment y + r->setShape(NL3D::CPSRibbon::SimpleSegmentY, NL3D::CPSRibbon::NbVerticesInSimpleSegmentY, true); + break; + case 6: // simple segment z + r->setShape(NL3D::CPSRibbon::SimpleSegmentZ, NL3D::CPSRibbon::NbVerticesInSimpleSegmentZ, true); + break; + case 7: // simple brace + r->setShape(NL3D::CPSRibbon::SimpleBrace, NL3D::CPSRibbon::NbVerticesInSimpleBrace, true); + break; + } + + // Update graphics widget + std::vector verts; + verts.resize(r->getNbVerticesInShape() ); + r->getShape(&verts[0]); + _ui.pathWidget->setRibbonShape(verts, r->getBraceMode()); +} + +void CTailParticleWidget::setRibbonOrientation(int index) +{ + NL3D::CPSRibbon *r = dynamic_cast(_TailParticle); + nlassert(r); + if (index != r->getOrientation()) + { + r->setOrientation((NL3D::CPSRibbon::TOrientation) index); + _Node->setModified(true); + } +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/tail_particle_widget.h b/code/nel/tools/3d/object_viewer_qt/src/tail_particle_widget.h new file mode 100644 index 000000000..fa74ce848 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/tail_particle_widget.h @@ -0,0 +1,65 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef TAIL_PARTICLE_WIDGET_H +#define TAIL_PARTICLE_WIDGET_H + +#include "ui_tail_form.h" + +// STL includes + +// Qt includes + +// NeL includes + +// Project includes +#include "particle_node.h" + +namespace NL3D { + struct CPSTailParticle; +} + +namespace NLQT { + +class CTailParticleWidget: public QWidget +{ + Q_OBJECT + +public: + CTailParticleWidget(QWidget *parent = 0); + ~CTailParticleWidget(); + + void setCurrentTailParticle(CWorkspaceNode *ownerNode, NL3D::CPSTailParticle *tp); + +private Q_SLOTS: + void setTailFading(bool state); + void setTailShape(int index); + void setRibbonOrientation(int index); + +private: + CWorkspaceNode *_Node; + + NL3D::CPSTailParticle *_TailParticle; + + Ui::CTailParticleWidget _ui; +}; /* class CTailParticleWidget */ + +} /* namespace NLQT */ + +#endif // TAIL_PARTICLE_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/value_blender_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/value_blender_dialog.cpp new file mode 100644 index 000000000..d3bdda106 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/value_blender_dialog.cpp @@ -0,0 +1,70 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "value_blender_dialog.h" + +namespace NLQT { + +CValueBlenderDialog::CValueBlenderDialog(IValueBlenderDialogClient *createInterface, + CWorkspaceNode *ownerNode, + bool destroyInterface, + QWidget *parent) + : QDialog(parent), + _CreateInterface(createInterface), + _Node(ownerNode), + _DestroyInterface(destroyInterface) +{ + _gridLayout = new QGridLayout(this); + _startLabel = new QLabel(this); + + _gridLayout->addWidget(_startLabel, 0, 0, 1, 1); + + _startWidget = _CreateInterface->createDialog(0, _Node, this); + QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(_startWidget->sizePolicy().hasHeightForWidth()); + _startWidget->setSizePolicy(sizePolicy); + + _gridLayout->addWidget(_startWidget, 1, 0, 1, 1); + + _endLabel = new QLabel(this); + + _gridLayout->addWidget(_endLabel, 2, 0, 1, 1); + + _endWidget = _CreateInterface->createDialog(1, _Node, this); + sizePolicy.setHeightForWidth(_endWidget->sizePolicy().hasHeightForWidth()); + _endWidget->setSizePolicy(sizePolicy); + + _gridLayout->addWidget(_endWidget, 3, 0, 1, 1); + + setWindowTitle(tr("Value blender")); + _startLabel->setText(tr("Start value:")); + _endLabel->setText(tr("End value:")); + + setFixedHeight(sizeHint().height()); +} + +CValueBlenderDialog::~CValueBlenderDialog() +{ + if (_DestroyInterface) delete _CreateInterface; +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/value_blender_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/value_blender_dialog.h new file mode 100644 index 000000000..c76d08801 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/value_blender_dialog.h @@ -0,0 +1,200 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef VALUE_BLENDER_DIALOG_H +#define VALUE_BLENDER_DIALOG_H + +#include + +// Qt includes +#include +#include +#include +#include +#include + +// STL includes + +// NeL includes +#include +#include +#include + +#include "nel/misc/rgba.h" +#include "nel/3d/ps_attrib_maker.h" + +// Project includes +#include "ps_wrapper.h" +#include "edit_range_widget.h" +#include "color_edit_widget.h" + +namespace NLQT { + +struct IValueBlenderDialogClient +{ + /// Create a dialog to edit a single value. + /// @param index - must be 0 or 1, it says which value is being edited + virtual QWidget *createDialog(uint index, CWorkspaceNode *ownerNode, QWidget *parent = 0) = 0; + + virtual ~IValueBlenderDialogClient() {} +}; + +class CValueBlenderDialog : public QDialog +{ + Q_OBJECT + +public: + /// Create the dialog. + /// @param createInterface - interface that allows to create a dialog to edit one of the 2 values used for the blend. + /// @param destroyInterface - true if this object must take care to call 'delete' on the 'createInterface' pointer + CValueBlenderDialog(IValueBlenderDialogClient *createInterface, + CWorkspaceNode *ownerNode, + bool destroyInterface, + QWidget *parent = 0); + + ~CValueBlenderDialog() ; + +// Implementation +protected: + IValueBlenderDialogClient *_CreateInterface ; + + CWorkspaceNode *_Node; + + bool _DestroyInterface; + + QGridLayout *_gridLayout; + + QLabel *_startLabel; + + QLabel *_endLabel; + + // the 2 dialog used to choose the blending value + QWidget *_startWidget, *_endWidget; +}; + +/// GENERAL INTERFACE FOR BLENDER EDITION + +/// T is the type to be edited (color, float, etc..), even if it is unused +template +class CValueBlenderDialogClientT : public IValueBlenderDialogClient +{ +public: + // the scheme being used. Must be set by the user + NL3D::CPSValueBlendFuncBase *SchemeFunc; + +protected: + virtual QWidget *createDialog(uint index, CWorkspaceNode *ownerNode, QWidget *parent = 0) + { + _ValueInfos[index].ValueIndex = index; + _ValueInfos[index].SchemeFunc = SchemeFunc; + _ValueInfos[index].OwnerNode = ownerNode; + return newDialog(&_ValueInfos[index], parent); + } + + + // construct a dialog + virtual QWidget *newDialog(IPSWrapper *wrapper, QWidget *parent) = 0; + + // inherited from IPSWrapper + struct COneValueInfo : public IPSWrapper + { + // value 0 or 1 being edited + uint ValueIndex; + // the scheme being edited + NL3D::CPSValueBlendFuncBase *SchemeFunc; + + virtual T get(void) const + { + T t1, t2; + SchemeFunc->getValues(t1, t2); + return ValueIndex == 0 ? t1 : t2; + } + virtual void set(const T &value) + { + T t1, t2; + SchemeFunc->getValues(t1, t2); + if (ValueIndex == 0 ) t1 = value; else t2 = value; + SchemeFunc->setValues(t1, t2); + } + }; + + COneValueInfo _ValueInfos[2]; +}; + +/// FLOAT BLENDER EDITION INTERFACE +class CFloatBlenderDialogClient : public CValueBlenderDialogClientT +{ +public: + QWidget *newDialog(IPSWrapper *wrapper, QWidget *parent) + { + CEditRangeFloatWidget *erf = new CEditRangeFloatWidget(parent); + erf->setRange(MinRange, MaxRange); + erf->setWrapper(wrapper); + erf->updateUi(); + return erf; + } + float MinRange, MaxRange; +}; + +/// UINT BLENDER EDITION INTERFACE +class CUIntBlenderDialogClient : public CValueBlenderDialogClientT +{ +public: + QWidget *newDialog(IPSWrapper *wrapper, QWidget *parent) + { + CEditRangeUIntWidget *erf = new CEditRangeUIntWidget(parent); + erf->setRange(MinRange, MaxRange); + erf->setWrapper(wrapper); + erf->updateUi(); + return erf; + } + uint32 MinRange, MaxRange; +}; + +/// INT BLENDER EDITION INTERFACE +class CIntBlenderDialogClient : public CValueBlenderDialogClientT +{ +public: + QWidget *newDialog(IPSWrapper *wrapper, QWidget *parent) + { + CEditRangeIntWidget *erf = new CEditRangeIntWidget(parent); + erf->setRange(MinRange, MaxRange); + erf->setWrapper(wrapper); + erf->updateUi(); + return erf; + } + sint32 MinRange, MaxRange; +}; + +/// RGBA BLENDER EDITION INTERFACE +class CRGBABlenderDialogClient : public CValueBlenderDialogClientT +{ +public: + QWidget *newDialog(IPSWrapper *wrapper, QWidget *parent) + { + CColorEditWidget *ce = new CColorEditWidget(parent); + ce->setWrapper(wrapper); + ce->updateUi(); + return ce; + } +}; + +} /* namespace NLQT */ + +#endif // VALUE_BLENDER_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/value_from_emitter_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/value_from_emitter_dialog.cpp new file mode 100644 index 000000000..e44e6f393 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/value_from_emitter_dialog.cpp @@ -0,0 +1,41 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "value_from_emitter_dialog.h" + +namespace NLQT { + +CValueFromEmitterDialog::CValueFromEmitterDialog(QWidget *widget, QWidget *parent) + : QDialog(parent) +{ + _gridLayout = new QGridLayout(this); + _widget = widget; + _gridLayout->addWidget(_widget, 0, 0, 1, 1); + + setWindowTitle(tr("Value from emitter")); + + //setFixedHeight(sizeHint().height()); +} + +CValueFromEmitterDialog::~CValueFromEmitterDialog() +{ +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/value_from_emitter_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/value_from_emitter_dialog.h new file mode 100644 index 000000000..d40dce655 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/value_from_emitter_dialog.h @@ -0,0 +1,109 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef VALUE_FROM_EMITTER_DIALOG_H +#define VALUE_FROM_EMITTER_DIALOG_H + +#include + +// Qt includes +#include +#include +#include +#include + +// NeL include +#include "nel/3d/ps_attrib_maker.h" + +// Project includes +#include "ps_wrapper.h" +#include "attrib_widget.h" + +namespace NL3D +{ + template class CPSAttribMakerMemory ; +} + +namespace NLQT { + +class CValueFromEmitterDialog : public QDialog +{ + Q_OBJECT + +public: + CValueFromEmitterDialog(QWidget *widget, QWidget *parent = 0); + ~CValueFromEmitterDialog(); + + virtual void init() = 0; + +protected: + + QGridLayout *_gridLayout; + QWidget *_widget; +}; + +/** construct a dialog that allow to edit a scheme used for initial attribute generation in a particle + */ +template class CValueFromEmitterDialogT : public CValueFromEmitterDialog +{ +public: + CValueFromEmitterDialogT(NL3D::CPSAttribMakerMemory *editedScheme, CAttribWidgetT *srcDlg, QWidget *parent = 0) + : CValueFromEmitterDialog(srcDlg, parent), _AttrbDlg(srcDlg) + { + nlassert(srcDlg); + _SchemeWrapper.S = editedScheme ; + } + // inherited from CValueFromEmitterDialog + void init() + { + _AttrbDlg->setEnabledConstantValue(false) ; + _AttrbDlg->setWrapper(&_DummyWrapper) ; + _AttrbDlg->setSchemeWrapper(&_SchemeWrapper) ; + _AttrbDlg->init(); + } + + ~CValueFromEmitterDialogT() + { + delete _AttrbDlg ; + } + +protected: + + /// the dialog that allow us to edit the scheme + CAttribWidgetT *_AttrbDlg ; + + /// a wrapper to edit the scheme (which himself owns a scheme !!) + struct CSchemeWrapper : public IPSSchemeWrapper + { + NL3D::CPSAttribMakerMemory *S ; + virtual NL3D::CPSAttribMaker *getScheme(void) const { return S->getScheme() ; } + virtual void setScheme(NL3D::CPSAttribMaker *s) { S->setScheme(s) ; } ; + } _SchemeWrapper ; + + /// a dummy wrapper for constant value. This shouldn't be called , however + struct CDummyWrapper : public IPSWrapper + { + T get(void) const { nlassert(false) ; return T() ; } + void set(const T &) { nlassert(false) ; } + } _DummyWrapper ; +} ; + +} /* namespace NLQT */ + +#endif // VALUE_FROM_EMITTER_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/value_gradient_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/value_gradient_dialog.cpp new file mode 100644 index 000000000..56be8d500 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/value_gradient_dialog.cpp @@ -0,0 +1,395 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "value_gradient_dialog.h" + +// Qt include +#include + +// NeL includes +#include +#include "nel/3d/texture_file.h" +#include "nel/misc/path.h" + +// Projects include +#include "particle_texture_widget.h" + +namespace NLQT { + +CGradientDialog::CGradientDialog(CWorkspaceNode *ownerNode, + IValueGradientClient *clientInterface, + bool destroyClientInterface, + bool canTuneNbStages, + uint minSize, + QWidget *parent) + : QDialog(parent), + _MinSize(minSize), + _CanTuneNbStages(canTuneNbStages), + _ClientInterface(clientInterface), + _DestroyClientInterface(destroyClientInterface), + _Node(ownerNode) +{ + nlassert(_ClientInterface); + + resize(490, 210); + _gridLayout = new QGridLayout(this); + _listWidget = new QListWidget(this); + QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(_listWidget->sizePolicy().hasHeightForWidth()); + _listWidget->setSizePolicy(sizePolicy); + //_listWidget->setIconSize(QSize(16, 16)); + _listWidget->setMaximumSize(QSize(175, 16777215)); + _gridLayout->addWidget(_listWidget, 0, 0, 9, 1); + + _horizontalLayout = new QHBoxLayout(); + _addPushButton = new QPushButton(this); + QSizePolicy sizePolicy1(QSizePolicy::Fixed, QSizePolicy::Fixed); + sizePolicy1.setHorizontalStretch(0); + sizePolicy1.setVerticalStretch(0); + sizePolicy1.setHeightForWidth(_addPushButton->sizePolicy().hasHeightForWidth()); + _addPushButton->setSizePolicy(sizePolicy1); + _addPushButton->setMaximumSize(QSize(36, 36)); + QIcon icon; + icon.addFile(QString::fromUtf8(":/images/list-add.png"), QSize(), QIcon::Normal, QIcon::Off); + _addPushButton->setIcon(icon); + _addPushButton->setIconSize(QSize(24, 24)); + _horizontalLayout->addWidget(_addPushButton); + + _removePushButton = new QPushButton(this); + sizePolicy1.setHeightForWidth(_removePushButton->sizePolicy().hasHeightForWidth()); + _removePushButton->setSizePolicy(sizePolicy1); + _removePushButton->setMinimumSize(QSize(0, 0)); + _removePushButton->setMaximumSize(QSize(36, 36)); + QIcon icon1; + icon1.addFile(QString::fromUtf8(":/images/list-remove.png"), QSize(), QIcon::Normal, QIcon::Off); + _removePushButton->setIcon(icon1); + _removePushButton->setIconSize(QSize(24, 24)); + _horizontalLayout->addWidget(_removePushButton); + + _upPushButton = new QPushButton(this); + sizePolicy1.setHeightForWidth(_upPushButton->sizePolicy().hasHeightForWidth()); + _upPushButton->setSizePolicy(sizePolicy1); + _upPushButton->setMaximumSize(QSize(36, 36)); + QIcon icon2; + icon2.addFile(QString::fromUtf8(":/images/go-up.png"), QSize(), QIcon::Normal, QIcon::Off); + _upPushButton->setIcon(icon2); + _upPushButton->setIconSize(QSize(24, 24)); + _horizontalLayout->addWidget(_upPushButton); + + _downPushButton = new QPushButton(this); + sizePolicy1.setHeightForWidth(_downPushButton->sizePolicy().hasHeightForWidth()); + _downPushButton->setSizePolicy(sizePolicy1); + _downPushButton->setMaximumSize(QSize(36, 36)); + QIcon icon3; + icon3.addFile(QString::fromUtf8(":/images/go-down.png"), QSize(), QIcon::Normal, QIcon::Off); + _downPushButton->setIcon(icon3); + _downPushButton->setIconSize(QSize(24, 24)); + _horizontalLayout->addWidget(_downPushButton); + + _horizontalSpacer = new QSpacerItem(208, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + _horizontalLayout->addItem(_horizontalSpacer); + _gridLayout->addLayout(_horizontalLayout, 0, 1, 1, 2); + + _label = new QLabel(this); + _gridLayout->addWidget(_label, 1, 1, 1, 1); + + _nbStepWidget = new NLQT::CEditRangeUIntWidget(this); + _gridLayout->addWidget(_nbStepWidget, 2, 1, 1, 2); + + _verticalSpacer = new QSpacerItem(20, 85, QSizePolicy::Minimum, QSizePolicy::Expanding); + _gridLayout->addItem(_verticalSpacer, 3, 2, 1, 1); + + editWidget = _ClientInterface->createDialog(this); + _gridLayout->addWidget(editWidget, 4, 1, 1, 2); + + setWindowTitle(_ClientInterface->getTitleDialog()); + _label->setText(tr("Num samples:")); + + if (canTuneNbStages) + { + _NbStepWrapper.OwnerNode = _Node; + _NbStepWrapper.I = _ClientInterface; + _nbStepWidget->setRange(1, 255); + _nbStepWidget->enableLowerBound(0, true); + _nbStepWidget->setWrapper(&_NbStepWrapper); + _nbStepWidget->updateUi(); + } + else + { + _nbStepWidget->hide(); + _label->hide(); + } + + connect(_addPushButton, SIGNAL(clicked()), this, SLOT(addValue())); + connect(_removePushButton, SIGNAL(clicked()), this, SLOT(removeValue())); + connect(_upPushButton, SIGNAL(clicked()), this, SLOT(valueUp())); + connect(_downPushButton, SIGNAL(clicked()), this, SLOT(valueDown())); + connect(_listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(changeCurrentRow(int))); + connect(clientInterface, SIGNAL(itemChanged()), this, SLOT(updateItem())); + + _Size = _ClientInterface->getSchemeSize(); + for (uint k = 0; k < _Size; ++k) + { + QListWidgetItem *item = new QListWidgetItem(); + _ClientInterface->displayValue(k, item); + _listWidget->addItem(item); + } + _removePushButton->setEnabled(_Size > _MinSize ? true : false); + _listWidget->setCurrentRow(0); +} + +CGradientDialog::~CGradientDialog() +{ + if (_DestroyClientInterface) delete _ClientInterface; +} + +void CGradientDialog::addValue() +{ + nlassert(_ClientInterface); + if (!_ClientInterface->modifyGradient(IValueGradientClient::Add, 0)) return; + ++_Size; + QListWidgetItem *item = new QListWidgetItem(); + _ClientInterface->displayValue(_Size - 1, item); + _listWidget->addItem(item); + + _removePushButton->setEnabled(true); + + _listWidget->setCurrentRow(_Size - 1); +} + +void CGradientDialog::insertValue() +{ + nlassert(_ClientInterface); + int oldIndex = _listWidget->currentRow(); + if (!_ClientInterface->modifyGradient(IValueGradientClient::Insert, oldIndex)) return; + ++_Size; + QListWidgetItem *item = new QListWidgetItem(); + _ClientInterface->displayValue(_Size - 1, item); + _listWidget->insertItem(oldIndex, item); + _listWidget->setCurrentRow(oldIndex); +} + +void CGradientDialog::removeValue() +{ + nlassert(_ClientInterface); + + int oldIndex = _listWidget->currentRow(); + if (oldIndex == -1) + return; + + if (uint(oldIndex) == 0) + _listWidget->setCurrentRow(oldIndex + 1); + else + _listWidget->setCurrentRow(oldIndex - 1); + + if (!_ClientInterface->modifyGradient(IValueGradientClient::Delete, oldIndex)) + { + _listWidget->setCurrentRow(oldIndex); + return; + } + + --_Size; + + if (_Size <= _MinSize) + _removePushButton->setEnabled(false); + + QListWidgetItem *removeItem = _listWidget->takeItem(oldIndex); + if (!removeItem) + delete removeItem; +} + +void CGradientDialog::valueDown() +{ + nlassert(_ClientInterface); + int currentRow = _listWidget->currentRow(); + if (!((currentRow == _listWidget->count()-1) || (currentRow == -1))) + { + if (!_ClientInterface->modifyGradient(IValueGradientClient::Down, currentRow)) return; + QListWidgetItem *item = _listWidget->takeItem(currentRow); + _listWidget->insertItem(++currentRow, item); + _listWidget->setCurrentRow(currentRow); + } + _listWidget->setCurrentRow(currentRow); +} + +void CGradientDialog::valueUp() +{ + nlassert(_ClientInterface); + int currentRow = _listWidget->currentRow(); + if (!((currentRow == 0) || (currentRow == -1))) + { + if (!_ClientInterface->modifyGradient(IValueGradientClient::Up, currentRow)) return; + QListWidgetItem *item = _listWidget->takeItem(currentRow); + _listWidget->insertItem(--currentRow, item); + _listWidget->setCurrentRow(currentRow); + } + _listWidget->setCurrentRow(currentRow); +} + +void CGradientDialog::changeCurrentRow(int currentRow) +{ + _ClientInterface->setCurrentIndex(currentRow); +} + +void CGradientDialog::updateItem() +{ + _ClientInterface->displayValue(_listWidget->currentRow(), _listWidget->currentItem()); +} + +QWidget *CTextureGradientInterface::createDialog(QWidget *parent) +{ + editWidget = new CParticleTextureWidget(); + + _TextureWrapper.P = TP; + _TextureWrapper.Index = 0; + _TextureWrapper.OwnerNode = Node; + editWidget->setWrapper(&_TextureWrapper); + connect(editWidget, SIGNAL(textureChanged(QString)), this, SIGNAL(itemChanged())); + return editWidget; +} + +bool CTextureGradientInterface::modifyGradient(TAction action, uint index) +{ + nlassert(TP); + nlassert(TP->getTextureGroup()); + + NLMISC::CSmartPtr tex = TP->getTextureGroup()->getTexture(index); + std::string texName = (static_cast(tex.getPtr()))->getFileName().c_str(); + if (texName.empty()) + return false; + + std::vector< NLMISC::CSmartPtr > textureList; + textureList.resize(TP->getTextureGroup()->getNbTextures()); + TP->getTextureGroup()->getTextures(&textureList[0]); + + switch(action) + { + case IValueGradientClient::Add: + { + // we duplicate the last texture, so that they have the same size + NLMISC::CSmartPtr lastTex = textureList[textureList.size() - 1]; + textureList.push_back(lastTex); + } + break; + case IValueGradientClient::Insert: + { + // we duplicate the current texture, so that they have the same size + NLMISC::CSmartPtr tex = textureList[index]; + textureList.insert(textureList.begin() + index, tex); + } + break; + case IValueGradientClient::Delete: + textureList.erase(textureList.begin() + index); + break; + case IValueGradientClient::Up: + return false; + case IValueGradientClient::Down: + return false; + } + + TP->getTextureGroup()->setTextures(&textureList[0], (uint)textureList.size()); + return true; +} + +void CTextureGradientInterface::displayValue(uint index, QListWidgetItem *item) +{ + QPixmap pixmap; + NLMISC::CSmartPtr tex = TP->getTextureGroup()->getTexture(index); + + if (dynamic_cast(tex.getPtr())) + { + std::string texName = (static_cast(tex.getPtr()))->getFileName().c_str(); + if (!texName.empty()) + { + pixmap.load(NLMISC::CPath::lookup(texName).c_str()); + item->setText(texName.c_str()); + } + else + item->setText("Dummy texture"); + } + item->setIcon(QIcon(pixmap)); +} + +void CTextureGradientInterface::setCurrentIndex(uint index) +{ + _TextureWrapper.Index = index; + editWidget->updateUi(); +} + +uint32 CTextureGradientInterface::getSchemeSize(void) const +{ + nlassert(TP->getTextureGroup()); + return TP->getTextureGroup()->getNbTextures(); +} +uint32 CTextureGradientInterface::getNbSteps(void) const +{ + return 1; +} +void CTextureGradientInterface::setNbSteps(uint32 value) +{ + // this should never be called, as we don't allow nbsteps to be called + nlassert(false); +} + +NL3D::ITexture *CTextureGradientInterface::CTextureWrapper::get(void) +{ + nlassert(P); + nlassert(P->getTextureGroup()); + return P->getTextureGroup()->getTexture(Index); +} + +void CTextureGradientInterface::CTextureWrapper::set(NL3D::ITexture *t) +{ + nlassert(P); + nlassert(P->getTextureGroup()); + + // if a texture is added, it must have the same size than other textures + if (P->getTextureGroup()->getNbTextures() > 1) + { + NLMISC::CSmartPtr tex = P->getTextureGroup()->getTexture(0); + tex->generate(); + t->generate(); + + if (t->getWidth() != tex->getWidth() || t->getHeight() != tex->getHeight()) + { + QMessageBox::critical(0, QString("Texture error"), QString("All textures must have the same size !"), QMessageBox::Ok); + return; + } + + if (t->PixelFormat != tex->PixelFormat) + { + QMessageBox::critical(0, QString("Texture error"), QString("All textures must have the same pixel format !"), QMessageBox::Ok); + return; + } + } + + std::vector< NLMISC::CSmartPtr > textureList; + textureList.resize(P->getTextureGroup()->getNbTextures()); + P->getTextureGroup()->getTextures(&textureList[0]); + + textureList[Index] = t; + + + P->getTextureGroup()->setTextures(&textureList[0], (uint)textureList.size()); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/value_gradient_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/value_gradient_dialog.h new file mode 100644 index 000000000..1ebaff85a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/value_gradient_dialog.h @@ -0,0 +1,476 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef VALUE_GRADIENT_DIALOG_H +#define VALUE_GRADIENT_DIALOG_H + +#include + +// Qt includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// NeL includes +#include + +// Project includes +#include "basic_edit_widget.h" +#include "color_edit_widget.h" +#include "edit_range_widget.h" +#include "ps_wrapper.h" +#include "particle_node.h" + +namespace NL3D { + class CPSTexturedParticle; +} + +namespace NLQT { + +class CParticleTextureWidget; + +class IValueGradientClient: public QObject +{ + Q_OBJECT +public: + IValueGradientClient(QObject *parent = 0): QObject(parent) {} + + virtual QWidget *createDialog(QWidget *parent) = 0; + + /// Return the title of dialog in client + virtual QString getTitleDialog() const = 0; + + /// This enumerate the action that we can apply on a gradient + enum TAction { Add, Insert, Delete, Up, Down }; + + /// A function that can display a value in a gradient, with the given offset + virtual void displayValue(uint index, QListWidgetItem *item) = 0; + + virtual void setCurrentIndex(uint index) = 0; + + /// A function that can add, remove, or insert a new element in the gradient + virtual bool modifyGradient(TAction, uint index) = 0; + + /// Return the number of values in a scheme + virtual uint32 getSchemeSize(void) const = 0; + + /// Get the number of interpolation step + virtual uint32 getNbSteps(void) const = 0; + + /// Set the number of interpolation steps + virtual void setNbSteps(uint32 value) = 0; + +Q_SIGNALS: + void itemChanged(); +}; + +class CGradientDialog: public QDialog +{ + Q_OBJECT + +public: + CGradientDialog(CWorkspaceNode *ownerNode, + IValueGradientClient *clientInterface, + bool destroyClientInterface, + bool canTuneNbStages = true, + uint minSize = 2, + QWidget *parent = 0); + ~CGradientDialog(); + +private Q_SLOTS: + void addValue(); + void insertValue(); + void removeValue(); + void valueDown(); + void valueUp(); + void changeCurrentRow(int currentRow); + void updateItem(); + +protected: + + // the minimum number of element in the gradient + uint _MinSize; + + // false to disable the dialog that control the number of stages between each value + bool _CanTuneNbStages; + + IValueGradientClient *_ClientInterface; + + bool _DestroyClientInterface; + + // the current size of the gradient + uint _Size; + + CWorkspaceNode *_Node; + + // a wrapper to tune the number of step + struct CNbStepWrapper :public IPSWrapperUInt + { + // the interface that was passed to the dialog this struct is part of + IValueGradientClient *I; + uint32 get(void) const { return I->getNbSteps(); } + void set(const uint32 &nbSteps) { I->setNbSteps(nbSteps); } + + } _NbStepWrapper; + + QGridLayout *_gridLayout; + QListWidget *_listWidget; + QHBoxLayout *_horizontalLayout; + QPushButton *_addPushButton; + QPushButton *_removePushButton; + QPushButton *_upPushButton; + QPushButton *_downPushButton; + QSpacerItem *_horizontalSpacer; + QLabel *_label; + NLQT::CEditRangeUIntWidget *_nbStepWidget; + QSpacerItem *_verticalSpacer; + QWidget *editWidget; +}; /* class CGradientDialog */ + +/** +@class CValueGradientClientT +@brief This template generate an interface that is used with the gradient edition dialog +This the type to be edited (color, floet, etc..) + */ +template +class CValueGradientClientT : public IValueGradientClient, public IPSWrapper +{ +public: + CValueGradientClientT(QObject *parent = 0): IValueGradientClient(parent) {} + + /// the gradient being edited, must be filled by the instancier + NL3D::CPSValueGradientFunc *Scheme; + + /// the gradient dialog, must be filled by the instancier + T DefaultValue; + + /// inherited from IPSWrapper + virtual T get(void) const { return Scheme->getValue(_CurrentEditedIndex); } + virtual void set(const T &v) + { + T *tab = new T[Scheme->getNumValues()]; + Scheme->getValues(tab); + tab[_CurrentEditedIndex] = v; + Scheme->setValues(tab, Scheme->getNumValues(), Scheme->getNumStages()); + delete[] tab; + } + + virtual QWidget *createDialog(QWidget *parent) + { + return newDialog(this, parent); + } + + virtual QString getTitleDialog() const = 0; + + /// create a new dialog with given id and wrapper + virtual QWidget *newDialog(IPSWrapper *wrapper, QWidget *parent) = 0; + + virtual void setCurrentIndex(uint index) = 0; + + virtual void displayValue(uint index, QListWidgetItem *item) = 0; + + /// a function that can add, remove, or insert a new element in the gradient + virtual bool modifyGradient(TAction action, uint index) + { + + T *tab = new T[Scheme->getNumValues() + 1]; // +1 is for the add / insert case + Scheme->getValues(tab); + + switch(action) + { + case IValueGradientClient::Add: + tab[Scheme->getNumValues()] = DefaultValue; + Scheme->setValues(tab, Scheme->getNumValues() + 1, Scheme->getNumStages()); + break; + case IValueGradientClient::Insert: + ::memmove(tab + (index + 1), tab + index, sizeof(T) * (Scheme->getNumValues() - index)); + tab[index] = DefaultValue; + Scheme->setValues(tab, Scheme->getNumValues() + 1, Scheme->getNumStages()); + break; + case IValueGradientClient::Delete: + ::memmove(tab + index, tab + index + 1, sizeof(T) * (Scheme->getNumValues() - index - 1)); + Scheme->setValues(tab, Scheme->getNumValues() - 1, Scheme->getNumStages()); + break; + case IValueGradientClient::Up: + nlassert(index > 0); + std::swap(tab[index], tab[index - 1]); + Scheme->setValues(tab, Scheme->getNumValues(), Scheme->getNumStages()); + break; + case IValueGradientClient::Down: + nlassert(index < Scheme->getNumValues() - 1); + std::swap(tab[index], tab[index + 1]); + Scheme->setValues(tab, Scheme->getNumValues(), Scheme->getNumStages()); + break; + } + + delete[] tab; + return true; + } + virtual uint32 getSchemeSize(void) const { return Scheme->getNumValues(); } + + /// Get the number of interpolation step + uint32 getNbSteps(void) const + { + return Scheme->getNumStages(); + } + + /// Set the number of interpolation steps + void setNbSteps(uint32 value) + { + Scheme->setNumStages(value); + } + +protected: + // index of the value OF the current dialog that exist + uint32 _CurrentEditedIndex; +}; /* class CValueGradientClientT */ + +/// FLOAT GRADIENT EDITION INTERFACE +class CFloatGradientWrapper : public CValueGradientClientT +{ + Q_OBJECT +public: + CFloatGradientWrapper(QObject *parent = 0): CValueGradientClientT(parent) {} + + virtual QWidget *newDialog(IPSWrapperFloat *wrapper, QWidget *parent) + { + editWidget = new CEditRangeFloatWidget(parent); + editWidget->setRange(MinRange, MaxRange); + editWidget->setWrapper(wrapper); + connect(editWidget, SIGNAL(valueChanged(float)), this, SIGNAL(itemChanged())); + return editWidget; + } + + virtual QString getTitleDialog() const + { + return tr("Float values gradient dialog"); + } + + virtual void setCurrentIndex(uint index) + { + _CurrentEditedIndex = index; + editWidget->updateUi(); + } + + virtual void displayValue(uint index, QListWidgetItem *item) + { + item->setText(QString("%1").arg(Scheme->getValue(index),0,'f',2)); + } + + CEditRangeFloatWidget *editWidget; + float MinRange, MaxRange; +}; /* CFloatGradientWrapper */ + +/// UINT GRADIENT EDITION INTERFACE +class CUIntGradientWrapper : public CValueGradientClientT +{ + Q_OBJECT +public: + CUIntGradientWrapper(QObject *parent = 0): CValueGradientClientT(parent) {} + + virtual QWidget *newDialog(IPSWrapperUInt *wrapper, QWidget *parent) + { + editWidget = new CEditRangeUIntWidget(parent); + editWidget->setRange(MinRange, MaxRange); + editWidget->setWrapper(wrapper); + connect(editWidget, SIGNAL(valueChanged(uint32)), this, SIGNAL(itemChanged())); + return editWidget; + } + + virtual QString getTitleDialog() const + { + return tr("UInt values gradient dialog"); + } + + virtual void setCurrentIndex(uint index) + { + _CurrentEditedIndex = index; + editWidget->updateUi(); + } + + virtual void displayValue(uint index, QListWidgetItem *item) + { + item->setText(QString("%1").arg(Scheme->getValue(index))); + } + + CEditRangeUIntWidget *editWidget; + uint32 MinRange, MaxRange; +}; /* CUIntGradientWrapper */ + +/// INT GRADIENT EDITION INTERFACE +class CIntGradientWrapper : public CValueGradientClientT +{ + Q_OBJECT +public: + CIntGradientWrapper(QObject *parent = 0): CValueGradientClientT(parent) {} + + virtual QWidget *newDialog(IPSWrapper *wrapper, QWidget *parent) + { + editWidget = new CEditRangeIntWidget(parent); + editWidget->setRange(MinRange, MaxRange); + editWidget->setWrapper(wrapper); + connect(editWidget, SIGNAL(valueChanged(sint32)), this, SIGNAL(itemChanged())); + return editWidget; + } + + virtual QString getTitleDialog() const + { + return tr("Int values gradient dialog"); + } + + virtual void setCurrentIndex(uint index) + { + _CurrentEditedIndex = index; + editWidget->updateUi(); + } + + virtual void displayValue(uint index, QListWidgetItem *item) + { + item->setText(QString("%1").arg(Scheme->getValue(index))); + } + + CEditRangeIntWidget *editWidget; + sint32 MinRange, MaxRange; +}; /* CIntGradientWrapper */ + +/// COLOR GRADIENT EDITION INTERFACE +class CColorGradientWrapper : public CValueGradientClientT +{ + Q_OBJECT +public: + CColorGradientWrapper(QObject *parent = 0): CValueGradientClientT(parent) {} + + virtual QWidget *newDialog(IPSWrapper *wrapper, QWidget *parent) + { + editWidget = new CColorEditWidget(parent); + editWidget->setWrapper(wrapper); + connect(editWidget, SIGNAL(colorChanged(NLMISC::CRGBA)), this, SIGNAL(itemChanged())); + return editWidget; + } + + virtual QString getTitleDialog() const + { + return tr("Color gradient dialog"); + } + + virtual void setCurrentIndex(uint index) + { + _CurrentEditedIndex = index; + editWidget->updateUi(); + } + + virtual void displayValue(uint index, QListWidgetItem *item) + { + NLMISC::CRGBA color = Scheme->getValue(index); + item->setText(QString("RGBA(%1,%2,%3,%4)").arg(color.R).arg(color.G).arg(color.B).arg(color.A)); + QPixmap pixmap(QSize(16, 16)); + QPainter painter(&pixmap); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.setBrush(QBrush(QColor(color.R, color.G, color.B))); + painter.setPen(QPen(Qt::black, 1, Qt::SolidLine)); + painter.drawRect(0, 0, pixmap.width() , pixmap.height()); + item->setIcon(QIcon(pixmap)); + } + + CColorEditWidget *editWidget; +}; /* CColorGradientWrapper */ + +/// PLANE BASIS GRADIENT EDITION INTERFACE +class CPlaneBasisGradientWrapper : public CValueGradientClientT +{ + Q_OBJECT +public: + CPlaneBasisGradientWrapper(QObject *parent = 0): CValueGradientClientT(parent) {} + + virtual QWidget *newDialog(IPSWrapper *wrapper, QWidget *parent) + { + editWidget = new CBasicEditWidget(parent); + editWidget->setWrapper(wrapper); + return editWidget; + } + virtual QString getTitleDialog() const + { + return tr("Plane basis gradient dialog"); + } + virtual void setCurrentIndex(uint index) + { + _CurrentEditedIndex = index; + editWidget->updateUi(); + } + + virtual void displayValue(uint index, QListWidgetItem *item) + { + item->setText(QString("Plane %1").arg(index)); + } + + CBasicEditWidget *editWidget; +}; /* class CPlaneBasisGradientWrapper */ + +/** +@class CTextureGradientInterface +@brief The implementation of this struct tells the gradient dialog bow how to edit a texture list +*/ +class CTextureGradientInterface : public IValueGradientClient +{ + Q_OBJECT +public: + CTextureGradientInterface(QObject *parent = 0): IValueGradientClient(parent) {} + + CTextureGradientInterface(NL3D::CPSTexturedParticle *tp, CWorkspaceNode *ownerNode): Node(ownerNode), TP(tp) {} + + CWorkspaceNode *Node; + NL3D::CPSTexturedParticle *TP; + + // all method inherited from IValueGradientClient + virtual QWidget *createDialog(QWidget *parent); + virtual QString getTitleDialog() const + { + return tr("Texture grouped dialog"); + } + virtual bool modifyGradient(TAction, uint index); + virtual void displayValue(uint index, QListWidgetItem *item); + virtual void setCurrentIndex(uint index); + virtual uint32 getSchemeSize(void) const; + virtual uint32 getNbSteps(void) const; + virtual void setNbSteps(uint32 value); + + /// wrapper for the texture chooser + /// that allows to choose a texture in the list + struct CTextureWrapper : public IPSWrapperTexture + { + NL3D::CPSTexturedParticle *P; + // index of the particle in the list + uint32 Index; + NL3D::ITexture *get(void); + void set(NL3D::ITexture *t); + } _TextureWrapper; + + CParticleTextureWidget *editWidget; +}; + +} /* namespace NLQT */ + +#endif // VALUE_GRADIENT_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_appearance_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/vegetable_appearance_page.cpp new file mode 100644 index 000000000..dfa8d3e92 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_appearance_page.cpp @@ -0,0 +1,235 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "vegetable_appearance_page.h" + +// Qt includes +#include +#include +#include + +// NeL includes +#include + +// Projects include +#include "modules.h" + +namespace NLQT { + +CVegetableApperancePage::CVegetableApperancePage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + _ui.bendPhaseGroupBox->setDefaultRangeAbs(NL_VEGETABLE_BENDPHASE_RANGE_MIN, NL_VEGETABLE_BENDPHASE_RANGE_MAX); + _ui.bendPhaseGroupBox->setDefaultRangeRand(NL_VEGETABLE_BENDPHASE_RANGE_MIN, NL_VEGETABLE_BENDPHASE_RANGE_MAX); + _ui.bendPhaseGroupBox->setDefaultRangeFreq(NL_VEGETABLE_FREQ_RANGE_MIN, NL_VEGETABLE_FREQ_RANGE_MAX); + + _ui.bendFactorGroupBox->setDefaultRangeAbs(NL_VEGETABLE_BENDFACTOR_RANGE_MIN, NL_VEGETABLE_BENDFACTOR_RANGE_MAX); + _ui.bendFactorGroupBox->setDefaultRangeRand(NL_VEGETABLE_BENDFACTOR_RANGE_MIN, NL_VEGETABLE_BENDFACTOR_RANGE_MAX); + _ui.bendFactorGroupBox->setDefaultRangeFreq(NL_VEGETABLE_FREQ_RANGE_MIN, NL_VEGETABLE_FREQ_RANGE_MAX); + + _ui.colorNoiseGroupBox->setDefaultRangeAbs(NL_VEGETABLE_COLOR_RANGE_MIN, NL_VEGETABLE_COLOR_RANGE_MAX); + _ui.colorNoiseGroupBox->setDefaultRangeRand(NL_VEGETABLE_COLOR_RANGE_MIN, NL_VEGETABLE_COLOR_RANGE_MAX); + _ui.colorNoiseGroupBox->setDefaultRangeFreq(NL_VEGETABLE_FREQ_RANGE_MIN, NL_VEGETABLE_FREQ_RANGE_MAX); + + connect(_ui.bendFactorGroupBox, SIGNAL(noiseValueChanged(NLMISC::CNoiseValue)), this, SLOT(setNoiseValueBendFactor(NLMISC::CNoiseValue))); + connect(_ui.bendPhaseGroupBox, SIGNAL(noiseValueChanged(NLMISC::CNoiseValue)), this, SLOT(setNoiseValueBendPhase(NLMISC::CNoiseValue))); + connect(_ui.colorNoiseGroupBox, SIGNAL(noiseValueChanged(NLMISC::CNoiseValue)), this, SLOT(setNoiseValueColor(NLMISC::CNoiseValue))); + + connect(_ui.addColorPushButton, SIGNAL(clicked()), this, SLOT(addNewColor())); + connect(_ui.insColorPushButton, SIGNAL(clicked()), this, SLOT(insNewColor())); + connect(_ui.removePushButton, SIGNAL(clicked()), this, SLOT(removeColor())); + connect(_ui.getListPushButton, SIGNAL(clicked()), this, SLOT(getFromListColors())); + + connect(_ui.listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(browseColor(QListWidgetItem*))); + setEnabled(false); +} + +CVegetableApperancePage::~CVegetableApperancePage() +{ +} + +QIcon getRectColorIcon(QColor color) +{ + QPixmap pixmap(QSize(32, 32)); + QPainter painter(&pixmap); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.setBrush(QBrush(color)); + painter.setPen(QPen(Qt::black, 1, Qt::SolidLine)); + painter.drawRect(0, 0, pixmap.width() , pixmap.height()); + return QIcon(pixmap); +} + +void CVegetableApperancePage::setVegetableToEdit(NL3D::CVegetable *vegetable) +{ + _Vegetable = vegetable; + + if(_Vegetable) + { + setEnabled(true); + _ui.bendPhaseGroupBox->setNoiseValue(_Vegetable->BendPhase, false); + _ui.bendFactorGroupBox->setNoiseValue(_Vegetable->BendFactor, false); + _ui.colorNoiseGroupBox->setNoiseValue(_Vegetable->Color.NoiseValue, false); + + updateColorList(); + } + else + setEnabled(false); +} + +void CVegetableApperancePage::setNoiseValueBendPhase(NLMISC::CNoiseValue value) +{ + _Vegetable->BendPhase = value; + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableApperancePage::setNoiseValueBendFactor(NLMISC::CNoiseValue value) +{ + _Vegetable->BendFactor = value; + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableApperancePage::setNoiseValueColor(NLMISC::CNoiseValue value) +{ + _Vegetable->Color.NoiseValue = value; + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableApperancePage::browseColor(QListWidgetItem * item) +{ + sint row = _ui.listWidget->currentRow(); + + NLMISC::CRGBA oldColor = _Vegetable->Color.Gradients[row]; + QColor color = QColorDialog::getColor(QColor(oldColor.R, oldColor.G, oldColor.B)); + if (!color.isValid()) return; + + item->setIcon(getRectColorIcon(color)); + + _Vegetable->Color.Gradients[row] = NLMISC::CRGBA(color.red(), color.green(), color.blue()); + + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableApperancePage::addNewColor() +{ + sint row = _ui.listWidget->currentRow(); + + // copy the current selected color + NLMISC::CRGBA color(255, 255, 255); + if(row != -1) + color = _Vegetable->Color.Gradients[row]; + + // update view and vegetable + QListWidgetItem *item = new QListWidgetItem(); + + item->setIcon(getRectColorIcon(QColor(color.R, color.G, color.B))); + + _ui.listWidget->addItem(item); + + _Vegetable->Color.Gradients.push_back(color); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableApperancePage::insNewColor() +{ + sint row = _ui.listWidget->currentRow(); + + // copy the current selected color + NLMISC::CRGBA color(255, 255, 255); + + if(row != -1) + color = _Vegetable->Color.Gradients[row]; + else + row++; + + // update view and vegetable + QListWidgetItem *item = new QListWidgetItem(); + + item->setIcon(getRectColorIcon(QColor(color.R, color.G, color.B))); + + _ui.listWidget->insertItem(row, item); + + _Vegetable->Color.Gradients.insert(_Vegetable->Color.Gradients.begin() + row ,color); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableApperancePage::removeColor() +{ + sint row = _ui.listWidget->currentRow(); + if (row == -1) return; + + // remove curSel from the list + QListWidgetItem *item = _ui.listWidget->takeItem(row); + delete item; + _Vegetable->Color.Gradients.erase(_Vegetable->Color.Gradients.begin() + row); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableApperancePage::getFromListColors() +{ + std::vector listVegetables; + Modules::veget().getListVegetables(listVegetables); + if (listVegetables.empty()) + return; + + QStringList items; + for(size_t i = 0; i < listVegetables.size(); ++i) + items << QString(listVegetables[i].c_str()); + + bool ok; + QString item = QInputDialog::getItem(this, tr("Select on other vegetables"), + tr("Select the other vegetable to copy color."), items, 0, false, &ok); + if (ok) + { + int i = items.indexOf(item); + + NL3D::CVegetable *otherVegetable = Modules::veget().getVegetable(i)->Vegetable; + + _Vegetable->Color.Gradients = otherVegetable->Color.Gradients; + + updateColorList(); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); + } +} + +void CVegetableApperancePage::updateColorList() +{ + // clear all + _ui.listWidget->clear(); + // fill list. + for(uint i = 0; i < _Vegetable->Color.Gradients.size(); i++) + { + NLMISC::CRGBA color = _Vegetable->Color.Gradients[i]; + QListWidgetItem *item = new QListWidgetItem(); + item->setIcon(getRectColorIcon(QColor(color.R, color.G, color.B))); + _ui.listWidget->addItem(item); + } +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_appearance_page.h b/code/nel/tools/3d/object_viewer_qt/src/vegetable_appearance_page.h new file mode 100644 index 000000000..e68e1e904 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_appearance_page.h @@ -0,0 +1,71 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef VEGETABLE_APPEARANCE_PAGE_H +#define VEGETABLE_APPEARANCE_PAGE_H + +#include "ui_vegetable_apperance_form.h" + +// STL includes + +// NeL includes + +// Project includes + +namespace NL3D +{ + class CVegetable; +} + +namespace NLQT { + +class CVegetableApperancePage: public QWidget +{ + Q_OBJECT + +public: + CVegetableApperancePage(QWidget *parent = 0); + ~CVegetableApperancePage(); + + /// set the vegetble to edit. NULL will disable all the controls. + void setVegetableToEdit(NL3D::CVegetable *vegetable); + +private Q_SLOTS: + void setNoiseValueBendPhase(NLMISC::CNoiseValue value); + void setNoiseValueBendFactor(NLMISC::CNoiseValue value); + void setNoiseValueColor(NLMISC::CNoiseValue value); + void browseColor(QListWidgetItem * item); + void addNewColor(); + void insNewColor(); + void removeColor(); + void getFromListColors(); + +private: + void updateColorList(); + + // The vegetable to edit. + NL3D::CVegetable *_Vegetable; + + Ui::CVegetableApperancePage _ui; + +}; /* class CVegetableApperancePage */ + +} /* namespace NLQT */ + +#endif // VEGETABLE_APPEARANCE_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_apperance_form.ui b/code/nel/tools/3d/object_viewer_qt/src/vegetable_apperance_form.ui new file mode 100644 index 000000000..a1874f0a4 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_apperance_form.ui @@ -0,0 +1,166 @@ + + + CVegetableApperancePage + + + + 0 + 0 + 340 + 309 + + + + Form + + + + + + QTabWidget::South + + + QTabWidget::Rounded + + + 0 + + + true + + + false + + + + Bend Phase + + + + + + + + + + + + + + Bend Factor + + + + + + + + + + + + + + + + + Color Noise + + + + + + + Color setup + + + + + + + 0 + 0 + + + + Double cliclk to change color + + + QListView::LeftToRight + + + QListView::IconMode + + + + + + + + + + + :/images/list-remove.png:/images/list-remove.png + + + + + + + Get List from other + + + + + + + + + + + :/images/insert-horizontal.png:/images/insert-horizontal.png + + + + + + + + + + + :/images/list-add.png:/images/list-add.png + + + + + + + + + + Qt::Vertical + + + + 20 + 34 + + + + + + + + + NLQT::CVegetNoiseValueWidget + QGroupBox +
vegetable_noise_value_widget.h
+ 1 +
+
+ + + + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_density_form.ui b/code/nel/tools/3d/object_viewer_qt/src/vegetable_density_form.ui new file mode 100644 index 000000000..563460e29 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_density_form.ui @@ -0,0 +1,382 @@ + + + CVegetableDensityPage + + + + 0 + 0 + 314 + 568 + + + + Form + + + + + + Vegetable mesh selection + + + + + + true + + + + + + + Browse + + + + + + + + + + + + Distance of creation + + + distanceSpinBox + + + + + + + 0 m + + + 1 + + + 5 + + + + + + + + + Density + + + + + + + MaxDensity + + + + + + MaxDensity enabled + + + + + + + false + + + + + + + + + + Angle setup + + + + + + Angle Mode: + + + + + + + Floor + + + + + + + Wall + + + + + + + Ceiling + + + + + + + AngleMin + + + angleMinHorizontalSlider + + + + + + + false + + + -1000 + + + 1000 + + + Qt::Horizontal + + + + + + + false + + + -99.000000000000000 + + + + + + + AngleMax + + + angleMaxHorizontalSlider + + + + + + + false + + + -1000 + + + 1000 + + + Qt::Horizontal + + + + + + + false + + + -99.000000000000000 + + + + + + + + + + Qt::Vertical + + + + 20 + 239 + + + + + + + + + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CVegetNoiseValueWidget + QGroupBox +
vegetable_noise_value_widget.h
+ 1 +
+
+ + + + maxDensityCheckBox + toggled(bool) + maxDensityWidget + setEnabled(bool) + + + 99 + 221 + + + 110 + 244 + + + + + wallRadioButton + toggled(bool) + angleMinHorizontalSlider + setEnabled(bool) + + + 272 + 331 + + + 270 + 353 + + + + + wallRadioButton + toggled(bool) + angleMinDoubleSpinBox + setEnabled(bool) + + + 294 + 329 + + + 361 + 355 + + + + + wallRadioButton + toggled(bool) + angleMaxHorizontalSlider + setEnabled(bool) + + + 307 + 331 + + + 301 + 377 + + + + + wallRadioButton + toggled(bool) + angleMaxDoubleSpinBox + setEnabled(bool) + + + 312 + 333 + + + 355 + 378 + + + + + floorRadioButton + toggled(bool) + angleMinHorizontalSlider + setEnabled(bool) + + + 178 + 335 + + + 174 + 346 + + + + + ceilingRadioButton + toggled(bool) + angleMaxHorizontalSlider + setEnabled(bool) + + + 343 + 331 + + + 304 + 390 + + + + + floorRadioButton + toggled(bool) + angleMinDoubleSpinBox + setEnabled(bool) + + + 219 + 335 + + + 381 + 358 + + + + + ceilingRadioButton + toggled(bool) + angleMaxDoubleSpinBox + setEnabled(bool) + + + 385 + 329 + + + 398 + 377 + + + + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_density_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/vegetable_density_page.cpp new file mode 100644 index 000000000..c49ba9111 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_density_page.cpp @@ -0,0 +1,304 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "vegetable_density_page.h" + +// Qt includes +#include +#include + +// NeL includes +#include +#include +#include + +// Projects include +#include "modules.h" +#include "vegetable_dialog.h" + +namespace NLQT { + +CVegetableDensityPage::CVegetableDensityPage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + // Init Density widget. + _ui.densityGroupBox->setDefaultRangeAbs(NL_VEGETABLE_DENSITY_ABS_RANGE_MIN, NL_VEGETABLE_DENSITY_ABS_RANGE_MAX); + _ui.densityGroupBox->setDefaultRangeRand(NL_VEGETABLE_DENSITY_RAND_RANGE_MIN, NL_VEGETABLE_DENSITY_RAND_RANGE_MAX); + _ui.densityGroupBox->setDefaultRangeFreq(NL_VEGETABLE_FREQ_RANGE_MIN, NL_VEGETABLE_FREQ_RANGE_MAX); + + // Init MaxDensity widget. + _ui.maxDensityWidget->setRange(0, NL_VEGETABLE_EDIT_DEFAULT_MAX_DENSITY); + _ui.maxDensityWidget->enableLowerBound(0, false); + + + connect(_ui.browseShapePushButton, SIGNAL(clicked()), this, SLOT(browseShapeVeget())); + connect(_ui.distanceSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setDistanceOfCreat(int))); + connect(_ui.densityGroupBox, SIGNAL(noiseValueChanged(NLMISC::CNoiseValue)), this, SLOT(setDensity(NLMISC::CNoiseValue))); + connect(_ui.maxDensityCheckBox, SIGNAL(toggled(bool)), this, SLOT(setEnabledMaxDensity(bool))); + connect(_ui.maxDensityWidget, SIGNAL(valueChanged(float)), this, SLOT(setMaxDensity(float))); + connect(_ui.floorRadioButton, SIGNAL(clicked()), this, SLOT(updateAngleMode())); + connect(_ui.wallRadioButton, SIGNAL(clicked()), this, SLOT(updateAngleMode())); + connect(_ui.ceilingRadioButton, SIGNAL(clicked()), this, SLOT(updateAngleMode())); + connect(_ui.angleMinHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setAngleMinSlider(int))); + connect(_ui.angleMaxHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setAngleMaxSlider(int))); + + setEnabled(false); +} + +CVegetableDensityPage::~CVegetableDensityPage() +{ +} + +void CVegetableDensityPage::setVegetableToEdit(NL3D::CVegetable *vegetable) +{ + _Vegetable = vegetable; + + if(_Vegetable) + { + setEnabled(true); + + // ShapeName + _ui.meshLineEdit->setText(QString(_Vegetable->ShapeName.c_str())); + + // Creation Distance. + // normalize creation distance for this editor. + _Vegetable->DistType = std::min(uint(_Vegetable->DistType), uint(_ui.distanceSpinBox->maximum()) ); + + // set Creation Distance. + _ui.distanceSpinBox->setValue(_Vegetable->DistType + 1); + + // set density widget + _ui.densityGroupBox->setNoiseValue(_Vegetable->Density, false); + + // init MaxDensity + if(_Vegetable->MaxDensity == -1) + { + // Disable the checkBox and the slider. + _ui.maxDensityCheckBox->setChecked(false); + + _PrecMaxDensityValue = NL_VEGETABLE_EDIT_DEFAULT_MAX_DENSITY; + } + else + { + // Enable the checkBox and the slider + _PrecMaxDensityValue = _Vegetable->MaxDensity; + _ui.maxDensityCheckBox->setChecked(true); + _ui.maxDensityWidget->setValue(_Vegetable->MaxDensity, false); + } + + // init AngleSetup. + // ---------- + NL3D::CVegetable::TAngleType angType = _Vegetable->getAngleType(); + + // enable only the one of interest. + _ui.floorRadioButton->blockSignals(true); + _ui.wallRadioButton->blockSignals(true); + _ui.ceilingRadioButton->blockSignals(true); + switch(angType) + { + case NL3D::CVegetable::AngleGround: + updateAngleMin(); + _ui.floorRadioButton->setChecked(true); + break; + case NL3D::CVegetable::AngleWall: + updateAngleMin(); + updateAngleMax(); + _ui.wallRadioButton->setChecked(true); + break; + case NL3D::CVegetable::AngleCeiling: + updateAngleMax(); + _ui.ceilingRadioButton->setChecked(true); + break; + } + _ui.floorRadioButton->blockSignals(false); + _ui.wallRadioButton->blockSignals(false); + _ui.ceilingRadioButton->blockSignals(false); + } + else + setEnabled(false); +} + +void CVegetableDensityPage::browseShapeVeget() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Open Vegetable Shape"), + ".", + tr("veget files (*.veget);;")); + if (!fileName.isEmpty()) + { + // Add search path for the .veget + NLMISC::CPath::addSearchPath (NLMISC::CFile::getPath(fileName.toStdString())); + + try + { + // update shapeName and view + _Vegetable->ShapeName = NLMISC::CFile::getFilename(fileName.toStdString()); + _ui.meshLineEdit->setText(QString(NLMISC::CFile::getFilename(fileName.toStdString()).c_str())); + + // update the name in the list-box + Q_EMIT vegetNameChanged(); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); + } + catch (NLMISC::EPathNotFound &ep) + { + QMessageBox::critical(this, "Can't open file", QString(ep.what()), QMessageBox::Ok); + } + } +} + +void CVegetableDensityPage::setDistanceOfCreat(int value) +{ + // Get the DistType, and just copy to vegetable. + _Vegetable->DistType = value - 1; + + // Since used to display name in selection listBox, must update the name + Q_EMIT vegetNameChanged(); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableDensityPage::setEnabledMaxDensity(bool state) +{ + if(state) + { + // check, restore maxDensity + _Vegetable->MaxDensity = _PrecMaxDensityValue; + // enable dlg. + _ui.maxDensityWidget->setValue(_PrecMaxDensityValue); + _ui.maxDensityWidget->setEnabled(true); + } + else + { + // uncheck, bkup maxDenstiy + _PrecMaxDensityValue = _Vegetable->MaxDensity; + + _ui.maxDensityWidget->setEnabled(false); + + // and setup vegetable (disable MaxDensity). + _Vegetable->MaxDensity= -1; + } + + // update 3D view + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableDensityPage::updateAngleMode() +{ + if (_ui.floorRadioButton->isChecked()) + { + _Vegetable->setAngleGround(0); + updateAngleMin(); + } + if (_ui.wallRadioButton->isChecked()) + { + _Vegetable->setAngleWall(-1, 1); + updateAngleMin(); + updateAngleMax(); + } + if (_ui.ceilingRadioButton->isChecked()) + { + _Vegetable->setAngleCeiling(0); + updateAngleMax(); + } + // update 3D view + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableDensityPage::setDensity(NLMISC::CNoiseValue value) +{ + _Vegetable->Density = value; + + // update 3D view + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableDensityPage::setMaxDensity(float value) +{ + _Vegetable->MaxDensity = value; + + // update 3D view + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableDensityPage::setAngleMinSlider(int pos) +{ + float angle = 180 * float(pos) / float(abs(_ui.angleMinHorizontalSlider->maximum() - _ui.angleMinHorizontalSlider->minimum())); + NLMISC::clamp(angle, -90, 90); + // make a sinus, because 90 => 1, and -90 =>-1 + float cosAngleMin = float(sin(angle * NLMISC::Pi / 180.f)); + + // setup vegetable. + if(_Vegetable->getAngleType()== NL3D::CVegetable::AngleWall) + _Vegetable->setAngleWall(cosAngleMin, _Vegetable->getCosAngleMax()); + else + _Vegetable->setAngleGround(cosAngleMin); + + // update view + _ui.angleMinDoubleSpinBox->setValue(angle); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableDensityPage::setAngleMaxSlider(int pos) +{ + float angle = 180 * float(pos) / float(abs(_ui.angleMaxHorizontalSlider->maximum() - _ui.angleMaxHorizontalSlider->minimum())); + NLMISC::clamp(angle, -90, 90); + // make a sinus, because 90 => 1, and -90 =>-1 + float cosAngleMax = float(sin(angle * NLMISC::Pi / 180.f)); + + // setup vegetable. + if(_Vegetable->getAngleType() == NL3D::CVegetable::AngleWall) + _Vegetable->setAngleWall(_Vegetable->getCosAngleMin(), cosAngleMax); + else + _Vegetable->setAngleCeiling(cosAngleMax); + + // update view + _ui.angleMaxDoubleSpinBox->setValue(angle); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableDensityPage::updateAngleMin() +{ + double angle = _Vegetable->getCosAngleMin(); + NLMISC::clamp(angle, -1, 1); + angle = asin(angle) * (180.f / NLMISC::Pi); + sint pos = sint(angle * abs(_ui.angleMinHorizontalSlider->maximum() - _ui.angleMinHorizontalSlider->minimum()) / 180); + NLMISC::clamp(pos, _ui.angleMinHorizontalSlider->minimum(), _ui.angleMinHorizontalSlider->maximum()); + _ui.angleMinHorizontalSlider->setSliderPosition(pos); +} + +void CVegetableDensityPage::updateAngleMax() +{ + double angle = _Vegetable->getCosAngleMax(); + NLMISC::clamp(angle, -1, 1); + angle = asin(angle) * (180.f / NLMISC::Pi); + sint pos = sint(angle * abs(_ui.angleMaxHorizontalSlider->maximum() - _ui.angleMaxHorizontalSlider->minimum()) / 180); + NLMISC::clamp(pos, _ui.angleMaxHorizontalSlider->minimum(), _ui.angleMaxHorizontalSlider->maximum()); + _ui.angleMaxHorizontalSlider->setSliderPosition(pos); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_density_page.h b/code/nel/tools/3d/object_viewer_qt/src/vegetable_density_page.h new file mode 100644 index 000000000..6700941fd --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_density_page.h @@ -0,0 +1,77 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef VEGETABLE_DENSITY_PAGE_H +#define VEGETABLE_DENSITY_PAGE_H + +#include "ui_vegetable_density_form.h" + +// STL includes + +// NeL includes + +// Project includes + +namespace NL3D +{ + class CVegetable; +} + +namespace NLQT { + +class CVegetableDensityPage: public QWidget +{ + Q_OBJECT + +public: + CVegetableDensityPage(QWidget *parent = 0); + ~CVegetableDensityPage(); + + /// set the vegetble to edit. NULL will disable all the controls. + void setVegetableToEdit(NL3D::CVegetable *vegetable); + +Q_SIGNALS: + void vegetNameChanged(); + +private Q_SLOTS: + void browseShapeVeget(); + void setDistanceOfCreat(int value); + void setEnabledMaxDensity(bool state); + void updateAngleMode(); + void setDensity(NLMISC::CNoiseValue value); + void setMaxDensity(float value); + void setAngleMinSlider(int pos); + void setAngleMaxSlider(int pos); + +private: + void updateAngleMin(); + void updateAngleMax(); + + // The vegetable to edit. + NL3D::CVegetable *_Vegetable; + + float _PrecMaxDensityValue; + + Ui::CVegetableDensityPage _ui; + +}; /* class CVegetableDensityPage */ + +} /* namespace NLQT */ + +#endif // VEGETABLE_DENSITY_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/vegetable_dialog.cpp new file mode 100644 index 000000000..579a3aadb --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_dialog.cpp @@ -0,0 +1,322 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "vegetable_dialog.h" + +// Qt includes +#include +#include + +// NeL includes +#include +#include +#include "nel/misc/file.h" + +// Project includes +#include "modules.h" + +namespace NLQT { + +CVegetableDialog::CVegetableDialog(QWidget *parent) + : QDockWidget(parent) +{ + _ui.setupUi(this); + + connect(_ui.addtPushButton, SIGNAL(clicked()), this, SLOT(addVegetList())); + connect(_ui.insPushButton, SIGNAL(clicked()), this, SLOT(insVegetList())); + connect(_ui.delPushButton, SIGNAL(clicked()), this, SLOT(removeVegetList())); + connect(_ui.clearPushButton, SIGNAL(clicked()), this, SLOT(clearVegetList())); + connect(_ui.copyVegetPushButton, SIGNAL(clicked()), this, SLOT(copyVegetable())); + connect(_ui.loadVegetdescPushButton, SIGNAL(clicked()), this, SLOT(loadVegetdesc())); + connect(_ui.saveVegetdescPushButton, SIGNAL(clicked()), this, SLOT(saveVegetdesc())); + connect(_ui.loadVegetsetPushButton, SIGNAL(clicked()), this, SLOT(loadVegetset())); + connect(_ui.appendVegetsetPushButton, SIGNAL(clicked()), this, SLOT(appendVegetset())); + connect(_ui.saveVegetsetPushButton, SIGNAL(clicked()), this, SLOT(saveVegetset())); + connect(_ui.showVegetCheckBox, SIGNAL(toggled(bool)), this, SLOT(setVisibleVegetables(bool))); + connect(_ui.listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(setCurrentItem(int))); +} + +CVegetableDialog::~CVegetableDialog() +{ +} + +void CVegetableDialog::loadVegetset() +{ + // ask name of the load new vegetset file + QString fileName = QFileDialog::getOpenFileName(this, tr("Load a new vegetset file"), + ".", + tr("vegetset files (*.vegetset);;")); + if (!fileName.isEmpty()) + { + NL3D::CTileVegetableDesc vegetSet; + // if succes to load the vegetSet + if(Modules::veget().loadVegetableSet(vegetSet, fileName.toStdString())) + { + // Delete all vegetables. + Modules::veget().clearVegetables(); + + // build them from list. + Modules::veget().appendVegetableSet(vegetSet); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); + + updateVegetList(); + } + } +} + +void CVegetableDialog::appendVegetset() +{ + // ask name of the load new vegetset file + QString fileName = QFileDialog::getOpenFileName(this, tr("Append vegetset file"), + ".", + tr("vegetset files (*.vegetset);;")); + if (!fileName.isEmpty()) + { + NL3D::CTileVegetableDesc vegetSet; + // if succes to load the vegetSet + if(Modules::veget().loadVegetableSet(vegetSet, fileName.toStdString())) + { + // Do not Delete any vegetables. + // build them from list. + Modules::veget().appendVegetableSet(vegetSet); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); + + updateVegetList(); + } + } +} + +void CVegetableDialog::saveVegetset() +{ + NL3D::CTileVegetableDesc vegetSet; + + // first build the vegetSet. + Modules::veget().buildVegetableSet(vegetSet); + + // Then try to save it. + QString fileName = QFileDialog::getSaveFileName(this, tr("Save Vegetable Set"), + ".", + tr("VegetSetFiles (*.vegetset);;")); + // after check + if (!fileName.isEmpty()) + { + NLMISC::COFile f; + + if( f.open(fileName.toStdString()) ) + { + try + { + // save the vegetable set + f.serial(vegetSet); + } + catch(NLMISC::EStream &e) + { + QMessageBox::critical(this, "Failed to save file!", QString(e.what()), QMessageBox::Ok); + } + } + else + QMessageBox::critical(this, "Failed to save file!", QString("Failed to open file for write!"), QMessageBox::Ok); + } + +} + +void CVegetableDialog::addVegetList() +{ + // Add a new vegetable to the list. + uint id = _ui.listWidget->count(); + + Modules::veget().insEmptyVegetDesc(id); + + // update view + QListWidgetItem *item = new QListWidgetItem(_ui.listWidget); + item->setText(QString(Modules::veget().getVegetable(id)->VegetableName.c_str())); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableDialog::removeVegetList() +{ + sint id = _ui.listWidget->currentRow(); + if(id == -1) return; + + Modules::veget().delVegetDesc(id); + + QListWidgetItem *item = _ui.listWidget->takeItem(id); + delete item; + + id--; + + _ui.listWidget->setCurrentRow(id); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableDialog::insVegetList() +{ + sint id = _ui.listWidget->currentRow(); + if(id != -1) + { + // Add a new vegetable to the list. + Modules::veget().insEmptyVegetDesc(id); + + // update view + QListWidgetItem *item = new QListWidgetItem(); + item->setText(QString(Modules::veget().getVegetable(id)->VegetableName.c_str())); + _ui.listWidget->insertItem(id, item); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); + } + else + { + // perform like an add. + addVegetList(); + } +} + +void CVegetableDialog::clearVegetList() +{ + if (_ui.listWidget->count() == 0) return; + int ok = QMessageBox::question(this, "Clear List", QString("Clear all the list?"), QMessageBox::Yes | QMessageBox::No); + if (ok == QMessageBox::Yes) + { + Modules::veget().clearVegetables(); + + _ui.listWidget->clear(); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); + } +} + +void CVegetableDialog::copyVegetable() +{ +} + +void CVegetableDialog::loadVegetdesc() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Open Vegetable Descriptor"), + ".", + tr("vegetdesc files (*.vegetdesc);;")); + if (!fileName.isEmpty()) + { + NLMISC::CIFile f; + + if( f.open(fileName.toStdString()) ) + { + NL3D::CVegetable veget; + try + { + // read the vegetable + f.serial(veget); + + // Add a new vegetable to the list. + uint id = Modules::veget().addVegetDesc(veget); + + // update view + QListWidgetItem *item = new QListWidgetItem(_ui.listWidget); + item->setText(QString(Modules::veget().getVegetable(id)->VegetableName.c_str())); + + // update 3D view + Modules::veget().refreshVegetableDisplay(); + } + catch(NLMISC::EStream &e) + { + QMessageBox::critical(this, "Failed to load file!", QString(e.what()), QMessageBox::Ok); + } + } + else + QMessageBox::critical(this, "Failed to open file!", QString("Failed to open file for read!"), QMessageBox::Ok); + } +} + +void CVegetableDialog::saveVegetdesc() +{ + sint id = _ui.listWidget->currentRow(); + if(id == -1) return; + + CVegetableNode *vegetNode = Modules::veget().getVegetable(id); + + QString oldFileName = QString(vegetNode->VegetableName.c_str()) + ".vegetdesc"; + + // Then try to save it. + QString fileName = QFileDialog::getSaveFileName(this, tr("Save Vegetable Descriptor"), + oldFileName, + tr("VegetDescFiles (*.vegetdesc);;")); + // after check + if (!fileName.isEmpty()) + { + NLMISC::COFile f; + + if( f.open(fileName.toStdString()) ) + { + try + { + // save the vegetable + f.serial(*vegetNode->Vegetable); + } + catch(NLMISC::EStream &e) + { + QMessageBox::critical(this, "Failed to save file!", QString(e.what()), QMessageBox::Ok); + } + } + else + QMessageBox::critical(this, "Failed to save file!", QString("Failed to open file for write!"), QMessageBox::Ok); + } +} + +void CVegetableDialog::setVisibleVegetables(bool state) +{ + // update view. + Modules::veget().enableLandscapeVegetable(state); +} + +void CVegetableDialog::setCurrentItem(int row) +{ + NL3D::CVegetable *veget = NULL; + if (row != -1) + veget = Modules::veget().getVegetable(row)->Vegetable; + _ui.densityPage->setVegetableToEdit(veget); + _ui.appearancePage->setVegetableToEdit(veget); + _ui.scalePage->setVegetableToEdit(veget); + _ui.rotatePage->setVegetableToEdit(veget); +} + +void CVegetableDialog::updateVegetList() +{ + std::vector listVegetables; + Modules::veget().getListVegetables(listVegetables); + + _ui.listWidget->clear(); + + for (size_t i = 0; i < listVegetables.size(); i++) + { + QListWidgetItem *item = new QListWidgetItem(_ui.listWidget); + item->setText(QString(listVegetables[i].c_str())); + } +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/vegetable_dialog.h new file mode 100644 index 000000000..a46551e0c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_dialog.h @@ -0,0 +1,74 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef VEGETABLE_DIALOG_H +#define VEGETABLE_DIALOG_H + +#include "ui_vegetable_dialog_form.h" + +// STL includes + +// NeL includes + +// Project includes +#include "vegetable_node.h" + +namespace NL3D +{ + class CTileVegetableDesc; +} + +namespace NLQT { + +class CVegetableDialog: public QDockWidget +{ + Q_OBJECT + +public: + CVegetableDialog(QWidget *parent = 0); + ~CVegetableDialog(); + +private Q_SLOTS: + void loadVegetset(); + void appendVegetset(); + void saveVegetset(); + + void addVegetList(); + void removeVegetList(); + void insVegetList(); + void clearVegetList(); + + void copyVegetable(); + void loadVegetdesc(); + void saveVegetdesc(); + + void setVisibleVegetables(bool state); + + void setCurrentItem(int row); + +private: + void updateVegetList(); + + Ui::CVegetableDialog _ui; + +}; /* class CVegetableDialog */ + +} /* namespace NLQT */ + +#endif // VEGETABLE_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_dialog_form.ui b/code/nel/tools/3d/object_viewer_qt/src/vegetable_dialog_form.ui new file mode 100644 index 000000000..b16477ee7 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_dialog_form.ui @@ -0,0 +1,274 @@ + + + CVegetableDialog + + + + 0 + 0 + 618 + 679 + + + + + :/images/veget.png:/images/veget.png + + + Vegetable editor + + + + + + + true + + + + + 0 + 0 + 598 + 640 + + + + + + + QLayout::SetFixedSize + + + + + Vegetables: + + + + + + + + 0 + 0 + + + + + 170 + 16777215 + + + + + + + + List edition + + + + + + Add vegetable + + + + + + + :/images/list-add.png:/images/list-add.png + + + + + + + Insert vegetable + + + + + + + :/images/insert-horizontal.png:/images/insert-horizontal.png + + + + + + + Remove vegetable + + + + + + + :/images/list-remove.png:/images/list-remove.png + + + + + + + Clear all vegetables + + + + + + + :/images/clear.png:/images/clear.png + + + + + + + false + + + Copy Vegetable + + + + + + + Load .vegetdesc + + + + + + + Save .vegetdesc + + + + + + + + + + List Save/Load + + + + + + Load .vegetset + + + + + + + Append .vegetset + + + + + + + Save .vegetset + + + + + + + + + + true + + + Display Vegetables + + + true + + + + + + + + + 0 + + + + Landscape + + + + + General/Density + + + + + Appearance + + + + + Scale + + + + + Rotation + + + + + + + + + + + + + + NLQT::CVegetableDensityPage + QWidget +
vegetable_density_page.h
+ 1 +
+ + NLQT::CVegetableLandscapePage + QWidget +
vegetable_landscape_page.h
+ 1 +
+ + NLQT::CVegetableScalePage + QWidget +
vegetable_scale_page.h
+ 1 +
+ + NLQT::CVegetableRotatePage + QWidget +
vegetable_rotate_page.h
+ 1 +
+ + NLQT::CVegetableApperancePage + QWidget +
vegetable_appearance_page.h
+ 1 +
+
+ + + + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_editor.cpp b/code/nel/tools/3d/object_viewer_qt/src/vegetable_editor.cpp new file mode 100644 index 000000000..0e4133d98 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_editor.cpp @@ -0,0 +1,739 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "vegetable_editor.h" + +// Qt includes +#include +#include + +// NeL includes +#include +#include +#include "nel/misc/file.h" +#include +#include +#include + +//#include + +// Project includes +#include "modules.h" +#include + +namespace NLQT { + +CVegetableEditor::CVegetableEditor(void) + : _VegetableLandscape(NULL), + _VegetableCollisionManager(NULL), + _VegetableCollisionEntity(NULL), + _Driver(NULL), _Scene(NULL) +{ + loadConfig(); +} + +CVegetableEditor::~CVegetableEditor(void) +{ + saveConfig(); +} + +void CVegetableEditor::init() +{ + //H_AUTO2 + nldebug("CVegetableEditor::init"); + + NL3D::CDriverUser *driver = dynamic_cast(Modules::objView().getDriver()); + _Driver = driver->getDriver(); + + NL3D::CSceneUser *scene = dynamic_cast(Modules::objView().getScene()); + _Scene = &scene->getScene(); +} + +void CVegetableEditor::release() +{ + //H_AUTO2 + nldebug("CVegetableEditor::release"); + + if(_VegetableCollisionEntity) + { + _VegetableCollisionManager->deleteEntity(_VegetableCollisionEntity); + _VegetableCollisionEntity= NULL; + } + if(_VegetableCollisionManager) + { + delete _VegetableCollisionManager; + _VegetableCollisionManager= NULL; + } + + // delete Landscape + if(_VegetableLandscape) + { + Modules::veget().getScene()->deleteModel(_VegetableLandscape); + _VegetableLandscape= NULL; + } +} + +bool CVegetableEditor::createVegetableLandscape() +{ + /// TODO: switch from C to U classes, if possible + // If not already done. + if(!_VegetableLandscape) + { + // load general landscape param + loadLandscapeSetup(); + + // create the landscape. + _VegetableLandscape= static_cast(Modules::veget().getScene()->createModel(NL3D::LandscapeModelId)); + + // create progress dialog + QProgressDialog progress("Loading TileBanks....", "Cancel", 0, 100); + progress.show(); + progress.setWindowModality(Qt::WindowModal); + progress.setValue(0); + try + { + if((_VegetableLandscapeTileBank.empty()) || (_VegetableLandscapeTileFarBank.empty()) || (_VegetableLandscapeZoneNames.empty())) + { + throw NLMISC::Exception("Landscape section object_viewer_qt.cfg not fully defined"); + } + + // Load The Bank files (copied from CLandscapeUser :) ). + // ================ + // load + NLMISC::CIFile bankFile(NLMISC::CPath::lookup(_VegetableLandscapeTileBank)); + _VegetableLandscape->Landscape.TileBank.serial(bankFile); + _VegetableLandscape->Landscape.TileBank.makeAllPathRelative(); + _VegetableLandscape->Landscape.TileBank.makeAllExtensionDDS(); + _VegetableLandscape->Landscape.TileBank.setAbsPath (""); + + // load + NLMISC::CIFile farbankFile(NLMISC::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(Modules::veget().getDriver()) + { + // progress + progress.setLabelText("Start loading Tiles..."); + // count nbText to load. + sint ts; + sint nbTextTotal = 0; + for (ts=0; ts < _VegetableLandscape->Landscape.TileBank.getTileSetCount (); ts++) + { + NL3D::CTileSet *tileSet =_VegetableLandscape->Landscape.TileBank.getTileSet (ts); + nbTextTotal += tileSet->getNumTile128(); + nbTextTotal += tileSet->getNumTile256(); + nbTextTotal += NL3D::CTileSet::count; + } + + // load. + sint nbTextDone= 0; + for (ts=0; ts < _VegetableLandscape->Landscape.TileBank.getTileSetCount (); ts++) + { + NL3D::CTileSet *tileSet=_VegetableLandscape->Landscape.TileBank.getTileSet (ts); + sint tl; + for (tl=0; tlgetNumTile128(); tl++, nbTextDone++) + { + _VegetableLandscape->Landscape.flushTiles (Modules::veget().getDriver(), (uint16)tileSet->getTile128(tl), 1); + progress.setValue(nbTextDone * 100 / nbTextTotal); + } + for (tl=0; tlgetNumTile256(); tl++, nbTextDone++) + { + _VegetableLandscape->Landscape.flushTiles (Modules::veget().getDriver(), (uint16)tileSet->getTile256(tl), 1); + progress.setValue(nbTextDone * 100 / nbTextTotal); + } + for (tl=0; tl < NL3D::CTileSet::count; tl++, nbTextDone++) + { + _VegetableLandscape->Landscape.flushTiles (Modules::veget().getDriver(), (uint16)tileSet->getTransition(tl)->getTile (), 1); + progress.setValue(nbTextDone * 100 / nbTextTotal); + } + } + progress.setValue(100); + } + + // 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); + _VegetableLandscape->Landscape.setUpdateLightingFrequency(1); + + // Load the zones. + // ================ + // landscape recentering. + bool zoneLoaded = false; + NL3D::CAABBox landscapeBBox; + // progress + progress.setLabelText("Start loading Zones..."); + progress.setValue(0); + uint nbZones= (uint)_VegetableLandscapeZoneNames.size(); + for(uint i = 0; i < nbZones; i++) + { + // open the file + NLMISC::CIFile zoneFile(NLMISC::CPath::lookup(_VegetableLandscapeZoneNames[i])); + NL3D::CZone zone; + // load + zoneFile.serial(zone); + // append to landscape + _VegetableLandscape->Landscape.addZone(zone); + // progress + progress.setValue(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) + { + NL3D::CMatrix matrix; + Modules::objView().get3dMouseListener()->setHotSpot(landscapeBBox.getCenter()); + matrix.setPos(landscapeBBox.getCenter()); + matrix.rotateX(-(float)NLMISC::Pi / 4); + matrix.translate(NLMISC::CVector(0, -1000, 0)); + Modules::objView().get3dMouseListener()->setMatrix(matrix); + } + + // Create collisions objects. + _VegetableCollisionManager= new NL3D::CVisualCollisionManager; + _VegetableCollisionManager->setLandscape(&_VegetableLandscape->Landscape); + _VegetableCollisionEntity= _VegetableCollisionManager->createEntity(); + progress.setValue(100); + } + catch (NLMISC::Exception &e) + { + // remove first possibly created collisions objects. + if(_VegetableCollisionEntity) + { + _VegetableCollisionManager->deleteEntity(_VegetableCollisionEntity); + _VegetableCollisionEntity= NULL; + } + + if(_VegetableCollisionManager) + { + delete _VegetableCollisionManager; + _VegetableCollisionManager= NULL; + } + + // remove the landscape + Modules::veget().getScene()->deleteModel(_VegetableLandscape); + + _VegetableLandscape= NULL; + + QMessageBox::critical(&Modules::mainWin(), "Failed to Load landscape", QString(e.what()), QMessageBox::Ok); + + return false; + } + } + + return true; +} + +void CVegetableEditor::showVegetableLandscape() +{ + if(_VegetableLandscape) + { + _VegetableLandscape->show(); + } +} + +void CVegetableEditor::hideVegetableLandscape() +{ + if(_VegetableLandscape) + { + _VegetableLandscape->hide(); + } +} + +void CVegetableEditor::enableLandscapeVegetable(bool enable) +{ + // update + _VegetableEnabled = enable; + + // update view. + if(_VegetableLandscape) + { + _VegetableLandscape->Landscape.enableVegetable(_VegetableEnabled); + } +} + +void CVegetableEditor::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++) + { + NL3D::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 CVegetableEditor::setVegetableWindPower(float w) +{ + _VegetableWindPower= w; + if(_VegetableLandscape) + _VegetableLandscape->Landscape.setVegetableWind(_VegetableWindDir, _VegetableWindFreq, _VegetableWindPower, _VegetableWindBendMin); +} + +void CVegetableEditor::setVegetableWindBendStart(float w) +{ + _VegetableWindBendMin= w; + if(_VegetableLandscape) + _VegetableLandscape->Landscape.setVegetableWind(_VegetableWindDir, _VegetableWindFreq, _VegetableWindPower, _VegetableWindBendMin); +} + +void CVegetableEditor::setVegetableWindFrequency(float w) +{ + _VegetableWindFreq= w; + if(_VegetableLandscape) + _VegetableLandscape->Landscape.setVegetableWind(_VegetableWindDir, _VegetableWindFreq, _VegetableWindPower, _VegetableWindBendMin); +} + +void CVegetableEditor::snapToGroundVegetableLandscape(bool enable) +{ + // update + if(_VegetableLandscape) + _VegetableSnapToGround = enable; +} + +void CVegetableEditor::setVegetableAmbientLight(const NLMISC::CRGBA &ambient) +{ + _VegetableLandscapeAmbient = ambient; + if(_VegetableLandscape) + _VegetableLandscape->Landscape.setupStaticLight(_VegetableLandscapeDiffuse, _VegetableLandscapeAmbient, 1); +} + +void CVegetableEditor::setVegetableDiffuseLight(const NLMISC::CRGBA &diffuse) +{ + _VegetableLandscapeDiffuse = diffuse; + if(_VegetableLandscape) + _VegetableLandscape->Landscape.setupStaticLight(_VegetableLandscapeDiffuse, _VegetableLandscapeAmbient, 1); +} + +void CVegetableEditor::update() +{ + // Vegetable: manage collision snapping if wanted and possible + if(_VegetableSnapToGround && _VegetableLandscape) + { + // get matrix from camera. + NLMISC::CMatrix matrix = Modules::objView().getScene()->getCam().getMatrix(); + + // snap To ground. + NLMISC::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. + Modules::objView().get3dMouseListener()->setMatrix(matrix); + Modules::objView().getScene()->getCam().setMatrix(matrix); + } + } +} + +void CVegetableEditor::getListVegetables(std::vector &listVeget) +{ + listVeget.clear(); + for (size_t i = 0; i < _Vegetables.size(); i++) + listVeget.push_back(_Vegetables[i].VegetableName); +} + +bool CVegetableEditor::loadVegetableSet(NL3D::CTileVegetableDesc &vegetSet, std::string fileName) +{ + bool ok = true; + NLMISC::CIFile f; + + if( f.open(fileName) ) + { + try + { + // read the vegetable + f.serial(vegetSet); + } + catch(NLMISC::EStream &) + { + ok = false; + QMessageBox::critical(&Modules::mainWin(), "NeL Vegetable editor", QString("Failed to load file!"), QMessageBox::Ok); + } + } + else + { + ok = false; + QMessageBox::critical(&Modules::mainWin(), "NeL Vegetable editor", QString("Failed to load file!"), QMessageBox::Ok); + } + + return ok; +} + +void CVegetableEditor::buildVegetableSet(NL3D::CTileVegetableDesc &vegetSet, bool keepDefaultShapeName, bool keepHiden ) +{ + vegetSet.clear(); + float degToRad= (float)(NLMISC::Pi / 180.f); + + // build the list. + std::vector vegetables; + for(uint i = 0; i < _Vegetables.size(); i++) + { + // if don't want to keep ShapeNames, skip them. + if(!keepDefaultShapeName && _Vegetables[i].Vegetable->ShapeName == "") + continue; + // if don't want to keep hiden vegetables, skip them. + if(!keepHiden && !_Vegetables[i].Visible) + continue; + + vegetables.push_back(*_Vegetables[i].Vegetable); + // get dst index. + uint dstId= (uint)vegetables.size()-1; + // transform degrees in radians. + vegetables[dstId].Rx.Abs *= degToRad; + vegetables[dstId].Rx.Rand *= degToRad; + vegetables[dstId].Ry.Abs *= degToRad; + vegetables[dstId].Ry.Rand *= degToRad; + vegetables[dstId].Rz.Abs *= degToRad; + vegetables[dstId].Rz.Rand *= degToRad; + } + + // build the set. + vegetSet.build(vegetables); +} + +void CVegetableEditor::appendVegetableSet(NL3D::CTileVegetableDesc &vegetSet) +{ + float radToDeg = (float)(180.f / NLMISC::Pi); + + // for all distances Types. + for(uint distType = 0; distType < NL3D_VEGETABLE_BLOCK_NUMDIST; distType++) + { + // retrieve list of vegetable + const std::vector &vegetList = vegetSet.getVegetableList(distType); + + // for all of them + for(uint i = 0; i < vegetList.size();i++) + { + // append the vegetable to the list. + NL3D::CVegetable veget = vegetList[i]; + + // transform radians into degrees. + veget.Rx.Abs *= radToDeg; + veget.Rx.Rand *= radToDeg; + veget.Ry.Abs *= radToDeg; + veget.Ry.Rand *= radToDeg; + veget.Rz.Abs *= radToDeg; + veget.Rz.Rand *= radToDeg; + + // Add a new vegetable to the list. + _Vegetables.push_back( CVegetableNode()); + uint id= (uint)_Vegetables.size()-1; + _Vegetables[id].initVegetable(veget); + } + } +} + +void CVegetableEditor::clearVegetables() +{ + // delete all vegetables. + for(uint i=0; i<_Vegetables.size(); i++) + { + _Vegetables[i].deleteVegetable(); + } + _Vegetables.clear(); +} + +CVegetableNode *CVegetableEditor::getVegetable(sint id) +{ + if(id == -1) + return NULL; + else + return &_Vegetables[id]; +} + +uint CVegetableEditor::addVegetDesc(const NL3D::CVegetable &vegetable) +{ + // Add a new vegetable to the list. + _Vegetables.push_back(CVegetableNode ()); + uint id = (uint)_Vegetables.size()-1; + _Vegetables[id].initVegetable(vegetable); + return id; +} + +void CVegetableEditor::insEmptyVegetDesc(uint row) +{ + _Vegetables.insert(_Vegetables.begin() + row, CVegetableNode()); + _Vegetables[row].initDefaultVegetable(); +} + +void CVegetableEditor::delVegetDesc(uint id) +{ + // erase the vegetable from the list. + _Vegetables[id].deleteVegetable(); + _Vegetables.erase(_Vegetables.begin()+id); +} + +void CVegetableEditor::refreshVegetableDisplay() +{ + NL3D::CTileVegetableDesc vegetSet; + + // first build the vegetSet, but don't keep shapeName. and skip Hiden vegetables too + buildVegetableSet(vegetSet, false, false); + + // then refresh window. + Modules::veget().refreshVegetableLandscape(vegetSet); +} + +void CVegetableEditor::loadConfig() +{ + // vegetable display is true by default. + _VegetableEnabled = true; + _VegetableSnapToGround = false; + + // Load Landscape params. + // -------------- + // threshold + try + { + _VegetableLandscapeThreshold = Modules::config().getConfigFile().getVar("VegetLandscapeThreshold").asFloat(); + // clamp to avoid divide/0. + _VegetableLandscapeThreshold = std::max(_VegetableLandscapeThreshold, 0.001f); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableLandscapeThreshold = 0.003f; + } + // tilenear + try + { + _VegetableLandscapeTileNear = Modules::config().getConfigFile().getVar("VegetLandscapeTileNear").asFloat(); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableLandscapeTileNear= 50; + } + // ambient + try + { + NLMISC::CConfigFile::CVar &color = Modules::config().getConfigFile().getVar("VegetLandscapeAmbient"); + _VegetableLandscapeAmbient.R = color.asInt(0); + _VegetableLandscapeAmbient.G = color.asInt(1); + _VegetableLandscapeAmbient.B = color.asInt(2); + _VegetableLandscapeAmbient.A = color.asInt(3); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableLandscapeAmbient.set(80, 80, 80, 255); + } + // diffuse + try + { + NLMISC::CConfigFile::CVar &color= Modules::config().getConfigFile().getVar("VegetLandscapeDiffuse"); + _VegetableLandscapeDiffuse.R = color.asInt(0); + _VegetableLandscapeDiffuse.G = color.asInt(1); + _VegetableLandscapeDiffuse.B = color.asInt(2); + _VegetableLandscapeDiffuse.A = color.asInt(3); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableLandscapeDiffuse.set(255, 255, 255, 255); + } + // Snapping + try + { + _VegetableSnapHeight = Modules::config().getConfigFile().getVar("VegetLandscapeSnapHeight").asFloat(); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableSnapHeight = 1.70f; + } + + + // Load Vegetable params. + // -------------- + + // vegetable ambient + try + { + NLMISC::CConfigFile::CVar &color = Modules::config().getConfigFile().getVar("VegetAmbient"); + _VegetableAmbient.R = color.asInt(0); + _VegetableAmbient.G = color.asInt(1); + _VegetableAmbient.B = color.asInt(2); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableAmbient.set(80, 80, 80, 255); + } + // vegetable diffuse + try + { + NLMISC::CConfigFile::CVar &color = Modules::config().getConfigFile().getVar("VegetDiffuse"); + // setup to behave correclty ie as maxLightFactor: + sint R = color.asInt(0) - _VegetableAmbient.R; NLMISC::clamp(R, 0, 255); _VegetableDiffuse.R = R; + sint G = color.asInt(1) - _VegetableAmbient.G; NLMISC::clamp(G, 0, 255); _VegetableDiffuse.G = G; + sint B = color.asInt(2) - _VegetableAmbient.B; NLMISC::clamp(B, 0, 255); _VegetableDiffuse.B = B; + } + catch (NLMISC::EUnknownVar &) + { + sint R = 255 - _VegetableAmbient.R; NLMISC::clamp(R, 0, 255); _VegetableDiffuse.R = R; + sint G = 255 - _VegetableAmbient.G; NLMISC::clamp(G, 0, 255); _VegetableDiffuse.G = G; + sint B = 255 - _VegetableAmbient.B; NLMISC::clamp(B, 0, 255); _VegetableDiffuse.B = B; + } + // vegetable lightDir + try + { + NLMISC::CConfigFile::CVar &var = Modules::config().getConfigFile().getVar("VegetLightDir"); + _VegetableLightDir.x = var.asFloat(0); + _VegetableLightDir.y = var.asFloat(1); + _VegetableLightDir.z = var.asFloat(2); + _VegetableLightDir.normalize(); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableLightDir.set(0, 1, -1); + _VegetableLightDir.normalize(); + } + + // windDir + try + { + NLMISC::CConfigFile::CVar &var = Modules::config().getConfigFile().getVar("VegetWindDir"); + _VegetableWindDir.x = var.asFloat(0); + _VegetableWindDir.y = var.asFloat(1); + _VegetableWindDir.z = var.asFloat(2); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableWindDir.x = 0.5f; + _VegetableWindDir.y = 0.5f; + _VegetableWindDir.z = 0; + } + // windFreq + try + { + _VegetableWindFreq = Modules::config().getConfigFile().getVar("VegetWindFreq").asFloat(); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableWindFreq= 0.5; + } + // windPower + try + { + _VegetableWindPower = Modules::config().getConfigFile().getVar("VegetWindPower").asFloat(); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableWindPower= 1; + } + // windBendMin + try + { + _VegetableWindBendMin = Modules::config().getConfigFile().getVar("VegetWindBendMin").asFloat(); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableWindBendMin= 0; + } +} + +void CVegetableEditor::loadLandscapeSetup() +{ + // Load landscape setup + // -------------- + try + { + // tileBank setup. + _VegetableLandscapeTileBank = Modules::config().getConfigFile().getVar("VegetTileBank").asString(); + _VegetableLandscapeTileFarBank = Modules::config().getConfigFile().getVar("VegetTileFarBank").asString(); + // zone list. + _VegetableLandscapeZoneNames.clear(); + NLMISC::CConfigFile::CVar &zones = Modules::config().getConfigFile().getVar("VegetLandscapeZones"); + for (uint i=0; i<(uint)zones.size(); i++) + _VegetableLandscapeZoneNames.push_back(zones.asString(i).c_str()); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableLandscapeTileBank.clear(); + _VegetableLandscapeTileFarBank.clear(); + _VegetableLandscapeZoneNames.clear(); + } + + // Load Vegetable params. + // -------------- + + // vegetable texture + try + { + _VegetableTexture = Modules::config().getConfigFile().getVar("VegetTexture").asString(); + } + catch (NLMISC::EUnknownVar &) + { + _VegetableTexture= ""; + } +} + +void CVegetableEditor::saveConfig() +{ + Modules::config().getConfigFile().getVar("VegetLandscapeThreshold").setAsFloat(_VegetableLandscapeThreshold); + Modules::config().getConfigFile().getVar("VegetLandscapeTileNear").setAsFloat(_VegetableLandscapeTileNear); + + Modules::config().getConfigFile().getVar("VegetLandscapeAmbient").setAsInt(_VegetableLandscapeAmbient.R, 0); + Modules::config().getConfigFile().getVar("VegetLandscapeAmbient").setAsInt(_VegetableLandscapeAmbient.G, 1); + Modules::config().getConfigFile().getVar("VegetLandscapeAmbient").setAsInt(_VegetableLandscapeAmbient.B, 2); + Modules::config().getConfigFile().getVar("VegetLandscapeAmbient").setAsInt(_VegetableLandscapeAmbient.A, 3); + + Modules::config().getConfigFile().getVar("VegetLandscapeDiffuse").setAsInt(_VegetableLandscapeDiffuse.R, 0); + Modules::config().getConfigFile().getVar("VegetLandscapeDiffuse").setAsInt(_VegetableLandscapeDiffuse.G, 1); + Modules::config().getConfigFile().getVar("VegetLandscapeDiffuse").setAsInt(_VegetableLandscapeDiffuse.B, 2); + Modules::config().getConfigFile().getVar("VegetLandscapeAmbient").setAsInt(_VegetableLandscapeAmbient.A, 3); + + Modules::config().getConfigFile().getVar("VegetWindDir").setAsFloat(_VegetableWindDir.x, 0); + Modules::config().getConfigFile().getVar("VegetWindDir").setAsFloat(_VegetableWindDir.y, 1); + Modules::config().getConfigFile().getVar("VegetWindDir").setAsFloat(_VegetableWindDir.z, 2); + + Modules::config().getConfigFile().getVar("VegetWindPower").setAsFloat(_VegetableWindPower); + Modules::config().getConfigFile().getVar("VegetWindFreq").setAsFloat(_VegetableWindFreq); + Modules::config().getConfigFile().getVar("VegetWindBendMin").setAsFloat(_VegetableWindBendMin); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_editor.h b/code/nel/tools/3d/object_viewer_qt/src/vegetable_editor.h new file mode 100644 index 000000000..a61238b6f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_editor.h @@ -0,0 +1,252 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef VEGETABLE_EDITOR_H +#define VEGETABLE_EDITOR_H + +// STL includes +#include +#include + +// NeL includes +#include +#include +#include + +// Project includes +#include "vegetable_node.h" + +// Defaults Sliders ranges. +#define NL_VEGETABLE_EDIT_DEFAULT_MAX_DENSITY 50.f + +// General Frequence +#define NL_VEGETABLE_FREQ_RANGE_MIN 0.0001f +#define NL_VEGETABLE_FREQ_RANGE_MAX 1.f +#define NL_VEGETABLE_FREQ_DEFAULT 0.1f + +// Density +#define NL_VEGETABLE_DENSITY_ABS_RANGE_MIN -10.f +#define NL_VEGETABLE_DENSITY_ABS_RANGE_MAX 10.f +#define NL_VEGETABLE_DENSITY_RAND_RANGE_MIN 0.f +#define NL_VEGETABLE_DENSITY_RAND_RANGE_MAX 10.f +#define NL_VEGETABLE_DENSITY_ABS_DEFAULT 0.f +#define NL_VEGETABLE_DENSITY_RAND_DEFAULT 0.25f + +// BendPhase +#define NL_VEGETABLE_BENDPHASE_RANGE_MIN 0.f +#define NL_VEGETABLE_BENDPHASE_RANGE_MAX 2.f +#define NL_VEGETABLE_BENDPHASE_ABS_DEFAULT 0.f +#define NL_VEGETABLE_BENDPHASE_RAND_DEFAULT 2.f + +// BendFactor +#define NL_VEGETABLE_BENDFACTOR_RANGE_MIN 0.f +#define NL_VEGETABLE_BENDFACTOR_RANGE_MAX 1.f +#define NL_VEGETABLE_BENDFACTOR_ABS_DEFAULT 0.5f +#define NL_VEGETABLE_BENDFACTOR_RAND_DEFAULT 0.5f + +// ColorNoise +#define NL_VEGETABLE_COLOR_RANGE_MIN -1.f +#define NL_VEGETABLE_COLOR_RANGE_MAX 3.f +#define NL_VEGETABLE_COLOR_ABS_DEFAULT -1.f +#define NL_VEGETABLE_COLOR_RAND_DEFAULT 3.f + +// Scale +#define NL_VEGETABLE_SCALE_RANGE_MIN 0.f +#define NL_VEGETABLE_SCALE_RANGE_MAX 1.f +#define NL_VEGETABLE_SCALE_ABS_DEFAULT 0.5f +#define NL_VEGETABLE_SCALE_RAND_DEFAULT 0.5f + +// Rotate +#define NL_VEGETABLE_ROTATE_RANGE_MIN -90.f +#define NL_VEGETABLE_ROTATE_RANGE_MAX 90.f +#define NL_VEGETABLE_ROTATEX_ABS_DEFAULT -20.f +#define NL_VEGETABLE_ROTATEX_RAND_DEFAULT 40.f +#define NL_VEGETABLE_ROTATEY_ABS_DEFAULT 0.f +#define NL_VEGETABLE_ROTATEY_RAND_DEFAULT 0.f +#define NL_VEGETABLE_ROTATEZ_ABS_DEFAULT 0.f +#define NL_VEGETABLE_ROTATEZ_RAND_DEFAULT 3000.f +#define NL_VEGETABLE_ROTATEZ_FREQ_DEFAULT 10.f + +// BendFreq +#define NL_VEGETABLE_BENDFREQ_RANGE_MIN 0.f +#define NL_VEGETABLE_BENDFREQ_RANGE_MAX 4.f + +namespace NL3D +{ + class CTileVegetableDesc; + class CLandscapeModel; + class CVisualCollisionManager; + class CVisualCollisionEntity; + class CScene; + class IDriver; +} + + +namespace NLQT { +/** +@class CVegetableEditor +@brief Loading and viewing .zonel, .vegetset files. +Dynamic control of parameters of the landscape (wind/colors) and +list micro-vegetation node (load/save veget, create/add/ins/del list micro-vegetation node). +*/ +class CVegetableEditor +{ +public: + CVegetableEditor(void); + ~CVegetableEditor(void); + + void init(); + + void release(); + + /// @name Landscape control + //@{ + + /// @return true if landscape is created + bool isVegetableLandscapeCreated() const {return _VegetableLandscape != NULL;} + + /// Load the landscape with help of setup in object_viewer_qt.cfg. return true if OK. + bool createVegetableLandscape(); + + /// If created, show the landscape + void showVegetableLandscape(); + + /// If created, hide the landscape + void hideVegetableLandscape(); + + /// Display vegetable with landscape + void enableLandscapeVegetable(bool enable); + + /// Refresh the vegetables in landscape, with the new vegetableSet + void refreshVegetableLandscape(const NL3D::CTileVegetableDesc &tvdesc); + + /// Get vegetable Wind wetup. + float getVegetableWindPower() const {return _VegetableWindPower;} + float getVegetableWindBendStart() const {return _VegetableWindBendMin;} + float getVegetableWindFrequency() const {return _VegetableWindFreq;} + + /// Set vegetable Wind wetup (updat view if possible) + void setVegetableWindPower(float w); + void setVegetableWindBendStart(float w); + void setVegetableWindFrequency(float w); + + void setVegetableAmbientLight(const NLMISC::CRGBA &ambient); + void setVegetableDiffuseLight(const NLMISC::CRGBA &diffuse); + + NLMISC::CRGBA getVegetableAmbientLight() const {return _VegetableLandscapeAmbient;} + NLMISC::CRGBA getVegetableDiffuseLight() const {return _VegetableLandscapeDiffuse;} + + /// If enable, snap the camera to the ground of the landscape. + void snapToGroundVegetableLandscape(bool enable); + //@} + + /// @name Vegetable control + //@{ + + /// Refresh vegetable display even if box unchecked. + void refreshVegetableDisplay(); + + /// Load a vegetSet + bool loadVegetableSet(NL3D::CTileVegetableDesc &vegetSet, std::string fileName); + + /// Build the vegetSet from the current _Vegetables + /// NB: transform Rotate Angle in Radians. + /// @param keepDefaultShapeName - if true, then vegetables with a ShapeName=="" are kept. + /// @param keepHiden - if true, then vegetables maked as hiden in ObjectViewer are kept. + void buildVegetableSet(NL3D::CTileVegetableDesc &vegetSet, bool keepDefaultShapeName = true, bool keepHiden = true ); + + /// Append the vegetSet to the current _Vegetables + /// NB: transform Rotate Angle in Degrees. + void appendVegetableSet(NL3D::CTileVegetableDesc &vegetSet); + + /// Clear all vegetables. + void clearVegetables(); + + /// Get full list vegetables from the landscape + /// @param listVeget - ref of return list vegetables + void getListVegetables(std::vector &listVeget); + + /// Create and add veget node to list + uint addVegetDesc(const NL3D::CVegetable &vegetable); + + /// Create empty veget node and insert to list + void insEmptyVegetDesc(uint row); + + /// Remove veget node from the list + void delVegetDesc(uint id); + + CVegetableNode *getVegetable(sint id); + //@} + + /// Update snap the camera to the ground of the landscape (if enabled snapToGroundVegetableLandscape()). + void update(); + + NL3D::IDriver *getDriver() const { return _Driver; } + + NL3D::CScene *getScene() const { return _Scene; } + +private: + void loadConfig(); + + void loadLandscapeSetup(); + + void saveConfig(); + + NL3D::CLandscapeModel *_VegetableLandscape; + + // File info to build it + std::string _VegetableLandscapeTileBank; + std::string _VegetableLandscapeTileFarBank; + std::vector _VegetableLandscapeZoneNames; + + // Misc. + float _VegetableLandscapeThreshold; + float _VegetableLandscapeTileNear; + float _VegetableLandscapeMultiply; + NLMISC::CRGBA _VegetableLandscapeAmbient; + NLMISC::CRGBA _VegetableLandscapeDiffuse; + std::string _VegetableTexture; + NLMISC::CRGBA _VegetableAmbient; + NLMISC::CRGBA _VegetableDiffuse; + NLMISC::CVector _VegetableLightDir; + // Vegetable wind. + NLMISC::CVector _VegetableWindDir; + float _VegetableWindFreq; + float _VegetableWindPower; + float _VegetableWindBendMin; + + bool _VegetableEnabled; + + // Collision + bool _VegetableSnapToGround; + float _VegetableSnapHeight; + NL3D::CVisualCollisionManager *_VegetableCollisionManager; + NL3D::CVisualCollisionEntity *_VegetableCollisionEntity; + + // The vegetable List. + std::vector _Vegetables; + + NL3D::IDriver *_Driver; + NL3D::CScene *_Scene; + +}; /* class CVegetableEditor */ + +} /* namespace NLQT */ + +#endif // VEGETABLE_EDITOR_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_landscape_form.ui b/code/nel/tools/3d/object_viewer_qt/src/vegetable_landscape_form.ui new file mode 100644 index 000000000..352fe72f4 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_landscape_form.ui @@ -0,0 +1,268 @@ + + + CVegetableLandscapePage + + + + 0 + 0 + 374 + 475 + + + + Form + + + + + + false + + + Setup Wind + + + + + + + + Power: + + + powerHorizontalSlider + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + true + + + QAbstractSpinBox::NoButtons + + + 10.000000000000000 + + + + + + + + + 1000 + + + Qt::Horizontal + + + + + + + + + Bend Start: + + + bendStartHorizontalSlider + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + true + + + QAbstractSpinBox::NoButtons + + + 3 + + + 1.000000000000000 + + + + + + + + + 1000 + + + Qt::Horizontal + + + + + + + + + Frequency + + + frequencyHorizontalSlider + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + true + + + QAbstractSpinBox::NoButtons + + + 10.000000000000000 + + + + + + + + + 1000 + + + Qt::Horizontal + + + + + + + + + + false + + + QTabWidget::South + + + 0 + + + + Ambient color + + + + + + + + + + Diffuse color + + + + + + + + + + + + + Show Vegetable Lands + + + + + + + false + + + Snap Camera To Ground + + + + + + + Qt::Vertical + + + + 20 + 168 + + + + + + + + + NLQT::CColorEditWidget + QWidget +
color_edit_widget.h
+ 1 +
+
+ + powerHorizontalSlider + bendStartHorizontalSlider + frequencyHorizontalSlider + colorTabWidget + showLandscapeCheckBox + snapCameraToGroundCheckBox + powerDoubleSpinBox + bendStartDoubleSpinBox + frequiencyDoubleSpinBox + + + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_landscape_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/vegetable_landscape_page.cpp new file mode 100644 index 000000000..aaef671bf --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_landscape_page.cpp @@ -0,0 +1,135 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "vegetable_landscape_page.h" + +// Project includes +#include "modules.h" + +#define NL_VEGETABLE_EDIT_WIND_MAX_POWER 10.f +#define NL_VEGETABLE_EDIT_WIND_MAX_FREQUENCY 10.f +#define NL_VEGETABLE_EDIT_WIND_MAX_BENDSTART 1.f + +namespace NLQT { + +CVegetableLandscapePage::CVegetableLandscapePage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + connect(_ui.powerHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setPowerSlider(int))); + connect(_ui.bendStartHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setBendStartSlider(int))); + connect(_ui.frequencyHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setFrequencySlider(int))); + connect(_ui.showLandscapeCheckBox, SIGNAL(toggled(bool)), this, SLOT(setVisibleLandscape(bool))); + connect(_ui.snapCameraToGroundCheckBox, SIGNAL(toggled(bool)), this, SLOT(setSnapCameraToGround(bool))); + connect(_ui.diffuseColorWidget, SIGNAL(colorChanged(NLMISC::CRGBA)), this, SLOT(setColorDiffuse(NLMISC::CRGBA))); + connect(_ui.ambientColorwidget, SIGNAL(colorChanged(NLMISC::CRGBA)), this, SLOT(setColorAmbient(NLMISC::CRGBA))); + + float windPower = Modules::veget().getVegetableWindPower(); + NLMISC::clamp(windPower, 0, NL_VEGETABLE_EDIT_WIND_MAX_POWER); + _ui.powerHorizontalSlider->setValue(int(windPower * _ui.powerHorizontalSlider->maximum() / NL_VEGETABLE_EDIT_WIND_MAX_POWER)); + + float bendStar = Modules::veget().getVegetableWindBendStart(); + NLMISC::clamp(bendStar, 0, NL_VEGETABLE_EDIT_WIND_MAX_BENDSTART); + _ui.bendStartHorizontalSlider->setValue(int(bendStar * _ui.bendStartHorizontalSlider->maximum() / NL_VEGETABLE_EDIT_WIND_MAX_BENDSTART)); + + float frequency = Modules::veget().getVegetableWindFrequency(); + NLMISC::clamp(frequency, 0, NL_VEGETABLE_EDIT_WIND_MAX_FREQUENCY); + _ui.frequencyHorizontalSlider->setValue(int(frequency * _ui.frequencyHorizontalSlider->maximum() / NL_VEGETABLE_EDIT_WIND_MAX_FREQUENCY)); + + _ui.diffuseColorWidget->setColor(Modules::veget().getVegetableDiffuseLight(), false); + _ui.ambientColorwidget->setColor(Modules::veget().getVegetableAmbientLight(), false); +} + +CVegetableLandscapePage::~CVegetableLandscapePage() +{ +} + +void CVegetableLandscapePage::setPowerSlider(int value) +{ + float windPower = float(value * NL_VEGETABLE_EDIT_WIND_MAX_POWER / _ui.powerHorizontalSlider->maximum()); + _ui.powerDoubleSpinBox->setValue(windPower); + Modules::veget().setVegetableWindPower(windPower); +} + +void CVegetableLandscapePage::setBendStartSlider(int value) +{ + float bendStar = float(value * NL_VEGETABLE_EDIT_WIND_MAX_BENDSTART / _ui.bendStartHorizontalSlider->maximum()); + _ui.bendStartDoubleSpinBox->setValue(bendStar); + Modules::veget().setVegetableWindBendStart(bendStar); +} + +void CVegetableLandscapePage::setFrequencySlider(int value) +{ + float frequency = float(value * NL_VEGETABLE_EDIT_WIND_MAX_FREQUENCY / _ui.frequencyHorizontalSlider->maximum()); + _ui.frequiencyDoubleSpinBox->setValue(frequency); + Modules::veget().setVegetableWindFrequency(frequency); +} + +void CVegetableLandscapePage::setVisibleLandscape(bool state) +{ + if(state) + { + // Landscape not created ?? + if(!Modules::veget().isVegetableLandscapeCreated()) + { + // if success to create / Load the landscape. + if(Modules::veget().createVegetableLandscape()) + { + _ui.windGroupBox->setEnabled(true); + _ui.colorTabWidget->setEnabled(true); + _ui.snapCameraToGroundCheckBox->setEnabled(true); + // refresh view, independently of checkBox + //doRefreshVegetableDisplay(); + } + else + { + // Failed in load, never retry. + _ui.showLandscapeCheckBox->setChecked(false); + } + } + + // show the landscape + Modules::veget().showVegetableLandscape(); + Q_EMIT changeVisibleLandscape(true); + } + else + { + Modules::veget().hideVegetableLandscape(); + Q_EMIT changeVisibleLandscape(false); + } +} + +void CVegetableLandscapePage::setSnapCameraToGround(bool state) +{ + Modules::veget().snapToGroundVegetableLandscape(state); +} + +void CVegetableLandscapePage::setColorAmbient(NLMISC::CRGBA color) +{ + Modules::veget().setVegetableAmbientLight(color); +} + +void CVegetableLandscapePage::setColorDiffuse(NLMISC::CRGBA color) +{ + Modules::veget().setVegetableDiffuseLight(color); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_landscape_page.h b/code/nel/tools/3d/object_viewer_qt/src/vegetable_landscape_page.h new file mode 100644 index 000000000..b545bc52f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_landscape_page.h @@ -0,0 +1,61 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef VEGETABLE_LANDSCAPE_PAGE_H +#define VEGETABLE_LANDSCAPE_PAGE_H + +#include "ui_vegetable_landscape_form.h" + +// STL includes + +// NeL includes + +// Project includes + +namespace NLQT { + +class CVegetableLandscapePage: public QWidget +{ + Q_OBJECT + +public: + CVegetableLandscapePage(QWidget *parent = 0); + ~CVegetableLandscapePage(); + +Q_SIGNALS: + void changeVisibleLandscape(bool state); + +private Q_SLOTS: + void setPowerSlider(int value); + void setBendStartSlider(int value); + void setFrequencySlider(int value); + void setVisibleLandscape(bool state); + void setSnapCameraToGround(bool state); + void setColorAmbient(NLMISC::CRGBA color); + void setColorDiffuse(NLMISC::CRGBA color); + +private: + + Ui::CVegetableLandscapePage _ui; + +}; /* class CVegetableLandscapePage */ + +} /* namespace NLQT */ + +#endif // VEGETABLE_LANDSCAPE_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_node.cpp b/code/nel/tools/3d/object_viewer_qt/src/vegetable_node.cpp new file mode 100644 index 000000000..5403bd8f4 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_node.cpp @@ -0,0 +1,130 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "vegetable_node.h" + +#include "modules.h" + +namespace NLQT { + +static const char *NL_DefaultVegetName= ""; + +CVegetableNode::CVegetableNode(void) +{ + Vegetable = NULL; + VegetableName = NL_DefaultVegetName; + Visible = true; +} + +void CVegetableNode::initDefaultVegetable() +{ + Vegetable= new NL3D::CVegetable; + // update vegetableName according to Vegetable + updateVegetableName(); + + // init Vegetable with some good default values. + + // General/Density. + // Density. + Vegetable->Density.Abs = NL_VEGETABLE_DENSITY_ABS_DEFAULT; + Vegetable->Density.Rand = NL_VEGETABLE_DENSITY_RAND_DEFAULT; + Vegetable->Density.Frequency = NL_VEGETABLE_FREQ_DEFAULT; + // disable MaxDensity + Vegetable->MaxDensity = -1; + // Leave ShapeName to "" + // Default DistType is always 0. + Vegetable->DistType = 0; + + + // Apperance + // BendPhase + Vegetable->BendPhase.Abs = NL_VEGETABLE_BENDPHASE_ABS_DEFAULT; + Vegetable->BendPhase.Rand = NL_VEGETABLE_BENDPHASE_RAND_DEFAULT; + Vegetable->BendPhase.Frequency = NL_VEGETABLE_FREQ_DEFAULT; + // BendFactor + Vegetable->BendFactor.Abs = NL_VEGETABLE_BENDFACTOR_ABS_DEFAULT; + Vegetable->BendFactor.Rand = NL_VEGETABLE_BENDFACTOR_RAND_DEFAULT; + Vegetable->BendFactor.Frequency = NL_VEGETABLE_FREQ_DEFAULT; + // Color + Vegetable->Color.NoiseValue.Abs = NL_VEGETABLE_COLOR_ABS_DEFAULT; + Vegetable->Color.NoiseValue.Rand = NL_VEGETABLE_COLOR_RAND_DEFAULT; + Vegetable->Color.NoiseValue.Frequency = NL_VEGETABLE_FREQ_DEFAULT; + + // Scale + // ScaleXY + Vegetable->Sxy.Abs = NL_VEGETABLE_SCALE_ABS_DEFAULT; + Vegetable->Sxy.Rand = NL_VEGETABLE_SCALE_RAND_DEFAULT; + Vegetable->Sxy.Frequency = NL_VEGETABLE_FREQ_DEFAULT; + // ScaleZ. + Vegetable->Sz.Abs = NL_VEGETABLE_SCALE_ABS_DEFAULT; + Vegetable->Sz.Rand = NL_VEGETABLE_SCALE_RAND_DEFAULT; + Vegetable->Sz.Frequency = NL_VEGETABLE_FREQ_DEFAULT; + + // Rotate + // RotateX + Vegetable->Rx.Abs = NL_VEGETABLE_ROTATEX_ABS_DEFAULT; + Vegetable->Rx.Rand = NL_VEGETABLE_ROTATEX_RAND_DEFAULT; + Vegetable->Rx.Frequency = NL_VEGETABLE_FREQ_DEFAULT; + // RotateY + Vegetable->Ry.Abs = NL_VEGETABLE_ROTATEY_ABS_DEFAULT; + Vegetable->Ry.Rand = NL_VEGETABLE_ROTATEY_RAND_DEFAULT; + Vegetable->Ry.Frequency = NL_VEGETABLE_FREQ_DEFAULT; + // RotateZ + Vegetable->Rz.Abs = NL_VEGETABLE_ROTATEZ_ABS_DEFAULT; + Vegetable->Rz.Rand = NL_VEGETABLE_ROTATEZ_RAND_DEFAULT; + Vegetable->Rz.Frequency = NL_VEGETABLE_ROTATEZ_FREQ_DEFAULT; + +} + +void CVegetableNode::initVegetable(const NL3D::CVegetable &vegetable) +{ + Vegetable = new NL3D::CVegetable(vegetable); + // update vegetableName according to Vegetable + updateVegetableName(); +} + + +void CVegetableNode::updateVegetableName() +{ + // Build the vegetable Name according to the ShapeName + if(Vegetable->ShapeName == "") + { + VegetableName = NL_DefaultVegetName; + } + else + { + std::string::size_type pos = Vegetable->ShapeName.find(".veget"); + VegetableName= Vegetable->ShapeName.substr(0, pos); + // And (to be clearer) append distance of creation. + char str[256]; + sprintf(str, " - %dm", (Vegetable->DistType + 1) * 10); + VegetableName += str; + // NB: if you add info with other parameters, you must use updateCurSelVegetableName() if they change + } +} + +void CVegetableNode::deleteVegetable() +{ + delete Vegetable; + Vegetable = NULL; + VegetableName = NL_DefaultVegetName; +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_node.h b/code/nel/tools/3d/object_viewer_qt/src/vegetable_node.h new file mode 100644 index 000000000..aa739ac21 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_node.h @@ -0,0 +1,61 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef VEGETABLE_NODE_H +#define VEGETABLE_NODE_H + +// STL includes +#include + +// NeL includes +#include + +namespace NLQT { + +class CVegetableNode +{ +public: + /// Constructor + CVegetableNode(void); + + // init the vegetable + void initDefaultVegetable(); + + void initVegetable(const NL3D::CVegetable &vegetable); + + // update VegetableName according to Vegetable + void updateVegetableName(); + + // delete the vegetable + void deleteVegetable(); + + // The vegetable + NL3D::CVegetable *Vegetable; + + // The name of this vegetable. + std::string VegetableName; + + // Visibility. Editor feature only + bool Visible; + +}; /* class CVegetableNode */ + +} /* namespace NLQT */ + +#endif // VEGETABLE_NODE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_noise_value_form.ui b/code/nel/tools/3d/object_viewer_qt/src/vegetable_noise_value_form.ui new file mode 100644 index 000000000..a30bf0883 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_noise_value_form.ui @@ -0,0 +1,168 @@ + + + CVegetNoiseValueWidget + + + + 0 + 0 + 312 + 110 + + + + GroupBox + + + + + + + + + AbsValue: + + + + + + + false + + + 100 + + + 50 + + + Qt::Vertical + + + + + + + QLayout::SetMinimumSize + + + + + false + + + *3 + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 23 + + + + + + + + false + + + 100% + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 23 + + + + + + + + false + + + /3 + + + + + + + + + + 0 + 0 + + + + + + + + RandValue: + + + + + + + + 0 + 0 + + + + + + + + Frequency: + + + + + + + + 0 + 0 + + + + + + + + + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_noise_value_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/vegetable_noise_value_widget.cpp new file mode 100644 index 000000000..c4e4c6a15 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_noise_value_widget.cpp @@ -0,0 +1,108 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "vegetable_noise_value_widget.h" + +// NeL includes + +#define NL_VEGETABLE_EDIT_SLIDER_NVS_SIZE_THRESHOLD 0.03f +#define NL_VEGETABLE_EDIT_SLIDER_NVS_SCALE 3.0f + +namespace NLQT { + +CVegetNoiseValueWidget::CVegetNoiseValueWidget(QWidget *parent) + : QGroupBox(parent), _emit(true) +{ + _ui.setupUi(this); + + connect(_ui.verticalSlider, SIGNAL(valueChanged(int)), this, SLOT(setSlider(int))); + connect(_ui.verticalSlider, SIGNAL(sliderReleased()), this, SLOT(sliderReleased())); + connect(_ui.absWidget, SIGNAL(valueChanged(float)), this, SLOT(setAbsValue(float))); + connect(_ui.randWidget, SIGNAL(valueChanged(float)), this, SLOT(setRandValue(float))); + connect(_ui.freqWidget, SIGNAL(valueChanged(float)), this, SLOT(setFreqValue(float))); + + setDefaultRangeAbs(0, 1); + setDefaultRangeRand(0, 1); + setDefaultRangeFreq(0, 1); + + setNoiseValue(NLMISC::CNoiseValue(), false); +} + +CVegetNoiseValueWidget::~CVegetNoiseValueWidget() +{ +} + +void CVegetNoiseValueWidget::setNoiseValue(const NLMISC::CNoiseValue &value, bool emit) +{ + _emit = false; + _ui.absWidget->setValue(value.Abs); + _ui.randWidget->setValue(value.Rand); + _ui.freqWidget->setValue(value.Frequency); + _emit = true; + if (emit) + noiseValueChanged(_NoiseValue); +} + +void CVegetNoiseValueWidget::setDefaultRangeAbs(float defRangeMin, float defRangeMax) +{ + _ui.absWidget->setRange(defRangeMin, defRangeMax); +} + +void CVegetNoiseValueWidget::setDefaultRangeRand(float defRangeMin, float defRangeMax) +{ + _ui.randWidget->setRange(defRangeMin, defRangeMax); +} + +void CVegetNoiseValueWidget::setDefaultRangeFreq(float defRangeMin, float defRangeMax) +{ + _ui.freqWidget->setRange(defRangeMin, defRangeMax); +} + +void CVegetNoiseValueWidget::setSlider(int value) +{ +} + +void CVegetNoiseValueWidget::sliderReleased() +{ +} + +void CVegetNoiseValueWidget::setAbsValue(float value) +{ + _NoiseValue.Abs = value; + if (_emit) + noiseValueChanged(_NoiseValue); +} + +void CVegetNoiseValueWidget::setRandValue(float value) +{ + _NoiseValue.Rand = value; + if (_emit) + noiseValueChanged(_NoiseValue); + +} + +void CVegetNoiseValueWidget::setFreqValue(float value) +{ + _NoiseValue.Frequency = value; + if (_emit) + noiseValueChanged(_NoiseValue); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_noise_value_widget.h b/code/nel/tools/3d/object_viewer_qt/src/vegetable_noise_value_widget.h new file mode 100644 index 000000000..8f715851b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_noise_value_widget.h @@ -0,0 +1,69 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef VEGETABLE_NOISE_VALUE_WIDGET_H +#define VEGETABLE_NOISE_VALUE_WIDGET_H + +#include "ui_vegetable_noise_value_form.h" + +// STL includes + +// NeL includes +#include + +// Project includes + +namespace NLQT { + +class CVegetNoiseValueWidget: public QGroupBox +{ + Q_OBJECT + +public: + CVegetNoiseValueWidget(QWidget *parent = 0); + ~CVegetNoiseValueWidget(); + + void setNoiseValue(const NLMISC::CNoiseValue &value, bool emit = true); + + void setDefaultRangeAbs(float defRangeMin, float defRangeMax); + void setDefaultRangeRand(float defRangeMin, float defRangeMax); + void setDefaultRangeFreq(float defRangeMin, float defRangeMax); + +Q_SIGNALS: + void noiseValueChanged(NLMISC::CNoiseValue value); + +private Q_SLOTS: + void setSlider(int value); + void sliderReleased(); + void setAbsValue(float value); + void setRandValue(float value); + void setFreqValue(float value); + +private: + NLMISC::CNoiseValue _NoiseValue; + + bool _emit; + + Ui::CVegetNoiseValueWidget _ui; + +}; /* class CVegetNoiseValueWidget */ + +} /* namespace NLQT */ + +#endif // VEGETABLE_NOISE_VALUE_WIDGET_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_rotate_form.ui b/code/nel/tools/3d/object_viewer_qt/src/vegetable_rotate_form.ui new file mode 100644 index 000000000..825b5a860 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_rotate_form.ui @@ -0,0 +1,63 @@ + + + CVegetableRotatePage + + + + 0 + 0 + 204 + 223 + + + + Form + + + + + + Rotate X + + + + + + + Rotate Y + + + + + + + Rotate Z + + + + + + + Qt::Vertical + + + + 20 + 158 + + + + + + + + + NLQT::CVegetNoiseValueWidget + QGroupBox +
vegetable_noise_value_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_rotate_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/vegetable_rotate_page.cpp new file mode 100644 index 000000000..73a49597d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_rotate_page.cpp @@ -0,0 +1,93 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "vegetable_rotate_page.h" + +// NeL includes +#include + +// Projects include +#include "modules.h" + +namespace NLQT { + +CVegetableRotatePage::CVegetableRotatePage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + _ui.rotateXGroupBox->setDefaultRangeAbs(NL_VEGETABLE_ROTATE_RANGE_MIN, NL_VEGETABLE_ROTATE_RANGE_MAX); + _ui.rotateXGroupBox->setDefaultRangeRand(NL_VEGETABLE_ROTATE_RANGE_MIN, NL_VEGETABLE_ROTATE_RANGE_MAX); + _ui.rotateXGroupBox->setDefaultRangeFreq(NL_VEGETABLE_FREQ_RANGE_MIN, NL_VEGETABLE_FREQ_RANGE_MAX); + + _ui.rotateYGroupBox->setDefaultRangeAbs(NL_VEGETABLE_ROTATE_RANGE_MIN, NL_VEGETABLE_ROTATE_RANGE_MAX); + _ui.rotateYGroupBox->setDefaultRangeRand(NL_VEGETABLE_ROTATE_RANGE_MIN, NL_VEGETABLE_ROTATE_RANGE_MAX); + _ui.rotateYGroupBox->setDefaultRangeFreq(NL_VEGETABLE_FREQ_RANGE_MIN, NL_VEGETABLE_FREQ_RANGE_MAX); + + _ui.rotateZGroupBox->setDefaultRangeAbs(NL_VEGETABLE_ROTATE_RANGE_MIN, NL_VEGETABLE_ROTATE_RANGE_MAX); + _ui.rotateZGroupBox->setDefaultRangeRand(NL_VEGETABLE_ROTATE_RANGE_MIN, NL_VEGETABLE_ROTATE_RANGE_MAX); + _ui.rotateZGroupBox->setDefaultRangeFreq(NL_VEGETABLE_FREQ_RANGE_MIN, NL_VEGETABLE_FREQ_RANGE_MAX); + + setEnabled(false); + + connect(_ui.rotateXGroupBox, SIGNAL(noiseValueChanged(NLMISC::CNoiseValue)), this, SLOT(setNoiseValueRotateX(NLMISC::CNoiseValue))); + connect(_ui.rotateYGroupBox, SIGNAL(noiseValueChanged(NLMISC::CNoiseValue)), this, SLOT(setNoiseValueRotateX(NLMISC::CNoiseValue))); + connect(_ui.rotateZGroupBox, SIGNAL(noiseValueChanged(NLMISC::CNoiseValue)), this, SLOT(setNoiseValueRotateZ(NLMISC::CNoiseValue))); +} + +CVegetableRotatePage::~CVegetableRotatePage() +{ +} + +void CVegetableRotatePage::setVegetableToEdit(NL3D::CVegetable *vegetable) +{ + _Vegetable = vegetable; + + if(_Vegetable) + { + setEnabled(true); + + _ui.rotateXGroupBox->setNoiseValue(_Vegetable->Rx, false); + _ui.rotateYGroupBox->setNoiseValue(_Vegetable->Ry, false); + _ui.rotateZGroupBox->setNoiseValue(_Vegetable->Rz, false); + } + else + setEnabled(false); +} + +void CVegetableRotatePage::setNoiseValueRotateX(NLMISC::CNoiseValue value) +{ + _Vegetable->Rx = value; + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableRotatePage::setNoiseValueRotateY(NLMISC::CNoiseValue value) +{ + _Vegetable->Ry = value; + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableRotatePage::setNoiseValueRotateZ(NLMISC::CNoiseValue value) +{ + _Vegetable->Rz = value; + Modules::veget().refreshVegetableDisplay(); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_rotate_page.h b/code/nel/tools/3d/object_viewer_qt/src/vegetable_rotate_page.h new file mode 100644 index 000000000..21f1e7414 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_rotate_page.h @@ -0,0 +1,64 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef VEGETABLE_ROTATE_PAGE_H +#define VEGETABLE_ROTATE_PAGE_H + +#include "ui_vegetable_rotate_form.h" + +// STL includes + +// NeL includes + +// Project includes + +namespace NL3D +{ + class CVegetable; +} + +namespace NLQT { + +class CVegetableRotatePage: public QWidget +{ + Q_OBJECT + +public: + CVegetableRotatePage(QWidget *parent = 0); + ~CVegetableRotatePage(); + + /// set the vegetble to edit. NULL will disable all the controls. + void setVegetableToEdit(NL3D::CVegetable *vegetable); + +private Q_SLOTS: + void setNoiseValueRotateX(NLMISC::CNoiseValue value); + void setNoiseValueRotateY(NLMISC::CNoiseValue value); + void setNoiseValueRotateZ(NLMISC::CNoiseValue value); + +private: + + // The vegetable to edit. + NL3D::CVegetable *_Vegetable; + + Ui::CVegetableRotatePage _ui; + +}; /* class CVegetableRotatePage */ + +} /* namespace NLQT */ +#endif // VEGETABLE_ROTATE_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_scale_form.ui b/code/nel/tools/3d/object_viewer_qt/src/vegetable_scale_form.ui new file mode 100644 index 000000000..a78c16abd --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_scale_form.ui @@ -0,0 +1,74 @@ + + + CVegetableScalePage + + + + 0 + 0 + 194 + 237 + + + + Form + + + + + + Scale X/Y + + + + + + + Scale Z + + + + + + + Bend Frequency Factor + + + + + + + + + + + + Qt::Vertical + + + + 20 + 172 + + + + + + + + + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CVegetNoiseValueWidget + QGroupBox +
vegetable_noise_value_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_scale_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/vegetable_scale_page.cpp new file mode 100644 index 000000000..5d429e631 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_scale_page.cpp @@ -0,0 +1,92 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "vegetable_scale_page.h" + +// NeL includes +#include + +// Projects include +#include "modules.h" + +namespace NLQT { + +CVegetableScalePage::CVegetableScalePage(QWidget *parent) + : QWidget(parent) +{ + _ui.setupUi(this); + + _ui.scaleXYGroupBox->setDefaultRangeAbs(NL_VEGETABLE_SCALE_RANGE_MIN, NL_VEGETABLE_SCALE_RANGE_MAX); + _ui.scaleXYGroupBox->setDefaultRangeRand(NL_VEGETABLE_SCALE_RANGE_MIN, NL_VEGETABLE_SCALE_RANGE_MAX); + _ui.scaleXYGroupBox->setDefaultRangeFreq(NL_VEGETABLE_FREQ_RANGE_MIN, NL_VEGETABLE_FREQ_RANGE_MAX); + + _ui.scaleZGroupBox->setDefaultRangeAbs(NL_VEGETABLE_SCALE_RANGE_MIN, NL_VEGETABLE_SCALE_RANGE_MAX); + _ui.scaleZGroupBox->setDefaultRangeRand(NL_VEGETABLE_SCALE_RANGE_MIN, NL_VEGETABLE_SCALE_RANGE_MAX); + _ui.scaleZGroupBox->setDefaultRangeFreq(NL_VEGETABLE_FREQ_RANGE_MIN, NL_VEGETABLE_FREQ_RANGE_MAX); + + _ui.freqFactorWidget->setRange(NL_VEGETABLE_BENDFREQ_RANGE_MIN, NL_VEGETABLE_BENDFREQ_RANGE_MAX); + + setEnabled(false); + + connect(_ui.scaleXYGroupBox, SIGNAL(noiseValueChanged(NLMISC::CNoiseValue)), this, SLOT(setNoiseValueXYSize(NLMISC::CNoiseValue))); + connect(_ui.scaleZGroupBox, SIGNAL(noiseValueChanged(NLMISC::CNoiseValue)), this, SLOT(setNoiseValueXYSize(NLMISC::CNoiseValue))); + connect(_ui.freqFactorWidget, SIGNAL(valueChanged(float)), this, SLOT(setFreqFactor(float))); +} + +CVegetableScalePage::~CVegetableScalePage() +{ +} + +void CVegetableScalePage::setVegetableToEdit(NL3D::CVegetable *vegetable) +{ + _Vegetable = vegetable; + + if(_Vegetable) + { + setEnabled(true); + + _ui.scaleXYGroupBox->setNoiseValue(_Vegetable->Sxy, false); + _ui.scaleZGroupBox->setNoiseValue(_Vegetable->Sz, false); + + _ui.freqFactorWidget->setValue(_Vegetable->BendFrequencyFactor, false); + } + else + setEnabled(false); +} + +void CVegetableScalePage::setNoiseValueXYSize(NLMISC::CNoiseValue value) +{ + _Vegetable->Sxy = value; + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableScalePage::setNoiseValueZSize(NLMISC::CNoiseValue value) +{ + _Vegetable->Sz = value; + Modules::veget().refreshVegetableDisplay(); +} + +void CVegetableScalePage::setFreqFactor(float value) +{ + _Vegetable->BendFrequencyFactor = value; + Modules::veget().refreshVegetableDisplay(); +} + +} /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/vegetable_scale_page.h b/code/nel/tools/3d/object_viewer_qt/src/vegetable_scale_page.h new file mode 100644 index 000000000..4181f0e41 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/vegetable_scale_page.h @@ -0,0 +1,65 @@ +/* + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef VEGETABLE_SCALE_PAGE_H +#define VEGETABLE_SCALE_PAGE_H + +#include "ui_vegetable_scale_form.h" + +// STL includes + +// NeL includes + +// Project includes + +namespace NL3D +{ + class CVegetable; +} + +namespace NLQT { + +class CVegetableScalePage: public QWidget +{ + Q_OBJECT + +public: + CVegetableScalePage(QWidget *parent = 0); + ~CVegetableScalePage(); + + /// set the vegetble to edit. NULL will disable all the controls. + void setVegetableToEdit(NL3D::CVegetable *vegetable); + +private Q_SLOTS: + void setNoiseValueXYSize(NLMISC::CNoiseValue value); + void setNoiseValueZSize(NLMISC::CNoiseValue value); + void setFreqFactor(float value); + +private: + + // The vegetable to edit. + NL3D::CVegetable *_Vegetable; + + Ui::CVegetableScalePage _ui; + +}; /* class CVegetableScalePage */ + +} /* namespace NLQT */ + +#endif // VEGETABLE_SCALE_PAGE_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/water_pool_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/water_pool_dialog.cpp new file mode 100644 index 000000000..00a02e93a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/water_pool_dialog.cpp @@ -0,0 +1,35 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "stdpch.h" +#include "water_pool_dialog.h" + +namespace NLQT { + +CWaterPoolDialog::CWaterPoolDialog(QWidget *parent) + : QDockWidget(parent) +{ + ui.setupUi(this); +} + +CWaterPoolDialog::~CWaterPoolDialog() +{ +} + +} /* namespace NLQT */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/water_pool_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/water_pool_dialog.h new file mode 100644 index 000000000..46319dc9a --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/water_pool_dialog.h @@ -0,0 +1,51 @@ +/* + Object Viewer Qt + Copyright (C) 2010 Dzmitry Kamiahin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifndef WATER_POOL_DIALOG_H +#define WATER_POOL_DIALOG_H + +#include "ui_water_pool_form.h" + +// STL includes + +// NeL includes + +// Project includes + +namespace NLQT { + +class CWaterPoolDialog: public QDockWidget +{ + Q_OBJECT + +public: + CWaterPoolDialog(QWidget *parent = 0); + ~CWaterPoolDialog(); + +private Q_SLOTS: + +private: + + Ui::CWaterPoolDialog ui; + +}; /* class CWaterPoolDialog */ + +} /* namespace NLQT */ + +#endif // WATER_POOL_DIALOG_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/water_pool_form.ui b/code/nel/tools/3d/object_viewer_qt/src/water_pool_form.ui new file mode 100644 index 000000000..f1103a7bd --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/water_pool_form.ui @@ -0,0 +1,281 @@ + + + CWaterPoolDialog + + + + 0 + 0 + 390 + 690 + + + + Water pool editor + + + + + + + Qt::Horizontal + + + + + QLayout::SetMinimumSize + + + + + Pool ID List: + + + + + + + + + + Add + + + + + + + Delete + + + + + + + Name... + + + + + + + + + + + + + Size: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 16 + + + + + 32 + + + + + 64 + + + + + 128 + + + + + 256 + + + + + 512 + + + + + + + + + + Water Unit Size: + + + + + + + + + + Damping: + + + + + + + + + + Filter weight: + + + + + + + + + + Propagation time: + + + + + + + + + + Enable automatic waves generation + + + + + + + Waves + + + + + + Impulsion strenght: + + + + + + + + + + Period: + + + + + + + + + + Impulsion radius: + + + + + + + + + + Generate on border only + + + + + + + + + + + + Load + + + + + + + Save + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + NLQT::CEditRangeUIntWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+
+ + +
diff --git a/code/nel/tools/3d/object_viewer_qt/src/workspace_form.ui b/code/nel/tools/3d/object_viewer_qt/src/workspace_form.ui new file mode 100644 index 000000000..640cda6c2 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/workspace_form.ui @@ -0,0 +1,456 @@ + + + CWorkspacePage + + + + 0 + 0 + 258 + 246 + + + + Form + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 11 + 75 + false + true + true + + + + 0 + + + Particle system editor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Workspace: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 55 + 55 + + + + + 55 + 55 + + + + New + + + + :/images/new.png:/images/new.png + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + true + + + + + + + + 55 + 55 + + + + + 55 + 55 + + + + Load + + + + :/images/open-file.png:/images/open-file.png + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + true + + + + + + + false + + + + 55 + 55 + + + + + 55 + 55 + + + + Save + + + + :/images/save.png:/images/save.png + + + + 32 + 32 + + + + false + + + Qt::ToolButtonTextUnderIcon + + + true + + + + + + + false + + + + 55 + 55 + + + + + 55 + 55 + + + + Save As + + + + :/images/save-as.png:/images/save-as.png + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Particle system: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + false + + + + 70 + 65 + + + + + 61 + 61 + + + + Insert New + + + + :/images/pqrticles.png:/images/pqrticles.png + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + true + + + + + + + false + + + + 70 + 65 + + + + + 61 + 61 + + + + Create New + + + + :/images/insert.png:/images/insert.png + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + true + + + + + + + false + + + + 70 + 65 + + + + + 61 + 61 + + + + Reset all + + + + :/images/clear.png:/images/clear.png + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 3 + + + + + + + + + + + diff --git a/code/nel/tools/3d/plugin_max/nel_3dsmax_shared/CMakeLists.txt b/code/nel/tools/3d/plugin_max/nel_3dsmax_shared/CMakeLists.txt index 37a9bb0be..04f0c3e52 100644 --- a/code/nel/tools/3d/plugin_max/nel_3dsmax_shared/CMakeLists.txt +++ b/code/nel/tools/3d/plugin_max/nel_3dsmax_shared/CMakeLists.txt @@ -14,7 +14,7 @@ TARGET_LINK_LIBRARIES(nel_3dsmax_shared NL_DEFAULT_PROPS(nel_3dsmax_shared "MAX Plugin: NeL 3DSMAX Shared") NL_ADD_RUNTIME_FLAGS(nel_3dsmax_shared) NL_ADD_LIB_SUFFIX(nel_3dsmax_shared) -SET_TARGET_PROPERTIES(nel_export PROPERTIES SUFFIX ".dlx") +#SET_TARGET_PROPERTIES(nel_export PROPERTIES SUFFIX ".dlx") ADD_DEFINITIONS(-DNEL_3DSMAX_SHARED_EXPORTS) diff --git a/code/nel/tools/3d/shapes_exporter/main.cpp b/code/nel/tools/3d/shapes_exporter/main.cpp index ec42049d6..dd004d460 100644 --- a/code/nel/tools/3d/shapes_exporter/main.cpp +++ b/code/nel/tools/3d/shapes_exporter/main.cpp @@ -174,9 +174,9 @@ sint main(int argc, char **argv) std::string output_path = exporter.settings.output_path + md5.substr(0, 2) + "/" + md5; // file is an animation - std::string animation = ""; // CPath::lookup(baseFilename + ".anim", false, false, false); + std::string animation; // CPath::lookup(baseFilename + ".anim", false, false, false); // file is a skeleton - std::string skeleton = ""; // CPath::lookup(baseFilename + ".skel", false, false, false); + std::string skeleton; // CPath::lookup(baseFilename + ".skel", false, false, false); // file is a shape std::string shape = CPath::lookup(baseFilename + ".shape", false, false, false); diff --git a/code/nel/tools/3d/shapes_exporter/shapes_exporter.cpp b/code/nel/tools/3d/shapes_exporter/shapes_exporter.cpp index 6abfe682b..a9cff1fc1 100644 --- a/code/nel/tools/3d/shapes_exporter/shapes_exporter.cpp +++ b/code/nel/tools/3d/shapes_exporter/shapes_exporter.cpp @@ -843,7 +843,7 @@ bool ShapesExporter::renderPS(UInstance &entity, const string &output_path, doub if(!saveOneImage(filename)) return false; } - if(time >= 30.0 || nbparticle == 0 && startTime > 0.0f || duration != 0.0f && time > duration) + if(time >= 30.0 || (nbparticle == 0 && startTime > 0.0f) || (duration != 0.0f && time > duration)) break; } diff --git a/code/nel/tools/3d/tile_edit_qt/browser_model.cpp b/code/nel/tools/3d/tile_edit_qt/browser_model.cpp index 55f2b33cf..a70966106 100644 --- a/code/nel/tools/3d/tile_edit_qt/browser_model.cpp +++ b/code/nel/tools/3d/tile_edit_qt/browser_model.cpp @@ -208,7 +208,7 @@ const std::string TileInfo::getRelativeFileName (TileTexture texture, int index) { nlassert(this->tileType != UnSet); - std::string currentPath = ""; + std::string currentPath; if (tileType != Displace) { currentPath = tileBankBrowser.getTile(index)->getRelativeFileName ((CTile::TBitmap)texture); diff --git a/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.tga b/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.tga index e25a81ef9..14ab1b585 100644 Binary files a/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.tga and b/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.txt b/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.txt index 48610a1c4..e8b54e4c0 100644 --- a/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.txt +++ b/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.txt @@ -22,7 +22,7 @@ bk_karavan.tga 0.078125000000 0.117187500000 0.117187500000 0.156250000000 BK_matis.tga 0.117187500000 0.117187500000 0.156250000000 0.156250000000 bk_mission.tga 0.156250000000 0.117187500000 0.195312500000 0.156250000000 bk_mission2.tga 0.195312500000 0.117187500000 0.234375000000 0.156250000000 -bk_outpost.tga 0.000000000000 0.156250000000 0.039062500000 0.195312500000 +BK_outpost.tga 0.000000000000 0.156250000000 0.039062500000 0.195312500000 BK_primes.tga 0.039062500000 0.156250000000 0.078125000000 0.195312500000 bk_service.tga 0.078125000000 0.156250000000 0.117187500000 0.195312500000 bk_training.tga 0.117187500000 0.156250000000 0.156250000000 0.195312500000 @@ -310,20 +310,13 @@ w_pa_diadem.tga 0.312500000000 0.468750000000 0.351562500000 0.507812500000 w_pa_earring.tga 0.351562500000 0.468750000000 0.390625000000 0.507812500000 w_pa_pendant.tga 0.390625000000 0.468750000000 0.429687500000 0.507812500000 w_pa_ring.tga 0.429687500000 0.468750000000 0.468750000000 0.507812500000 -faction_matis.tga 0.468750000000 0.468750000000 0.500000000000 0.500000000000 -faction_tryker.tga 0.500000000000 0.468750000000 0.531250000000 0.500000000000 -faction_tryton.tga 0.531250000000 0.468750000000 0.562500000000 0.500000000000 -faction_zorai.tga 0.562500000000 0.468750000000 0.593750000000 0.500000000000 -asc_exit.tga 0.593750000000 0.468750000000 0.625000000000 0.500000000000 -asc_rolemastercraft.tga 0.625000000000 0.468750000000 0.656250000000 0.500000000000 -asc_rolemasterfight.tga 0.656250000000 0.468750000000 0.687500000000 0.500000000000 -asc_rolemasterharvest.tga 0.687500000000 0.468750000000 0.718750000000 0.500000000000 -asc_rolemastermagic.tga 0.718750000000 0.468750000000 0.750000000000 0.500000000000 -asc_unknown.tga 0.750000000000 0.468750000000 0.781250000000 0.500000000000 -faction_fyros.tga 0.781250000000 0.468750000000 0.812500000000 0.500000000000 -faction_kami.tga 0.812500000000 0.468750000000 0.843750000000 0.500000000000 -faction_karavan.tga 0.843750000000 0.468750000000 0.875000000000 0.500000000000 -mail.tga 0.875000000000 0.468750000000 0.906250000000 0.492187500000 +asc_unknown.tga 0.468750000000 0.468750000000 0.500000000000 0.500000000000 +asc_exit.tga 0.500000000000 0.468750000000 0.531250000000 0.500000000000 +asc_rolemastercraft.tga 0.531250000000 0.468750000000 0.562500000000 0.500000000000 +asc_rolemasterfight.tga 0.562500000000 0.468750000000 0.593750000000 0.500000000000 +asc_rolemasterharvest.tga 0.593750000000 0.468750000000 0.625000000000 0.500000000000 +asc_rolemastermagic.tga 0.625000000000 0.468750000000 0.656250000000 0.500000000000 +mail.tga 0.656250000000 0.468750000000 0.687500000000 0.492187500000 ico_aim_homin_feet.tga 0.976562500000 0.078125000000 1.000000000000 0.101562500000 ico_aim_homin_feint.tga 0.976562500000 0.101562500000 1.000000000000 0.125000000000 ico_aim_homin_hands.tga 0.976562500000 0.125000000000 1.000000000000 0.148437500000 @@ -334,324 +327,340 @@ ico_aim_kitin_head.tga 0.976562500000 0.218750000000 1.000000000000 0.2421875000 mp_back_curative.tga 0.976562500000 0.242187500000 1.000000000000 0.265625000000 mp_back_offensive.tga 0.976562500000 0.265625000000 1.000000000000 0.289062500000 mp_back_selfonly.tga 0.976562500000 0.289062500000 1.000000000000 0.312500000000 -bk_outpost_brick.tga 0.976562500000 0.312500000000 1.000000000000 0.335937500000 +building_state_24x24.tga 0.976562500000 0.312500000000 1.000000000000 0.335937500000 ico_ammo_bullet.tga 0.976562500000 0.335937500000 1.000000000000 0.359375000000 ico_ammo_jacket.tga 0.976562500000 0.359375000000 1.000000000000 0.382812500000 ico_angle.tga 0.976562500000 0.382812500000 1.000000000000 0.406250000000 ico_anti_magic_shield.tga 0.976562500000 0.406250000000 1.000000000000 0.429687500000 ico_armor.tga 0.976562500000 0.429687500000 1.000000000000 0.453125000000 ico_armor_clip.tga 0.976562500000 0.453125000000 1.000000000000 0.476562500000 -ico_armor_heavy.tga 0.906250000000 0.468750000000 0.929687500000 0.492187500000 -ico_armor_kitin.tga 0.929687500000 0.468750000000 0.953125000000 0.492187500000 -ico_armor_light.tga 0.953125000000 0.468750000000 0.976562500000 0.492187500000 -ico_armor_medium.tga 0.976562500000 0.476562500000 1.000000000000 0.500000000000 -ico_armor_penalty.tga 0.875000000000 0.492187500000 0.898437500000 0.515625000000 -ico_armor_shell.tga 0.898437500000 0.492187500000 0.921875000000 0.515625000000 -ico_atys.tga 0.921875000000 0.492187500000 0.945312500000 0.515625000000 -ico_atysian.tga 0.945312500000 0.492187500000 0.968750000000 0.515625000000 -ico_balance_hp.tga 0.468750000000 0.500000000000 0.492187500000 0.523437500000 -ico_barrel.tga 0.492187500000 0.500000000000 0.515625000000 0.523437500000 -ico_bash.tga 0.515625000000 0.500000000000 0.539062500000 0.523437500000 -ico_berserk.tga 0.539062500000 0.500000000000 0.562500000000 0.523437500000 -ico_blade.tga 0.562500000000 0.500000000000 0.585937500000 0.523437500000 -ico_bleeding.tga 0.585937500000 0.500000000000 0.609375000000 0.523437500000 -ico_blind.tga 0.609375000000 0.500000000000 0.632812500000 0.523437500000 -ico_blunt.tga 0.632812500000 0.500000000000 0.656250000000 0.523437500000 -ico_bomb.tga 0.656250000000 0.500000000000 0.679687500000 0.523437500000 -bk_power.tga 0.679687500000 0.500000000000 0.703125000000 0.523437500000 -ico_celestial.tga 0.703125000000 0.500000000000 0.726562500000 0.523437500000 -ico_circular_attack.tga 0.726562500000 0.500000000000 0.750000000000 0.523437500000 -ico_clothes.tga 0.750000000000 0.500000000000 0.773437500000 0.523437500000 -ico_cold.tga 0.773437500000 0.500000000000 0.796875000000 0.523437500000 -ico_concentration.tga 0.796875000000 0.500000000000 0.820312500000 0.523437500000 -2h_over.tga 0.820312500000 0.500000000000 0.843750000000 0.523437500000 -ico_constitution.tga 0.843750000000 0.500000000000 0.867187500000 0.523437500000 -ico_counterweight.tga 0.968750000000 0.500000000000 0.992187500000 0.523437500000 -ico_craft_buff.tga 0.000000000000 0.507812500000 0.023437500000 0.531250000000 -ico_create_sapload.tga 0.023437500000 0.507812500000 0.046875000000 0.531250000000 -ico_curse.tga 0.046875000000 0.507812500000 0.070312500000 0.531250000000 -ico_debuff.tga 0.070312500000 0.507812500000 0.093750000000 0.531250000000 -ico_debuff_resist.tga 0.093750000000 0.507812500000 0.117187500000 0.531250000000 -ico_debuff_skill.tga 0.117187500000 0.507812500000 0.140625000000 0.531250000000 -ico_desert.tga 0.140625000000 0.507812500000 0.164062500000 0.531250000000 -ico_dexterity.tga 0.164062500000 0.507812500000 0.187500000000 0.531250000000 -ico_disarm.tga 0.187500000000 0.507812500000 0.210937500000 0.531250000000 -ico_dodge.tga 0.210937500000 0.507812500000 0.234375000000 0.531250000000 -ico_dot.tga 0.234375000000 0.507812500000 0.257812500000 0.531250000000 -ico_durability.tga 0.257812500000 0.507812500000 0.281250000000 0.531250000000 -ico_electric.tga 0.281250000000 0.507812500000 0.304687500000 0.531250000000 -ico_explosif.tga 0.304687500000 0.507812500000 0.328125000000 0.531250000000 -ico_extracting.tga 0.328125000000 0.507812500000 0.351562500000 0.531250000000 -ico_fear.tga 0.351562500000 0.507812500000 0.375000000000 0.531250000000 -ico_feint.tga 0.375000000000 0.507812500000 0.398437500000 0.531250000000 -ico_fire.tga 0.398437500000 0.507812500000 0.421875000000 0.531250000000 -ico_firing_pin.tga 0.421875000000 0.507812500000 0.445312500000 0.531250000000 -1h_over.tga 0.445312500000 0.507812500000 0.468750000000 0.531250000000 -BK_fyros_brick.tga 0.867187500000 0.515625000000 0.890625000000 0.539062500000 -mp_over_link.tga 0.890625000000 0.515625000000 0.914062500000 0.539062500000 -BK_magie_noire_brick.tga 0.914062500000 0.515625000000 0.937500000000 0.539062500000 -BK_tryker_brick.tga 0.937500000000 0.515625000000 0.960937500000 0.539062500000 -cp_back.tga 0.468750000000 0.523437500000 0.492187500000 0.546875000000 -cp_over_break.tga 0.492187500000 0.523437500000 0.515625000000 0.546875000000 -ico_focus.tga 0.515625000000 0.523437500000 0.539062500000 0.546875000000 -ico_forage_buff.tga 0.539062500000 0.523437500000 0.562500000000 0.546875000000 -ico_forbid_item.tga 0.562500000000 0.523437500000 0.585937500000 0.546875000000 -ico_forest.tga 0.585937500000 0.523437500000 0.609375000000 0.546875000000 -cp_over_less.tga 0.609375000000 0.523437500000 0.632812500000 0.546875000000 -ico_gardening.tga 0.632812500000 0.523437500000 0.656250000000 0.546875000000 -ico_gentle.tga 0.656250000000 0.523437500000 0.679687500000 0.546875000000 -ico_goo.tga 0.679687500000 0.523437500000 0.703125000000 0.546875000000 -ico_gripp.tga 0.703125000000 0.523437500000 0.726562500000 0.546875000000 -cp_over_more.tga 0.726562500000 0.523437500000 0.750000000000 0.546875000000 -cp_over_opening.tga 0.750000000000 0.523437500000 0.773437500000 0.546875000000 -ico_hammer.tga 0.773437500000 0.523437500000 0.796875000000 0.546875000000 -ico_harmful.tga 0.796875000000 0.523437500000 0.820312500000 0.546875000000 -ico_hatred.tga 0.820312500000 0.523437500000 0.843750000000 0.546875000000 -ico_heal.tga 0.843750000000 0.523437500000 0.867187500000 0.546875000000 -ico_hit_rate.tga 0.960937500000 0.523437500000 0.984375000000 0.546875000000 -ico_incapacity.tga 0.000000000000 0.531250000000 0.023437500000 0.554687500000 -ico_intelligence.tga 0.023437500000 0.531250000000 0.046875000000 0.554687500000 -ico_interrupt.tga 0.046875000000 0.531250000000 0.070312500000 0.554687500000 -ico_invulnerability.tga 0.070312500000 0.531250000000 0.093750000000 0.554687500000 -ico_jewel_stone.tga 0.093750000000 0.531250000000 0.117187500000 0.554687500000 -ico_jewel_stone_support.tga 0.117187500000 0.531250000000 0.140625000000 0.554687500000 -ico_jungle.tga 0.140625000000 0.531250000000 0.164062500000 0.554687500000 -ico_lacustre.tga 0.164062500000 0.531250000000 0.187500000000 0.554687500000 -ico_landmark_bonus.tga 0.187500000000 0.531250000000 0.210937500000 0.554687500000 -ico_level.tga 0.210937500000 0.531250000000 0.234375000000 0.554687500000 -ico_lining.tga 0.234375000000 0.531250000000 0.257812500000 0.554687500000 -ico_location.tga 0.257812500000 0.531250000000 0.281250000000 0.554687500000 -ico_madness.tga 0.281250000000 0.531250000000 0.304687500000 0.554687500000 -ico_magic.tga 0.304687500000 0.531250000000 0.328125000000 0.554687500000 -ico_magic_action_buff.tga 0.328125000000 0.531250000000 0.351562500000 0.554687500000 -ico_magic_focus.tga 0.351562500000 0.531250000000 0.375000000000 0.554687500000 -ico_magic_target_buff.tga 0.375000000000 0.531250000000 0.398437500000 0.554687500000 -ico_melee_action_buff.tga 0.398437500000 0.531250000000 0.421875000000 0.554687500000 -ico_melee_target_buff.tga 0.421875000000 0.531250000000 0.445312500000 0.554687500000 -ico_mental.tga 0.445312500000 0.531250000000 0.468750000000 0.554687500000 -no_action.tga 0.867187500000 0.539062500000 0.890625000000 0.562500000000 -op_back.tga 0.890625000000 0.539062500000 0.914062500000 0.562500000000 -op_over_break.tga 0.914062500000 0.539062500000 0.937500000000 0.562500000000 -op_over_less.tga 0.937500000000 0.539062500000 0.960937500000 0.562500000000 -op_over_more.tga 0.468750000000 0.546875000000 0.492187500000 0.570312500000 -ico_metabolism.tga 0.492187500000 0.546875000000 0.515625000000 0.570312500000 -pa_back.tga 0.515625000000 0.546875000000 0.539062500000 0.570312500000 -ico_mezz.tga 0.539062500000 0.546875000000 0.562500000000 0.570312500000 -ico_misfortune.tga 0.562500000000 0.546875000000 0.585937500000 0.570312500000 -cp_over_opening_2.tga 0.585937500000 0.546875000000 0.609375000000 0.570312500000 -pa_over_break.tga 0.609375000000 0.546875000000 0.632812500000 0.570312500000 -pa_over_less.tga 0.632812500000 0.546875000000 0.656250000000 0.570312500000 -pa_over_more.tga 0.656250000000 0.546875000000 0.679687500000 0.570312500000 -bg_downloader.tga 0.679687500000 0.546875000000 0.703125000000 0.570312500000 -BK_zorai_brick.tga 0.703125000000 0.546875000000 0.726562500000 0.570312500000 -ef_back.tga 0.726562500000 0.546875000000 0.750000000000 0.570312500000 -ef_over_break.tga 0.750000000000 0.546875000000 0.773437500000 0.570312500000 -ef_over_less.tga 0.773437500000 0.546875000000 0.796875000000 0.570312500000 -ef_over_more.tga 0.796875000000 0.546875000000 0.820312500000 0.570312500000 -brick_default.tga 0.820312500000 0.546875000000 0.843750000000 0.570312500000 -building_state_24x24.tga 0.843750000000 0.546875000000 0.867187500000 0.570312500000 -cb_main_nue.tga 0.960937500000 0.546875000000 0.984375000000 0.570312500000 -BK_matis_brick.tga 0.000000000000 0.554687500000 0.023437500000 0.578125000000 -ch_back.tga 0.023437500000 0.554687500000 0.046875000000 0.578125000000 -ico_move.tga 0.046875000000 0.554687500000 0.070312500000 0.578125000000 -ico_multiple_spots.tga 0.070312500000 0.554687500000 0.093750000000 0.578125000000 -ico_multi_fight.tga 0.093750000000 0.554687500000 0.117187500000 0.578125000000 -BK_generic_brick.tga 0.117187500000 0.554687500000 0.140625000000 0.578125000000 -ico_opening_hit.tga 0.140625000000 0.554687500000 0.164062500000 0.578125000000 -ico_over_autumn.tga 0.164062500000 0.554687500000 0.187500000000 0.578125000000 -ico_over_degenerated.tga 0.187500000000 0.554687500000 0.210937500000 0.578125000000 -ico_over_fauna.tga 0.210937500000 0.554687500000 0.234375000000 0.578125000000 -ico_over_flora.tga 0.234375000000 0.554687500000 0.257812500000 0.578125000000 -ico_over_hit_arms.tga 0.257812500000 0.554687500000 0.281250000000 0.578125000000 -ico_over_hit_chest.tga 0.281250000000 0.554687500000 0.304687500000 0.578125000000 -ico_over_hit_feet.tga 0.304687500000 0.554687500000 0.328125000000 0.578125000000 -ico_over_hit_feet_hands.tga 0.328125000000 0.554687500000 0.351562500000 0.578125000000 -ico_over_hit_feet_head.tga 0.351562500000 0.554687500000 0.375000000000 0.578125000000 -ico_over_hit_feet_x2.tga 0.375000000000 0.554687500000 0.398437500000 0.578125000000 -ico_over_hit_feint_x3.tga 0.398437500000 0.554687500000 0.421875000000 0.578125000000 -ico_over_hit_hands.tga 0.421875000000 0.554687500000 0.445312500000 0.578125000000 -ico_over_hit_hands_chest.tga 0.445312500000 0.554687500000 0.468750000000 0.578125000000 -ico_over_hit_hands_head.tga 0.867187500000 0.562500000000 0.890625000000 0.585937500000 -ico_over_hit_head.tga 0.890625000000 0.562500000000 0.914062500000 0.585937500000 -ico_over_hit_head_x3.tga 0.914062500000 0.562500000000 0.937500000000 0.585937500000 -ico_over_hit_legs.tga 0.937500000000 0.562500000000 0.960937500000 0.585937500000 -ico_over_homin.tga 0.468750000000 0.570312500000 0.492187500000 0.593750000000 -ico_over_kitin.tga 0.492187500000 0.570312500000 0.515625000000 0.593750000000 -ico_over_magic.tga 0.515625000000 0.570312500000 0.539062500000 0.593750000000 -ico_over_melee.tga 0.539062500000 0.570312500000 0.562500000000 0.593750000000 -ico_over_racial.tga 0.562500000000 0.570312500000 0.585937500000 0.593750000000 -ico_over_range.tga 0.585937500000 0.570312500000 0.609375000000 0.593750000000 -ico_over_special.tga 0.609375000000 0.570312500000 0.632812500000 0.593750000000 -ico_over_spring.tga 0.632812500000 0.570312500000 0.656250000000 0.593750000000 -ico_over_summer.tga 0.656250000000 0.570312500000 0.679687500000 0.593750000000 -ico_over_winter.tga 0.679687500000 0.570312500000 0.703125000000 0.593750000000 -ico_parry.tga 0.703125000000 0.570312500000 0.726562500000 0.593750000000 -ico_piercing.tga 0.726562500000 0.570312500000 0.750000000000 0.593750000000 -ico_pointe.tga 0.750000000000 0.570312500000 0.773437500000 0.593750000000 -ico_poison.tga 0.773437500000 0.570312500000 0.796875000000 0.593750000000 -ico_power.tga 0.796875000000 0.570312500000 0.820312500000 0.593750000000 -ico_preservation.tga 0.820312500000 0.570312500000 0.843750000000 0.593750000000 -ico_primal.tga 0.843750000000 0.570312500000 0.867187500000 0.593750000000 -ico_prime_roots.tga 0.960937500000 0.570312500000 0.984375000000 0.593750000000 -ico_private.tga 0.000000000000 0.578125000000 0.023437500000 0.601562500000 -ico_prospecting.tga 0.023437500000 0.578125000000 0.046875000000 0.601562500000 -ico_quality.tga 0.046875000000 0.578125000000 0.070312500000 0.601562500000 -bk_aura.tga 0.070312500000 0.578125000000 0.093750000000 0.601562500000 -ico_range.tga 0.093750000000 0.578125000000 0.117187500000 0.601562500000 -ico_range_action_buff.tga 0.117187500000 0.578125000000 0.140625000000 0.601562500000 -ico_range_target_buff.tga 0.140625000000 0.578125000000 0.164062500000 0.601562500000 -ico_ricochet.tga 0.164062500000 0.578125000000 0.187500000000 0.601562500000 -ico_root.tga 0.187500000000 0.578125000000 0.210937500000 0.601562500000 -ico_rot.tga 0.210937500000 0.578125000000 0.234375000000 0.601562500000 -ico_safe.tga 0.234375000000 0.578125000000 0.257812500000 0.601562500000 -ico_sap.tga 0.257812500000 0.578125000000 0.281250000000 0.601562500000 -ico_self_damage.tga 0.281250000000 0.578125000000 0.304687500000 0.601562500000 -ico_shaft.tga 0.304687500000 0.578125000000 0.328125000000 0.601562500000 -ico_shielding.tga 0.328125000000 0.578125000000 0.351562500000 0.601562500000 -ico_shield_buff.tga 0.351562500000 0.578125000000 0.375000000000 0.601562500000 -ico_shield_up.tga 0.375000000000 0.578125000000 0.398437500000 0.601562500000 -ico_shockwave.tga 0.398437500000 0.578125000000 0.421875000000 0.601562500000 -ico_sickness.tga 0.421875000000 0.578125000000 0.445312500000 0.601562500000 -ico_slashing.tga 0.445312500000 0.578125000000 0.468750000000 0.601562500000 -ico_slow.tga 0.867187500000 0.585937500000 0.890625000000 0.609375000000 -ico_soft_spot.tga 0.890625000000 0.585937500000 0.914062500000 0.609375000000 -ico_source_time.tga 0.914062500000 0.585937500000 0.937500000000 0.609375000000 -ico_speed.tga 0.937500000000 0.585937500000 0.960937500000 0.609375000000 -ico_speeding_up.tga 0.468750000000 0.593750000000 0.492187500000 0.617187500000 -ico_spell_break.tga 0.492187500000 0.593750000000 0.515625000000 0.617187500000 -fo_back.tga 0.515625000000 0.593750000000 0.539062500000 0.617187500000 -ico_spray.tga 0.539062500000 0.593750000000 0.562500000000 0.617187500000 -ico_spying.tga 0.562500000000 0.593750000000 0.585937500000 0.617187500000 -ico_stamina.tga 0.585937500000 0.593750000000 0.609375000000 0.617187500000 -ico_strength.tga 0.609375000000 0.593750000000 0.632812500000 0.617187500000 -ico_stuffing.tga 0.632812500000 0.593750000000 0.656250000000 0.617187500000 -ico_stunn.tga 0.656250000000 0.593750000000 0.679687500000 0.617187500000 -fo_over.tga 0.679687500000 0.593750000000 0.703125000000 0.617187500000 -fp_ammo.tga 0.703125000000 0.593750000000 0.726562500000 0.617187500000 -fp_armor.tga 0.726562500000 0.593750000000 0.750000000000 0.617187500000 -fp_building.tga 0.750000000000 0.593750000000 0.773437500000 0.617187500000 -fp_jewel.tga 0.773437500000 0.593750000000 0.796875000000 0.617187500000 -fp_melee.tga 0.796875000000 0.593750000000 0.820312500000 0.617187500000 -tb_action_attack.tga 0.820312500000 0.593750000000 0.843750000000 0.617187500000 -tb_action_config.tga 0.843750000000 0.593750000000 0.867187500000 0.617187500000 -tb_action_disband.tga 0.960937500000 0.593750000000 0.984375000000 0.617187500000 -tb_action_disengage.tga 0.000000000000 0.601562500000 0.023437500000 0.625000000000 -tb_action_extract.tga 0.023437500000 0.601562500000 0.046875000000 0.625000000000 -tb_action_invite.tga 0.046875000000 0.601562500000 0.070312500000 0.625000000000 -tb_action_kick.tga 0.070312500000 0.601562500000 0.093750000000 0.625000000000 -tb_action_move.tga 0.093750000000 0.601562500000 0.117187500000 0.625000000000 -tb_action_run.tga 0.117187500000 0.601562500000 0.140625000000 0.625000000000 -tb_action_sit.tga 0.140625000000 0.601562500000 0.164062500000 0.625000000000 -tb_action_stand.tga 0.164062500000 0.601562500000 0.187500000000 0.625000000000 -tb_action_stop.tga 0.187500000000 0.601562500000 0.210937500000 0.625000000000 -tb_action_talk.tga 0.210937500000 0.601562500000 0.234375000000 0.625000000000 -tb_action_walk.tga 0.234375000000 0.601562500000 0.257812500000 0.625000000000 -tb_animals.tga 0.257812500000 0.601562500000 0.281250000000 0.625000000000 -tb_config.tga 0.281250000000 0.601562500000 0.304687500000 0.625000000000 -tb_connection.tga 0.304687500000 0.601562500000 0.328125000000 0.625000000000 -tb_contacts.tga 0.328125000000 0.601562500000 0.351562500000 0.625000000000 -tb_desk_1.tga 0.351562500000 0.601562500000 0.375000000000 0.625000000000 -tb_desk_2.tga 0.375000000000 0.601562500000 0.398437500000 0.625000000000 -tb_desk_3.tga 0.398437500000 0.601562500000 0.421875000000 0.625000000000 -tb_desk_4.tga 0.421875000000 0.601562500000 0.445312500000 0.625000000000 -tb_faction.tga 0.445312500000 0.601562500000 0.468750000000 0.625000000000 -tb_forum.tga 0.867187500000 0.609375000000 0.890625000000 0.632812500000 -tb_guild.tga 0.890625000000 0.609375000000 0.914062500000 0.632812500000 -tb_keys.tga 0.914062500000 0.609375000000 0.937500000000 0.632812500000 -tb_macros.tga 0.937500000000 0.609375000000 0.960937500000 0.632812500000 -tb_mail.tga 0.468750000000 0.617187500000 0.492187500000 0.640625000000 -tb_mode_dodge.tga 0.492187500000 0.617187500000 0.515625000000 0.640625000000 -tb_mode_parry.tga 0.515625000000 0.617187500000 0.539062500000 0.640625000000 -tb_over.tga 0.539062500000 0.617187500000 0.562500000000 0.640625000000 -tb_support.tga 0.562500000000 0.617187500000 0.585937500000 0.640625000000 -tb_team.tga 0.585937500000 0.617187500000 0.609375000000 0.640625000000 -tb_windows.tga 0.609375000000 0.617187500000 0.632812500000 0.640625000000 -fp_over.tga 0.632812500000 0.617187500000 0.656250000000 0.640625000000 -fp_range.tga 0.656250000000 0.617187500000 0.679687500000 0.640625000000 -fp_shield.tga 0.679687500000 0.617187500000 0.703125000000 0.640625000000 -fp_tools.tga 0.703125000000 0.617187500000 0.726562500000 0.640625000000 -bk_conso.tga 0.726562500000 0.617187500000 0.750000000000 0.640625000000 -ico_taunt.tga 0.750000000000 0.617187500000 0.773437500000 0.640625000000 -ico_time.tga 0.773437500000 0.617187500000 0.796875000000 0.640625000000 -ico_time_bonus.tga 0.796875000000 0.617187500000 0.820312500000 0.640625000000 -ico_absorb_damage.tga 0.820312500000 0.617187500000 0.843750000000 0.640625000000 -ico_trigger.tga 0.843750000000 0.617187500000 0.867187500000 0.640625000000 -ico_umbrella.tga 0.960937500000 0.617187500000 0.984375000000 0.640625000000 -ico_use_enchantement.tga 0.000000000000 0.625000000000 0.023437500000 0.648437500000 -ico_vampire.tga 0.023437500000 0.625000000000 0.046875000000 0.648437500000 -ico_visibility.tga 0.046875000000 0.625000000000 0.070312500000 0.648437500000 -ico_war_cry.tga 0.070312500000 0.625000000000 0.093750000000 0.648437500000 -ico_weight.tga 0.093750000000 0.625000000000 0.117187500000 0.648437500000 -ico_wellbalanced.tga 0.117187500000 0.625000000000 0.140625000000 0.648437500000 -ico_will.tga 0.140625000000 0.625000000000 0.164062500000 0.648437500000 -ico_windding.tga 0.164062500000 0.625000000000 0.187500000000 0.648437500000 -ico_wisdom.tga 0.187500000000 0.625000000000 0.210937500000 0.648437500000 -ico_accurate.tga 0.210937500000 0.625000000000 0.234375000000 0.648437500000 -ico_acid.tga 0.234375000000 0.625000000000 0.257812500000 0.648437500000 -us_back_0.tga 0.257812500000 0.625000000000 0.281250000000 0.648437500000 -us_back_1.tga 0.281250000000 0.625000000000 0.304687500000 0.648437500000 -us_back_2.tga 0.304687500000 0.625000000000 0.328125000000 0.648437500000 -us_back_3.tga 0.328125000000 0.625000000000 0.351562500000 0.648437500000 -us_back_4.tga 0.351562500000 0.625000000000 0.375000000000 0.648437500000 -us_back_5.tga 0.375000000000 0.625000000000 0.398437500000 0.648437500000 -us_back_6.tga 0.398437500000 0.625000000000 0.421875000000 0.648437500000 -us_back_7.tga 0.421875000000 0.625000000000 0.445312500000 0.648437500000 -us_back_8.tga 0.445312500000 0.625000000000 0.468750000000 0.648437500000 -us_back_9.tga 0.867187500000 0.632812500000 0.890625000000 0.656250000000 -us_ico_0.tga 0.890625000000 0.632812500000 0.914062500000 0.656250000000 -us_ico_1.tga 0.914062500000 0.632812500000 0.937500000000 0.656250000000 -us_ico_2.tga 0.937500000000 0.632812500000 0.960937500000 0.656250000000 -us_ico_3.tga 0.468750000000 0.640625000000 0.492187500000 0.664062500000 -us_ico_4.tga 0.492187500000 0.640625000000 0.515625000000 0.664062500000 -us_ico_5.tga 0.515625000000 0.640625000000 0.539062500000 0.664062500000 -us_ico_6.tga 0.539062500000 0.640625000000 0.562500000000 0.664062500000 -us_ico_7.tga 0.562500000000 0.640625000000 0.585937500000 0.664062500000 -us_ico_8.tga 0.585937500000 0.640625000000 0.609375000000 0.664062500000 -us_ico_9.tga 0.609375000000 0.640625000000 0.632812500000 0.664062500000 -us_over_0.tga 0.632812500000 0.640625000000 0.656250000000 0.664062500000 -us_over_1.tga 0.656250000000 0.640625000000 0.679687500000 0.664062500000 -us_over_2.tga 0.679687500000 0.640625000000 0.703125000000 0.664062500000 -us_over_3.tga 0.703125000000 0.640625000000 0.726562500000 0.664062500000 -us_over_4.tga 0.726562500000 0.640625000000 0.750000000000 0.664062500000 -ico_aim.tga 0.750000000000 0.640625000000 0.773437500000 0.664062500000 -ico_aim_bird_wings.tga 0.773437500000 0.640625000000 0.796875000000 0.664062500000 -ico_aim_flying_kitin_abdomen.tga 0.796875000000 0.640625000000 0.820312500000 0.664062500000 -ico_aim_homin_arms.tga 0.820312500000 0.640625000000 0.843750000000 0.664062500000 -ico_aim_homin_chest.tga 0.843750000000 0.640625000000 0.867187500000 0.664062500000 -mf_back.tga 0.960937500000 0.640625000000 0.984375000000 0.664062500000 -mf_over.tga 0.000000000000 0.648437500000 0.023437500000 0.671875000000 -W_slot_shortcut_id0.tga 0.023437500000 0.648437500000 0.046875000000 0.671875000000 -W_slot_shortcut_id1.tga 0.046875000000 0.648437500000 0.070312500000 0.671875000000 -W_slot_shortcut_id2.tga 0.070312500000 0.648437500000 0.093750000000 0.671875000000 -W_slot_shortcut_id3.tga 0.093750000000 0.648437500000 0.117187500000 0.671875000000 -W_slot_shortcut_id4.tga 0.117187500000 0.648437500000 0.140625000000 0.671875000000 -W_slot_shortcut_id5.tga 0.140625000000 0.648437500000 0.164062500000 0.671875000000 -W_slot_shortcut_id6.tga 0.164062500000 0.648437500000 0.187500000000 0.671875000000 -W_slot_shortcut_id7.tga 0.187500000000 0.648437500000 0.210937500000 0.671875000000 -W_slot_shortcut_id8.tga 0.210937500000 0.648437500000 0.234375000000 0.671875000000 -W_slot_shortcut_id9.tga 0.234375000000 0.648437500000 0.257812500000 0.671875000000 -w_slot_shortcut_shift_id0.tga 0.257812500000 0.648437500000 0.281250000000 0.671875000000 -w_slot_shortcut_shift_id1.tga 0.281250000000 0.648437500000 0.304687500000 0.671875000000 -w_slot_shortcut_shift_id2.tga 0.304687500000 0.648437500000 0.328125000000 0.671875000000 -w_slot_shortcut_shift_id3.tga 0.328125000000 0.648437500000 0.351562500000 0.671875000000 -w_slot_shortcut_shift_id4.tga 0.351562500000 0.648437500000 0.375000000000 0.671875000000 -w_slot_shortcut_shift_id5.tga 0.375000000000 0.648437500000 0.398437500000 0.671875000000 -w_slot_shortcut_shift_id6.tga 0.398437500000 0.648437500000 0.421875000000 0.671875000000 -w_slot_shortcut_shift_id7.tga 0.421875000000 0.648437500000 0.445312500000 0.671875000000 -w_slot_shortcut_shift_id8.tga 0.445312500000 0.648437500000 0.468750000000 0.671875000000 -w_slot_shortcut_shift_id9.tga 0.867187500000 0.656250000000 0.890625000000 0.679687500000 -ico_source_knowledge.tga 0.890625000000 0.656250000000 0.912109375000 0.679687500000 +ico_armor_heavy.tga 0.687500000000 0.468750000000 0.710937500000 0.492187500000 +ico_armor_kitin.tga 0.710937500000 0.468750000000 0.734375000000 0.492187500000 +ico_armor_light.tga 0.734375000000 0.468750000000 0.757812500000 0.492187500000 +ico_armor_medium.tga 0.757812500000 0.468750000000 0.781250000000 0.492187500000 +ico_armor_penalty.tga 0.781250000000 0.468750000000 0.804687500000 0.492187500000 +ico_armor_shell.tga 0.804687500000 0.468750000000 0.828125000000 0.492187500000 +ico_atys.tga 0.828125000000 0.468750000000 0.851562500000 0.492187500000 +ico_atysian.tga 0.851562500000 0.468750000000 0.875000000000 0.492187500000 +ico_balance_hp.tga 0.875000000000 0.468750000000 0.898437500000 0.492187500000 +ico_barrel.tga 0.898437500000 0.468750000000 0.921875000000 0.492187500000 +ico_bash.tga 0.921875000000 0.468750000000 0.945312500000 0.492187500000 +ico_berserk.tga 0.945312500000 0.468750000000 0.968750000000 0.492187500000 +ico_blade.tga 0.968750000000 0.476562500000 0.992187500000 0.500000000000 +ico_bleeding.tga 0.656250000000 0.492187500000 0.679687500000 0.515625000000 +ico_blind.tga 0.679687500000 0.492187500000 0.703125000000 0.515625000000 +ico_blunt.tga 0.703125000000 0.492187500000 0.726562500000 0.515625000000 +ico_bomb.tga 0.726562500000 0.492187500000 0.750000000000 0.515625000000 +cb_main_nue.tga 0.750000000000 0.492187500000 0.773437500000 0.515625000000 +ico_celestial.tga 0.773437500000 0.492187500000 0.796875000000 0.515625000000 +ico_circular_attack.tga 0.796875000000 0.492187500000 0.820312500000 0.515625000000 +ico_clothes.tga 0.820312500000 0.492187500000 0.843750000000 0.515625000000 +ico_cold.tga 0.843750000000 0.492187500000 0.867187500000 0.515625000000 +ico_concentration.tga 0.867187500000 0.492187500000 0.890625000000 0.515625000000 +BK_matis_brick.tga 0.890625000000 0.492187500000 0.914062500000 0.515625000000 +ico_constitution.tga 0.914062500000 0.492187500000 0.937500000000 0.515625000000 +ico_counterweight.tga 0.937500000000 0.492187500000 0.960937500000 0.515625000000 +ico_craft_buff.tga 0.468750000000 0.500000000000 0.492187500000 0.523437500000 +ico_create_sapload.tga 0.492187500000 0.500000000000 0.515625000000 0.523437500000 +ico_curse.tga 0.515625000000 0.500000000000 0.539062500000 0.523437500000 +ico_debuff.tga 0.539062500000 0.500000000000 0.562500000000 0.523437500000 +ico_debuff_resist.tga 0.562500000000 0.500000000000 0.585937500000 0.523437500000 +ico_debuff_skill.tga 0.585937500000 0.500000000000 0.609375000000 0.523437500000 +ico_desert.tga 0.609375000000 0.500000000000 0.632812500000 0.523437500000 +ico_dexterity.tga 0.632812500000 0.500000000000 0.656250000000 0.523437500000 +ico_disarm.tga 0.960937500000 0.500000000000 0.984375000000 0.523437500000 +ico_dodge.tga 0.000000000000 0.507812500000 0.023437500000 0.531250000000 +ico_dot.tga 0.023437500000 0.507812500000 0.046875000000 0.531250000000 +ico_durability.tga 0.046875000000 0.507812500000 0.070312500000 0.531250000000 +ico_electric.tga 0.070312500000 0.507812500000 0.093750000000 0.531250000000 +ico_explosif.tga 0.093750000000 0.507812500000 0.117187500000 0.531250000000 +ico_extracting.tga 0.117187500000 0.507812500000 0.140625000000 0.531250000000 +ico_fear.tga 0.140625000000 0.507812500000 0.164062500000 0.531250000000 +ico_feint.tga 0.164062500000 0.507812500000 0.187500000000 0.531250000000 +ico_fire.tga 0.187500000000 0.507812500000 0.210937500000 0.531250000000 +ico_firing_pin.tga 0.210937500000 0.507812500000 0.234375000000 0.531250000000 +ch_back.tga 0.234375000000 0.507812500000 0.257812500000 0.531250000000 +BK_generic_brick.tga 0.257812500000 0.507812500000 0.281250000000 0.531250000000 +mp_over_link.tga 0.281250000000 0.507812500000 0.304687500000 0.531250000000 +bk_aura.tga 0.304687500000 0.507812500000 0.328125000000 0.531250000000 +bk_conso.tga 0.328125000000 0.507812500000 0.351562500000 0.531250000000 +bk_outpost_brick.tga 0.351562500000 0.507812500000 0.375000000000 0.531250000000 +bk_power.tga 0.375000000000 0.507812500000 0.398437500000 0.531250000000 +ico_focus.tga 0.398437500000 0.507812500000 0.421875000000 0.531250000000 +ico_forage_buff.tga 0.421875000000 0.507812500000 0.445312500000 0.531250000000 +ico_forbid_item.tga 0.445312500000 0.507812500000 0.468750000000 0.531250000000 +ico_forest.tga 0.656250000000 0.515625000000 0.679687500000 0.539062500000 +2h_over.tga 0.679687500000 0.515625000000 0.703125000000 0.539062500000 +ico_gardening.tga 0.703125000000 0.515625000000 0.726562500000 0.539062500000 +ico_gentle.tga 0.726562500000 0.515625000000 0.750000000000 0.539062500000 +ico_goo.tga 0.750000000000 0.515625000000 0.773437500000 0.539062500000 +ico_gripp.tga 0.773437500000 0.515625000000 0.796875000000 0.539062500000 +1h_over.tga 0.796875000000 0.515625000000 0.820312500000 0.539062500000 +BK_fyros_brick.tga 0.820312500000 0.515625000000 0.843750000000 0.539062500000 +ico_hammer.tga 0.843750000000 0.515625000000 0.867187500000 0.539062500000 +ico_harmful.tga 0.867187500000 0.515625000000 0.890625000000 0.539062500000 +ico_hatred.tga 0.890625000000 0.515625000000 0.914062500000 0.539062500000 +ico_heal.tga 0.914062500000 0.515625000000 0.937500000000 0.539062500000 +ico_hit_rate.tga 0.937500000000 0.515625000000 0.960937500000 0.539062500000 +ico_incapacity.tga 0.468750000000 0.523437500000 0.492187500000 0.546875000000 +ico_intelligence.tga 0.492187500000 0.523437500000 0.515625000000 0.546875000000 +ico_interrupt.tga 0.515625000000 0.523437500000 0.539062500000 0.546875000000 +ico_invulnerability.tga 0.539062500000 0.523437500000 0.562500000000 0.546875000000 +ico_jewel_stone.tga 0.562500000000 0.523437500000 0.585937500000 0.546875000000 +ico_jewel_stone_support.tga 0.585937500000 0.523437500000 0.609375000000 0.546875000000 +ico_jungle.tga 0.609375000000 0.523437500000 0.632812500000 0.546875000000 +ico_lacustre.tga 0.632812500000 0.523437500000 0.656250000000 0.546875000000 +ico_landmark_bonus.tga 0.960937500000 0.523437500000 0.984375000000 0.546875000000 +ico_level.tga 0.000000000000 0.531250000000 0.023437500000 0.554687500000 +ico_lining.tga 0.023437500000 0.531250000000 0.046875000000 0.554687500000 +ico_location.tga 0.046875000000 0.531250000000 0.070312500000 0.554687500000 +ico_madness.tga 0.070312500000 0.531250000000 0.093750000000 0.554687500000 +ico_magic.tga 0.093750000000 0.531250000000 0.117187500000 0.554687500000 +ico_magic_action_buff.tga 0.117187500000 0.531250000000 0.140625000000 0.554687500000 +ico_magic_focus.tga 0.140625000000 0.531250000000 0.164062500000 0.554687500000 +ico_magic_target_buff.tga 0.164062500000 0.531250000000 0.187500000000 0.554687500000 +ico_melee_action_buff.tga 0.187500000000 0.531250000000 0.210937500000 0.554687500000 +ico_melee_target_buff.tga 0.210937500000 0.531250000000 0.234375000000 0.554687500000 +ico_mental.tga 0.234375000000 0.531250000000 0.257812500000 0.554687500000 +no_action.tga 0.257812500000 0.531250000000 0.281250000000 0.554687500000 +op_back.tga 0.281250000000 0.531250000000 0.304687500000 0.554687500000 +op_over_break.tga 0.304687500000 0.531250000000 0.328125000000 0.554687500000 +op_over_less.tga 0.328125000000 0.531250000000 0.351562500000 0.554687500000 +op_over_more.tga 0.351562500000 0.531250000000 0.375000000000 0.554687500000 +ico_metabolism.tga 0.375000000000 0.531250000000 0.398437500000 0.554687500000 +pa_back.tga 0.398437500000 0.531250000000 0.421875000000 0.554687500000 +ico_mezz.tga 0.421875000000 0.531250000000 0.445312500000 0.554687500000 +ico_misfortune.tga 0.445312500000 0.531250000000 0.468750000000 0.554687500000 +BK_magie_noire_brick.tga 0.656250000000 0.539062500000 0.679687500000 0.562500000000 +pa_over_break.tga 0.679687500000 0.539062500000 0.703125000000 0.562500000000 +pa_over_less.tga 0.703125000000 0.539062500000 0.726562500000 0.562500000000 +pa_over_more.tga 0.726562500000 0.539062500000 0.750000000000 0.562500000000 +BK_tryker_brick.tga 0.750000000000 0.539062500000 0.773437500000 0.562500000000 +cp_back.tga 0.773437500000 0.539062500000 0.796875000000 0.562500000000 +cp_over_break.tga 0.796875000000 0.539062500000 0.820312500000 0.562500000000 +pvp_ally_0.tga 0.820312500000 0.539062500000 0.843750000000 0.562500000000 +pvp_ally_1.tga 0.843750000000 0.539062500000 0.867187500000 0.562500000000 +pvp_ally_2.tga 0.867187500000 0.539062500000 0.890625000000 0.562500000000 +pvp_ally_3.tga 0.890625000000 0.539062500000 0.914062500000 0.562500000000 +pvp_ally_4.tga 0.914062500000 0.539062500000 0.937500000000 0.562500000000 +pvp_ally_6.tga 0.937500000000 0.539062500000 0.960937500000 0.562500000000 +pvp_ally_primas.tga 0.468750000000 0.546875000000 0.492187500000 0.570312500000 +pvp_ally_ranger.tga 0.492187500000 0.546875000000 0.515625000000 0.570312500000 +pvp_enemy_0.tga 0.515625000000 0.546875000000 0.539062500000 0.570312500000 +pvp_enemy_1.tga 0.539062500000 0.546875000000 0.562500000000 0.570312500000 +pvp_enemy_2.tga 0.562500000000 0.546875000000 0.585937500000 0.570312500000 +pvp_enemy_3.tga 0.585937500000 0.546875000000 0.609375000000 0.570312500000 +pvp_enemy_4.tga 0.609375000000 0.546875000000 0.632812500000 0.570312500000 +pvp_enemy_6.tga 0.632812500000 0.546875000000 0.656250000000 0.570312500000 +pvp_enemy_marauder.tga 0.960937500000 0.546875000000 0.984375000000 0.570312500000 +pvp_enemy_trytonist.tga 0.000000000000 0.554687500000 0.023437500000 0.578125000000 +cp_over_less.tga 0.023437500000 0.554687500000 0.046875000000 0.578125000000 +cp_over_more.tga 0.046875000000 0.554687500000 0.070312500000 0.578125000000 +cp_over_opening.tga 0.070312500000 0.554687500000 0.093750000000 0.578125000000 +cp_over_opening_2.tga 0.093750000000 0.554687500000 0.117187500000 0.578125000000 +bg_downloader.tga 0.117187500000 0.554687500000 0.140625000000 0.578125000000 +BK_zorai_brick.tga 0.140625000000 0.554687500000 0.164062500000 0.578125000000 +ef_back.tga 0.164062500000 0.554687500000 0.187500000000 0.578125000000 +ef_over_break.tga 0.187500000000 0.554687500000 0.210937500000 0.578125000000 +ico_move.tga 0.210937500000 0.554687500000 0.234375000000 0.578125000000 +ico_multiple_spots.tga 0.234375000000 0.554687500000 0.257812500000 0.578125000000 +ico_multi_fight.tga 0.257812500000 0.554687500000 0.281250000000 0.578125000000 +ef_over_less.tga 0.281250000000 0.554687500000 0.304687500000 0.578125000000 +ico_opening_hit.tga 0.304687500000 0.554687500000 0.328125000000 0.578125000000 +ico_over_autumn.tga 0.328125000000 0.554687500000 0.351562500000 0.578125000000 +ico_over_degenerated.tga 0.351562500000 0.554687500000 0.375000000000 0.578125000000 +ico_over_fauna.tga 0.375000000000 0.554687500000 0.398437500000 0.578125000000 +ico_over_flora.tga 0.398437500000 0.554687500000 0.421875000000 0.578125000000 +ico_over_hit_arms.tga 0.421875000000 0.554687500000 0.445312500000 0.578125000000 +ico_over_hit_chest.tga 0.445312500000 0.554687500000 0.468750000000 0.578125000000 +ico_over_hit_feet.tga 0.656250000000 0.562500000000 0.679687500000 0.585937500000 +ico_over_hit_feet_hands.tga 0.679687500000 0.562500000000 0.703125000000 0.585937500000 +ico_over_hit_feet_head.tga 0.703125000000 0.562500000000 0.726562500000 0.585937500000 +ico_over_hit_feet_x2.tga 0.726562500000 0.562500000000 0.750000000000 0.585937500000 +ico_over_hit_feint_x3.tga 0.750000000000 0.562500000000 0.773437500000 0.585937500000 +ico_over_hit_hands.tga 0.773437500000 0.562500000000 0.796875000000 0.585937500000 +ico_over_hit_hands_chest.tga 0.796875000000 0.562500000000 0.820312500000 0.585937500000 +ico_over_hit_hands_head.tga 0.820312500000 0.562500000000 0.843750000000 0.585937500000 +ico_over_hit_head.tga 0.843750000000 0.562500000000 0.867187500000 0.585937500000 +ico_over_hit_head_x3.tga 0.867187500000 0.562500000000 0.890625000000 0.585937500000 +ico_over_hit_legs.tga 0.890625000000 0.562500000000 0.914062500000 0.585937500000 +ico_over_homin.tga 0.914062500000 0.562500000000 0.937500000000 0.585937500000 +ico_over_kitin.tga 0.937500000000 0.562500000000 0.960937500000 0.585937500000 +ico_over_magic.tga 0.468750000000 0.570312500000 0.492187500000 0.593750000000 +ico_over_melee.tga 0.492187500000 0.570312500000 0.515625000000 0.593750000000 +ico_over_racial.tga 0.515625000000 0.570312500000 0.539062500000 0.593750000000 +ico_over_range.tga 0.539062500000 0.570312500000 0.562500000000 0.593750000000 +ico_over_special.tga 0.562500000000 0.570312500000 0.585937500000 0.593750000000 +ico_over_spring.tga 0.585937500000 0.570312500000 0.609375000000 0.593750000000 +ico_over_summer.tga 0.609375000000 0.570312500000 0.632812500000 0.593750000000 +ico_over_winter.tga 0.632812500000 0.570312500000 0.656250000000 0.593750000000 +ico_parry.tga 0.960937500000 0.570312500000 0.984375000000 0.593750000000 +ico_piercing.tga 0.000000000000 0.578125000000 0.023437500000 0.601562500000 +ico_pointe.tga 0.023437500000 0.578125000000 0.046875000000 0.601562500000 +ico_poison.tga 0.046875000000 0.578125000000 0.070312500000 0.601562500000 +ico_power.tga 0.070312500000 0.578125000000 0.093750000000 0.601562500000 +ico_preservation.tga 0.093750000000 0.578125000000 0.117187500000 0.601562500000 +ico_primal.tga 0.117187500000 0.578125000000 0.140625000000 0.601562500000 +ico_prime_roots.tga 0.140625000000 0.578125000000 0.164062500000 0.601562500000 +ico_private.tga 0.164062500000 0.578125000000 0.187500000000 0.601562500000 +ico_prospecting.tga 0.187500000000 0.578125000000 0.210937500000 0.601562500000 +ico_quality.tga 0.210937500000 0.578125000000 0.234375000000 0.601562500000 +ef_over_more.tga 0.234375000000 0.578125000000 0.257812500000 0.601562500000 +ico_range.tga 0.257812500000 0.578125000000 0.281250000000 0.601562500000 +ico_range_action_buff.tga 0.281250000000 0.578125000000 0.304687500000 0.601562500000 +ico_range_target_buff.tga 0.304687500000 0.578125000000 0.328125000000 0.601562500000 +ico_ricochet.tga 0.328125000000 0.578125000000 0.351562500000 0.601562500000 +ico_root.tga 0.351562500000 0.578125000000 0.375000000000 0.601562500000 +ico_rot.tga 0.375000000000 0.578125000000 0.398437500000 0.601562500000 +ico_safe.tga 0.398437500000 0.578125000000 0.421875000000 0.601562500000 +ico_sap.tga 0.421875000000 0.578125000000 0.445312500000 0.601562500000 +ico_self_damage.tga 0.445312500000 0.578125000000 0.468750000000 0.601562500000 +ico_shaft.tga 0.656250000000 0.585937500000 0.679687500000 0.609375000000 +ico_shielding.tga 0.679687500000 0.585937500000 0.703125000000 0.609375000000 +ico_shield_buff.tga 0.703125000000 0.585937500000 0.726562500000 0.609375000000 +ico_shield_up.tga 0.726562500000 0.585937500000 0.750000000000 0.609375000000 +ico_shockwave.tga 0.750000000000 0.585937500000 0.773437500000 0.609375000000 +ico_sickness.tga 0.773437500000 0.585937500000 0.796875000000 0.609375000000 +ico_slashing.tga 0.796875000000 0.585937500000 0.820312500000 0.609375000000 +ico_slow.tga 0.820312500000 0.585937500000 0.843750000000 0.609375000000 +ico_soft_spot.tga 0.843750000000 0.585937500000 0.867187500000 0.609375000000 +ico_source_time.tga 0.867187500000 0.585937500000 0.890625000000 0.609375000000 +ico_speed.tga 0.890625000000 0.585937500000 0.914062500000 0.609375000000 +ico_speeding_up.tga 0.914062500000 0.585937500000 0.937500000000 0.609375000000 +ico_spell_break.tga 0.937500000000 0.585937500000 0.960937500000 0.609375000000 +fo_back.tga 0.468750000000 0.593750000000 0.492187500000 0.617187500000 +ico_spray.tga 0.492187500000 0.593750000000 0.515625000000 0.617187500000 +ico_spying.tga 0.515625000000 0.593750000000 0.539062500000 0.617187500000 +ico_stamina.tga 0.539062500000 0.593750000000 0.562500000000 0.617187500000 +ico_strength.tga 0.562500000000 0.593750000000 0.585937500000 0.617187500000 +ico_stuffing.tga 0.585937500000 0.593750000000 0.609375000000 0.617187500000 +ico_stunn.tga 0.609375000000 0.593750000000 0.632812500000 0.617187500000 +fo_over.tga 0.632812500000 0.593750000000 0.656250000000 0.617187500000 +fp_ammo.tga 0.960937500000 0.593750000000 0.984375000000 0.617187500000 +fp_armor.tga 0.000000000000 0.601562500000 0.023437500000 0.625000000000 +fp_building.tga 0.023437500000 0.601562500000 0.046875000000 0.625000000000 +fp_jewel.tga 0.046875000000 0.601562500000 0.070312500000 0.625000000000 +fp_melee.tga 0.070312500000 0.601562500000 0.093750000000 0.625000000000 +tb_action_attack.tga 0.093750000000 0.601562500000 0.117187500000 0.625000000000 +tb_action_config.tga 0.117187500000 0.601562500000 0.140625000000 0.625000000000 +tb_action_disband.tga 0.140625000000 0.601562500000 0.164062500000 0.625000000000 +tb_action_disengage.tga 0.164062500000 0.601562500000 0.187500000000 0.625000000000 +tb_action_extract.tga 0.187500000000 0.601562500000 0.210937500000 0.625000000000 +tb_action_invite.tga 0.210937500000 0.601562500000 0.234375000000 0.625000000000 +tb_action_kick.tga 0.234375000000 0.601562500000 0.257812500000 0.625000000000 +tb_action_move.tga 0.257812500000 0.601562500000 0.281250000000 0.625000000000 +tb_action_run.tga 0.281250000000 0.601562500000 0.304687500000 0.625000000000 +tb_action_sit.tga 0.304687500000 0.601562500000 0.328125000000 0.625000000000 +tb_action_stand.tga 0.328125000000 0.601562500000 0.351562500000 0.625000000000 +tb_action_stop.tga 0.351562500000 0.601562500000 0.375000000000 0.625000000000 +tb_action_talk.tga 0.375000000000 0.601562500000 0.398437500000 0.625000000000 +tb_action_walk.tga 0.398437500000 0.601562500000 0.421875000000 0.625000000000 +tb_animals.tga 0.421875000000 0.601562500000 0.445312500000 0.625000000000 +tb_config.tga 0.445312500000 0.601562500000 0.468750000000 0.625000000000 +tb_connection.tga 0.656250000000 0.609375000000 0.679687500000 0.632812500000 +tb_contacts.tga 0.679687500000 0.609375000000 0.703125000000 0.632812500000 +tb_desk_1.tga 0.703125000000 0.609375000000 0.726562500000 0.632812500000 +tb_desk_2.tga 0.726562500000 0.609375000000 0.750000000000 0.632812500000 +tb_desk_3.tga 0.750000000000 0.609375000000 0.773437500000 0.632812500000 +tb_desk_4.tga 0.773437500000 0.609375000000 0.796875000000 0.632812500000 +tb_faction.tga 0.796875000000 0.609375000000 0.820312500000 0.632812500000 +tb_forum.tga 0.820312500000 0.609375000000 0.843750000000 0.632812500000 +tb_guild.tga 0.843750000000 0.609375000000 0.867187500000 0.632812500000 +tb_keys.tga 0.867187500000 0.609375000000 0.890625000000 0.632812500000 +tb_macros.tga 0.890625000000 0.609375000000 0.914062500000 0.632812500000 +tb_mail.tga 0.914062500000 0.609375000000 0.937500000000 0.632812500000 +tb_mode_dodge.tga 0.937500000000 0.609375000000 0.960937500000 0.632812500000 +tb_mode_parry.tga 0.468750000000 0.617187500000 0.492187500000 0.640625000000 +tb_over.tga 0.492187500000 0.617187500000 0.515625000000 0.640625000000 +tb_support.tga 0.515625000000 0.617187500000 0.539062500000 0.640625000000 +tb_team.tga 0.539062500000 0.617187500000 0.562500000000 0.640625000000 +tb_windows.tga 0.562500000000 0.617187500000 0.585937500000 0.640625000000 +fp_over.tga 0.585937500000 0.617187500000 0.609375000000 0.640625000000 +fp_range.tga 0.609375000000 0.617187500000 0.632812500000 0.640625000000 +fp_shield.tga 0.632812500000 0.617187500000 0.656250000000 0.640625000000 +fp_tools.tga 0.960937500000 0.617187500000 0.984375000000 0.640625000000 +brick_default.tga 0.000000000000 0.625000000000 0.023437500000 0.648437500000 +ico_taunt.tga 0.023437500000 0.625000000000 0.046875000000 0.648437500000 +ico_time.tga 0.046875000000 0.625000000000 0.070312500000 0.648437500000 +ico_time_bonus.tga 0.070312500000 0.625000000000 0.093750000000 0.648437500000 +ico_absorb_damage.tga 0.093750000000 0.625000000000 0.117187500000 0.648437500000 +ico_trigger.tga 0.117187500000 0.625000000000 0.140625000000 0.648437500000 +ico_umbrella.tga 0.140625000000 0.625000000000 0.164062500000 0.648437500000 +ico_use_enchantement.tga 0.164062500000 0.625000000000 0.187500000000 0.648437500000 +ico_vampire.tga 0.187500000000 0.625000000000 0.210937500000 0.648437500000 +ico_visibility.tga 0.210937500000 0.625000000000 0.234375000000 0.648437500000 +ico_war_cry.tga 0.234375000000 0.625000000000 0.257812500000 0.648437500000 +ico_weight.tga 0.257812500000 0.625000000000 0.281250000000 0.648437500000 +ico_wellbalanced.tga 0.281250000000 0.625000000000 0.304687500000 0.648437500000 +ico_will.tga 0.304687500000 0.625000000000 0.328125000000 0.648437500000 +ico_windding.tga 0.328125000000 0.625000000000 0.351562500000 0.648437500000 +ico_wisdom.tga 0.351562500000 0.625000000000 0.375000000000 0.648437500000 +ico_accurate.tga 0.375000000000 0.625000000000 0.398437500000 0.648437500000 +ico_acid.tga 0.398437500000 0.625000000000 0.421875000000 0.648437500000 +us_back_0.tga 0.421875000000 0.625000000000 0.445312500000 0.648437500000 +us_back_1.tga 0.445312500000 0.625000000000 0.468750000000 0.648437500000 +us_back_2.tga 0.656250000000 0.632812500000 0.679687500000 0.656250000000 +us_back_3.tga 0.679687500000 0.632812500000 0.703125000000 0.656250000000 +us_back_4.tga 0.703125000000 0.632812500000 0.726562500000 0.656250000000 +us_back_5.tga 0.726562500000 0.632812500000 0.750000000000 0.656250000000 +us_back_6.tga 0.750000000000 0.632812500000 0.773437500000 0.656250000000 +us_back_7.tga 0.773437500000 0.632812500000 0.796875000000 0.656250000000 +us_back_8.tga 0.796875000000 0.632812500000 0.820312500000 0.656250000000 +us_back_9.tga 0.820312500000 0.632812500000 0.843750000000 0.656250000000 +us_ico_0.tga 0.843750000000 0.632812500000 0.867187500000 0.656250000000 +us_ico_1.tga 0.867187500000 0.632812500000 0.890625000000 0.656250000000 +us_ico_2.tga 0.890625000000 0.632812500000 0.914062500000 0.656250000000 +us_ico_3.tga 0.914062500000 0.632812500000 0.937500000000 0.656250000000 +us_ico_4.tga 0.937500000000 0.632812500000 0.960937500000 0.656250000000 +us_ico_5.tga 0.468750000000 0.640625000000 0.492187500000 0.664062500000 +us_ico_6.tga 0.492187500000 0.640625000000 0.515625000000 0.664062500000 +us_ico_7.tga 0.515625000000 0.640625000000 0.539062500000 0.664062500000 +us_ico_8.tga 0.539062500000 0.640625000000 0.562500000000 0.664062500000 +us_ico_9.tga 0.562500000000 0.640625000000 0.585937500000 0.664062500000 +us_over_0.tga 0.585937500000 0.640625000000 0.609375000000 0.664062500000 +us_over_1.tga 0.609375000000 0.640625000000 0.632812500000 0.664062500000 +us_over_2.tga 0.632812500000 0.640625000000 0.656250000000 0.664062500000 +us_over_3.tga 0.960937500000 0.640625000000 0.984375000000 0.664062500000 +us_over_4.tga 0.000000000000 0.648437500000 0.023437500000 0.671875000000 +ico_aim.tga 0.023437500000 0.648437500000 0.046875000000 0.671875000000 +ico_aim_bird_wings.tga 0.046875000000 0.648437500000 0.070312500000 0.671875000000 +ico_aim_flying_kitin_abdomen.tga 0.070312500000 0.648437500000 0.093750000000 0.671875000000 +ico_aim_homin_arms.tga 0.093750000000 0.648437500000 0.117187500000 0.671875000000 +ico_aim_homin_chest.tga 0.117187500000 0.648437500000 0.140625000000 0.671875000000 +mf_back.tga 0.140625000000 0.648437500000 0.164062500000 0.671875000000 +mf_over.tga 0.164062500000 0.648437500000 0.187500000000 0.671875000000 +W_slot_shortcut_id0.tga 0.187500000000 0.648437500000 0.210937500000 0.671875000000 +W_slot_shortcut_id1.tga 0.210937500000 0.648437500000 0.234375000000 0.671875000000 +W_slot_shortcut_id2.tga 0.234375000000 0.648437500000 0.257812500000 0.671875000000 +W_slot_shortcut_id3.tga 0.257812500000 0.648437500000 0.281250000000 0.671875000000 +W_slot_shortcut_id4.tga 0.281250000000 0.648437500000 0.304687500000 0.671875000000 +W_slot_shortcut_id5.tga 0.304687500000 0.648437500000 0.328125000000 0.671875000000 +W_slot_shortcut_id6.tga 0.328125000000 0.648437500000 0.351562500000 0.671875000000 +W_slot_shortcut_id7.tga 0.351562500000 0.648437500000 0.375000000000 0.671875000000 +W_slot_shortcut_id8.tga 0.375000000000 0.648437500000 0.398437500000 0.671875000000 +W_slot_shortcut_id9.tga 0.398437500000 0.648437500000 0.421875000000 0.671875000000 +w_slot_shortcut_shift_id0.tga 0.421875000000 0.648437500000 0.445312500000 0.671875000000 +w_slot_shortcut_shift_id1.tga 0.445312500000 0.648437500000 0.468750000000 0.671875000000 +w_slot_shortcut_shift_id2.tga 0.656250000000 0.656250000000 0.679687500000 0.679687500000 +w_slot_shortcut_shift_id3.tga 0.679687500000 0.656250000000 0.703125000000 0.679687500000 +w_slot_shortcut_shift_id4.tga 0.703125000000 0.656250000000 0.726562500000 0.679687500000 +w_slot_shortcut_shift_id5.tga 0.726562500000 0.656250000000 0.750000000000 0.679687500000 +w_slot_shortcut_shift_id6.tga 0.750000000000 0.656250000000 0.773437500000 0.679687500000 +w_slot_shortcut_shift_id7.tga 0.773437500000 0.656250000000 0.796875000000 0.679687500000 +w_slot_shortcut_shift_id8.tga 0.796875000000 0.656250000000 0.820312500000 0.679687500000 +w_slot_shortcut_shift_id9.tga 0.820312500000 0.656250000000 0.843750000000 0.679687500000 +ico_source_knowledge.tga 0.843750000000 0.656250000000 0.865234375000 0.679687500000 small_task_travel.tga 0.984375000000 0.000000000000 1.000000000000 0.015625000000 small_task_craft.tga 0.984375000000 0.015625000000 1.000000000000 0.031250000000 small_task_done.tga 0.984375000000 0.031250000000 1.000000000000 0.046875000000 small_task_failed.tga 0.980468750000 0.046875000000 0.996093750000 0.062500000000 small_task_fight.tga 0.980468750000 0.062500000000 0.996093750000 0.078125000000 -small_task_forage.tga 0.984375000000 0.523437500000 1.000000000000 0.539062500000 -small_task_generic.tga 0.984375000000 0.539062500000 1.000000000000 0.554687500000 -small_task_guild.tga 0.984375000000 0.554687500000 1.000000000000 0.570312500000 -small_task_rite.tga 0.984375000000 0.570312500000 1.000000000000 0.585937500000 -W_leader.tga 0.984375000000 0.585937500000 0.997070312500 0.597656250000 -tb_mode.tga 0.984375000000 0.597656250000 0.996093750000 0.609375000000 -w_major.tga 0.984375000000 0.609375000000 0.996093750000 0.621093750000 +small_task_forage.tga 0.984375000000 0.500000000000 1.000000000000 0.515625000000 +small_task_generic.tga 0.984375000000 0.515625000000 1.000000000000 0.531250000000 +small_task_guild.tga 0.984375000000 0.531250000000 1.000000000000 0.546875000000 +small_task_rite.tga 0.984375000000 0.546875000000 1.000000000000 0.562500000000 +W_leader.tga 0.984375000000 0.562500000000 0.997070312500 0.574218750000 +tb_mode.tga 0.984375000000 0.574218750000 0.996093750000 0.585937500000 +w_major.tga 0.984375000000 0.585937500000 0.996093750000 0.597656250000 ge_acc_baniere_em.ps 0.000000000000 0.000000000000 0.000000000000 0.000000000000 ge_acc_baniere_em - Copie.ps 0.000000000000 0.000000000000 0.000000000000 0.000000000000 diff --git a/code/ryzom/client/data/gamedev/adds/shapes/FY_Acc_Bowl.shape b/code/ryzom/client/data/gamedev/adds/shapes/FY_Acc_Bowl.shape new file mode 100644 index 000000000..83e361eee Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/FY_Acc_Bowl.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/FY_Acc_Pick_A.shape b/code/ryzom/client/data/gamedev/adds/shapes/FY_Acc_Pick_A.shape new file mode 100644 index 000000000..68388c51b Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/FY_Acc_Pick_A.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/FY_Acc_Vase.shape b/code/ryzom/client/data/gamedev/adds/shapes/FY_Acc_Vase.shape new file mode 100644 index 000000000..e6ab4ae23 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/FY_Acc_Vase.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/FY_Acc_Vase2.shape b/code/ryzom/client/data/gamedev/adds/shapes/FY_Acc_Vase2.shape new file mode 100644 index 000000000..5f506b8d2 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/FY_Acc_Vase2.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/FY_appart_joueur.ig b/code/ryzom/client/data/gamedev/adds/shapes/FY_appart_joueur.ig new file mode 100644 index 000000000..0e3c30d17 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/FY_appart_joueur.ig differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/GE_Acc_Candys.shape b/code/ryzom/client/data/gamedev/adds/shapes/GE_Acc_Candys.shape new file mode 100644 index 000000000..b5088f065 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/GE_Acc_Candys.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/GE_Mission_RaceCup.shape b/code/ryzom/client/data/gamedev/adds/shapes/GE_Mission_RaceCup.shape new file mode 100644 index 000000000..c76ae4f88 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/GE_Mission_RaceCup.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/MA_Acc_Bowl.shape b/code/ryzom/client/data/gamedev/adds/shapes/MA_Acc_Bowl.shape new file mode 100644 index 000000000..7da2514f8 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/MA_Acc_Bowl.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/MA_Acc_Pick_A.shape b/code/ryzom/client/data/gamedev/adds/shapes/MA_Acc_Pick_A.shape new file mode 100644 index 000000000..00ab58854 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/MA_Acc_Pick_A.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/MA_appart_joueur.ig b/code/ryzom/client/data/gamedev/adds/shapes/MA_appart_joueur.ig new file mode 100644 index 000000000..c9bb9f466 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/MA_appart_joueur.ig differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/TR_Acc_Bowl.shape b/code/ryzom/client/data/gamedev/adds/shapes/TR_Acc_Bowl.shape new file mode 100644 index 000000000..19967b75e Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/TR_Acc_Bowl.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/TR_Acc_Pick_A.shape b/code/ryzom/client/data/gamedev/adds/shapes/TR_Acc_Pick_A.shape new file mode 100644 index 000000000..30a98b7be Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/TR_Acc_Pick_A.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/ZO_Acc_Bowl.shape b/code/ryzom/client/data/gamedev/adds/shapes/ZO_Acc_Bowl.shape new file mode 100644 index 000000000..e28ba717d Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/ZO_Acc_Bowl.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/ZO_Acc_Pick_A.shape b/code/ryzom/client/data/gamedev/adds/shapes/ZO_Acc_Pick_A.shape new file mode 100644 index 000000000..1dd713587 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/ZO_Acc_Pick_A.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/ZO_bt_Appart.ig b/code/ryzom/client/data/gamedev/adds/shapes/ZO_bt_Appart.ig new file mode 100644 index 000000000..cef5c7db7 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/ZO_bt_Appart.ig differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/tr_appart.ig b/code/ryzom/client/data/gamedev/adds/shapes/tr_appart.ig new file mode 100644 index 000000000..b9e908e25 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/tr_appart.ig differ diff --git a/code/ryzom/client/data/gamedev/adds/shapes/tr_appart.shape b/code/ryzom/client/data/gamedev/adds/shapes/tr_appart.shape new file mode 100644 index 000000000..d4d67e27f Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/shapes/tr_appart.shape differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/DragonTail.tga b/code/ryzom/client/data/gamedev/adds/textures/DragonTail.tga new file mode 100644 index 000000000..ae3bc47fb Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/DragonTail.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_blue.tga b/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_blue.tga new file mode 100644 index 000000000..19b0581e8 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_blue.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_craft.tga b/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_craft.tga new file mode 100644 index 000000000..c7a015b75 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_craft.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_green.tga b/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_green.tga new file mode 100644 index 000000000..b7d40dbe7 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_green.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_red.tga b/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_red.tga new file mode 100644 index 000000000..3a81e8fea Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_red.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_yellow.tga b/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_yellow.tga new file mode 100644 index 000000000..ab99465ca Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_yellow.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_yuboskin.tga b/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_yuboskin.tga new file mode 100644 index 000000000..608aefc2d Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/Ge_gift_yuboskin.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/f_pick-blades_c1.tga b/code/ryzom/client/data/gamedev/adds/textures/f_pick-blades_c1.tga new file mode 100644 index 000000000..431eafbe9 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/f_pick-blades_c1.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/f_pick-blades_c2.tga b/code/ryzom/client/data/gamedev/adds/textures/f_pick-blades_c2.tga new file mode 100644 index 000000000..d2e1972d1 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/f_pick-blades_c2.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/f_pick-blades_c3.tga b/code/ryzom/client/data/gamedev/adds/textures/f_pick-blades_c3.tga new file mode 100644 index 000000000..e5fce7fcb Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/f_pick-blades_c3.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/f_pick-stick_c1.tga b/code/ryzom/client/data/gamedev/adds/textures/f_pick-stick_c1.tga new file mode 100644 index 000000000..2bcc80af6 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/f_pick-stick_c1.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/f_pick-stick_c2.tga b/code/ryzom/client/data/gamedev/adds/textures/f_pick-stick_c2.tga new file mode 100644 index 000000000..d6076ea72 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/f_pick-stick_c2.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/f_pick-stick_c3.tga b/code/ryzom/client/data/gamedev/adds/textures/f_pick-stick_c3.tga new file mode 100644 index 000000000..345bf9526 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/f_pick-stick_c3.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/m_pick-blades_c1.tga b/code/ryzom/client/data/gamedev/adds/textures/m_pick-blades_c1.tga new file mode 100644 index 000000000..befef3438 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/m_pick-blades_c1.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/m_pick-blades_c2.tga b/code/ryzom/client/data/gamedev/adds/textures/m_pick-blades_c2.tga new file mode 100644 index 000000000..8643ec118 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/m_pick-blades_c2.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/m_pick-blades_c3.tga b/code/ryzom/client/data/gamedev/adds/textures/m_pick-blades_c3.tga new file mode 100644 index 000000000..d96ea0fcf Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/m_pick-blades_c3.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/m_pick-stick_c1.tga b/code/ryzom/client/data/gamedev/adds/textures/m_pick-stick_c1.tga new file mode 100644 index 000000000..213ef1165 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/m_pick-stick_c1.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/m_pick-stick_c2.tga b/code/ryzom/client/data/gamedev/adds/textures/m_pick-stick_c2.tga new file mode 100644 index 000000000..e2d0e9f09 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/m_pick-stick_c2.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/m_pick-stick_c3.tga b/code/ryzom/client/data/gamedev/adds/textures/m_pick-stick_c3.tga new file mode 100644 index 000000000..5a6c784e1 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/m_pick-stick_c3.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/t_pick-blades_c1.tga b/code/ryzom/client/data/gamedev/adds/textures/t_pick-blades_c1.tga new file mode 100644 index 000000000..26844487c Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/t_pick-blades_c1.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/t_pick-blades_c2.tga b/code/ryzom/client/data/gamedev/adds/textures/t_pick-blades_c2.tga new file mode 100644 index 000000000..a0d3f35dc Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/t_pick-blades_c2.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/t_pick-blades_c3.tga b/code/ryzom/client/data/gamedev/adds/textures/t_pick-blades_c3.tga new file mode 100644 index 000000000..53502abf0 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/t_pick-blades_c3.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/t_pick-stick_c1.tga b/code/ryzom/client/data/gamedev/adds/textures/t_pick-stick_c1.tga new file mode 100644 index 000000000..57e7701de Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/t_pick-stick_c1.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/t_pick-stick_c2.tga b/code/ryzom/client/data/gamedev/adds/textures/t_pick-stick_c2.tga new file mode 100644 index 000000000..bce9c1f0c Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/t_pick-stick_c2.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/t_pick-stick_c3.tga b/code/ryzom/client/data/gamedev/adds/textures/t_pick-stick_c3.tga new file mode 100644 index 000000000..57e7701de Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/t_pick-stick_c3.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/t_pick-stick_c4.tga b/code/ryzom/client/data/gamedev/adds/textures/t_pick-stick_c4.tga new file mode 100644 index 000000000..105c412a3 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/t_pick-stick_c4.tga differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/z_pick-blades_c1.dds b/code/ryzom/client/data/gamedev/adds/textures/z_pick-blades_c1.dds new file mode 100644 index 000000000..5ed471264 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/z_pick-blades_c1.dds differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/z_pick-blades_c2.dds b/code/ryzom/client/data/gamedev/adds/textures/z_pick-blades_c2.dds new file mode 100644 index 000000000..d2a5a9079 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/z_pick-blades_c2.dds differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/z_pick-blades_c3.dds b/code/ryzom/client/data/gamedev/adds/textures/z_pick-blades_c3.dds new file mode 100644 index 000000000..5185b969c Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/z_pick-blades_c3.dds differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/z_pick-stick_c1.dds b/code/ryzom/client/data/gamedev/adds/textures/z_pick-stick_c1.dds new file mode 100644 index 000000000..369422d09 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/z_pick-stick_c1.dds differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/z_pick-stick_c2.dds b/code/ryzom/client/data/gamedev/adds/textures/z_pick-stick_c2.dds new file mode 100644 index 000000000..db7efaea0 Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/z_pick-stick_c2.dds differ diff --git a/code/ryzom/client/data/gamedev/adds/textures/z_pick-stick_c3.dds b/code/ryzom/client/data/gamedev/adds/textures/z_pick-stick_c3.dds new file mode 100644 index 000000000..26940042d Binary files /dev/null and b/code/ryzom/client/data/gamedev/adds/textures/z_pick-stick_c3.dds differ diff --git a/code/ryzom/client/data/gamedev/html/context_help/ch_compas_en.html b/code/ryzom/client/data/gamedev/html/context_help/ch_compas_en.html index a668317fc..4e2511219 100644 --- a/code/ryzom/client/data/gamedev/html/context_help/ch_compas_en.html +++ b/code/ryzom/client/data/gamedev/html/context_help/ch_compas_en.html @@ -3,7 +3,7 @@ -

To open the compas, use this menu or use the key +

To show the compas, use this menu or press

Don't show this message anymore

diff --git a/code/ryzom/client/data/gamedev/html/help/credits_en.html b/code/ryzom/client/data/gamedev/html/help/credits_en.html index 899c8a71c..f34b2a9fb 100644 --- a/code/ryzom/client/data/gamedev/html/help/credits_en.html +++ b/code/ryzom/client/data/gamedev/html/help/credits_en.html @@ -1,8 +1,10 @@  The Saga Of Ryzom Credits + - + +
diff --git a/code/ryzom/client/data/gamedev/html/help/help_en.html b/code/ryzom/client/data/gamedev/html/help/help_en.html index d34dc9cf5..f38172198 100644 --- a/code/ryzom/client/data/gamedev/html/help/help_en.html +++ b/code/ryzom/client/data/gamedev/html/help/help_en.html @@ -1,38 +1,38 @@ - + Ryzom Help - +

Tutorial

-

- How To Move : Go

-

- How To Use Windows : Go

-

- How To Fight : Go

-

- How To Do Magic : Go

-

- How To Find Your Way : Go

+

- How to Move: Go

+

- How to Use Windows: Go

+

- How to Fight: Go

+

- How to Do Magic: Go

+

- How to Get Your Bearings: Go

 

How to

-

- Heal yourself : Go

-

- Heal others : Go

-

- Cast offensive spells : Go

-

- Change items in hand : Go

-

- Find raw material sources : Go

-

- Extract raw material from a source : Go

-

- Resuscitate a friend : Go

+

- Heal yourself: Go

+

- Heal others: Go

+

- Cast offensive spells: Go

+

- Change items in hand: Go

+

- Find raw materials: Go

+

- Extract raw materials: Go

+

- Resurrect a dead friend: Go

 

Interfaces

-

- p's IDENTITY : Go

-

- MY GAUGE : Go

-

- TARGET GAUGE : Go

-

- HANDS : Go

-

- MAIN CHAT : Go

-

- COMPASS : Go

-

- ANIMALS : Go

-

- PROGRESSION : Go

-

 

+

- My Statistics: Go

+

- My Gauges: Go

+

- Target: Go

+

- Action Bar: Go

+

- Main Chat: Go

+

- Compass: Go

+

- Animals: Go

+

- Actions: Go

+

- NPC Trade: Go

 

 

diff --git a/code/ryzom/client/data/gamedev/html/help/how_to_castoffensivespells_en.html b/code/ryzom/client/data/gamedev/html/help/how_to_castoffensivespells_en.html index 3200d17e8..2467412c5 100644 --- a/code/ryzom/client/data/gamedev/html/help/how_to_castoffensivespells_en.html +++ b/code/ryzom/client/data/gamedev/html/help/how_to_castoffensivespells_en.html @@ -1,17 +1,25 @@ - + - + + + + + +
+

How to cast offensive spells

+
-

How to cast offensive spells

-In order to cast offensive spells, you must target a foe by clicking on them and then clicking on the spell icon in the 'Hands Bar' interface. -You cannot cast offensive spells against the NPCs in the towns and villages.
-Most of the game areas are not flagged as PvP meaning that you will not be able to cast offensive spells against other players in these areas. +In order to cast offensive spells, you must target a foe by clicking on them and then clicking on the spell icon in the 'action bar' interface. +You cannot cast offensive spells against the NPCs in the towns and villages.

+ +

+Most of the game areas are not flagged as PvP, meaning that you will not be able to cast offensive spells against other players in these areas.

diff --git a/code/ryzom/client/data/gamedev/html/help/how_to_changeitemsinhand_en.html b/code/ryzom/client/data/gamedev/html/help/how_to_changeitemsinhand_en.html index 3e2425ff7..8f92b19ae 100644 --- a/code/ryzom/client/data/gamedev/html/help/how_to_changeitemsinhand_en.html +++ b/code/ryzom/client/data/gamedev/html/help/how_to_changeitemsinhand_en.html @@ -1,23 +1,27 @@ - + - +How to Change Items in Hand - + + + + + +
+

How to change the items in your hands

+
-

How to change the items in your hands

-

-The item that you are holding in your right hand is displayed at the right hand end of the 'Hands Bar' interface. -If the item takes up both of your hands, then a copy of the icon also appears in a half tone at the left hand end of the Hands Bar. -In order to change the item in your right hand click on the icon at the right end of the Hands Bar. +

The item that you are holding in your right hand is displayed at the right hand end of the 'action bar' interface. +If the item takes up both of your hands, then a copy of the icon also appears in a half tone at the left hand end of the action bar.

+

In order to change the item in your right hand, click on the icon at the right end of the Hands Bar. A pop-up window will appear showing all of the items in your inventory that can be carried in your right hand. -Click on the item to place it in your hand.
-Note that items in your hands can't be used for a few seconds after they are changed. -The action icons in the Hands Bar are all displayed in half tones to represent that they cannot be used during this time. -

- +Click on the item to equip it.

+

Note that items in your hands can't be used for a few seconds after they are changed. +The action icons in the action bar are all displayed in gray to represent that they cannot be used during this time. +

diff --git a/code/ryzom/client/data/gamedev/html/help/how_to_craft_en.html b/code/ryzom/client/data/gamedev/html/help/how_to_craft_en.html index 66e01264c..01048cf95 100644 --- a/code/ryzom/client/data/gamedev/html/help/how_to_craft_en.html +++ b/code/ryzom/client/data/gamedev/html/help/how_to_craft_en.html @@ -1,4 +1,4 @@ - + diff --git a/code/ryzom/client/data/gamedev/html/help/how_to_extractrawmaterialsfromasource_en.html b/code/ryzom/client/data/gamedev/html/help/how_to_extractrawmaterialsfromasource_en.html index d96716010..251b91801 100644 --- a/code/ryzom/client/data/gamedev/html/help/how_to_extractrawmaterialsfromasource_en.html +++ b/code/ryzom/client/data/gamedev/html/help/how_to_extractrawmaterialsfromasource_en.html @@ -1,22 +1,29 @@ - + - + How to Extract Raw Materials - + -

How to extract raw materials from a source

-

Prerequisite : How to find raw material sources

-

-

For beginners

-You must ensure that you have a foraging tool in your hand (typically a pick). + + + + +
+

How to extract raw materials

+
+ +

See first: How to find raw materials

+ +

Beginning

+

You must ensure that you have a foraging tool in your hand (typically a pick). Look at the right hand slot of the 'hands bar'. Click on the source to target it. Click a second time to begin extraction. This will start running the default foraging action repeatedly.

-

Advanced

+

Advanced

When you know several foraging actions, either learnt from your forager trainer or built by yourself with combined stanzas, you can click the action you want to start, @@ -25,16 +32,16 @@ an extraction, you can switch from one action to another. For example, if the ex gets dangerous (watch the glow and colour of the source, or the 'extraction risk' bar), you should rush at a Ground Stability care action, or the source will blow up!

-

+

Actions that are more effective are often more dangerous too. Damage caused by your actions can result in explosions, poisonous gas clouds or even in provoking the wrath of the local Kamis.

-

+

The default foraging action, used if you click a source twice, is the leftmost and topmost foraging action in the 'hands' bar. Then you can assign it to any action you want.

-

+

Unlike combat actions, all extraction actions are cyclic. This means that you only need to click on an action once to start performing it and it will repeat indefinitely - or at least until you click on another action or stop extracting.

diff --git a/code/ryzom/client/data/gamedev/html/help/how_to_findrawmaterialsources_en.html b/code/ryzom/client/data/gamedev/html/help/how_to_findrawmaterialsources_en.html index 846d40677..9fb33f2c7 100644 --- a/code/ryzom/client/data/gamedev/html/help/how_to_findrawmaterialsources_en.html +++ b/code/ryzom/client/data/gamedev/html/help/how_to_findrawmaterialsources_en.html @@ -1,36 +1,38 @@ - + - + How to Find Raw Materials - + + + + + + +
+

How to find raw materials

+
-

Where to find raw material sources

-In order to use 'extraction' actions you will need to locate a 'raw material source'. +In order to use 'extraction' actions you will need to locate a raw material source. Sources have a green phosphorescent glow and a green name over them. Sources appear randomly in some areas of the world. -Their appearance can also be provoked by players with prospecting actions. -

-

Where are my prospecting actions ?

-

-You have a prospecting action only if you started with enough 'forage' action packs. -If you don't have the prospecting action, at first you will have to extract either some randomly-appearing sources or extract sources prospected by another homin. -After some experience in extracting, your Forager Trainer will accept to teach you a prospecting action. -

-

-However, if you didn't choose any 'forage' action pack and you want to retrain into a forager career, -you will have to learn even an extracting action from your favorite trainer. -

-

How to look for specific raw materials?

-

-When your skill will be sufficient, your Forager Trainer will teach you new prospecting actions. Gradually, -they will allow you to refine your search... -

-

I have found a raw material source, now what?

-

-Once you can find or provoke the appearance of a raw material source, see How to extract raw materials. -

+They can also be made to appear by players with prospecting actions. +

+

Where are my prospecting actions?

+

+You should have a basic prospecting action in your action bar. If the stanza does not appear in your action bar, drag and drop it from your action progression window. +or create it by right clicking on a free slot of the action bar. +

+

How to look for specific raw materials?

+

+When your skill is sufficient, your Forager Trainer will teach you new prospecting actions. Gradually, +they will allow you to refine your search. +

+

I have found a raw material source, now what?

+

+Once you have prospected a raw material source, see How to extract raw materials. +

diff --git a/code/ryzom/client/data/gamedev/html/help/how_to_healothers_en.html b/code/ryzom/client/data/gamedev/html/help/how_to_healothers_en.html index ea2f18578..c91855e22 100644 --- a/code/ryzom/client/data/gamedev/html/help/how_to_healothers_en.html +++ b/code/ryzom/client/data/gamedev/html/help/how_to_healothers_en.html @@ -1,20 +1,25 @@ - + - + How to Heal Others - + -

How to heal others

-

-In order to heal other players you will need a heal spell (not a "self" power). -If you had taken at least a magician pack 2 during the character creation, you should have one, -else, you will need to learn one from the magic trainer.
-You need to target the player you wish to heal and click on the healing spell icon in the Hands Bar.
-If the action does not appear in your hands bar, drop it from your progression window. -or create it by right clicking on a free slot of the hands bar. -Note that if you only have a 'self' power, you will not be able to heal other players. + + + + +
+

How to heal others

+
+ +

In order to heal other players you will need a heal spell (not a "self" power). +If you do not have one, you will need to learn one from the magic trainer.

+

You need to target the player you wish to heal and click on the healing spell icon in the action bar. +If the stanza does not appear in your action bar, drag and drop it from your action progression window. +or create it by right clicking on a free slot of the action bar. +Note that if you only have a "self" power, you will not be able to heal other players.

diff --git a/code/ryzom/client/data/gamedev/html/help/how_to_resurectadeadfriend_en.html b/code/ryzom/client/data/gamedev/html/help/how_to_resurectadeadfriend_en.html index ce4d3d471..278a1a49a 100644 --- a/code/ryzom/client/data/gamedev/html/help/how_to_resurectadeadfriend_en.html +++ b/code/ryzom/client/data/gamedev/html/help/how_to_resurectadeadfriend_en.html @@ -1,20 +1,28 @@ - + - + How to Resurrect a Dead Friend - + + + + + + +
+

How to resurrect a dead friend

+
-

How to resuscitate a dead friend

-In Ryzom players who loose all of their hit points fall into a coma. +In Ryzom, players who lose all of their hit points fall into a coma. When they are in a coma their hit point bar starts to fill up with a deep red color. When the bar is completely full they die and must -choose a bind point and re-spawn. Comatose players can be resuscitated. -Dead players cannot.
-One resuscitates players by casting heal spells on their comatose -corpses. +choose a respawn point to re-spawn. Comatose players can be revived. +Dead players cannot.

+ +

You can revive players by casting heal spells on their comatose +bodies. Each heal spell makes the deep red bar recede. Casting sufficient heal spells to completely eliminate the dark red brings the comatose player back to life. diff --git a/code/ryzom/client/data/gamedev/html/help/how_to_selfheal_en.html b/code/ryzom/client/data/gamedev/html/help/how_to_selfheal_en.html index e451fac4a..ac7086715 100644 --- a/code/ryzom/client/data/gamedev/html/help/how_to_selfheal_en.html +++ b/code/ryzom/client/data/gamedev/html/help/how_to_selfheal_en.html @@ -1,26 +1,33 @@ - + - + How to Heal Yourself - + -

How to heal yourself

-

-You will recover naturally from damage inflicted to you by foes. + + + + +
+

How to heal yourself

+
+ +

You will recover naturally from damage inflicted to you by foes. You will recover faster if you sit down than if you remain standing. -The rate at which you heal is determined by your Metabolism score.
+The rate at which you heal is determined by your Metabolism score.

-You can also heal yourself with powers called “self heal life†you can find by your trainers. -If the power does not appear in your hands bar, drop it from your progression windows or create it by right clicking on a free slot of the hands bar. -Now that you have the “self heal life†power in your hands bar, just click on the icon to activate it. -You don’t need to target yourself to perform this action.
+

You can also heal yourself with powers called "self heal life", which you can get from trainers. +If the stanza does not appear in your action bar, drag and drop it from your action progression window or +create it by right clicking on a free slot of the action bar. +Now that you have the "self heal life" stanza in your action bar, just click on the icon to activate it. +You don’t need to target yourself to perform this action.

-You can also use the “restore sap†and “restore stamina†stanzas in this power to heal your sap points or your stamina points. -Each time that you create a “self heal†power, you need to choose a time credit wich define how long your self heal abilities will be disabled. -Note that this timer is common to ALL self heals…so you cannot use a self heal hit points power and use a self heal stamina just after it. -

+

You can also use the "restore sap" and "restore stamina" stanzas in this stanza to heal your sap points or your stamina points. +Each time that you create a "self heal" stanza, you need to choose a time credit wich define how long your self heal abilities will be disabled. +Note that this timer is common to ALL self heals, so you cannot use a self heal life stanza and use a self heal stamina immediately after it. +

diff --git a/code/ryzom/client/data/gamedev/html/help/interf_action_bar_en.html b/code/ryzom/client/data/gamedev/html/help/interf_action_bar_en.html index f582ab7ee..0c6b1c012 100644 --- a/code/ryzom/client/data/gamedev/html/help/interf_action_bar_en.html +++ b/code/ryzom/client/data/gamedev/html/help/interf_action_bar_en.html @@ -1,10 +1,10 @@ - + - + Action Bar - + diff --git a/code/ryzom/client/data/gamedev/html/help/interf_action_book_en.html b/code/ryzom/client/data/gamedev/html/help/interf_action_book_en.html index 1e18abea7..b53599e74 100644 --- a/code/ryzom/client/data/gamedev/html/help/interf_action_book_en.html +++ b/code/ryzom/client/data/gamedev/html/help/interf_action_book_en.html @@ -1,10 +1,10 @@ - + - +Action Progression - +
@@ -15,36 +15,33 @@
-

-This interface allows you to see the progression of your skills and the progression of your actions. +This window allows you to see the progression of your skills and the progression of your actions.

-

Skill Tree

-The Skill Tree allows you to see the state of your skills.
-You have the current level of the skill over it's max level (eg: Craft: 1/20).
-The bar indicate the progression in the current skill level.
-The color of the skill indicates either:
- - transparent: skill not trained
- - orange: skill currently trained
- - green: skill completed
-
-When you complete a skill, new skills are opened. you can browse the skill tree, clicking on "+".
-The whole skill tree is not displayed. Only completed skills, currently trained skills, -and the untrained skills that relies directly on a trained skill are displayed.
-

Actions

-The Actions part shows the actions you can learn or the actions you have learnt at each skill level.
-You have to select a skill to see the actions related to this skill.
-The actions you have not learnt are grayed.
-The actions you can either not learn because the requirements are not met (e.g.: you don't reach the required skill level) are in Red.
-The actions are separated in two groups: +

Skill Tree

+The Skill Tree allows you to see the state of your skills. +
It displays the current level of the skill and its max level (eg: Craft: 1/20). +
The bar indicates the progression in the current skill level. +
The color of the skill indicates either: +
- transparent: skill not trained +
- orange: skill currently trained +
- green: skill completed + +

When you complete a skill, a new part of the tree is opened, which you can see by clicking on "+". +
The whole skill tree is not displayed. Only completed skills, currently trained skills, +and the untrained skills that relies directly on a trained skill are displayed. +

Actions

+The Actions part shows the actions you can learn or the actions you have learnt at each skill level. +
You have to select a skill to see the actions related to this skill. +
The actions you have not learned are grayed out. +
The actions you cannot learn because you do not meet the requirements (e.g. you don't have the required skill level) displayed are in red. +

The actions are separated in two groups: Actions, and -Action Upgrades.
-You can drag and drop an Action to your action bar, while you cannot drag an Action Upgrade because they are either characteristic upgrades, or action upgrade -which are not castable.
-

- - +Upgrades. +

You can drag and drop an Action to your action bar, but you cannot drag an Action Upgrade because they are either characteristic upgrades, or action upgrades +which are not castable directly. +

diff --git a/code/ryzom/client/data/gamedev/html/help/interf_animals_en.html b/code/ryzom/client/data/gamedev/html/help/interf_animals_en.html index 6a331b568..6a9034cf2 100644 --- a/code/ryzom/client/data/gamedev/html/help/interf_animals_en.html +++ b/code/ryzom/client/data/gamedev/html/help/interf_animals_en.html @@ -1,12 +1,11 @@ - + Animals - + + @@ -22,15 +21,15 @@

This interface references all of the animals in your posession. It closely resembles the 'team' interface.

Basics

-Selection : In order to select an animal you must click -on their name. You can only select animals that are physically close to -you. Clicking on the name of animal who is too far away has no effect.
-Orders : The context menu on the right mouse button is +Selection: In order to select an animal you must click +on its name. You can only select animals that are physically close to +you. Clicking on the name of animal who is too far away has no effect. +
Orders: The context menu on the right mouse button is used to give orders to your animals. Click the right mouse button on the name of an animal in order to give it individual orders. Click the right mouse button on the title bar of the animals interface in order -to give the same orders to all of the animals at once.
-Stables : When you are close to stable buildings you can +to give the same orders to all of the animals at once. +
Stables: When you are close to stable buildings you can order your animals to enter or leave. Stables are places where your animals are safe. Given that your animals can be attacked and cannot be resurreted when they die, you are strongly recomended to leave your @@ -38,26 +37,26 @@ animals in stables whenever you don't have an immediate need for them. There is a stable building located at the entrance to each town and village. Note that when you are close to the stables where your animals are located you continue to the inventories of items that they are -carrying.
-

Description

-Name or Type : Indicates whether an animal is a steed or -a pack animal.
-Weight : Displays the total weight carried by your +carrying. +

Description

+Name or Type: Indicates whether an animal is a steed or +a pack animal. +
Weight: Displays the total weight carried by your animal (a value followed by the 'weight' icon). Weight has no impact at -all on your pack animals. The value is purely informative.
-Life :The red bar represents your animal's life (hit +all on your pack animals. The value is purely informative. +
Life:The red bar represents your animal's life (hit points). When the bar is empty your animal will die. A dead animal cannot be brought back to life. One can only retrieve the items that -they were carrying.
-Bulk : The yellow bar (the last bar) represents the bulk +they were carrying. +
Bulk: The yellow bar (the last bar) represents the bulk of the items carried by the animal. When the bar is full it becomes impossible to add more items to the -animal's inventory.
-Inventory : The icon depicting a chest (displayed on the +animal's inventory. +
Inventory: The icon depicting a chest (displayed on the right) gives access to the items transported by an animal. You are always allowed to look at the items carried by all of your animals. However, you cannot do anything with items that are carried by animals -who are not near by.
-

+who are not near by. +

diff --git a/code/ryzom/client/data/gamedev/html/help/interf_bot_trade_en.html b/code/ryzom/client/data/gamedev/html/help/interf_bot_trade_en.html index fb1d9893a..43d176c99 100644 --- a/code/ryzom/client/data/gamedev/html/help/interf_bot_trade_en.html +++ b/code/ryzom/client/data/gamedev/html/help/interf_bot_trade_en.html @@ -1,53 +1,49 @@ - + - +Trade With an NPC - - +
-

Trade With a NPC

+

Trade With an NPC

-

-This interface allows you to buy and sell items to a NPC. +This window allows you to buy from and sell items to a NPC.

Sell List

-The Sell List allows you to sell your items (either from your Bag, or from a Pack Animal).
-When You sell an item to a NPC, this NPC will resell it to other players under certain conditions:
- - Raw Materials can always be resold
- - Item freshly crafted (i.e. never damaged) such as swords, armors, ammo etc... can be resold
-
-When you sell an item to the NPC, it will ask you a 'Resale Price' which is the 'Basic Price' multiplied by 2 by default. -Other players will be able to buy this item at this 'Resale Price'.
-Following rules are applied for those prices:
- - When you sell the item to the NPC, you receive immediatly the 'Basic Price'
- - You will receive the difference 'Resale Price' - 'Basic Price' once some player buy your item
-
-Note: you can sell any item to any NPC. For instance, you can sell swords to Raw Material merchant.
-
+The Sell List allows you to sell your items (either from your Bag, or from a Pack Animal). +
When You sell an item to a NPC, this NPC will resell it to other players under certain conditions: +
- Raw Materials can always be resold +
- Item freshly crafted (i.e. never damaged) such as swords, armors, ammo etc... can be resold -

Buy List

-The 'Buy List' allows you to buy items from NPC. There is 2 Lists:
- - 'Players and NPC Sale' shows all the items put in resale by all players and the one sold by merchant.
- Note: you'll see only items of type and quality related to the merchant (e.g.: players swords resale won't be seen at the Raw Materials Merchant, and you won't see Swords of quality 100 at the Weapon Merchant of quality 20-50)
- Note: NPC items are usually of higher price and lesser interest than Players 's items.
- - 'Your Sale' shows all the items you have sold and that are waiting for resale. NB: Unlike 'Players Sale' you see all your items sold here (not filtered by type or quality)
-
-In the 'Your Sale' tab, and sometimes in the 'Players and NPC Sale' tab, you'll see items that were sold by you (marked with yellow text). You can retire those items so you can change the Resale Price.
-
-Note: Items are resold within a certain amount of time. You can see the resale time left for each item you have put in resale. After this time, the item is lost (kept by the NPC) +

When you sell an item to the NPC, it will ask you a 'Resale Price' which is the 'Basic Price' multiplied by 2 by default. +Other players will be able to buy this item at this 'Resale Price'. +
Following rules are applied for those prices: +
- When you sell the item to the NPC, you receive immediatly the 'Basic Price' +
- You will receive the difference 'Resale Price' - 'Basic Price' once some player buy your item + +

Note: you can sell any item to any NPC. For instance, you can sell swords to Raw Material merchant. + +

Buy List

+The 'Buy List' allows you to buy items from NPC. There are 2 Lists: +
- 'Players and NPC Sale' shows all the items put in resale by all players and the one sold by merchant. +
Note: you'll see only items of type and quality related to the merchant (e.g.: players swords resale won't be seen at the Raw Materials Merchant, and you won't see Swords of quality 100 at the Weapon Merchant of quality 20-50) +
Note: NPC items are usually of higher price and lesser interest than Players 's items. +
- 'Your Sale' shows all the items you have sold and that are waiting for resale. NB: Unlike 'Players Sale' you see all your items sold here (not filtered by type or quality) + +

In the 'Your Sale' tab, and sometimes in the 'Players and NPC Sale' tab, you'll see items that were sold by you (marked with yellow text). You can retire those items so you can change the Resale Price. + +

Note: Items are resold within a certain amount of time. You can see the resale time left for each item you have put in resale. After this time, the item is lost (kept by the NPC)

- diff --git a/code/ryzom/client/data/gamedev/html/help/interf_chat_en.html b/code/ryzom/client/data/gamedev/html/help/interf_chat_en.html index 0b899bdb1..1a38139ed 100644 --- a/code/ryzom/client/data/gamedev/html/help/interf_chat_en.html +++ b/code/ryzom/client/data/gamedev/html/help/interf_chat_en.html @@ -1,10 +1,10 @@ - + - + diff --git a/code/ryzom/client/data/gamedev/html/help/interf_compass_en.html b/code/ryzom/client/data/gamedev/html/help/interf_compass_en.html index 8d99d54d2..1930f8b31 100644 --- a/code/ryzom/client/data/gamedev/html/help/interf_compass_en.html +++ b/code/ryzom/client/data/gamedev/html/help/interf_compass_en.html @@ -1,10 +1,10 @@ - + - +
diff --git a/code/ryzom/client/data/gamedev/html/help/interf_identity_en.html b/code/ryzom/client/data/gamedev/html/help/interf_identity_en.html index 964bf57d1..7a2497259 100644 --- a/code/ryzom/client/data/gamedev/html/help/interf_identity_en.html +++ b/code/ryzom/client/data/gamedev/html/help/interf_identity_en.html @@ -1,10 +1,10 @@ -? + - + My Statistics - +
@@ -17,66 +17,66 @@

-uiPlayerTitle : Dislays the name of other players when they look at your character.
-Click on the current title to display the list of titles that you have won and select those that you prefer the most. -As you progress through the game, you will earn new titles which will be added automatically to this list.
-The uiInfo button allows you to see exactly what is required in order to earn the title currently displayed.
-
-uiGuildMembership : If you are a member of a guild, the name of the guild will be displayed here.
+uiPlayerTitle: Dislays the title other players will seewhen they look at your character. +
Click on the current title to display the list of titles that you have won and select the one that you wish to display. +As you progress through the game, you will earn new titles which will be added to this list. +
The uiInfo button allows you to see what is required in order to earn the title currently displayed. -

uiScoreTable

+

uiGuildMembership: If you are a member of a guild, the name of your guild will be displayed here. +

uiScoreTable

uiValues
- uiHP : Your life - when your life points drop to 0, you will fall into a coma and, if you are not treated immediately by your friends, you will die.
- uiSap : Your magic points - when your level of sap is low, you will no longer be able to cast spells.
- uiStamina : Your special attack energy - when your level of stamina is low, you will no longer be able to carry out special attacks and must be satisfied instead with the "default attack" until your stamina regenerates.
- uiFocus : Your forage energy - when your level of concentration is low, you will no longer be able to carry out forage actions. -
uiRegeneration
- uiHP : Points regenerate in 10 seconds.
- uiSap : Points regenerate in 10 seconds.
-uiStamina : Points regenerate in 10 seconds.
- uiFocus : Points regenerate in 10 seconds.
-NOTE : You will recover more quickly in a sitting position.
+ uiHP: Your life - when your life points drop to 0, you will fall into a coma and, if you are not healed by your friends, you will die. +
uiSap: Your magic points - when your sap is low, you will no longer be able to cast spells. +
uiStamina: Your stamina - when your stamina is low, you will no longer be able to carry out special attacks and must use the "default attack" until your stamina regenerates or is healed. +
uiFocus: Your focus - when your focus is low, you will no longer be able to carry out forage or crafting actions. -

uiCaracsTable

- uiCarac_HpMax : Determines the maximum value of your Life Points.
- uiCarac_SapMax : Determines the maximum value of your Sap.
- uiCarac_StaMax : Determines the maximum value of your Stamina.
-uiCarac_WishMax : Determines the maximum value of your Concentration.
- uiCarac_HpReg : Determines the rate of regeneration of your Life Points.
- uiCarac_SapReg : Determines the rate of regeneration of your Sap.
- uiCarac_StaReg : Determines the rate of regeneration of your Stamina.
-uiCarac_WishReg : Determines the rate of regeneration of your Concentration.
+
uiRegeneration
+ uiHP: Points regenerated in 10 seconds. +
uiSap: Points regenerated in 10 seconds. +
uiStamina: Points regenerated in 10 seconds. +
uiFocus: Points regenerated in 10 seconds. +

NOTE: You will recover more quickly when you are sitting down. -

uiSkillPoints

-uiSkillPoints0 : Points used for learning with the Combat Trainers (PNJ). -You will earn points based on how your Combat abilities progress.
-uiSkillPoints1 : Points used for learning with the Magic Trainers (PNJ). -You will earn points based on how your Magic abilities progress.
-uiSkillPoints2 : Points used for learning with the Craft Trainers (PNJ). -You will earn points based on how your Craft abilities progress.
-uiSkillPoints3 : Points used for learning with the Harvest Trainers (PNJ). -You will earn points based on how your Harvest abilities progress.
+

uiCaracsTable

+ uiCarac_HpMax : Determines the maximum value of your Life Points. +
uiCarac_SapMax : Determines the maximum value of your Sap. +
uiCarac_StaMax : Determines the maximum value of your Stamina. +
uiCarac_WishMax: Determines the maximum value of your Concentration. +
uiCarac_HpReg : Determines the rate of regeneration of your Life Points. +
uiCarac_SapReg : Determines the rate of regeneration of your Sap. +
uiCarac_StaReg : Determines the rate of regeneration of your Stamina. +
uiCarac_WishReg: Determines the rate of regeneration of your Concentration. -

uiCaracMisc

-uiTotalMalus : This indicates the overall penalty for actions when you cast a spell or carry out forage or craft actions. +

uiSkillPoints

+uiSkillPoints0: Points used for learning with the Combat Trainers (NPC). +You will earn points based on how your Combat abilities progress. +
uiSkillPoints1: Points used for learning with the Magic Trainers (NPC). +You will earn points based on how your Magic abilities progress. +
uiSkillPoints2: Points used for learning with the Craft Trainers (NPC). +You will earn points based on how your Craft abilities progress. +
uiSkillPoints3: Points used for learning with the Harvest Trainers (NPC). +You will earn points based on how your Harvest abilities progress. + +

uiCaracMisc

+uiTotalMalus: This indicates the overall penalty for actions when you cast a spell or carry out forage or craft actions. A higher malus implies a higher cost in energy, a long spell-casting time and a reduced area of effectiveness. -This total depends on the properties of the "Actions Malus" relating to the clothes and armor that you are wearing and the objects you are carrying.
-uiBagBulk : This indicates the total space occupied by the objects in your inventory. -When it is full, you will no longer be able to add items to your inventory.
-uiWeightSpeedFactor : This indicates the effect on your speed of movement of the objects you are wearing or carrying in your inventory. -It can also be affected by spells (either positively or negatively as the case may be).
+This total depends on the properties of the "Actions Malus" relating to the clothes and armor that you are wearing and the objects you are carrying. +
uiBagBulk: This indicates the total space occupied by the objects in your inventory. +When it is full, you will no longer be able to add items to your inventory. +
uiWeightSpeedFactor: This indicates the effect on your speed of movement of the objects you are wearing or carrying in your inventory. +It can also be affected by spells (either positively or negatively as the case may be). -

uiResistsTable

-This table displays your level of resistance to spells.
-For each type of spell, you have a different type of resistance. These values are based primarily on the level of your abilities, but can be modified by wearing jewelry.
-The level of the attacker is based on the level of the ability being used to carry out the action. The higher your level is compared to your opponent, the greater your chances are of resisting (or partially resisting and therefore reducing the effects of the spell).
-NOTE : Certain creatures possess special attacks that are not based on magic and cannot be resisted.
+

uiResistsTable

+This table displays your level of resistance to spells. +
For each type of spell, you have a different type of resistance. These values are based primarily on the level of your abilities, but can be modified by wearing jewelry. +

The level of the attacker is based on the level of the ability being used to carry out the action. The higher your level is compared to your opponent, the greater your chances are of resisting (or partially resisting and therefore reducing the effects of the spell). +

NOTE: Certain creatures possess special attacks that are not based on magic and cannot be resisted. -

uiDefenseTitle

-This table displays your defense level.
-Depending on which moded you are in (dodge or block), one or other of these levels is the one that you will use against that of your opponent.
-uiDodge : The first figure represents the level you have at this moment and the second represents the level you have normally (without Bonus or Malus)
-uiParry : The first figure represents the level you have at this moment and the second represents the level you have normally (without Bonus or Malus) +

uiDefenseTitle

+This table displays your defense level. +

Depending on which moded you are in (dodge or block), one or other of these levels is the one that you will use against that of your opponent. +
uiDodge: Displays your current Dodge level +
uiParry: Displays your current Parry level

diff --git a/code/ryzom/client/data/gamedev/html/help/interf_my_gauges_en.html b/code/ryzom/client/data/gamedev/html/help/interf_my_gauges_en.html index f4e6d2b82..3fdd0d035 100644 --- a/code/ryzom/client/data/gamedev/html/help/interf_my_gauges_en.html +++ b/code/ryzom/client/data/gamedev/html/help/interf_my_gauges_en.html @@ -1,41 +1,32 @@ - + - +My Gauges - - - +
-

My Gauges

-Name +Name and title: Your name followed by the title which you've chosen to -make visible to others.
-
-Life: -Your life level (hit points).
-
-Sap: -Used for magic action.
-
-Stamina: -Used for any action (like fighting).
-
-Focus: -Used for prospection and material extraction.
-
+make visible to others. + +

Life: +Your life level (hit points). + +

Sap: +Used for magic action. + +

Stamina: +Used for any action (like fighting). + +

Focus: +Used for prospection and material extraction.

diff --git a/code/ryzom/client/data/gamedev/html/help/interf_target_en.html b/code/ryzom/client/data/gamedev/html/help/interf_target_en.html index 02e5735d0..1fef6be00 100644 --- a/code/ryzom/client/data/gamedev/html/help/interf_target_en.html +++ b/code/ryzom/client/data/gamedev/html/help/interf_target_en.html @@ -1,11 +1,9 @@ -? + - +Target - - - +
@@ -14,19 +12,19 @@

-Name + Title: Name of your target as well as their Title (or Function in the case of a non-player character).
-
-Life: Life (life points) of your target.
-
+Name + Title: Name of your target as well as their title (or Function in the case of a non-player character). + +

Life: Life (hit points) of your target. + -Force: Gives a general indication of the abilities of the target. The basic color gives an indication of the average level of the region where the target is located. The white stars preceded by a figure indicates the strength of the character within the region. Black stars are reserved for Named creatures (1 star) or the Bosses (2 stars).
-
-Average ability level by color: +

Level: Gives a general indication of the abilities of the target. The basic color gives an indication of the average level of the region where the target is located. The white stars preceded by a figure indicates the strength of the character within the region. Black stars are reserved for Named creatures (1 star) or the Bosses (2 stars). + +

Average ability level by color: diff --git a/code/ryzom/client/data/gamedev/html/help/intro_en.html b/code/ryzom/client/data/gamedev/html/help/intro_en.html index db1d76c91..8b05bb02b 100644 --- a/code/ryzom/client/data/gamedev/html/help/intro_en.html +++ b/code/ryzom/client/data/gamedev/html/help/intro_en.html @@ -1,8 +1,8 @@  - Intro + Introduction - +
-
@@ -15,7 +15,7 @@

Contacting Customer Support

- A dedicated team of customer support representatives keep a watchful eye over Atys day and night. They can be contacted via the 'SUPPORT' button in the 'GAME' tab of the button menu on the right hand edge of the screen.
+ A dedicated team of customer support representatives keep a watchful eye over Atys day and night. They can be contacted via the 'SUPPORT' option under the 'HELP' button in the button menu on the right hand edge of the screen.

diff --git a/code/ryzom/client/data/gamedev/html/quick_help/qh_fight_de.html b/code/ryzom/client/data/gamedev/html/quick_help/qh_fight_de.html index 748e6b492..ba8d0690d 100644 --- a/code/ryzom/client/data/gamedev/html/quick_help/qh_fight_de.html +++ b/code/ryzom/client/data/gamedev/html/quick_help/qh_fight_de.html @@ -1,10 +1,10 @@ - +Wie man kämpft - + @@ -12,133 +12,142 @@

- Start by selecting your opponent. To do this, simply click on the character in the scene that you wish to attack. - Once you have done this, your target appears in - this window. + 1. Beginne, indem du deinen Gegner anwählst. Dazu klicke einfach auf den Mob oder den Spieler, den du angreifen möchtest. + Daraufhin erscheinen die Informationen über dein Ziel in + diesem Fenster. + +

- Fortfahren - -
- Continue -

-

- You can also look on the + Werfe auch einen Blick auf den Radar. - This is the green dot. + Das ist der grüne Punkt. -
- Continue - -

+

- Fortfahren - +

-->

- The opponent's direction can also be located using the - Compass. - To do this, do a right click on the - Compass - and select the name of your target. + 2. Die Richtung, in der sich dein Gegner befindet, siehst du ebenso im + Kompass. + Dazu klicke rechts in den + Kompass + und wähle 'Ziel'. + +

- Fortfahren - -
- Continue -

- From here on you can fight. Simply click on - - or do a right click on your mouse and select ATTACK - (this is not always present as not everybody can be attacked). + 3. Du kannst nun den Kampf beginnen. Drücke einfach + , doppeklicke auf dein Ziel oder wähle es mit Rechtsklick an und geh auf ANGREIFEN + (diese Option erscheint nicht immer, da nicht jeder oder alles angreifbar ist). -
- Continue - +

- Fortfahren -

+

- It is now possible to change weapons using this - window. -
- Continue - + 4. Es ist möglich Deine Waffe zu wechseln, und zwar mit Hilfe der + Aktionsleiste. + +

- Fortfahren -

- Do a left click on your mouse on - this button - to display the list of weapons at your disposal. - Note : this list will be empty if you have no weapons. + quick_help_link="ah:context_help&target=ui:interface:gestionsets:hands:handr&text=wtHANDS"> + 5. Klicke links mit der Maus auf + diese Schaltfläche, + + um dir eine Liste der dir zur Verfügung stehenden Waffen anzeigen zu lassen. +

Anmerkung: Diese Liste ist leer, wenn du keine anderen Waffen hast. + +

- Fortfahren - -
- Continue -

- In the same way, you can change your left hand weapon by pressing - HERE. - As above nothing will happen if you have no left hand weapons. + quick_help_link="ah:context_help&target=ui:interface:gestionsets:hands:handl&text=wtHANDS"> + 6. Auf die selbe Weise kannst du die Waffe oder deinen Schild in deiner linken Hand wechseln, indem du + hier klickst. +

Anmerkung: Diese Liste ist leer, wenn du keinen Schild oder keine Waffe für die linke Hand besitzt. + +

- Fortfahren - -
- Continue -

- You can attack using actions other than those proposed by default. - For this you will need to have combat actions memorized in the - Action Window. - There is a singleslot - for each combat action. - The background of the icon for these combat actions is composed of the following image
- combat -
-
- Continue - + 7. Du kannst mit anderen Aktionen angreifen als mit der Standardaktion. + Dazu benötigst du die Kampfaktionen, die im + Aktionsbuch gespeichert sind. + Es gibt einen eigenen Slot + für jede Kampfaktion. + +

- Fortfahren - +

- Check that you have at least one memorized combat action. - If you haven't, then start by memorizing one - (
more info). + 8. Stelle sicher, dass du mindestens eine gespeicherte Kampfaktion hast. + Falls das nicht der Fall ist, erstelle eine und sichere sie. +
(Mehr Informationen.) + +

- Fortfahren - -
- Continue -

-

- Once you have memorized at least one combat action, - just click on it in order to go into combat mode - and activate the combat action in question. - A small icon will appear indicating that the action will be the next to be executed. -
- Continue - +

+ 9. Sobald du mindestens eine Kampfaktion gespeichert hast, + klicke einfach auf sie, um in den Kampfmodus zu gehen + und aktiviere die jeweilige Kampfaktion. + Es wird ein kleines Icon erscheinen, das anzeigt, welche Aktion als nächstes ausgeführt wird. + +

- Fortfahren -

- To cycle the action then just click on it again. - A new icon will appear indicating that this action is activated in cycles - (you can only cycle one action at a time). + 10. Um die Aktion auf Wiederholung zu stellen, doppelklicke auf sie. + Ein neues Icon erscheint, das anzeigt, dass diese Aktion wiederholt durchgeführt wird + (du kannst nur eine Aktion gleichzeitig auf Wiederholung stellen). + +

- Fortfahren - -
- Continue -

+

- Now you know the rudiments of fighting. -
-- Start again -- + Du kennst nun die Grundlagen des Kampfes. +

- Noch einmal starten -

diff --git a/code/ryzom/client/data/gamedev/html/quick_help/qh_fight_en.html b/code/ryzom/client/data/gamedev/html/quick_help/qh_fight_en.html index 748e6b492..7c0f3db3c 100644 --- a/code/ryzom/client/data/gamedev/html/quick_help/qh_fight_en.html +++ b/code/ryzom/client/data/gamedev/html/quick_help/qh_fight_en.html @@ -1,10 +1,10 @@ - +How to Fight - + @@ -12,133 +12,129 @@

- Start by selecting your opponent. To do this, simply click on the character in the scene that you wish to attack. - Once you have done this, your target appears in + 1. Start by selecting your opponent. To do this, simply click on the mob or player that you wish to attack. + Once you have done this, your targets information appears in this window. -
- Continue - +

- Continue -

-

You can also look on the Radar. This is the green dot. -
- Continue - -

+

- Continue - +

-->

- The opponent's direction can also be located using the + 2. Your opponent's direction can be located using the Compass. To do this, do a right click on the Compass - and select the name of your target. + and select 'Target'. -
- Continue - +

- Continue -

- From here on you can fight. Simply click on - - or do a right click on your mouse and select ATTACK - (this is not always present as not everybody can be attacked). + 3. From here on you can fight. Simply press + , double click your target, or right click and select ATTACK + (this is not always present as not everybody or everything can be attacked). -
- Continue - +

- Continue -

- It is now possible to change weapons using this - window. + 4. It is possible to change your weapons using the + action bar. -
- Continue - +

- Continue -

- Do a left click on your mouse on - this button + quick_help_link="ah:context_help&target=ui:interface:gestionsets:hands:handr&text=wtHANDS"> + 5. Left click on your mouse on + this button to display the list of weapons at your disposal. - Note : this list will be empty if you have no weapons. +

Note: this list will be empty if you have no other weapons. -
- Continue - +

- Continue -

- In the same way, you can change your left hand weapon by pressing - HERE. - As above nothing will happen if you have no left hand weapons. + quick_help_link="ah:context_help&target=ui:interface:gestionsets:hands:handl&text=wtHANDS"> + 6. In the same way, you can change the weapon or shield in your left hand weapon by pressing + here. +

Note: this list will be empty if you have no shield or left handed weapons. -
- Continue - +

- Continue -

- You can attack using actions other than those proposed by default. + 7. You can attack using actions other than the default. For this you will need to have combat actions memorized in the Action Window. - There is a singleslot + There is a single slot for each combat action. - The background of the icon for these combat actions is composed of the following image
- combat -
-
- Continue - +

- Continue -

- Check that you have at least one memorized combat action. - If you haven't, then start by memorizing one - (
more info). + 8. Check that you have at least one memorized combat action. + If you haven't, then start by memorizing one. +
(more info) -
- Continue - +

- Continue -

- Once you have memorized at least one combat action, + 9. Once you have memorized at least one combat action, just click on it in order to go into combat mode and activate the combat action in question. A small icon will appear indicating that the action will be the next to be executed. -
- Continue - +

- Continue -

- To cycle the action then just click on it again. + 10. To cycle the action then just double click it. A new icon will appear indicating that this action is activated in cycles (you can only cycle one action at a time). -
- Continue - +

- Continue -

Now you know the rudiments of fighting. -
-- Start again -- +

- Start again -

diff --git a/code/ryzom/client/data/gamedev/html/quick_help/qh_magic_de.html b/code/ryzom/client/data/gamedev/html/quick_help/qh_magic_de.html index 2d0e97370..ed214e347 100644 --- a/code/ryzom/client/data/gamedev/html/quick_help/qh_magic_de.html +++ b/code/ryzom/client/data/gamedev/html/quick_help/qh_magic_de.html @@ -1,10 +1,10 @@ - +Wie man zaubert - + @@ -12,55 +12,45 @@

- Start by selecting a target. This can be you, for example in the case where you need to heal yourself. - To do this, simply click on the character you wish to target in the scene. - Information on your target will appear in - Start by selecting a target. This can be you, for example in the case where you need to heal yourself. - To do this, simply click on the character you wish to target in the scene. - Information on your target will appear in - Start by selecting a target. This can be you, for example in the case where you need to heal yourself. - To do this, simply click on the character you wish to target in the scene. - Information on your target will appear in - - this window - this window - this window - . + 1. Beginne, indem du ein Ziel auswählst. Klicke dazu einfach auf den Mob oder den Spieler. Informationen über dein Ziel erscheinen im + Zielfenster. + +

- Fortfahren - -
- Continue -

- Next make sure that you have memorized a magic action in - this window. - The background of the icon for these magic actions is composed of the following images :
- offensive magic -
- healing magic -
- If you have no magic actions memorized then you will have to memorize one - (
more info). + quick_help_link="ah:context_help&target=ui:interface:gestionsets&text=uimwHands"> + 2. Stelle als nächstes sicher, dass du eine Magie-Aktion in der + Aktionsleiste hast. + Der Hintergrund des Icons für diese Magie-Aktionen setzt sich aus folgenden Bildern zusammen: +
Offensive Magie +
Heilmagie +

Wenn du keine Magie-Aktionen gespeichert hast, musst du welche erlernen. +
(mehr Informationen) + +

- Fortfahren - -
- Continue -

- Now just click one of the magic icons to cast your spell. + quick_help_link="ah:context_help&target=ui:interface:gestionsets:shortcuts:s10&text=uiAction"> + 3. Klicke jetzt auf eine der Magie-Aktionen, um deinen Zauberspruch auf dein Ziel zu sprechen. Sprüche, die auf dich selbst wirken, wie + Selbstheilungen oder Auren, benötigen kein Ziel. -
- Continue - +

- Fortfahren -

- Vous voila pret. -
-- Start again -- + + Du kennst nun die Grundlagen der Verwendung von Magie. +

- Fortfahren -

diff --git a/code/ryzom/client/data/gamedev/html/quick_help/qh_magic_en.html b/code/ryzom/client/data/gamedev/html/quick_help/qh_magic_en.html index 2d0e97370..d3dfe99e7 100644 --- a/code/ryzom/client/data/gamedev/html/quick_help/qh_magic_en.html +++ b/code/ryzom/client/data/gamedev/html/quick_help/qh_magic_en.html @@ -1,10 +1,10 @@ - +How to do Magic - + @@ -12,55 +12,42 @@

- Start by selecting a target. This can be you, for example in the case where you need to heal yourself. - To do this, simply click on the character you wish to target in the scene. - Information on your target will appear in - Start by selecting a target. This can be you, for example in the case where you need to heal yourself. - To do this, simply click on the character you wish to target in the scene. - Information on your target will appear in - Start by selecting a target. This can be you, for example in the case where you need to heal yourself. - To do this, simply click on the character you wish to target in the scene. - Information on your target will appear in - - this window - this window - this window - . + 1. Start by selecting a target. To do this, simply click on the mob or player. Information on your target will appear in the + target gauge. -
- Continue - +

- Continue -

- Next make sure that you have memorized a magic action in - this window. - The background of the icon for these magic actions is composed of the following images :
- offensive magic -
- healing magic -
- If you have no magic actions memorized then you will have to memorize one - (
more info). + quick_help_link="ah:context_help&target=ui:interface:gestionsets&text=uimwHands"> + 2. Next make sure that you have a magic action in + Action Window. + The background of the icon for these magic actions is composed of the following images: +
offensive magic +
healing magic +

If you have no magic actions memorized then you will have to memorize one. +
(more info) -
- Continue - +

- Continue -

- Now just click one of the magic icons to cast your spell. + quick_help_link="ah:context_help&target=ui:interface:gestionsets:shortcuts:s10&text=uiAction"> + 3. Now just click one of the magic icons to cast your spell action on your target. Spells that work on yourself, like + self heals or auras, do not require a target. -
- Continue - +

- Continue -

- Vous voila pret. -
-- Start again -- + You now know the basics of using magic. +

- Start again -

diff --git a/code/ryzom/client/data/gamedev/html/quick_help/qh_motion_de.html b/code/ryzom/client/data/gamedev/html/quick_help/qh_motion_de.html index ee162b32f..ec79a41cf 100644 --- a/code/ryzom/client/data/gamedev/html/quick_help/qh_motion_de.html +++ b/code/ryzom/client/data/gamedev/html/quick_help/qh_motion_de.html @@ -1,64 +1,66 @@ - - +Wie man sich bewegt - + -

1. Um vorwärts zu gehen, drücken Sie '' auf Ihrem Keyboard

+

1. Drücke die ''-Taste auf deiner Tastatur, um dich vorwärts zu bewegen.

-

2. Gut gemacht !
-Drücken Sie jetzt '' um rückwärts zu gehen.

+

2. Gut gemacht! +
Jetzt drücke die ''-Taste, um rückwärts zu laufen.

+ -

3. Um nach links zu biegen, drücken Sie ''

+

3. Drücke die ''-Taste, um dich nach links zu drehen.

-

4. Um nach rechts zu biegen, drücken Sie ''

+

4. Drücke die ''-Taste, um dich nach rechts zu drehen.

-

5. Um nach links zu schießen, drücken Sie ''

+

5. Drücke die ''-Taste, um nach links auszuweichen.

-

6. Um nach rechts zu schießen, drücken Sie ''

+

6. Drücke die ''-Taste, um nach rechts auszuweichen.

-

7. Ausgezeichnet !
-Lernen wir wie man geht oder läuft.
-Drücken Sie '' um den Bewegungsmodus zu ändern. + +

7. Exzellent! +
Kommen wir zum Gehen und Rennen. +
Drücke die ''-Taste, um die Bewegungsart zu ändern.

-

8. Great.
-Sie können den Bewegungsmodus auch ändern indem Sie hier klicken: -this icon.
-Versuchen Sie diese Methode, um zu Ihren vorigen Modus zurück zu kehren. +

8. Großartig. +
Du kannst auch die Bewegungsart ändern, indem du auf +dieses Tab drückst und dann auf +dieses Icon. +
Benutze diese Methode, um zu deiner vorherigen Bewegungsart zurückzuschalten.

-

9. Sehr gut !
-Jetzt lernen wir, wie man sich automatisch bewegt.
-Drücken Sie '' um vorwärts zu gehen, ohne den Key gedrückt zu halten. +

9. Sehr gut! + +
Jetzt zur automatischen Bewegung. +
Drücke die ''-Taste, um vorwärts zu laufen, ohne eine Taste gedrückt zu halten.

-

10. Stop !
-Um stehen zu bleiben, drücken Sie noch Mal ''key again,
-entweder vorwärts gehen (''),
-oder rückwärts (''). +

10. Stop! +
Um anzuhalten, drücke die ''-Taste nochmals, oder bewege dich entweder vorwärts (''), +
oder rückwärts ('').

- + - + -

Gut gemacht, jetzt beherrschen Sie die Basis-Bewegungen !!!

+

Gut gemacht, du kennst nun die Grundlagen der Bewegung!

diff --git a/code/ryzom/client/data/gamedev/html/quick_help/qh_motion_en.html b/code/ryzom/client/data/gamedev/html/quick_help/qh_motion_en.html index a2d9db3f3..8de5989c9 100644 --- a/code/ryzom/client/data/gamedev/html/quick_help/qh_motion_en.html +++ b/code/ryzom/client/data/gamedev/html/quick_help/qh_motion_en.html @@ -1,45 +1,45 @@ - +How to Move - + -

1. Press the '' key on your keyboard to Move Forward.

+

1. Press the '' key on your keyboard to Move Forward.

-

2. Well done !
-Now press the '' key to Move Backwards.

+

2. Well done! +
Now press the '' key to Move Backwards.

-

3. Press the '' key to Turn Left.

+

3. Press the '' key to Turn Left.

-

4. Press the '' key to turn right.

+

4. Press the '' key to turn right.

-

5. Press the '' key to Strafe Left.

+

5. Press the '' key to Strafe Left.

-

6. Press the '' key to Strafe Right.

+

6. Press the '' key to Strafe Right.

-

7. Excellent !
-Let's learn how to walk or run.
-Press the '' key to change the movement mode. +

7. Excellent! +
Let's learn how to walk or run. +
Press the '' key to change the movement mode.

-

8. Great.
-You can also change the movement mode by clicking on -this icon.
-Try this method to return to your previous movement mode. +

8. Great. +
You can also change the movement mode by clicking on +this tab and then on +this icon. +
Try this method to return to your previous movement mode.

-

9. Very good !
-Now let's learn how to move automatically.
-Press the '' key to start moving forward without keeping the key pressed down. +

9. Very good! +
Now let's learn how to move automatically. +
Press the '' key to start moving forward without keeping the key pressed down.

-

10. Stop !
-To stop, press the ''key again,
-either move forward (''),
-or move backward (''). +

10. Stop! +
To stop, press the '' key again, either move forward (''), +
or move backward ('').

@@ -57,7 +57,7 @@ or move backward ('').

--> -

Well done, now you know the basic movements !!!

+

Well done, you now know the basic movements!

diff --git a/code/ryzom/client/data/gamedev/html/quick_help/qh_orientation_en.html b/code/ryzom/client/data/gamedev/html/quick_help/qh_orientation_en.html index 43b384225..8510b3d70 100644 --- a/code/ryzom/client/data/gamedev/html/quick_help/qh_orientation_en.html +++ b/code/ryzom/client/data/gamedev/html/quick_help/qh_orientation_en.html @@ -1,9 +1,9 @@ - +How to Get Your Bearings - + @@ -11,30 +11,30 @@

- The indicated window is your - Compass. - By default the arrow indicates when it points towards the top. - Click on it with the right button of your mouse to display the menu. + 1. Your compass is at the top right of your screen. + By default the arrow indicates where North is. + Right click on it to display the menu. -
- Continuer - +

- Continue -

- Several choices appear such as the direction of your departure point (home) or the direction of your target. - Additionally, the direction of certain villages are shown below the separator. - In all cases, whichever destination you choose your - Compass - to indicate, the arrow must be oriented towards the top of the screen for you to get there. + 2. Several choices appear, such as the direction of your target, your pet animals or your landmarks. + Additionally, the direction of mission location, or team members can be selected. -
- Continue - +

In all cases, whichever destination you choose your + compass + to indicate, the arrow must be oriented towards the top of the screen for you to be heading in the right direction. + +

- Continue -

-
-- Start again -- +
- Start again -

diff --git a/code/ryzom/client/data/gamedev/html/quick_help/qh_profession_en.html b/code/ryzom/client/data/gamedev/html/quick_help/qh_profession_en.html index 4e31220e7..5b2387560 100644 --- a/code/ryzom/client/data/gamedev/html/quick_help/qh_profession_en.html +++ b/code/ryzom/client/data/gamedev/html/quick_help/qh_profession_en.html @@ -8,6 +8,6 @@

step1...>

step2...>

step3...>

-

Success!!!>

+

Success!>

\ No newline at end of file diff --git a/code/ryzom/client/data/gamedev/html/quick_help/qh_windows_en.html b/code/ryzom/client/data/gamedev/html/quick_help/qh_windows_en.html index 83149dbcb..ecc9fc08d 100644 --- a/code/ryzom/client/data/gamedev/html/quick_help/qh_windows_en.html +++ b/code/ryzom/client/data/gamedev/html/quick_help/qh_windows_en.html @@ -1,71 +1,77 @@ - +How to Use Windows - +

-1. We are going to take a quick look at the main windows of the game and go over their functions.
-Click here to continue. +1. We are going to take a quick look at the main windows of the game and go over their functions. + +

Click here to continue.

-2. This is the window bar.
-This is a direct link to basic actions, windows and game configuration (more info).
-Click here to continue. +2. This is the windows bar. +
This is a direct link to basic actions, windows and game configuration. +
(more info) + +

Click here to continue.

3. This is your -main communication window.
-It is through this window that you will be able to communicate with the world.
-This is also where you will get feedback.
-If you right click on a tab the window will be detached.
-Click here to continue. +main chat window. +
It is through this window that you will be able to communicate with the world. +
This is also where you will get feedback. +
If you right click on a tab the window will be detached. + +

- Continue -.

-4. The -player window -gives information on your state (life points, stamina, etc.) as well as your current action.
-Click here to continue. +4. The gauges window +gives information about your state (life points, stamina, etc.) as well as your current action. + +

- Continue -.

-5. The -window of your target -gives some information on the state of your target such as name and life points.
-Click here to continue. +5. The target gauge +gives some information on the state of your target such as name and life points. + +

- Continue -.

6. The compass indicates North when the arrow points towards the top of the screen. It can also indicate other directions such as that of your target. -It allows you to locate people or creatures around you.
-Click here to continue. +It allows you to locate people or creatures around you. + +

- Continue -.

-7. The hands interface -shows you the items you are holding along with their corresponding memorized actions.
-Click here to continue. +7. The action bar +shows you the items you are holding along with their corresponding memorized actions. + +

- Continue -.

--- The End --
-Start again
-

+-- The End -- +

- Start again - +

diff --git a/code/ryzom/client/data/gamedev/html/quick_help/qh_windowsbar_en.html b/code/ryzom/client/data/gamedev/html/quick_help/qh_windowsbar_en.html index bf385b97f..1209cd8bb 100644 --- a/code/ryzom/client/data/gamedev/html/quick_help/qh_windowsbar_en.html +++ b/code/ryzom/client/data/gamedev/html/quick_help/qh_windowsbar_en.html @@ -1,75 +1,77 @@ - +How to Use Windows - +

1. Tutorial to learn the functions of the -Windows Bar.
-- Continue - +Windows Bar. +
- Continue -

2. The Cross -is for leaving the game (more info).
-- Continue - +is for leaving the game +
(more info). +

- Continue -

3. The question mark -gives access to help files (more info).
-- Continue - +gives access to help files. +
(more info) +

- Continue -

4. The window icon -gives access to a list of game windows.
-- Continue - +gives access to a list of game windows. +

- Continue -

5. The computer icon -gives access to the game configuration window.
-- Continue - +gives access to the game configuration window. +

- Continue -

6. The desktops button -allows you to switch between your 4 desktops.
-- Continue - +allows you to switch between your 4 desktops. +

- Continue -

7. The move/stop button -is to toggle between moving and stoping.
-- Continue - +is to toggle between moving and stoping. +

- Continue -

8. Button -for changing movement mode between walking and running -(more info).
-- Continue - +for changing movement mode between walking and running. +
(more info) +

- Continue -

@@ -77,40 +79,40 @@ for changing movement mode between walking and running

9. The stand/sit button -is to toggle between sitting and standing.
-- Continue - +is to toggle between sitting and standing. +

- Continue -

10. The talk button -is to talk to the person you're targeting.
-- Continue - +is to talk to the person you're targeting. +

- Continue -

11. The fight button -is to attack/disengage your target.
-- Continue - +is to attack/disengage your target. +

- Continue -

12. The extract button -is to extract MPs from the source you're targeting.
-- Continue - +is to extract MPs from the source you're targeting. +

- Continue -

13. The team button -allows you to invite or kick someone from your team or to disband.
-- Continue - +allows you to invite or kick someone from your team or to disband. +

- Continue -

@@ -128,9 +130,9 @@ If an icon appears here, it means that the connection with the server is faulty.

--- The End --
-Start again
-

+-- The End -- +

- Start again - +

diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/bot_chat_v4.xml b/code/ryzom/client/data/gamedev/interfaces_v3/bot_chat_v4.xml index 6697f8151..4efed8d2f 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/bot_chat_v4.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/bot_chat_v4.xml @@ -4432,6 +4432,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4445,4 +4488,5 @@ + diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/commands.xml b/code/ryzom/client/data/gamedev/interfaces_v3/commands.xml index 594184805..ca013f242 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/commands.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/commands.xml @@ -78,6 +78,8 @@ + + diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/compass.xml b/code/ryzom/client/data/gamedev/interfaces_v3/compass.xml index 0acff5c5a..7ff4b026a 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/compass.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/compass.xml @@ -564,13 +564,36 @@ posref="BR BR" texture="Compas_R.tga" /> + + + + + + y="42"> + x="-20" + y="22"> + @@ -2785,6 +2788,12 @@ This MUST follow the Enum MISSION_DESC::TIconId + + + + @@ -3608,6 +3623,8 @@ This MUST follow the Enum MISSION_DESC::TIconId value="iapd.sitem" /> + @@ -3627,9 +3644,13 @@ This MUST follow the Enum MISSION_DESC::TIconId - + diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/game_config.xml b/code/ryzom/client/data/gamedev/interfaces_v3/game_config.xml index d3e22e986..f15f3adc9 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/game_config.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/game_config.xml @@ -1341,6 +1341,14 @@ posparent="opamin" x="-20" y="-12" /> + + + + + + + + @@ -96,7 +97,6 @@ - diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/guild.xml b/code/ryzom/client/data/gamedev/interfaces_v3/guild.xml index 3b0879574..3ecd0f746 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/guild.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/guild.xml @@ -33,6 +33,10 @@ + + + @@ -40,6 +44,8 @@ id="menu_member" extends="base_menu" on_active="guild_member_menu_open"> + + @@ -71,6 +77,8 @@ h="#h" posparent="#posparent" posref="#posref" + group_onclick_l="proc" + group_params_l="guild_tell_member_proc" group_onclick_r="active_menu" group_params_r="menu=ui:interface:menu_member"> + + + = 60) then + bar.color = "255 0 0 255" + bar.w = "368" + t.hardtext = i18n.get("uiRpjobMaxLevel"):toUtf8() + t.color = "255 255 0 255" + else + bar.color = tostring(math.floor((105*quantity)/maxlevel)).." "..tostring(100+math.floor((155*quantity)/maxlevel)).." "..tostring(math.floor((105*quantity)/maxlevel)).." 255" + bar.w = tostring((368*quantity)/maxlevel) + t.hardtext = tostring(quantity).." / "..tostring(maxlevel) + t.color = tostring(255*math.floor(3*(maxlevel-quantity)/maxlevel)).." "..tostring(255*math.floor(3*(maxlevel-quantity)/maxlevel)).." "..tostring(255*math.floor(3*(maxlevel-quantity)/maxlevel)).." 255" + end end end end diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/info_player.xml b/code/ryzom/client/data/gamedev/interfaces_v3/info_player.xml index 07c1b97be..d8a5105c4 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/info_player.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/info_player.xml @@ -3421,7 +3421,7 @@ - + @@ -3433,23 +3433,28 @@ - + group_params_r="menu=ui:interface:base_menu_with_color" + on_active="lua" on_active_params="game:closeNpcWebBrowserHeader()"> + + group_params_r="menu=ui:interface:base_menu_with_color" + on_active="lua" on_active_params="game:openNpcWebBrowserHeader()"> + + + + + + + + + + + @@ -316,7 +380,8 @@ tooltip="uittTargetHp" tooltip_parent="win" /> - + + @@ -888,11 +953,11 @@ textid="SERVER:DYN_CHAT:CHANNEL#nb:NAME" dynamic_string="true" onclick_r="set" - params_r="dblink=UI:VARIABLES:DYNAMIC_CHAT#nb:WANT_POPUP|value=1" + params_r="dblink=UI:SAVE:ISDETACHED:DYNAMIC_CHAT#nb|value=1" onclick_l="chat_group_filter" params_l="dyn_chat#nb" /> - @@ -1852,44 +1917,70 @@ id="main_chat_source_menu" extends="base_menu_with_color"> - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -3046,8 +3137,8 @@ target="cant_write_ebw:active" /> - @@ -3055,6 +3146,6 @@ + params="dblink=UI:SAVE:ISDETACHED:DYNAMIC_CHAT@0|value=0" /> diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/widgets.xml b/code/ryzom/client/data/gamedev/interfaces_v3/widgets.xml index 161e7c825..83d5b336e 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/widgets.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/widgets.xml @@ -330,6 +330,18 @@ y="" texture="target.tga" global_color="false" /> +