diff --git a/code/nel/tools/3d/CMakeLists.txt b/code/nel/tools/3d/CMakeLists.txt index 412ef130c..7c0d02fec 100644 --- a/code/nel/tools/3d/CMakeLists.txt +++ b/code/nel/tools/3d/CMakeLists.txt @@ -46,6 +46,7 @@ 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/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..abaa6fc30 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/CMakeLists.txt @@ -0,0 +1,71 @@ +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 + ${PLATFORM_LINKFLAGS} + ${LIBXML2_LIBRARIES} + ${PNG_LIBRARIES} + ${FREETYPE_LIBRARY} + ${JPEG_LIBRARY} + nelmisc + nel3d + nelsound + nelsnd_lowlevel + 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..474f7a929 --- /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..eba33d564 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/callback.h @@ -0,0 +1,320 @@ +/* + * 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 +#include + +// 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..4099f03fa --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/edit_range_widget.cpp @@ -0,0 +1,363 @@ +/* + 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) +{ + if (_emit) + Q_EMIT valueChanged(value); + + // NeL wrapper + if (_Wrapper == NULL) return; + if (_Wrapper->get() == uint32(value)) return; + _Wrapper->setAndUpdateModifiedFlag(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) +{ + if (_emit) + Q_EMIT valueChanged(value); + + // NeL wrapper + if (_Wrapper == NULL) return; + if (_Wrapper->get() == sint32(value)) return; + _Wrapper->setAndUpdateModifiedFlag(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); + if (_emit) + Q_EMIT valueChanged(newValue); + + // NeL wrapper + if (_Wrapper == NULL) return; + if (fabs(newValue - _Wrapper->get()) < 0.0001) return; + _Wrapper->setAndUpdateModifiedFlag(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..af73d1531 --- /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: + + + + + + + + + + + + + + + + Use hermitte interpolation + + + + + + + Non parametric anim only + + + Force constant length + + + + + + + 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::CEditRangeUIntWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CEditRangeFloatWidget + QWidget +
edit_range_widget.h
+ 1 +
+ + NLQT::CAttribFloatWidget + QGroupBox +
attrib_widget.h
+ 1 +
+ + NLQT::CParticleTextureWidget + QWidget +
particle_texture_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..b5c67c8a2 --- /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.alignCheckBox, 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..f63d2ead4 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/located_page.cpp @@ -0,0 +1,264 @@ +/* + 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->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..70b80360b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/mesh_form.ui @@ -0,0 +1,87 @@ + + + CMeshWidget + + + + 0 + 0 + 195 + 114 + + + + GroupBox + + + + + + + + + Shape: + + + + + + + true + + + + + + + Browse + + + + + + + Shape not loaded + + + false + + + false + + + 1 + + + + + + + + + + + + + Morph + + + + + + + false + + + Edit + + + + + + + + + + + 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..f84ff703c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/mesh_widget.cpp @@ -0,0 +1,205 @@ +/* + 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); + + 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); + _ui.editPushButton->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..9756fb7b0 --- /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())); + + 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..357b1ac5d --- /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..f512eaeac --- /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..7a2a095f0 --- /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 + + + + Force global lighting + + + + + + + + 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 + + + + + + + Max view dist: + + + + + + + + + + LOD Ratio: + + + + + + + + + + Qt::Vertical + + + + 20 + 132 + + + + + + + + + Global color + + + + + + + + + + + + + + + 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 + + + + + + + + + + Sharable + + + + + + + Auto-LOD + + + + + + + false + + + + 0 + 0 + + + + + 53454 + 16777215 + + + + Settings + + + + + + + + + + + + + + + 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..453868813 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_anim_form.ui @@ -0,0 +1,110 @@ + + + CParticleTextureAnimWidget + + + + 0 + 0 + 306 + 186 + + + + Form + + + + + + Enable texture animation + + + + + + + + 0 + 0 + + + + + + + + + + Multitexturing + + + + + + + false + + + Edit + + + + + + + + + + true + + + Texture grouped + + + true + + + + + + + + + + + + + + NLQT::CAttribIntWidget + QWidget +
attrib_widget.h
+ 1 +
+ + NLQT::CParticleTextureWidget + QWidget +
particle_texture_widget.h
+ 1 +
+
+ + + + multitexturingCheckBox + toggled(bool) + editPushButton + setEnabled(bool) + + + 81 + 46 + + + 129 + 56 + + + + +
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..243304250 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_anim_widget.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_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; + + _ui.texAnimCheckBox->blockSignals(true); + + 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(); + + _ui.texAnimCheckBox->blockSignals(false); +} + +void CParticleTextureAnimWidget::setEnabledTexAnim(bool state) +{ + if (state) + { + // 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.textureGroupedPushButton->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..564bfe7c7 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_texture_form.ui @@ -0,0 +1,107 @@ + + + CParticleTextureWidget + + + + 0 + 0 + 191 + 162 + + + + Form + + + + + + + 100 + 100 + + + + + 100 + 100 + + + + true + + + + + 0 + 0 + 94 + 94 + + + + + + + + 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..99db046a6 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/particle_workspace_dialog.cpp @@ -0,0 +1,767 @@ +/* + 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; + } + 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..4f40c50ae --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/stdpch.h @@ -0,0 +1,176 @@ +/* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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..f6f9e4b19 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/tail_form.ui @@ -0,0 +1,131 @@ + + + CTailParticleWidget + + + + 0 + 0 + 243 + 107 + + + + Form + + + + + + Tail fading + + + + + + + false + + + Tail persist after death + + + + + + + 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 + + + + + + + + + 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..2f4e4ff9f --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/tail_particle_widget.cpp @@ -0,0 +1,144 @@ +/* + 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.tailPersistAfterDeathCheckBox, SIGNAL(toggled(bool)), this, SLOT(setPersistAfterDeath(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.tailPersistAfterDeathCheckBox->hide(); + _ui.tailShapeComboBox->hide(); + } + else + { + _ui.pathWidget->show(); + _ui.ribbonOrientationComboBox->show(); + _ui.tailPersistAfterDeathCheckBox->show(); + _ui.tailShapeComboBox->show(); + NL3D::CPSRibbon *r = dynamic_cast(_TailParticle); +// _ui.tailPersistAfterDeathCheckBox = (r->getPersistAfterDeath(); + _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::setPersistAfterDeath(bool state) +{ + nlassert(dynamic_cast(_TailParticle)); +// (dynamic_cast(_TailParticle))->setPersistAfterDeath(state); +} + +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..a5f868cd6 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/tail_particle_widget.h @@ -0,0 +1,66 @@ +/* + 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 setPersistAfterDeath(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..02e4ae1d7 --- /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(tr("Dialog")); + _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..5d109857d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/value_gradient_dialog.h @@ -0,0 +1,444 @@ +/* + 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; + + /// 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); + } + + /// 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 void setCurrentIndex(uint index) + { + _CurrentEditedIndex = index; + editWidget->updateUi(); + } + + virtual void displayValue(uint index, QListWidgetItem *item) + { + item->setText(QString("%1").arg(Scheme->getValue(index))); + } + + 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 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 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 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)").arg(color.R).arg(color.G).arg(color.B)); + 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 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 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 + + + + + + + + + + +