diff --git a/direct/src/interval/FunctionInterval.py b/direct/src/interval/FunctionInterval.py index 8f84ca9df8..db626c404e 100644 --- a/direct/src/interval/FunctionInterval.py +++ b/direct/src/interval/FunctionInterval.py @@ -77,7 +77,10 @@ class FunctionInterval(Interval.Interval): @staticmethod def makeUniqueName(func, suffix = ''): - name = 'Func-%s-%d' % (getattr(func, '__name__', str(func)), FunctionInterval.functionIntervalNum) + func_name = getattr(func, '__name__', None) + if func_name is None: + func_name = str(func) + name = 'Func-%s-%d' % (func_name, FunctionInterval.functionIntervalNum) FunctionInterval.functionIntervalNum += 1 if suffix: name = '%s-%s' % (name, str(suffix)) diff --git a/doc/INSTALLING-PLUGINS.TXT b/doc/INSTALLING-PLUGINS.TXT deleted file mode 100644 index 994e164936..0000000000 --- a/doc/INSTALLING-PLUGINS.TXT +++ /dev/null @@ -1,20 +0,0 @@ -HOW TO INSTALL MAX PANDA PLUGINS. - -Step 1. Install the visual studio 2008 runtime by -running "vcredist_x86-sp1.exe" as administrator. -As a convenience, this installer is included with panda. - -Step 2. Make sure that there is only one copy of panda -in your system PATH. If you only have one copy of panda -installed, you can skip this step. - -Step 3. Copy the relevant DLLs for your version -of max from the panda plugins directory to the -max plugins directory. For instance, if you are -using Max 9, copy maxegg9.dlo and maxeggimport9.dlo - -HOW TO INSTALL MAYA PANDA PLUGINS. - -(To be written) - - diff --git a/doc/InstallerNotes b/doc/InstallerNotes deleted file mode 100644 index cf57b15cc1..0000000000 --- a/doc/InstallerNotes +++ /dev/null @@ -1,183 +0,0 @@ ------------------------- RELEASE 1.0.0 --------------------------------- - - * We now have working exporters for Max5, Max6, Max7, Maya5, Maya6 - - * The Max exporter is dramatically improved: - - - it now includes support for character studio. - - the polygon winding bug has been fixed. - - * Panda no longer requires any registry keys or environment - variables. This means it is now possible to: - - - run panda directly from a compact disc - - install multiple copies of panda on a single machine - - install panda by copying the tree from another computer - - Note that the installer does add the panda 'bin' directory to - your PATH, and it does store an uninstall key in the registry, - but neither of these is needed for panda to function. - - * The 'makepanda' build system is now capable of building - prepackaged games for Windows. These prepackaged games are simply - copies of panda with the game code included, some of the - unnecessary stuff stripped out, and some changes to the start - menu. See "Airblade - Installer" on the panda downloads page - for an example. - - * All of the sample programs have been tested. The ones that didn't - work have been removed, the ones that do work have been (lightly) - documented. - - * This is the first release to include not just a binary installer - for windows, but: - - - a binary installer (RPM) for Fedora 2 - - a binary installer (RPM) for Fedora 3 - - a binary installer (RPM) for Redhat 9 - - a binary installer for windows, as always - - a source tar-ball for linux - - a source zip-file for windows - ------------------------- RELEASE 2004-12-13 --------------------------------- - - * Basic server-client networking support is back in Panda3D. There is a - networking sample in the samples directory. This uses the Panda3d - distributed object system.The README file will explain how to run this. - Documentation of this if forthcoming. - - * Panda3d now reduces the number of environment variables such that only 2 - are needed now - PRC_PATH and PLAYER. - - * GraphicsChannel and GraphicsLayer class have been removed from the - panda/src/display directory. Most Panda applications won't need to be - changed, since most applications simply use ShowBase.py (which has been - adjustedappropriately) to open a window and do the initial setup. For - those rare applications where you need to create your own DisplayRegions, - the makeDisplayRegion() interface has been moved from GraphicsLayer to - GraphicsWindow (actually, to GraphicsOutput, which is the base class of - GraphicsWindow). You can modify your application to call - base.win.makeDisplayRegion() accordingly. If you have something like - displayRegion.getLayer(), replace it with displayRegion.getWindow() - instead. - - * Effective with the current version of Panda, the way that HPR angles are - calculated will be changing. The change will make a difference to existing - code or databases that store a hard-coded rotation as a HPR, but only when - R is involved, or both H and P are involved together. That is to say more - precisely, HPR angles with (R != 0 || (H != 0 && P != 0)) now represent a - different rotation than they used to. If you find some legacy code that no - longer works correctly (e.g. it introduces crazy rotations), try putting - the following in your Config.prc file: - - temp-hpr-fix 0 - - To turn off the correct behavior and return to the old, broken behavior. - Note that a longer-term solution will be to represent the HPR angles - correctly in all legacy code. The function oldToNewHpr() is provided to - aid this transition. - - * PandaNode definition has been changed to support setting an - into_collide_mask for any arbitrary node, in particular for any GeomNode. - It used to be that only CollisionNodes had an into_collide_mask. This - change obviates the need for CollisionNode::set_collide_geom(), which is - now a deprecated interface and will be removed at some point in the future. - - Details: - There's now a NodePath::set_collide_mask() and - NodePath::get_collide_mask(), which operate on all CollisionNodes and - GeomNodes at and below the current node. By default, set_collide_mask() - will replace the entire collide mask, but you may also specify (via a - second parameter) the subset of bits that are to be changed; other bits - will be left alone. You can also specify a particular type of node to - modify via a third parameter, e.g. you can adjust the masks for GeomNodes - or CollisionNodes only. - - The NodePath set_collide_mask() interface changes the into_collide_mask. - Those familiar with the collision system will recall that a CollisionNode - (but only a CollisionNode) also has a from_collide_mask. The - from_collide_mask of the active mover is compared with the into_collide_mask - of each object in the world; a collision is only possible if there are some - bits in common. - - It used to be that only other CollisionNodes had an into_collide_mask. A - mover would only test for collisions with CollisionNodes that matched its - collide_mask. If you wanted to make your mover detect collisions with - visible geometry which had no into_collide_mask, you had to call - set_collide_geom(1). This allowed the mover to detect collisions with *all* - visible geometry; it was either an all-or-none thing. - - Now that GeomNodes also have an into_collide_mask, there's no longer a need - for set_collide_geom(). A mover will detect collisions with any - CollisionNodes or GeomNodes that match its collide_mask. This means, for - the purposes of collision detection, you can use CollisionNodes and - GeomNodes pretty much interchangeably; simply set the appropriate bits on - the objects you want to collide with, regardless of whether they are - invisible collision solids or visible geometry. - - (This should not be taken as a license to avoid using CollisionNodes - altogether. The intersection computation with visible geometry is still - less efficient than the same computation with collision solids. And visible - geometry tends to be many times more complex than is strictly necessary for - collisions.) - - There's one more detail: every GeomNode, by default, has one bit set on in - its collide_mask, unless it is explicitly turned off. This bit is - GeomNode::get_default_collide_mask(). This bit is provided for the - convenience of programmers who still want the old behavior of - set_collide_geom(): it allows you to easily create a CollisionNode that - will collide with all visible geometry in the world. - - Along the same lines, there's also CollisionNode::get_default_collide_mask(), - which is 0x000fffff. This is the default mask that is created for a new - CollisionNode (and it does not include the bit reserved for GeomNodes, - above). Previously, a new CollisionNode would have all bits on by default. - - - ------------------------- RELEASE 2004-11-11 ----------------------------------- - - * Multiple mice can now be used with Panda3D. showbase has a list called - pointerWatcherNodes. The first mouse on this list is the system mouse. The - getMouseX() and getMouseY() will return coordinates relative to the - application window. The rest of the mice on the list will give raw mouse - positions and will change when they are moved on the screen. - - In addition there are new events for mouse buttons. Each mouse will be have - a corresponding event. mouse1 will send mousedev1-mouse1, mousedev1-mouse2 - and mousedev1-mouse3 events. mouse2 and any other mouse attached - will send similar events mousedev2-mouse1 etc. - - The old mouse buttons work too. mouse1, mouse2, mouse3 events will be - triggered if that button is pressed on any mouse - ------------------------- RELEASE 2004-10-13 ----------------------------------- - -General - - * Release notes: Each release will now have an entry associated with - it in this document. This will be updated in reverse-chronological order. - -Panda3D - * Distributed with this release is a working version of the SceneEditor - created in Spring 2004 at the ETC. Documentation will be forthcoming on the - website. This can be found in /SceneEditor - - * The latest version of FMOD is distributed with this release. The latest - version is 3.73. - - * AudioSound object now allows more types of sound. These include wma and - ogg vorbis formats. This is valid when using the fmod sound system. Midi, - Mod, s3m, it, xm and such sequencer type file formats are not supported. - Exception - Midi files can be played. This is not fully implemented. - - * A bug in SoundInterval is fixed. SoundInterval looping would incorrectly - add a minimum of 1.5 seconds to the sound. This has been fixed. Sound - looping problems in general should be fixed. Midi's still don't support - looping through the AudioSound object. They should loop through - SoundIntervals though. - - * Cg support has been added to Panda3D. Documentation for this is - forthcoming. - - diff --git a/dtool/src/cppparser/cppStructType.cxx b/dtool/src/cppparser/cppStructType.cxx index d0707c4404..745abab586 100644 --- a/dtool/src/cppparser/cppStructType.cxx +++ b/dtool/src/cppparser/cppStructType.cxx @@ -306,7 +306,6 @@ is_trivial() const { } // Now look for functions that are virtual or con/destructors. - bool is_default_constructible = true; CPPScope::Functions::const_iterator fi; for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) { CPPFunctionGroup *fgroup = (*fi).second; @@ -343,9 +342,6 @@ is_trivial() const { // Same for the default constructor. return false; } - // The presence of a non-default constructor makes the class not - // default-constructible. - is_default_constructible = false; } if (fgroup->_name == "operator =") { @@ -356,7 +352,7 @@ is_trivial() const { } // Finally, the class must be default-constructible. - return is_default_constructible; + return is_default_constructible(V_public); } /** diff --git a/dtool/src/dtoolbase/dtoolbase.cxx b/dtool/src/dtoolbase/dtoolbase.cxx index a45a1de4e0..3bd34815c9 100644 --- a/dtool/src/dtoolbase/dtoolbase.cxx +++ b/dtool/src/dtoolbase/dtoolbase.cxx @@ -62,4 +62,12 @@ default_thread_consider_yield() { void (*global_thread_yield)() = default_thread_yield; void (*global_thread_consider_yield)() = default_thread_consider_yield; +#ifdef HAVE_PYTHON +static PyThreadState * +default_thread_state_swap(PyThreadState *state) { + return nullptr; +} +PyThreadState *(*global_thread_state_swap)(PyThreadState *tstate) = default_thread_state_swap; +#endif // HAVE_PYTHON + #endif // HAVE_THREADS && SIMPLE_THREADS diff --git a/dtool/src/dtoolbase/dtoolbase.h b/dtool/src/dtoolbase/dtoolbase.h index f21e653695..2f8e7ca05d 100644 --- a/dtool/src/dtoolbase/dtoolbase.h +++ b/dtool/src/dtoolbase/dtoolbase.h @@ -63,8 +63,10 @@ /* Windows likes to define min() and max() macros, which will conflict with std::min() and std::max() respectively, unless we do this: */ #ifdef WIN32 +#ifndef NOMINMAX #define NOMINMAX #endif +#endif #ifndef __has_builtin #define __has_builtin(x) 0 diff --git a/dtool/src/dtoolbase/dtoolbase_cc.h b/dtool/src/dtoolbase/dtoolbase_cc.h index 36da6b2b0b..8894469422 100644 --- a/dtool/src/dtoolbase/dtoolbase_cc.h +++ b/dtool/src/dtoolbase/dtoolbase_cc.h @@ -233,6 +233,15 @@ INLINE void thread_consider_yield() { (*global_thread_consider_yield)(); } +#ifdef HAVE_PYTHON +typedef struct _ts PyThreadState; +extern EXPCL_DTOOL_DTOOLBASE PyThreadState *(*global_thread_state_swap)(PyThreadState *tstate); + +INLINE PyThreadState *thread_state_swap(PyThreadState *tstate) { + return (*global_thread_state_swap)(tstate); +} +#endif // HAVE_PYTHON + #else INLINE void thread_yield() { diff --git a/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx b/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx index 89a0ebcc30..2cd825ff58 100644 --- a/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx +++ b/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx @@ -1,2 +1,3 @@ #include "filename_ext.cxx" #include "globPattern_ext.cxx" +#include "textEncoder_ext.cxx" diff --git a/dtool/src/dtoolutil/stringDecoder.I b/dtool/src/dtoolutil/stringDecoder.I index f7a3b14701..ce128833d0 100644 --- a/dtool/src/dtoolutil/stringDecoder.I +++ b/dtool/src/dtoolutil/stringDecoder.I @@ -53,5 +53,5 @@ StringUtf8Decoder(const std::string &input) : StringDecoder(input) { * */ INLINE StringUnicodeDecoder:: -StringUnicodeDecoder(const std::string &input) : StringDecoder(input) { +StringUtf16Decoder(const std::string &input) : StringDecoder(input) { } diff --git a/dtool/src/dtoolutil/stringDecoder.cxx b/dtool/src/dtoolutil/stringDecoder.cxx index e77e0c5e13..f9ecfdecd3 100644 --- a/dtool/src/dtoolutil/stringDecoder.cxx +++ b/dtool/src/dtoolutil/stringDecoder.cxx @@ -26,7 +26,7 @@ StringDecoder:: /** * Returns the next character in sequence. */ -int StringDecoder:: +char32_t StringDecoder:: get_next_character() { if (test_eof()) { return -1; @@ -57,19 +57,20 @@ get_notify_ptr() { /* In UTF-8, each 16-bit Unicode character is encoded as a sequence of -one, two, or three 8-bit bytes, depending on the value of the +one, two, three or four 8-bit bytes, depending on the value of the character. The following table shows the format of such UTF-8 byte sequences (where the "free bits" shown by x's in the table are combined in the order shown, and interpreted from most significant to least significant): Binary format of bytes in sequence: - Number of Maximum expressible - 1st byte 2nd byte 3rd byte free bits: Unicode value: + Number of Maximum expressible + 1st byte 2nd byte 3rd byte 4th byte free bits: Unicode value: - 0xxxxxxx 7 007F hex (127) - 110xxxxx 10xxxxxx (5+6)=11 07FF hex (2047) - 1110xxxx 10xxxxxx 10xxxxxx (4+6+6)=16 FFFF hex (65535) + 0xxxxxxx 7 007F hex (127) + 110xxxxx 10xxxxxx (5+6)=11 07FF hex (2047) + 1110xxxx 10xxxxxx 10xxxxxx (4+6+6)=16 FFFF hex (65535) + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (4+6*3)=21 10FFFF hex (1114111) The value of each individual byte indicates its UTF-8 function, as follows: @@ -77,12 +78,13 @@ The value of each individual byte indicates its UTF-8 function, as follows: 80 to BF hex (128 to 191): continuing byte in a multi-byte sequence. C2 to DF hex (194 to 223): first byte of a two-byte sequence. E0 to EF hex (224 to 239): first byte of a three-byte sequence. + F0 to F7 hex (240 to 247): first byte of a four-byte sequence. */ /** * Returns the next character in sequence. */ -int StringUtf8Decoder:: +char32_t StringUtf8Decoder:: get_next_character() { unsigned int result; while (!test_eof()) { @@ -125,6 +127,35 @@ get_next_character() { unsigned int three = (unsigned char)_input[_p++]; result = ((result & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f); return result; + + } else if ((result & 0xf8) == 0xf0) { + // First byte of four. + if (test_eof()) { + if (_notify_ptr != nullptr) { + (*_notify_ptr) + << "utf-8 encoded string '" << _input << "' ends abruptly.\n"; + } + return -1; + } + unsigned int two = (unsigned char)_input[_p++]; + if (test_eof()) { + if (_notify_ptr != nullptr) { + (*_notify_ptr) + << "utf-8 encoded string '" << _input << "' ends abruptly.\n"; + } + return -1; + } + unsigned int three = (unsigned char)_input[_p++]; + if (test_eof()) { + if (_notify_ptr != nullptr) { + (*_notify_ptr) + << "utf-8 encoded string '" << _input << "' ends abruptly.\n"; + } + return -1; + } + unsigned int four = (unsigned char)_input[_p++]; + result = ((result & 0x07) << 18) | ((two & 0x3f) << 12) | ((three & 0x3f) << 6) | (four & 0x3f); + return result; } // Otherwise--the high bit is set but it is not one of the introductory @@ -144,7 +175,7 @@ get_next_character() { /** * Returns the next character in sequence. */ -int StringUnicodeDecoder:: +char32_t StringUtf16Decoder:: get_next_character() { if (test_eof()) { return -1; @@ -159,5 +190,33 @@ get_next_character() { return -1; } unsigned int low = (unsigned char)_input[_p++]; - return ((high << 8) | low); + int ch = ((high << 8) | low); + + /* + using std::swap; + + if (ch == 0xfffe) { + // This is a byte-swapped byte-order-marker. That means we need to swap + // the endianness of the rest of the stream. + char *data = (char *)_input.data(); + for (size_t p = _p; p < _input.size() - 1; p += 2) { + std::swap(data[p], data[p + 1]); + } + ch = 0xfeff; + } + */ + + if (ch >= 0xd800 && ch < 0xdc00 && (_p + 1) < _input.size()) { + // This is a high surrogate. Look for a subsequent low surrogate. + unsigned int high = (unsigned char)_input[_p]; + unsigned int low = (unsigned char)_input[_p + 1]; + int ch2 = ((high << 8) | low); + if (ch2 >= 0xdc00 && ch2 < 0xe000) { + // Yes, this is a low surrogate. + _p += 2; + return 0x10000 + ((ch - 0xd800) << 10) + (ch2 - 0xdc00); + } + } + // No, this is just a regular character, or an unpaired surrogate. + return ch; } diff --git a/dtool/src/dtoolutil/stringDecoder.h b/dtool/src/dtoolutil/stringDecoder.h index c0b2534ee2..6885f77e08 100644 --- a/dtool/src/dtoolutil/stringDecoder.h +++ b/dtool/src/dtoolutil/stringDecoder.h @@ -26,7 +26,7 @@ public: INLINE StringDecoder(const std::string &input); virtual ~StringDecoder(); - virtual int get_next_character(); + virtual char32_t get_next_character(); INLINE bool is_eof(); static void set_notify_ptr(std::ostream *ptr); @@ -48,20 +48,23 @@ class StringUtf8Decoder : public StringDecoder { public: INLINE StringUtf8Decoder(const std::string &input); - virtual int get_next_character(); + virtual char32_t get_next_character(); }; /** * This decoder extracts characters two at a time to get a plain wide - * character sequence. + * character sequence. It supports surrogate pairs. */ -class StringUnicodeDecoder : public StringDecoder { +class StringUtf16Decoder : public StringDecoder { public: - INLINE StringUnicodeDecoder(const std::string &input); + INLINE StringUtf16Decoder(const std::string &input); - virtual int get_next_character(); + virtual char32_t get_next_character(); }; +// Deprecated alias of StringUtf16Encoder. +typedef StringUtf16Decoder StringUnicodeDecoder; + #include "stringDecoder.I" #endif diff --git a/dtool/src/dtoolutil/textEncoder.I b/dtool/src/dtoolutil/textEncoder.I index e07f489ab0..aa6b42fdb5 100644 --- a/dtool/src/dtoolutil/textEncoder.I +++ b/dtool/src/dtoolutil/textEncoder.I @@ -90,6 +90,7 @@ set_text(const std::string &text) { if (!has_text() || _text != text) { _text = text; _flags = (_flags | F_got_text) & ~F_got_wtext; + text_changed(); } } @@ -101,7 +102,11 @@ set_text(const std::string &text) { */ INLINE void TextEncoder:: set_text(const std::string &text, TextEncoder::Encoding encoding) { - set_wtext(decode_text(text, encoding)); + if (encoding == _encoding) { + set_text(text); + } else { + set_wtext(decode_text(text, encoding)); + } } /** @@ -112,6 +117,7 @@ clear_text() { _text = std::string(); _wtext = std::wstring(); _flags |= (F_got_text | F_got_wtext); + text_changed(); } /** @@ -151,8 +157,11 @@ get_text(TextEncoder::Encoding encoding) const { */ INLINE void TextEncoder:: append_text(const std::string &text) { - _text = get_text() + text; - _flags = (_flags | F_got_text) & ~F_got_wtext; + if (!text.empty()) { + _text = get_text() + text; + _flags = (_flags | F_got_text) & ~F_got_wtext; + text_changed(); + } } /** @@ -160,9 +169,25 @@ append_text(const std::string &text) { * wide character, up to 16 bits in Unicode. */ INLINE void TextEncoder:: -append_unicode_char(int character) { +append_unicode_char(char32_t character) { +#if WCHAR_MAX >= 0x10FFFF + // wchar_t might be UTF-32. _wtext = get_wtext() + std::wstring(1, (wchar_t)character); +#else + if ((character & ~0xffff) == 0) { + _wtext = get_wtext() + std::wstring(1, (wchar_t)character); + } else { + // Encode as a surrogate pair. + uint32_t v = (uint32_t)character - 0x10000u; + wchar_t wstr[2] = { + (wchar_t)((v >> 10u) | 0xd800u), + (wchar_t)((v & 0x3ffu) | 0xdc00u), + }; + _wtext = get_wtext() + std::wstring(wstr, 2); + } +#endif _flags = (_flags | F_got_wtext) & ~F_got_text; + text_changed(); } /** @@ -195,11 +220,12 @@ get_unicode_char(size_t index) const { * according to set_encoding(). */ INLINE void TextEncoder:: -set_unicode_char(size_t index, int character) { +set_unicode_char(size_t index, char32_t character) { get_wtext(); if (index < _wtext.length()) { _wtext[index] = character; _flags &= ~F_got_text; + text_changed(); } } @@ -257,7 +283,7 @@ reencode_text(const std::string &text, TextEncoder::Encoding from, * otherwise. This is akin to ctype's isalpha(), extended to Unicode. */ INLINE bool TextEncoder:: -unicode_isalpha(int character) { +unicode_isalpha(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { return false; @@ -271,7 +297,7 @@ unicode_isalpha(int character) { * otherwise. This is akin to ctype's isdigit(), extended to Unicode. */ INLINE bool TextEncoder:: -unicode_isdigit(int character) { +unicode_isdigit(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { // The digits aren't actually listed in the map. @@ -286,11 +312,11 @@ unicode_isdigit(int character) { * otherwise. This is akin to ctype's ispunct(), extended to Unicode. */ INLINE bool TextEncoder:: -unicode_ispunct(int character) { +unicode_ispunct(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { // Some punctuation marks aren't listed in the map. - return (character >= 0 && character < 128 && ispunct(character)); + return (character < 128 && ispunct(character)); } return entry->_char_type == UnicodeLatinMap::CT_punct; } @@ -300,7 +326,7 @@ unicode_ispunct(int character) { * otherwise. This is akin to ctype's isupper(), extended to Unicode. */ INLINE bool TextEncoder:: -unicode_isupper(int character) { +unicode_isupper(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { return false; @@ -313,7 +339,7 @@ unicode_isupper(int character) { * otherwise. This is akin to ctype's isspace(), extended to Unicode. */ INLINE bool TextEncoder:: -unicode_isspace(int character) { +unicode_isspace(char32_t character) { switch (character) { case ' ': case '\t': @@ -330,7 +356,7 @@ unicode_isspace(int character) { * otherwise. This is akin to ctype's islower(), extended to Unicode. */ INLINE bool TextEncoder:: -unicode_islower(int character) { +unicode_islower(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { return false; @@ -343,7 +369,7 @@ unicode_islower(int character) { * akin to ctype's toupper(), extended to Unicode. */ INLINE int TextEncoder:: -unicode_toupper(int character) { +unicode_toupper(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { return character; @@ -356,7 +382,7 @@ unicode_toupper(int character) { * akin to ctype's tolower(), extended to Unicode. */ INLINE int TextEncoder:: -unicode_tolower(int character) { +unicode_tolower(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { return character; @@ -418,6 +444,7 @@ set_wtext(const std::wstring &wtext) { if (!has_text() || _wtext != wtext) { _wtext = wtext; _flags = (_flags | F_got_wtext) & ~F_got_text; + text_changed(); } } @@ -439,8 +466,11 @@ get_wtext() const { */ INLINE void TextEncoder:: append_wtext(const std::wstring &wtext) { - _wtext = get_wtext() + wtext; - _flags = (_flags | F_got_wtext) & ~F_got_text; + if (!wtext.empty()) { + _wtext = get_wtext() + wtext; + _flags = (_flags | F_got_wtext) & ~F_got_text; + text_changed(); + } } /** diff --git a/dtool/src/dtoolutil/textEncoder.cxx b/dtool/src/dtoolutil/textEncoder.cxx index 1e1cd4bc61..1065f21dcb 100644 --- a/dtool/src/dtoolutil/textEncoder.cxx +++ b/dtool/src/dtoolutil/textEncoder.cxx @@ -21,7 +21,7 @@ using std::ostream; using std::string; using std::wstring; -TextEncoder::Encoding TextEncoder::_default_encoding = TextEncoder::E_iso8859; +TextEncoder::Encoding TextEncoder::_default_encoding = TextEncoder::E_utf8; /** * Adjusts the text stored within the encoder to all uppercase letters @@ -35,6 +35,7 @@ make_upper() { (*si) = unicode_toupper(*si); } _flags &= ~F_got_text; + text_changed(); } /** @@ -49,6 +50,7 @@ make_lower() { (*si) = unicode_tolower(*si); } _flags &= ~F_got_text; + text_changed(); } /** @@ -107,11 +109,11 @@ is_wtext() const { } /** - * Encodes a single wide char into a one-, two-, or three-byte string, - * according to the given encoding system. + * Encodes a single Unicode character into a one-, two-, three-, or four-byte + * string, according to the given encoding system. */ string TextEncoder:: -encode_wchar(wchar_t ch, TextEncoder::Encoding encoding) { +encode_wchar(char32_t ch, TextEncoder::Encoding encoding) { switch (encoding) { case E_iso8859: if ((ch & ~0xff) == 0) { @@ -143,17 +145,38 @@ encode_wchar(wchar_t ch, TextEncoder::Encoding encoding) { return string(1, (char)((ch >> 6) | 0xc0)) + string(1, (char)((ch & 0x3f) | 0x80)); - } else { + } else if ((ch & ~0xffff) == 0) { return string(1, (char)((ch >> 12) | 0xe0)) + string(1, (char)(((ch >> 6) & 0x3f) | 0x80)) + string(1, (char)((ch & 0x3f) | 0x80)); + } else { + return + string(1, (char)((ch >> 18) | 0xf0)) + + string(1, (char)(((ch >> 12) & 0x3f) | 0x80)) + + string(1, (char)(((ch >> 6) & 0x3f) | 0x80)) + + string(1, (char)((ch & 0x3f) | 0x80)); } - case E_unicode: - return - string(1, (char)(ch >> 8)) + - string(1, (char)(ch & 0xff)); + case E_utf16be: + if ((ch & ~0xffff) == 0) { + // Note that this passes through surrogates and BOMs unharmed. + return + string(1, (char)(ch >> 8)) + + string(1, (char)(ch & 0xff)); + } else { + // Use a surrogate pair. + uint32_t v = (uint32_t)ch - 0x10000u; + uint16_t hi = (v >> 10u) | 0xd800u; + uint16_t lo = (v & 0x3ffu) | 0xdc00u; + char encoded[4] = { + (char)(hi >> 8), + (char)(hi & 0xff), + (char)(lo >> 8), + (char)(lo & 0xff), + }; + return string(encoded, 4); + } } return ""; @@ -167,8 +190,25 @@ string TextEncoder:: encode_wtext(const wstring &wtext, TextEncoder::Encoding encoding) { string result; - for (wstring::const_iterator pi = wtext.begin(); pi != wtext.end(); ++pi) { - result += encode_wchar(*pi, encoding); + for (size_t i = 0; i < wtext.size(); ++i) { + wchar_t ch = wtext[i]; + + // On some systems, wstring may be UTF-16, and contain surrogate pairs. +#if WCHAR_MAX < 0x10FFFF + if (ch >= 0xd800 && ch < 0xdc00 && (i + 1) < wtext.size()) { + // This is a high surrogate. Look for a subsequent low surrogate. + wchar_t ch2 = wtext[i + 1]; + if (ch2 >= 0xdc00 && ch2 < 0xe000) { + // Yes, this is a low surrogate. + char32_t code_point = 0x10000 + ((ch - 0xd800) << 10) + (ch2 - 0xdc00); + result += encode_wchar(code_point, encoding); + i++; + continue; + } + } +#endif + + result += encode_wchar(ch, encoding); } return result; @@ -187,9 +227,9 @@ decode_text(const string &text, TextEncoder::Encoding encoding) { return decode_text_impl(decoder); } - case E_unicode: + case E_utf16be: { - StringUnicodeDecoder decoder(text); + StringUtf16Decoder decoder(text); return decode_text_impl(decoder); } @@ -211,7 +251,7 @@ decode_text_impl(StringDecoder &decoder) { wstring result; // bool expand_amp = get_expand_amp(); - wchar_t character = decoder.get_next_character(); + char32_t character = decoder.get_next_character(); while (!decoder.is_eof()) { /* if (character == '&' && expand_amp) { @@ -219,7 +259,14 @@ decode_text_impl(StringDecoder &decoder) { character = expand_amp_sequence(decoder); } */ - result += character; + if (character <= WCHAR_MAX) { + result += character; + } else { + // We need to encode this as a surrogate pair. + uint32_t v = (uint32_t)character - 0x10000u; + result += (wchar_t)((v >> 10u) | 0xd800u); + result += (wchar_t)((v & 0x3ffu) | 0xdc00u); + } character = decoder.get_next_character(); } @@ -314,6 +361,12 @@ expand_amp_sequence(StringDecoder &decoder) const { } */ +/** + * Called whenever the text has been changed. + */ +void TextEncoder:: +text_changed() { +} /** * @@ -327,8 +380,8 @@ operator << (ostream &out, TextEncoder::Encoding encoding) { case TextEncoder::E_utf8: return out << "utf8"; - case TextEncoder::E_unicode: - return out << "unicode"; + case TextEncoder::E_utf16be: + return out << "utf16be"; }; return out << "**invalid TextEncoder::Encoding(" << (int)encoding << ")**"; @@ -346,8 +399,9 @@ operator >> (istream &in, TextEncoder::Encoding &encoding) { encoding = TextEncoder::E_iso8859; } else if (word == "utf8" || word == "utf-8") { encoding = TextEncoder::E_utf8; - } else if (word == "unicode") { - encoding = TextEncoder::E_unicode; + } else if (word == "unicode" || word == "utf16be" || word == "utf-16be" || + word == "utf16-be" || word == "utf-16-be") { + encoding = TextEncoder::E_utf16be; } else { ostream *notify_ptr = StringDecoder::get_notify_ptr(); if (notify_ptr != nullptr) { diff --git a/dtool/src/dtoolutil/textEncoder.h b/dtool/src/dtoolutil/textEncoder.h index a7eaf395ff..1e1d9eeda4 100644 --- a/dtool/src/dtoolutil/textEncoder.h +++ b/dtool/src/dtoolutil/textEncoder.h @@ -23,7 +23,7 @@ class StringDecoder; /** * This class can be used to convert text between multiple representations, - * e.g. utf-8 to Unicode. You may use it as a static class object, passing + * e.g. UTF-8 to UTF-16. You may use it as a static class object, passing * the encoding each time, or you may create an instance and use that object, * which will record the current encoding and retain the current string. * @@ -35,12 +35,17 @@ PUBLISHED: enum Encoding { E_iso8859, E_utf8, - E_unicode + E_utf16be, + + // Deprecated alias for E_utf16be + E_unicode = E_utf16be, }; INLINE TextEncoder(); INLINE TextEncoder(const TextEncoder ©); + virtual ~TextEncoder() = default; + INLINE void set_encoding(Encoding encoding); INLINE Encoding get_encoding() const; @@ -48,35 +53,46 @@ PUBLISHED: INLINE static Encoding get_default_encoding(); MAKE_PROPERTY(default_encoding, get_default_encoding, set_default_encoding); +#ifdef CPPPARSER + EXTEND void set_text(PyObject *text); + EXTEND void set_text(PyObject *text, Encoding encoding); +#else INLINE void set_text(const std::string &text); INLINE void set_text(const std::string &text, Encoding encoding); +#endif INLINE void clear_text(); INLINE bool has_text() const; void make_upper(); void make_lower(); +#ifdef CPPPARSER + EXTEND PyObject *get_text() const; + EXTEND PyObject *get_text(Encoding encoding) const; + EXTEND void append_text(PyObject *text); +#else INLINE std::string get_text() const; INLINE std::string get_text(Encoding encoding) const; INLINE void append_text(const std::string &text); - INLINE void append_unicode_char(int character); +#endif + INLINE void append_unicode_char(char32_t character); INLINE size_t get_num_chars() const; INLINE int get_unicode_char(size_t index) const; - INLINE void set_unicode_char(size_t index, int character); + INLINE void set_unicode_char(size_t index, char32_t character); INLINE std::string get_encoded_char(size_t index) const; INLINE std::string get_encoded_char(size_t index, Encoding encoding) const; INLINE std::string get_text_as_ascii() const; INLINE static std::string reencode_text(const std::string &text, Encoding from, Encoding to); - INLINE static bool unicode_isalpha(int character); - INLINE static bool unicode_isdigit(int character); - INLINE static bool unicode_ispunct(int character); - INLINE static bool unicode_islower(int character); - INLINE static bool unicode_isupper(int character); - INLINE static bool unicode_isspace(int character); - INLINE static int unicode_toupper(int character); - INLINE static int unicode_tolower(int character); + INLINE static bool unicode_isalpha(char32_t character); + INLINE static bool unicode_isdigit(char32_t character); + INLINE static bool unicode_ispunct(char32_t character); + INLINE static bool unicode_islower(char32_t character); + INLINE static bool unicode_isupper(char32_t character); + INLINE static bool unicode_isspace(char32_t character); + INLINE static int unicode_toupper(char32_t character); + INLINE static int unicode_tolower(char32_t character); INLINE static std::string upper(const std::string &source); INLINE static std::string upper(const std::string &source, Encoding encoding); @@ -91,11 +107,24 @@ PUBLISHED: std::wstring get_wtext_as_ascii() const; bool is_wtext() const; - static std::string encode_wchar(wchar_t ch, Encoding encoding); +#ifdef CPPPARSER + EXTEND static PyObject *encode_wchar(char32_t ch, Encoding encoding); + EXTEND INLINE PyObject *encode_wtext(const std::wstring &wtext) const; + EXTEND static PyObject *encode_wtext(const std::wstring &wtext, Encoding encoding); + EXTEND INLINE PyObject *decode_text(PyObject *text) const; + EXTEND static PyObject *decode_text(PyObject *text, Encoding encoding); +#else + static std::string encode_wchar(char32_t ch, Encoding encoding); INLINE std::string encode_wtext(const std::wstring &wtext) const; static std::string encode_wtext(const std::wstring &wtext, Encoding encoding); INLINE std::wstring decode_text(const std::string &text) const; static std::wstring decode_text(const std::string &text, Encoding encoding); +#endif + + MAKE_PROPERTY(text, get_text, set_text); + +protected: + virtual void text_changed(); private: enum Flags { diff --git a/dtool/src/dtoolutil/textEncoder_ext.I b/dtool/src/dtoolutil/textEncoder_ext.I new file mode 100644 index 0000000000..2924fda011 --- /dev/null +++ b/dtool/src/dtoolutil/textEncoder_ext.I @@ -0,0 +1,30 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file textEncoder_ext.I + * @author rdb + * @date 2018-10-08 + */ + +/** + * Encodes a wide-text string into a single-char string, according to the + * current encoding. + */ +INLINE PyObject *Extension:: +encode_wtext(const std::wstring &wtext) const { + return encode_wtext(wtext, _this->get_encoding()); +} + +/** + * Returns the given wstring decoded to a single-byte string, via the current + * encoding system. + */ +INLINE PyObject *Extension:: +decode_text(PyObject *text) const { + return decode_text(text, _this->get_encoding()); +} diff --git a/dtool/src/dtoolutil/textEncoder_ext.cxx b/dtool/src/dtoolutil/textEncoder_ext.cxx new file mode 100644 index 0000000000..1947e6c749 --- /dev/null +++ b/dtool/src/dtoolutil/textEncoder_ext.cxx @@ -0,0 +1,164 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file textEncoder_ext.cxx + * @author rdb + * @date 2018-09-29 + */ + +#include "textEncoder_ext.h" + +#ifdef HAVE_PYTHON + +/** + * Sets the text as a Unicode string. In Python 2, if a regular str is given, + * it is assumed to be in the TextEncoder's specified encoding. + */ +void Extension:: +set_text(PyObject *text) { + if (PyUnicode_Check(text)) { +#if PY_VERSION_HEX >= 0x03030000 + Py_ssize_t len; + const char *str = PyUnicode_AsUTF8AndSize(text, &len); + _this->set_text(std::string(str, len), TextEncoder::E_utf8); +#else + Py_ssize_t len = PyUnicode_GET_SIZE(text); + wchar_t *str = (wchar_t *)alloca(sizeof(wchar_t) * (len + 1)); + PyUnicode_AsWideChar((PyUnicodeObject *)text, str, len); + _this->set_wtext(std::wstring(str, len)); +#endif + } else { +#if PY_MAJOR_VERSION >= 3 + Dtool_Raise_TypeError("expected string"); +#else + char *str; + Py_ssize_t len; + if (PyString_AsStringAndSize(text, (char **)&str, &len) != -1) { + _this->set_text(std::string(str, len)); + } +#endif + } +} + +/** + * Sets the text as an encoded byte string of the given encoding. + */ +void Extension:: +set_text(PyObject *text, TextEncoder::Encoding encoding) { + char *str; + Py_ssize_t len; + if (PyBytes_AsStringAndSize(text, &str, &len) >= 0) { + _this->set_text(std::string(str, len), encoding); + } +} + +/** + * Returns the text as a string. In Python 2, the returned string is in the + * TextEncoder's specified encoding. In Python 3, it is returned as unicode. + */ +PyObject *Extension:: +get_text() const { +#if PY_MAJOR_VERSION >= 3 + std::wstring text = _this->get_wtext(); + return PyUnicode_FromWideChar(text.data(), (Py_ssize_t)text.size()); +#else + std::string text = _this->get_text(); + return PyString_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size()); +#endif +} + +/** + * Returns the text as a bytes object in the given encoding. + */ +PyObject *Extension:: +get_text(TextEncoder::Encoding encoding) const { + std::string text = _this->get_text(encoding); +#if PY_MAJOR_VERSION >= 3 + return PyBytes_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size()); +#else + return PyString_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size()); +#endif +} + +/** + * Appends the text as a string (or Unicode object in Python 2). + */ +void Extension:: +append_text(PyObject *text) { + if (PyUnicode_Check(text)) { +#if PY_VERSION_HEX >= 0x03030000 + Py_ssize_t len; + const char *str = PyUnicode_AsUTF8AndSize(text, &len); + std::string text_str(str, len); + if (_this->get_encoding() == TextEncoder::E_utf8) { + _this->append_text(text_str); + } else { + _this->append_wtext(TextEncoder::decode_text(text_str, TextEncoder::E_utf8)); + } +#else + Py_ssize_t len = PyUnicode_GET_SIZE(text); + wchar_t *str = (wchar_t *)alloca(sizeof(wchar_t) * (len + 1)); + PyUnicode_AsWideChar((PyUnicodeObject *)text, str, len); + _this->append_wtext(std::wstring(str, len)); +#endif + } else { +#if PY_MAJOR_VERSION >= 3 + Dtool_Raise_TypeError("expected string"); +#else + char *str; + Py_ssize_t len; + if (PyString_AsStringAndSize(text, (char **)&str, &len) != -1) { + _this->append_text(std::string(str, len)); + } +#endif + } +} + +/** + * Encodes the given wide character as byte string in the given encoding. + */ +PyObject *Extension:: +encode_wchar(char32_t ch, TextEncoder::Encoding encoding) { + std::string value = TextEncoder::encode_wchar(ch, encoding); +#if PY_MAJOR_VERSION >= 3 + return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size()); +#else + return PyString_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size()); +#endif +} + +/** + * Encodes a wide-text string into a single-char string, according to the + * given encoding. + */ +PyObject *Extension:: +encode_wtext(const wstring &wtext, TextEncoder::Encoding encoding) { + std::string value = TextEncoder::encode_wtext(wtext, encoding); +#if PY_MAJOR_VERSION >= 3 + return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size()); +#else + return PyString_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size()); +#endif +} + +/** + * Returns the given wstring decoded to a single-byte string, via the given + * encoding system. + */ +PyObject *Extension:: +decode_text(PyObject *text, TextEncoder::Encoding encoding) { + char *str; + Py_ssize_t len; + if (PyBytes_AsStringAndSize(text, &str, &len) >= 0) { + return Dtool_WrapValue(TextEncoder::decode_text(std::string(str, len), encoding)); + } else { + return nullptr; + } +} + +#endif // HAVE_PYTHON diff --git a/dtool/src/dtoolutil/textEncoder_ext.h b/dtool/src/dtoolutil/textEncoder_ext.h new file mode 100644 index 0000000000..049c16e493 --- /dev/null +++ b/dtool/src/dtoolutil/textEncoder_ext.h @@ -0,0 +1,50 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file textEncoder_ext.h + * @author rdb + * @date 2018-09-29 + */ + +#ifndef TEXTENCODER_EXT_H +#define TEXTENCODER_EXT_H + +#include "dtoolbase.h" + +#ifdef HAVE_PYTHON + +#include "extension.h" +#include "textEncoder.h" +#include "py_panda.h" + +/** + * This class defines the extension methods for TextEncoder, which are called + * instead of any C++ methods with the same prototype. + */ +template<> +class Extension : public ExtensionBase { +public: + void set_text(PyObject *text); + void set_text(PyObject *text, TextEncoder::Encoding encoding); + + PyObject *get_text() const; + PyObject *get_text(TextEncoder::Encoding encoding) const; + void append_text(PyObject *text); + + static PyObject *encode_wchar(char32_t ch, TextEncoder::Encoding encoding); + INLINE PyObject *encode_wtext(const std::wstring &wtext) const; + static PyObject *encode_wtext(const std::wstring &wtext, TextEncoder::Encoding encoding); + INLINE PyObject *decode_text(PyObject *text) const; + static PyObject *decode_text(PyObject *text, TextEncoder::Encoding encoding); +}; + +#include "textEncoder_ext.I" + +#endif // HAVE_PYTHON + +#endif // TEXTENCODER_EXT_H diff --git a/dtool/src/dtoolutil/unicodeLatinMap.cxx b/dtool/src/dtoolutil/unicodeLatinMap.cxx index 87c9cb5a7d..288b85a4ce 100644 --- a/dtool/src/dtoolutil/unicodeLatinMap.cxx +++ b/dtool/src/dtoolutil/unicodeLatinMap.cxx @@ -1378,7 +1378,7 @@ static const wchar_t combining_accent_map[] = { * Returns the Entry associated with the indicated character, if there is one. */ const UnicodeLatinMap::Entry *UnicodeLatinMap:: -look_up(wchar_t character) { +look_up(char32_t character) { if (!_initialized) { init(); } diff --git a/dtool/src/dtoolutil/unicodeLatinMap.h b/dtool/src/dtoolutil/unicodeLatinMap.h index fb94154f7f..6ed3c5f17c 100644 --- a/dtool/src/dtoolutil/unicodeLatinMap.h +++ b/dtool/src/dtoolutil/unicodeLatinMap.h @@ -112,17 +112,17 @@ public: class Entry { public: - wchar_t _character; + char32_t _character; CharType _char_type; char _ascii_equiv; char _ascii_additional; - wchar_t _tolower_character; - wchar_t _toupper_character; + char32_t _tolower_character; + char32_t _toupper_character; AccentType _accent_type; int _additional_flags; }; - static const Entry *look_up(wchar_t character); + static const Entry *look_up(char32_t character); static wchar_t get_combining_accent(AccentType accent); @@ -130,7 +130,7 @@ private: static void init(); static bool _initialized; - typedef phash_map > ByCharacter; + typedef phash_map > ByCharacter; static ByCharacter *_by_character; enum { max_direct_chars = 256 }; static const Entry *_direct_chars[max_direct_chars]; diff --git a/dtool/src/interrogate/interrogateBuilder.cxx b/dtool/src/interrogate/interrogateBuilder.cxx index 15607c95ea..b740d59e1a 100644 --- a/dtool/src/interrogate/interrogateBuilder.cxx +++ b/dtool/src/interrogate/interrogateBuilder.cxx @@ -1389,7 +1389,8 @@ scan_element(CPPInstance *element, CPPStructType *struct_type, // We can only generate a getter and a setter if we can talk about the // type it is. - if (parameter_type->as_struct_type() != nullptr) { + if (parameter_type->as_struct_type() != nullptr && + !parameter_type->is_trivial()) { // Wrap the type in a const reference. parameter_type = TypeManager::wrap_const_reference(parameter_type); } diff --git a/dtool/src/interrogatedb/py_panda.cxx b/dtool/src/interrogatedb/py_panda.cxx index 42bcdb9a35..c29796def6 100644 --- a/dtool/src/interrogatedb/py_panda.cxx +++ b/dtool/src/interrogatedb/py_panda.cxx @@ -722,7 +722,10 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) { // Extract the __file__ attribute, if present. Filename main_dir; - PyObject *file_attr = PyObject_GetAttrString(main_module, "__file__"); + PyObject *file_attr = nullptr; + if (main_module != nullptr) { + file_attr = PyObject_GetAttrString(main_module, "__file__"); + } if (file_attr == nullptr) { // Must be running in the interactive interpreter. Use the CWD. main_dir = ExecutionEnvironment::get_cwd(); @@ -752,6 +755,11 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) { ExecutionEnvironment::shadow_environment_variable("MAIN_DIR", main_dir.to_os_specific()); PyErr_Clear(); initialized_main_dir = true; + + // Also, while we are at it, initialize the thread swap hook. +#if defined(HAVE_THREADS) && defined(SIMPLE_THREADS) + global_thread_state_swap = PyThreadState_Swap; +#endif } PyModule_AddIntConstant(module, "Dtool_PyNativeInterface", 1); diff --git a/dtool/src/parser-inc/Python.h b/dtool/src/parser-inc/Python.h index ddd660072d..5f1a98a825 100644 --- a/dtool/src/parser-inc/Python.h +++ b/dtool/src/parser-inc/Python.h @@ -28,7 +28,7 @@ typedef _typeobject PyTypeObject; typedef struct {} PyStringObject; typedef struct {} PyUnicodeObject; -class PyThreadState; +typedef struct _ts PyThreadState; typedef int Py_ssize_t; typedef struct bufferinfo Py_buffer; diff --git a/dtool/src/prc/notifyCategory.I b/dtool/src/prc/notifyCategory.I index 5793917d91..20678fbace 100644 --- a/dtool/src/prc/notifyCategory.I +++ b/dtool/src/prc/notifyCategory.I @@ -82,26 +82,6 @@ is_debug() const { // Instruct the compiler to optimize for the usual case. return UNLIKELY(is_on(NS_debug)); } -#else -/** - * When NOTIFY_DEBUG is not defined, the categories are never set to "spam" or - * "debug" severities, and these methods are redefined to be static to make it - * more obvious to the compiler. - */ -constexpr bool NotifyCategory:: -is_spam() { - return false; -} - -/** - * When NOTIFY_DEBUG is not defined, the categories are never set to "spam" or - * "debug" severities, and these methods are redefined to be static to make it - * more obvious to the compiler. - */ -constexpr bool NotifyCategory:: -is_debug() { - return false; -} #endif /** diff --git a/dtool/src/prc/notifyCategory.h b/dtool/src/prc/notifyCategory.h index f3e99b09ba..9a2a9fa4e2 100644 --- a/dtool/src/prc/notifyCategory.h +++ b/dtool/src/prc/notifyCategory.h @@ -55,8 +55,8 @@ PUBLISHED: INLINE bool is_spam() const; INLINE bool is_debug() const; #else - constexpr static bool is_spam(); - constexpr static bool is_debug(); + constexpr static bool is_spam() { return false; } + constexpr static bool is_debug() { return false; } #endif INLINE bool is_info() const; INLINE bool is_warning() const; diff --git a/dtool/src/prc/notifyCategoryProxy.I b/dtool/src/prc/notifyCategoryProxy.I index eaca9b6e33..fbdac1f0ca 100644 --- a/dtool/src/prc/notifyCategoryProxy.I +++ b/dtool/src/prc/notifyCategoryProxy.I @@ -72,12 +72,6 @@ is_spam() { // Instruct the compiler to optimize for the usual case. return UNLIKELY(get_unsafe_ptr()->is_spam()); } -#else -template -constexpr bool NotifyCategoryProxy:: -is_spam() { - return false; -} #endif /** @@ -90,12 +84,6 @@ is_debug() { // Instruct the compiler to optimize for the usual case. return UNLIKELY(get_unsafe_ptr()->is_debug()); } -#else -template -constexpr bool NotifyCategoryProxy:: -is_debug() { - return false; -} #endif /** diff --git a/dtool/src/prc/notifyCategoryProxy.h b/dtool/src/prc/notifyCategoryProxy.h index 06f38ec804..5465529583 100644 --- a/dtool/src/prc/notifyCategoryProxy.h +++ b/dtool/src/prc/notifyCategoryProxy.h @@ -75,8 +75,8 @@ public: INLINE bool is_spam(); INLINE bool is_debug(); #else - constexpr static bool is_spam(); - constexpr static bool is_debug(); + constexpr static bool is_spam() { return false; } + constexpr static bool is_debug() { return false; } #endif INLINE bool is_info(); INLINE bool is_warning(); diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 6bf63bc0a3..31516c4249 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -681,6 +681,9 @@ if (COMPILER == "MSVC"): IncDirectory("FCOLLADA", GetThirdpartyDir() + "fcollada/include/FCollada") if (PkgSkip("ASSIMP")==0): LibName("ASSIMP", GetThirdpartyDir() + "assimp/lib/assimp.lib") + path = GetThirdpartyDir() + "assimp/lib/IrrXML.lib" + if os.path.isfile(path): + LibName("ASSIMP", GetThirdpartyDir() + "assimp/lib/IrrXML.lib") IncDirectory("ASSIMP", GetThirdpartyDir() + "assimp/include/assimp") if (PkgSkip("SQUISH")==0): if GetOptimize() <= 2: @@ -947,8 +950,6 @@ if (COMPILER=="GCC"): if GetTarget() == 'darwin': LibName("ALWAYS", "-framework AppKit") - if (PkgSkip("OPENCV")==0): - LibName("OPENCV", "-framework QuickTime") LibName("AGL", "-framework AGL") LibName("CARBON", "-framework Carbon") LibName("COCOA", "-framework Cocoa") @@ -1335,9 +1336,10 @@ def CompileCxx(obj,src,opts): # Work around Apple compiler bug. cmd += " -U__EXCEPTIONS" - if 'RTTI' not in opts: + target = GetTarget() + if 'RTTI' not in opts and target != "darwin": # We always disable RTTI on Android for memory usage reasons. - if optlevel >= 4 or GetTarget() == "android": + if optlevel >= 4 or target == "android": cmd += " -fno-rtti" if ('SSE2' in opts or not PkgSkip("SSE2")) and not arch.startswith("arm") and arch != 'aarch64': @@ -1597,6 +1599,8 @@ def CompileLib(lib, obj, opts): else: cmd = GetAR() + ' cru ' + BracketNameWithQuotes(lib) for x in obj: + if GetLinkAllStatic() and x.endswith('.a'): + continue cmd += ' ' + BracketNameWithQuotes(x) oscmd(cmd) @@ -3161,10 +3165,10 @@ CopyAllHeaders('panda/src/movies') CopyAllHeaders('panda/src/pgraphnodes') CopyAllHeaders('panda/src/pgraph') CopyAllHeaders('panda/src/cull') +CopyAllHeaders('panda/src/display') CopyAllHeaders('panda/src/chan') CopyAllHeaders('panda/src/char') CopyAllHeaders('panda/src/dgraph') -CopyAllHeaders('panda/src/display') CopyAllHeaders('panda/src/device') CopyAllHeaders('panda/src/pnmtext') CopyAllHeaders('panda/src/text') @@ -3297,7 +3301,6 @@ if (PkgSkip("PANDATOOL")==0): CopyAllHeaders('pandatool/src/ptloader') CopyAllHeaders('pandatool/src/miscprogs') CopyAllHeaders('pandatool/src/pstatserver') - CopyAllHeaders('pandatool/src/softprogs') CopyAllHeaders('pandatool/src/text-stats') CopyAllHeaders('pandatool/src/vrmlprogs') CopyAllHeaders('pandatool/src/win-stats') @@ -3553,6 +3556,7 @@ IGATEFILES += [ "dSearchPath.h", "executionEnvironment.h", "textEncoder.h", + "textEncoder_ext.h", "filename.h", "filename_ext.h", "globPattern.h", @@ -3817,7 +3821,7 @@ if (not RUNTIME): if (not RUNTIME): OPTS=['DIR:panda/src/gobj', 'BUILDING:PANDA', 'NVIDIACG', 'ZLIB', 'SQUISH'] TargetAdd('p3gobj_composite1.obj', opts=OPTS, input='p3gobj_composite1.cxx') - TargetAdd('p3gobj_composite2.obj', opts=OPTS, input='p3gobj_composite2.cxx') + TargetAdd('p3gobj_composite2.obj', opts=OPTS+['BIGOBJ'], input='p3gobj_composite2.cxx') OPTS=['DIR:panda/src/gobj', 'NVIDIACG', 'ZLIB', 'SQUISH', 'PYTHON'] IGATEFILES=GetDirectoryContents('panda/src/gobj', ["*.h", "*_composite*.cxx"]) @@ -3876,38 +3880,6 @@ if (not RUNTIME): TargetAdd('libp3cull.in', opts=['IMOD:panda3d.core', 'ILIB:libp3cull', 'SRCDIR:panda/src/cull']) TargetAdd('libp3cull_igate.obj', input='libp3cull.in', opts=["DEPENDENCYONLY"]) -# -# DIRECTORY: panda/src/chan/ -# - -if (not RUNTIME): - OPTS=['DIR:panda/src/chan', 'BUILDING:PANDA'] - TargetAdd('p3chan_composite1.obj', opts=OPTS, input='p3chan_composite1.cxx') - TargetAdd('p3chan_composite2.obj', opts=OPTS, input='p3chan_composite2.cxx') - - OPTS=['DIR:panda/src/chan', 'PYTHON'] - IGATEFILES=GetDirectoryContents('panda/src/chan', ["*.h", "*_composite*.cxx"]) - IGATEFILES.remove('movingPart.h') - IGATEFILES.remove('animChannelFixed.h') - TargetAdd('libp3chan.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3chan.in', opts=['IMOD:panda3d.core', 'ILIB:libp3chan', 'SRCDIR:panda/src/chan']) - TargetAdd('libp3chan_igate.obj', input='libp3chan.in', opts=["DEPENDENCYONLY"]) - - -# DIRECTORY: panda/src/char/ -# - -if (not RUNTIME): - OPTS=['DIR:panda/src/char', 'BUILDING:PANDA'] - TargetAdd('p3char_composite1.obj', opts=OPTS, input='p3char_composite1.cxx') - TargetAdd('p3char_composite2.obj', opts=OPTS, input='p3char_composite2.cxx') - - OPTS=['DIR:panda/src/char', 'PYTHON'] - IGATEFILES=GetDirectoryContents('panda/src/char', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3char.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3char.in', opts=['IMOD:panda3d.core', 'ILIB:libp3char', 'SRCDIR:panda/src/char']) - TargetAdd('libp3char_igate.obj', input='libp3char.in', opts=["DEPENDENCYONLY"]) - # # DIRECTORY: panda/src/dgraph/ # @@ -3944,6 +3916,7 @@ if (not RUNTIME): if (not RUNTIME): OPTS=['DIR:panda/src/display', 'BUILDING:PANDA'] + TargetAdd('p3display_graphicsStateGuardian.obj', opts=OPTS, input='graphicsStateGuardian.cxx') TargetAdd('p3display_composite1.obj', opts=OPTS, input='p3display_composite1.cxx') TargetAdd('p3display_composite2.obj', opts=OPTS, input='p3display_composite2.cxx') @@ -3962,6 +3935,38 @@ if (not RUNTIME): TargetAdd('subprocessWindowBuffer.obj', opts=OPTS, input='subprocessWindowBuffer.cxx') TargetAdd('libp3subprocbuffer.ilb', input='subprocessWindowBuffer.obj') +# +# DIRECTORY: panda/src/chan/ +# + +if (not RUNTIME): + OPTS=['DIR:panda/src/chan', 'BUILDING:PANDA'] + TargetAdd('p3chan_composite1.obj', opts=OPTS, input='p3chan_composite1.cxx') + TargetAdd('p3chan_composite2.obj', opts=OPTS, input='p3chan_composite2.cxx') + + OPTS=['DIR:panda/src/chan', 'PYTHON'] + IGATEFILES=GetDirectoryContents('panda/src/chan', ["*.h", "*_composite*.cxx"]) + IGATEFILES.remove('movingPart.h') + IGATEFILES.remove('animChannelFixed.h') + TargetAdd('libp3chan.in', opts=OPTS, input=IGATEFILES) + TargetAdd('libp3chan.in', opts=['IMOD:panda3d.core', 'ILIB:libp3chan', 'SRCDIR:panda/src/chan']) + TargetAdd('libp3chan_igate.obj', input='libp3chan.in', opts=["DEPENDENCYONLY"]) + + +# DIRECTORY: panda/src/char/ +# + +if (not RUNTIME): + OPTS=['DIR:panda/src/char', 'BUILDING:PANDA'] + TargetAdd('p3char_composite1.obj', opts=OPTS, input='p3char_composite1.cxx') + TargetAdd('p3char_composite2.obj', opts=OPTS, input='p3char_composite2.cxx') + + OPTS=['DIR:panda/src/char', 'PYTHON'] + IGATEFILES=GetDirectoryContents('panda/src/char', ["*.h", "*_composite*.cxx"]) + TargetAdd('libp3char.in', opts=OPTS, input=IGATEFILES) + TargetAdd('libp3char.in', opts=['IMOD:panda3d.core', 'ILIB:libp3char', 'SRCDIR:panda/src/char']) + TargetAdd('libp3char_igate.obj', input='libp3char.in', opts=["DEPENDENCYONLY"]) + # # DIRECTORY: panda/src/pnmtext/ # @@ -4169,6 +4174,7 @@ if (not RUNTIME): TargetAdd('libpanda.dll', input='p3device_composite2.obj') TargetAdd('libpanda.dll', input='p3dgraph_composite1.obj') TargetAdd('libpanda.dll', input='p3dgraph_composite2.obj') + TargetAdd('libpanda.dll', input='p3display_graphicsStateGuardian.obj') TargetAdd('libpanda.dll', input='p3display_composite1.obj') TargetAdd('libpanda.dll', input='p3display_composite2.obj') TargetAdd('libpanda.dll', input='p3pipeline_composite1.obj') @@ -6348,21 +6354,6 @@ if (PkgSkip("PANDATOOL")==0): TargetAdd('p3pstatserver_composite1.obj', opts=OPTS, input='p3pstatserver_composite1.cxx') TargetAdd('libp3pstatserver.lib', input='p3pstatserver_composite1.obj') -# -# DIRECTORY: pandatool/src/softprogs/ -# - -if (PkgSkip("PANDATOOL")==0): - OPTS=['DIR:pandatool/src/softprogs', 'OPENSSL'] - TargetAdd('softcvs_softCVS.obj', opts=OPTS, input='softCVS.cxx') - TargetAdd('softcvs_softFilename.obj', opts=OPTS, input='softFilename.cxx') - TargetAdd('softcvs.exe', input='softcvs_softCVS.obj') - TargetAdd('softcvs.exe', input='softcvs_softFilename.obj') - TargetAdd('softcvs.exe', input='libp3progbase.lib') - TargetAdd('softcvs.exe', input='libp3pandatoolbase.lib') - TargetAdd('softcvs.exe', input=COMMON_PANDA_LIBS) - TargetAdd('softcvs.exe', opts=['ADVAPI']) - # # DIRECTORY: pandatool/src/text-stats/ # diff --git a/makepanda/makepanda.vcproj b/makepanda/makepanda.vcproj index 6be22d7d1a..c4c34db4e3 100644 --- a/makepanda/makepanda.vcproj +++ b/makepanda/makepanda.vcproj @@ -4770,12 +4770,6 @@ - - - - - - @@ -5305,20 +5299,6 @@ - - - - - - - - - - - - - - diff --git a/panda/src/chan/animControl.cxx b/panda/src/chan/animControl.cxx index aa47ea7486..df7fb26498 100644 --- a/panda/src/chan/animControl.cxx +++ b/panda/src/chan/animControl.cxx @@ -32,14 +32,14 @@ AnimControl(const std::string &name, PartBundle *part, Namable(name), _pending_lock(name), _pending_cvar(_pending_lock), - _bound_joints(BitArray::all_on()) + _bound_joints(BitArray::all_on()), + _part(part) { #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); #endif _pending = true; - _part = part; _anim = nullptr; _channel_index = -1; set_frame_rate(frame_rate); diff --git a/panda/src/chan/animControl.h b/panda/src/chan/animControl.h index bee9f7223b..d52b2e4835 100644 --- a/panda/src/chan/animControl.h +++ b/panda/src/chan/animControl.h @@ -39,6 +39,8 @@ class EXPCL_PANDA_CHAN AnimControl : public TypedReferenceCount, public AnimInte public: AnimControl(const std::string &name, PartBundle *part, double frame_rate, int num_frames); + AnimControl(const AnimControl ©) = delete; + void setup_anim(PartBundle *part, AnimBundle *anim, int channel_index, const BitArray &bound_joints); void set_bound_joints(const BitArray &bound_joints); @@ -82,7 +84,7 @@ private: // This is a PT(PartGroup) instead of a PT(PartBundle), just because we // can't include partBundle.h for circular reasons. But it actually keeps a // pointer to a PartBundle. - PT(PartGroup) _part; + const PT(PartGroup) _part; PT(AnimBundle) _anim; int _channel_index; diff --git a/panda/src/chan/partBundle.cxx b/panda/src/chan/partBundle.cxx index 966987995a..9d960f3e7d 100644 --- a/panda/src/chan/partBundle.cxx +++ b/panda/src/chan/partBundle.cxx @@ -556,8 +556,15 @@ control_removed(AnimControl *control) { CDStageWriter cdata(_cycler, pipeline_stage); ChannelBlend::iterator cbi = cdata->_blend.find(control); if (cbi != cdata->_blend.end()) { + cdata->_net_blend -= cbi->second; cdata->_blend.erase(cbi); cdata->_anim_changed = true; + + // We need to make sure that any _effective_channel pointers that point + // to this control are cleared. + if (pipeline_stage == 0) { + determine_effective_channels(cdata); + } } } CLOSE_ITERATE_ALL_STAGES(_cycler); diff --git a/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm b/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm index 26d4dbdf71..b584d02a2c 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm @@ -134,6 +134,12 @@ get_properties(FrameBufferProperties &properties, NSOpenGLPixelFormat* pixel_for if (accelerated) { properties.set_force_hardware(1); } + + // Cautiously setting this to true. It appears that macOS framebuffers are + // sRGB-capable, but I don't really know how to verify this. + if (color_size == 32 && !color_float) { + properties.set_srgb_color(true); + } } /** diff --git a/panda/src/cocoadisplay/cocoaPandaApp.mm b/panda/src/cocoadisplay/cocoaPandaApp.mm index e7226786da..83f0b8ef42 100644 --- a/panda/src/cocoadisplay/cocoaPandaApp.mm +++ b/panda/src/cocoadisplay/cocoaPandaApp.mm @@ -12,6 +12,7 @@ */ #import "cocoaPandaApp.h" +#include "config_cocoadisplay.h" @implementation CocoaPandaApp - (void) sendEvent: (NSEvent *) event { diff --git a/panda/src/collide/collisionTraverser.cxx b/panda/src/collide/collisionTraverser.cxx index 6e8a01d68f..35f7966a3f 100644 --- a/panda/src/collide/collisionTraverser.cxx +++ b/panda/src/collide/collisionTraverser.cxx @@ -1254,7 +1254,7 @@ compare_collider_to_geom(CollisionEntry &entry, const Geom *geom, if (geom->get_primitive_type() == Geom::PT_polygons) { Thread *current_thread = Thread::get_current_thread(); - CPT(GeomVertexData) data = geom->get_vertex_data()->animate_vertices(true, current_thread); + CPT(GeomVertexData) data = geom->get_animated_vertex_data(true, current_thread); GeomVertexReader vertex(data, InternalName::get_vertex()); int num_primitives = geom->get_num_primitives(); diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 57a592f05d..496a05e273 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -753,7 +753,7 @@ render_frame() { // frames, so we won't have to recompute it each frame. int num_drs = win->get_num_active_display_regions(); for (int i = 0; i < num_drs; ++i) { - DisplayRegion *dr = win->get_active_display_region(i); + PT(DisplayRegion) dr = win->get_active_display_region(i); if (dr != nullptr) { NodePath camera_np = dr->get_camera(current_thread); if (!camera_np.is_empty()) { @@ -1359,7 +1359,7 @@ is_scene_root(const PandaNode *node) { if (win->is_active() && win->get_gsg()->is_active()) { int num_display_regions = win->get_num_active_display_regions(); for (int i = 0; i < num_display_regions; i++) { - DisplayRegion *dr = win->get_active_display_region(i); + PT(DisplayRegion) dr = win->get_active_display_region(i); if (dr != nullptr) { NodePath camera = dr->get_camera(); if (camera.is_empty()) { @@ -1435,7 +1435,7 @@ cull_and_draw_together(GraphicsEngine::Windows wlist, int num_display_regions = win->get_num_active_display_regions(); for (int i = 0; i < num_display_regions; i++) { - DisplayRegion *dr = win->get_active_display_region(i); + PT(DisplayRegion) dr = win->get_active_display_region(i); if (dr != nullptr) { cull_and_draw_together(win, dr, current_thread); } @@ -1539,7 +1539,7 @@ cull_to_bins(GraphicsEngine::Windows wlist, Thread *current_thread) { PStatTimer timer(win->get_cull_window_pcollector(), current_thread); int num_display_regions = win->get_num_active_display_regions(); for (int i = 0; i < num_display_regions; ++i) { - DisplayRegion *dr = win->get_active_display_region(i); + PT(DisplayRegion) dr = win->get_active_display_region(i); if (dr != nullptr) { PT(SceneSetup) scene_setup; PT(CullResult) cull_result; @@ -1659,7 +1659,7 @@ draw_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) { } int num_display_regions = win->get_num_active_display_regions(); for (int i = 0; i < num_display_regions; ++i) { - DisplayRegion *dr = win->get_active_display_region(i); + PT(DisplayRegion) dr = win->get_active_display_region(i); if (dr != nullptr) { do_draw(win, gsg, dr, current_thread); } diff --git a/panda/src/display/graphicsOutput.cxx b/panda/src/display/graphicsOutput.cxx index 7c6cef51cb..c8237059b8 100644 --- a/panda/src/display/graphicsOutput.cxx +++ b/panda/src/display/graphicsOutput.cxx @@ -697,9 +697,6 @@ void GraphicsOutput:: remove_all_display_regions() { LightMutexHolder holder(_lock); - CDWriter cdata(_cycler, true); - cdata->_active_display_regions_stale = true; - TotalDisplayRegions::iterator dri; for (dri = _total_display_regions.begin(); dri != _total_display_regions.end(); @@ -713,6 +710,12 @@ remove_all_display_regions() { } _total_display_regions.clear(); _total_display_regions.push_back(_overlay_display_region); + + OPEN_ITERATE_ALL_STAGES(_cycler) { + CDStageWriter cdata(_cycler, pipeline_stage); + cdata->_active_display_regions_stale = true; + } + CLOSE_ITERATE_ALL_STAGES(_cycler); } /** @@ -740,13 +743,8 @@ set_overlay_display_region(DisplayRegion *display_region) { */ int GraphicsOutput:: get_num_display_regions() const { - determine_display_regions(); - int result; - { - LightMutexHolder holder(_lock); - result = _total_display_regions.size(); - } - return result; + LightMutexHolder holder(_lock); + return _total_display_regions.size(); } /** @@ -1504,13 +1502,15 @@ do_remove_display_region(DisplayRegion *display_region) { find(_total_display_regions.begin(), _total_display_regions.end(), drp); if (dri != _total_display_regions.end()) { // Let's aggressively clean up the display region too. - CDWriter cdata(_cycler, true); display_region->cleanup(); display_region->_window = nullptr; _total_display_regions.erase(dri); - cdata->_active_display_regions_stale = true; - + OPEN_ITERATE_ALL_STAGES(_cycler) { + CDStageWriter cdata(_cycler, pipeline_stage); + cdata->_active_display_regions_stale = true; + } + CLOSE_ITERATE_ALL_STAGES(_cycler); return true; } diff --git a/panda/src/display/graphicsOutput.h b/panda/src/display/graphicsOutput.h index acd41e8289..f426b41bee 100644 --- a/panda/src/display/graphicsOutput.h +++ b/panda/src/display/graphicsOutput.h @@ -394,6 +394,7 @@ protected: typedef CycleDataLockedReader CDLockedReader; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; + typedef CycleDataStageWriter CDStageWriter; protected: int _creation_flags; diff --git a/panda/src/display/graphicsPipeSelection.cxx b/panda/src/display/graphicsPipeSelection.cxx index 9c4f52ff63..58866efef6 100644 --- a/panda/src/display/graphicsPipeSelection.cxx +++ b/panda/src/display/graphicsPipeSelection.cxx @@ -18,7 +18,6 @@ #include "load_dso.h" #include "config_display.h" #include "typeRegistry.h" -#include "pset.h" #include "config_putil.h" #include @@ -61,8 +60,8 @@ GraphicsPipeSelection() : _lock("GraphicsPipeSelection") { // Also get the set of modules named in the various aux-display Config // variables. We'll want to know this when we call load_modules() later. - int num_aux = aux_display.get_num_unique_values(); - for (int i = 0; i < num_aux; i++) { + size_t num_aux = aux_display.get_num_unique_values(); + for (size_t i = 0; i < num_aux; ++i) { string name = aux_display.get_unique_value(i); if (name != _default_display_module) { _display_modules.push_back(name); @@ -124,9 +123,7 @@ print_pipe_types() const { LightMutexHolder holder(_lock); nout << "Known pipe types:" << std::endl; - PipeTypes::const_iterator pi; - for (pi = _pipe_types.begin(); pi != _pipe_types.end(); ++pi) { - const PipeType &pipe_type = (*pi); + for (const PipeType &pipe_type : _pipe_types) { nout << " " << pipe_type._type << "\n"; } if (_display_modules.empty()) { @@ -187,11 +184,9 @@ make_pipe(const string &type_name, const string &module_name) { PT(GraphicsPipe) GraphicsPipeSelection:: make_pipe(TypeHandle type) { LightMutexHolder holder(_lock); - PipeTypes::const_iterator ti; // First, look for an exact match of the requested type. - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { if (ptype._type == type) { // Here's an exact match. PT(GraphicsPipe) pipe = (*ptype._constructor)(); @@ -202,8 +197,7 @@ make_pipe(TypeHandle type) { } // Now look for a more-specific type. - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { if (ptype._type.is_derived_from(type)) { // Here's an approximate match. PT(GraphicsPipe) pipe = (*ptype._constructor)(); @@ -215,8 +209,7 @@ make_pipe(TypeHandle type) { // Couldn't find any match; load the default module and try again. load_default_module(); - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { if (ptype._type.is_derived_from(type)) { // Here's an approximate match. PT(GraphicsPipe) pipe = (*ptype._constructor)(); @@ -260,13 +253,11 @@ make_default_pipe() { load_default_module(); LightMutexHolder holder(_lock); - PipeTypes::const_iterator ti; if (!_default_pipe_name.empty()) { // First, look for an exact match of the default type name from the // Configrc file (excepting case and hyphenunderscore). - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { if (cmp_nocase_uh(ptype._type.get_name(), _default_pipe_name) == 0) { // Here's an exact match. PT(GraphicsPipe) pipe = (*ptype._constructor)(); @@ -278,8 +269,7 @@ make_default_pipe() { // No match; look for a substring match. string preferred_name = downcase(_default_pipe_name); - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { string ptype_name = downcase(ptype._type.get_name()); if (ptype_name.find(preferred_name) != string::npos) { // Here's a substring match. @@ -292,8 +282,7 @@ make_default_pipe() { } // Couldn't find a matching pipe type; choose the first one on the list. - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { PT(GraphicsPipe) pipe = (*ptype._constructor)(); if (pipe != nullptr) { return pipe; @@ -310,9 +299,8 @@ make_default_pipe() { */ void GraphicsPipeSelection:: load_aux_modules() { - DisplayModules::iterator di; - for (di = _display_modules.begin(); di != _display_modules.end(); ++di) { - load_named_module(*di); + for (const string &module : _display_modules) { + load_named_module(module); } _display_modules.clear(); @@ -337,9 +325,7 @@ add_pipe_type(TypeHandle type, PipeConstructorFunc *func) { // First, make sure we don't already have a GraphicsPipe of this type. LightMutexHolder holder(_lock); - PipeTypes::const_iterator ti; - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { if (ptype._type == type) { display_cat->warning() << "Attempt to register GraphicsPipe type " << type @@ -375,8 +361,8 @@ do_load_default_module() { load_named_module(_default_display_module); DisplayModules::iterator di = - find(_display_modules.begin(), _display_modules.end(), - _default_display_module); + std::find(_display_modules.begin(), _display_modules.end(), + _default_display_module); if (di != _display_modules.end()) { _display_modules.erase(di); } diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 1050f8372f..0e82a23f88 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -24,7 +24,6 @@ #include "renderBuffer.h" #include "light.h" #include "planeNode.h" -#include "ambientLight.h" #include "throw_event.h" #include "clockObject.h" #include "pStatTimer.h" @@ -60,7 +59,6 @@ #include "fogAttrib.h" #include "config_pstatclient.h" -#include #include using std::string; @@ -932,12 +930,12 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, } case Shader::SMO_frame_time: { PN_stdfloat time = ClockObject::get_global_clock()->get_frame_time(); - t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, time, time, time, time); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, time, time, time, time); return &t; } case Shader::SMO_frame_delta: { PN_stdfloat dt = ClockObject::get_global_clock()->get_dt(); - t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dt, dt, dt, dt); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dt, dt, dt, dt); return &t; } case Shader::SMO_texpad_x: { @@ -949,7 +947,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, double cx = (sx * 0.5) / tex->get_x_size(); double cy = (sy * 0.5) / tex->get_y_size(); double cz = (sz * 0.5) / tex->get_z_size(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,cx,cy,cz,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cx, cy, cz, 0); return &t; } case Shader::SMO_texpix_x: { @@ -958,7 +956,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, double px = 1.0 / tex->get_x_size(); double py = 1.0 / tex->get_y_size(); double pz = 1.0 / tex->get_z_size(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,px,py,pz,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, px, py, pz, 0); return &t; } case Shader::SMO_attr_material: { @@ -966,7 +964,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()); // Material matrix contains AMBIENT, DIFFUSE, EMISSION, SPECULAR+SHININESS if (target_material->is_off()) { - t = LMatrix4(1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0); + t.set(1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0); return &t; } Material *m = target_material->get_material(); @@ -975,17 +973,17 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LVecBase4 const &emm = m->get_emission(); LVecBase4 spc = m->get_specular(); spc[3] = m->get_shininess(); - t = LMatrix4(amb[0],amb[1],amb[2],amb[3], - dif[0],dif[1],dif[2],dif[3], - emm[0],emm[1],emm[2],emm[3], - spc[0],spc[1],spc[2],spc[3]); + t.set(amb[0], amb[1], amb[2], amb[3], + dif[0], dif[1], dif[2], dif[3], + emm[0], emm[1], emm[2], emm[3], + spc[0], spc[1], spc[2], spc[3]); return &t; } case Shader::SMO_attr_material2: { const MaterialAttrib *target_material = (const MaterialAttrib *) _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()); if (target_material->is_off()) { - t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); return &t; } Material *m = target_material->get_material(); @@ -1000,7 +998,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, return &LMatrix4::ones_mat(); } LVecBase4 c = target_color->get_color(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]); return &t; } case Shader::SMO_attr_colorscale: { @@ -1010,7 +1008,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, return &LMatrix4::ones_mat(); } LVecBase4 cs = target_color->get_scale(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,cs[0],cs[1],cs[2],cs[3]); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cs[0], cs[1], cs[2], cs[3]); return &t; } case Shader::SMO_attr_fog: { @@ -1022,7 +1020,8 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, } PN_stdfloat start, end; fog->get_linear_range(start, end); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,fog->get_exp_density(),start,end,1.0f/(end-start)); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + fog->get_exp_density(), start, end, 1.0f / (end - start)); return &t; } case Shader::SMO_attr_fogcolor: { @@ -1033,7 +1032,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, return &LMatrix4::ones_mat(); } LVecBase4 c = fog->get_color(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]); return &t; } case Shader::SMO_alight_x: { @@ -1042,7 +1041,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, AmbientLight *lt; DCAST_INTO_R(lt, np.node(), &LMatrix4::zeros_mat()); LColor const &c = lt->get_color(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]); return &t; } case Shader::SMO_satten_x: { @@ -1052,7 +1051,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, DCAST_INTO_R(lt, np.node(), &LMatrix4::ones_mat()); LVecBase3 const &a = lt->get_attenuation(); PN_stdfloat x = lt->get_exponent(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,a[0],a[1],a[2],x); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a[0], a[1], a[2], x); return &t; } case Shader::SMO_dlight_x: { @@ -1069,7 +1068,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, d.normalize(); LVecBase3 h = d + LVecBase3(0,-1,0); h.normalize(); - t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],c[3],d[0],d[1],d[2],0,h[0],h[1],h[2],0); + t.set(c[0], c[1], c[2], c[3], + s[0], s[1], s[2], c[3], + d[0], d[1], d[2], 0, + h[0], h[1], h[2], 0); return &t; } case Shader::SMO_plight_x: { @@ -1087,7 +1089,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, Lens *lens = lt->get_lens(0); PN_stdfloat lnear = lens->get_near(); PN_stdfloat lfar = lens->get_far(); - t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],lnear,a[0],a[1],a[2],lfar); + t.set(c[0], c[1], c[2], c[3], + s[0], s[1], s[2], s[3], + p[0], p[1], p[2], lnear, + a[0], a[1], a[2], lfar); return &t; } case Shader::SMO_slight_x: { @@ -1105,7 +1110,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, _scene_setup->get_world_transform()->get_mat(); LVecBase3 p = t.xform_point(lens->get_nodal_point()); LVecBase3 d = -(t.xform_vec(lens->get_view_vector())); - t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,d[0],d[1],d[2],cutoff); + t.set(c[0], c[1], c[2], c[3], + s[0], s[1], s[2], s[3], + p[0], p[1], p[2], 0, + d[0], d[1], d[2], cutoff); return &t; } case Shader::SMO_light_ambient: { @@ -1149,7 +1157,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma) && index < ta->get_num_on_stages()) { LVecBase3 scale = tma->get_transform(ta->get_on_stage(index))->get_scale(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,scale[0],scale[1],scale[2],0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, scale[0], scale[1], scale[2], 0); return &t; } else { return &LMatrix4::ident_mat(); @@ -1173,7 +1181,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, index < ta->get_num_on_stages()) { TextureStage *ts = ta->get_on_stage(index); PN_stdfloat v = (ta->get_on_texture(ts)->get_format() == Texture::F_alpha); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,v,v,v,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, v, v, v, 0); return &t; } else { return &LMatrix4::zeros_mat(); @@ -1185,7 +1193,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, const PlaneNode *plane_node; DCAST_INTO_R(plane_node, np.node(), &LMatrix4::zeros_mat()); LPlane p = plane_node->get_plane(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,p[0],p[1],p[2],p[3]); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, p[0], p[1], p[2], p[3]); return &t; } case Shader::SMO_clipplane_x: { @@ -1235,10 +1243,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, case Shader::SMO_vec_constant_x: { const LVecBase4 &input = _target_shader->get_shader_input_vector(name); const PN_stdfloat *data = input.get_data(); - t = LMatrix4(data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3]); + t.set(data[0], data[1], data[2], data[3], + data[0], data[1], data[2], data[3], + data[0], data[1], data[2], data[3], + data[0], data[1], data[2], data[3]); return &t; } case Shader::SMO_world_to_view: { @@ -1394,10 +1402,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, // There is an input specifying precisely this whole thing, with dot and // all. Support this, even if only for backward compatibility. const LVecBase4 &data = _target_shader->get_shader_input_vector(name); - t = LMatrix4(data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3]); + t.set(data[0], data[1], data[2], data[3], + data[0], data[1], data[2], data[3], + data[0], data[1], data[2], data[3], + data[0], data[1], data[2], data[3]); return &t; } @@ -1578,11 +1586,11 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) } else if (attrib == IN_position) { if (np.is_empty()) { - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); return &t; } else if (node->is_ambient_light()) { // Ambient light has no position. - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); return &t; } else if (node->is_of_type(DirectionalLight::get_class_type())) { DirectionalLight *light; @@ -1591,7 +1599,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent()); LVector3 dir = -(light->get_direction() * transform->get_mat()); dir *= _scene_setup->get_cs_world_transform()->get_mat(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dir[0], dir[1], dir[2], 0); return &t; } else { LightLensNode *light; @@ -1611,11 +1619,11 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) } else if (attrib == IN_halfVector) { if (np.is_empty()) { - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); return &t; } else if (node->is_ambient_light()) { // Ambient light has no half-vector. - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); return &t; } else if (node->is_of_type(DirectionalLight::get_class_type())) { DirectionalLight *light; @@ -1627,7 +1635,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) dir.normalize(); dir += LVector3(0, 0, 1); dir.normalize(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],1); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dir[0], dir[1], dir[2], 1); return &t; } else { LightLensNode *light; @@ -1644,7 +1652,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) pos.normalize(); pos += LVector3(0, 0, 1); pos.normalize(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,pos[0],pos[1],pos[2],1); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pos[0],pos[1],pos[2], 1); return &t; } @@ -2722,7 +2730,7 @@ do_issue_color_scale() { } if (_alpha_scale_via_texture && !_has_scene_graph_color && - target_color_scale->has_alpha_scale()) { + _vertex_colors_enabled && target_color_scale->has_alpha_scale()) { // This color scale will set a special texture--so again, clear the // texture. _state_mask.clear_bit(TextureAttrib::get_class_slot()); @@ -3168,6 +3176,17 @@ determine_light_color_scale() { _scene_graph_color[3] * _current_color_scale[3]); } + } else if (!_vertex_colors_enabled) { + // We don't have a scene graph color, but we don't want to enable vertex + // colors either, so we still need to force a white material color in + // absence of any other color. + _has_material_force_color = true; + _material_force_color.set(1.0f, 1.0f, 1.0f, 1.0f); + _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f); + if (!_color_blend_involves_color_scale && _color_scale_enabled) { + _material_force_color.componentwise_mult(_current_color_scale); + } + } else { // Otherise, leave the materials alone, but we might still scale the // lights. diff --git a/panda/src/display/graphicsWindowProc.h b/panda/src/display/graphicsWindowProc.h index c9c056eebd..a330c06a11 100644 --- a/panda/src/display/graphicsWindowProc.h +++ b/panda/src/display/graphicsWindowProc.h @@ -32,6 +32,7 @@ class GraphicsWindow; class EXPCL_PANDA_DISPLAY GraphicsWindowProc { public: GraphicsWindowProc(); + virtual ~GraphicsWindowProc() = default; #if defined(__WIN32__) || defined(_WIN32) virtual LONG wnd_proc(GraphicsWindow* graphicsWindow, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); diff --git a/panda/src/display/p3display_composite2.cxx b/panda/src/display/p3display_composite2.cxx index c2d47f7aad..ef13357435 100644 --- a/panda/src/display/p3display_composite2.cxx +++ b/panda/src/display/p3display_composite2.cxx @@ -1,5 +1,4 @@ #include "graphicsPipeSelection.cxx" -#include "graphicsStateGuardian.cxx" #include "graphicsThreadingModel.cxx" #include "graphicsWindow.cxx" #include "graphicsWindowProc.cxx" diff --git a/panda/src/display/standardMunger.cxx b/panda/src/display/standardMunger.cxx index 94f376e99b..2dba4aa6c0 100644 --- a/panda/src/display/standardMunger.cxx +++ b/panda/src/display/standardMunger.cxx @@ -12,10 +12,14 @@ */ #include "standardMunger.h" -#include "renderState.h" -#include "graphicsStateGuardian.h" + #include "config_gobj.h" + #include "displayRegion.h" +#include "graphicsStateGuardian.h" +#include "lightAttrib.h" +#include "materialAttrib.h" +#include "renderState.h" TypeHandle StandardMunger::_type_handle; @@ -55,24 +59,10 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state, const ColorScaleAttrib *color_scale_attrib; if (state->get_attrib(color_attrib) && - color_attrib->get_color_type() == ColorAttrib::T_flat) { + color_attrib->get_color_type() != ColorAttrib::T_vertex) { - if (!get_gsg()->get_color_scale_via_lighting()) { - // We only need to munge the color directly if the GSG says it can't - // cheat the color via lighting (presumably, in this case, by applying - // a material). - _color = color_attrib->get_color(); - if (state->get_attrib(color_scale_attrib) && - color_scale_attrib->has_scale()) { - const LVecBase4 &cs = color_scale_attrib->get_scale(); - _color.set(_color[0] * cs[0], - _color[1] * cs[1], - _color[2] * cs[2], - _color[3] * cs[3]); - } - _munge_color = true; - _should_munge_state = true; - } + // In this case, we don't need to munge anything as we can apply the + // color and color scale via glColor4f. } else if (state->get_attrib(color_scale_attrib) && color_scale_attrib->has_scale()) { diff --git a/panda/src/display/standardMunger.h b/panda/src/display/standardMunger.h index 5703fd01b5..d7c71e28e5 100644 --- a/panda/src/display/standardMunger.h +++ b/panda/src/display/standardMunger.h @@ -51,12 +51,13 @@ private: NumericType _numeric_type; Contents _contents; - bool _munge_color; - bool _munge_color_scale; bool _auto_shader; bool _shader_skinning; bool _remove_material; +protected: + bool _munge_color; + bool _munge_color_scale; LColor _color; LVecBase4 _color_scale; diff --git a/panda/src/display/subprocessWindow.cxx b/panda/src/display/subprocessWindow.cxx index 03b438ac1f..21e4b634c2 100644 --- a/panda/src/display/subprocessWindow.cxx +++ b/panda/src/display/subprocessWindow.cxx @@ -18,6 +18,8 @@ #include "graphicsEngine.h" #include "config_display.h" #include "nativeWindowHandle.h" +#include "mouseButton.h" +#include "throw_event.h" using std::string; diff --git a/panda/src/distort/projectionScreen.cxx b/panda/src/distort/projectionScreen.cxx index e3bed91e27..74314bce06 100644 --- a/panda/src/distort/projectionScreen.cxx +++ b/panda/src/distort/projectionScreen.cxx @@ -484,8 +484,7 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) { const LMatrix4 &to_uv = _invert_uvs ? lens_to_uv_inverted : lens_to_uv; // Iterate through all the vertices in the Geom. - CPT(GeomVertexData) vdata = geom->get_vertex_data(current_thread); - vdata = vdata->animate_vertices(true, current_thread); + CPT(GeomVertexData) vdata = geom->get_animated_vertex_data(true, current_thread); CPT(GeomVertexFormat) vformat = vdata->get_format(); if (!vformat->has_column(_texcoord_name) || (_texcoord_3d && vformat->get_column(_texcoord_name)->get_num_components() < 3)) { @@ -507,7 +506,7 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) { PT(GeomVertexData) modify_vdata = geom->modify_vertex_data(); // Maybe the vdata has animation that we should consider. - CPT(GeomVertexData) animated_vdata = geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread); + CPT(GeomVertexData) animated_vdata = geom->get_animated_vertex_data(true, current_thread); GeomVertexWriter texcoord(modify_vdata, _texcoord_name, current_thread); GeomVertexWriter color(modify_vdata, current_thread); @@ -674,9 +673,8 @@ make_mesh_geom(const Geom *geom, Lens *lens, LMatrix4 &rel_mat) { Thread *current_thread = Thread::get_current_thread(); PT(Geom) new_geom = geom->make_copy(); + new_geom->set_vertex_data(new_geom->get_animated_vertex_data(false, current_thread)); PT(GeomVertexData) vdata = new_geom->modify_vertex_data(); - new_geom->set_vertex_data(vdata->animate_vertices(false, current_thread)); - vdata = new_geom->modify_vertex_data(); GeomVertexRewriter vertex(vdata, InternalName::get_vertex()); while (!vertex.is_at_end()) { LVertex vert = vertex.get_data3(); diff --git a/panda/src/dxgsg9/dxGeomMunger9.I b/panda/src/dxgsg9/dxGeomMunger9.I index cc972bf94b..2accff3b11 100644 --- a/panda/src/dxgsg9/dxGeomMunger9.I +++ b/panda/src/dxgsg9/dxGeomMunger9.I @@ -10,34 +10,3 @@ * @author drose * @date 2005-03-11 */ - -/** - * - */ -INLINE DXGeomMunger9:: -DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state) : - StandardMunger(gsg, state, 1, NT_packed_dabc, C_color), - _texture(nullptr), - _tex_gen(nullptr) -{ - const TextureAttrib *texture = nullptr; - const TexGenAttrib *tex_gen = nullptr; - state->get_attrib(texture); - state->get_attrib(tex_gen); - _texture = texture; - _tex_gen = tex_gen; - - _filtered_texture = nullptr; - _reffed_filtered_texture = false; - if (texture != nullptr) { - _filtered_texture = texture->filter_to_max(gsg->get_max_texture_stages()); - if (_filtered_texture != texture) { - _filtered_texture->ref(); - _reffed_filtered_texture = true; - } - } - // Set a callback to unregister ourselves when either the Texture or the - // TexGen object gets deleted. - _texture.add_callback(this); - _tex_gen.add_callback(this); -} diff --git a/panda/src/dxgsg9/dxGeomMunger9.cxx b/panda/src/dxgsg9/dxGeomMunger9.cxx index 638b121f27..0e95070c91 100644 --- a/panda/src/dxgsg9/dxGeomMunger9.cxx +++ b/panda/src/dxgsg9/dxGeomMunger9.cxx @@ -19,6 +19,66 @@ GeomMunger *DXGeomMunger9::_deleted_chain = nullptr; TypeHandle DXGeomMunger9::_type_handle; +/** + * + */ +DXGeomMunger9:: +DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state) : + StandardMunger(gsg, state, 1, NT_packed_dabc, C_color), + _texture(nullptr), + _tex_gen(nullptr) +{ + const TextureAttrib *texture = nullptr; + const TexGenAttrib *tex_gen = nullptr; + state->get_attrib(texture); + state->get_attrib(tex_gen); + _texture = texture; + _tex_gen = tex_gen; + + if (!gsg->get_color_scale_via_lighting()) { + // We might need to munge the colors, if we are overriding the vertex + // colors and the GSG can't cheat the color via lighting. + + const ColorAttrib *color_attrib; + const ShaderAttrib *shader_attrib; + state->get_attrib_def(shader_attrib); + + if (!shader_attrib->auto_shader() && + shader_attrib->get_shader() == nullptr && + state->get_attrib(color_attrib) && + color_attrib->get_color_type() != ColorAttrib::T_vertex) { + + if (color_attrib->get_color_type() == ColorAttrib::T_off) { + _color.set(1, 1, 1, 1); + } else { + _color = color_attrib->get_color(); + } + + const ColorScaleAttrib *color_scale_attrib; + if (state->get_attrib(color_scale_attrib) && + color_scale_attrib->has_scale()) { + _color.componentwise_mult(color_scale_attrib->get_scale()); + } + _munge_color = true; + _should_munge_state = true; + } + } + + _filtered_texture = nullptr; + _reffed_filtered_texture = false; + if (texture != nullptr) { + _filtered_texture = texture->filter_to_max(gsg->get_max_texture_stages()); + if (_filtered_texture != texture) { + _filtered_texture->ref(); + _reffed_filtered_texture = true; + } + } + // Set a callback to unregister ourselves when either the Texture or the + // TexGen object gets deleted. + _texture.add_callback(this); + _tex_gen.add_callback(this); +} + /** * */ diff --git a/panda/src/dxgsg9/dxGeomMunger9.h b/panda/src/dxgsg9/dxGeomMunger9.h index c0762e3cf3..c0cb8f8edd 100644 --- a/panda/src/dxgsg9/dxGeomMunger9.h +++ b/panda/src/dxgsg9/dxGeomMunger9.h @@ -28,7 +28,7 @@ */ class EXPCL_PANDADX DXGeomMunger9 : public StandardMunger, public WeakPointerCallback { public: - INLINE DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state); + DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state); virtual ~DXGeomMunger9(); ALLOC_DELETED_CHAIN(DXGeomMunger9); diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index 0921350629..b7b0f7d3e7 100644 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -140,6 +140,7 @@ DXGraphicsStateGuardian9(GraphicsEngine *engine, GraphicsPipe *pipe) : _last_fvf = 0; _num_bound_streams = 0; + _white_vbuffer = nullptr; _vertex_shader_version_major = 0; _vertex_shader_version_minor = 0; @@ -798,9 +799,9 @@ clear(DrawableRegion *clearable) { main_flags |= D3DCLEAR_TARGET; } - if (clearable->get_clear_depth_active()) { + if (clearable->get_clear_depth_active() && + _screen->_presentation_params.EnableAutoDepthStencil) { aux_flags |= D3DCLEAR_ZBUFFER; - nassertv(_screen->_presentation_params.EnableAutoDepthStencil); } if (clearable->get_clear_stencil_active()) { @@ -4545,6 +4546,11 @@ reset_d3d_device(D3DPRESENT_PARAMETERS *presentation_params, release_all_vertex_buffers(); release_all_index_buffers(); + if (_white_vbuffer != nullptr) { + _white_vbuffer->Release(); + _white_vbuffer = nullptr; + } + // must be called before reset Thread *current_thread = Thread::get_current_thread(); _prepared_objects->begin_frame(this, current_thread); @@ -5234,9 +5240,9 @@ calc_fb_properties(DWORD cformat, DWORD dformat, #define GAMMA_1 (255.0 * 256.0) static bool _gamma_table_initialized = false; -static unsigned short _orignial_gamma_table [256 * 3]; +static unsigned short _original_gamma_table [256 * 3]; -void _create_gamma_table (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) { +void _create_gamma_table_dx9 (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) { int i; double gamma_correction; @@ -5298,7 +5304,7 @@ get_gamma_table(void) { HDC hdc = GetDC(nullptr); if (hdc) { - if (GetDeviceGammaRamp (hdc, (LPVOID) _orignial_gamma_table)) { + if (GetDeviceGammaRamp (hdc, (LPVOID) _original_gamma_table)) { _gamma_table_initialized = true; get = true; } @@ -5323,10 +5329,10 @@ static_set_gamma(bool restore, PN_stdfloat gamma) { unsigned short ramp [256 * 3]; if (restore && _gamma_table_initialized) { - _create_gamma_table (gamma, &_orignial_gamma_table [0], &_orignial_gamma_table [256], &_orignial_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]); + _create_gamma_table_dx9 (gamma, &_original_gamma_table [0], &_original_gamma_table [256], &_original_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]); } else { - _create_gamma_table (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]); + _create_gamma_table_dx9 (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]); } if (SetDeviceGammaRamp (hdc, ramp)) { @@ -5404,6 +5410,40 @@ set_cg_device(LPDIRECT3DDEVICE9 cg_device) { #endif // HAVE_CG } +/** + * Returns a vertex buffer containing only a full-white color. + */ +LPDIRECT3DVERTEXBUFFER9 DXGraphicsStateGuardian9:: +get_white_vbuffer() { + if (_white_vbuffer != nullptr) { + return _white_vbuffer; + } + + LPDIRECT3DVERTEXBUFFER9 vbuffer; + HRESULT hr; + hr = _screen->_d3d_device->CreateVertexBuffer(sizeof(D3DCOLOR), D3DUSAGE_WRITEONLY, D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &vbuffer, nullptr); + + if (FAILED(hr)) { + dxgsg9_cat.error() + << "CreateVertexBuffer failed" << D3DERRORSTRING(hr); + return nullptr; + } + + D3DCOLOR *local_pointer; + hr = vbuffer->Lock(0, sizeof(D3DCOLOR), (void **) &local_pointer, D3DLOCK_DISCARD); + if (FAILED(hr)) { + dxgsg9_cat.error() + << "VertexBuffer::Lock failed" << D3DERRORSTRING(hr); + return false; + } + + *local_pointer = D3DCOLOR_ARGB(255, 255, 255, 255); + + vbuffer->Unlock(); + _white_vbuffer = vbuffer; + return vbuffer; +} + typedef std::string KEY; typedef struct _KEY_ELEMENT diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h index 66b2fb82d5..8852f413a7 100644 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h @@ -168,6 +168,7 @@ public: static void set_cg_device(LPDIRECT3DDEVICE9 cg_device); virtual bool get_supports_cg_profile(const std::string &name) const; + LPDIRECT3DVERTEXBUFFER9 get_white_vbuffer(); protected: void do_issue_transform(); @@ -274,12 +275,6 @@ protected: RenderBuffer::Type _cur_read_pixel_buffer; // source for copy_pixel_buffer operation - PN_stdfloat _material_ambient; - PN_stdfloat _material_diffuse; - PN_stdfloat _material_specular; - PN_stdfloat _material_shininess; - PN_stdfloat _material_emission; - enum DxgsgFogType { None, PerVertexFog=D3DRS_FOGVERTEXMODE, @@ -320,6 +315,7 @@ protected: DWORD _last_fvf; int _num_bound_streams; + LPDIRECT3DVERTEXBUFFER9 _white_vbuffer; // Cache the data necessary to bind each particular light each frame, so if // we bind a given light multiple times, we only have to compute its data diff --git a/panda/src/dxgsg9/dxInput9.cxx b/panda/src/dxgsg9/dxInput9.cxx deleted file mode 100644 index 17d5b2f88e..0000000000 --- a/panda/src/dxgsg9/dxInput9.cxx +++ /dev/null @@ -1,269 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file dxInput9.cxx - * @author angelina jolie - * @date 1999-10-07 - */ - -#include "config_wdxdisplay9.h" -#include "dxInput9.h" - -#define AXIS_RESOLUTION 2000 // use this many levels of resolution by default (could be more if needed and device supported it) -#define AXIS_RANGE_CENTERED // if defined, axis range is centered on 0, instead of starting on 0 - -using std::endl; - -BOOL CALLBACK EnumGameCtrlsCallback( const DIDEVICEINSTANCE* pdidInstance, - VOID* pContext ) { - DI_DeviceInfos *pDevInfos = (DI_DeviceInfos *)pContext; - - (*pDevInfos).push_back(*pdidInstance); - - if(wdxdisplay_cat.is_debug()) - wdxdisplay_cat.debug() << "Found DevType 0x" << (void*)pdidInstance->dwDevType << ": " << pdidInstance->tszInstanceName << ": " << pdidInstance->tszProductName <Unacquire(); - SAFE_RELEASE(_DeviceList[i]); - } - - // bugbug: need to handle this if(_JoystickPollTimer!=NULL) KillTimer(...) - - SAFE_RELEASE(_pDInput9); - if(_hDInputDLL) { - FreeLibrary(_hDInputDLL); - _hDInputDLL=nullptr; - } -} - -bool DInput9Info::InitDirectInput() { - HRESULT hr; - - // assumes dx9 exists use dynamic load so non-dinput programs don't have - // to load dinput - #define DLLNAME "dinput9.dll" - #define DINPUTCREATE "DirectInput9Create" - - HINSTANCE _hDInputDLL = LoadLibrary(DLLNAME); - if(_hDInputDLL == 0) { - wdxdisplay_cat.fatal() << "LoadLibrary(" << DLLNAME <<") failed!, error=" << GetLastError() << endl; - exit(1); - } - - typedef HRESULT (WINAPI * LPDIRECTINPUT9CREATE)(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter); - LPDIRECTINPUT9CREATE pDInputCreate9; - - pDInputCreate9 = (LPDIRECTINPUT9CREATE) GetProcAddress(_hDInputDLL,DINPUTCREATE); - if(pDInputCreate9 == nullptr) { - wdxdisplay_cat.fatal() << "GetProcAddr failed for " << DINPUTCREATE << endl; - exit(1); - } - - // Register with the DirectInput subsystem and get a pointer to a - // IDirectInput interface we can use. Create a DInput object - if( FAILED( hr = (*pDInputCreate9)(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, - IID_IDirectInput9, (VOID**)&_pDInput9, nullptr ) ) ) { - wdxdisplay_cat.error() << DINPUTCREATE << "failed" << D3DERRORSTRING(hr); - return false; - } - - // enum all the joysticks,etc (but not keybdmouse) - if( FAILED( hr = _pDInput9->EnumDevices(DI9DEVCLASS_GAMECTRL, - EnumGameCtrlsCallback, - (LPVOID)&_DevInfos, DIEDFL_ATTACHEDONLY ) ) ) { - wdxdisplay_cat.error() << "EnumDevices failed" << D3DERRORSTRING(hr); - return false; - } - - return true; -} - -bool DInput9Info::CreateJoystickOrPad(HWND _window) { - bool bFoundDev = false; - UINT devnum=0; - char *errstr=nullptr; - - // look through the list for the first joystick or gamepad - for(;devnum<_DevInfos.size();devnum++) { - DWORD devType = GET_DIDEVICE_TYPE(_DevInfos[devnum].dwDevType); - if((devType==DI9DEVTYPE_GAMEPAD) ||(devType==DI9DEVTYPE_JOYSTICK)) { - bFoundDev=true; - break; - } - } - - if(!bFoundDev) { - wdxdisplay_cat.error() << "Cant find an attached Joystick or GamePad!\n"; - return false; - } - - LPDIRECTINPUTDEVICE9 pJoyDevice; - - // Obtain an interface to the enumerated joystick. - HRESULT hr = _pDInput9->CreateDevice(_DevInfos[devnum].guidInstance, &pJoyDevice, nullptr ); - if(FAILED(hr)) { - errstr="CreateDevice"; - goto handle_error; - } - - assert(pJoyDevice!=nullptr); - _DeviceList.push_back(pJoyDevice); - - // Set the data format to "simple joystick" - a predefined data format A - // data format specifies which controls on a device we are interested in, - // and how they should be reported. This tells DInput that we will be - // passing a DIJOYSTATE2 structure to - // IDirectInputDevice::GetDeviceState(). - hr = pJoyDevice->SetDataFormat(&c_dfDIJoystick2); - if(FAILED(hr)) { - errstr="SetDataFormat"; - goto handle_error; - } - - // must be called AFTER SetDataFormat to get all the proper flags - DX_DECLARE_CLEAN(DIDEVCAPS, DIDevCaps); - hr = pJoyDevice->GetCapabilities(&DIDevCaps); - assert(SUCCEEDED(hr)); - - _DevCaps.push_back(DIDevCaps); - - if(wdxdisplay_cat.is_debug()) - wdxdisplay_cat.debug() << "Joy/Pad has " << DIDevCaps.dwAxes << " Axes, " << DIDevCaps.dwButtons << " Buttons, " << DIDevCaps.dwPOVs << " POVs" << endl; - - // Set the cooperative level to let DInput know how this device should - // interact with the system and with other DInput applications. - hr = pJoyDevice->SetCooperativeLevel( _window, DISCL_EXCLUSIVE | DISCL_FOREGROUND); - if(FAILED(hr)) { - errstr="SetCooperativeLevel"; - goto handle_error; - } - - // set the minmax values property for discovered axes. - hr = pJoyDevice->EnumObjects(EnumObjectsCallbackJoystick, (LPVOID)pJoyDevice, DIDFT_AXIS); - if(FAILED(hr)) { - errstr="EnumObjects"; - goto handle_error; - } - - return true; - - handle_error: - wdxdisplay_cat.error() << errstr << " failed for (" << _DevInfos[devnum].tszInstanceName << ":" << _DevInfos[devnum].tszProductName << ")" << D3DERRORSTRING(hr); - return false; -} - -// --------------------------------------------------------------------------- -// -- Name: EnumObjectsCallback() Desc: Callback function for enumerating -// objects (axes, buttons, POVs) on a joystick. This function enables user -// interface elements for objects that are found to exist, and scales axes -// minmax values. ----------------------------------------------------------- -// ------------------ -BOOL CALLBACK EnumObjectsCallbackJoystick( const DIDEVICEOBJECTINSTANCE* pdidoi, - VOID* pContext ) { - - LPDIRECTINPUTDEVICE9 pJoyDevice = (LPDIRECTINPUTDEVICE9) pContext; - HRESULT hr; - - // For axes that are returned, set the DIPROP_RANGE property for the - // enumerated axis in order to scale minmax values. - if( pdidoi->dwType & DIDFT_AXIS ) { - DIPROPRANGE diprg; - diprg.diph.dwSize = sizeof(DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYID; - diprg.diph.dwObj = pdidoi->dwType; // Specify the enumerated axis - - #ifdef AXIS_RANGE_CENTERED - diprg.lMin = -AXIS_RESOLUTION/2; - diprg.lMax = +AXIS_RESOLUTION/2; - #else - diprg.lMin = 0; - diprg.lMax = +AXIS_RESOLUTION; - #endif - - // Set the range for the axis - hr = pJoyDevice->SetProperty( DIPROP_RANGE, &diprg.diph); - if(FAILED(hr)) { - wdxdisplay_cat.error() << "SetProperty on axis failed" << D3DERRORSTRING(hr); - return DIENUM_STOP; - } - } - - return DIENUM_CONTINUE; -} - -bool DInput9Info::ReadJoystick(int devnum, DIJOYSTATE2 &js) { - LPDIRECTINPUTDEVICE9 pJoystick = _DeviceList[devnum]; - assert(pJoystick!=nullptr); - HRESULT hr; - char *errstr; - - // Poll the device to read the current state - - hr = pJoystick->Poll(); - - if( FAILED(hr) ) { - // DInput is telling us that the input stream has been interrupted. - // We aren't tracking any state between polls, so we don't have any - // special reset that needs to be done. We just re-acquire and try - // again. - - if((hr==DIERR_NOTACQUIRED)||(hr == DIERR_INPUTLOST)) { - hr = pJoystick->Acquire(); - - if(FAILED(hr)) { - if(wdxdisplay_cat.is_spam()) - wdxdisplay_cat.spam() << "Acquire failed" << D3DERRORSTRING(hr); - - // hr may be DIERR_OTHERAPPHASPRIO or other errors. This may - // occur when the app is minimized or in the process of - // switching, so just try again later - return false; - } - - hr = pJoystick->Poll(); - if(FAILED(hr)) { - // should never happen! - errstr = "Poll after successful Acquire failed"; - goto handle_error; - } - } else { - errstr = "Unknown Poll failure"; - goto handle_error; - } - } - - // should we make a vector of devstate dataformats to generalize this fn - // for all device types? - - // Get the input's device state - hr = pJoystick->GetDeviceState( sizeof(DIJOYSTATE2), &js); - if(FAILED(hr)) { - errstr = "GetDeviceState failed"; - goto handle_error; - } - - return true; - - handle_error: - wdxdisplay_cat.fatal() << errstr << D3DERRORSTRING(hr); - return false; -} diff --git a/panda/src/dxgsg9/dxInput9.h b/panda/src/dxgsg9/dxInput9.h deleted file mode 100644 index 9614a2627d..0000000000 --- a/panda/src/dxgsg9/dxInput9.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file dxInput9.h - * @author blllyjo - * @date 1999-10-07 - */ - -#ifndef DXINPUT9_H -#define DXINPUT9_H - -#define DIRECTINPUT_VERSION 0x900 -#include -typedef std::vector DI_DeviceInfos; -typedef std::vector DI_DeviceObjInfos; - -class DInput9Info { -public: - DInput9Info(); - ~DInput9Info(); - bool InitDirectInput(); - bool CreateJoystickOrPad(HWND _window); - bool ReadJoystick(int devnum, DIJOYSTATE2 &js); - - HINSTANCE _hDInputDLL; - UINT_PTR _JoystickPollTimer; - LPDIRECTINPUT8 _pDInput9; - DI_DeviceInfos _DevInfos; - // arrays for all created devices. Should probably put these together in a - // struct, along with the data fmt info - std::vector _DeviceList; - std::vector _DevCaps; -}; - -#endif diff --git a/panda/src/dxgsg9/dxShaderContext9.cxx b/panda/src/dxgsg9/dxShaderContext9.cxx index 6513ce8a89..a737c342bf 100644 --- a/panda/src/dxgsg9/dxShaderContext9.cxx +++ b/panda/src/dxgsg9/dxShaderContext9.cxx @@ -390,6 +390,8 @@ update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force) { // arrays ("streams"), and we repeatedly iterate the parameters to pull // out only those for a single stream. + bool apply_white_color = false; + int number_of_arrays = gsg->_data_reader->get_num_arrays(); for (int array_index = 0; array_index < number_of_arrays; ++array_index) { const GeomVertexArrayDataHandle* array_reader = @@ -423,6 +425,11 @@ update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force) { } } + if (name == InternalName::get_color() && !gsg->_vertex_colors_enabled) { + apply_white_color = true; + continue; + } + const GeomVertexArrayDataHandle *param_array_reader; Geom::NumericType numeric_type; int num_values, start, stride; @@ -435,6 +442,9 @@ update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force) { // shader parameter, which can cause Bad Things to happen so I'd // like to at least get a hint as to what's gone wrong. dxgsg9_cat.info() << "Geometry contains no data for shader parameter " << *name << "\n"; + if (name == InternalName::get_color()) { + apply_white_color = true; + } continue; } @@ -564,6 +574,19 @@ update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force) { _num_bound_streams = number_of_arrays; + if (apply_white_color) { + // The shader needs a vertex color, but vertex colors are disabled. + // Bind a vertex buffer containing only one white colour. + int array_index = number_of_arrays; + LPDIRECT3DVERTEXBUFFER9 vbuffer = gsg->get_white_vbuffer(); + hr = device->SetStreamSource(array_index, vbuffer, 0, 0); + if (FAILED(hr)) { + dxgsg9_cat.error() << "SetStreamSource failed" << D3DERRORSTRING(hr); + } + vertex_element_array->add_diffuse_color_vertex_element(array_index, 0); + ++_num_bound_streams; + } + if (_vertex_element_array != nullptr && _vertex_element_array->add_end_vertex_element()) { if (dxgsg9_cat.is_debug()) { diff --git a/panda/src/dxgsg9/wdxGraphicsWindow9.cxx b/panda/src/dxgsg9/wdxGraphicsWindow9.cxx index 3136d75fd0..3207c81189 100644 --- a/panda/src/dxgsg9/wdxGraphicsWindow9.cxx +++ b/panda/src/dxgsg9/wdxGraphicsWindow9.cxx @@ -1229,7 +1229,10 @@ init_resized_window() { DWORD flags; D3DCOLOR clear_color; - flags = D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER; + flags = D3DCLEAR_TARGET; + if (_fb_properties.get_depth_bits() > 0) { + flags |= D3DCLEAR_ZBUFFER; + } clear_color = 0x00000000; hr = _wcontext._d3d_device-> Clear (0, nullptr, flags, clear_color, 0.0f, 0); if (FAILED(hr)) { diff --git a/panda/src/dxgsg9/wdxGraphicsWindow9.h b/panda/src/dxgsg9/wdxGraphicsWindow9.h index 391fb9d7e9..42a6fe6763 100644 --- a/panda/src/dxgsg9/wdxGraphicsWindow9.h +++ b/panda/src/dxgsg9/wdxGraphicsWindow9.h @@ -17,7 +17,6 @@ #include "pandabase.h" #include "winGraphicsWindow.h" #include "dxGraphicsStateGuardian9.h" -#include "dxInput9.h" #include "wdxGraphicsPipe9.h" class wdxGraphicsPipe9; diff --git a/panda/src/express/pointerToArray_ext.I b/panda/src/express/pointerToArray_ext.I index ee4c10e155..5bcd1b77e9 100644 --- a/panda/src/express/pointerToArray_ext.I +++ b/panda/src/express/pointerToArray_ext.I @@ -38,7 +38,8 @@ INLINE void set_matrix_view(Py_buffer &view, int flags, int length, int size, bo } else if (size == 4 && double_prec) { mat_size = sizeof(UnalignedLMatrix4d); } else { - assert(false); + nassertv_always(false); + return; // Make sure compiler knows control flow doesn't proceed. } view.len = length * mat_size; diff --git a/panda/src/express/pointerToArray_ext.h b/panda/src/express/pointerToArray_ext.h index 2daf885943..f17d1b634a 100644 --- a/panda/src/express/pointerToArray_ext.h +++ b/panda/src/express/pointerToArray_ext.h @@ -97,11 +97,11 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const; #ifdef _MSC_VER // Ugh... MSVC needs this because they still don't have a decent linker. -#include "PTA_uchar.h" -#include "PTA_ushort.h" -#include "PTA_float.h" -#include "PTA_double.h" -#include "PTA_int.h" +#include "pta_uchar.h" +#include "pta_ushort.h" +#include "pta_float.h" +#include "pta_double.h" +#include "pta_int.h" template class EXPORT_THIS Extension; template class EXPORT_THIS Extension; diff --git a/panda/src/gles2gsg/gles2gsg.h b/panda/src/gles2gsg/gles2gsg.h index 8d80e690eb..363baad0ca 100644 --- a/panda/src/gles2gsg/gles2gsg.h +++ b/panda/src/gles2gsg/gles2gsg.h @@ -51,7 +51,7 @@ // OpenGL ES 2 has no fixed-function pipeline. #undef SUPPORT_FIXED_FUNCTION -#ifdef IS_OSX +#ifdef BUILD_IPHONE #include // #include #else diff --git a/panda/src/glesgsg/glesgsg.h b/panda/src/glesgsg/glesgsg.h index 64d64db216..b7c7348cb9 100644 --- a/panda/src/glesgsg/glesgsg.h +++ b/panda/src/glesgsg/glesgsg.h @@ -54,7 +54,7 @@ #define __glext_h_ #define ES1_GLEXT_H_GUARD -#ifdef IS_OSX +#ifdef BUILD_IPHONE #include // #include #else diff --git a/panda/src/glstuff/glCgShaderContext_src.cxx b/panda/src/glstuff/glCgShaderContext_src.cxx index 3a9b2fea6a..649208fb47 100644 --- a/panda/src/glstuff/glCgShaderContext_src.cxx +++ b/panda/src/glstuff/glCgShaderContext_src.cxx @@ -226,12 +226,14 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte if (!resource) { resource = "unknown"; } - GLCAT.error() - << "Could not find Cg varying " << cgGetParameterName(p); - if (attribname) { - GLCAT.error(false) << " : " << attribname; + if (GLCAT.is_debug()) { + GLCAT.debug() + << "Could not find Cg varying " << cgGetParameterName(p); + if (attribname) { + GLCAT.debug(false) << " : " << attribname; + } + GLCAT.debug(false) << " (" << resource << ") in the compiled GLSL program.\n"; } - GLCAT.error(false) << " (" << resource << ") in the compiled GLSL program.\n"; } else if (loc != 0 && bind._id._name == "vtx_position") { // We really have to bind the vertex position to attribute 0, since @@ -312,10 +314,10 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte GLCAT.debug(false) << " is bound to a conventional attribute (" << resource << ")\n"; } - } - if (loc == CA_unknown) { - // Suggest fix to developer. - GLCAT.error() << "Try using a different semantic.\n"; + if (loc == CA_unknown) { + // Suggest fix to developer. + GLCAT.debug() << "Try using a different semantic.\n"; + } } #endif diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index eab850bdba..d5a8763fc8 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -1097,6 +1097,15 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, #endif glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rbm[slot]); GLuint format = GL_DEPTH_COMPONENT; +#ifndef OPENGLES + if (_fb_properties.get_float_depth()) { + if (!glgsg->_use_remapped_depth_range) { + format = GL_DEPTH_COMPONENT32F; + } else { + format = GL_DEPTH_COMPONENT32F_NV; + } + } else +#endif if (tex) { switch (tex->get_format()) { case Texture::F_depth_component16: diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 48b9112387..19594750c8 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -4392,7 +4392,8 @@ update_standard_vertex_arrays(bool force) { GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f); } else #endif // NDEBUG - if (_data_reader->get_color_info(array_reader, num_values, numeric_type, + if (_vertex_colors_enabled && + _data_reader->get_color_info(array_reader, num_values, numeric_type, start, stride)) { if (!setup_array_data(client_pointer, array_reader, force)) { return false; @@ -4409,7 +4410,13 @@ update_standard_vertex_arrays(bool force) { glDisableClientState(GL_COLOR_ARRAY); // Since we don't have per-vertex color, the implicit color is white. - GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f); + if (_color_scale_via_lighting) { + GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f); + } else { + LColor color = _scene_graph_color; + color.componentwise_mult(_current_color_scale); + GLPf(Color4)(color[0], color[1], color[2], color[3]); + } } // Now set up each of the active texture coordinate stages--or at least @@ -8918,6 +8925,9 @@ get_panda_wrap_mode(GLenum wm) { case GL_REPEAT: return SamplerState::WM_repeat; + case GL_MIRRORED_REPEAT: + return SamplerState::WM_mirror; + #ifndef OPENGLES case GL_MIRROR_CLAMP_EXT: case GL_MIRROR_CLAMP_TO_EDGE_EXT: diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index a96a07a2e8..64a5e77553 100644 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -2440,9 +2440,9 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) { if (p == _color_attrib_index) { // Vertex colors are disabled or not present. Apply flat color. #ifdef STDFLOAT_DOUBLE - _glgsg->_glVertexAttrib4dv(p, color_attrib->get_color().get_data()); + _glgsg->_glVertexAttrib4dv(p, _glgsg->_scene_graph_color.get_data()); #else - _glgsg->_glVertexAttrib4fv(p, color_attrib->get_color().get_data()); + _glgsg->_glVertexAttrib4fv(p, _glgsg->_scene_graph_color.get_data()); #endif } } diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 565f8c47b4..bafe523e0f 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -286,6 +286,28 @@ make_nonindexed(bool composite_only) { return num_changed; } +/** + * Returns a GeomVertexData that represents the results of computing the + * vertex animation on the CPU for this Geom's vertex data. + * + * If there is no CPU-defined vertex animation on this object, this just + * returns the original object. + * + * If there is vertex animation, but the VertexTransform values have not + * changed since last time, this may return the same pointer it returned + * previously. Even if the VertexTransform values have changed, it may still + * return the same pointer, but with its contents modified (this is preferred, + * since it allows the graphics backend to update vertex buffers optimally). + * + * If force is false, this method may return immediately with stale data, if + * the vertex data is not completely resident. If force is true, this method + * will never return stale data, but may block until the data is available. + */ +CPT(GeomVertexData) Geom:: +get_animated_vertex_data(bool force, Thread *current_thread) const { + return get_vertex_data()->animate_vertices(force, current_thread); +} + /** * Replaces the ith GeomPrimitive object stored within the Geom with the new * object. @@ -1311,8 +1333,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { int num_vertices = 0; // Get the vertex data, after animation. - CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer(current_thread); - vertex_data = vertex_data->animate_vertices(true, current_thread); + CPT(GeomVertexData) vertex_data = get_animated_vertex_data(true, current_thread); // Now actually compute the bounding volume. We do this by using // calc_tight_bounds to determine our box first. diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index 833ac3cd83..82aac75cfa 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -85,6 +85,8 @@ PUBLISHED: void offset_vertices(const GeomVertexData *data, int offset); int make_nonindexed(bool composite_only); + CPT(GeomVertexData) get_animated_vertex_data(bool force, Thread *current_thread) const; + INLINE bool is_empty() const; INLINE size_t get_num_primitives() const; diff --git a/panda/src/gobj/geomVertexArrayData.I b/panda/src/gobj/geomVertexArrayData.I index cfe12f9013..30e5c590e8 100644 --- a/panda/src/gobj/geomVertexArrayData.I +++ b/panda/src/gobj/geomVertexArrayData.I @@ -45,7 +45,9 @@ has_column(const InternalName *name) const { */ INLINE int GeomVertexArrayData:: get_num_rows() const { - return get_handle()->get_num_rows(); + CDReader cdata(_cycler); + nassertr(_array_format->get_stride() != 0, 0); + return cdata->_buffer.get_size() / _array_format->get_stride(); } /** diff --git a/panda/src/gobj/geomVertexData.I b/panda/src/gobj/geomVertexData.I index bfea5a10ef..d0c6bba632 100644 --- a/panda/src/gobj/geomVertexData.I +++ b/panda/src/gobj/geomVertexData.I @@ -60,9 +60,20 @@ has_column(const InternalName *name) const { */ INLINE int GeomVertexData:: get_num_rows() const { - GeomVertexDataPipelineReader reader(this, Thread::get_current_thread()); - reader.check_array_readers(); - return reader.get_num_rows(); + CPT(GeomVertexArrayData) array; + { + CDReader cdata(_cycler); + nassertr(cdata->_format->get_num_arrays() == cdata->_arrays.size(), 0); + + if (cdata->_arrays.size() == 0) { + // No arrays means no rows. Weird but legal. + return 0; + } + + array = cdata->_arrays[0].get_read_pointer(); + } + + return array->get_num_rows(); } /** @@ -761,7 +772,9 @@ set_object(const GeomVertexData *object) { _cdata = (GeomVertexData::CData *)_object->_cycler.read_unlocked(_current_thread); _got_array_readers = false; +#ifdef DO_PIPELINING _cdata->ref(); +#endif // DO_PIPELINING } /** diff --git a/panda/src/gobj/geomVertexData.cxx b/panda/src/gobj/geomVertexData.cxx index 5e5fa7a1d4..d97197e25c 100644 --- a/panda/src/gobj/geomVertexData.cxx +++ b/panda/src/gobj/geomVertexData.cxx @@ -621,13 +621,26 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, const TransformBlend &blend = blend_table->get_blend(from.get_data1i()); LVecBase4 weights = LVecBase4::zero(); LVecBase4i indices(0, 0, 0, 0); - nassertv(blend.get_num_transforms() <= 4); - for (size_t i = 0; i < blend.get_num_transforms(); i++) { - weights[i] = blend.get_weight(i); - indices[i] = add_transform(transform_table, blend.get_transform(i), - already_added); + if (blend.get_num_transforms() <= 4) { + for (size_t i = 0; i < blend.get_num_transforms(); i++) { + weights[i] = blend.get_weight(i); + indices[i] = add_transform(transform_table, blend.get_transform(i), + already_added); + } + } else { + // Limit the number of blends to the four with highest weights. + TransformBlend blend2(blend); + blend2.limit_transforms(4); + blend2.normalize_weights(); + + for (size_t i = 0; i < 4; i++) { + weights[i] = blend2.get_weight(i); + indices[i] = add_transform(transform_table, blend2.get_transform(i), + already_added); + } } + if (weight.has_column()) { weight.set_data4(weights); } diff --git a/panda/src/gobj/preparedGraphicsObjects.cxx b/panda/src/gobj/preparedGraphicsObjects.cxx index 4f6ecea1ed..96fcd80269 100644 --- a/panda/src/gobj/preparedGraphicsObjects.cxx +++ b/panda/src/gobj/preparedGraphicsObjects.cxx @@ -1619,8 +1619,8 @@ begin_frame(GraphicsStateGuardianBase *gsg, Thread *current_thread) { ++qsi) { Shader *shader = qsi->first; ShaderContext *sc = shader->prepare_now(this, gsg); - if (qti->second != nullptr) { - qti->second->set_result(sc); + if (qsi->second != nullptr) { + qsi->second->set_result(sc); } } diff --git a/panda/src/gobj/textureReloadRequest.cxx b/panda/src/gobj/textureReloadRequest.cxx index 4c17b550b7..b63acb6090 100644 --- a/panda/src/gobj/textureReloadRequest.cxx +++ b/panda/src/gobj/textureReloadRequest.cxx @@ -40,7 +40,7 @@ do_task() { // become a kind of a leak (if the texture is never rendered again on // this GSG, we'll just end up carrying the texture memory in RAM // forever, instead of dumping it as soon as it gets prepared). - _texture->prepare(_pgo); + _pgo->enqueue_texture(_texture); } } diff --git a/panda/src/gobj/textureStage.cxx b/panda/src/gobj/textureStage.cxx index 4fecd20999..0d6202d949 100644 --- a/panda/src/gobj/textureStage.cxx +++ b/panda/src/gobj/textureStage.cxx @@ -84,7 +84,7 @@ operator = (const TextureStage &other) { _combine_rgb_operand2 = other._combine_rgb_operand2; _combine_alpha_mode = other._combine_alpha_mode; _combine_alpha_source0 = other._combine_alpha_source0; - _combine_alpha_operand0 = _combine_alpha_operand0; + _combine_alpha_operand0 = other._combine_alpha_operand0; _combine_alpha_source1 = other._combine_alpha_source1; _combine_alpha_operand1 = other._combine_alpha_operand1; _combine_alpha_source2 = other._combine_alpha_source2; diff --git a/panda/src/grutil/multitexReducer.cxx b/panda/src/grutil/multitexReducer.cxx index fdad25bb48..2fff484de3 100644 --- a/panda/src/grutil/multitexReducer.cxx +++ b/panda/src/grutil/multitexReducer.cxx @@ -866,7 +866,7 @@ transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name, PT(Geom) geom = orig_geom->make_copy(); // Ensure that any vertex animation has been applied. - geom->set_vertex_data(geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread)); + geom->set_vertex_data(geom->get_animated_vertex_data(true, current_thread)); // Now get a modifiable pointer to the vertex data in the new Geom. This // will actually perform a deep copy of the vertex data. diff --git a/panda/src/net/connection.cxx b/panda/src/net/connection.cxx index aecfc111ac..27f5c8bb24 100644 --- a/panda/src/net/connection.cxx +++ b/panda/src/net/connection.cxx @@ -445,7 +445,7 @@ do_flush() { if (data_sent > 0) { total_sent += data_sent; } - double last_report = 0; + while (!okflag && tcp->Active() && (data_sent > 0 || tcp->GetLastError() == LOCAL_BLOCKING_ERROR)) { if (data_sent == 0) { diff --git a/panda/src/osxdisplay/osxGraphicsStateGuardian.h b/panda/src/osxdisplay/osxGraphicsStateGuardian.h index 038ba42055..96c86f28dd 100644 --- a/panda/src/osxdisplay/osxGraphicsStateGuardian.h +++ b/panda/src/osxdisplay/osxGraphicsStateGuardian.h @@ -64,7 +64,7 @@ private: CGGammaValue _gOriginalRedTable[ 256 ]; CGGammaValue _gOriginalGreenTable[ 256 ]; CGGammaValue _gOriginalBlueTable[ 256 ]; - CGTableCount _sampleCount; + uint32_t _sampleCount; CGDisplayErr _cgErr; public: diff --git a/panda/src/particlesystem/baseParticle.cxx b/panda/src/particlesystem/baseParticle.cxx index 046b2dfb40..46e18179da 100644 --- a/panda/src/particlesystem/baseParticle.cxx +++ b/panda/src/particlesystem/baseParticle.cxx @@ -68,7 +68,6 @@ write(std::ostream &out, int indent) const { out.width(indent+2); out<<""; out<<"_lifespan "<<_lifespan<<"\n"; out.width(indent+2); out<<""; out<<"_alive "<<_alive<<"\n"; out.width(indent+2); out<<""; out<<"_index "<<_index<<"\n"; - out.width(indent+2); out<<""; out<<"_last_position "<<_last_position<<"\n"; PhysicsObject::write(out, indent+2); #endif //] NDEBUG } diff --git a/panda/src/particlesystem/baseParticle.h b/panda/src/particlesystem/baseParticle.h index 487f9ba476..834327bfec 100644 --- a/panda/src/particlesystem/baseParticle.h +++ b/panda/src/particlesystem/baseParticle.h @@ -62,8 +62,6 @@ private: PN_stdfloat _lifespan; bool _alive; int _index; - - LPoint3 _last_position; }; #include "baseParticle.I" diff --git a/panda/src/pgraph/colorAttrib.cxx b/panda/src/pgraph/colorAttrib.cxx index 129f5a9184..f1d71845cd 100644 --- a/panda/src/pgraph/colorAttrib.cxx +++ b/panda/src/pgraph/colorAttrib.cxx @@ -68,7 +68,7 @@ make_off() { */ CPT(RenderAttrib) ColorAttrib:: make_default() { - return make_off(); + return make_vertex(); } /** diff --git a/panda/src/pgraph/colorAttrib.h b/panda/src/pgraph/colorAttrib.h index a92543c855..b652233a62 100644 --- a/panda/src/pgraph/colorAttrib.h +++ b/panda/src/pgraph/colorAttrib.h @@ -88,7 +88,7 @@ public: register_type(_type_handle, "ColorAttrib", RenderAttrib::get_class_type()); _attrib_slot = register_slot(_type_handle, 100, - new ColorAttrib(T_off, LColor(1, 1, 1, 1))); + new ColorAttrib(T_vertex, LColor::zero())); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/cullTraverserData.cxx b/panda/src/pgraph/cullTraverserData.cxx index 8d54308af8..a260dd3ebb 100644 --- a/panda/src/pgraph/cullTraverserData.cxx +++ b/panda/src/pgraph/cullTraverserData.cxx @@ -54,6 +54,9 @@ apply_transform_and_state(CullTraverser *trav) { CPT(TransformState) node_transform = _node_reader.get_transform(); node_effects->cull_callback(trav, *this, node_transform, node_state); apply_transform(node_transform); + + // The cull callback may have changed the node properties. + _node_reader.check_cached(false); } if (!node_state->is_empty()) { diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index 16e95442c2..17d5555e5d 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -376,8 +376,7 @@ r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, geom = transformer.premunge_geom(geom, munger); // Prepare each of the vertex arrays in the munged Geom. - CPT(GeomVertexData) vdata = geom->get_vertex_data(current_thread); - vdata = vdata->animate_vertices(false, current_thread); + CPT(GeomVertexData) vdata = geom->get_animated_vertex_data(false, current_thread); GeomVertexDataPipelineReader vdata_reader(vdata, current_thread); int num_arrays = vdata_reader.get_num_arrays(); for (int i = 0; i < num_arrays; ++i) { @@ -474,7 +473,7 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any, for (gi = geoms->begin(); gi != geoms->end(); ++gi) { CPT(Geom) geom = (*gi)._geom.get_read_pointer(); geom->calc_tight_bounds(min_point, max_point, found_any, - geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread), + geom->get_animated_vertex_data(true, current_thread), !next_transform->is_identity(), mat, current_thread); } diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index 73b1e4b392..9bac4e666a 100644 --- a/panda/src/pgraph/renderAttrib.cxx +++ b/panda/src/pgraph/renderAttrib.cxx @@ -211,7 +211,7 @@ garbage_collect() { } num_this_pass = std::min(num_this_pass, size); - size_t stop_at_element = (_garbage_index + num_this_pass) % size; + size_t stop_at_element = (si + num_this_pass) % size; do { RenderAttrib *attrib = (RenderAttrib *)_attribs->get_key(si); @@ -229,6 +229,9 @@ garbage_collect() { // still need to visit. --size; --si; + if (stop_at_element > 0) { + --stop_at_element; + } } si = (si + 1) % size; diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index 927d1e7073..5ce1527247 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -950,6 +950,9 @@ garbage_collect() { // still need to visit. --size; --si; + if (stop_at_element > 0) { + --stop_at_element; + } } si = (si + 1) % size; diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index 453fb505b4..4d02425683 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -1216,6 +1216,9 @@ garbage_collect() { // still need to visit. --size; --si; + if (stop_at_element > 0) { + --stop_at_element; + } } si = (si + 1) % size; diff --git a/panda/src/pipeline/blockerSimple.I b/panda/src/pipeline/blockerSimple.I index 0188281728..89be34a412 100644 --- a/panda/src/pipeline/blockerSimple.I +++ b/panda/src/pipeline/blockerSimple.I @@ -11,14 +11,6 @@ * @date 2007-06-20 */ -/** - * - */ -INLINE BlockerSimple:: -BlockerSimple() { - _flags = 0; -} - /** * */ diff --git a/panda/src/pipeline/blockerSimple.h b/panda/src/pipeline/blockerSimple.h index 71ae25c41d..d375d5dc16 100644 --- a/panda/src/pipeline/blockerSimple.h +++ b/panda/src/pipeline/blockerSimple.h @@ -28,7 +28,7 @@ */ class EXPCL_PANDA_PIPELINE BlockerSimple { protected: - INLINE BlockerSimple(); + constexpr BlockerSimple() = default; INLINE ~BlockerSimple(); protected: @@ -38,7 +38,7 @@ protected: F_has_waiters = 0x40000000, }; - unsigned int _flags; + unsigned int _flags = 0; friend class ThreadSimpleManager; }; diff --git a/panda/src/pipeline/config_pipeline.cxx b/panda/src/pipeline/config_pipeline.cxx index 2e7bf6487e..4fd5214323 100644 --- a/panda/src/pipeline/config_pipeline.cxx +++ b/panda/src/pipeline/config_pipeline.cxx @@ -71,7 +71,10 @@ init_libpipeline() { } initialized = true; +#ifdef DO_PIPELINING CycleData::init_type(); +#endif + MainThread::init_type(); ExternalThread::init_type(); GenericThread::init_type(); diff --git a/panda/src/pipeline/contextSwitch_longjmp_src.c b/panda/src/pipeline/contextSwitch_longjmp_src.c index c3640b8f1f..5dec92804a 100644 --- a/panda/src/pipeline/contextSwitch_longjmp_src.c +++ b/panda/src/pipeline/contextSwitch_longjmp_src.c @@ -1,8 +1,4 @@ -/* Filename: contextSwitch_longjmp_src.c - * Created by: drose (15Apr10) - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * +/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * @@ -10,7 +6,10 @@ * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * @file contextSwitch_longjmp_src.c + * @author drose + * @date 2010-04-15 + */ /* This is the implementation of user-space context switching using setmp() / longjmp(). This is the hackier implementation, @@ -90,14 +89,14 @@ void cs_longjmp(cs_jmp_buf env) { _asm { mov eax, env; - + mov ebx, [eax + 0]; mov edi, [eax + 4]; mov esi, [eax + 8]; mov ebp, [eax + 12]; mov esp, [eax + 16]; mov edx, [eax + 20]; - + frstor [eax + 24]; /* restore floating-point state */ mov eax, 1; /* return 1 from setjmp: pass 2 return */ @@ -251,7 +250,7 @@ setup_context_1(void) { } void -init_thread_context(struct ThreadContext *context, +init_thread_context(struct ThreadContext *context, unsigned char *stack, size_t stack_size, ThreadFunction *thread_func, void *data) { /* Copy all of the input parameters to static variables, then begin @@ -263,7 +262,7 @@ init_thread_context(struct ThreadContext *context, st_data = data; setup_context_1(); -} +} void save_thread_context(struct ThreadContext *context, diff --git a/panda/src/pipeline/contextSwitch_posix_src.c b/panda/src/pipeline/contextSwitch_posix_src.c index 6f5df46445..f553cefc45 100644 --- a/panda/src/pipeline/contextSwitch_posix_src.c +++ b/panda/src/pipeline/contextSwitch_posix_src.c @@ -1,8 +1,4 @@ -/* Filename: contextSwitch_posix_src.c - * Created by: drose (15Apr10) - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * +/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * @@ -10,7 +6,10 @@ * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * @file contextSwitch_posix_src.c + * @author drose + * @date 2010-04-15 + */ /* This is the implementation of user-space context switching using posix threads to manage the different execution contexts. This @@ -44,7 +43,7 @@ struct ThreadContext { pthread_mutex_t _ready_mutex; pthread_cond_t _ready_cvar; int _ready_flag; - + /* This is set FALSE while the thread is alive, and TRUE if the thread is to be terminated when it next wakes up. */ int _terminated; @@ -83,19 +82,19 @@ thread_main(void *data) { } void -init_thread_context(struct ThreadContext *context, +init_thread_context(struct ThreadContext *context, unsigned char *stack, size_t stack_size, ThreadFunction *thread_func, void *data) { context->_thread_func = thread_func; context->_data = data; - pthread_attr_t attr; - pthread_attr_init(&attr); + pthread_attr_t attr; + pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, stack_size); - pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); - pthread_create(&(context->_thread), &attr, thread_main, context); - pthread_attr_destroy(&attr); + pthread_create(&(context->_thread), &attr, thread_main, context); + pthread_attr_destroy(&attr); } void @@ -142,7 +141,7 @@ switch_to_thread_context(struct ThreadContext *from_context, /* We've been rudely terminated. Exit gracefully. */ pthread_exit(NULL); } - + /* Now we have been signaled again, and we're ready to resume the thread. */ longjmp(from_context->_jmp_context, 1); @@ -164,7 +163,7 @@ alloc_thread_context() { pthread_mutexattr_init(&attr); // The symbol PTHREAD_MUTEX_DEFAULT isn't always available? // pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT); - int result = pthread_mutex_init(&context->_ready_mutex, &attr); + pthread_mutex_init(&context->_ready_mutex, &attr); pthread_mutexattr_destroy(&attr); pthread_cond_init(&context->_ready_cvar, NULL); diff --git a/panda/src/pipeline/contextSwitch_ucontext_src.c b/panda/src/pipeline/contextSwitch_ucontext_src.c index f589dbb5bf..f08c6d9afe 100644 --- a/panda/src/pipeline/contextSwitch_ucontext_src.c +++ b/panda/src/pipeline/contextSwitch_ucontext_src.c @@ -1,8 +1,4 @@ -/* Filename: contextSwitch_ucontext_src.c - * Created by: drose (15Apr10) - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * +/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * @@ -10,7 +6,10 @@ * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * @file contextSwitch_ucontext_src.c + * @author drose + * @date 2010-04-15 + */ /* This is the implementation of user-space context switching using getcontext() / setcontext(). This is the preferred implementation, @@ -43,7 +42,7 @@ begin_context(ThreadFunction *thread_func, void *data) { } void -init_thread_context(struct ThreadContext *context, +init_thread_context(struct ThreadContext *context, unsigned char *stack, size_t stack_size, ThreadFunction *thread_func, void *data) { if (getcontext(&context->_ucontext) != 0) { diff --git a/panda/src/pipeline/contextSwitch_windows_src.c b/panda/src/pipeline/contextSwitch_windows_src.c index 9f157d8eec..727eef43b9 100644 --- a/panda/src/pipeline/contextSwitch_windows_src.c +++ b/panda/src/pipeline/contextSwitch_windows_src.c @@ -1,8 +1,4 @@ -/* Filename: contextSwitch_windows_src.c - * Created by: drose (15Apr10) - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * +/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * @@ -10,7 +6,10 @@ * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * @file contextSwitch_windows_src.c + * @author drose + * @date 2010-04-15 + */ /* This is the implementation of user-space context switching using native Windows threading constructs to manage the different @@ -37,7 +36,7 @@ struct ThreadContext { /* This event is in the signaled state when the thread is ready to roll. */ HANDLE _ready; - + /* This is set FALSE while the thread is alive, and TRUE if the thread is to be terminated when it next wakes up. */ int _terminated; @@ -71,13 +70,13 @@ thread_main(LPVOID data) { } void -init_thread_context(struct ThreadContext *context, +init_thread_context(struct ThreadContext *context, unsigned char *stack, size_t stack_size, ThreadFunction *thread_func, void *data) { context->_thread_func = thread_func; context->_data = data; - context->_thread = CreateThread(NULL, stack_size, + context->_thread = CreateThread(NULL, stack_size, thread_main, context, 0, NULL); } @@ -117,7 +116,7 @@ switch_to_thread_context(struct ThreadContext *from_context, /* We've been rudely terminated. Exit gracefully. */ ExitThread(1); } - + /* Now we have been signaled again, and we're ready to resume the thread. */ longjmp(from_context->_jmp_context, 1); diff --git a/panda/src/pipeline/cycleData.h b/panda/src/pipeline/cycleData.h index de90bdf226..ef21ad7a33 100644 --- a/panda/src/pipeline/cycleData.h +++ b/panda/src/pipeline/cycleData.h @@ -54,6 +54,9 @@ public: INLINE CycleData(const CycleData ©) = default; virtual ~CycleData(); + CycleData &operator = (CycleData &&from) = default; + CycleData &operator = (const CycleData ©) = default; + virtual CycleData *make_copy() const=0; virtual void write_datagram(BamWriter *, Datagram &) const; diff --git a/panda/src/pipeline/cycleDataLockedReader.I b/panda/src/pipeline/cycleDataLockedReader.I index a622b9a2c0..882d8f600e 100644 --- a/panda/src/pipeline/cycleDataLockedReader.I +++ b/panda/src/pipeline/cycleDataLockedReader.I @@ -45,6 +45,19 @@ CycleDataLockedReader(const CycleDataLockedReader ©) : _cycler->increment_read(_pointer); } +/** + * + */ +template +INLINE CycleDataLockedReader:: +CycleDataLockedReader(CycleDataLockedReader &&from) noexcept : + _cycler(from._cycler), + _current_thread(from._current_thread), + _pointer(from._pointer) +{ + from._pointer = nullptr; +} + /** * */ @@ -61,19 +74,6 @@ operator = (const CycleDataLockedReader ©) { _cycler->increment_read(_pointer); } -/** - * - */ -template -INLINE CycleDataLockedReader:: -CycleDataLockedReader(CycleDataLockedReader &&from) noexcept : - _cycler(from._cycler), - _current_thread(from._current_thread), - _pointer(from._pointer) -{ - from._pointer = nullptr; -} - /** * */ @@ -177,6 +177,18 @@ operator = (const CycleDataLockedReader ©) { _pointer = copy._pointer; } +/** + * + */ +template +INLINE void CycleDataLockedReader:: +operator = (CycleDataLockedReader &&from) noexcept { + nassertv(_pointer == nullptr); + + _pointer = from._pointer; + from._pointer = nullptr; +} + /** * */ diff --git a/panda/src/pipeline/cycleDataLockedStageReader.I b/panda/src/pipeline/cycleDataLockedStageReader.I index 22b8785c82..a471aac0b7 100644 --- a/panda/src/pipeline/cycleDataLockedStageReader.I +++ b/panda/src/pipeline/cycleDataLockedStageReader.I @@ -47,6 +47,20 @@ CycleDataLockedStageReader(const CycleDataLockedStageReader © _cycler->increment_read(_pointer); } +/** + * + */ +template +INLINE CycleDataLockedStageReader:: +CycleDataLockedStageReader(CycleDataLockedStageReader &&from) noexcept : + _cycler(from._cycler), + _current_thread(from._current_thread), + _pointer(from._pointer), + _stage(from._stage) +{ + from._pointer = nullptr; +} + /** * */ @@ -64,20 +78,6 @@ operator = (const CycleDataLockedStageReader ©) { _cycler->increment_read(_pointer); } -/** - * - */ -template -INLINE CycleDataLockedStageReader:: -CycleDataLockedStageReader(CycleDataLockedStageReader &&from) noexcept : - _cycler(from._cycler), - _current_thread(from._current_thread), - _pointer(from._pointer), - _stage(from._stage) -{ - from._pointer = nullptr; -} - /** * */ @@ -174,6 +174,17 @@ CycleDataLockedStageReader(const CycleDataLockedStageReader © { } +/** + * + */ +template +INLINE CycleDataLockedStageReader:: +CycleDataLockedStageReader(CycleDataLockedStageReader &&from) noexcept : + _pointer(from._cycler) +{ + from._pointer = nullptr; +} + /** * */ @@ -183,6 +194,18 @@ operator = (const CycleDataLockedStageReader ©) { _pointer = copy._pointer; } +/** + * + */ +template +INLINE void CycleDataLockedStageReader:: +operator = (CycleDataLockedStageReader &&from) noexcept { + nassertv(_pointer == nullptr); + + _pointer = from._pointer; + from._pointer = nullptr; +} + /** * */ diff --git a/panda/src/pipeline/cycleDataStageWriter.I b/panda/src/pipeline/cycleDataStageWriter.I index a4c1851dde..cf25cf807a 100644 --- a/panda/src/pipeline/cycleDataStageWriter.I +++ b/panda/src/pipeline/cycleDataStageWriter.I @@ -62,23 +62,6 @@ CycleDataStageWriter(const CycleDataStageWriter ©) : _cycler->increment_write(_pointer); } -/** - * - */ -template -INLINE void CycleDataStageWriter:: -operator = (const CycleDataStageWriter ©) { - nassertv(_pointer == nullptr); - nassertv(_current_thread == copy._current_thread); - - _cycler = copy._cycler; - _pointer = copy._pointer; - _stage = copy._stage; - - nassertv(_pointer != nullptr); - _cycler->increment_write(_pointer); -} - /** * This flavor of the constructor elevates the pointer from the * CycleDataLockedStageReader from a read to a write pointer (and invalidates @@ -128,6 +111,23 @@ CycleDataStageWriter(CycleDataStageWriter &&from) noexcept : from._pointer = nullptr; } +/** + * + */ +template +INLINE void CycleDataStageWriter:: +operator = (const CycleDataStageWriter ©) { + nassertv(_pointer == nullptr); + nassertv(_current_thread == copy._current_thread); + + _cycler = copy._cycler; + _pointer = copy._pointer; + _stage = copy._stage; + + nassertv(_pointer != nullptr); + _cycler->increment_write(_pointer); +} + /** * */ @@ -227,6 +227,17 @@ CycleDataStageWriter(const CycleDataStageWriter ©) : { } +/** + * + */ +template +INLINE CycleDataStageWriter:: +CycleDataStageWriter(CycleDataStageWriter &&from) noexcept : + _pointer(from._pointer) +{ + from._pointer = nullptr; +} + /** * */ @@ -236,6 +247,18 @@ operator = (const CycleDataStageWriter ©) { _pointer = copy._pointer; } +/** + * + */ +template +INLINE void CycleDataStageWriter:: +operator = (CycleDataStageWriter &&from) noexcept { + nassertv(_pointer == nullptr); + + _pointer = from._pointer; + from._pointer = nullptr; +} + /** * This flavor of the constructor elevates the pointer from the * CycleDataLockedStageReader from a read to a write pointer (and invalidates diff --git a/panda/src/pipeline/pythonThread.cxx b/panda/src/pipeline/pythonThread.cxx index ab41070fb8..53a811401e 100644 --- a/panda/src/pipeline/pythonThread.cxx +++ b/panda/src/pipeline/pythonThread.cxx @@ -225,7 +225,7 @@ call_python_func(PyObject *function, PyObject *args) { } else { // No exception. Restore the thread state normally. - PyThreadState *state = PyThreadState_Swap(orig_thread_state); + PyThreadState_Swap(orig_thread_state); thread_states.push_back(new_thread_state); // PyThreadState_Clear(new_thread_state); // PyThreadState_Delete(new_thread_state); diff --git a/panda/src/pipeline/threadSimpleImpl.I b/panda/src/pipeline/threadSimpleImpl.I index 001f3037d4..d712892883 100644 --- a/panda/src/pipeline/threadSimpleImpl.I +++ b/panda/src/pipeline/threadSimpleImpl.I @@ -51,14 +51,6 @@ is_threading_supported() { return true; } -/** - * - */ -INLINE bool ThreadSimpleImpl:: -is_true_threads() { - return (is_os_threads != 0); -} - /** * */ diff --git a/panda/src/pipeline/threadSimpleImpl.cxx b/panda/src/pipeline/threadSimpleImpl.cxx index a631421503..14d6f7561f 100644 --- a/panda/src/pipeline/threadSimpleImpl.cxx +++ b/panda/src/pipeline/threadSimpleImpl.cxx @@ -141,8 +141,8 @@ start(ThreadPriority priority, bool joinable) { #ifdef HAVE_PYTHON // Query the current Python thread state. - _python_state = PyThreadState_Swap(nullptr); - PyThreadState_Swap(_python_state); + _python_state = thread_state_swap(nullptr); + thread_state_swap(_python_state); #endif // HAVE_PYTHON init_thread_context(_context, _stack, _stack_size, st_begin_thread, this); @@ -201,6 +201,14 @@ prepare_for_exit() { manager->prepare_for_exit(); } +/** + * + */ +bool ThreadSimpleImpl:: +is_true_threads() { + return (is_os_threads != 0); +} + /** * */ @@ -238,7 +246,7 @@ st_begin_thread(void *data) { void ThreadSimpleImpl:: begin_thread() { #ifdef HAVE_PYTHON - PyThreadState_Swap(_python_state); + thread_state_swap(_python_state); #endif // HAVE_PYTHON #ifdef HAVE_POSIX_THREADS diff --git a/panda/src/pipeline/threadSimpleImpl.h b/panda/src/pipeline/threadSimpleImpl.h index c552dd1357..5bd6af3fdc 100644 --- a/panda/src/pipeline/threadSimpleImpl.h +++ b/panda/src/pipeline/threadSimpleImpl.h @@ -63,7 +63,7 @@ public: INLINE static void bind_thread(Thread *thread); INLINE static bool is_threading_supported(); - INLINE static bool is_true_threads(); + static bool is_true_threads(); INLINE static bool is_simple_threads(); INLINE static void sleep(double seconds); INLINE static void yield(); diff --git a/panda/src/pipeline/threadSimpleManager.cxx b/panda/src/pipeline/threadSimpleManager.cxx index 4d9890dfd4..861e19cd77 100644 --- a/panda/src/pipeline/threadSimpleManager.cxx +++ b/panda/src/pipeline/threadSimpleManager.cxx @@ -20,7 +20,9 @@ #include "mainThread.h" #ifdef WIN32 -#define WIN32_LEAN_AND_MEAN +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif #include #endif @@ -235,7 +237,7 @@ next_context() { #ifdef HAVE_PYTHON // Save the current Python thread state. - _current_thread->_python_state = PyThreadState_Swap(nullptr); + _current_thread->_python_state = thread_state_swap(nullptr); #endif // HAVE_PYTHON #ifdef DO_PSTATS @@ -256,7 +258,7 @@ next_context() { #endif // DO_PSTATS #ifdef HAVE_PYTHON - PyThreadState_Swap(_current_thread->_python_state); + thread_state_swap(_current_thread->_python_state); #endif // HAVE_PYTHON } @@ -468,16 +470,6 @@ init_pointers() { _pointers_initialized = true; _global_ptr = new ThreadSimpleManager; Thread::get_main_thread(); - -#ifdef HAVE_PYTHON - // Ensure that the Python threading system is initialized and ready to go. - -#if PY_VERSION_HEX >= 0x03020000 - Py_Initialize(); -#endif - - PyEval_InitThreads(); -#endif } } diff --git a/panda/src/text/textNode.I b/panda/src/text/textNode.I index 8070504c6b..1d02442451 100644 --- a/panda/src/text/textNode.I +++ b/panda/src/text/textNode.I @@ -1010,61 +1010,6 @@ clear_glyph_shift() { invalidate_with_measure(); } - -/** - * Changes the text that is displayed under the TextNode. - */ -INLINE void TextNode:: -set_text(const std::string &text) { - MutexHolder holder(_lock); - TextEncoder::set_text(text); - invalidate_with_measure(); -} - -/** - * The two-parameter version of set_text() accepts an explicit encoding; the - * text is immediately decoded and stored as a wide-character string. - * Subsequent calls to get_text() will return the same text re-encoded using - * whichever encoding is specified by set_encoding(). - */ -INLINE void TextNode:: -set_text(const std::string &text, TextNode::Encoding encoding) { - MutexHolder holder(_lock); - TextEncoder::set_text(text, encoding); - invalidate_with_measure(); -} - -/** - * Removes the text from the TextNode. - */ -INLINE void TextNode:: -clear_text() { - MutexHolder holder(_lock); - TextEncoder::clear_text(); - invalidate_with_measure(); -} - -/** - * Appends the indicates string to the end of the stored text. - */ -INLINE void TextNode:: -append_text(const std::string &text) { - MutexHolder holder(_lock); - TextEncoder::append_text(text); - invalidate_with_measure(); -} - -/** - * Appends a single character to the end of the stored text. This may be a - * wide character, up to 16 bits in Unicode. - */ -INLINE void TextNode:: -append_unicode_char(wchar_t character) { - MutexHolder holder(_lock); - TextEncoder::append_unicode_char(character); - invalidate_with_measure(); -} - /** * Returns a string that represents the contents of the text, as it has been * formatted by wordwrap rules. @@ -1086,28 +1031,6 @@ calc_width(const std::string &line) const { return calc_width(decode_text(line)); } -/** - * Changes the text that is displayed under the TextNode, with a wide text. - * This automatically sets the string reported by get_text() to the 8-bit - * encoded version of the same string. - */ -INLINE void TextNode:: -set_wtext(const std::wstring &wtext) { - MutexHolder holder(_lock); - TextEncoder::set_wtext(wtext); - invalidate_with_measure(); -} - -/** - * Appends the indicates string to the end of the stored wide-character text. - */ -INLINE void TextNode:: -append_wtext(const std::wstring &wtext) { - MutexHolder holder(_lock); - TextEncoder::append_wtext(wtext); - invalidate_with_measure(); -} - /** * Returns a wstring that represents the contents of the text, as it has been * formatted by wordwrap rules. diff --git a/panda/src/text/textNode.cxx b/panda/src/text/textNode.cxx index 1ecfc1ea65..4a77acd6d3 100644 --- a/panda/src/text/textNode.cxx +++ b/panda/src/text/textNode.cxx @@ -291,8 +291,8 @@ output(std::ostream &out) const { */ void TextNode:: write(std::ostream &out, int indent_level) const { - MutexHolder holder(_lock); PandaNode::write(out, indent_level); + MutexHolder holder(_lock); TextProperties::write(out, indent_level + 2); indent(out, indent_level + 2) << "transform is: " << *TransformState::make_mat(_transform) << "\n"; @@ -319,6 +319,15 @@ get_internal_geom() const { return do_get_internal_geom(); } +/** + * Called whenever the text has been changed. + */ +void TextNode:: +text_changed() { + MutexHolder holder(_lock); + invalidate_with_measure(); +} + /** * Returns the union of all attributes from SceneGraphReducer::AttribTypes * that may not safely be applied to the vertices of this node. If this is diff --git a/panda/src/text/textNode.h b/panda/src/text/textNode.h index ecf7dcafcf..02e1cb51c7 100644 --- a/panda/src/text/textNode.h +++ b/panda/src/text/textNode.h @@ -182,14 +182,6 @@ PUBLISHED: INLINE void set_glyph_shift(PN_stdfloat glyph_shift); INLINE void clear_glyph_shift(); - // These methods are inherited from TextEncoder, but we override here so we - // can flag the TextNode as dirty when they have been changed. - INLINE void set_text(const std::string &text); - INLINE void set_text(const std::string &text, Encoding encoding); - INLINE void clear_text(); - INLINE void append_text(const std::string &text); - INLINE void append_unicode_char(wchar_t character); - // After the text has been set, you can query this to determine how it will // be wordwrapped. INLINE std::string get_wordwrapped_text() const; @@ -203,10 +195,6 @@ PUBLISHED: bool has_character(wchar_t character) const; bool is_whitespace(wchar_t character) const; - // Direct support for wide-character strings. - INLINE void set_wtext(const std::wstring &wtext); - INLINE void append_wtext(const std::wstring &text); - INLINE std::wstring get_wordwrapped_wtext() const; PN_stdfloat calc_width(const std::wstring &line) const; @@ -245,8 +233,6 @@ PUBLISHED: MAKE_PROPERTY(usage_hint, get_usage_hint, set_usage_hint); MAKE_PROPERTY(flatten_flags, get_flatten_flags, set_flatten_flags); - MAKE_PROPERTY(text, get_text, set_text); - MAKE_PROPERTY2(font, has_font, get_font, set_font, clear_font); MAKE_PROPERTY2(small_caps, has_small_caps, get_small_caps, set_small_caps, clear_small_caps); @@ -281,6 +267,9 @@ PUBLISHED: set_text_scale, clear_text_scale); public: + // From parent class TextEncoder; + virtual void text_changed() final; + // From parent class PandaNode virtual int get_unsafe_to_apply_attribs() const; virtual void apply_attribs_to_vertices(const AccumulatedAttribs &attribs, diff --git a/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx b/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx index 735f7fc409..c98f12cf48 100644 --- a/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx +++ b/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx @@ -778,9 +778,9 @@ register_twindow_class() { #define GAMMA_1 (255.0 * 256.0) static bool _gamma_table_initialized = false; -static unsigned short _orignial_gamma_table [256 * 3]; +static unsigned short _original_gamma_table [256 * 3]; -void _create_gamma_table (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) { +void _create_gamma_table_wgl (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) { int i; double gamma_correction; @@ -842,7 +842,7 @@ get_gamma_table(void) { HDC hdc = GetDC(nullptr); if (hdc) { - if (GetDeviceGammaRamp (hdc, (LPVOID) _orignial_gamma_table)) { + if (GetDeviceGammaRamp (hdc, (LPVOID) _original_gamma_table)) { _gamma_table_initialized = true; get = true; } @@ -867,10 +867,10 @@ static_set_gamma(bool restore, PN_stdfloat gamma) { unsigned short ramp [256 * 3]; if (restore && _gamma_table_initialized) { - _create_gamma_table (gamma, &_orignial_gamma_table [0], &_orignial_gamma_table [256], &_orignial_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]); + _create_gamma_table_wgl (gamma, &_original_gamma_table [0], &_original_gamma_table [256], &_original_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]); } else { - _create_gamma_table (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]); + _create_gamma_table_wgl (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]); } if (SetDeviceGammaRamp (hdc, ramp)) { diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index b81f9f3a57..01d952b832 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -283,6 +283,41 @@ set_properties_now(WindowProperties &properties) { return; } + if (properties.has_undecorated() || + properties.has_fixed_size()) { + if (properties.has_undecorated()) { + _properties.set_undecorated(properties.get_undecorated()); + properties.clear_undecorated(); + } + if (properties.has_fixed_size()) { + _properties.set_fixed_size(properties.get_fixed_size()); + properties.clear_fixed_size(); + } + // When switching undecorated mode, Windows will keep the window at the + // current outer size, whereas we want to keep it with the configured + // inner size. Store the current size and origin. + LPoint2i top_left = _properties.get_origin(); + LPoint2i bottom_right = top_left + _properties.get_size(); + + DWORD window_style = make_style(_properties); + SetWindowLong(_hWnd, GWL_STYLE, window_style); + + // Now calculate the proper size and origin with the new window style. + RECT view_rect; + SetRect(&view_rect, top_left[0], top_left[1], + bottom_right[0], bottom_right[1]); + WINDOWINFO wi; + GetWindowInfo(_hWnd, &wi); + AdjustWindowRectEx(&view_rect, wi.dwStyle, FALSE, wi.dwExStyle); + + // We need to call this to ensure that the style change takes effect. + SetWindowPos(_hWnd, HWND_NOTOPMOST, view_rect.left, view_rect.top, + view_rect.right - view_rect.left, + view_rect.bottom - view_rect.top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | + SWP_NOSENDCHANGING | SWP_SHOWWINDOW); + } + if (properties.has_title()) { std::string title = properties.get_title(); _properties.set_title(title); @@ -487,7 +522,7 @@ open_window() { // CreateWindow() and know which window it is sending events to even before // it gives us a handle. Warning: this is not thread safe! _creating_window = this; - bool opened = open_graphic_window(is_fullscreen()); + bool opened = open_graphic_window(); _creating_window = nullptr; if (!opened) { @@ -866,7 +901,9 @@ do_fullscreen_switch() { return false; } - DWORD window_style = make_style(true); + WindowProperties props(_properties); + props.set_fullscreen(true); + DWORD window_style = make_style(props); SetWindowLong(_hWnd, GWL_STYLE, window_style); WINDOW_METRICS metrics; @@ -886,7 +923,10 @@ do_fullscreen_switch() { bool WinGraphicsWindow:: do_windowed_switch() { do_fullscreen_disable(); - DWORD window_style = make_style(false); + + WindowProperties props(_properties); + props.set_fullscreen(false); + DWORD window_style = make_style(props); SetWindowLong(_hWnd, GWL_STYLE, window_style); WINDOW_METRICS metrics; @@ -929,7 +969,7 @@ support_overlay_window(bool) { * Constructs a dwStyle for the specified mode, be it windowed or fullscreen. */ DWORD WinGraphicsWindow:: -make_style(bool fullscreen) { +make_style(const WindowProperties &properties) { // from MSDN: An OpenGL window has its own pixel format. Because of this, // only device contexts retrieved for the client area of an OpenGL window // are allowed to draw into the window. As a result, an OpenGL window @@ -939,7 +979,7 @@ make_style(bool fullscreen) { DWORD window_style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - if (fullscreen){ + if (_properties.get_fullscreen()) { window_style |= WS_SYSMENU; } else if (!_properties.get_undecorated()) { window_style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX); @@ -1016,8 +1056,8 @@ calculate_metrics(bool fullscreen, DWORD window_style, WINDOW_METRICS &metrics, * Creates a regular or fullscreen window. */ bool WinGraphicsWindow:: -open_graphic_window(bool fullscreen) { - DWORD window_style = make_style(fullscreen); +open_graphic_window() { + DWORD window_style = make_style(_properties); wstring title; if (_properties.has_title()) { @@ -2187,12 +2227,12 @@ update_cursor_window(WinGraphicsWindow *to_window) { // We are leaving a graphics window; we should restore the Win2000 // effects. if (_got_saved_params) { - SystemParametersInfo(SPI_SETMOUSETRAILS, 0, - (PVOID)_saved_mouse_trails, 0); + SystemParametersInfo(SPI_SETMOUSETRAILS, _saved_mouse_trails, + 0, 0); SystemParametersInfo(SPI_SETCURSORSHADOW, 0, - (PVOID)_saved_cursor_shadow, 0); + _saved_cursor_shadow ? (PVOID)1 : nullptr, 0); SystemParametersInfo(SPI_SETMOUSEVANISH, 0, - (PVOID)_saved_mouse_vanish, 0); + _saved_mouse_vanish ? (PVOID)1 : nullptr, 0); _got_saved_params = false; } diff --git a/panda/src/windisplay/winGraphicsWindow.h b/panda/src/windisplay/winGraphicsWindow.h index 2be766a5db..841e2b9854 100644 --- a/panda/src/windisplay/winGraphicsWindow.h +++ b/panda/src/windisplay/winGraphicsWindow.h @@ -119,7 +119,7 @@ protected: virtual bool calculate_metrics(bool fullscreen, DWORD style, WINDOW_METRICS &metrics, bool &has_origin); - virtual DWORD make_style(bool fullscreen); + DWORD make_style(const WindowProperties &properties); virtual void reconsider_fullscreen_size(DWORD &x_size, DWORD &y_size, DWORD &bitdepth); @@ -127,7 +127,7 @@ protected: virtual void support_overlay_window(bool flag); private: - bool open_graphic_window(bool fullscreen); + bool open_graphic_window(); void adjust_z_order(); void adjust_z_order(WindowProperties::ZOrder last_z_order, WindowProperties::ZOrder this_z_order); diff --git a/pandatool/src/eggcharbase/eggBackPointer.cxx b/pandatool/src/eggcharbase/eggBackPointer.cxx index 400d9e3b2f..b1e269624a 100644 --- a/pandatool/src/eggcharbase/eggBackPointer.cxx +++ b/pandatool/src/eggcharbase/eggBackPointer.cxx @@ -13,6 +13,8 @@ #include "eggBackPointer.h" +#include "pnotify.h" + TypeHandle EggBackPointer::_type_handle; diff --git a/pandatool/src/eggcharbase/eggCharacterDb.h b/pandatool/src/eggcharbase/eggCharacterDb.h index 037367dc8b..31af55f231 100644 --- a/pandatool/src/eggcharbase/eggCharacterDb.h +++ b/pandatool/src/eggcharbase/eggCharacterDb.h @@ -29,6 +29,7 @@ */ class EggJointPointer; +class LMatrix4d; /** * This class is used during joint optimization or restructuring to store the diff --git a/pandatool/src/eggcharbase/eggJointData.cxx b/pandatool/src/eggcharbase/eggJointData.cxx index 65ed9505a5..ebf656b113 100644 --- a/pandatool/src/eggcharbase/eggJointData.cxx +++ b/pandatool/src/eggcharbase/eggJointData.cxx @@ -12,6 +12,8 @@ */ #include "eggJointData.h" + +#include "eggCharacterDb.h" #include "eggJointNodePointer.h" #include "eggMatrixTablePointer.h" #include "pvector.h" diff --git a/pandatool/src/eggcharbase/eggJointNodePointer.cxx b/pandatool/src/eggcharbase/eggJointNodePointer.cxx index c9c891606b..23bf7ea480 100644 --- a/pandatool/src/eggcharbase/eggJointNodePointer.cxx +++ b/pandatool/src/eggcharbase/eggJointNodePointer.cxx @@ -14,8 +14,9 @@ #include "eggJointNodePointer.h" #include "dcast.h" -#include "eggObject.h" +#include "eggCharacterDb.h" #include "eggGroup.h" +#include "eggObject.h" #include "pointerTo.h" diff --git a/pandatool/src/eggcharbase/eggMatrixTablePointer.cxx b/pandatool/src/eggcharbase/eggMatrixTablePointer.cxx index 21c9c63516..267296483f 100644 --- a/pandatool/src/eggcharbase/eggMatrixTablePointer.cxx +++ b/pandatool/src/eggcharbase/eggMatrixTablePointer.cxx @@ -12,7 +12,9 @@ */ #include "eggMatrixTablePointer.h" + #include "dcast.h" +#include "eggCharacterDb.h" #include "eggSAnimData.h" #include "eggXfmAnimData.h" #include "eggXfmSAnim.h" diff --git a/pandatool/src/palettizer/paletteGroup.cxx b/pandatool/src/palettizer/paletteGroup.cxx index 182479216f..5f231b2e14 100644 --- a/pandatool/src/palettizer/paletteGroup.cxx +++ b/pandatool/src/palettizer/paletteGroup.cxx @@ -17,6 +17,7 @@ #include "textureImage.h" #include "palettizer.h" #include "paletteImage.h" +#include "sourceTextureImage.h" #include "indent.h" #include "datagram.h" diff --git a/pandatool/src/softegg/config_softegg.cxx b/pandatool/src/softegg/config_softegg.cxx deleted file mode 100644 index 89ad412508..0000000000 --- a/pandatool/src/softegg/config_softegg.cxx +++ /dev/null @@ -1,55 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_softegg.cxx - * @author masad - * @date 2003-09-25 - */ - -#include "config_softegg.h" -#include "softEggGroupUserData.h" -#include "softNodeDesc.h" - -#include "dconfig.h" - -Configure(config_softegg); -NotifyCategoryDef(softegg, ":soft"); - -ConfigureFn(config_softegg) { - init_libsoftegg(); -} - -// These control the default behavior of the softegg converter, but not -// necessarily the default behavior of the soft2egg command-line tool (which -// has its own defaults). - -// Should we respect the Soft? double-sided flag (true) or ignore it and -// assume everything is single-sided (false)? -ConfigVariableBool soft_default_double_sided("soft-default-double-sided", false); - -// Should we apply vertex color even when a texture is applied (true) or only -// when no texture is applied or the vertex-color egg flag is set (false)? -ConfigVariableBool soft_default_vertex_color("soft-default-vertex-color", true); - -/** - * Initializes the library. This must be called at least once before any of - * the functions or classes in this library can be used. Normally it will be - * called by the static initializers and need not be called explicitly, but - * special cases exist. - */ -void -init_libsoftegg() { - static bool initialized = false; - if (initialized) { - return; - } - initialized = true; - - SoftEggGroupUserData::init_type(); - SoftNodeDesc::init_type(); -} diff --git a/pandatool/src/softegg/config_softegg.h b/pandatool/src/softegg/config_softegg.h deleted file mode 100644 index 8deb0cb7aa..0000000000 --- a/pandatool/src/softegg/config_softegg.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_softegg.h - * @author masad - * @date 2003-09-25 - */ - -#ifndef CONFIG_SOFTEGG_H -#define CONFIG_SOFTEGG_H - -#include "pandatoolbase.h" -#include "notifyCategoryProxy.h" -#include "configVariableBool.h" - -NotifyCategoryDeclNoExport(softegg); - -extern ConfigVariableBool soft_default_double_sided; -extern ConfigVariableBool soft_default_vertex_color; - -extern void init_libsoftegg(); - -#endif diff --git a/pandatool/src/softegg/soft2Egg.c b/pandatool/src/softegg/soft2Egg.c deleted file mode 100644 index 9e744b8655..0000000000 --- a/pandatool/src/softegg/soft2Egg.c +++ /dev/null @@ -1,4751 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file soft2Egg.c - * @author masad - * @date 2003-09-26 - */ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include "pandatoolbase.h" - -int init_soft2egg(int, char **); - -#if 0 -// DWD includes -#include "eggBase.h" -#include -#include -#include - -// system includes -#include -#include -#include -#include -#include -#include - -// Performer includes -#include - -// SoftImage includes -#include -#include - -static const int TEX_PER_MAT = 1; -static FILE *outStream = stdout; -// static FILE *outStream = stderr; - -class soft2egg : public EggBase -{ - public: - - soft2egg() : EggBase("r:d:s:m:t:P:b:e:f:T:S:M:A:N:v:o:FhknpaxiucCD") - { - rsrc_path = "/ful/ufs/soft371_mips2/3D/rsrc"; - database_name = NULL; - scene_name = NULL; - model_name = NULL; - animFileName = NULL; - eggFileName = NULL; - tex_path = NULL; - eggGroupName = NULL; - tex_filename = NULL; - search_prefix = NULL; - result = SI_SUCCESS; - - skeleton = new EggGroup(); - foundRoot = FALSE; - animRoot = NULL; - morphRoot = NULL; - geom_as_joint = 0; - make_anim = 0; - make_nurbs = 0; - make_poly = 0; - make_soft = 0; - make_morph = 1; - make_duv = 1; - make_dart = TRUE; - has_morph = 0; - make_pose = 0; - animData.is_z_up = FALSE; - nurbs_step = 1; - anim_start = -1000; - anim_end = -1000; - anim_rate = 24; - pose_frame = -1; - verbose = 0; - flatten = 0; - shift_textures = 0; - ignore_tex_offsets = 0; - use_prefix = 0; - } - - virtual void Help(); - virtual void Usage(); - virtual void ShowOpts(); - - virtual boolean UseOutputSwitch() const { - return false; - } - - virtual boolean - HandleGetopts(char flag, char *optarg, int &optind, int argc, char **argv); - - int isNum( float ); - char *GetRootName( const char * ); - char *RemovePathName( const char * ); - char *GetSliderName( const char * ); - char *GetFullName( SAA_Scene *, SAA_Elem * ); - char *GetName( SAA_Scene *, SAA_Elem * ); - char *GetModelNoteInfo( SAA_Scene *, SAA_Elem * ); - char *MakeTableName( const char *, int ); - char *DepointellizeName( char * ); - SAA_Elem *FindModelByName( char *, SAA_Scene *, SAA_Elem *, int ); - char *ConvertTexture( SAA_Scene *, SAA_Elem * ); - int *FindClosestTriVert( EggVertexPool *, SAA_DVector *, int ); - int *MakeIndexMap( int *, int, int ); - int findShapeVert( SAA_DVector, SAA_DVector *, int ); - void LoadSoft(); - void MakeEgg( EggGroup *, EggJoint *, AnimGroup *, SAA_Scene *, SAA_Elem * ); - void MakeSurfaceCurve( SAA_Scene *, SAA_Elem *, EggGroup *, - EggNurbsSurface *&, int , SAA_SubElem *, bool ); - - EggNurbsCurve *MakeUVNurbsCurve( int, long *, double *, double *, - EggGroup *, char * ); - - EggNurbsCurve *MakeNurbsCurve( SAA_Scene *, SAA_Elem *, EggGroup *, - float [4][4], char * ); - - void AddKnots( perf_vector &, double *, int, SAA_Boolean, int ); - void MakeJoint( SAA_Scene *, EggJoint *&, AnimGroup *&, SAA_Elem *, char * ); - void MakeSoftSkin( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, char * ); - void CleanUpSoftSkin( SAA_Scene *, SAA_Elem *, char * ); - void MakeAnimTable( SAA_Scene *, SAA_Elem *, char * ); - void MakeVertexOffsets( SAA_Scene *, SAA_Elem *, SAA_ModelType type, - int, int, SAA_DVector *, float (*)[4], char * ); - void MakeMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, char *, - float ); - void MakeLinearMorphTable( SAA_Scene *, SAA_Elem *, int, char *, float ); - void MakeWeightedMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, - int, char *, float ); - void MakeExpressionMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, - int, char *, float ); - void MakeTexAnim( SAA_Scene *, SAA_Elem *, char * ); - - private: - - char *rsrc_path; - char *database_name; - char *scene_name; - char *model_name; - char *eggFileName; - char *animFileName; - char *eggGroupName; - char *tex_path; - char *tex_filename; - char *search_prefix; - - SI_Error result; - SAA_Scene scene; - SAA_Elem model; - SAA_Database database; - EggGroup *dart; - EggGroup *skeleton; - AnimGroup *rootAnim; - EggJoint *rootJnt; - AnimGroup *animRoot; - AnimGroup *morphRoot; - EggData animData; - - int nurbs_step; - int anim_start; - int anim_end; - int anim_rate; - int pose_frame; - int verbose; - int flatten; - int shift_textures; - int ignore_tex_offsets; - int use_prefix; - - bool foundRoot; - bool geom_as_joint; - bool make_anim; - bool make_nurbs; - bool make_poly; - bool make_soft; - bool make_morph; - bool make_duv; - bool make_dart; - bool has_morph; - bool make_pose; - - std::ofstream eggFile; - std::ofstream animFile; - std::ofstream texFile; -}; - - -/** - * Displays the "what is this program" message, along with the usage message. - * Should be overridden in base classes to describe the current program. - */ -void soft2egg:: -Help() -{ - cerr << - "soft2egg takes a SoftImage scene or model\n" - "and outputs its contents as an egg file\n"; - - Usage(); -} - -/** - * Displays the usage message. - */ -void soft2egg:: -Usage() { - cerr << "\nUsage:\n" - << _commandName << " [opts] (must specify -m or -s)\n\n" - << "Options:\n"; - - ShowOpts(); - cerr << "\n"; -} - - - -/** - * Displays the valid options. Should be extended in base classes to show - * additional options relevant to the current program. - */ -void soft2egg:: -ShowOpts() -{ - cerr << - " -r - Used to provide soft with the resource\n" - " Defaults to 'c:/Softimage/SOFT_3.9.2/3D/test'.\n" - // " Defaults to 'fulufssoft371_mips23Drsrc'.\n" - " -d - Database path.\n" - " -s - Indicates that a scene will be converted.\n" - " -m - Indicates that a model will be converted.\n" - " -t - Specify path to place converted textures.\n" - " -T - Specify filename for texture map listing.\n" - " -S - Specify step for nurbs surface triangulation.\n" - " -M - Specify model output filename. Defaults to scene name.\n" - " -A - Specify anim output filename. Defaults to scene name.\n" - " -N - Specify egg group name.\n" - " -k - Enable soft assignment for geometry.\n" - " -n - Specify egg NURBS representation instead of poly's.\n" - " -p - Specify egg polygon output for geometry.\n" - " -P - Specify frame number for static pose.\n" - " -b - Specify starting frame for animation (default = first).\n" - " -e - Specify ending frame for animation (default = last).\n" - " -f - Specify frame rate for animation playback.\n" - " -a - Compile animation tables if animation present.\n" - " -F - Ignore hierarchy and build a completely flat skeleton.\n" - " -v - Set debug level.\n" - " -x - Shift NURBS parameters to preserve Alias textures.\n" - " -i - Ignore Soft texture uv offsets.\n" - " -u - Use Soft prefix in model names.\n" - " -c - Cancel morph conversion.\n" - " -C - Cancel duv conversion.\n" - " -D - Don't make the output model a character.\n" - " -o - Convert only models with given prefix.\n"; - - EggBase::ShowOpts(); -} - - -/** - * - */ -boolean soft2egg:: -HandleGetopts(char flag, char *optarg, int &optind, int argc, char **argv) -{ - boolean okflag = true; - - switch (flag) - { - case 'r': // Set the resource path for soft. - if ( strcmp( optarg, "" ) ) - { - // Get the path. - rsrc_path = optarg; - fprintf( outStream, "using rsrc path %s\n", rsrc_path ); - } - break; - - case 'd': // Set the database path. - if ( strcmp( optarg, "" ) ) - { - // Get the path. - database_name = optarg; - fprintf( outStream, "using database %s\n", database_name ); - } - break; - - case 's': // Check if its a scene. - if ( strcmp( optarg, "" ) ) - { - // Get scene name. - scene_name = optarg; - fprintf( outStream, "loading scene %s\n", scene_name ); - } - break; - - case 'm': // Check if its a model. - if ( strcmp( optarg, "" ) ) - { - // Get model name. - model_name = optarg; - fprintf( outStream, "loading model %s\n", model_name ); - } - break; - - case 't': // Get converted texture path. - if ( strcmp( optarg, "" ) ) - { - // Get tex path name. - tex_path = optarg; - fprintf( outStream, "texture path: %s\n", tex_path ); - } - break; - - case 'T': // Specify texture list filename. - if ( strcmp( optarg, "") ) - { - // Get the name. - tex_filename = optarg; - fprintf( outStream, "creating texture list file: %s\n", - tex_filename ); - } - break; - case 'S': // Set NURBS step. - if ( strcmp( optarg, "" ) ) - { - nurbs_step = atoi(optarg); - fprintf( outStream, "NURBS step: %d\n", nurbs_step ); - } - break; - - case 'M': // Set model output file name. - if ( strcmp( optarg, "" ) ) - { - eggFileName = optarg; - fprintf( outStream, "Model output filename: %s\n", eggFileName ); - } - break; - - case 'A': // Set anim output file name. - if ( strcmp( optarg, "" ) ) - { - animFileName = optarg; - fprintf( outStream, "Anim output filename: %s\n", animFileName ); - } - break; - - case 'N': // Set egg model name. - if ( strcmp( optarg, "" ) ) - { - eggGroupName = optarg; - fprintf( outStream, "Egg group name: %s\n", eggGroupName ); - } - break; - - case 'o': // Set search_prefix. - if ( strcmp( optarg, "" ) ) - { - search_prefix = optarg; - fprintf( outStream, "Only converting models with prefix: %s\n", - search_prefix ); - } - break; - - case 'h': // print help message - Help(); - exit(1); - break; - - case 'c': // Cancel morph animation conversion - make_morph = FALSE; - fprintf( outStream, "canceling morph conversion\n" ); - break; - - case 'C': // Cancel uv animation conversion - make_duv = FALSE; - fprintf( outStream, "canceling uv animation conversion\n" ); - break; - - case 'D': // Omit the Dart flag - make_dart = FALSE; - fprintf( outStream, "making a non-character model\n" ); - break; - - case 'k': // Enable soft skinning - // make_soft = TRUE; fprintf( outStream, "enabling soft skinning\n" ); - fprintf( outStream, "-k flag no longer necessary\n" ); - break; - - case 'n': // Generate egg NURBS output - make_nurbs = TRUE; - fprintf( outStream, "outputting egg NURBS info\n" ); - break; - - case 'p': // Generate egg polygon output - make_poly = TRUE; - fprintf( outStream, "outputting egg polygon info\n" ); - break; - - case 'P': // Generate static pose from given frame - if ( strcmp( optarg, "" ) ) - { - make_pose = TRUE; - pose_frame = atoi(optarg); - fprintf( outStream, "generating static pose from frame %d\n", - pose_frame ); - } - break; - - case 'a': // Compile animation tables. - make_anim = TRUE; - fprintf( outStream, "attempting to compile anim tables\n" ); - break; - - case 'F': // Build a flat skeleton. - flatten = TRUE; - fprintf( outStream, "building a flat skeleton!!!\n" ); - break; - - case 'x': // Shift NURBS parameters to preserve Alias textures. - shift_textures = TRUE; - fprintf( outStream, "shifting NURBS parameters...\n" ); - break; - - case 'i': // Ignore Soft uv texture offsets - ignore_tex_offsets = TRUE; - fprintf( outStream, "ignoring texture offsets...\n" ); - break; - - case 'u': // Use Soft prefix in model names - use_prefix = TRUE; - fprintf( outStream, "using prefix in model names...\n" ); - break; - - - case 'v': // print debug messages. - if ( strcmp( optarg, "" ) ) - { - verbose = atoi(optarg); - fprintf( outStream, "using debug level %d\n", verbose ); - } - break; - - case 'b': // Set animation start frame. - if ( strcmp( optarg, "" ) ) - { - anim_start = atoi(optarg); - fprintf( outStream, "animation starting at frame: %d\n", - anim_start ); - } - break; - - case 'e': /// Set animation end frame. - if ( strcmp( optarg, "" ) ) - { - anim_end = atoi(optarg); - fprintf( outStream, "animation ending at frame: %d\n", anim_end ); - } - break; - - case 'f': /// Set animation frame rate. - if ( strcmp( optarg, "" ) ) - { - anim_rate = atoi(optarg); - fprintf( outStream, "animation frame rate: %d\n", anim_rate ); - } - break; - - default: - okflag = EggBase::HandleGetopts(flag, optarg, optind, argc, argv); - } - - return (okflag); -} - - - -/** - * Take a float and make sure it is of the body. - */ -int soft2egg:: -isNum( float num ) -{ - return( ( num < HUGE_VAL ) && finite( num ) ); -} - - -/** - * Given a string, return a copy of the string up to the first occurrence of - * '-'. - */ -char *soft2egg:: -GetRootName( const char *name ) -{ - char *hyphen; - char *root; - int len; - - hyphen = strchr( name, '-' ); - len = hyphen-name; - - if ( (hyphen != NULL) && len ) - { - root = (char *)malloc(sizeof(char)*(len+1)); - strncpy( root, name, len ); - root[sizeof(char)*(len)] = '\0'; - } - else - { - root = (char *)malloc( sizeof(char)*(strlen(name)+1)); - strcpy( root, name ); - } - - return( root ); -} - - -/** - * Given a string, return a copy of the string after the last occurence of ' - */ -char *soft2egg:: -RemovePathName( const char *name ) -{ - char *slash; - char *root; - - if ( *name != NULL ) - { - slash = strrchr( name, '/' ); - - root = (char *)malloc( sizeof(char)*(strlen(name)+1)); - - if ( slash != NULL ) - strcpy( root, ++slash ); - else - strcpy( root, name ); - - return( root ); - } - - fprintf( stderr, "Error: RemovePathName received NULL string!\n" ); - return ( (char *)name ); -} - -/** - * Given a string, return that part of the string after the first occurence of - * '-' and before the last occurance of '.' - */ -char *soft2egg:: -GetSliderName( const char *name ) -{ - if ( name != NULL ) - { - strstream newStr; - char *hyphen; - char *end; - - hyphen = strchr( name, '-' ); - - // pull off stuff before first hyphen - if (hyphen != NULL) - { - newStr << ++hyphen; - end = newStr.str(); - } - - char *lastPeriod; - - lastPeriod = strrchr( end, '.' ); - - // ignore stuff after last period - if ( lastPeriod != NULL ) - { - *lastPeriod = '\0'; - } - - if ( verbose >= 1 ) - fprintf( stdout, "slider name: '%s'\n", end ); - - return( end ); - } - - return( (char *)name ); -} - -/** - * Given an element, return a copy of the element's name WITHOUT prefix. - */ -char *soft2egg:: -GetName( SAA_Scene *scene, SAA_Elem *element ) -{ - int nameLen; - char *name; - - // get the name - SAA_elementGetNameLength( scene, element, &nameLen ); - name = (char *)malloc(sizeof(char)*++nameLen); - SAA_elementGetName( scene, element, nameLen, name ); - - return name; -} - -/** - * Given an element, return a copy of the element's name complete with prefix. - */ -char *soft2egg:: -GetFullName( SAA_Scene *scene, SAA_Elem *element ) -{ - int nameLen; - char *name; - - // get the name - SAA_elementGetNameLength( scene, element, &nameLen ); - name = (char *)malloc(sizeof(char)*++nameLen); - SAA_elementGetName( scene, element, nameLen, name ); - - int prefixLen; - char *prefix; - - // get the prefix - SAA_elementGetPrefixLength( scene, element, &prefixLen ); - prefix = (char *)malloc(sizeof(char)*++prefixLen); - SAA_elementGetPrefix( scene, element, prefixLen, prefix ); - - strstream fullNameStrm; - - // add 'em together - fullNameStrm << prefix << "-" << name << ends; - - // free( name ); free( prefix ); - - return fullNameStrm.str(); -} - -/** - * Given an element, return a string containing the contents of its MODEL NOTE - * entry - */ -char *soft2egg:: -GetModelNoteInfo( SAA_Scene *scene, SAA_Elem *model ) -{ - - int size; - char *modelNote = NULL; - SAA_Boolean bigEndian; - - - SAA_elementGetUserDataSize( scene, model, "MNOT", &size ); - - if ( size != 0 ) - { - // allocate modelNote string - modelNote = (char *)malloc(sizeof(char)*(size + 1)); - - // get ModelNote data from this model - SAA_elementGetUserData( scene, model, "MNOT", size, - &bigEndian, (void *)modelNote ); - - // strip off newline, if present - char *eol = strchr( modelNote, '\n' ); - if ( eol != NULL) - *eol = '\0'; - else - modelNote[size] = '\0'; - - if ( verbose >= 1 ) - fprintf( outStream, "\nmodelNote = %s\n", - modelNote ); - } - - return modelNote; -} - - -/** - * Given a string, and a number, return a new string consisting of - * "string.number". - */ -char *soft2egg:: -MakeTableName( const char *name, int number ) -{ - strstream namestrm; - - namestrm << name << "." << number << ends; - return namestrm.str(); -} - -/** - * Given a string, find the model in the scene whose name corresponds to the - * given string. - */ -SAA_Elem *soft2egg:: -FindModelByName( char *name, SAA_Scene *scene, SAA_Elem *models, - int numModels ) -{ - char *foundName; - SAA_Elem *foundModel = NULL; - - for ( int model = 0; model < numModels; model++ ) - { - foundName = GetName( scene, &models[model] ); - - if ( !strcmp( name, foundName ) ) - { - if ( verbose >= 1 ) - fprintf( outStream, "foundModel: '%s' = '%s'\n", - name, foundName ); - - foundModel = &models[model]; - return( foundModel ); - } - } - - fprintf( outStream, "findModelByName: failed to find model named: '%s'\n", - name ); - - return ( foundModel ); -} - - -/** - * Given a string, return the string up to the first period. - */ -char *soft2egg:: -DepointellizeName( char *name ) -{ - char *endPtr; - char *newName; - - newName = (char *)malloc(sizeof(char)*(strlen(name)+1)); - sprintf( newName, "%s", name ); - - endPtr = strchr( newName, '.' ); - if ( endPtr != NULL ) - *endPtr = '\0'; - - return ( newName ); -} - - -/** - * Given a string, return a copy of the string without the leading file path, - * and make an rgb file of the same name in the tex_path directory. - */ -char *soft2egg:: -ConvertTexture( SAA_Scene *scene, SAA_Elem *texture ) -{ - char *fileName = NULL; - int fileNameLen = 0; - - // get the texture's name - SAA_texture2DGetPicNameLength( scene, texture, &fileNameLen); - - if ( fileNameLen ) - { - fileName = (char *)malloc(sizeof(char)*++fileNameLen); - SAA_texture2DGetPicName( scene, texture, fileNameLen, fileName ); - } - - // make sure we are not being passed a NULL image, an empty image string or - // the default image created by egg2soft - if ( (fileName != NULL) && strlen( fileName ) && strcmp( fileName, - "/fat/people/gregw/new_test/PICTURES/default") && - ( strstr( fileName, "noIcon" ) == NULL) ) - { - char *texName = NULL; - char *texNamePath = NULL; - char *tmpName = NULL; - char *fileNameExt = NULL; - - // strip off path and add .rgb - tmpName = strrchr( fileName, '/' ); - - if ( tmpName == NULL ) - tmpName = fileName; - else - tmpName++; - - float transp; - - // check for alpha - SAA_texture2DGetTransparency( scene, texture, &transp ); - - if ( transp != 0.0f ) { - texName = (char *)malloc(sizeof(char)*(strlen(tmpName)+6)); - sprintf( texName, "%s.rgba", tmpName ); - } else { - texName = (char *)malloc(sizeof(char)*(strlen(tmpName)+5)); - sprintf( texName, "%s.rgb", tmpName ); - } - - fileNameExt = (char *)malloc(sizeof(char)*(strlen(fileName)+5)); - sprintf( fileNameExt, "%s.pic", fileName ); - - if ( verbose >= 1 ) - fprintf( outStream, "Looking for texture file: '%s'\n", fileNameExt ); - - // try to make conversion of file - int found_file = ( access( fileNameExt, F_OK ) == 0); - - if ( found_file ) - { - if ( tex_path ) - { - texNamePath = (char *)malloc(sizeof(char)*(strlen(tex_path) + - strlen(texName) + 2)); - - sprintf( texNamePath, "%s/%s", tex_path, texName ); - - if ( texFile ) - texFile << texNamePath << ": " << fileNameExt << "\n"; - - // make sure conversion doesn't already exist - if ( (access( texNamePath, F_OK ) != 0) && !texFile ) - { - char *command = (char *)malloc(sizeof(char)* - (strlen(fileNameExt) + strlen(texNamePath) + 20)); - - sprintf( command, "image-resize -1 %s %s", - fileNameExt, texNamePath ); - - if ( verbose >=1 ) - fprintf( outStream, "executing %s\n", command ); - - system( command ); - - // free( command ); - } - else - if ( verbose >=1 ) - fprintf( outStream, "%s already exists!\n", texNamePath ); - } - else - { - if ( verbose >= 1 ) - { - fprintf( outStream, "Warning: No texture path defined" ); - fprintf( outStream, " - No automatic conversion performed\n" ); - } - } - } - else - { - fprintf( outStream, "Warning: Couldn't find texture file: %s\n", - fileNameExt ); - } - - // free( fileNameExt ); - - if (tex_path) - return( texNamePath ); - else - return( texName ); - } - else - { - fprintf( outStream, "Warning: ConvertTexture received NULL fileName\n" ); - return( NULL ); - } -} - -/** - * Given an egg vertex pool, map each vertex therein to a vertex within an - * array of SAA model vertices of size numVert. Mapping is done by closest - * proximity. - */ -int *soft2egg:: -FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert ) -{ - int *vertMap = NULL; - int vpoolSize = vpool->NumVertices(); - int i,j; - float thisDist; - float closestDist; - int closest; - - - vertMap = (int *)malloc(sizeof(int)*vpoolSize); - - // for each vertex in vpool - for ( i = 0; i < vpoolSize; i++ ) - { - // find closest model vertex - for ( j = 0; j < numVert-1; j++ ) - { - // calculate distance - thisDist = sqrtf( - powf( vpool->Vertex(i)->position[0] - vertices[j].x , 2 ) + - powf( vpool->Vertex(i)->position[1] - vertices[j].y , 2 ) + - powf( vpool->Vertex(i)->position[2] - vertices[j].z , 2 ) ); - - // remember this if its the closest so far - if ( !j || ( thisDist < closestDist ) ) - { - closest = j; - closestDist = thisDist; - } - } - vertMap[i] = closest; - - if ( verbose >= 2 ) - { - fprintf( outStream, "mapping v %d of %d:( %f, %f, %f )\n", i, - vpoolSize, vpool->Vertex(i)->position[0], - vpool->Vertex(i)->position[1], - vpool->Vertex(i)->position[2] ); - fprintf( outStream, "to cv %d of %d:( %f, %f, %f )\tdelta = %f\n", - closest, numVert-1, vertices[closest].x, vertices[closest].y, - vertices[closest].z, closestDist ); - } - } - - return( vertMap ); -} - - -/** - * Given an array of indices that is a map from one set of vertices to - * another, return an array that performs the reverse mapping of the indices - * array - */ -int *soft2egg:: -MakeIndexMap( int *indices, int numIndices, int mapSize ) -{ - int i, j; - - // allocate map array - int *map = (int *)malloc(sizeof(int)*mapSize); - - if ( map != NULL ) - { - for ( i = 0; i < mapSize; i++ ) - { - j = 0; - int found = 0; - while( j < numIndices ) - { - if ( indices[j] == i ) - { - map[i] = j; - if ( verbose >= 2 ) - fprintf( outStream, "map[%d] = %d\n", i, map[i] ); - found = 1; - break; - } - j++; - } - if ( !found) - { - if ( verbose >= 2 ) - fprintf( outStream, "Warning: orphan vertex (%d)\n", i ); - // default to -1 for now - map[i] = -1; - } - } - } - else - fprintf( outStream, "Not enough Memory for index Map...\n"); - - return( map ); -} - -/** - * given a vertex, find its corresponding shape vertex and return its index. - */ -int soft2egg:: -findShapeVert( SAA_DVector vertex, SAA_DVector *vertices, int numVert ) -{ - int i; - int found = 0; - - for ( i = 0; i < numVert && !found ; i++ ) - { - if ( ( vertex.x == vertices[i].x ) && - ( vertex.y == vertices[i].y ) && - ( vertex.z == vertices[i].z ) ) - { - found = 1; - - if ( verbose >= 2) - fprintf( outStream, "found shape vert at index %d\n", i ); - } - } - - if (!found ) - i = -1; - else - i--; - - return( i ); -} - - -/** - * Open the SI database and grab the scene & model info - */ -void soft2egg:: -LoadSoft() -{ - int i; - - if ( (scene_name == NULL && model_name == NULL) || database_name == NULL ) - { - Usage(); - exit( 1 ); - } - - if ((result = SAA_Init(rsrc_path, FALSE)) != SI_SUCCESS) - { - fprintf( outStream, "Error: Couldn't get resource path!\n"); - exit( 1 ); - } - - if ((result = SAA_databaseLoad(database_name, &database)) != SI_SUCCESS) - { - fprintf( outStream, "Error: Couldn't load database!\n"); - exit( 1 ); - } - - if ((result = SAA_sceneGetCurrent(&scene)) == SI_SUCCESS) - { - // load scene if present - if ( scene_name != NULL ) - { - SAA_sceneLoad( &database, scene_name, &scene ); - - // if no egg filename specified, make up a name - if ( eggFileName == NULL ) - { - eggFileName = (char *)malloc(sizeof(char)* - (strlen( scene_name ) + 14 )); - sprintf( eggFileName, "%s", DepointellizeName(scene_name) ); - if ( make_nurbs ) - strcat( eggFileName, "-nurb" ); - strcat( eggFileName, "-mod.egg" ); - } - - // open an output file for the geometry if necessary - if ( make_poly || make_nurbs ) - { - unlink( eggFileName ); - eggFile.open( eggFileName, ios::out, 0666 ); - - if ( !eggFile ) - { - fprintf( outStream, "Couldn't open output file: %s\n", - eggFileName ); - exit( 1 ); - } - } - - // open an output file for texture list if specified - if ( tex_filename != NULL ) - { - unlink( tex_filename ); - texFile.open( tex_filename, ios::out, 0666 ); - - if ( !texFile ) - { - fprintf( outStream, "Couldn't open output file: %s\n", - tex_filename ); - exit( 1 ); - } - } - - if ( SAA_updatelistGet( &scene ) == SI_SUCCESS ) - { - float time; - - fprintf( outStream, "setting Scene to frame %d...\n", pose_frame ); - // SAA_sceneSetPlayCtrlCurrentFrame( &scene, pose_frame ); - SAA_frame2Seconds( &scene, pose_frame, &time ); - SAA_updatelistEvalScene( &scene, time ); - sginap( 100 ); - SAA_updatelistEvalScene( &scene, time ); - if ( make_pose ) - SAA_sceneFreeze( &scene ); - } - - int numModels; - SAA_Elem *models; - - SAA_sceneGetNbModels( &scene, &numModels ); - fprintf( outStream, "Scene has %d model(s)...\n", numModels ); - - if ( numModels ) - { - // allocate array of models - models = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numModels); - - if ( models != NULL ) - { - char *rootName = GetRootName( eggFileName ); - - if ( eggGroupName == NULL ) - dart = _data.CreateGroup( NULL, rootName ); - else - dart = _data.CreateGroup( NULL, eggGroupName ); - - if (make_dart) - dart->flags |= EF_DART; - - AnimGroup *rootTable; - - rootTable = animData.CreateTable( NULL, eggFileName ); - - if ( eggGroupName == NULL ) - animRoot = animData.CreateBundle( rootTable, rootName ); - else - animRoot = animData.CreateBundle( rootTable, - eggGroupName ); - - // propagate commet to anim data - animData.root_group.children.push_front( - new EggComment( _commandLine ) ); - - if ( verbose >= 1 ) - fprintf( outStream, "made animRoot: %s\n", rootName ); - - SAA_sceneGetModels( &scene, numModels, models ); - - for ( i = 0; i < numModels; i++ ) - { - int level; - - SAA_elementGetHierarchyLevel( &scene, &models[i], &level ); - if ( !level ) - { - if ( verbose >= 1 ) - fprintf( outStream, - "\negging scene model[%d]\n", i ); - - MakeEgg( dart, NULL, NULL, &scene, &models[i] ); - } - } - - if ( make_poly || make_nurbs ) - { - // generate soft skinning assignments if desired disabled 1199 - // to streamline joint assignments. all joint assignments now - // done here. Hard & Soft. if ( make_soft) - { - char *name; - char *fullname; - SAA_Boolean isSkeleton; - - // search through models and look for skeleton parts - for ( i = 0; i < numModels; i++ ) - { - SAA_modelIsSkeleton( &scene, &models[i], &isSkeleton ); - - // get fullname for splitting files, but only use it - // in file if requested - fullname = GetFullName( &scene, &models[i] ); - if ( use_prefix ) - name = fullname; - else - name = GetName( &scene, &models[i] ); - - // split - if ( strstr( fullname, search_prefix ) != NULL ) - { - // for every skel part: get soft skin info - if ( isSkeleton ) - MakeSoftSkin( &scene, &models[i], models, - numModels, name ); - } - - // free( name ); - } - - // make sure all vertices were assigned via soft skinning - // - if not hard assign them - for ( i = 0; i < numModels; i++ ) - { - // get fullname for splitting files, but only use it - // in file if requested - fullname = GetFullName( &scene, &models[i] ); - if ( use_prefix ) - name = fullname; - else - name = GetName( &scene, &models[i] ); - - // split - if ( strstr( fullname, search_prefix ) != NULL ) - CleanUpSoftSkin( &scene, &models[i], name ); - - // free( name ); - } - - } - - - // put the skeleton data into the egg data - dart->StealChildren( *skeleton ); - - // make sure all elements have unique names - _data.UniquifyNames(); - - // write out the geometry data if requested if ( make_poly || - // make_nurbs ) { - eggFile << _data << "\n"; - fprintf( outStream, "\nwriting out %s...\n", eggFileName ); - eggFile.close(); - } - - // close texture list file if opened - if ( texFile ) - texFile.close(); - - // generate animation data if desired - if ( make_anim ) - { - if ( animFileName == NULL ) - { - animFileName = (char *)malloc(sizeof(char)* - (strlen(scene_name)+ 10 )); - sprintf( animFileName, "%s", DepointellizeName(scene_name) ); - strcat( animFileName, "-chan.egg" ); - } - - unlink( animFileName ); - animFile.open( animFileName, ios::out, 0666 ); - - if ( !animFile ) - { - fprintf( outStream, "Couldn't open output file: %s\n", - animFileName ); - exit( 1 ); - } - - int frame; - // int frameStep; - float time; - - // get all the animation frame info if not specified on the - // command line - if (anim_start == -1000) - SAA_sceneGetPlayCtrlStartFrame( &scene, &anim_start ); - - if (anim_end == -1000) - SAA_sceneGetPlayCtrlEndFrame( &scene, &anim_end ); - - // SAA_sceneGetPlayCtrlFrameStep( &scene, &frameStep ); - - fprintf( outStream, "\nframeStart = %d\n", anim_start ); - fprintf( outStream, "frameEnd = %d\n", anim_end ); - // fprintf( outStream, "frameStep = %d\n", frameStep ); - - // start at first frame and go to last - for ( frame = anim_start; frame <= anim_end; - frame += 1) - { - SAA_frame2Seconds( &scene, frame, &time ); - SAA_updatelistEvalScene( &scene, time ); - sginap( 100 ); - SAA_updatelistEvalScene( &scene, time ); - fprintf( outStream, "\n> animating frame %d\n", frame ); - - // for each model - for ( i = 0; i < numModels; i++ ) - { - char *name; - char *fullname; - SAA_Boolean isSkeleton; - SAA_ModelType type; - - SAA_modelIsSkeleton( &scene, &models[i], &isSkeleton ); - - // get fullname for splitting files, but only use it - // in file if requested - fullname = GetFullName( &scene, &models[i] ); - if ( use_prefix ) - name = fullname; - else - name = GetName( &scene, &models[i] ); - - // split - if ( strstr( fullname, search_prefix ) != NULL ) - { - // make the morph table for this critter - if ( make_morph ) - { - MakeMorphTable( &scene, &models[i], models, - numModels, name, time ); - } - } - - // find out what type of node we're dealing with - result = SAA_modelGetType( &scene, &models[i], &type ); - - int size; - - // check for uv texture animation - SAA_elementGetUserDataSize( &scene, &models[i], - "TEX_OFFSETS", &size ); - - // if so, update for this frame if desired - if ( ( size != 0 ) && make_duv ) - MakeTexAnim( &scene, &models[i], name ); - - // if we have a skeleton or something that acts like - // one - build anim tables - if ( isSkeleton || - ( strstr( name, "joint") != NULL ) ) - MakeAnimTable( &scene, &models[i], name ); - - // free( name ); - } - - if ( verbose >= 1 ) - fprintf( outStream, "\n" ); - } - - animFile << animData << "\n"; - fprintf( outStream, "\nwriting out %s...\n", animFileName ); - animFile.close(); - } - - // free( models ); - - } - else - fprintf( outStream, "Error: Not enough Memory for models...\n"); - } - } - // otherwise try to load a model - else if ( model_name != NULL ) - { - - if ( eggFileName == NULL ) - { - eggFileName = - (char *)malloc(sizeof(char)*(strlen( model_name )+13)); - sprintf( eggFileName, "%s", DepointellizeName( model_name ) ); - - if ( make_nurbs ) - strcat( eggFileName, "-nurb" ); - strcat( eggFileName, "-mod.egg" ); - } - - eggFile.open( eggFileName ); - - if ( !eggFile ) - { - fprintf( outStream, "Couldn't open output file: %s\n", - eggFileName ); - exit( 1 ); - } - - if ((result = - SAA_elementLoad(&database, &scene, model_name, &model)) - == SI_SUCCESS) - { - fprintf( outStream, "Loading single model...\n"); - MakeEgg( NULL, NULL, NULL, &scene, &model ); - } - - eggFile << _data << "\n"; - } - } - -} - -/** - * Make egg geometry from a given model. This include textures, tex coords, - * colors, normals, and joints. - */ -void soft2egg:: -MakeEgg( EggGroup *parent, EggJoint *lastJoint, AnimGroup *lastAnim, - SAA_Scene *scene, SAA_Elem *model ) -{ - char *name; - char *fullname; - SAA_ModelType type; - int id = 0; - int numShapes; - int numTri; - int numVert; - int numTexLoc = 0; - int numTexGlb = 0; - int i, j; - float matrix[4][4]; - float *uScale = NULL; - float *vScale = NULL; - float *uOffset = NULL; - float *vOffset = NULL; - SAA_Boolean uv_swap = FALSE; - void *relinfo; - SAA_SubElem *triangles = NULL; - SAA_Elem *materials = NULL; - SAA_SubElem *cvertices = NULL; - SAA_DVector *cvertPos = NULL; - SAA_DVector *vertices = NULL; - SAA_DVector *normals = NULL; - int *indices = NULL; - int *indexMap = NULL; - int *numTexTri = NULL; - SAA_Elem *textures = NULL; - char **texNameArray; - float *uCoords = NULL; - float *vCoords = NULL; - SAA_GeomType gtype = SAA_GEOM_ORIGINAL; - SAA_Boolean visible; - - // find out what type of node we're dealing with - result = SAA_modelGetType( scene, model, &type ); - - if ( verbose >= 1 ) - { - if ( type == SAA_MNILL ) - fprintf( outStream, "encountered null\n"); - else if ( type == SAA_MPTCH ) - fprintf( outStream, "encountered patch\n" ); - else if ( type == SAA_MFACE ) - fprintf( outStream, "encountered face\n" ); - else if ( type == SAA_MSMSH ) - fprintf( outStream, "encountered mesh\n" ); - else if ( type == SAA_MJNT ) - fprintf( outStream, "encountered joint\n" ); - else if ( type == SAA_MSPLN ) - fprintf( outStream, "encountered spline\n" ); - else if ( type == SAA_MMETA ) - fprintf( outStream, "encountered meta element\n" ); - else if ( type == SAA_MBALL ) - fprintf( outStream, "encountered metaball\n" ); - else if ( type == SAA_MNCRV ) - fprintf( outStream, "encountered nurb curve\n" ); - else if ( type == SAA_MNSRF ) - fprintf( outStream, "encountered nurbs surf\n" ); - else - fprintf( outStream, "encountered unknown type: %d\n", type ); - } - - // Get the name of the model - - // Get the FULL name of the model - fullname = GetFullName( scene, model ); - - if ( use_prefix ) - { - // Get the FULL name of the trim curve - name = fullname; - } - else - { - // Get the name of the trim curve - name = GetName( scene, model ); - } - - if ( verbose >= 1 ) - fprintf( outStream, "element name <%s>\n", name ); - - fflush( outStream ); - - // get the model's matrix - SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL, matrix ); - - if ( verbose >= 2 ) - { - fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[0][0], - matrix[0][1], matrix[0][2], matrix[0][3] ); - fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[1][0], - matrix[1][1], matrix[1][2], matrix[1][3] ); - fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[2][0], - matrix[2][1], matrix[2][2], matrix[2][3] ); - fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[3][0], - matrix[3][1], matrix[3][2], matrix[3][3] ); - } - - // check to see if this is a branch we don't want to descend - this will - // prevent creating geometry for animation control structures - if ( (strstr( name, "con-" ) == NULL) && - (strstr( name, "con_" ) == NULL) && - (strstr( name, "fly_" ) == NULL) && - (strstr( name, "fly-" ) == NULL) && - (strstr( name, "camRIG" ) == NULL) && - (strstr( name, "bars" ) == NULL) && - // split - (strstr( fullname, search_prefix ) != NULL) ) - { - - // if making a pose - get deformed geometry - if ( make_pose ) - gtype = SAA_GEOM_DEFORMED; - - // Get the number of key shapes - SAA_modelGetNbShapes( scene, model, &numShapes ); - if ( verbose >= 1 ) - fprintf( outStream, "MakeEgg: num shapes: %d\n", numShapes); - - // if multiple key shapes exist create table entries for each - if ( (numShapes > 0) && make_morph ) - { - has_morph = 1; - - // make sure root morph table exists - if ( morphRoot == NULL ) - morphRoot = animData.CreateTable( animRoot, "morph" ); - - char *tableName; - - // create morph table entry for each key shape (start at second shape - // - as first is the original geometry) - for ( i = 1; i < numShapes; i++ ) - { - tableName = MakeTableName( name, i ); - SAnimTable *table = new SAnimTable( ); - table->name = tableName; - table->fps = anim_rate; - morphRoot->children.push_back( table ); - if ( verbose >= 1 ) - fprintf( outStream, "created table named: '%s'\n", tableName ); - } - - // free( tableName ); - } - - SAA_modelGetNodeVisibility( scene, model, &visible ); - if ( verbose >= 1 ) - fprintf( outStream, "model visibility: %d\n", visible ); - - // Only create egg polygon data if: the node is visible, and its not a - // NULL or a Joint, and we're outputing polys (or if we are outputing - // NURBS and the model is a poly mesh or a face) - if ( visible && - (type != SAA_MNILL) && - (type != SAA_MJNT) && - ((make_poly || - (make_nurbs && ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) - || (!make_poly && !make_nurbs && make_duv && - ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) - ) - { - // If the model is a NURBS in soft, set its step before tesselating - if ( type == SAA_MNSRF ) - SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step ); - - // If the model is a PATCH in soft, set its step before tesselating - else if ( type == SAA_MPTCH ) - SAA_patchSetStep( scene, model, nurbs_step, nurbs_step ); - - // Get the number of triangles - result = SAA_modelGetNbTriangles( scene, model, gtype, id, &numTri); - if ( verbose >= 1 ) - fprintf( outStream, "triangles: %d\n", numTri); - - if ( result != SI_SUCCESS ) - { - if ( verbose >= 1 ) { - fprintf( outStream, - "Error: couldn't get number of triangles!\n" ); - fprintf( outStream, "\tbailing on model: '%s'\n", name ); - } - return; - } - - // check to see if surface is also skeleton... - SAA_Boolean isSkeleton = FALSE; - - SAA_modelIsSkeleton( scene, model, &isSkeleton ); - - // check to see if this surface is used as a skeleton or is animated via - // constraint only ( these nodes are tagged by the animator with the - // keyword "joint" somewhere in the nodes name) - if ( isSkeleton || (strstr( name, "joint" ) != NULL) ) - { - if ( verbose >= 1 ) - fprintf( outStream, "animating Polys as joint!!!\n" ); - - MakeJoint( scene, lastJoint, lastAnim, model, name ); - } - - // model is not a null and has no triangles! - if ( !numTri ) - { - if ( verbose >= 1 ) - fprintf( outStream, "no triangles!\n"); - } - else - { - // allocate array of triangles - triangles = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTri); - if ( triangles != NULL ) - { - // triangulate model and read the triangles into array - SAA_modelGetTriangles( scene, model, gtype, id, numTri, triangles ); - } - else - fprintf( outStream, "Not enough Memory for triangles...\n"); - - // allocate array of materials - materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTri); - if ( materials != NULL ) - { - // read each triangle's material into array - SAA_triangleGetMaterials( scene, model, numTri, triangles, - materials ); - } - else - fprintf( outStream, "Not enough Memory for materials...\n"); - - // allocate array of textures per triangle - numTexTri = (int *)malloc(sizeof(int)*numTri); - - // find out how many local textures per triangle - for ( i = 0; i < numTri; i++ ) - { - result = SAA_materialRelationGetT2DLocNbElements( scene, - &materials[i], FALSE, &relinfo, &numTexTri[i] ); - - // polytex - if ( result == SI_SUCCESS ) - numTexLoc += numTexTri[i]; - } - - // don't need this anymore... free( numTexTri ); - - // get local textures if present - if ( numTexLoc ) - { - // ASSUME only one texture per material - textures = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTri); - - for ( i = 0; i < numTri; i++ ) - { - // and read all referenced local textures into array - SAA_materialRelationGetT2DLocElements( scene, &materials[i], - TEX_PER_MAT , &textures[i] ); - } - - if ( verbose >= 1 ) - fprintf( outStream, "numTexLoc = %d\n", numTexLoc); - } - // if no local textures, try to get global textures - else - { - SAA_modelRelationGetT2DGlbNbElements( scene, model, - FALSE, &relinfo, &numTexGlb ); - - if ( numTexGlb ) - { - // ASSUME only one texture per model - textures = (SAA_Elem *)malloc(sizeof(SAA_Elem)); - - // get the referenced texture - SAA_modelRelationGetT2DGlbElements( scene, model, - TEX_PER_MAT, textures ); - - if ( verbose >= 1 ) - fprintf( outStream, "numTexGlb = %d\n", numTexGlb); - } - } - - // allocate array of control vertices - cvertices = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTri*3); - if ( cvertices != NULL ) - { - // read each triangle's control vertices into array - SAA_triangleGetCtrlVertices( scene, model, gtype, id, - numTri, triangles, cvertices ); - - if ( verbose >= 2 ) - { - cvertPos = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numTri*3); - SAA_ctrlVertexGetPositions( scene, model, numTri*3, - cvertices, cvertPos); - - for ( i=0; i < numTri*3; i++ ) - { - fprintf( outStream, "cvert[%d] = %f %f %f %f\n", i, - cvertPos[i].x, cvertPos[i].y, cvertPos[i].z, - cvertPos[i].w ); - } - } - } - else - fprintf( outStream, "Not enough Memory for control vertices...\n"); - - // allocate array of control vertex indices this array maps from the - // redundant cvertices array into the unique vertices array - // (cvertices->vertices) - indices = (int *)malloc(sizeof(int)*numTri*3); - if ( indices != NULL ) - { - for ( i=0; i < numTri*3; i++ ) - indices[i] = 0; - - SAA_ctrlVertexGetIndices( scene, model, numTri*3, - cvertices, indices ); - - if ( verbose >= 2 ) - for ( i=0; i < numTri*3; i++ ) - fprintf( outStream, "indices[%d] = %d\n", i, indices[i] ); - } - else - fprintf( outStream, "Not enough Memory for indices...\n"); - - // get number of UNIQUE vertices in model - SAA_modelGetNbTriVertices( scene, model, &numVert ); - - if ( verbose >= 2 ) - fprintf( outStream, "num unique verts = %d\n", numVert ); - - // allocate array of vertices - vertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numVert); - - // get the UNIQUE vertices of all triangles in model - SAA_modelGetTriVertices( scene, model, numVert, vertices ); - - if ( verbose >= 2 ) - { - for ( i=0; i < numVert; i++ ) - { - fprintf( outStream, "vertices[%d] = %f ", i, vertices[i].x ); - fprintf( outStream, "%f %f %f\n", vertices[i].y, - vertices[i].z, vertices[i].w ); - } - } - - // allocate indexMap array we contruct this array to map from the - // unique vertices array to the redundant cvertices array - it will - // save us from doing repetitive searches later - indexMap = MakeIndexMap( indices, numTri*3, numVert ); - - // allocate array of normals - normals = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numTri*3); - if ( normals != NULL ) - { - // read each control vertex's normals into an array - SAA_ctrlVertexGetNormals( scene, model, numTri*3, - cvertices, normals ); - } - else - fprintf( outStream, "Not enough Memory for normals...\n"); - - if ( verbose >= 2 ) - { - for ( i=0; i= 2 ) - { - for ( i=0; i= 2 ) - fprintf( outStream, " tritex[%d] named: %s\n", i, - texNameArray[i] ); - - SAA_texture2DGetUVSwap( scene, &textures[i], &uv_swap ); - - if ( verbose >= 2 ) - if ( uv_swap == TRUE ) - fprintf( outStream, " swapping u and v...\n" ); - - SAA_texture2DGetUScale( scene, &textures[i], &uScale[i] ); - SAA_texture2DGetVScale( scene, &textures[i], &vScale[i] ); - SAA_texture2DGetUOffset( scene, &textures[i], &uOffset[i] ); - SAA_texture2DGetVOffset( scene, &textures[i], &vOffset[i] ); - - if ( verbose >= 2 ) - { - fprintf(outStream, "tritex[%d] uScale: %f vScale: %f\n", i, uScale[i], vScale[i] ); - fprintf(outStream, " uOffset: %f vOffset: %f\n", - uOffset[i], vOffset[i] ); - } - - - SAA_texture2DGetRepeats( scene, &textures[i], &uRepeat, - &vRepeat ); - - if ( verbose >= 2 ) - { - fprintf(outStream, "uRepeat = %d, vRepeat = %d\n", - uRepeat, vRepeat ); - } - } - else - { - if ( verbose >= 2 ) - { - fprintf( outStream, "Invalid texture...\n"); - fprintf( outStream, " tritex[%d] named: (null)\n", i ); - } - } - } - -/* - * debug for ( i = 0; i < numTri; i++ ) { if ( texNameArray[i] != NULL ) - * fprintf( outStream, " tritex[%d] named: %s\n", i, texNameArray[i] ); else - * fprintf( outStream, " tritex[%d] named: (null)\n", i ); } - */ - } - // make sure we have textures before we get t-coords - else if ( numTexGlb ) - { - SAA_Boolean valid; - - // check to see if texture is present - SAA_elementIsValid( scene, textures, &valid ); - - // texture present - get the name and uv info - if ( valid ) - { - SAA_texture2DGetUVSwap( scene, textures, &uv_swap ); - - if ( verbose >= 1 ) - if ( uv_swap == TRUE ) - fprintf( outStream, " swapping u and v...\n" ); - - // allocate arrays for u & v coords - uCoords = (float *)malloc(sizeof(float)*numTri*numTexGlb*3); - vCoords = (float *)malloc(sizeof(float)*numTri*numTexGlb*3); - - for ( i = 0; i < numTri*numTexGlb*3; i++ ) - { - uCoords[i] = vCoords[i] = 0.0f; - } - - // read the u & v coords into the arrays - if ( uCoords != NULL && vCoords != NULL) - { - SAA_triCtrlVertexGetGlobalUVTxtCoords( scene, model, - numTri*3, cvertices, numTexGlb, textures, - uCoords, vCoords ); - } - else - fprintf( outStream, "Not enough Memory for texture coords...\n"); - - if ( verbose >= 2 ) - { - for ( i=0; i= 1 ) - fprintf( outStream, " global tex named: %s\n", - texNameArray ); - - // allocate arrays of texture info - uScale = ( float *)malloc(sizeof(float)); - vScale = ( float *)malloc(sizeof(float)); - uOffset = ( float *)malloc(sizeof(float)); - vOffset = ( float *)malloc(sizeof(float)); - - SAA_texture2DGetUScale( scene, textures, uScale ); - SAA_texture2DGetVScale( scene, textures, vScale ); - SAA_texture2DGetUOffset( scene, textures, uOffset ); - SAA_texture2DGetVOffset( scene, textures, vOffset ); - - if ( verbose >= 1 ) - { - fprintf( outStream, " global tex uScale: %f vScale: %f\n", - *uScale, *vScale ); - fprintf( outStream, " uOffset: %f vOffset: %f\n", - *uOffset, *vOffset ); - } - - SAA_texture2DGetRepeats( scene, textures, &uRepeat, - &vRepeat ); - - if ( verbose >= 2 ) - { - fprintf(outStream, "uRepeat = %d, vRepeat = %d\n", - uRepeat, vRepeat ); - } - } - else fprintf( outStream, "Invalid texture...\n"); - } - - // make the egg vertex pool - EggVertexPool *pool = _data.CreateVertexPool( parent, name ); - - for ( i = 0; i < numVert; i++ ) - { - pfVec3 eggVert; - pfVec3 eggNorm; - - // convert to global coords - SAA_DVector local = vertices[i]; - SAA_DVector global; - - _VCT_X_MAT( global, local, matrix ); - - // set vertices array to reflect global coords vertices[i].x = - // global.x; vertices[i].y = global.y; vertices[i].z = global.z; - - // eggVert.set( vertices[i].x, vertices[i].y, vertices[i].z ); - - // we'll preserve original verts for now - eggVert.set( global.x, global.y, global.z ); - - local = normals[indexMap[i]]; - - _VCT_X_MAT( global, local, matrix ); - - eggNorm.set( global.x, global.y, global.z ); - eggNorm.normalize(); - - pool->AddVertex( eggVert, i ); - pool->Vertex(i)->attrib.SetNormal( eggNorm ); - - // translate local uv's to global and add to vertex pool - if ( numTexLoc && (uCoords != NULL && vCoords !=NULL )) - { - float u, v; - - if ( ignore_tex_offsets ) { - u = uCoords[indexMap[i]]; - v = 1.0f - vCoords[indexMap[i]]; - } else { - u = (uCoords[indexMap[i]] - uOffset[indexMap[i]/3]) / - uScale[indexMap[i]/3]; - - v = 1.0f - ((vCoords[indexMap[i]] - vOffset[indexMap[i]/3]) / - vScale[indexMap[i]/3]); - } - - if ( isNum(u) && isNum(v) ) - { - if ( uv_swap == TRUE ) - pool->Vertex(i)->attrib.SetUV( v, u ); - else - pool->Vertex(i)->attrib.SetUV( u, v ); - } - } - else if ( numTexGlb && (uCoords != NULL && vCoords !=NULL ) ) - { - float u, v; - - if ( ignore_tex_offsets ) { - u = uCoords[indexMap[i]]; - v = 1.0f - vCoords[indexMap[i]]; - } else { - u = (uCoords[indexMap[i]] - *uOffset) / *uScale; - v = 1.0f - (( vCoords[indexMap[i]] - *vOffset ) / *vScale); - } - - if ( isNum(u) && isNum(v) ) - { - if ( uv_swap == TRUE ) - pool->Vertex(i)->attrib.SetUV( v, u ); - else - pool->Vertex(i)->attrib.SetUV( u, v ); - } - } - - // if we've encountered textures and we desire duv anims - if (( numTexLoc || numTexGlb ) && make_duv ) - { - int numExp; - SAA_Elem *tex; - - // grab the current texture - if ( numTexLoc ) - tex = &textures[0]; - else - tex = textures; - - // find how many expressions for this shape - SAA_elementGetNbExpressions( scene, tex, NULL, FALSE, - &numExp ); - - // if it has expressions we'll assume its animated - if ( numExp ) - { - // if animated object make base duv's, animtables for the - // duv's and store the original offsets - strstream uName, vName; - - // create duv target names - uName << name << ".u" << ends; - vName << name << ".v" << ends; - - // only create tables and store offsets on a per model - // basis (not per vertex) - if ( !i ) - { - - // make sure root morph table exists - if ( morphRoot == NULL ) - morphRoot = animData.CreateTable( animRoot, - "morph" ); - - // create morph table entry for each duv - SAnimTable *uTable = new SAnimTable( ); - uTable->name = uName.str(); - uTable->fps = anim_rate; - morphRoot->children.push_back( uTable ); - if ( verbose >= 1 ) - fprintf( outStream, "created duv table named: %s\n", uName.str() ); - - SAnimTable *vTable = new SAnimTable( ); - vTable->name = vName.str(); - vTable->fps = anim_rate; - morphRoot->children.push_back( vTable ); - if ( verbose >= 1 ) - fprintf( outStream, "created duv table named: %s\n", vName.str() ); - - float texOffsets[4]; - - if ( numTexGlb ) - { - texOffsets[0] = *uOffset; - texOffsets[1] = *vOffset; - texOffsets[2] = *uScale; - texOffsets[3] = *vScale; - } - else - { - texOffsets[0] = uOffset[indexMap[i]/3]; - texOffsets[1] = vOffset[indexMap[i]/3]; - texOffsets[2] = uScale[indexMap[i]/3]; - texOffsets[3] = vScale[indexMap[i]/3]; - } - - // remember original texture offsets future reference - SAA_elementSetUserData( scene, model, "TEX_OFFSETS", - sizeof( texOffsets ), TRUE, (void **)&texOffsets ); - } - - EggMorphOffset *duvU; - EggMorphOffset *duvV; - - // generate base duv's for this vertex - duvU = new EggMorphOffset( uName.str(), 1.0 , 0.0 ); - pool->Vertex(i)->attrib.uv_morphs.push_back( *duvU ); - - duvV = new EggMorphOffset( vName.str(), 0.0 , 1.0 ); - pool->Vertex(i)->attrib.uv_morphs.push_back( *duvV ); - - } // if ( numExp ) - - } // if ( numTexLoc || numTexGlb ) - - } // for ( i = 0; i < numVert; i++ ) - - // if model has key shapes, generate vertex offsets - if ( has_morph && make_morph ) - MakeVertexOffsets( scene, model, type, numShapes, numVert, - vertices, matrix, name ); - - - // create vertex ref list for all polygons in the model - EggVertexRef *vref; - - vref = new EggVertexRef( pool); - for ( i = 0; i < numVert; i++ ) - { - // add each vert in pool to last joint for hard skinning - vref->indices.push_back( EggVertexIndex( i ) ); - } - -/* - * hard assign poly geometry if no soft-skinning requested disabled 1199 to - * streamline joint assignments. all hard-skinning now done in - * CleanUpSoftSkin. if ( !make_soft ) { if ( lastJoint != NULL ) { - * lastJoint->vrefs.AddUniqueNode( *vref ); - */ - - // if ( verbose >= 1 ) fprintf( outStream, "hard-skinning %s - // (%d vertices)\n", name, i+1 ); } } - - // make an egg group to hold all triangles - EggGroup *group = _data.CreateGroup( parent, name); - - // make this group the current parent - parent = group; - - EggPolygon *poly = NULL; - EggColor *cref = NULL; - EggTexture *tref = NULL; - - // for each triangle - for ( i = 0; i < numTri*3; i+=3 ) - { - float r,g,b,a; - pfVec4 color; - - // make egg poly for each traingle and reference the appropriate - // vertex in the pool - poly = _data.CreatePolygon( group, pool ); - poly->AddVertex(indices[i]); - poly->AddVertex(indices[i+1]); - poly->AddVertex(indices[i+2]); - - // check for back face flag in model note info - char *modelNoteStr = GetModelNoteInfo( scene, model ); - - if ( modelNoteStr != NULL ) - { - if ( strstr( modelNoteStr, "bface" ) != NULL ) - poly->flags |= EG_BFACE; - } - - // check to see if material is present - SAA_Boolean valid; - SAA_elementIsValid( scene, &materials[i/3], &valid ); - - // material present - get the color - if ( valid ) - { - SAA_materialGetDiffuse( scene, &materials[i/3], &r, &g, &b ); - SAA_materialGetTransparency( scene, &materials[i/3], &a ); - color.set( r, g, b, 1.0f - a ); - } - // no material - default to white - else - color.set( 1.0, 1.0, 1.0, 1.0 ); - - cref = _data.CreateColor(color); - poly->attrib.SetCRef(cref); - - strstream uniqueTexName; - - if (numTexLoc) - { - // polytex - if ( (texNameArray[i/3] != NULL) && - (strcmp(texNameArray[i/3], "NULL") != 0) ) - { - // append unique identifier to texname for this particular - // object - uniqueTexName << name << "-" - << RemovePathName(texNameArray[i/3]); - - tref = _data.CreateTexture( texNameArray[i/3], - uniqueTexName.str() ); - - if ( verbose >= 1 ) - fprintf( outStream, " tritex[%d] named: %s\n", i/3, - texNameArray[i/3] ); - } - } - else if ( numTexGlb ) - { - if ( texNameArray != NULL ) - { - // append unique identifier to texname for this particular - // object - uniqueTexName << name << "-" - << RemovePathName(*texNameArray); - - tref = _data.CreateTexture( *texNameArray, - uniqueTexName.str() ); - - if ( verbose >= 1 ) - fprintf( outStream, " tritex named: %s\n", - *texNameArray ); - } - } - - // set the clamp on the texture - if ( tref != NULL ) - { - if ( uRepeat > 0 ) - tref->wrapu = EggTexture::WM_repeat; - else - tref->wrapu = EggTexture::WM_clamp; - - if ( vRepeat > 1 ) - tref->wrapv = EggTexture::WM_repeat; - else - tref->wrapv = EggTexture::WM_clamp; - - poly->attrib.SetTRef(tref); - } - - } - - // we're done - trash triangles... - SAA_modelClearTriangles( scene, model ); - -/* - * free molloc'd memory free( triangles ); free( materials ); free( normals ); - * free( cvertices ); free( vertices ); free( indices ); free( indexMap ); - */ - - // free these only if they were malloc'd for textures - if (numTexLoc || numTexGlb) - { -/* - * free( textures ); free( uCoords ); free( vCoords ); free( texNameArray ); - * free( uScale ); free( vScale ); free( uOffset ); free( vOffset ); - */ - } - } - } - else - { - // check to see if its a nurbs surface - if ( (type == SAA_MNSRF) && ( visible ) && (( make_nurbs ) - || ( !make_nurbs && !make_poly && make_duv )) ) - { - // check to see if NURBS is also skeleton... - SAA_Boolean isSkeleton = FALSE; - - SAA_modelIsSkeleton( scene, model, &isSkeleton ); - - // check to see if this NURBS is used as a skeleton or is animated - // via constraint only ( these nodes are tagged by the animator - // with the keyword "joint" somewhere in the nodes name) - if ( isSkeleton || (strstr( name, "joint" ) != NULL) ) - { - MakeJoint( scene, lastJoint, lastAnim, model, name ); - geom_as_joint = 1; - if ( verbose >= 1 ) - fprintf( outStream, "animating NURBS as joint!!!\n" ); - } - - EggNurbsSurface *eggNurbsSurf = new EggNurbsSurface( name ); - int uDegree, vDegree; - - // create nurbs representation of surface - SAA_nurbsSurfaceGetDegree( scene, model, &uDegree, &vDegree ); - eggNurbsSurf->u_order = uDegree + 1; - eggNurbsSurf->v_order = vDegree + 1; - if ( verbose >= 1 ) - { - fprintf( outStream, "nurbs degree: %d u, %d v\n", - uDegree, vDegree ); - fprintf( outStream, "nurbs order: %d u, %d v\n", - uDegree + 1, vDegree + 1 ); - } - - SAA_Boolean uClosed = FALSE; - SAA_Boolean vClosed = FALSE; - - SAA_nurbsSurfaceGetClosed( scene, model, &uClosed, &vClosed); - - if ( verbose >= 1 ) - { - if ( uClosed ) - fprintf( outStream, "nurbs is closed in u...\n"); - if ( vClosed ) - fprintf( outStream, "nurbs is closed in v...\n"); - } - - int uRows, vRows; - SAA_nurbsSurfaceGetNbVertices( scene, model, &uRows, &vRows ); - if ( verbose >= 1 ) - fprintf( outStream, "nurbs vertices: %d u, %d v\n", - uRows, vRows ); - - int uCurves, vCurves; - SAA_nurbsSurfaceGetNbCurves( scene, model, &uCurves, &vCurves ); - if ( verbose >= 1 ) - fprintf( outStream, "nurbs curves: %d u, %d v\n", - uCurves, vCurves ); - - if ( shift_textures ) - { - if ( uClosed ) - // shift starting point on NURBS surface for correct textures - SAA_nurbsSurfaceShiftParameterization( scene, model, -2, 0 ); - - if ( vClosed ) - // shift starting point on NURBS surface for correct textures - SAA_nurbsSurfaceShiftParameterization( scene, model, 0, -2 ); - } - - SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step ); - - // check for back face flag in model note info - char *modelNoteStr = GetModelNoteInfo( scene, model ); - - if ( modelNoteStr != NULL ) - { - if ( strstr( modelNoteStr, "bface" ) != NULL ) - eggNurbsSurf->flags |= EG_BFACE; - } - - int numKnotsU, numKnotsV; - - SAA_nurbsSurfaceGetNbKnots( scene, model, &numKnotsU, &numKnotsV ); - if ( verbose >= 1 ) - fprintf( outStream, "nurbs knots: %d u, %d v\n", - numKnotsU, numKnotsV ); - - double *knotsU, *knotsV; - knotsU = (double *)malloc(sizeof(double)*numKnotsU); - knotsV = (double *)malloc(sizeof(double)*numKnotsV); - SAA_nurbsSurfaceGetKnots( scene, model, gtype, 0, - numKnotsU, numKnotsV, knotsU, knotsV ); - - if ( verbose >= 2 ) - fprintf( outStream, "u knots:\n" ); - - AddKnots( eggNurbsSurf->u_knots, knotsU, numKnotsU, uClosed, uDegree ); - if ( verbose >= 2 ) - fprintf( outStream, "v knots:\n" ); - - AddKnots( eggNurbsSurf->v_knots, knotsV, numKnotsV, vClosed, vDegree); - - // free( knotsU ); free( knotsV ); - - // set sub_div so we can see it in perfly - eggNurbsSurf->u_subdiv = (uRows-1)*nurbs_step; - eggNurbsSurf->v_subdiv = (vRows-1)*nurbs_step; - - SAA_modelGetNbVertices( scene, model, &numVert ); - - if ( verbose >= 2 ) - fprintf( outStream, "%d CV's\n", numVert ); - - // get the CV's - vertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numVert); - SAA_modelGetVertices( scene, model, gtype, 0, - numVert, vertices ); - - // create pool of NURBS vertices - EggVertexPool *pool = _data.CreateVertexPool( parent, name ); - eggNurbsSurf->SetVertexPool( pool ); - - // create vertex ref list for all cv's in the model - EggVertexRef *vref; - - vref = new EggVertexRef( pool); - - for ( int k = 0; k= 2 ) - { - fprintf( outStream, "original cv[%d] = %f %f %f %f\n", k, - vertices[k].x, vertices[k].y, vertices[k].z, - vertices[k].w ); - } - - pfVec4 eggVert; - - // convert to global coords - SAA_DVector global; - - _VCT_X_MAT( global, vertices[k], matrix ); - - // preserve original weight - global.w = vertices[k].w; - - // normalize coords to weight - global.x *= global.w; - global.y *= global.w; - global.z *= global.w; - - // this code is commented out because I am no longer sending - // global data to the other routines (ie makevertexoffset) - - // set vertices array to reflect global coords vertices[k].x = - // global.x; vertices[k].y = global.y; vertices[k].z = - // global.z; vertices[k].w = global.w; - - // if ( verbose >= 2 ) { fprintf( outStream, "global cv[%d] = - // %f %f %f %f\n", k, vertices[k].x, vertices[k].y, - // vertices[k].z, vertices[k].w ); } - - // eggVert.set( vertices[k].x, vertices[k].y, vertices[k].z, - // vertices[k].w ); - - if ( verbose >= 2 ) - { - fprintf( outStream, "global cv[%d] = %f %f %f %f\n", k, - global.x, global.y, global.z, - global.w ); - } - - eggVert.set( global.x, global.y, global.z, - global.w ); - - // populate vertex pool - pool->AddVertex( eggVert, k ); - - // add vref's to NURBS info - eggNurbsSurf->AddVertex( k ); - - // add each vert in pool to vref for hard skinning - vref->indices.push_back( EggVertexIndex( k ) ); - - // check to see if the NURB is closed in u - if ( uClosed ) - { - // add first uDegree verts to end of row - if ( (k % uRows) == ( uRows - 1) ) - for ( int i = 0; i < uDegree; i++ ) - { - // add vref's to NURBS info - eggNurbsSurf->AddVertex( i+((k/uRows)*uRows) ); - - // add each vert to vref - vref->indices.push_back( - EggVertexIndex( i+((k/uRows)*uRows) ) ); - } - } - } - -/* - * if hard skinned or this nurb is also a joint disabled 1199 to streamline - * joint assignments. all hard skinning now done in CleanUpSoftSkin. if - * (!make_soft || geom_as_joint) { add the new cv references to the last joint - * for hard skinning only if ( lastJoint != NULL ) { - * lastJoint->vrefs.AddUniqueNode( *vref ); geom_as_joint = 0; if ( verbose >= - * 1 ) fprintf( outStream, "Doing NURBS hard skinning...\n"); } } - */ - - // check to see if the NURB is closed in v - if ( vClosed && !uClosed ) - { - // add first vDegree rows of verts to end of list - for ( int i = 0; i < vDegree*uRows; i++ ) - eggNurbsSurf->AddVertex( i ); - } - // check to see if the NURB is closed in u and v - else if ( vClosed && uClosed ) - { - // add the first (degree) v verts and a few extra - for good - // measure - for ( i = 0; i < vDegree; i++ ) - { - // add first vDegree rows of verts to end of list - for ( j = 0; j < uRows; j++ ) - eggNurbsSurf->AddVertex( j+(i*uRows) ); - - // if u is closed to we have added uDegree verts onto the - // ends of the rows - add them here too - for ( k = 0; k < uDegree; k++ ) - eggNurbsSurf->AddVertex( k+(i*uRows)+((k/uRows)*uRows) ); - } - - } - - // get the color of the NURBS surface - int numNurbMats; - EggColor *nurbCref; - pfVec4 nurbColor; - - SAA_modelRelationGetMatNbElements( scene, model, FALSE, &relinfo, - &numNurbMats ); - - if ( verbose >= 1 ) - fprintf( outStream, "nurbs surf has %d materials\n", - numNurbMats ); - - if ( numNurbMats ) - { - float r,g,b,a; - - materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numNurbMats); - - SAA_modelRelationGetMatElements( scene, model, relinfo, - numNurbMats, materials ); - - SAA_materialGetDiffuse( scene, &materials[0], &r, &g, &b ); - SAA_materialGetTransparency( scene, &materials[0], &a ); - nurbColor.set( r, g, b, 1.0f - a ); - // nurbColor.set( r, g, b, 1.0 ); - - nurbCref = _data.CreateColor(nurbColor); - eggNurbsSurf->attrib.SetCRef(nurbCref); - - // get the texture of the NURBS surface from the material - int numNurbTexLoc = 0; - int numNurbTexGlb = 0; - - // ASSUME only one texture per material - SAA_Elem nurbTex; - - // find out how many local textures per NURBS surface ASSUME - // it only has one material - SAA_materialRelationGetT2DLocNbElements( scene, &materials[0], - FALSE, &relinfo, &numNurbTexLoc ); - - // if present, get local textures - if ( numNurbTexLoc ) - { - if ( verbose >= 1 ) - fprintf( outStream, "%s had %d local tex\n", name, - numNurbTexLoc ); - - // get the referenced texture - SAA_materialRelationGetT2DLocElements( scene, &materials[0], - TEX_PER_MAT, &nurbTex ); - - } - // if no locals, try to get globals - else - { - SAA_modelRelationGetT2DGlbNbElements( scene, model, - FALSE, &relinfo, &numNurbTexGlb ); - - if ( numNurbTexGlb ) - { - if ( verbose >= 1 ) - fprintf( outStream, "%s had %d global tex\n", name, - numNurbTexGlb ); - - // get the referenced texture - SAA_modelRelationGetT2DGlbElements( scene, - model, TEX_PER_MAT, &nurbTex ); - } - } - - // add tex ref's if we found any textures - if ( numNurbTexLoc || numNurbTexGlb) - { - char *texName = NULL; - char *uniqueTexName = NULL; - EggTexture *tref; - pfMatrix nurbTexMat; - - - // convert the texture to .rgb and adjust name - texName = ConvertTexture( scene, &nurbTex ); - - // append unique identifier to texname for this particular - // object - uniqueTexName = (char *)malloc(sizeof(char)* - (strlen(name)+strlen(texName)+3) ); - sprintf( uniqueTexName, "%s-%s", name, - RemovePathName(texName) ); - - if ( verbose >= 1 ) - { - fprintf( outStream, "creating tref %s\n", - uniqueTexName ); - } - - tref = _data.CreateTexture( texName, uniqueTexName ); - - uScale = ( float *)malloc(sizeof(float)); - vScale = ( float *)malloc(sizeof(float)); - uOffset = ( float *)malloc(sizeof(float)); - vOffset = ( float *)malloc(sizeof(float)); - - // get texture offset info - SAA_texture2DGetUScale( scene, &nurbTex, uScale ); - SAA_texture2DGetVScale( scene, &nurbTex, vScale ); - SAA_texture2DGetUOffset( scene, &nurbTex, uOffset ); - SAA_texture2DGetVOffset( scene, &nurbTex, vOffset ); - SAA_texture2DGetUVSwap( scene, &nurbTex, &uv_swap ); - - - if ( verbose >= 1 ) - { - fprintf( outStream, "nurbTex uScale: %f\n", *uScale ); - fprintf( outStream, "nurbTex vScale: %f\n", *vScale ); - fprintf( outStream, "nurbTex uOffset: %f\n", *uOffset ); - fprintf( outStream, "nurbTex vOffset: %f\n", *vOffset ); - if ( uv_swap ) - fprintf( outStream, "nurbTex u & v swapped!\n" ); - else - fprintf( outStream, "nurbTex u & v NOT swapped\n" ); - } - - nurbTexMat.makeIdent(); - - if ( !ignore_tex_offsets ) - { - if ( uv_swap ) - { - nurbTexMat[0][0] = 0.0f; - nurbTexMat[1][1] = 0.0f; - nurbTexMat[0][1] = 1 / *vScale; - nurbTexMat[1][0] = 1 / *uScale; - nurbTexMat[2][1] = -(*uOffset / *uScale); - nurbTexMat[2][0] = -(*vOffset / *vScale); - } - else - { - nurbTexMat[0][0] = 1 / *uScale; - nurbTexMat[1][1] = 1 / *vScale; - nurbTexMat[2][0] = -(*uOffset / *uScale); - nurbTexMat[2][1] = -(*vOffset / *vScale); - } - } - - - // call printMat - if ( verbose >= 2 ) - { - fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[0][0], - nurbTexMat[0][1], nurbTexMat[0][2], nurbTexMat[0][3] ); - fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[1][0], - nurbTexMat[1][1], nurbTexMat[1][2], nurbTexMat[1][3] ); - fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[2][0], - nurbTexMat[2][1], nurbTexMat[2][2], nurbTexMat[2][3] ); - fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[3][0], - nurbTexMat[3][1], nurbTexMat[3][2], nurbTexMat[3][3] ); - } - - - tref->tex_mat = nurbTexMat; - tref->flags |= EFT_TRANSFORM; - - eggNurbsSurf->attrib.SetTRef(tref); - - } - - // if we've encountered textures and we desire duv anims - if (( numNurbTexLoc || numNurbTexGlb ) && make_duv ) - { - int numExp; - - // find how many expressions for this shape - SAA_elementGetNbExpressions( scene, &nurbTex, NULL, FALSE, - &numExp ); - - // if it has expressions we'll assume its animated - if ( numExp ) - { - if ( verbose > 1 ) - printf( "nurbTex has %d expressions...\n", numExp ); - - // if animated object make base duv's, animtables for - // the duv's and store the original offsets - strstream uName, vName; - - // create duv target names - uName << name << ".u" << ends; - vName << name << ".v" << ends; - - // make sure root morph table exists - if ( morphRoot == NULL ) - morphRoot = animData.CreateTable( animRoot, - "morph" ); - - // create morph table entry for each duv - SAnimTable *uTable = new SAnimTable( ); - uTable->name = uName.str(); - uTable->fps = anim_rate; - morphRoot->children.push_back( uTable ); - if ( verbose >= 1 ) - fprintf( outStream, "created duv table named: %s\n", uName.str() ); - - SAnimTable *vTable = new SAnimTable( ); - vTable->name = vName.str(); - vTable->fps = anim_rate; - morphRoot->children.push_back( vTable ); - if ( verbose >= 1 ) - fprintf( outStream, "created duv table named: %s\n", vName.str() ); - - float texOffsets[4]; - - texOffsets[0] = *uOffset; - texOffsets[1] = *vOffset; - texOffsets[2] = *uScale; - texOffsets[3] = *vScale; - - // remember original texture offsets future reference - SAA_elementSetUserData( scene, model, "TEX_OFFSETS", - sizeof( texOffsets ), TRUE, (void **)&texOffsets ); - - // create UV's and duv's for each vertex - for( i = 0; i < numVert; i++ ) - { - pfVec2 tmpUV; - EggMorphOffset *duvU; - EggMorphOffset *duvV; - - // create uv's so we can store duv's - eggNurbsSurf->CalcActualUV( i, tmpUV ); - pool->Vertex(i)->attrib.SetUV( tmpUV[0], tmpUV[1] ); - - // generate base duv's for this vertex - duvU = new EggMorphOffset(uName.str(), 1.0 , 0.0); - pool->Vertex(i)->attrib.uv_morphs.push_back(*duvU); - - duvV = new EggMorphOffset(vName.str(), 0.0 , 1.0); - pool->Vertex(i)->attrib.uv_morphs.push_back(*duvV); - } - - } // if ( numExp ) - } // if ( numTexLoc || numTexGlb ) - - // free( uScale ); free( vScale ); free( uOffset ); free( - // vOffset ); - - // free( materials ); - } - else - { - // no material present - default to white - nurbColor.set( 1.0, 1.0, 1.0, 1.0 ); - } - - // check NURBS surface for trim curves - int numTrims; - bool isTrim = TRUE; - SAA_SubElem *trims; - - SAA_nurbsSurfaceGetNbTrimCurves( scene, model, SAA_TRIMTYPE_TRIM, - &numTrims ); - - if ( verbose >= 1 ) - fprintf( outStream, "nurbs surf has %d trim curves\n", - numTrims ); - - if ( numTrims) - { - trims = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTrims); - - if ( trims ) - { - SAA_nurbsSurfaceGetTrimCurves( scene, model, - gtype, 0, SAA_TRIMTYPE_TRIM, numTrims, - trims ); - - MakeSurfaceCurve( scene, model, parent, eggNurbsSurf, - numTrims, trims, isTrim ); - } - - // free( trims ); - } - - // check NURBS surface for surface curves - isTrim = FALSE; - - SAA_nurbsSurfaceGetNbTrimCurves( scene, model, - SAA_TRIMTYPE_PROJECTION, &numTrims ); - - if ( verbose >= 1 ) - fprintf( outStream, "nurbs surf has %d surface curves\n", - numTrims ); - - if ( numTrims) - { - trims = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTrims); - - if ( trims ) - { - SAA_nurbsSurfaceGetTrimCurves( scene, model, - gtype, 0, SAA_TRIMTYPE_PROJECTION, - numTrims, trims ); - - MakeSurfaceCurve( scene, model, parent, eggNurbsSurf, - numTrims, trims, isTrim ); - } - - // free( trims ); - } - - // push the NURBS into the egg data - parent->children.push_back( eggNurbsSurf ); - - // if model has key shapes, generate vertex offsets - if ( has_morph && make_morph ) - MakeVertexOffsets( scene, model, type, numShapes, numVert, - vertices, matrix, name ); - - - // free( vertices ); - - } - - // check to see if its a NURBS curve - else if ( (type == SAA_MNCRV) && ( visible ) && ( make_nurbs ) ) - { - // ignore for now make the NURBS curve and push it into the egg - // data parent->children.push_back( MakeNurbsCurve( scene, model, - // parent, matrix, name ) ); - } - else if ( type == SAA_MJNT ) - { - MakeJoint( scene, lastJoint, lastAnim, model, name ); - if ( verbose >= 1 ) - fprintf( outStream, "encountered IK joint: %s\n", name ); - } - - // it must be a NULL - else - { - SAA_AlgorithmType algo; - - SAA_modelGetAlgorithm( scene, model, &algo ); - if ( verbose >= 1 ) - fprintf( outStream, "null algorithm: %d\n", algo ); - - if ( algo == SAA_ALG_INV_KIN ) - { - MakeJoint( scene, lastJoint, lastAnim, model, name ); - if ( verbose >= 1 ) - fprintf( outStream, "encountered IK root: %s\n", name ); - } - else if ( algo == SAA_ALG_INV_KIN_LEAF ) - { - MakeJoint( scene, lastJoint, lastAnim, model, name ); - if ( verbose >= 1 ) - fprintf( outStream, "encountered IK leaf: %s\n", name ); - } - else if ( algo == SAA_ALG_STANDARD ) - { - SAA_Boolean isSkeleton = FALSE; - - if ( verbose >= 1 ) - fprintf( outStream, "encountered Standard null: %s\n", name); - - SAA_modelIsSkeleton( scene, model, &isSkeleton ); - - // check to see if this NULL is used as a skeleton or is - // animated via constraint only ( these nodes are tagged by - // the animator with the keyword "joint" somewhere in the - // nodes name) - if ( isSkeleton || (strstr( name, "joint" ) != NULL) ) - { - MakeJoint( scene, lastJoint, lastAnim, model, name ); - if ( verbose >= 1 ) - fprintf( outStream, "animating Standard null!!!\n" ); - } - } - else - if ( verbose >= 1 ) - fprintf( outStream, "encountered some other NULL: %d\n", - algo ); - } - } - - - // check for children... - int numChildren; - int thisChild; - SAA_Elem *children; - - SAA_modelGetNbChildren( scene, model, &numChildren ); - if ( verbose >= 1 ) - fprintf( outStream, "Model children: %d\n", numChildren ); - - if ( numChildren ) - { - children = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numChildren); - SAA_modelGetChildren( scene, model, numChildren, children ); - if ( children != NULL ) - { - for ( thisChild = 0; thisChild < numChildren; thisChild++ ) - { - if ( verbose >= 1 ) - fprintf( outStream, "\negging child %d...\n", thisChild); - MakeEgg( parent, lastJoint, lastAnim, scene, - &children[thisChild] ); - } - } - else - fprintf( outStream, "Not enough Memory for children...\n"); - // free( children ); - } - fflush( outStream ); - } - else - if ( verbose >= 1 ) - fprintf( outStream, "Don't descend this branch!\n" ); - - // we are done for the most part - start cleaning up memory free( name ); -} - - -/** - * Given a scene and lists of u and v samples create a an egg NURBS curve of - * degree two from the samples - */ -void soft2egg:: -MakeSurfaceCurve( SAA_Scene *scene, SAA_Elem *model, EggGroup *parent, - EggNurbsSurface *&nurbsSurf, int numTrims, SAA_SubElem *trims, - bool isTrim ) -{ - int i; - long totalSamples = 0; - long *numSamples; - double *uSamples; - double *vSamples; - SAA_Elem *trimCurves; - char *name; - - // get UV coord data - numSamples = (long *)malloc(sizeof(long)*numTrims); - - SAA_surfaceCurveGetNbLinearSamples( scene, model, numTrims, trims, - numSamples ); - - for ( i = 0; i < numTrims; i++ ) - { - totalSamples += numSamples[i]; - if ( verbose >= 2 ) - fprintf( outStream, "numSamples[%d] = %d\n", i, numSamples[i] ); - } - - if ( verbose >= 2 ) - fprintf( outStream, "total samples = %ld\n", totalSamples ); - - uSamples = (double *)malloc(sizeof(double)*totalSamples); - vSamples = (double *)malloc(sizeof(double)*totalSamples); - - SAA_surfaceCurveGetLinearSamples( scene, model, numTrims, trims, - numSamples, uSamples, vSamples ); - - if ( verbose >= 2 ) - for ( long li = 0; li < totalSamples; li++ ) - fprintf( outStream, "master list cv[%ld] = %f, %f\n", li, - uSamples[li], vSamples[li] ); - - trimCurves = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTrims); - - SAA_surfaceCurveExtract( scene, model, numTrims, trims, trimCurves ); - - // if it's a trim create a trim to assign trim curves to - EggNurbsSurface::Trim *eggTrim = new EggNurbsSurface::Trim(); - - // for each trim curve, make an egg curve and add it to the trims of the - // NURBS surface - for ( i = 0; i < numTrims; i++ ) - { - if ( use_prefix ) - { - // Get the FULL name of the trim curve - name = GetFullName( scene, &trimCurves[i] ); - } - else - { - // Get the name of the trim curve - name = GetName( scene, &trimCurves[i] ); - } - - if ( isTrim ) - { - // add to trim list - EggNurbsSurface::Loop *eggLoop = new EggNurbsSurface::Loop(); - eggLoop->push_back( MakeUVNurbsCurve( i, numSamples, uSamples, - vSamples, parent, name ) ); - eggTrim->push_back( *eggLoop ); - } - else - // add to curve list - nurbsSurf->curves.push_back( MakeUVNurbsCurve( i, numSamples, uSamples, vSamples, parent, name ) ); - } - - if ( isTrim ) - // pus trim list onto trims list - nurbsSurf->trims.push_back( *eggTrim ); - - // free( name ); free( trimCurves ); free( uSamples ); free( vSamples ); -} - -/** - * Given a scene and lists of u and v samples create a an egg NURBS curve of - * degree two from the samples - */ -EggNurbsCurve *soft2egg:: -MakeUVNurbsCurve( int numCurve, long *numSamples, double *uSamples, - double *vSamples, EggGroup *parent, char *name ) -{ - EggNurbsCurve *eggNurbsCurve = new EggNurbsCurve( name ); - - eggNurbsCurve->order = 2; - - - if ( verbose >= 2 ) - fprintf( outStream, "nurbs UV curve %s:\n", name ); - - // set sub_div so we can see it in perfly eggNurbsCurve->subdiv = - // numSamples[numCurve]4; perfly chokes on big numbers - keep it - // reasonable - eggNurbsCurve->subdiv = 150; - - // create pool of NURBS vertices - EggVertexPool *pool = _data.CreateVertexPool( parent, name ); - eggNurbsCurve->SetVertexPool( pool ); - - // calculate offset to this curve's samples in list of all curve samples - int offset = 0; - - for ( int o = 0; o < numCurve; o++ ) - offset += numSamples[o]; - - for ( int k = 0; k= 2 ) - fprintf( outStream, "cv[%d] = %f %f %f\n", k, eggVert[0], - eggVert[1], eggVert[2] ); - - // populate vertex pool - pool->AddVertex( eggVert, k ); - - // add vref's to NURBS info - eggNurbsCurve->AddVertex( k ); - } - - // create numSamples[numCurve]+2 knots - eggNurbsCurve->knots.push_back( 0 ); - for ( k = 0; k < numSamples[numCurve]; k++ ) - eggNurbsCurve->knots.push_back( k ); - eggNurbsCurve->knots.push_back( numSamples[numCurve] - 1 ); - - // set color to bright green for now - EggColor *nurbCref; - pfVec4 nurbColor; - - nurbColor.set( 0.5, 1.0, 0.5, 1.0 ); - nurbCref = _data.CreateColor(nurbColor); - eggNurbsCurve->attrib.SetCRef(nurbCref); - - return( eggNurbsCurve ); -} - -/** - * Given a scene and a NURBS curve model create the the appropriate egg - * structures - */ -EggNurbsCurve *soft2egg:: -MakeNurbsCurve( SAA_Scene *scene, SAA_Elem *model, EggGroup *parent, - float matrix[4][4], char *name ) -{ - EggNurbsCurve *eggNurbsCurve = new EggNurbsCurve( name ); - int degree; - - if ( verbose >= 2 ) - fprintf( outStream, "nurbs curve %s:\n", name ); - - // create nurbs representation of surface - SAA_nurbsCurveGetDegree( scene, model, °ree ); - eggNurbsCurve->order = degree + 1; - if ( verbose >= 2 ) - fprintf( outStream, "nurbs curve order: %d\n", degree + 1 ); - - SAA_nurbsCurveSetStep( scene, model, nurbs_step ); - - SAA_Boolean closed = FALSE; - - SAA_nurbsCurveGetClosed( scene, model, &closed ); - if ( closed ) - if ( verbose >= 2 ) - fprintf( outStream, "nurbs curve is closed...\n"); - - int numKnots; - - SAA_nurbsCurveGetNbKnots( scene, model, &numKnots ); - if ( verbose >= 2 ) - fprintf( outStream, "nurbs curve knots: %d\n", numKnots ); - double *knots; - knots = (double *)malloc(sizeof(double)*numKnots); - SAA_nurbsCurveGetKnots( scene, model, SAA_GEOM_ORIGINAL, 0, - numKnots, knots ); - - AddKnots( eggNurbsCurve->knots, knots, numKnots, closed, degree ); - - // free( knots ); - - int numCV; - - SAA_modelGetNbVertices( scene, model, &numCV ); - if ( verbose >= 2 ) - fprintf( outStream, "%d CV's (=? %d)\n", numCV, (numKnots-(degree+1)) ); - - // set sub_div so we can see it in perfly - eggNurbsCurve->subdiv = (numCV-1)*nurbs_step; - - // get the CV's - SAA_DVector *cvArray; - cvArray = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV); - SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0, - numCV, cvArray ); - - // create pool of NURBS vertices - EggVertexPool *pool = _data.CreateVertexPool( parent, name ); - eggNurbsCurve->SetVertexPool( pool ); - - for ( int k = 0; k= 2 ) - fprintf( outStream, "cv[%d] = %f %f %f %f\n", k, cvArray[k].x, - cvArray[k].y, cvArray[k].z, cvArray[k].w ); - - pfVec4 eggVert; - - // convert to global coords - SAA_DVector local = cvArray[k]; - SAA_DVector global; - - _HVCT_X_MAT( global, local, matrix ); - - eggVert.set( global.x, global.y, global.z, global.w ); - - // populate vertex pool - pool->AddVertex( eggVert, k ); - - // add vref's to NURBS info - eggNurbsCurve->AddVertex( k ); - } - - if ( closed ) - { - // need to replicate first (degree) vertices - for ( k = 0; k < degree; k++ ) - { - eggNurbsCurve->AddVertex( k ); - if ( verbose >= 2 ) - fprintf( outStream, "adding cv[%d] = %f %f %f %f\n", k, - cvArray[k].x, cvArray[k].y, cvArray[k].z, cvArray[k].w ); - } - } - - // free( cvArray ); - - // set color to bright green for now - EggColor *nurbCref; - pfVec4 nurbColor; - - nurbColor.set( 0.5, 1.0, 0.5, 1.0 ); - nurbCref = _data.CreateColor(nurbColor); - eggNurbsCurve->attrib.SetCRef(nurbCref); - - return( eggNurbsCurve ); -} - -/** - * Given a parametric surface, and its knots, create the appropriate egg - * structure by filling in Soft's implicit knots and assigning the rest to - * eggKnots. - */ -void soft2egg:: -AddKnots( perf_vector &eggKnots, double *knots, int numKnots, - SAA_Boolean closed, int degree ) -{ - int k = 0; - double lastKnot = knots[0]; - double *newKnots; - - // add initial implicit knot(s) - if ( closed ) - { - int i = 0; - newKnots = (double *)malloc(sizeof(double)*degree); - - // need to add (degree) number of knots - for ( k = numKnots - 1; k >= numKnots - degree; k-- ) - { - // we have to know these in order to calculate next knot value so - // hold them in temp array - newKnots[i] = lastKnot - (knots[k] - knots[k-1]); - lastKnot = newKnots[i]; - i++; - } - for ( k = degree - 1; k >= 0; k-- ) - { - eggKnots.push_back( newKnots[k] ); - if ( verbose >= 2 ) - fprintf( outStream, "knots[%d] = %f\n", k, newKnots[k] ); - } - - // free( newKnots ); - } - else - { - eggKnots.push_back( knots[k] ); - if ( verbose >= 2 ) - fprintf( outStream, "knots[%d] = %f\n", k, knots[k] ); - } - - // add the regular complement of knots - for (k = 0; k < numKnots; k++) - { - eggKnots.push_back( knots[k] ); - if ( verbose >= 2 ) - fprintf( outStream, "knots[%d] = %f\n", k+1, knots[k] ); - } - - lastKnot = knots[numKnots-1]; - - // add trailing implicit knots - if ( closed ) - { - - // need to add (degree) number of knots - for ( k = 1; k <= degree; k++ ) - { - eggKnots.push_back( lastKnot + (knots[k] - knots[k-1]) ); - if ( verbose >= 2 ) - fprintf( outStream, "knots[%d] = %f\n", k, - lastKnot + (knots[k] - knots[k-1]) ); - lastKnot = lastKnot + (knots[k] - knots[k-1]); - } - } - else - { - eggKnots.push_back( knots[k-1] ); - if ( verbose >= 2 ) - fprintf( outStream, "knots[%d] = %f\n", k+1, knots[k-1] ); - } -} - -/** - * Given a name, a parent and a model create a new a new EggJoint for that - * model. - */ -void soft2egg:: -MakeJoint( SAA_Scene *scene, EggJoint *&lastJoint, AnimGroup *&lastAnim, - SAA_Elem *model, char *name ) -{ - float matrix[4][4]; - pfMatrix Matrix; - EggJoint *joint; - SAA_Boolean globalFlag = FALSE; - int scale_joint = 0; - - - // this is a quick fix to make scaled skeletons possible if the parent - // contains the keyword "scale" make this joint a global root joint - // instead of a child... - if (lastJoint != NULL) - { - if ( strstr( lastJoint->name.Str(), "scale" ) != NULL ) - { - scale_joint = 1; - if ( verbose >= 1 ) - fprintf( outStream, "scale joint flag set!\n" ); - } - } - - // if not root, flatten is false, and last joint had no scaling applied to - // it, then create joint in skeleton tree - if ( (lastJoint != NULL) && !flatten && !scale_joint ) - { - if ( verbose >= 1 ) - { - fprintf( outStream, "lastJoint = %s\n", lastJoint->name.Str() ); - fprintf( outStream, "getting local transform\n" ); - } - - SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ), - TRUE, (void **)&globalFlag ); - - // get the local matrix - SAA_modelGetMatrix( scene, model, SAA_COORDSYS_LOCAL, matrix ); - - // make this into a pfMatrix - Matrix[0][0] = matrix[0][0]; - Matrix[0][1] = matrix[0][1]; - Matrix[0][2] = matrix[0][2]; - Matrix[0][3] = matrix[0][3]; - Matrix[1][0] = matrix[1][0]; - Matrix[1][1] = matrix[1][1]; - Matrix[1][2] = matrix[1][2]; - Matrix[1][3] = matrix[1][3]; - Matrix[2][0] = matrix[2][0]; - Matrix[2][1] = matrix[2][1]; - Matrix[2][2] = matrix[2][2]; - Matrix[2][3] = matrix[2][3]; - Matrix[3][0] = matrix[3][0]; - Matrix[3][1] = matrix[3][1]; - Matrix[3][2] = matrix[3][2]; - Matrix[3][3] = matrix[3][3]; - - joint = _data.CreateJoint( lastJoint, name ); - joint->transform = Matrix; - } - // if we already have a root attach this joint to it - else if (foundRoot) - { - if ( verbose >= 1 ) - fprintf( outStream, "getting global transform\n" ); - - globalFlag = TRUE; - - SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ), - TRUE, (void *)&globalFlag ); - - // get the global matrix - SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL, matrix ); - - // make this into a pfMatrix - Matrix[0][0] = matrix[0][0]; - Matrix[0][1] = matrix[0][1]; - Matrix[0][2] = matrix[0][2]; - Matrix[0][3] = matrix[0][3]; - Matrix[1][0] = matrix[1][0]; - Matrix[1][1] = matrix[1][1]; - Matrix[1][2] = matrix[1][2]; - Matrix[1][3] = matrix[1][3]; - Matrix[2][0] = matrix[2][0]; - Matrix[2][1] = matrix[2][1]; - Matrix[2][2] = matrix[2][2]; - Matrix[2][3] = matrix[2][3]; - Matrix[3][0] = matrix[3][0]; - Matrix[3][1] = matrix[3][1]; - Matrix[3][2] = matrix[3][2]; - Matrix[3][3] = matrix[3][3]; - - if ( verbose >= 1 ) - fprintf( outStream, "attaching orphan chain to root\n" ); - - joint = _data.CreateJoint( rootJnt, name ); - joint->transform = Matrix; - lastAnim = rootAnim; - } - // if root, make a seperate tree for skeleton and create required Table - // for the Egg heirarchy - else - { - if ( verbose >= 1 ) - fprintf( outStream, "getting global transform\n" ); - - globalFlag = TRUE; - - SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ), - TRUE, (void *)&globalFlag ); - - // get the global matrix - SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL, matrix ); - - // make this into a pfMatrix - Matrix[0][0] = matrix[0][0]; - Matrix[0][1] = matrix[0][1]; - Matrix[0][2] = matrix[0][2]; - Matrix[0][3] = matrix[0][3]; - Matrix[1][0] = matrix[1][0]; - Matrix[1][1] = matrix[1][1]; - Matrix[1][2] = matrix[1][2]; - Matrix[1][3] = matrix[1][3]; - Matrix[2][0] = matrix[2][0]; - Matrix[2][1] = matrix[2][1]; - Matrix[2][2] = matrix[2][2]; - Matrix[2][3] = matrix[2][3]; - Matrix[3][0] = matrix[3][0]; - Matrix[3][1] = matrix[3][1]; - Matrix[3][2] = matrix[3][2]; - Matrix[3][3] = matrix[3][3]; - - rootJnt = _data.CreateJoint( skeleton, "root" ); - rootJnt->transform.makeIdent(); - if ( verbose >= 1 ) - fprintf( outStream, "setting skeleton root\n" ); - rootJnt->flags |= EF_TRANSFORM; - - joint = _data.CreateJoint( rootJnt, name ); - joint->transform = Matrix; - foundRoot = TRUE; - if ( verbose >= 1 ) - fprintf( outStream, "found first chain\n" ); - - // make skeleton table - AnimGroup *skeletonTable; - skeletonTable = animData.CreateTable( animRoot, "" ); - rootAnim = animData.CreateTable( skeletonTable, "root" ); - XfmSAnimTable *table = new XfmSAnimTable( ); - table->name = "xform"; - table->fps = anim_rate; - rootAnim->children.push_back( table ); - lastAnim = rootAnim; - } - - joint->flags |= EF_TRANSFORM; - - // if ( make_anim) { - AnimGroup *anim = animData.CreateTable( lastAnim, name ); - XfmSAnimTable *table = new XfmSAnimTable( ); - if ( verbose >= 1 ) - fprintf( outStream, "created anim table: %s\n", "xform" ); - table->name = "xform"; - table->fps = anim_rate; - anim->children.push_back( table ); - lastAnim = anim; - // } - - // make this joint current parent of chain - lastJoint = joint; -} - - -/** - * Given a skeleton part find its envelopes (if any) get the vertices - * associated with the envelopes and their weights and make vertex ref's for - * the joint - */ -void soft2egg:: -MakeSoftSkin( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, - int numModels, char *name ) -{ - int numEnv; - SAA_ModelType type; - SAA_Elem *envelopes; - - if ( verbose >= 1 ) - fprintf( outStream, "\n>found skeleton part( %s )!\n", name ); - - SAA_skeletonGetNbEnvelopes( scene, model, &numEnv ); - - if ( numEnv ) - { - // it's got envelopes - must be soft skinned - if ( verbose >= 1 ) - fprintf( outStream, "numEnv = %d\n", numEnv ); - - // allocate envelope array - envelopes = ( SAA_Elem *)malloc( sizeof( SAA_Elem )*numEnv ); - - if ( envelopes != NULL ) - { - int thisEnv; - SAA_EnvType envType; - bool hasEnvVertices = 0; - - SAA_skeletonGetEnvelopes( scene, model, numEnv, envelopes ); - - for ( thisEnv = 0; thisEnv < numEnv; thisEnv++ ) - { - if ( verbose >= 1 ) - fprintf( outStream, "env[%d]: ", thisEnv ); - - SAA_envelopeGetType( scene, &envelopes[thisEnv], &envType ); - - if ( envType == SAA_ENVTYPE_NONE ) - { - if ( verbose >= 1 ) - fprintf( outStream, "envType = none\n" ); - } - else if ( envType == SAA_ENVTYPE_FLXLCL ) - { - if ( verbose >= 1 ) - fprintf( outStream, "envType = flexible, local\n" ); - hasEnvVertices = 1; - } - else if ( envType == SAA_ENVTYPE_FLXGLB ) - { - if ( verbose >= 1 ) - fprintf( outStream, "envType = flexible, global\n" ); - hasEnvVertices = 1; - } - else if ( envType == SAA_ENVTYPE_RGDGLB ) - { - if ( verbose >= 1 ) - fprintf( outStream, "envType = rigid, global\n" ); - hasEnvVertices = 1; - } - else - { - if ( verbose >= 1 ) - fprintf( outStream, "envType = unknown\n" ); - } - } - - if ( hasEnvVertices) - { - int *numEnvVertices; - SAA_SubElem *envVertices = NULL; - - numEnvVertices = (int *)malloc(sizeof(int)*numEnv); - - SAA_envelopeGetNbCtrlVertices( scene, model, numEnv, - envelopes, numEnvVertices ); - - if ( numEnvVertices != NULL ) - { - int totalEnvVertices = 0; - int i,j,k; - - for( i = 0; i < numEnv; i++ ) - { - totalEnvVertices += numEnvVertices[i]; - if ( verbose >= 1 ) - fprintf( outStream, "numEnvVertices[%d] = %d\n", - i, numEnvVertices[i] ); - } - - - if ( verbose >= 1 ) - fprintf( outStream, "total env verts = %d\n", - totalEnvVertices ); - - if ( totalEnvVertices ) - { - envVertices = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*totalEnvVertices); - - if ( envVertices != NULL ) - { - - SAA_envelopeGetCtrlVertices( scene, model, - numEnv, envelopes, numEnvVertices, envVertices); - - // loop through for each envelope - for ( i = 0; i < numEnv; i++ ) - { - float *weights = NULL; - int vertArrayOffset = 0; - - if ( verbose >= 2 ) - fprintf( outStream, "\nenvelope[%d]:\n", i ); - - weights = (float *)malloc(sizeof(float)*numEnvVertices[i]); - - if ( weights ) - { - char *envName; - int *vpoolMap = NULL; - - for ( j = 0; j < i; j++ ) - vertArrayOffset += numEnvVertices[j]; - - if ( verbose >= 1 ) - fprintf( outStream, - "envVertArray offset = %d\n", - vertArrayOffset ); - - // get the weights of the envelope vertices - SAA_ctrlVertexGetEnvelopeWeights( - scene, model, &envelopes[i], - numEnvVertices[i], - &envVertices[vertArrayOffset], weights ); - - // Get the name of the envelope model - if ( use_prefix ) - { - // Get the FULL name of the envelope - envName = GetFullName( scene, &envelopes[i] ); - } - else - { - // Get the name of the envelope - envName = GetName( scene, &envelopes[i] ); - } - - if ( verbose >= 1 ) - fprintf( outStream, "envelope name %s\n", envName ); - - // find out if envelope geometry is poly or nurb - // SAA_modelGetType( scene, FindModelByName( - // envName, scene, models, numModels ), &type ); - - SAA_modelGetType( scene, &envelopes[i], &type ); - - if ( verbose >= 1 ) - { - fprintf( outStream, "envelope model type "); - - if ( type == SAA_MSMSH ) - fprintf( outStream, "MESH\n" ); - else if ( type == SAA_MNSRF ) - fprintf( outStream, "NURBS\n" ); - else - fprintf( outStream, "OTHER\n" ); - } - - int *envVtxIndices = NULL; - envVtxIndices = (int *)malloc(sizeof(int)*numEnvVertices[i]); - - // Get the envelope vertex indices - SAA_ctrlVertexGetIndices( scene, &envelopes[i], numEnvVertices[i], - &envVertices[vertArrayOffset], envVtxIndices ); - - // find out how many vertices the model has - int modelNumVert; - - SAA_modelGetNbVertices( scene, &envelopes[i], &modelNumVert ); - - SAA_DVector *modelVertices = NULL; - modelVertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*modelNumVert); - - // get the model vertices - SAA_modelGetVertices( scene, &envelopes[i], - SAA_GEOM_ORIGINAL, 0, modelNumVert, - modelVertices ); - - // create array of global model coords - SAA_DVector *globalModelVertices = NULL; - globalModelVertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*modelNumVert); - float matrix[4][4]; - - // tranform local model vert coords to global - - // first get the global matrix - SAA_modelGetMatrix( scene, &envelopes[i], SAA_COORDSYS_GLOBAL, matrix ); - - // populate array of global model verts - for ( j = 0; j < modelNumVert; j++ ) - { - _VCT_X_MAT( globalModelVertices[j], - modelVertices[j], matrix ); - } - - // find the egg vertex pool that corresponds to - // this envelope model - EggVertexPool *envPool = - (EggVertexPool *)(_data.pools.FindName( envName )); - // If we are outputting triangles: create an array - // that maps from a referenced vertex in the - // envelope to a corresponding vertex in the egg - // vertex pool if ( (type == SAA_MNSRF) && - // !make_nurbs ) - if ( !make_nurbs || (type == SAA_MSMSH) ) - { - vpoolMap = FindClosestTriVert( envPool, - globalModelVertices, modelNumVert ); - } - - - if ( envPool != NULL ) - { - - // find the egg joint that corresponds to this - // model - EggJoint *joint = - (EggJoint *)(skeleton->FindDescendent( name )); - - // this doesn't seem to be necessary 4799 EggJoint - // *parent = (EggJoint *)joint->parent; - // assert(parent->IsA(NT_EggJoint)); - - // for every envelope vertex - for (j = 0; j < numEnvVertices[i]; j++) - { - double scaledWeight = weights[j]/ 100.0f; - - // make sure its in legal range - if (( envVtxIndices[j] < modelNumVert ) - && ( envVtxIndices[j] >= 0 )) - { - if ( (type == SAA_MNSRF) && make_nurbs ) - { - // assign all referenced control vertices - joint->AddVertex( envPool->Vertex(envVtxIndices[j]), scaledWeight ); - - if ( verbose >= 2 ) - fprintf( outStream, - "%d: adding vref to cv %d with weight %f\n", - j, envVtxIndices[j], scaledWeight ); - - envPool->Vertex(envVtxIndices[j])->AddJoint( joint, scaledWeight ); - // set flag to show this vertex has been - // assigned - envPool->Vertex(envVtxIndices[j])->multipleJoints = 1; - } - else - { - // assign all the tri verts associated - // with this control vertex to joint - for ( k = 0; k < envPool->NumVertices(); k++ ) - { - if ( vpoolMap[k] == envVtxIndices[j] ) - { - - // add each vert in pool to last joint - // for soft skinning - joint->AddVertex(envPool->Vertex(k), - scaledWeight); - - if ( verbose >= 2 ) - fprintf( outStream, - "%d: adding vref from cv %d to vert %d with weight %f(vpool)\n", - j, envVtxIndices[j], k, scaledWeight ); - - envPool->Vertex(k)->AddJoint( joint, scaledWeight ); - // set flag to show this vertex has - // been assigned - envPool->Vertex(k)->multipleJoints = 1; - } - } - } - } - else - if ( verbose >= 2 ) - fprintf( outStream, - "%d: Omitted vref from cv %d with weight %f (out of range 0 to %d )\n", - j, envVtxIndices[j], scaledWeight, modelNumVert ); - } - - } - else - if ( verbose >= 2 ) - fprintf( outStream, "Couldn't find vpool %s!\n", envName ); - - // free( modelVertices ); free( - // globalModelVertices ); free( envVtxIndices ); - // free( envName ); - } //if (weights) - // free( weights ); - - } // for i - - } // if (envVertices != NULL) - else - fprintf( outStream, "Not enough memory for envelope vertices...\n"); - // free( envVertices ); - } // if (totalEnvVertices) - else - if ( verbose >= 1 ) - fprintf( outStream, "No envelope vertices present...\n"); - - // free( numEnvVertices ); - - } // if (numEnvVertices != NULL) - - } // if (hasEnvVertices) - - } // if (envelopes != NULL) - else - fprintf( outStream, "Not enough memory for envelopes...\n" ); - - // free( envelopes ); - - } //if (numEnv) - - else - if ( verbose >= 1 ) - fprintf( outStream, "Skeleton member has no envelopes...\n" ); -} - - -/** - * Given a model, make sure all its vertices have been soft assigned. If not - * hard assign to the last joint we saw. - */ -void soft2egg:: -CleanUpSoftSkin( SAA_Scene *scene, SAA_Elem *model, char *name ) -{ - static EggJoint *joint; - SAA_Elem parent; - SAA_ModelType type; - SAA_Boolean skel; - - // find out what type of node we're dealing with - SAA_modelGetType( scene, model, &type ); - - char *parentName; - int level; - SAA_Elem *searchNode = model; - - if ( verbose >= 1 ) - fprintf( outStream, "\nCleaning up model %s\n", name ); - - // this step is weird - I think I want it here but it seems to break some - // models. Files like props-props_wh_cookietime.3-0 in - // fulrndpubvrmlchipchips_adventurecharzone1roomswarehouse_final need to - // do the "if (skel)" bit. - - // am I a skeleton too? - SAA_modelIsSkeleton( scene, model, &skel ); - - // if not look for the last skeleton part - if ( skel ) - parentName = name; - else do - { - SAA_elementGetHierarchyLevel( scene, searchNode, &level ); - - // make sure we don't try to get the root's parent - if ( level ) - { - SAA_modelGetParent( scene, searchNode, &parent ); - - if ( use_prefix ) - { - // Get the FULL name of the parent - parentName = GetFullName( scene, &parent ); - } - else - { - // Get the name of the parent - parentName = GetName( scene, &parent ); - } - - SAA_modelGetType( scene, &parent, &type ); - - SAA_modelIsSkeleton( scene, &parent, &skel ); - - if ( verbose >= 1 ) - fprintf( outStream, "model %s, level %d, type %d, skel %d\n", - parentName, level, type, skel ); - - searchNode = &parent; - } - else - { - // we reached the root of the tree - parentName = NULL; - if ( verbose >= 1 ) - fprintf( outStream, "at root of tree! level %d\n", level ); - break; - } - - // look until parent is a joint or acts like one - } while ( !skel && ( strstr( parentName,"joint") == NULL )); - - EggJoint *thisJoint = NULL; - - if ( parentName != NULL ) - { - if ( verbose >= 1 ) - { - fprintf( outStream, "found model parent joint %s\n", parentName); - fprintf( outStream, "looking for joint %s\n", parentName ); - } - thisJoint = (EggJoint *)(skeleton->FindDescendent( parentName )); - } - else - if ( verbose >= 1 ) - fprintf( outStream, "Couldn't find parent joint!\n"); - - if ( thisJoint != NULL ) - { - joint = thisJoint; - if ( verbose >= 1 ) - fprintf( outStream, "setting joint to %s\n", parentName ); - - // find the vpool for this model - EggVertexPool *vPool = - (EggVertexPool *)(_data.pools.FindName( name )); - - if (vPool != NULL) - { - int i; - double membership; - int numVerts = vPool->NumVertices() ; - - - if ( verbose >= 1 ) - fprintf( outStream, "found vpool %s w/ %d verts\n", - name, numVerts ); - - for ( i = 0; i < numVerts; i++ ) - { - if ( vPool->Vertex(i)->multipleJoints != 1 ) - { - if ( verbose >= 1 ) - { - fprintf( outStream, "vpool %s vert %d", name, i ); - fprintf( outStream, " not assigned!\n" ); - } - - // hard skin this vertex - joint->AddVertex( vPool->Vertex(i), 1.0f ); - } - else - { - membership = vPool->Vertex(i)->NetMembership(); - - - if ( verbose >= 1 ) - { - fprintf( outStream, "vpool %s vert %d", name, - i ); - fprintf( outStream, " has membership %f\n", - membership ); - } - - if ( membership == 0 ) - { - if ( verbose >= 1 ) - fprintf( outStream, "adding full weight..\n" ); - - // hard skin this vertex - joint->AddVertex( vPool->Vertex(i), 1.0f ); - } - } - } - } - else - if ( verbose >= 1 ) - fprintf( outStream, "couldn't find vpool %s\n", name ); - } - else - { - if ( parentName != NULL ) - if ( verbose >= 1 ) - fprintf( outStream, "Couldn't find joint %s\n", parentName ); - } -} - -/** - * Given a scene and a skeleton part ,get all the position, rotation, and - * scale for the skeleton part for this frame and write them out as Egg - * animation tables. - */ -void soft2egg:: -MakeAnimTable( SAA_Scene *scene, SAA_Elem *skeletonPart, char *name ) -{ - - if ( skeletonPart != NULL ) - { - float i,j,k; - float h,p,r; - float x,y,z; - int size; - SAA_Boolean globalFlag = FALSE; - SAA_Boolean bigEndian; - - if ( verbose >= 1 ) - fprintf( outStream, "\n\nanimating child %s\n", name ); - - SAA_elementGetUserDataSize( scene, skeletonPart, "GLOBAL", &size ); - - if ( size != 0 ) - SAA_elementGetUserData( scene, skeletonPart, "GLOBAL", - sizeof( SAA_Boolean), &bigEndian, (void *)&globalFlag ); - - if ( globalFlag ) - { - if ( verbose >= 1 ) - fprintf( outStream, " using global matrix\n" ); - - // get SAA orientation - SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_GLOBAL, - &p, &h, &r ); - - // get SAA translation - SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_GLOBAL, - &x, &y, &z ); - - // get SAA scaling - SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_GLOBAL, - &i, &j, &k ); - } - else - { - if ( verbose >= 1 ) - fprintf( outStream, "using local matrix\n" ); - - // get SAA orientation - SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_LOCAL, - &p, &h, &r ); - - // get SAA translation - SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_LOCAL, - &x, &y, &z ); - - // get SAA scaling - SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_LOCAL, - &i, &j, &k ); - } - - - if ( verbose >= 2 ) - fprintf( outStream, "\nanim data: %f %f %f\n\t%f %f %f\n\t%f %f %f\n", - i, j, k, h, p, r, x, y, z ); - - // find the appropriate anim table for this skeleton part - AnimGroup *thisGroup; - XfmSAnimTable *thisTable; - - // find the anim table associated with this group - thisGroup = (AnimGroup *)(animRoot->FindDescendent( name )); - if ( verbose >= 2 ) - fprintf( outStream, "\nlooking for anim group %s\n", name ); - if ( thisGroup != NULL ) - { - thisTable = (XfmSAnimTable *)(thisGroup->FindDescendent( "xform" )); - - if ( thisTable != NULL ) - { - thisTable->sub_tables[0].AddElement( i ); - thisTable->sub_tables[1].AddElement( j ); - thisTable->sub_tables[2].AddElement( k ); - thisTable->sub_tables[3].AddElement( p ); - thisTable->sub_tables[4].AddElement( h ); - thisTable->sub_tables[5].AddElement( r ); - thisTable->sub_tables[6].AddElement( x ); - thisTable->sub_tables[7].AddElement( y ); - thisTable->sub_tables[8].AddElement( z ); - } - else - fprintf( outStream, "Couldn't allocate anim table\n" ); - } - else - if ( verbose >= 2 ) - fprintf( outStream, "Couldn't find anim group %s\n", name ); - } - else - { - if ( verbose >= 2 ) - fprintf( outStream, "Cannot build anim table - no skeleton\n" ); - } -} - -/** - * Given a scene, a model , the vertices of its original shape and its name - * find the difference between the geometry of its key shapes and the models - * original geometry and add morph vertices to the egg data to reflect these - * changes. - */ -void soft2egg:: -MakeVertexOffsets( SAA_Scene *scene, SAA_Elem *model, SAA_ModelType type, - int numShapes, int numOrigVert, SAA_DVector *originalVerts, float - matrix[4][4], char *name ) -{ - int i, j; - int offset; - int numCV; - char *mTableName; - SAA_DVector *shapeVerts = NULL; - SAA_DVector *uniqueVerts = NULL; - - if ( (type == SAA_MNSRF) && make_nurbs ) - SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step ); - - SAA_modelGetNbVertices( scene, model, &numCV ); - - // get the shape verts - uniqueVerts = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV); - SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0, - numCV, uniqueVerts ); - - if ( verbose >= 2 ) - fprintf( outStream, "%d CV's\n", numCV ); - - if ( verbose >= 2 ) - { - for ( i = 0; i < numCV; i++ ) - fprintf( outStream, "uniqueVerts[%d] = %f %f %f %f\n", i, - uniqueVerts[i].x, uniqueVerts[i].y, - uniqueVerts[i].z, uniqueVerts[i].w ); - } - - // iterate through for each key shape (except original) - for ( i = 1; i < numShapes; i++ ) - { - mTableName = MakeTableName( name, i ); - - if ( verbose >= 1 ) - { - fprintf( outStream, "\nMaking geometry offsets for %s...\n", - mTableName ); - - if ( (type == SAA_MNSRF) && make_nurbs ) - fprintf( outStream, "calculating NURBS morphs...\n" ); - else - fprintf( outStream, "calculating triangle morphs...\n" ); - } - - // get the shape verts - shapeVerts = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV); - SAA_modelGetVertices( scene, model, SAA_GEOM_SHAPE, i+1, - numCV, shapeVerts ); - - if ( verbose >= 2 ) - { - for ( j=0; j < numCV; j++ ) - { - fprintf( outStream, "shapeVerts[%d] = %f %f %f\n", j, - shapeVerts[j].x, shapeVerts[j].y, shapeVerts[j].z ); - } - } - - // find the appropriate vertex pool - EggVertexPool *vPool = - (EggVertexPool *)(_data.pools.FindName( name )); - - // for every original vertex, compare to the corresponding key shape - // vertex and see if a vertex offset is needed - for ( j=0; j < numOrigVert; j++ ) - { - double dx, dy, dz; - - if ( (type == SAA_MNSRF) && make_nurbs ) - { - // dx = shapeVerts[j].x - - // (originalVerts[j].xoriginalVerts[j].w); dy = - // shapeVerts[j].y - (originalVerts[j].yoriginalVerts[j].w); - // dz = shapeVerts[j].z - - // (originalVerts[j].zoriginalVerts[j].w); - dx = shapeVerts[j].x - originalVerts[j].x; - dy = shapeVerts[j].y - originalVerts[j].y; - dz = shapeVerts[j].z - originalVerts[j].z; - } - else - { - // we need to map from original vertices to triangle shape - // vertices here - offset = findShapeVert( originalVerts[j], uniqueVerts, - numCV ); - - dx = shapeVerts[offset].x - originalVerts[j].x; - dy = shapeVerts[offset].y - originalVerts[j].y; - dz = shapeVerts[offset].z - originalVerts[j].z; - } - - if ( verbose >= 2 ) - { - fprintf( outStream, "oVert[%d] = %f %f %f %f\n", j, - originalVerts[j].x, originalVerts[j].y, - originalVerts[j].z, originalVerts[j].w ); - - if ( (type == SAA_MNSRF) && make_nurbs ) - { - fprintf( outStream, "global shapeVerts[%d] = %f %f %f %f\n", j, shapeVerts[j].x, shapeVerts[j].y, - shapeVerts[j].z, shapeVerts[j].w ); - } - else - { - fprintf( outStream, - "global shapeVerts[%d] = %f %f %f\n", offset, - shapeVerts[offset].x, - shapeVerts[offset].y, - shapeVerts[offset].z ); - } - - fprintf( outStream, "%d: dx = %f, dy = %f, dz = %f\n", j, - dx, dy, dz ); - } - - // if change isn't negligible, make a morph vertex entry - double total = fabs(dx)+fabs(dy)+fabs(dz); - if ( total > 0.00001 ) - { - if ( vPool != NULL ) - { - // create offset - EggMorphOffset *dxyz = - new EggMorphOffset( mTableName, dx, dy, dz ); - - EggVertex *eggVert; - - // get the appropriate egg vertex - eggVert = vPool->Vertex(j); - - // add the offset to the vertex - eggVert->morphs.push_back( *dxyz ); - } - else - fprintf( outStream, "Error: couldn't find vertex pool %s\n", name ); - } // if total - } //for j - } //for i -} - - -/** - * Given a scene, a model, a name and a frame time, determine what type of - * shape interpolation is used and call the appropriate function to extract - * the shape weight info for this frame... - */ -void soft2egg:: -MakeMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, - int numModels, char *name, float time ) -{ - int numShapes; - SAA_AnimInterpType type; - - // Get the number of key shapes - SAA_modelGetNbShapes( scene, model, &numShapes ); - - if ( numShapes > 0 ) - { - if ( verbose >= 1 ) - fprintf( outStream, "MakeMorphTable: %s: num shapes: %d\n", - name, numShapes); - - SAA_modelGetShapeInterpolation( scene, model, &type ); - - if ( type == SAA_ANIM_LINEAR || type == SAA_ANIM_CARDINAL ) - { - MakeLinearMorphTable( scene, model, numShapes, name, time ); - } - else // must be weighted... - { - // check first for expressions - MakeExpressionMorphTable( scene, model, models, numModels, - numShapes, name, time ); - } - - } -} - - -/** - * Given a scene, a model, its name, and the time, get the shape fcurve for - * the model and determine the shape weights for the given time and use them - * to populate the morph table. - */ -void soft2egg:: -MakeLinearMorphTable( SAA_Scene *scene, SAA_Elem *model, int numShapes, - char *name, float time ) -{ - int i; - SAA_Elem fcurve; - float curveVal; - SAnimTable *thisTable; - char *tableName; - - if ( verbose >= 1 ) - fprintf( outStream, "linear interp, getting fcurve\n" ); - - SAA_modelFcurveGetShape( scene, model, &fcurve ); - - SAA_fcurveEval( scene, &fcurve, time, &curveVal ); - - if ( verbose >= 2 ) - fprintf( outStream, "at time %f, fcurve for %s = %f\n", time, - name, curveVal ); - - float nextVal = 0.0f; - - // populate morph table values for this frame - for ( i = 1; i < numShapes; i++ ) - { - // derive table name from the model name - tableName = MakeTableName( name, i ); - - if ( verbose >= 2 ) - fprintf( outStream, "Linear: looking for table '%s'\n", tableName ); - - // find the morph table associated with this key shape - thisTable = (SAnimTable *)(morphRoot->FindDescendent( tableName )); - - if ( thisTable != NULL ) - { - if ( i == (int)curveVal ) - { - if ( curveVal - i == 0 ) - { - thisTable->AddElement( 1.0f ); - if ( verbose >= 2 ) - fprintf( outStream, "adding element 1.0f\n" ); - } - else - { - thisTable->AddElement( 1.0f - (curveVal - i) ); - nextVal = curveVal - i; - if ( verbose >= 2 ) - fprintf( outStream, "adding element %f\n", 1.0f - (curveVal - i) ); - } - } - else - { - if ( nextVal ) - { - thisTable->AddElement( nextVal ); - nextVal = 0.0f; - if ( verbose >= 2 ) - fprintf( outStream, "adding element %f\n", nextVal ); - } - else - { - thisTable->AddElement( 0.0f ); - if ( verbose >= 2 ) - fprintf( outStream, "adding element 0.0f\n" ); - } - } - - if ( verbose >= 2 ) - fprintf( outStream, " to '%s'\n", tableName ); - } - else - fprintf( outStream, "%d: Couldn't find table '%s'\n", - i, tableName ); - } - -} - -/** - * Given a scene, a model, a list of all models in the scene, the number of - * models in the scece, the number of key shapes for this model, the name of - * the model and the current time, determine what method of controlling the - * shape weights is used and call the appropriate routine. - */ -void soft2egg:: -MakeWeightedMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, - int numModels, int numShapes, char *name, float time ) -{ - SI_Error result; - SAA_Elem *weightCurves; - float curveVal; - SAnimTable *thisTable; - char *tableName; - - // allocate array of weight curves (one for each shape) - weightCurves = ( SAA_Elem *)malloc( sizeof( SAA_Elem ) * numShapes ); - - result = SAA_modelFcurveGetShapeWeights( - scene, model, numShapes, weightCurves ); - - if ( result == SI_SUCCESS ) - { - for ( int i = 1; i < numShapes; i++ ) - { - SAA_fcurveEval( scene, &weightCurves[i], time, &curveVal ); - - // make sure soft gave us a - // reasonable number - if (!isNum(curveVal)) - curveVal = 0.0f; - - if ( verbose >= 2 ) - fprintf( outStream, "at time %f, weightCurve[%d] for %s = %f\n", time, i, name, curveVal ); - - - // derive table name from the model name - tableName = MakeTableName( name, i ); - - // find and populate shape - // table - if ( verbose >= 2 ) - fprintf( outStream, "Weight: looking for table '%s'\n", - tableName ); - - // find the morph table associated with this key shape - thisTable = (SAnimTable *)(morphRoot->FindDescendent( tableName )); - - if ( thisTable != NULL ) - { - thisTable->AddElement( curveVal ); - if ( verbose >= 2 ) - fprintf( outStream, "adding element %f\n", curveVal ); - } - else - fprintf( outStream, "%d: Couldn't find table '%s'\n", - i, tableName ); - } - } -} - - -/** - * Given a scene, a model and its number of key shapes generate a morph table - * describing transitions btwn the key shapes by evaluating the positions of - * the controlling sliders. - */ -void soft2egg:: -MakeExpressionMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, - int numModels, int numShapes, char *name, float time ) -{ - int j; - SAnimTable *thisTable; - char *tableName; - char *sliderName; - char *track; - int numExp; - SAA_Elem *expressions; - float expVal; - float sliderVal; - - // populate morph table values for this frame - - // compose track name - track = NULL; - - // find how many expressions for this shape - SAA_elementGetNbExpressions( scene, model, track, FALSE, &numExp ); - - if ( verbose >= 2 ) - fprintf( outStream, "%s has %d RHS expressions\n", name, numExp ); - - if ( numExp ) - { - // get the expressions for this shape - expressions = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numExp); - - if ( verbose >= 1 ) - fprintf( outStream, "getting %d RHS expressions...\n", numExp ); - - result = SAA_elementGetExpressions( scene, model, track, FALSE, - numExp, expressions ); - - if ( !result ) - { - for ( j = 1; j < numExp; j++ ) - { - if ( verbose >= 2 ) - { - // debug see what we got - int numvars; - - SAA_expressionGetNbVars( scene, &expressions[j], &numvars ); - - int *varnamelen; - int *varstrlen; - int expstrlen; - - varnamelen = (int *)malloc(sizeof(int)*numvars); - varstrlen = (int *)malloc(sizeof(int)*numvars); - - SAA_expressionGetStringLengths( scene, &expressions[j], - numvars, varnamelen, varstrlen, &expstrlen ); - - int *varnamesizes; - int *varstrsizes; - - varnamesizes = (int *)malloc(sizeof(int)*numvars); - varstrsizes = (int *)malloc(sizeof(int)*numvars); - - for ( int k = 0; k < numvars; k++ ) - { - varnamesizes[k] = varnamelen[k] + 1; - varstrsizes[k] = varstrlen[k] + 1; - } - - int expstrsize = expstrlen + 1; - - char **varnames; - char **varstrs; - - varnames = (char **)malloc(sizeof(char *)*numvars); - varstrs = (char **)malloc(sizeof(char *)*numvars); - - for ( k = 0; k < numvars; k++ ) - { - varnames[k] = (char *)malloc(sizeof(char)* - varnamesizes[k]); - - varstrs[k] = (char *)malloc(sizeof(char)* - varstrsizes[k]); - } - - char *expstr = (char *)malloc(sizeof(char)* expstrsize ); - - SAA_expressionGetStrings( scene, &expressions[j], numvars, - varnamesizes, varstrsizes, expstrsize, varnames, - varstrs, expstr ); - - if ( verbose >= 2 ) - { - fprintf( outStream, "expression = '%s'\n", expstr ); - fprintf( outStream, "has %d variables\n", numvars ); - } - } //if verbose - - if ( verbose >= 2 ) - fprintf( outStream, "evaling expression...\n" ); - - SAA_expressionEval( scene, &expressions[j], time, &expVal ); - - if ( verbose >= 2 ) - fprintf( outStream, "time %f: exp val %f\n", - time, expVal ); - - // derive table name from the model name - tableName = MakeTableName( name, j ); - - if ( verbose >= 2 ) - fprintf( outStream, "Exp: looking for table '%s'\n", - tableName ); - - // find the morph table associated with this key shape - thisTable = (SAnimTable *) - (morphRoot->FindDescendent( tableName )); - - if ( thisTable != NULL ) - { - thisTable->AddElement( expVal ); - if ( verbose >= 1 ) - fprintf( outStream, "%d: adding element %f to %s\n", - j, expVal, tableName ); - fflush( outStream ); - } - else - { - fprintf( outStream, "%d: Couldn't find table '%s'", j, - tableName ); - - fprintf( outStream, " for value %f\n", expVal ); - } - } - } - else - fprintf( outStream, "couldn't get expressions!!!\n" ); - } - else - // no expression, use weight curves - MakeWeightedMorphTable( scene, model, models, numModels, - numShapes, name, time ); - -} - - -/** - * Given a scene, a POLYGON model, and the name of the that model, get the u - * and v offsets for the current frame. - */ -void soft2egg:: -MakeTexAnim( SAA_Scene *scene, SAA_Elem *model, char *modelName ) -{ - if ( verbose >= 1 ) - fprintf( outStream, "\n\nmaking texture animation for %s...\n", - modelName ); - - // get the color of the surface - int numMats; - pfVec4 Color; - SAA_Elem *materials; - void *relinfo; - - SAA_modelRelationGetMatNbElements( scene, model, FALSE, &relinfo, - &numMats ); - - if ( verbose >= 2 ) - fprintf( outStream, "surface has %d materials\n", numMats ); - - if ( numMats ) - { - float r,g,b,a; - - materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numMats); - - SAA_modelRelationGetMatElements( scene, model, relinfo, - numMats, materials ); - - SAA_materialGetDiffuse( scene, &materials[0], &r, &g, &b ); - SAA_materialGetTransparency( scene, &materials[0], &a ); - Color.set( r, g, b, 1.0f - a ); - - int numTexLoc = 0; - int numTexGlb = 0; - - // ASSUME only one texture per material - SAA_Elem tex; - - // find out how many local textures per surface ASSUME it only has one - // material - SAA_materialRelationGetT2DLocNbElements( scene, &materials[0], - FALSE, &relinfo, &numTexLoc ); - - // if present, get local textures - if ( numTexLoc ) - { - if ( verbose >= 1 ) - fprintf( outStream, "%s had %d local tex\n", modelName, - numTexLoc ); - - // get the referenced texture - SAA_materialRelationGetT2DLocElements( scene, &materials[0], - TEX_PER_MAT, &tex ); - - } - // if no locals, try to get globals - else - { - SAA_modelRelationGetT2DGlbNbElements( scene, model, - FALSE, &relinfo, &numTexGlb ); - - if ( numTexGlb ) - { - if ( verbose >= 1 ) - fprintf( outStream, "%s had %d global tex\n", modelName, numTexGlb ); - - // get the referenced texture - SAA_modelRelationGetT2DGlbElements( scene, - model, TEX_PER_MAT, &tex ); - } - } - - // add tex ref's if we found any textures - if ( numTexLoc || numTexGlb) - { - char *fullTexName = NULL; - char *texName = NULL; - char *uniqueTexName = NULL; - int texNameLen; - - // get its name - SAA_texture2DGetPicNameLength( scene, &tex, &texNameLen); - fullTexName = (char *)malloc(sizeof(char)*++texNameLen); - SAA_texture2DGetPicName( scene, &tex, texNameLen, - fullTexName ); - - // append unique identifier to texname for this particular object - uniqueTexName = (char *)malloc(sizeof(char)* - (strlen(modelName)+strlen(texName)+3) ); - sprintf( uniqueTexName, "%s-%s", modelName, texName ); - if ( verbose >= 2 ) - fprintf( outStream, "referencing tref %s\n", - uniqueTexName ); - - float uScale; - float vScale; - float uOffset; - float vOffset; - SAA_Boolean uv_swap = FALSE; - - // get texture offset info - SAA_texture2DGetUScale( scene, &tex, &uScale ); - SAA_texture2DGetVScale( scene, &tex, &vScale ); - SAA_texture2DGetUOffset( scene, &tex, &uOffset ); - SAA_texture2DGetVOffset( scene, &tex, &vOffset ); - SAA_texture2DGetUVSwap( scene, &tex, &uv_swap ); - - - if ( verbose >= 2 ) - { - fprintf( outStream, "tex uScale: %f\n", uScale ); - fprintf( outStream, "tex vScale: %f\n", vScale ); - fprintf( outStream, "tex uOffset: %f\n", uOffset ); - fprintf( outStream, "tex vOffset: %f\n", vOffset ); - if ( uv_swap ) - fprintf( outStream, "nurbTex u & v swapped!\n" ); - else - fprintf( outStream, "nurbTex u & v NOT swapped\n" ); - } - - - // find the vpool for this model - EggVertexPool *vPool = - (EggVertexPool *)(_data.pools.FindName( modelName )); - - // if we found the pool - if ( vPool != NULL ) - { - // generate duv's for model - float oldOffsets[4]; - double u, v, du, dv; - int size; - SAA_Boolean bigEndian; - - SAA_elementGetUserDataSize( scene, model, "TEX_OFFSETS", &size ); - - if ( size != 0 ) - { - // remember original texture offsets future reference - SAA_elementGetUserData( scene, model, "TEX_OFFSETS", - size, &bigEndian, (void *)&oldOffsets ); - - // get the original scales and offsets - u = oldOffsets[0]; - v = oldOffsets[1]; - - du = u - uOffset; - dv = v - vOffset; - - if ( verbose >= 1 ) - { - fprintf( outStream, "original u = %f, v = %f\n", - u, v ); - fprintf( outStream, "u = %f, v = %f\n", - uOffset, vOffset ); - fprintf( outStream, "du = %f, dv = %f\n", - du, dv ); - } - - strstream uName, vName; - - // create duv target names - uName << modelName << ".u" << ends; - vName << modelName << ".v" << ends; - - // find the appropriate table to store the duv animation - // info into - SAnimTable *thisTable; - - // find the duv U table associated with this model - thisTable = (SAnimTable *)(morphRoot->FindDescendent( - uName.str() )); - - if ( thisTable != NULL ) - { - thisTable->AddElement( du ); - if ( verbose >= 1 ) - fprintf( outStream, "adding element %f to %s\n", - du, uName.str() ); - } - else - fprintf( outStream, "Couldn't find uTable %s\n", - uName.str() ); - - // find the duv V table associated with this model - thisTable = (SAnimTable *)(morphRoot->FindDescendent( - vName.str() )); - - if ( thisTable != NULL ) - { - thisTable->AddElement( dv ); - if ( verbose >= 1 ) - fprintf( outStream, "adding element %f to %s\n", - dv, uName.str() ); - } - else - fprintf( outStream, "Couldn't find vTable %s\n", - uName.str() ); - } - } - else - if ( verbose >= 2 ) - fprintf( outStream, "Couldn't find vpool %s\n", modelName ); - } - - // free( materials ); - } -} -#endif - -/** - * Instantiate converter and process a file - */ -EXPCL_MISC SI_Error soft2egg(int argc, char *argv[]) { - // pass control to the c++ system - init_soft2egg(argc, argv); - return SI_SUCCESS; -} -#ifdef __cplusplus -} -#endif diff --git a/pandatool/src/softegg/softEggGroupUserData.I b/pandatool/src/softegg/softEggGroupUserData.I deleted file mode 100644 index c6d2a5082c..0000000000 --- a/pandatool/src/softegg/softEggGroupUserData.I +++ /dev/null @@ -1,44 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softEggGroupUserData.I - * @author masad - * @date 2003-09-25 - */ - -/** - * - */ -INLINE SoftEggGroupUserData:: -SoftEggGroupUserData() { - _vertex_color = false; - _double_sided = false; -} - - -/** - * - */ -INLINE SoftEggGroupUserData:: -SoftEggGroupUserData(const SoftEggGroupUserData ©) : - EggUserData(copy), - _vertex_color(copy._vertex_color), - _double_sided(copy._double_sided) -{ -} - - -/** - * - */ -INLINE void SoftEggGroupUserData:: -operator = (const SoftEggGroupUserData ©) { - EggUserData::operator = (copy); - _vertex_color = copy._vertex_color; - _double_sided = copy._double_sided; -} diff --git a/pandatool/src/softegg/softEggGroupUserData.cxx b/pandatool/src/softegg/softEggGroupUserData.cxx deleted file mode 100644 index 1705b2b285..0000000000 --- a/pandatool/src/softegg/softEggGroupUserData.cxx +++ /dev/null @@ -1,16 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softEggGroupUserData.cxx - * @author masad - * @date 2003-09-25 - */ - -#include "softEggGroupUserData.h" - -TypeHandle SoftEggGroupUserData::_type_handle; diff --git a/pandatool/src/softegg/softEggGroupUserData.h b/pandatool/src/softegg/softEggGroupUserData.h deleted file mode 100644 index b8aa6ca892..0000000000 --- a/pandatool/src/softegg/softEggGroupUserData.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softEggGroupUserData.h - * @author masad - * @date 2003-09-25 - */ - -#ifndef SOFTEGGGROUPUSERDATA_H -#define SOFTEGGGROUPUSERDATA_H - -#include "pandatoolbase.h" -#include "eggUserData.h" - -/** - * This class contains extra user data which is piggybacked onto EggGroup - * objects for the purpose of the softimage converter. - */ -class SoftEggGroupUserData : public EggUserData { -public: - INLINE SoftEggGroupUserData(); - INLINE SoftEggGroupUserData(const SoftEggGroupUserData ©); - INLINE void operator = (const SoftEggGroupUserData ©); - - bool _vertex_color; - bool _double_sided; - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - EggUserData::init_type(); - register_type(_type_handle, "SoftEggGroupUserData", - EggUserData::get_class_type()); - } - virtual TypeHandle get_type() const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - -private: - static TypeHandle _type_handle; -}; - -#include "softEggGroupUserData.I" - -#endif diff --git a/pandatool/src/softegg/softNodeDesc.cxx b/pandatool/src/softegg/softNodeDesc.cxx deleted file mode 100644 index ff0f624a20..0000000000 --- a/pandatool/src/softegg/softNodeDesc.cxx +++ /dev/null @@ -1,1310 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softNodeDesc.cxx - * @author masad - * @date 2003-10-03 - */ - -#include "softNodeDesc.h" -#include "config_softegg.h" -#include "eggGroup.h" -#include "eggXfmSAnim.h" -#include "eggSAnimData.h" -#include "softToEggConverter.h" -#include "dcast.h" - -using std::endl; - -TypeHandle SoftNodeDesc::_type_handle; - -/** - * - */ -SoftNodeDesc:: -SoftNodeDesc(SoftNodeDesc *parent, const std::string &name) : - Namable(name), - _parent(parent) -{ - _model = nullptr; - _egg_group = nullptr; - _egg_table = nullptr; - _anim = nullptr; - _joint_type = JT_none; - - // Add ourselves to our parent. - if (_parent != nullptr) { - softegg_cat.spam() << "parent name " << _parent->get_name(); - _parent->_children.push_back(this); - } - - // set the _parentJoint to Null - _parentJoint = nullptr; - - fullname = nullptr; - - numTexLoc = 0; - numTexGlb = 0; - - uScale = nullptr; - vScale = nullptr; - uOffset = nullptr; - vOffset = nullptr; - - valid; - uv_swap; - // SAA_Boolean visible; - numTexTri = nullptr; - textures = nullptr; - materials = nullptr; - triangles = nullptr; - gtype = SAA_GEOM_ORIGINAL; -} - -/** - * - */ -SoftNodeDesc:: -~SoftNodeDesc() { - // I think it is a mistake to try to delete this. This was one member of an - // entire array allocated at once; you can't delete individual elements of - // an array. - - // Screw cleanup, anyway--we'll just let the array leak. - /* - if (_model != (SAA_Elem *)NULL) { - delete _model; - } - */ -} - -/** - * Indicates an associated between the SoftNodeDesc and some SAA_Elem - * instance. - */ -void SoftNodeDesc:: -set_model(SAA_Elem *model) { - _model = model; -} - -/** - * Sometimes, parent is not known at node creation As soon as it is known, set - * the parent - */ -void SoftNodeDesc:: -set_parent(SoftNodeDesc *parent) { - if (_parent) { - softegg_cat.spam() << endl; - /* - softegg_cat.spam() << " expected _parent to be null!?\n"; - if (_parent == parent) - softegg_cat.spam() << " parent already set\n"; - else { - softegg_cat.spam() << " current parent " << _parent->get_name() << " new parent " - << parent << endl; - } - */ - return; - } - _parent = parent; - softegg_cat.spam() << " set parent to " << _parent->get_name() << endl; - - // Add ourselves to our parent. - _parent->_children.push_back(this); -} - -/** - * Sometimes, parent is not known at node creation As soon as it is known, set - * the parent - */ -void SoftNodeDesc:: -force_set_parent(SoftNodeDesc *parent) { - if (_parent) - softegg_cat.spam() << " current parent " << _parent->get_name(); - - _parent = parent; - - if (_parent) - softegg_cat.spam() << " new parent " << _parent->get_name() << endl; - - // Add ourselves to our parent. - _parent->_children.push_back(this); -} - -/** - * Returns true if a Soft dag path has been associated with this node, false - * otherwise. - */ -bool SoftNodeDesc:: -has_model() const { - return (_model != nullptr); -} - -/** - * Returns the SAA_Elem * associated with this node. It is an error to call - * this unless has_model() returned true. - */ -SAA_Elem *SoftNodeDesc:: -get_model() const { - nassertr(_model != nullptr, _model); - return _model; -} - -/** - * Returns true if the node should be treated as a joint by the converter. - */ -bool SoftNodeDesc:: -is_joint() const { - // return _joint_type == JT_joint || _joint_type == JT_pseudo_joint; - return _joint_type == JT_joint; -} - -/** - * Returns true if the node should be treated as a junk by the converter. - */ -bool SoftNodeDesc:: -is_junk() const { - return _joint_type == JT_junk; -} - -/** - * sets the _joint_type to JT_joint - */ -void SoftNodeDesc:: -set_joint() { - _joint_type = JT_joint; -} -/** - * Returns true if the node is the parent or ancestor of a joint. - */ -bool SoftNodeDesc:: -is_joint_parent() const { - return _joint_type == JT_joint_parent; -} - -/** - * Recursively clears the egg pointers from this node and all children. - */ -void SoftNodeDesc:: -clear_egg() { - _egg_group = nullptr; - _egg_table = nullptr; - _anim = nullptr; - - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - child->clear_egg(); - } -} - -/** - * Indicates that this node has at least one child that is a joint or a - * pseudo-joint. - */ -void SoftNodeDesc:: -mark_joint_parent() { - if (_joint_type == JT_none) { - _joint_type = JT_joint_parent; - softegg_cat.spam() << " marked parent " << get_name(); - } - else - softegg_cat.spam() << " ?parent " << get_name() << " joint type " << _joint_type; - - if (_parent != nullptr) { - _parent->mark_joint_parent(); - } - softegg_cat.spam() << endl; -} - -/** - * Walks the hierarchy, if a node is joint, make sure all its parents are - * marked JT_joint_parent - */ -void SoftNodeDesc:: -check_joint_parent() { - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - if (child->is_joint()) { - softegg_cat.spam() << "child " << child->get_name(); - mark_joint_parent(); - } - child->check_joint_parent(); - } -} - -/** - * check to see if this is a branch we don't want to descend - this will - * prevent creating geometry for animation control structures - */ -void SoftNodeDesc:: -check_junk(bool parent_junk) { - const char *name = get_name().c_str(); - - if (parent_junk) { - _joint_type = JT_junk; - softegg_cat.spam() << "junk node " << get_name() << endl; - } - if ( (strstr(name, "con-") != nullptr) || - (strstr(name, "con_") != nullptr) || - (strstr(name, "fly_") != nullptr) || - (strstr(name, "fly-") != nullptr) || - (strstr(name, "camRIG") != nullptr) || - (strstr(name, "cam_rig") != nullptr) || - (strstr(name, "bars") != nullptr) ) - { - _joint_type = JT_junk; - softegg_cat.spam() << "junk node " << get_name() << endl; - parent_junk = true; - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - softegg_cat.spam() << child->get_name() << ","; - } - softegg_cat.spam() << endl; - } - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - child->check_junk(parent_junk); - } -} - -/** - * check to see if this is a selected branch we want to descend - this will - * prevent creating geometry for other parts - */ -bool SoftNodeDesc:: -is_partial(char *search_prefix) { - const char *name = fullname; - - // if no search prefix then return false - if (!search_prefix) - return false; - // if name is search_prefix, return false - if (strstr(name, search_prefix) != nullptr) { - softegg_cat.debug() << "matched " << name << " "; - return false; - } - // if name is not search_prefix, look in its parent - if (strstr(name, search_prefix) == nullptr) { - softegg_cat.debug() << "node " << name << " "; - if (_parent) - return _parent->is_partial(search_prefix); - } - // neither name nor its parent is search_prefix - return true; -} - -/** - * Go through the ancestors and figure out who is the immediate _parentJoint - * of this node - */ -void SoftNodeDesc:: -set_parentJoint(SAA_Scene *scene, SoftNodeDesc *lastJoint) { - if (is_junk()) - return; - // set its parent joint to the lastJoint - _parentJoint = lastJoint; - softegg_cat.spam() << get_name() << ": parent joint set to :" << lastJoint; - if (lastJoint) - softegg_cat.spam() << "(" << lastJoint->get_name() << ")"; - softegg_cat.spam() << endl; - - // is this node a joint? - SAA_Boolean isSkeleton = false; - if (has_model()) - SAA_modelIsSkeleton( scene, get_model(), &isSkeleton ); - - // if already a joint or name has "joint" in it - const char *name = get_name().c_str(); - if (is_joint() || isSkeleton || strstr(name, "joint") != nullptr) { - lastJoint = this; - } - if ( _parentJoint && strstr( _parentJoint->get_name().c_str(), "scale" ) != nullptr ) { - // make sure _parentJoint didn't have the name "joint" in it - if (strstr(_parentJoint->get_name().c_str(), "joint") == nullptr) { - _parentJoint = nullptr; - // _parentJoint = lastJoint = NULL; - softegg_cat.spam() << "scale joint flag set!\n"; - } - } - - // look in the children - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - child->set_parentJoint(scene, lastJoint); - } -} - -/** - * Walks the hierarchy, looking for non-joint nodes that are both children and - * parents of a joint. These nodes are deemed to be pseudo joints, since the - * converter must treat them as joints. - */ -void SoftNodeDesc:: -check_pseudo_joints(bool joint_above) { - if (_joint_type == JT_joint_parent && joint_above) { - // This is one such node: it is the parent of a joint (JT_joint_parent is - // set), and it is the child of a joint (joint_above is set). - _joint_type = JT_pseudo_joint; - softegg_cat.debug() << "pseudo " << get_name() << " case1\n"; - } - - if (_joint_type == JT_joint) { - // If this node is itself a joint, then joint_above is true for all child - // nodes. - joint_above = true; - } - - // Don't bother traversing further if _joint_type is none or junk, since - // that means this node has no joint children. - if (_joint_type != JT_none && _joint_type != JT_junk) { - - bool any_joints = false; - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - child->check_pseudo_joints(joint_above); - if (child->is_joint()) { - softegg_cat.spam() << get_name() << " any_joint true by " << child->get_name() << endl; - any_joints = true; - } - } - - // If any children qualify as joints, then any sibling nodes that are - // parents of joints are also elevated to joints. - if (any_joints) { - bool all_joints = true; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - if (child->_joint_type == JT_joint_parent) { - child->_joint_type = JT_pseudo_joint; - softegg_cat.debug() << "pseudo " << child->get_name() << " case2 by parent " << get_name() << "\n"; - } else if (child->_joint_type == JT_none || child->_joint_type == JT_junk) { - all_joints = false; - } - } - - if (all_joints || any_joints) { - // Finally, if all children or at least one is a joint, then we are - // too. - if (_joint_type == JT_joint_parent) { - _joint_type = JT_pseudo_joint; - softegg_cat.debug() << "pseudo " << get_name() << " case3\n"; - } - } - } - } - else - softegg_cat.spam() << "found null joint " << get_name() << endl; -} - -/** - * Extracts the transform on the indicated Soft node, and applies it to the - * corresponding Egg node. - */ -void SoftNodeDesc:: -get_transform(SAA_Scene *scene, EggGroup *egg_group, bool global) { - // Get the model's matrix - int scale_joint = 0; - - if (!global && _parentJoint && !stec.flatten && !scale_joint) { - - SAA_modelGetMatrix( scene, get_model(), SAA_COORDSYS_LOCAL, matrix ); - softegg_cat.debug() << get_name() << " using local matrix :parent "; - - } else { - - SAA_modelGetMatrix( scene, get_model(), SAA_COORDSYS_GLOBAL, matrix ); - softegg_cat.debug() << get_name() << " using global matrix :parent "; - - } - - if (_parentJoint && !stec.flatten) - softegg_cat.debug() << _parentJoint->get_name() << endl; - else - softegg_cat.debug() << _parentJoint << endl; - - - softegg_cat.spam() << "model matrix = " << matrix[0][0] << " " << matrix[0][1] << " " << matrix[0][2] << " " << matrix[0][3] << "\n"; - softegg_cat.spam() << "model matrix = " << matrix[1][0] << " " << matrix[1][1] << " " << matrix[1][2] << " " << matrix[1][3] << "\n"; - softegg_cat.spam() << "model matrix = " << matrix[2][0] << " " << matrix[2][1] << " " << matrix[2][2] << " " << matrix[2][3] << "\n"; - softegg_cat.spam() << "model matrix = " << matrix[3][0] << " " << matrix[3][1] << " " << matrix[3][2] << " " << matrix[3][3] << "\n"; - - if (!global && is_joint()) { - LMatrix4d m4d(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3], - matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3], - matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3], - matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]); - if (!m4d.almost_equal(LMatrix4d::ident_mat(), 0.0001)) { - egg_group->set_transform3d(m4d); - softegg_cat.spam() << "set transform in egg_group\n"; - } - } - return; -} - -/** - * Extracts the transform on the indicated Soft node, as appropriate for a - * joint in an animated character, and applies it to the indicated node. This - * is different from get_transform() in that it does not respect the - * _transform_type flag, and it does not consider the relative transforms - * within the egg file. more added functionality: now fills in components of - * anim (EffXfmSAnim) class (masad). - */ -void SoftNodeDesc:: -get_joint_transform(SAA_Scene *scene, EggGroup *egg_group, EggXfmSAnim *anim, bool global) { - // SI_Error result; - SAA_Elem *skeletonPart = _model; - const char *name = get_name().c_str(); - - if ( skeletonPart != nullptr ) { - PN_stdfloat i,j,k; - PN_stdfloat h,p,r; - PN_stdfloat x,y,z; - int scale_joint = 0; - - softegg_cat.spam() << "\n\nanimating child " << name << endl; - - if (_parentJoint && !stec.flatten && !scale_joint ) { - softegg_cat.debug() << "using local matrix\n"; - - // get SAA orientation - SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_LOCAL, - &p, &h, &r ); - - // get SAA translation - SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_LOCAL, - &x, &y, &z ); - - // get SAA scaling - SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_LOCAL, - &i, &j, &k ); - } else { - softegg_cat.debug() << " using global matrix\n"; - - // get SAA orientation - SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_GLOBAL, - &p, &h, &r ); - - // get SAA translation - SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_GLOBAL, - &x, &y, &z ); - - // get SAA scaling - SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_GLOBAL, - &i, &j, &k ); - } - - softegg_cat.spam() << "\nanim data: " << i << " " << j << " " << k << endl; - softegg_cat.spam() << "\t" << p << " " << h << " " << r << endl; - softegg_cat.spam() << "\t" << x << " " << y << " " << z << endl; - - // Encode the component multiplication ordering in the egg file. - // SoftImage always uses this order, regardless of the setting of temp- - // hpr-fix. - anim->set_order("sphrt"); - - // Add each component by their names - anim->add_component_data("i", i); - anim->add_component_data("j", j); - anim->add_component_data("k", k); - anim->add_component_data("p", p); - anim->add_component_data("h", h); - anim->add_component_data("r", r); - anim->add_component_data("x", x); - anim->add_component_data("y", y); - anim->add_component_data("z", z); - } - else { - softegg_cat.debug() << "Cannot build anim table - no skeleton\n"; - } -} - -/** - * Converts the indicated Soft polyset to a bunch of EggPolygons and parents - * them to the indicated egg group. - */ -void SoftNodeDesc:: -load_poly_model(SAA_Scene *scene, SAA_ModelType type) { - SI_Error result; - const char *name = get_name().c_str(); - - int i; - int id = 0; - - // if making a pose - get deformed geometry - if ( stec.make_pose ) - gtype = SAA_GEOM_DEFORMED; - - // If the model is a PATCH in soft, set its step before tesselating - else if ( type == SAA_MPTCH ) - SAA_patchSetStep( scene, _model, stec.nurbs_step, stec.nurbs_step ); - - // Get the number of triangles - result = SAA_modelGetNbTriangles( scene, _model, gtype, id, &numTri); - softegg_cat.spam() << "triangles: " << numTri << "\n"; - - if ( result != SI_SUCCESS ) { - softegg_cat.spam() << "Error: couldn't get number of triangles!\n"; - softegg_cat.debug() << "\tbailing on model: " << name << "\n"; - return; - } - - // check to see if surface is also skeleton... - SAA_Boolean isSkeleton = FALSE; - - SAA_modelIsSkeleton( scene, _model, &isSkeleton ); - - // check to see if this surface is used as a skeleton or is animated via - // constraint only ( these nodes are tagged by the animator with the keyword - // "joint" somewhere in the nodes name) - softegg_cat.spam() << "is Skeleton? " << isSkeleton << "\n"; - - /*************************************************************************************/ - - // model is not a null and has no triangles! - if ( !numTri ) { - softegg_cat.spam() << "no triangles!\n"; - } - else { - // allocate array of triangles - triangles = (SAA_SubElem *) new SAA_SubElem[numTri]; - if (!triangles) { - softegg_cat.info() << "Not enough Memory for triangles...\n"; - exit(1); - } - // triangulate model and read the triangles into array - SAA_modelGetTriangles( scene, _model, gtype, id, numTri, triangles ); - softegg_cat.spam() << "got triangles\n"; - - /***********************************************************************************/ - - // allocate array of materials (Asad: it gives a warning if try to get one - // triangle at a time...investigate later read each triangle's material - // into array - materials = (SAA_Elem*) new SAA_Elem[numTri]; - SAA_triangleGetMaterials( scene, _model, numTri, triangles, materials ); - if (!materials) { - softegg_cat.info() << "Not enough Memory for materials...\n"; - exit(1); - } - softegg_cat.spam() << "got materials\n"; - - /***********************************************************************************/ - - // allocate array of textures per triangle - numTexTri = new int[numTri]; - const void *relinfo; - - // find out how many local textures per triangle - for (i = 0; i < numTri; i++) { - result = SAA_materialRelationGetT2DLocNbElements( scene, &materials[i], FALSE, - &relinfo, &numTexTri[i] ); - // polytex - if ( result == SI_SUCCESS ) - numTexLoc += numTexTri[i]; - } - - // don't need this anymore... free( numTexTri ); - - // get local textures if present - if ( numTexLoc ) { - softegg_cat.spam() << "numTexLoc = " << numTexLoc << endl; - - // allocate arrays of texture info - uScale = new PN_stdfloat[numTri]; - vScale = new PN_stdfloat[numTri]; - uOffset = new PN_stdfloat[numTri]; - vOffset = new PN_stdfloat[numTri]; - texNameArray = new char *[numTri]; - uRepeat = new int[numTri]; - vRepeat = new int[numTri]; - - // ASSUME only one texture per material - textures = new SAA_Elem[numTri]; - - for ( i = 0; i < numTri; i++ ) { - // and read all referenced local textures into array - SAA_materialRelationGetT2DLocElements( scene, &materials[i], - TEX_PER_MAT , &textures[i] ); - - // initialize the array value - texNameArray[i] = nullptr; - // initialize the repeats - uRepeat[i] = vRepeat[i] = 0; - - // see if this triangle has texture info - if (numTexTri[i] == 0) - continue; - - // check to see if texture is present - result = SAA_elementIsValid( scene, &textures[i], &valid ); - - if ( result != SI_SUCCESS ) - softegg_cat.spam() << "SAA_elementIsValid failed!!!!\n"; - - // texture present - get the name and uv info - if ( valid ) { - // according to drose, we don't need to convert .pic files to .rgb, - // panda can now read the .pic files. - texNameArray[i] = stec.GetTextureName(scene, &textures[i]); - - softegg_cat.spam() << " tritex[" << i << "] named: " << texNameArray[i] << endl; - - SAA_texture2DGetUVSwap( scene, &textures[i], &uv_swap ); - - if ( uv_swap == TRUE ) - softegg_cat.spam() << " swapping u and v...\n" ; - - SAA_texture2DGetUScale( scene, &textures[i], &uScale[i] ); - SAA_texture2DGetVScale( scene, &textures[i], &vScale[i] ); - SAA_texture2DGetUOffset( scene, &textures[i], &uOffset[i] ); - SAA_texture2DGetVOffset( scene, &textures[i], &vOffset[i] ); - - softegg_cat.spam() << "tritex[" << i << "] uScale: " << uScale[i] << " vScale: " << vScale[i] << endl; - softegg_cat.spam() << " uOffset: " << uOffset[i] << " vOffset: " << vOffset[i] << endl; - - SAA_texture2DGetRepeats( scene, &textures[i], &uRepeat[i], &vRepeat[i] ); - softegg_cat.spam() << "uRepeat = " << uRepeat[i] << ", vRepeat = " << vRepeat[i] << endl; - } - else { - softegg_cat.spam() << "Invalid texture...\n"; - softegg_cat.spam() << " tritex[" << i << "] named: (null)\n"; - } - } - } - else { // if no local textures, try to get global textures - SAA_modelRelationGetT2DGlbNbElements( scene, _model, - FALSE, &relinfo, &numTexGlb ); - if ( numTexGlb ) { - // ASSUME only one texture per model - textures = new SAA_Elem; - // get the referenced texture - SAA_modelRelationGetT2DGlbElements( scene, _model, - TEX_PER_MAT, textures ); - softegg_cat.spam() << "numTexGlb = " << numTexGlb << endl; - // check to see if texture is present - SAA_elementIsValid( scene, textures, &valid ); - if ( valid ) { // texture present - get the name and uv info - SAA_texture2DGetUVSwap( scene, textures, &uv_swap ); - - if ( uv_swap == TRUE ) - softegg_cat.spam() << " swapping u and v...\n"; - - // according to drose, we don't need to convert .pic files to .rgb, - // panda can now read the .pic files. - texNameArray = new char *[1]; - *texNameArray = stec.GetTextureName(scene, textures); - - uRepeat = new int; - vRepeat = new int; - - softegg_cat.spam() << " global tex named: " << *texNameArray << endl; - - // allocate arrays of texture info - uScale = new PN_stdfloat; - vScale = new PN_stdfloat; - uOffset = new PN_stdfloat; - vOffset = new PN_stdfloat; - - SAA_texture2DGetUScale( scene, textures, uScale ); - SAA_texture2DGetVScale( scene, textures, vScale ); - SAA_texture2DGetUOffset( scene, textures, uOffset ); - SAA_texture2DGetVOffset( scene, textures, vOffset ); - - softegg_cat.spam() << " global tex uScale: " << *uScale << " vScale: " << *vScale << endl; - softegg_cat.spam() << " uOffset: " << *uOffset << " vOffset: " << *vOffset << endl; - - SAA_texture2DGetRepeats( scene, textures, uRepeat, vRepeat ); - softegg_cat.spam() << "uRepeat = " << *uRepeat << ", vRepeat = " << *vRepeat << endl; - } - else { - softegg_cat.spam() << "Invalid Texture...\n"; - } - } - } - } - softegg_cat.spam() << "got textures" << endl; -} - -/** - * Converts the indicated Soft polyset to a bunch of EggPolygons and parents - * them to the indicated egg group. - */ -void SoftNodeDesc:: -load_nurbs_model(SAA_Scene *scene, SAA_ModelType type) { - SI_Error result; - const char *name = get_name().c_str(); - - // if making a pose - get deformed geometry - if ( stec.make_pose ) - gtype = SAA_GEOM_DEFORMED; - - // If the model is a NURBS in soft, set its step before tesselating - if ( type == SAA_MNSRF ) - SAA_nurbsSurfaceSetStep( scene, _model, stec.nurbs_step, stec.nurbs_step ); - - // get the materials - /***********************************************************************************/ - const void *relinfo; - - SAA_modelRelationGetMatNbElements( scene, get_model(), FALSE, &relinfo, - &numNurbMats ); - - softegg_cat.spam() << "nurbs surf has " << numNurbMats << " materials\n"; - - if ( numNurbMats ) { - materials = new SAA_Elem[numNurbMats]; - if (!materials) { - softegg_cat.info() << "Out Of Memory on allocating materials\n"; - exit(1); - } - - SAA_modelRelationGetMatElements( scene, get_model(), relinfo, - numNurbMats, materials ); - - softegg_cat.spam() << "got materials\n"; - - // get the textures - /***********************************************************************************/ - numNurbTexLoc = 0; - numNurbTexGlb = 0; - - // find out how many local textures per NURBS surface ASSUME it only has - // one material - SAA_materialRelationGetT2DLocNbElements( scene, &materials[0], FALSE, &relinfo, &numNurbTexLoc ); - - // if present, get local textures - if ( numNurbTexLoc ) { - softegg_cat.spam() << name << " had " << numNurbTexLoc << " local tex\n"; - nassertv(numNurbTexLoc == 1); - - textures = new SAA_Elem[numNurbTexLoc]; - - // get the referenced texture - SAA_materialRelationGetT2DLocElements( scene, &materials[0], TEX_PER_MAT, &textures[0] ); - - } - // if no locals, try to get globals - else { - SAA_modelRelationGetT2DGlbNbElements( scene, get_model(), FALSE, &relinfo, &numNurbTexGlb ); - - if ( numNurbTexGlb ) { - softegg_cat.spam() << name << " had " << numNurbTexGlb << " global tex\n"; - nassertv(numNurbTexGlb == 1); - - textures = new SAA_Elem[numNurbTexGlb]; - - // get the referenced texture - SAA_modelRelationGetT2DGlbElements( scene, get_model(), TEX_PER_MAT, &textures[0] ); - } - } - - if ( numNurbTexLoc || numNurbTexGlb) { - - // allocate the texture name array - texNameArray = new char *[1]; - // allocate arrays of texture info - uScale = new PN_stdfloat; - vScale = new PN_stdfloat; - uOffset = new PN_stdfloat; - vOffset = new PN_stdfloat; - uRepeat = new int; - vRepeat = new int; - - // check to see if texture is present - result = SAA_elementIsValid( scene, &textures[0], &valid ); - - if ( result != SI_SUCCESS ) - softegg_cat.spam() << "SAA_elementIsValid failed!!!!\n"; - - // texture present - get the name and uv info - if ( valid ) { - // according to drose, we don't need to convert .pic files to .rgb, - // panda can now read the .pic files. - texNameArray[0] = stec.GetTextureName(scene, &textures[0]); - - softegg_cat.spam() << " tritex[0] named: " << texNameArray[0] << endl; - - SAA_texture2DGetUVSwap( scene, &textures[0], &uv_swap ); - - if ( uv_swap == TRUE ) - softegg_cat.spam() << " swapping u and v...\n" ; - - SAA_texture2DGetUScale( scene, &textures[0], uScale ); - SAA_texture2DGetVScale( scene, &textures[0], vScale ); - SAA_texture2DGetUOffset( scene, &textures[0], uOffset ); - SAA_texture2DGetVOffset( scene, &textures[0], vOffset ); - - softegg_cat.spam() << "tritex[0] uScale: " << *uScale << " vScale: " << *vScale << endl; - softegg_cat.spam() << " uOffset: " << *uOffset << " vOffset: " << *vOffset << endl; - - SAA_texture2DGetRepeats( scene, &textures[0], uRepeat, vRepeat ); - softegg_cat.spam() << "uRepeat = " << *uRepeat << ", vRepeat = " << *vRepeat << endl; - } - else { - softegg_cat.spam() << "Invalid texture...\n"; - softegg_cat.spam() << " tritex[0] named: (null)\n"; - } - } - - softegg_cat.spam() << "got textures\n"; - } -} - -/** - * given a vertex, find its corresponding shape vertex and return its index. - */ -int SoftNodeDesc:: -find_shape_vert(LPoint3d p3d, SAA_DVector *vertices, int numVert) { - int i, found = 0; - - for (i = 0; i < numVert && !found ; i++) { - if ((p3d[0] == vertices[i].x) && - (p3d[1] == vertices[i].y) && - (p3d[2] == vertices[i].z)) { - found = 1; - softegg_cat.spam() << "found shape vert at index " << i << endl; - } - } - - if (!found ) - i = -1; - else - i--; - - return i; -} - -/** - * Given a scene, a model , the vertices of its original shape and its name - * find the difference between the geometry of its key shapes and the models - * original geometry and add morph vertices to the egg data to reflect these - * changes. - */ -void SoftNodeDesc:: -make_vertex_offsets(int numShapes) { - int i, j; - int offset; - int numCV; - char tableName[_MAX_PATH]; - SAA_DVector *shapeVerts = nullptr; - SAA_DVector *uniqueVerts = nullptr; - SAA_Elem *model = get_model(); - SAA_Scene *scene = &stec.scene; - - EggVertexPool *vpool = nullptr; - std::string vpool_name = get_name() + ".verts"; - EggNode *t = stec._tree.get_egg_root()->find_child(vpool_name); - if (t) - DCAST_INTO_V(vpool, t); - - int numOrigVert = (int) vpool->size(); - EggVertexPool::iterator vi; - - if ((type == SAA_MNSRF) && stec.make_nurbs) - SAA_nurbsSurfaceSetStep( scene, model, stec.nurbs_step, stec.nurbs_step ); - - SAA_modelGetNbVertices( scene, model, &numCV ); - - // get the shape verts - uniqueVerts = new SAA_DVector[numCV]; - SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0, - numCV, uniqueVerts ); - - softegg_cat.spam() << numCV << " CV's\n"; - - for ( i = 0; i < numCV; i++ ) - // convert vertices to global - _VCT_X_MAT( uniqueVerts[i], uniqueVerts[i], matrix); - softegg_cat.spam() << "uniqueVerts[" << i << "] = " << uniqueVerts[i].x << " " << uniqueVerts[i].y - << " " << uniqueVerts[i].z << " " << uniqueVerts[i].w << endl; - - // iterate through for each key shape (except original) - for ( i = 1; i < numShapes; i++ ) { - - sprintf(tableName, "%s.%d", get_name().c_str(), i); - - softegg_cat.spam() << "\nMaking geometry offsets for " << tableName << "...\n"; - - if ((type == SAA_MNSRF) && stec.make_nurbs) - softegg_cat.spam() << "calculating NURBS morphs...\n"; - else - softegg_cat.spam() << "calculating triangle morphs...\n"; - - // get the shape verts - shapeVerts = new SAA_DVector[numCV]; - SAA_modelGetVertices( scene, model, SAA_GEOM_SHAPE, i+1, numCV, shapeVerts ); - - for ( j=0; j < numCV; j++ ) { - // convert vertices to global - _VCT_X_MAT( shapeVerts[j], shapeVerts[j], matrix); - - softegg_cat.spam() << "shapeVerts[" << j << "] = " << shapeVerts[j].x << " " - << shapeVerts[j].y << " " << shapeVerts[j].z << endl; - } - softegg_cat.spam() << endl; - - // for every original vertex, compare to the corresponding key shape - // vertex and see if a vertex offset is needed - j = 0; - for (vi = vpool->begin(); vi != vpool->end(); ++vi, ++j) { - - double dx, dy, dz; - EggVertex *vert = (*vi); - LPoint3d p3d = vert->get_pos3(); - - softegg_cat.spam() << "oVert[" << j << "] = " << p3d[0] << " " << p3d[1] << " " << p3d[2] << endl; - if ((type == SAA_MNSRF) && stec.make_nurbs) { - dx = shapeVerts[j].x - p3d[0]; - dy = shapeVerts[j].y - p3d[1]; - dz = shapeVerts[j].z - p3d[2]; - - softegg_cat.spam() << "global shapeVerts[" << j << "] = " << shapeVerts[j].x << " " - << shapeVerts[j].y << " " << shapeVerts[j].z << " " << shapeVerts[j].w << endl; - } - else { - // we need to map from original vertices to triangle shape vertices - // here - offset = find_shape_vert(p3d, uniqueVerts, numCV); - - dx = shapeVerts[offset].x - p3d[0]; - dy = shapeVerts[offset].y - p3d[1]; - dz = shapeVerts[offset].z - p3d[2]; - - softegg_cat.spam() << "global shapeVerts[" << offset << "] = " << shapeVerts[offset].x << " " - << shapeVerts[offset].y << " " << shapeVerts[offset].z << endl; - } - - softegg_cat.spam() << j << ": dx = " << dx << ", dy = " << dy << ", dz = " << dz << endl; - - // if change isn't negligible, make a morph vertex entry - double total = fabs(dx)+fabs(dy)+fabs(dz); - if ( total > 0.00001 ) { - if ( vpool != nullptr ) { - // create offset - LVector3d p(dx, dy, dz); - EggMorphVertex *dxyz = new EggMorphVertex(tableName, p); - // add the offset to the vertex - vert->_dxyzs.insert(*dxyz); - } - else - softegg_cat.spam() << "Error: couldn't find vertex pool " << vpool_name << endl; - - } // if total - } //for j - } //for i -} - -/** - * Given a scene, a model, a name and a frame time, determine what type of - * shape interpolation is used and call the appropriate function to extract - * the shape weight info for this frame... - */ -void SoftNodeDesc:: -make_morph_table( PN_stdfloat time ) { - int numShapes; - SAA_Elem *model = nullptr; - SAA_AnimInterpType type; - SAA_Scene *scene = &stec.scene; - - if (has_model()) - model = get_model(); - else - return; - - // Get the number of key shapes - SAA_modelGetNbShapes( scene, model, &numShapes ); - - if ( numShapes <= 0 ) { - return; - } - - stec.has_morph = true; - - softegg_cat.spam() << "make_morph_table: " << get_name() << " : num shapes: " << numShapes << endl; - - SAA_modelGetShapeInterpolation( scene, model, &type ); - - if ( type == SAA_ANIM_LINEAR || type == SAA_ANIM_CARDINAL ) { - softegg_cat.spam() << "linear morph" << endl; - make_linear_morph_table( numShapes, time ); - } - else { // must be weighted... - // check first for expressions - softegg_cat.spam() << "expression morph" << endl; - make_expression_morph_table( numShapes, time ); - } -} - -/** - * Given a scene, a model, its name, and the time, get the shape fcurve for - * the model and determine the shape weights for the given time and use them - * to populate the morph table. - */ -void SoftNodeDesc:: -make_linear_morph_table(int numShapes, PN_stdfloat time) { - int i; - PN_stdfloat curveVal; - char tableName[_MAX_PATH]; - SAA_Elem fcurve; - // SAnimTable *thisTable; - EggSAnimData *anim; - SAA_Elem *model = get_model(); - SAA_Scene *scene = &stec.scene; - - softegg_cat.spam() << "linear interp, getting fcurve\n"; - - SAA_modelFcurveGetShape( scene, model, &fcurve ); - - SAA_fcurveEval( scene, &fcurve, time, &curveVal ); - - softegg_cat.spam() << "at time " << time << ", fcurve for " << get_name() << " = " << curveVal << endl; - - PN_stdfloat nextVal = 0.0f; - - // populate morph table values for this frame - for ( i = 1; i < numShapes; i++ ) { - // derive table name from the model name - sprintf(tableName, "%s.%d", get_name().c_str(), i); - - softegg_cat.spam() << "Linear: looking for table '" << tableName << "'\n"; - - // find the morph table associated with this key shape - anim = stec.find_morph_table(tableName); - - if ( anim != nullptr ) { - if ( i == (int)curveVal ) { - if ( curveVal - i == 0 ) { - anim->add_data(1.0f ); - softegg_cat.spam() << "adding element 1.0f\n"; - } - else { - anim->add_data(1.0f - (curveVal - i)); - nextVal = curveVal - i; - softegg_cat.spam() << "adding element " << 1.0f - (curveVal - i) << endl; - } - } - else { - if ( nextVal ) { - anim->add_data(nextVal ); - nextVal = 0.0f; - softegg_cat.spam() << "adding element " << nextVal << endl; - } - else { - anim->add_data(0.0f); - softegg_cat.spam() << "adding element 0.0f\n"; - } - } - - softegg_cat.spam() <<" to '" << tableName << "'\n"; - } - else - softegg_cat.spam() << i << " : Couldn't find table '" << tableName << "'\n"; - } -} - -/** - * Given a scene, a model, a list of all models in the scene, the number of - * models in the scece, the number of key shapes for this model, the name of - * the model and the current time, determine what method of controlling the - * shape weights is used and call the appropriate routine. - */ -void SoftNodeDesc:: -make_weighted_morph_table(int numShapes, PN_stdfloat time) { - PN_stdfloat curveVal; - SI_Error result; - char tableName[_MAX_PATH]; - SAA_Elem *weightCurves; - // SAnimTable *thisTable; - EggSAnimData *anim; - SAA_Elem *model = get_model(); - SAA_Scene *scene = &stec.scene; - - // allocate array of weight curves (one for each shape) - weightCurves = new SAA_Elem[numShapes]; - - result = SAA_modelFcurveGetShapeWeights(scene, model, numShapes, weightCurves); - - if ( result == SI_SUCCESS ) { - for ( int i = 1; i < numShapes; i++ ) { - SAA_fcurveEval( scene, &weightCurves[i], time, &curveVal ); - - // make sure soft gave us a reasonable number if (!isNum(curveVal)) - // curveVal = 0.0f; - - softegg_cat.spam() << "at time " << time << ", weightCurve[" << i << "] for " << get_name() << " = " << curveVal << endl; - - // derive table name from the model name - sprintf(tableName, "%s.%d", get_name().c_str(), i); - - // find and populate shape table - softegg_cat.spam() << "Weight: looking for table '" << tableName << "'\n"; - - // find the morph table associated with this key shape - anim = stec.find_morph_table(tableName); - - if ( anim != nullptr ) { - anim->add_data(curveVal); - softegg_cat.spam() << "adding element " << curveVal << endl; - } - else - softegg_cat.spam() << i << " : Couldn't find table '" << tableName << "'\n"; - } - } -} - -/** - * Given a scene, a model and its number of key shapes generate a morph table - * describing transitions btwn the key shapes by evaluating the positions of - * the controlling sliders. - */ -void SoftNodeDesc:: -make_expression_morph_table(int numShapes, PN_stdfloat time) -{ - // int j; - int numExp; - char *track; - // PN_stdfloat expVal; PN_stdfloat sliderVal; char *tableName; char - // *sliderName; SAnimTable *thisTable; - SAA_Elem *expressions; - SI_Error result; - - SAA_Elem *model = get_model(); - SAA_Scene *scene = &stec.scene; - - // populate morph table values for this frame - - // compose track name - track = nullptr; - - // find how many expressions for this shape - SAA_elementGetNbExpressions( scene, model, track, FALSE, &numExp ); - - softegg_cat.spam() << get_name() << " has " << numExp << " RHS expressions\n"; - - if ( numExp ) { - // get the expressions for this shape - expressions = new SAA_Elem[numExp]; - softegg_cat.spam() << "getting " << numExp << " RHS expressions...\n"; - - result = SAA_elementGetExpressions( scene, model, track, FALSE, - numExp, expressions ); - /* - if ( !result ) { - for ( j = 1; j < numExp; j++ ) { - if ( verbose >= 2 ) - { - // debug see what we got - int numvars; - - SAA_expressionGetNbVars( scene, &expressions[j], &numvars ); - - int *varnamelen; - int *varstrlen; - int expstrlen; - - varnamelen = (int *)malloc(sizeof(int)*numvars); - varstrlen = (int *)malloc(sizeof(int)*numvars); - - SAA_expressionGetStringLengths( scene, &expressions[j], - numvars, varnamelen, varstrlen, &expstrlen ); - - int *varnamesizes; - int *varstrsizes; - - varnamesizes = (int *)malloc(sizeof(int)*numvars); - varstrsizes = (int *)malloc(sizeof(int)*numvars); - - for ( int k = 0; k < numvars; k++ ) - { - varnamesizes[k] = varnamelen[k] + 1; - varstrsizes[k] = varstrlen[k] + 1; - } - - int expstrsize = expstrlen + 1; - - char **varnames; - char **varstrs; - - varnames = (char **)malloc(sizeof(char *)*numvars); - varstrs = (char **)malloc(sizeof(char *)*numvars); - - for ( k = 0; k < numvars; k++ ) - { - varnames[k] = (char *)malloc(sizeof(char)* - varnamesizes[k]); - - varstrs[k] = (char *)malloc(sizeof(char)* - varstrsizes[k]); - } - - char *expstr = (char *)malloc(sizeof(char)* expstrsize ); - - SAA_expressionGetStrings( scene, &expressions[j], numvars, - varnamesizes, varstrsizes, expstrsize, varnames, - varstrs, expstr ); - - if ( verbose >= 2 ) - { - fprintf( outStream, "expression = '%s'\n", expstr ); - fprintf( outStream, "has %d variables\n", numvars ); - } - } //if verbose - - if ( verbose >= 2 ) - fprintf( outStream, "evaling expression...\n" ); - - SAA_expressionEval( scene, &expressions[j], time, &expVal ); - - if ( verbose >= 2 ) - fprintf( outStream, "time %f: exp val %f\n", - time, expVal ); - - // derive table name from the model name - tableName = MakeTableName( name, j ); - - if ( verbose >= 2 ) - fprintf( outStream, "Exp: looking for table '%s'\n", - tableName ); - - // find the morph table associated with this key shape - anim = (SAnimTable *) - (morphRoot->FindDescendent( tableName )); - - if ( anim != NULL ) - { - anim->AddElement( expVal ); - if ( verbose >= 1 ) - fprintf( outStream, "%d: adding element %f to %s\n", - j, expVal, tableName ); - fflush( outStream ); - } - else - { - fprintf( outStream, "%d: Couldn't find table '%s'", j, - tableName ); - - fprintf( outStream, " for value %f\n", expVal ); - } - } - } - else - fprintf( outStream, "couldn't get expressions!!!\n" ); - */ - } - else { - softegg_cat.spam() << "weighted morph" << endl; - // no expression, use weight curves - make_weighted_morph_table(numShapes, time ); - } -} diff --git a/pandatool/src/softegg/softNodeDesc.h b/pandatool/src/softegg/softNodeDesc.h deleted file mode 100644 index c6512b7dda..0000000000 --- a/pandatool/src/softegg/softNodeDesc.h +++ /dev/null @@ -1,159 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softNodeDesc.h - * @author masad - * @date 2003-10-03 - */ - -#ifndef SOFTNODEDESC_H -#define SOFTNODEDESC_H - -#ifdef _MIN -#undef _MIN -#endif -#ifdef _MAX -#undef _MAX -#endif - -#include "pandatoolbase.h" - -#include "eggVertex.h" -#include "eggVertexPool.h" -#include "referenceCount.h" -#include "pointerTo.h" -#include "namable.h" - -#include - -class EggGroup; -class EggTable; -class EggXfmSAnim; - -/** - * Describes a single instance of a node aka element in the Soft scene graph, - * relating it to the corresponding egg structures (e.g. node, group, or - * table entry) that will be created. - */ -class SoftNodeDesc : public ReferenceCount, public Namable { -public: - SoftNodeDesc(SoftNodeDesc *parent=nullptr, const std::string &name = std::string()); - ~SoftNodeDesc(); - - void set_parent(SoftNodeDesc *parent); - void force_set_parent(SoftNodeDesc *parent); - void set_model(SAA_Elem *model); - bool has_model() const; - SAA_Elem *get_model() const; - - bool is_joint() const; - bool is_junk() const; - void set_joint(); - bool is_joint_parent() const; - bool is_partial(char *search_prefix); - - SoftNodeDesc *_parent; - SoftNodeDesc *_parentJoint; // keep track of who is your parent joint - typedef pvector< PT(SoftNodeDesc) > Children; - Children _children; - -private: - void clear_egg(); - void mark_joint_parent(); - void check_joint_parent(); - void check_junk(bool parent_junk); - void check_pseudo_joints(bool joint_above); - - void set_parentJoint(SAA_Scene *scene, SoftNodeDesc *lastJoint); - - SAA_ModelType type; - - SAA_Elem *_model; - - EggGroup *_egg_group; - EggTable *_egg_table; - EggXfmSAnim *_anim; - - enum JointType { - JT_none, // Not a joint. - JT_joint, // An actual joint in Soft. - JT_pseudo_joint, // Not a joint in Soft, but treated just like a - // joint for the purposes of the converter. - JT_joint_parent, // A parent or ancestor of a joint or pseudo joint. - JT_junk, // originated from con-/fly-/car_rig/bars etc. - }; - JointType _joint_type; - -public: - - char **texNameArray; - int *uRepeat, *vRepeat; - PN_stdfloat matrix[4][4]; - - const char *fullname; - - int numTri; - // int numShapes; - int numTexLoc; - int numTexGlb; - int *numTexTri; - - // if the node is a MNSRF - int numNurbTexLoc; - int numNurbTexGlb; - int numNurbMats; - - PN_stdfloat *uScale; - PN_stdfloat *vScale; - PN_stdfloat *uOffset; - PN_stdfloat *vOffset; - - SAA_Boolean valid; - SAA_Boolean uv_swap; - // SAA_Boolean visible; - SAA_Elem *textures; - SAA_Elem *materials; - SAA_SubElem *triangles; - SAA_GeomType gtype; - - EggGroup *get_egg_group()const {return _egg_group;} - - void get_transform(SAA_Scene *scene, EggGroup *egg_group, bool global); - void get_joint_transform(SAA_Scene *scene, EggGroup *egg_group, EggXfmSAnim *anim, bool global); - void load_poly_model(SAA_Scene *scene, SAA_ModelType type); - void load_nurbs_model(SAA_Scene *scene, SAA_ModelType type); - - void make_morph_table(PN_stdfloat time); - void make_linear_morph_table(int numShapes, PN_stdfloat time); - void make_weighted_morph_table(int numShapes, PN_stdfloat time); - void make_expression_morph_table(int numShapes, PN_stdfloat time); - - void make_vertex_offsets(int numShapes); - int find_shape_vert(LPoint3d p3d, SAA_DVector *vertices, int numVert); - - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - ReferenceCount::init_type(); - Namable::init_type(); - register_type(_type_handle, "SoftNodeDesc", - ReferenceCount::get_class_type(), - Namable::get_class_type()); - } - -private: - static TypeHandle _type_handle; - - friend class SoftNodeTree; -}; - -class SoftToEggConverter; -extern SoftToEggConverter stec; - -#endif diff --git a/pandatool/src/softegg/softNodeTree.cxx b/pandatool/src/softegg/softNodeTree.cxx deleted file mode 100644 index 3b5be3252b..0000000000 --- a/pandatool/src/softegg/softNodeTree.cxx +++ /dev/null @@ -1,561 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softNodeTree.cxx - * @author masad - * @date 2003-09-26 - */ - -// Includes - -#include "softNodeTree.h" -#include "softEggGroupUserData.h" -#include "config_softegg.h" -#include "eggGroup.h" -#include "eggTable.h" -#include "eggXfmSAnim.h" -#include "eggData.h" -#include "softToEggConverter.h" -#include "dcast.h" - -#include - -using std::endl; - -/** - * - */ -SoftNodeTree:: -SoftNodeTree() { - _root = new SoftNodeDesc(nullptr, "----root"); - _root->fullname = "----root"; - _fps = 0.0; - _use_prefix = 0; - _search_prefix = nullptr; - _egg_data = nullptr; - _egg_root = nullptr; - _skeleton_node = nullptr; -} -/** - * Given an element, return a copy of the element's name WITHOUT prefix. - */ -char *SoftNodeTree:: -GetName( SAA_Scene *scene, SAA_Elem *element ) { - int nameLen; - char *name; - - // get the name - SAA_elementGetNameLength( scene, element, &nameLen ); - name = new char[++nameLen]; - SAA_elementGetName( scene, element, nameLen, name ); - - return name; -} - -/** - * Given an element, return a copy of the element's name complete with prefix. - */ -char *SoftNodeTree:: -GetFullName( SAA_Scene *scene, SAA_Elem *element ) -{ - int nameLen, prefixLen; - char *name, *prefix; - - // get the name length - SAA_elementGetNameLength( scene, element, &nameLen ); - // get the prefix length - SAA_elementGetPrefixLength( scene, element, &prefixLen ); - // allocate the array to hold name - name = new char[++nameLen]; - // allocate the array to hold prefix and length + hyphen - prefix = new char[++prefixLen + nameLen + 4]; - // get the name - SAA_elementGetName( scene, element, nameLen, name ); - // get the prefix - SAA_elementGetPrefix( scene, element, prefixLen, prefix ); - // add 'em together - strcat(prefix, "-"); - strcat(prefix, name); - - // return string - return prefix; -} - -/** - * Given an element, return a string containing the contents of its MODEL NOTE - * entry - */ -char *SoftNodeTree:: -GetModelNoteInfo( SAA_Scene *scene, SAA_Elem *model ) { - int size; - char *modelNote = nullptr; - SAA_Boolean bigEndian; - - SAA_elementGetUserDataSize( scene, model, "MNOT", &size ); - - if ( size != 0 ) { - // allocate modelNote string - modelNote = new char[size + 1]; - - // get ModelNote data from this model - SAA_elementGetUserData( scene, model, "MNOT", size, - &bigEndian, (void *)modelNote ); - - // strip off newline, if present - char *eol = (char *)memchr( modelNote, '\n', size ); - if ( eol != nullptr) - *eol = '\0'; - else - modelNote[size] = '\0'; - - softegg_cat.spam() << "\nmodelNote = " << modelNote << endl; - } - - return modelNote; -} - -/** - * Given a string, return a copy of the string up to the first occurence of - * '-'. - */ -char *SoftNodeTree:: -GetRootName( const char *name ) { - const char *hyphen; - char *root; - int len; - - hyphen = strchr( name, '-' ); - len = hyphen-name; - - if ( (hyphen != nullptr) && len ) { - root = new char[len+1]; - strncpy( root, name, len ); - root[len] = '\0'; - } - else { - root = new char[strlen(name)+1]; - strcpy( root, name ); - } - return( root ); -} - -/** - * Walks through the complete Soft hierarchy and builds up the corresponding - * tree. - */ -bool SoftNodeTree:: -build_complete_hierarchy(SAA_Scene &scene, SAA_Database &database) { - SI_Error status; - SoftNodeDesc *node; - - // Get the entire Soft scene. - int numModels; - SAA_Elem *models; - - SAA_sceneGetNbModels( &scene, &numModels ); - softegg_cat.spam() << "Scene has " << numModels << " model(s)...\n"; - - // This while loop walks through the entire Soft hierarchy, one node at a - // time. - bool all_ok = true; - if ( numModels ) { - // allocate array of models - models = (SAA_Elem *) new SAA_Elem[numModels]; - if ( models != nullptr ) { - if ((status = SAA_sceneGetModels( &scene, numModels, models )) != SI_SUCCESS) { - return false; - } - for ( int i = 0; i < numModels; i++ ) { - int level; - status = SAA_elementGetHierarchyLevel( &scene, &models[i], &level ); - softegg_cat.spam() << "model[" << i << "]" << endl; - softegg_cat.spam() << " level " << level << endl; - softegg_cat.spam() << " status is " << status << "\n"; - - node = build_node(&scene, &models[i]); - if (!level && node) - node->set_parent(_root); - } - } - } - - softegg_cat.spam() << "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj\n"; - - // check the nodes that are junk for animationartist control purposes - _root->check_junk(false); - - softegg_cat.spam() << "jpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjp\n"; - - // check the nodes that are parent of ancestors of a joint - _root->check_joint_parent(); - - softegg_cat.spam() << "pppppppppppppppppppppppppppppppppppppppppppppppppppppppp\n"; - - // check the nodes that are pseudo joints - _root->check_pseudo_joints(false); - - softegg_cat.spam() << "========================================================\n"; - - // find _parentJoint for each node - _root->set_parentJoint(&scene, nullptr); - - return all_ok; -} -#if 0 -/** - * Walks through the selected subset of the Soft hierarchy (or the complete - * hierarchy, if nothing is selected) and builds up the corresponding tree. - */ -bool SoftNodeTree:: -build_selected_hierarchy(char *scene_name) { - MStatus status; - - MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status); - if (!status) { - status.perror("MItDag constructor"); - return false; - } - - // Get only the selected geometry. - MSelectionList selection; - status = MGlobal::getActiveSelectionList(selection); - if (!status) { - status.perror("MGlobal::getActiveSelectionList"); - return false; - } - - // Get the selected geometry only if the selection is nonempty; otherwise, - // get the whole scene anyway. - if (selection.isEmpty()) { - softegg_cat.info() - << "Selection list is empty.\n"; - return build_complete_hierarchy(); - } - - bool all_ok = true; - unsigned int length = selection.length(); - for (unsigned int i = 0; i < length; i++) { - MDagPath root_path; - status = selection.getDagPath(i, root_path); - if (!status) { - status.perror("MSelectionList::getDagPath"); - } else { - // Now traverse through the selected dag path and all nested dag paths. - dag_iterator.reset(root_path); - while (!dag_iterator.isDone()) { - MDagPath dag_path; - status = dag_iterator.getPath(dag_path); - if (!status) { - status.perror("MItDag::getPath"); - } else { - build_node(dag_path); - } - - dag_iterator.next(); - } - } - } - - if (all_ok) { - _root->check_pseudo_joints(false); - } - - return all_ok; -} -#endif -/** - * Returns the total number of nodes in the hierarchy, not counting the root - * node. - */ -int SoftNodeTree:: -get_num_nodes() const { - return _nodes.size(); -} - -/** - * Returns the nth node in the hierarchy, in an arbitrary ordering. - */ -SoftNodeDesc *SoftNodeTree:: -get_node(int n) const { - nassertr(n >= 0 && n < (int)_nodes.size(), nullptr); - return _nodes[n]; -} - -/** - * Returns the node named 'name' in the hierarchy, in an arbitrary ordering. - */ -SoftNodeDesc *SoftNodeTree:: -get_node(std::string name) const { - NodesByName::const_iterator ni = _nodes_by_name.find(name); - if (ni != _nodes_by_name.end()) - return (*ni).second; - return nullptr; -} - -/** - * Removes all of the references to generated egg structures from the tree, - * and prepares the tree for generating new egg structures. - */ -void SoftNodeTree:: -clear_egg(EggData *egg_data, EggGroupNode *egg_root, - EggGroupNode *skeleton_node) { - _root->clear_egg(); - _egg_data = egg_data; - _egg_root = egg_root; - _skeleton_node = skeleton_node; -} - -/** - * Returns the EggGroupNode corresponding to the group or joint for the - * indicated node. Creates the group node if it has not already been created. - */ -EggGroup *SoftNodeTree:: -get_egg_group(SoftNodeDesc *node_desc) { - nassertr(_egg_root != nullptr, nullptr); - - // lets print some relationship - softegg_cat.spam() << " group " << node_desc->get_name() << "(" << node_desc->_egg_group << ")"; - if (node_desc->_parent) - softegg_cat.spam() << " parent " << node_desc->_parent->get_name() << "(" << node_desc->_parent << ")"; - else - softegg_cat.spam() << " parent " << node_desc->_parent; - softegg_cat.spam() << endl; - - if (node_desc->_egg_group == nullptr) { - // We need to make a new group node. - EggGroup *egg_group; - - egg_group = new EggGroup(node_desc->get_name()); - if (node_desc->is_joint()) { - egg_group->set_group_type(EggGroup::GT_joint); - } - - if (stec.flatten || (!node_desc->_parentJoint || node_desc->_parentJoint == _root)) { - // The parent is the root. - softegg_cat.spam() << "came hereeeee\n"; - _egg_root->add_child(egg_group); - } else { - // The parent is another node. - EggGroup *parent_egg_group = get_egg_group(node_desc->_parentJoint); - parent_egg_group->add_child(egg_group); - } - - node_desc->_egg_group = egg_group; - } - - return node_desc->_egg_group; -} - -/** - * Returns the EggTable corresponding to the joint for the indicated node. - * Creates the table node if it has not already been created. - */ -EggTable *SoftNodeTree:: -get_egg_table(SoftNodeDesc *node_desc) { - nassertr(_skeleton_node != nullptr, nullptr); - nassertr(node_desc->is_joint(), nullptr); - - // lets print some relationship - softegg_cat.spam() << " group " << node_desc->get_name() << "(" << node_desc->_egg_group << ")"; - if (node_desc->_parent) - softegg_cat.spam() << " parent " << node_desc->_parent->get_name() << "(" << node_desc->_parent << ")"; - else - softegg_cat.spam() << " parent " << node_desc->_parent; - softegg_cat.spam() << endl; - - if (node_desc->_egg_table == nullptr) { - softegg_cat.spam() << "creating a new table\n"; - // We need to make a new table node. nassertr(node_desc->_parent != - // (SoftNodeDesc *)NULL, NULL); - - EggTable *egg_table = new EggTable(node_desc->get_name()); - node_desc->_anim = new EggXfmSAnim("xform", _egg_data->get_coordinate_system()); - node_desc->_anim->set_fps(_fps); - egg_table->add_child(node_desc->_anim); - - if (stec.flatten || (!node_desc->_parentJoint || node_desc->_parentJoint == _root)) { - // if (!node_desc->_parent->is_joint()) { The parent is not a joint; put - // it at the top. - _skeleton_node->add_child(egg_table); - } else { - // The parent is another joint. - EggTable *parent_egg_table = get_egg_table(node_desc->_parentJoint); - parent_egg_table->add_child(egg_table); - } - - node_desc->_egg_table = egg_table; - } - - return node_desc->_egg_table; -} - -/** - * Returns the anim table corresponding to the joint for the indicated node. - * Creates the table node if it has not already been created. - */ -EggXfmSAnim *SoftNodeTree:: -get_egg_anim(SoftNodeDesc *node_desc) { - get_egg_table(node_desc); - return node_desc->_anim; -} - -/** - * Sets joint information for MNILL node - */ -void SoftNodeTree:: -handle_null(SAA_Scene *scene, SoftNodeDesc *node_desc, const char *node_name) { - const char *name = node_name; - SAA_AlgorithmType algo; - SAA_Elem *model = node_desc->get_model(); - - SAA_modelGetAlgorithm( scene, model, &algo ); - softegg_cat.spam() << " null algorithm: " << algo << endl; - - if ( algo == SAA_ALG_INV_KIN ) { - // MakeJoint( &scene, lastJoint, lastAnim, model, name ); - node_desc->set_joint(); - softegg_cat.spam() << " encountered IK root: " << name << endl; - } - else if ( algo == SAA_ALG_INV_KIN_LEAF ) { - // MakeJoint( &scene, lastJoint, lastAnim, model, name ); - node_desc->set_joint(); - softegg_cat.spam() << " encountered IK leaf: " << name << endl; - } - else if ( algo == SAA_ALG_STANDARD ) { - SAA_Boolean isSkeleton = FALSE; - softegg_cat.spam() << " encountered Standard null: " << name << endl; - - SAA_modelIsSkeleton( scene, model, &isSkeleton ); - - // check to see if this NULL is used as a skeleton or is animated via - // constraint only ( these nodes are tagged by the animator with the - // keyword "joint" somewhere in the nodes name) - if ( isSkeleton || (strstr( name, "joint" ) != nullptr) ) { - // MakeJoint( &scene, lastJoint, lastAnim, model, name ); - node_desc->set_joint(); - softegg_cat.spam() << " animating Standard null!!!\n"; - softegg_cat.spam() << "isSkeleton: " << isSkeleton << endl; - } - } - else - softegg_cat.spam() << " encountered some other NULL: " << algo << endl; -} - -/** - * Returns a pointer to the node corresponding to the indicated dag_path - * object, creating it first if necessary. - */ -SoftNodeDesc *SoftNodeTree:: -build_node(SAA_Scene *scene, SAA_Elem *model) { - char *name, *fullname; - std::string node_name; - int numChildren; - int thisChild; - SAA_Elem *children; - SAA_ModelType type; - SAA_Boolean isSkeleton = FALSE; - - fullname = GetFullName(scene, model); - if (_use_prefix) - name = fullname; - else - name = GetName(scene, model); - - node_name = name; - - SoftNodeDesc *node_desc = r_build_node(nullptr, node_name); - - node_desc->fullname = fullname; - node_desc->set_model(model); - SAA_modelIsSkeleton( scene, model, &isSkeleton ); - - // find out what type of node we're dealing with - SAA_modelGetType( scene, node_desc->get_model(), &type ); - - if (type == SAA_MJNT || isSkeleton || (strstr(node_desc->get_name().c_str(), "joint") != nullptr)) - node_desc->set_joint(); - - // treat the MNILL differently, because it needs to detect and set some - // joints - if (type == SAA_MNILL) - handle_null(scene, node_desc, name); - - if (node_desc->is_joint()) - softegg_cat.spam() << "type: " << type << " isSkeleton: " << isSkeleton << endl; - - // get to the children - SAA_modelGetNbChildren( scene, model, &numChildren ); - softegg_cat.spam() << " Model " << node_name << " children: " << numChildren << endl; - - if ( numChildren ) { - children = new SAA_Elem[numChildren]; - SAA_modelGetChildren( scene, model, numChildren, children ); - if (!children) - softegg_cat.info() << "Not enough Memory for children...\n"; - - for ( thisChild = 0; thisChild < numChildren; thisChild++ ) { - fullname = GetFullName(scene, &children[thisChild]); - if (_use_prefix) - node_name = fullname; - else - node_name = GetName(scene, &children[thisChild]); - - softegg_cat.spam() << " building child " << thisChild << "..."; - - SoftNodeDesc *node_child = r_build_node(node_desc, node_name); - - node_child->fullname = fullname; - node_child->set_model(&children[thisChild]); - SAA_modelIsSkeleton( scene, &children[thisChild], &isSkeleton ); - - // find out what type of node we're dealing with - SAA_modelGetType( scene, node_child->get_model(), &type ); - - if (type == SAA_MJNT || isSkeleton || (strstr(node_child->get_name().c_str(), "joint") != nullptr)) - node_child->set_joint(); - - // treat the MNILL differently, because it needs to detect and set some - // joints - if (type == SAA_MNILL) - handle_null(scene, node_child, node_name.c_str()); - - if (node_child->is_joint()) - softegg_cat.spam() << "type: " << type << " isSkeleton: " << isSkeleton << endl; - } - } - return node_desc; -} - -/** - * The recursive implementation of build_node(). - */ -SoftNodeDesc *SoftNodeTree:: -r_build_node(SoftNodeDesc *parent_node, const std::string &name) { - SoftNodeDesc *node_desc; - - // If we have already encountered this pathname, return the corresponding - // SoftNodeDesc immediately. - NodesByName::const_iterator ni = _nodes_by_name.find(name); - if (ni != _nodes_by_name.end()) { - softegg_cat.spam() << " already built node " << (*ni).first; - node_desc = (*ni).second; - node_desc->set_parent(parent_node); - return node_desc; - } - - // Otherwise, we have to create it. Do this recursively, so we create each - // node along the path. - node_desc = new SoftNodeDesc(parent_node, name); - - softegg_cat.spam() << " node name : " << name << endl; - _nodes.push_back(node_desc); - - _nodes_by_name.insert(NodesByName::value_type(name, node_desc)); - - return node_desc; -} diff --git a/pandatool/src/softegg/softNodeTree.h b/pandatool/src/softegg/softNodeTree.h deleted file mode 100644 index afbef5877b..0000000000 --- a/pandatool/src/softegg/softNodeTree.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softNodeTree.h - * @author masad - * @date 2003-10-03 - */ - -#ifndef SOFTNODETREE_H -#define SOFTNODETREE_H - -#include "pandatoolbase.h" -#include "softNodeDesc.h" - -#include - -class EggGroup; -class EggTable; -class EggXfmSAnim; -class EggData; -class EggGroupNode; - - -/** - * Describes a complete tree of soft nodes for conversion. - */ -class SoftNodeTree { -public: - SoftNodeTree(); - SoftNodeDesc *build_node(SAA_Scene *scene, SAA_Elem *model); - bool build_complete_hierarchy(SAA_Scene &scene, SAA_Database &database); - void handle_null(SAA_Scene *scene, SoftNodeDesc *node_desc, const char *node_name); - // bool build_selected_hierarchy(SAA_Scene *s, SAA_Database *d, char - // *scene_name); - - int get_num_nodes() const; - SoftNodeDesc *get_node(int n) const; - SoftNodeDesc *get_node(std::string name) const; - - char *GetRootName(const char *); - char *GetModelNoteInfo(SAA_Scene *, SAA_Elem *); - char *GetName(SAA_Scene *scene, SAA_Elem *element); - char *GetFullName(SAA_Scene *scene, SAA_Elem *element); - - EggGroupNode *get_egg_root() {return _egg_root;} - EggGroup *get_egg_group(SoftNodeDesc *node_desc); - EggTable *get_egg_table(SoftNodeDesc *node_desc); - EggXfmSAnim *get_egg_anim(SoftNodeDesc *node_desc); - - void clear_egg(EggData *egg_data, EggGroupNode *egg_root, EggGroupNode *skeleton_node); - - PT(SoftNodeDesc) _root; - PN_stdfloat _fps; - int _use_prefix; - char *_search_prefix; - - -private: - - EggData *_egg_data; - EggGroupNode *_egg_root; - EggGroupNode *_skeleton_node; - - SoftNodeDesc *r_build_node(SoftNodeDesc *parent_node, const std::string &path); - - typedef pmap NodesByName; - NodesByName _nodes_by_name; - - typedef pvector Nodes; - Nodes _nodes; -}; - -#endif diff --git a/pandatool/src/softegg/softToEggConverter.cxx b/pandatool/src/softegg/softToEggConverter.cxx deleted file mode 100644 index 44dafefb62..0000000000 --- a/pandatool/src/softegg/softToEggConverter.cxx +++ /dev/null @@ -1,2122 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softToEggConverter.cxx - * @author masad - * @date 2003-09-25 - */ - -#include "softToEggConverter.h" -#include "config_softegg.h" -#include "softEggGroupUserData.h" - -#include "eggData.h" -#include "eggGroup.h" -#include "eggTable.h" -#include "eggVertex.h" -#include "eggComment.h" -#include "eggVertexPool.h" -#include "eggNurbsSurface.h" -#include "eggNurbsCurve.h" -#include "eggPolygon.h" -#include "eggPrimitive.h" -#include "eggTexture.h" -#include "eggTextureCollection.h" -#include "eggXfmSAnim.h" -#include "eggSAnimData.h" -#include "string_utils.h" -#include "dcast.h" - -using std::endl; -using std::string; - -SoftToEggConverter stec; - -const int TEX_PER_MAT = 1; - -/** - * - */ -SoftToEggConverter:: -SoftToEggConverter(const string &program_name) : - _program_name(program_name) -{ - _from_selection = false; - _polygon_output = false; - _polygon_tolerance = 0.01; - /* - _respect_maya_double_sided = maya_default_double_sided; - _always_show_vertex_color = maya_default_vertex_color; - */ - _transform_type = TT_model; - - database_name = nullptr; - scene_name = nullptr; - model_name = nullptr; - animFileName = nullptr; - eggFileName = nullptr; - tex_path = nullptr; - eggGroupName = nullptr; - tex_filename = nullptr; - search_prefix = nullptr; - result = SI_SUCCESS; - - // skeleton = new EggGroup(); - foundRoot = FALSE; - // animRoot = NULL; morphRoot = NULL; - geom_as_joint = 0; - make_anim = 0; - make_nurbs = 0; - make_poly = 0; - make_soft = 0; - make_morph = 1; - make_duv = 1; - make_dart = TRUE; - has_morph = 0; - make_pose = 0; - // animData.is_z_up = FALSE; - nurbs_step = 1; - anim_start = -1000; - anim_end = -1000; - anim_rate = 24; - pose_frame = -1; - verbose = 0; - flatten = 0; - shift_textures = 0; - ignore_tex_offsets = 0; - use_prefix = 0; -} - -/** - * - */ -SoftToEggConverter:: -SoftToEggConverter(const SoftToEggConverter ©) : - _from_selection(copy._from_selection), - /* - _maya(copy._maya), - */ - _polygon_output(copy._polygon_output), - _polygon_tolerance(copy._polygon_tolerance), - /* - _respect_maya_double_sided(copy._respect_maya_double_sided), - _always_show_vertex_color(copy._always_show_vertex_color), - */ - _transform_type(copy._transform_type) -{ -} - -/** - * - */ -SoftToEggConverter:: -~SoftToEggConverter() { - /* - close_api(); - */ -} -/** - * Displays the "what is this program" message, along with the usage message. - * Should be overridden in base classes to describe the current program. - */ -void SoftToEggConverter:: -Help() -{ - softegg_cat.info() << - "soft2egg takes a SoftImage scene or model\n" - "and outputs its contents as an egg file\n"; - - Usage(); -} - -/** - * Displays the usage message. - */ -void SoftToEggConverter:: -Usage() { - softegg_cat.info() - << "\nUsage:\n" - // << _commandName << " [opts] (must specify -m or -s)\n\n" - << "soft" << " [opts] (must specify -m or -s)\n\n" - << "Options:\n"; - - ShowOpts(); - softegg_cat.info() << "\n"; -} - -/** - * Displays the valid options. Should be extended in base classes to show - * additional options relevant to the current program. - */ -void SoftToEggConverter:: -ShowOpts() -{ - softegg_cat.info() << - " -r - Used to provide soft with the resource\n" - " Defaults to '/ful/ufs/soft371_mips2/3D/rsrc'.\n" - " -d - Database path.\n" - " -s - Indicates that a scene will be converted.\n" - " -m - Indicates that a model will be converted.\n" - " -t - Specify path to place converted textures.\n" - " -T - Specify filename for texture map listing.\n" - " -S - Specify step for nurbs surface triangulation.\n" - " -M - Specify model output filename. Defaults to scene name.\n" - " -A - Specify anim output filename. Defaults to scene name.\n" - " -N - Specify egg group name.\n" - " -k - Enable soft assignment for geometry.\n" - " -n - Specify egg NURBS representation instead of poly's.\n" - " -p - Specify egg polygon output for geometry.\n" - " -P - Specify frame number for static pose.\n" - " -b - Specify starting frame for animation (default = first).\n" - " -e - Specify ending frame for animation (default = last).\n" - " -f - Specify frame rate for animation playback.\n" - " -a - Compile animation tables if animation present.\n" - " -F - Ignore hierarchy and build a completely flat skeleton.\n" - " -v - Set debug level.\n" - " -x - Shift NURBS parameters to preserve Alias textures.\n" - " -i - Ignore Soft texture uv offsets.\n" - " -u - Use Soft prefix in model names.\n" - " -c - Cancel morph conversion.\n" - " -C - Cancel duv conversion.\n" - " -D - Don't make the output model a character.\n" - " -o - Convert only models with given prefix.\n"; - - // EggBase::ShowOpts(); -} - -/** - * Calls getopt() to parse the command-line switches. Calls HandleGetopts() - * to interpret each switch. Returns true if the parsing was successful; - * false if there was an error. Adjusts argc and argv to remove the switches - * from the parameter list. - */ -bool SoftToEggConverter:: -DoGetopts(int &argc, char **&argv) { - bool okflag = true; - int i = 0; - softegg_cat.info() << "argc " << argc << "\n"; - if (argc <2) { - Usage(); - okflag = false; - } - while( i < argc ) { - strcat(_commandLine, argv[i]); - strcat(_commandLine, " "); - ++i; - } - softegg_cat.info() << endl << _commandLine << endl; - - i = 1; - while ((i < argc) && (argv[i][0] == '-') && okflag) { - softegg_cat.info() << "arg " << i << " is " << argv[i] << "\n"; - okflag = HandleGetopts(i, argc, argv); - } - return okflag; -} - -/** - * increment idx based on what kind of option parsed Supported options are as - * follows: r:d:s:m:t:P:b:e:f:T:S:M:A:N:v:o:FhknpaxiucCD - */ -bool SoftToEggConverter:: -HandleGetopts(int &idx, int argc, char **argv) -{ - bool okflag = true; - - char flag = argv[idx][1]; // skip the '-' from option - - switch (flag) - { - case 'r': // Set the resource path for soft. - if ( strcmp( argv[idx+1], "" ) ) { - // Get the path. - rsrc_path = argv[idx+1]; - softegg_cat.info() << "using rsrc path " << rsrc_path << "\n"; - } - ++idx; - break; - - case 'd': // Set the database path. - if ( strcmp( argv[idx+1], "" ) ) { - // Get the path. - database_name = argv[idx+1]; - softegg_cat.info() << "using database " << database_name << "\n"; - } - ++idx; - break; - - case 's': // Check if its a scene. - if ( strcmp( argv[idx+1], "" ) ) { - // Get scene name. - scene_name = argv[idx+1]; - softegg_cat.info() << "loading scene " << scene_name << "\n"; - } - ++idx; - break; - - case 'm': // Check if its a model. - if ( strcmp( argv[idx+1], "" ) ) { - // Get model name. - model_name = argv[idx+1]; - softegg_cat.info() << "loading model " << model_name << endl; - } - ++idx; - break; - - case 't': // Get converted texture path. - if ( strcmp( argv[idx+1], "" ) ) { - // Get tex path name. - tex_path = argv[idx+1]; - softegg_cat.info() << "texture path: " << tex_path << endl; - } - ++idx; - break; - - case 'T': // Specify texture list filename. - if ( strcmp( argv[idx+1], "") ) { - // Get the name. - tex_filename = argv[idx+1]; - softegg_cat.info() << "creating texture list file: " << tex_filename << endl; - } - ++idx; - break; - - case 'S': // Set NURBS step. - if ( strcmp( argv[idx+1], "" ) ) { - nurbs_step = atoi(argv[idx+1]); - softegg_cat.info() << "NURBS step: " << nurbs_step << endl; - } - ++idx; - break; - - case 'M': // Set model output file name. - if ( strcmp( argv[idx+1], "" ) ) { - eggFileName = argv[idx+1]; - softegg_cat.info() << "Model output filename: " << eggFileName << endl; - } - ++idx; - break; - - case 'A': // Set anim output file name. - if ( strcmp( argv[idx+1], "" ) ) { - animFileName = argv[idx+1]; - softegg_cat.info() << "Anim output filename: " << animFileName << endl; - } - ++idx; - break; - - case 'N': // Set egg model name. - if ( strcmp( argv[idx+1], "" ) ) { - eggGroupName = argv[idx+1]; - softegg_cat.info() << "Egg group name: " << eggGroupName << endl; - } - ++idx; - break; - - case 'o': // Set search_prefix. - if ( strcmp( argv[idx+1], "" ) ) { - search_prefix = argv[idx+1]; - softegg_cat.info() << "Only converting models with prefix: " << search_prefix << endl; - } - ++idx; - break; - - case 'h': // print help message - Help(); - exit(1); - break; - - case 'c': // Cancel morph animation conversion - make_morph = FALSE; - softegg_cat.info() << "canceling morph conversion\n"; - break; - - case 'C': // Cancel uv animation conversion - make_duv = FALSE; - softegg_cat.info() << "canceling uv animation conversion\n"; - break; - - case 'D': // Omit the Dart flag - make_dart = FALSE; - softegg_cat.info() << "making a non-character model\n"; - break; - - case 'k': // Enable soft skinning - // make_soft = TRUE; fprintf( outStream, "enabling soft skinning\n" ); - softegg_cat.info() << "-k flag no longer necessary\n"; - break; - - case 'n': // Generate egg NURBS output - make_nurbs = TRUE; - softegg_cat.info() << "outputting egg NURBS info\n"; - break; - - case 'p': // Generate egg polygon output - make_poly = TRUE; - softegg_cat.info() << "outputting egg polygon info\n"; - break; - - case 'P': // Generate static pose from given frame - if ( strcmp( argv[idx+1], "" ) ) { - make_pose = TRUE; - pose_frame = atoi(argv[idx+1]); - softegg_cat.info() << "generating static pose from frame " << pose_frame << endl; - } - ++idx; - break; - - case 'a': // Compile animation tables. - make_anim = TRUE; - softegg_cat.info() << "attempting to compile anim tables\n"; - break; - - case 'F': // Build a flat skeleton. - flatten = TRUE; - softegg_cat.info() << "building a flat skeleton!!!\n"; - break; - - case 'x': // Shift NURBS parameters to preserve Alias textures. - shift_textures = TRUE; - softegg_cat.info() << "shifting NURBS parameters...\n"; - break; - - case 'i': // Ignore Soft uv texture offsets - ignore_tex_offsets = TRUE; - softegg_cat.info() << "ignoring texture offsets...\n"; - break; - - case 'u': // Use Soft prefix in model names - use_prefix = TRUE; - softegg_cat.info() << "using prefix in model names...\n"; - break; - - - case 'v': // print debug messages. - if ( strcmp( argv[idx+1], "" ) ) { - verbose = atoi(argv[idx+1]); - softegg_cat.info() << "using debug level " << verbose << endl; - } - ++idx; - break; - - case 'b': // Set animation start frame. - anim_start = atoi(argv[idx]+2); - softegg_cat.info() << "animation starting at frame: " << anim_start << endl; - break; - - case 'e': /// Set animation end frame. - anim_end = atoi(argv[idx]+2); - softegg_cat.info() << "animation ending at frame: " << anim_end << endl; - break; - - case 'f': /// Set animation frame rate. - if ( strcmp( argv[idx+1], "" ) ) { - anim_rate = atoi(argv[idx+1]); - softegg_cat.info() << "animation frame rate: " << anim_rate << endl; - } - ++idx; - break; - - default: - softegg_cat.info() << flag << " flag not supported\n"; - okflag = false; - } - idx++; - return (okflag); -} - -/** - * Allocates and returns a new copy of the converter. - */ -SomethingToEggConverter *SoftToEggConverter:: -make_copy() { - return new SoftToEggConverter(*this); -} - -/** - * Returns the English name of the file type this converter supports. - */ -string SoftToEggConverter:: -get_name() const { - return "Soft"; -} - -/** - * Returns the common extension of the file type this converter supports. - */ -string SoftToEggConverter:: -get_extension() const { - return "mb"; -} - -/** - * Returns the English name of the file type this converter supports. - */ -SoftNodeDesc *SoftToEggConverter:: -find_node(string name) { - return _tree.get_node(name); -} - -/** - * Given a texture element, return texture name with given tex_path - */ -char *SoftToEggConverter:: -GetTextureName( SAA_Scene *scene, SAA_Elem *texture ) { - char *fileName = new char[_MAX_PATH]; - char tempName[_MAX_PATH]; - SAA_texture2DGetPicName( scene, texture, _MAX_PATH, tempName ); - - if (tex_path) { - // softegg_cat.spam() << "tempName :" << tempName << endl; - strcpy(fileName, tex_path); - - // do some processing on the name string - char *tmpName = nullptr; - tmpName = strrchr(tempName, '/'); - if (tmpName) - tmpName++; - else - tmpName = tempName; - - // softegg_cat.spam() << "tmpName : " << tmpName << endl; - strcat(fileName, "/"); - strcat(fileName, tmpName); - } - else { - strcpy(fileName, tempName); - } - - strcat(fileName, ".pic"); - // softegg_cat.spam() << "fileName : " << fileName << endl; - - return fileName; -} - -/** - * Handles the reading of the input file and converting it to egg. Returns - * true if successful, false otherwise. - * - * This is designed to be as generic as possible, generally in support of run- - * time loading. Also see convert_soft(). - */ -bool SoftToEggConverter:: -convert_file(const Filename &filename) { - if (!open_api()) { - softegg_cat.error() - << "Soft is not available.\n"; - return false; - } - if (_character_name.empty()) { - _character_name = filename.get_basename_wo_extension(); - } - return convert_soft(false); -} - -/** - * Fills up the egg_data structure according to the global soft model data. - * Returns true if successful, false if there is an error. If from_selection - * is true, the converted geometry is based on that which is selected; - * otherwise, it is the entire Soft scene. - */ -bool SoftToEggConverter:: -convert_soft(bool from_selection) { - bool all_ok = true; - - _from_selection = from_selection; - _textures.clear(); - - PT(EggData) egg_data = new EggData; - set_egg_data(egg_data); - softegg_cat.spam() << "eggData " << get_egg_data() << "\n"; - - // append the command line - softegg_cat.info() << _commandLine << endl; - get_egg_data()->insert(get_egg_data()->begin(), new EggComment("", _commandLine)); - - if (_egg_data->get_coordinate_system() != CS_default) { - softegg_cat.spam() << "coordinate system is not default\n"; - exit(1); - } - - _tree._use_prefix = use_prefix; - _tree._search_prefix = search_prefix; - all_ok = _tree.build_complete_hierarchy(scene, database); - - // Lets see if we have gotten the hierarchy right _tree.print_hierarchy(); - // exit(1); - - char *root_name = _tree.GetRootName( eggFileName ); - - softegg_cat.debug() << "main group name: " << root_name << endl; - if (root_name) - _character_name = root_name; - - if (make_poly || make_nurbs) { - // Specify that the texture names should be relative to the output file. - Filename output_filename(eggFileName); - _path_replace->_path_store = PS_relative; - _path_replace->_path_directory = output_filename.get_dirname(); - - if (!convert_char_model()) { - all_ok = false; - } - - // generate soft skinning assignments if desired - if (!make_soft_skin()) { - all_ok = false; - } - - // sometimes you need to hard assign some vertices - if (!cleanup_soft_skin()) { - all_ok = false; - } - - // reparent_decals(get_egg_data()); - softegg_cat.info() << "Converted Softimage file\n"; - - // write out the egg model file - _egg_data->write_egg(output_filename); - softegg_cat.info() << "Wrote Egg file " << output_filename << endl; - } - if (make_anim) { - if (!convert_char_chan()) { - all_ok = false; - } - - // reparent_decals(get_egg_data()); - softegg_cat.info() << "Converted Softimage file\n"; - - // write out the egg model file - _egg_data->write_egg(Filename(animFileName)); - softegg_cat.info() << "Wrote Anim file " << animFileName << endl; - } - return all_ok; -} - -/** - * Attempts to open the Soft API if it was not already open, and returns true - * if successful, or false if there is an error. - */ -bool SoftToEggConverter:: -open_api() { - if ((scene_name == nullptr && model_name == nullptr) || database_name == nullptr) { - Usage(); - exit( 1 ); - } - if ((result = SAA_Init(rsrc_path, FALSE)) != SI_SUCCESS) { - softegg_cat.info() << "Error: Couldn't get resource path!\n"; - exit( 1 ); - } - // cout << "got past init" << endl; - if ((result = SAA_databaseLoad(database_name, &database)) != SI_SUCCESS) { - softegg_cat.info() << "Error: Couldn't load database!\n"; - exit( 1 ); - } - // cout << "got past database load" << endl; - if ((result = SAA_sceneGetCurrent(&scene)) != SI_SUCCESS) { - softegg_cat.info() << "Error: Couldn't get current scene!\n"; - exit( 1 ); - } - // cout << "got past get current" << endl; - if ((result = SAA_sceneLoad( &database, scene_name, &scene )) != SI_SUCCESS) { - softegg_cat.info() << "Error: Couldn't load scene " << scene_name << "!\n"; - exit( 1 ); - } - // cout << "got past scene load" << endl; - if ( SAA_updatelistGet( &scene ) == SI_SUCCESS ) { - PN_stdfloat time; - - softegg_cat.info() << "setting Scene to frame " << pose_frame << "...\n"; - // SAA_sceneSetPlayCtrlCurrentFrame( &scene, pose_frame ); - SAA_frame2Seconds( &scene, pose_frame, &time ); - SAA_updatelistEvalScene( &scene, time ); - if ( make_pose ) - SAA_sceneFreeze(&scene); - } - - // if no egg filename specified, make up a name - if ( eggFileName == nullptr ) { - string madeName; - string tempName(scene_name); - string::size_type end = tempName.find(".dsc"); - if (end != string::npos) { - madeName.assign(tempName.substr(0,end)); - if ( make_nurbs ) - madeName.insert(madeName.size(), "-nurb"); - madeName.insert(madeName.size(), ".egg" ); - } - eggFileName = new char[madeName.size()+1]; - strcpy(eggFileName, madeName.c_str()); - - // if no anim filename specified, make up a name - if ( animFileName == nullptr ) { - madeName.assign(tempName.substr(0,end)); - madeName.insert(madeName.size(), "-chan.egg"); - animFileName = new char[strlen(scene_name)+ 10]; - strcpy(animFileName, madeName.c_str()); - } - } - - return true; -} - -/** - * Closes the Soft API, if it was previously opened. Caution! Soft appears - * to call exit() when its API is closed. - */ -void SoftToEggConverter:: -close_api() { - // don't know yet -} - -/** - * Converts the file as an animatable character model, with joints and vertex - * membership. - */ -bool SoftToEggConverter:: -convert_char_model() { - softegg_cat.spam() << "character name " << _character_name << "\n"; - EggGroup *char_node = new EggGroup(eggGroupName); - get_egg_data()->add_child(char_node); - char_node->set_dart_type(EggGroup::DT_default); - - return convert_hierarchy(char_node); -} - -/** - * Given a tablename, it either creates a new eggSAnimData structure (if - * doesn't exist) or locates it. - */ -EggSAnimData *SoftToEggConverter:: -find_morph_table(char *name) { - EggSAnimData *anim = nullptr; - MorphTable::iterator mt; - for (mt = _morph_table.begin(); mt != _morph_table.end(); ++mt) { - anim = (*mt); - if (!strcmp(anim->get_name().c_str(), name)) - return anim; - } - - // create an entry - anim = new EggSAnimData(name); - anim->set_fps(_tree._fps); - _morph_table.push_back(anim); - morph_node->add_child(anim); - return anim; -} - -/** - * Converts the animation as a series of tables to apply to the character - * model, as retrieved earlier via AC_model. - */ -bool SoftToEggConverter:: -convert_char_chan() { - int start_frame = -1; - int end_frame = -1; - int frame_inc, frame; - double output_frame_rate = anim_rate; - - PN_stdfloat time; - - EggTable *root_table_node = new EggTable(); - get_egg_data()->add_child(root_table_node); - EggTable *bundle_node = new EggTable(eggGroupName); - bundle_node->set_table_type(EggTable::TT_bundle); - root_table_node->add_child(bundle_node); - EggTable *skeleton_node = new EggTable(""); - bundle_node->add_child(skeleton_node); - - morph_node = new EggTable("morph"); - - // Set the frame rate before we start asking for anim tables to be created. - SAA_sceneGetPlayCtrlStartFrame(&scene, &start_frame); - SAA_sceneGetPlayCtrlEndFrame(&scene, &end_frame); - SAA_sceneGetPlayCtrlFrameStep( &scene, &frame_inc ); - if (frame_inc != 1) // Hmmm...some files gave me frame_inc of 0, that can't be good - frame_inc = 1; - - softegg_cat.info() << "animation start frame: " << start_frame << " end frame: " << end_frame << endl; - softegg_cat.info() << "animation frame inc: " << frame_inc << endl; - - _tree._fps = output_frame_rate / frame_inc; - // _tree.clear_egg(get_egg_data(), NULL, root_node); - _tree.clear_egg(get_egg_data(), nullptr, skeleton_node); - - // Now we can get the animation data by walking through all of the frames, - // one at a time, and getting the joint angles at each frame. - - // This is just a temporary EggGroup to receive the transform for each joint - // each frame. - PT(EggGroup) tgroup = new EggGroup; - - int num_nodes = _tree.get_num_nodes(); - int i; - - // MTime frame(start_frame, MTime::uiUnit()); MTime frame_stop(end_frame, - // MTime::uiUnit()); start at first frame and go to last - if (make_pose) { - start_frame = pose_frame; - end_frame = pose_frame; - } - if (anim_start > 0) - start_frame = anim_start; - if (anim_end > 0) - end_frame = anim_end; - for ( frame = start_frame; frame <= end_frame; frame += frame_inc) { - SAA_frame2Seconds( &scene, frame, &time ); - // softegg_cat.spam() << "got time " << time << endl; - if (!make_pose) { - SAA_updatelistEvalScene( &scene, time ); - } - softegg_cat.spam() << "\n> animating frame " << frame << endl; - - // if (softegg_cat.is_debug()) { softegg_cat.debug(false) - softegg_cat.info() << "frame " << time << "\n"; - // } else { We have to write to cerr instead of softegg_cat to allow - // flushing without writing a newline. std::cerr << "." << std::flush; } - // MGlobal::viewFrame(frame); - - for (i = 0; i < num_nodes; i++) { - SoftNodeDesc *node_desc = _tree.get_node(i); - - if (node_desc->is_partial(search_prefix)) { - softegg_cat.debug() << endl; - continue; - } - if (make_morph) { - node_desc->make_morph_table(time); - } - if (node_desc->is_joint()) { - softegg_cat.spam() << "-----joint " << node_desc->get_name() << "\n"; - EggXfmSAnim *anim = _tree.get_egg_anim(node_desc); - // following function fills in the anim structure - node_desc->get_joint_transform(&scene, tgroup, anim, TRUE); - } - } - - // frame += frame_inc; - } - - if (has_morph) - bundle_node->add_child(morph_node); - - // Now optimize all of the tables we just filled up, for no real good - // reason, except that it makes the resulting egg file a little easier to - // read. - for (i = 0; i < num_nodes; i++) { - SoftNodeDesc *node_desc = _tree.get_node(i); - if (node_desc->is_partial(search_prefix)) - continue; - - if (node_desc->is_joint()) { - _tree.get_egg_anim(node_desc)->optimize(); - } - } - - softegg_cat.info(false) - << "\n"; - - return true; -} - -/** - * Generates egg structures for each node in the Soft hierarchy. - */ -bool SoftToEggConverter:: -convert_hierarchy(EggGroupNode *egg_root) { - int num_nodes = _tree.get_num_nodes(); - - _tree.clear_egg(get_egg_data(), egg_root, nullptr); - softegg_cat.spam() << "num_nodes = " << num_nodes << endl; - for (int i = 0; i < num_nodes; i++) { - if (!process_model_node(_tree.get_node(i))) { - return false; - } - softegg_cat.debug() << i << endl; - } - return true; -} - -/** - * Converts the indicated Soft node (given a MDagPath, similar in concept to - * Panda's NodePath) to the corresponding Egg structure. Returns true if - * successful, false if an error was encountered. - */ -bool SoftToEggConverter:: -process_model_node(SoftNodeDesc *node_desc) { - EggGroup *egg_group = nullptr; - const char *name = nullptr; - char *fullname = nullptr; - SAA_ModelType type; - - name = node_desc->get_name().c_str(); - softegg_cat.debug() << "element name <" << name << ">\n"; - - if (node_desc->is_junk()) { - softegg_cat.spam() << "no processing, it is junk\n"; - return true; - } - - // split - if (node_desc->is_partial(search_prefix)) { - softegg_cat.debug() << endl; - return true; - } - else - softegg_cat.debug() << endl << name << ":being processed" << endl; - - egg_group = _tree.get_egg_group(node_desc); - - // find out what type of node we're dealing with - SAA_modelGetType( &scene, node_desc->get_model(), &type ); - - softegg_cat.debug() << "encountered "; - switch(type){ - case SAA_MNILL: - softegg_cat.debug() << "null\n"; - break; - case SAA_MPTCH: - softegg_cat.debug() << "patch\n"; - break; - case SAA_MFACE: - softegg_cat.debug() << "face\n"; - // break; - case SAA_MSMSH: - softegg_cat.debug() << "mesh\n"; - node_desc->get_transform(&scene, egg_group, TRUE); - make_polyset(node_desc, egg_group, type); - break; - case SAA_MJNT: - softegg_cat.debug() << "joint"; - softegg_cat.debug() << " joint type " << node_desc->is_joint() << endl; - break; - case SAA_MSPLN: - softegg_cat.debug() << "spline\n"; - break; - case SAA_MMETA: - softegg_cat.debug() << "meta element\n"; - break; - case SAA_MBALL: - softegg_cat.debug() << "meta ball\n"; - break; - case SAA_MNCRV: - softegg_cat.debug() << "nurbs curve\n"; - break; - case SAA_MNSRF: - softegg_cat.debug() << "nurbs surf\n"; - node_desc->get_transform(&scene, egg_group, TRUE); - make_nurb_surface(node_desc, egg_group, type); - break; - default: - softegg_cat.debug() << "unknown type: " << type << "\n"; - } - - if (node_desc->is_joint()) - node_desc->get_transform(&scene, egg_group, FALSE); - - return true; -} - -/** - * Converts the indicated Soft polyset to a bunch of EggPolygons and parents - * them to the indicated egg group. - */ -void SoftToEggConverter:: -make_polyset(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type) { - int id = 0; - int i, idx; - int numShapes; - SAA_Boolean valid; - SAA_Boolean visible; - PN_stdfloat *uCoords = nullptr; - PN_stdfloat *vCoords = nullptr; - string name = node_desc->get_name(); - - SAA_modelGetNodeVisibility( &scene, node_desc->get_model(), &visible ); - softegg_cat.spam() << "model visibility: " << visible << endl; - - // Only create egg polygon data if: the node is visible, and its not a NULL - // or a Joint, and we're outputing polys (or if we are outputing NURBS and - // the model is a poly mesh or a face) - if ( visible && - (type != SAA_MNILL) && - (type != SAA_MJNT) && - ((make_poly || - (make_nurbs && ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) || - (!make_poly && !make_nurbs && make_duv && - ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) - ) - { - // Get the number of key shapes - SAA_modelGetNbShapes( &scene, node_desc->get_model(), &numShapes ); - softegg_cat.spam() << "process_model_node: num shapes: " << numShapes << endl; - - // load all node data from soft for this node_desc - node_desc->load_poly_model(&scene, type); - - string vpool_name = name + ".verts"; - EggVertexPool *vpool = new EggVertexPool(vpool_name); - vpool->set_highest_index(0); - - // add the vertices in the _tree._root node, so that they will be - // written out first in egg file. This solves a problem of soft- - // skinning trying to access vertex pool before it is defined. - - _tree.get_egg_root()->insert(_tree.get_egg_root()->begin(), vpool); - - // We will need to transform all vertices from world coordinate space - // into the vertex space appropriate to this node. Usually, this is the - // same thing as world coordinate space, and this matrix will be - // identity; but if the node is under an instance (particularly, for - // instance, a billboard) then the vertex space will be different from - // world space. - LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv(); - - // Asad: change from soft2egg.c. Here I am trying to get one triangles - // vertices not all - for (idx=0; idxnumTri; ++idx) { - EggPolygon *egg_poly = new EggPolygon; - egg_group->add_child(egg_poly); - - softegg_cat.spam() << "processing polygon " << idx << endl; - - // Is this a double sided polygon? meaning check for back face flag - char *modelNoteStr = _tree.GetModelNoteInfo( &scene, node_desc->get_model() ); - if ( modelNoteStr != nullptr ) { - if ( strstr( modelNoteStr, "bface" ) != nullptr ) - egg_poly->set_bface_flag(TRUE); - } - - // read each triangle's control vertices into array - SAA_SubElem cvertices[3]; - SAA_triangleGetCtrlVertices( &scene, node_desc->get_model(), node_desc->gtype, id, 1, node_desc->triangles+idx, cvertices ); - - // read control vertices in this triangle - SAA_DVector cvertPos[3]; - SAA_ctrlVertexGetPositions( &scene, node_desc->get_model(), 3, cvertices, cvertPos); - - // read indices of each vertices in this triangle - int indices[3]; - indices[0] = indices[1] = indices[2] = 0; - SAA_ctrlVertexGetIndices( &scene, node_desc->get_model(), 3, cvertices, indices ); - - // read each control vertex's normals into an array - SAA_DVector normals[3]; - SAA_ctrlVertexGetNormals( &scene, node_desc->get_model(), 3, cvertices, normals ); - for (i=0; i<3; ++i) - softegg_cat.spam() << "normals[" << i <<"] = " << normals[i].x << " " << normals[i].y - << " " << normals[i].z << " " << normals[i].w << "\n"; - - // allocate arrays for u & v coords - if (node_desc->textures) { - if (node_desc->numTexLoc && node_desc->numTexTri[idx]) { - // allocate arrays for u & v coords I think there are one texture - // per triangle hence we need only 3 corrdinates - uCoords = new PN_stdfloat[3]; - vCoords = new PN_stdfloat[3]; - - // read the u & v coords into the arrays - if ( uCoords != nullptr && vCoords != nullptr) { - for ( i = 0; i < 3; i++ ) - uCoords[i] = vCoords[i] = 0.0f; - - // TODO: investigate the coord_cnt parameter... - SAA_ctrlVertexGetUVTxtCoords( &scene, node_desc->get_model(), 3, cvertices, - 3, uCoords, vCoords ); - } - else - softegg_cat.info() << "Not enough Memory for texture coords...\n"; - -#if 1 - for ( i=0; i<3; i++ ) - softegg_cat.spam() << "texcoords[" << i << "] = ( " << uCoords[i] << " , " << vCoords[i] <<" )\n"; -#endif - } - else if (node_desc->numTexGlb) { - // allocate arrays for u & v coords - uCoords = new PN_stdfloat[node_desc->numTexGlb*3]; - vCoords = new PN_stdfloat[node_desc->numTexGlb*3]; - - for ( i = 0; i < node_desc->numTexGlb*3; i++ ) { - uCoords[i] = vCoords[i] = 0.0f; - } - - // read the u & v coords into the arrays - if ( uCoords != nullptr && vCoords != nullptr) { - SAA_triCtrlVertexGetGlobalUVTxtCoords( &scene, node_desc->get_model(), 3, cvertices, - node_desc->numTexGlb, node_desc->textures, uCoords, vCoords ); - } - else - softegg_cat.info() << "Not enough Memory for texture coords...\n"; - } - } - - for ( i=0; i < 3; i++ ) { - EggVertex vert; - - // There are some conversions needed from local matrix to global - // coords - SAA_DVector local = cvertPos[i]; - SAA_DVector global = {0}; - - _VCT_X_MAT( global, local, node_desc->matrix ); - - softegg_cat.spam() << "indices[" << i << "] = " << indices[i] << "\n"; - softegg_cat.spam() << "cvert[" << i << "] = " << cvertPos[i].x << " " << cvertPos[i].y - << " " << cvertPos[i].z << " " << cvertPos[i].w << "\n"; - softegg_cat.spam() << " global cvert[" << i << "] = " << global.x << " " << global.y - << " " << global.z << " " << global.w << "\n"; - - // LPoint3d p3d(cvertPos[i].x, cvertPos[i].y, cvertPos[i].z); - LPoint3d p3d(global.x, global.y, global.z); - p3d = p3d * vertex_frame_inv; - vert.set_pos(p3d); - - local = normals[i]; - _VCT_X_MAT( global, local, node_desc->matrix ); - - softegg_cat.spam() << "normals[" << i <<"] = " << normals[i].x << " " << normals[i].y - << " " << normals[i].z << " " << normals[i].w << "\n"; - softegg_cat.spam() << " global normals[" << i <<"] = " << global.x << " " << global.y - << " " << global.z << " " << global.w << "\n"; - - LVector3d n3d(global.x, global.y, global.z); - n3d = n3d * vertex_frame_inv; - vert.set_normal(n3d); - - // if texture present set the texture coordinates - if (node_desc->textures) { - PN_stdfloat u, v; - - if (uCoords && vCoords) { - u = uCoords[i]; - v = 1.0f - vCoords[i]; - softegg_cat.spam() << "texcoords[" << i << "] = " << u << " " - << v << endl; - - vert.set_uv(LTexCoordd(u, v)); - // vert.set_uv(LTexCoordd(uCoords[i], vCoords[i])); - } - } - vert.set_external_index(indices[i]); - egg_poly->add_vertex(vpool->create_unique_vertex(vert)); - - // check to see if material is present - PN_stdfloat r,g,b,a; - SAA_elementIsValid( &scene, &node_desc->materials[idx], &valid ); - // material present - get the color - if ( valid ) { - SAA_materialGetDiffuse( &scene, &node_desc->materials[idx], &r, &g, &b ); - SAA_materialGetTransparency( &scene, &node_desc->materials[idx], &a ); - egg_poly->set_color(LColor(r, g, b, 1.0f - a)); - softegg_cat.spam() << "color r = " << r << " g = " << g << " b = " << b << " a = " << 1.0f - a << "\n"; - } - else { // no material - default to white - egg_poly->set_color(LColor(1.0, 1.0, 1.0, 1.0)); - softegg_cat.spam() << "default color\n"; - } - - /* - // keep a one to one copy in this node's vpool - EggVertex *t_vert = new EggVertex(vert); - if (!t_vert) { - softegg_cat.spam() << "out of memeory " << endl; - nassertv(t_vert != NULL); - } - node_desc->get_vpool()->add_vertex(t_vert, indices[i]); - */ - - softegg_cat.spam() << "\n"; - } - - // Now apply the shader. - if (node_desc->textures != nullptr) { - if (node_desc->numTexLoc && node_desc->numTexTri[idx]) { - if (!strstr(node_desc->texNameArray[idx], "noIcon")) - set_shader_attributes(node_desc, *egg_poly, idx); - else - softegg_cat.spam() << "texname :" << node_desc->texNameArray[idx] << endl; - } - else { - if (!strstr(node_desc->texNameArray[0], "noIcon")) - set_shader_attributes(node_desc, *egg_poly, 0); - else - softegg_cat.spam() << "texname :" << node_desc->texNameArray[0] << endl; - } - } - } - // if model has key shapes, generate vertex offsets - if ( numShapes > 0 && make_morph ) - node_desc->make_vertex_offsets( numShapes); - } -} - -/** - * Converts the indicated Soft nurbs set to a bunch of EggPolygons and parents - * them to the indicated egg group. - */ -void SoftToEggConverter:: -make_nurb_surface(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type) { - int id = 0; - int i, j, k; - int numShapes; - SAA_Boolean valid; - SAA_Boolean visible; - PN_stdfloat *uCoords = nullptr; - PN_stdfloat *vCoords = nullptr; - string name = node_desc->get_name(); - - SAA_modelGetNodeVisibility( &scene, node_desc->get_model(), &visible ); - softegg_cat.spam() << "model visibility: " << visible << endl; - softegg_cat.spam() << "nurbs!!!surface!!!" << endl; - - // check to see if its a nurbs surface - if ( (type == SAA_MNSRF) && ( visible ) && (( make_nurbs ) - || ( !make_nurbs && !make_poly && make_duv )) ) - { - // Get the number of key shapes - SAA_modelGetNbShapes( &scene, node_desc->get_model(), &numShapes ); - softegg_cat.spam() << "process_model_node: num shapes: " << numShapes << endl; - - // load all node data from soft for this node_desc - node_desc->load_nurbs_model(&scene, type); - - string vpool_name = name + ".verts"; - EggVertexPool *vpool = new EggVertexPool(vpool_name); - vpool->set_highest_index(0); - - // add the vertices in the _tree._egg_root node, so that they will be - // written out first in egg file. This solves a problem of soft- - // skinning trying to access vertex pool before it is defined. - - // _tree.get_egg_root()->add_child(vpool); - _tree.get_egg_root()->insert(_tree.get_egg_root()->begin(), vpool); - - // egg_group->add_child(vpool); - - /* - // create a copy of vpool in node_desc which will be used later for - // soft_skinning - node_desc->create_vpool(vpool_name); - */ - - int uRows, vRows; - int uKnots, vKnots; - int uExtra, vExtra; - int uDegree, vDegree; - int uCurves, vCurves; - - vector Knots; - - EggNurbsSurface *eggNurbs = new EggNurbsSurface( name ); - - // create nurbs representation of surface - SAA_nurbsSurfaceGetDegree( &scene, node_desc->get_model(), &uDegree, &vDegree ); - softegg_cat.spam() << "nurbs degree: " << uDegree << " u, " << vDegree << " v\n"; - - SAA_nurbsSurfaceGetNbKnots( &scene, node_desc->get_model(), &uKnots, &vKnots ); - softegg_cat.spam() << "nurbs knots: " << uKnots << " u, " << vKnots << " v\n"; - - SAA_Boolean uClosed = FALSE; - SAA_Boolean vClosed = FALSE; - - SAA_nurbsSurfaceGetClosed( &scene, node_desc->get_model(), &uClosed, &vClosed); - - uExtra = vExtra = 2; - if ( uClosed ) { - softegg_cat.spam() << "nurbs is closed in u...\n"; - uExtra += 4; - } - if ( vClosed ) { - softegg_cat.spam() << "nurbs is closed in v...\n"; - vExtra += 4; - } - eggNurbs->setup(uDegree+1, vDegree+1, - uKnots + uExtra, vKnots + vExtra); - - softegg_cat.spam() << "from eggNurbs: num u knots " << eggNurbs->get_num_u_knots() << endl; - softegg_cat.spam() << "from eggNurbs: num v knots " << eggNurbs->get_num_v_knots() << endl; - softegg_cat.spam() << "from eggNurbs: num u cvs " << eggNurbs->get_num_u_cvs() << endl; - softegg_cat.spam() << "from eggNurbs: num v cvs " << eggNurbs->get_num_v_cvs() << endl; - - SAA_nurbsSurfaceGetNbVertices( &scene, node_desc->get_model(), &uRows, &vRows ); - softegg_cat.spam() << "nurbs vertices: " << uRows << " u, " << vRows << " v\n"; - - SAA_nurbsSurfaceGetNbCurves( &scene, node_desc->get_model(), &uCurves, &vCurves ); - softegg_cat.spam() << "nurbs curves: " << uCurves << " u, " << vCurves << " v\n"; - - if ( shift_textures ) { - if ( uClosed ) - // shift starting point on NURBS surface for correct textures - SAA_nurbsSurfaceShiftParameterization( &scene, node_desc->get_model(), -2, 0 ); - - if ( vClosed ) - // shift starting point on NURBS surface for correct textures - SAA_nurbsSurfaceShiftParameterization( &scene, node_desc->get_model(), 0, -2 ); - } - - SAA_nurbsSurfaceSetStep( &scene, node_desc->get_model(), nurbs_step, nurbs_step ); - - // Is this a double sided polygon? meaning check for back face flag - char *modelNoteStr = _tree.GetModelNoteInfo( &scene, node_desc->get_model() ); - if ( modelNoteStr != nullptr ) { - if ( strstr( modelNoteStr, "bface" ) != nullptr ) { - eggNurbs->set_bface_flag(TRUE); - softegg_cat.spam() << "Set backface flag\n"; - } - } - - double *uKnotArray = new double[uKnots]; - double *vKnotArray = new double[vKnots]; - result = SAA_nurbsSurfaceGetKnots( &scene, node_desc->get_model(), node_desc->gtype, 0, - uKnots, vKnots, uKnotArray, vKnotArray ); - - if (result != SI_SUCCESS) { - softegg_cat.spam() << "Couldn't get knots\n"; - exit(1); - } - - // Lets prepare the softimage knots and then assign to eggKnots - add_knots( Knots, uKnotArray, uKnots, uClosed, uDegree ); - softegg_cat.spam() << "u knots: "; - for (i = 0; i < (int)Knots.size(); i++) { - softegg_cat.spam() << Knots[i] << " "; - eggNurbs->set_u_knot(i, Knots[i]); - } - softegg_cat.spam() << endl; - - Knots.resize(0); - add_knots( Knots, vKnotArray, vKnots, vClosed, vDegree ); - softegg_cat.spam() << "v knots: "; - for (i = 0; i < (int)Knots.size(); i++) { - softegg_cat.spam() << Knots[i] << " "; - eggNurbs->set_v_knot(i, Knots[i]); - } - softegg_cat.spam() << endl; - - // lets get the number of vertices from softimage - int numVert; - SAA_modelGetNbVertices( &scene, node_desc->get_model(), &numVert ); - - softegg_cat.spam() << numVert << " CV's\n"; - - // get the CV's - SAA_DVector *vertices = nullptr; - vertices = new SAA_DVector[numVert]; - - SAA_modelGetVertices( &scene, node_desc->get_model(), node_desc->gtype, 0, numVert, vertices ); - - LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv(); - - // create the buffer for EggVertices - EggVertex *verts = new EggVertex[numVert]; - - softegg_cat.spam() << endl << eggNurbs->get_num_cvs() << endl << endl; - - // for ( i = 0; iget_num_cvs(); i++ ) { - for ( k = 0; kget_u_index(i); - int vi = eggNurbs->get_v_index(i); - - int k = vRows * ui + vi; - - softegg_cat.spam() << i << ": ui " << ui << ", vi " << vi << ", k " << k << endl; - - softegg_cat.spam() << "original cv[" << k << "] = " - << vertices[k].x << " " << vertices[k].y << " " - << vertices[k].z << " " << vertices[k].w << endl; - */ - - // convert to global coords - _VCT_X_MAT( global, vertices[k], node_desc->matrix ); - - // preserve original weight - global.w = vertices[k].w; - - // normalize coords to weight - global.x *= global.w; - global.y *= global.w; - global.z *= global.w; - - /* - softegg_cat.spam() << "global cv[" << k << "] = " - << global.x << " " << global.y << " " - << global.x << " " << global.w << endl; - */ - - LPoint4d p4d(global.x, global.y, global.z, global.w); - p4d = p4d * vertex_frame_inv; - verts[k].set_pos(p4d); - - // check to see if material is present - if (node_desc->numNurbMats) { - PN_stdfloat r,g,b,a; - SAA_elementIsValid( &scene, &node_desc->materials[0], &valid ); - // material present - get the color - if ( valid ) { - SAA_materialGetDiffuse( &scene, &node_desc->materials[0], &r, &g, &b ); - SAA_materialGetTransparency( &scene, &node_desc->materials[0], &a ); - verts[k].set_color(LColor(r, g, b, 1.0f - a)); - // softegg_cat.spam() << "color r = " << r << " g = " << g << " b - // = " << b << " a = " << a << "\n"; - } - else { // no material - default to white - verts[k].set_color(LColor(1.0, 1.0, 1.0, 1.0)); - softegg_cat.spam() << "default color\n"; - } - } - vpool->add_vertex(verts+k, k); - eggNurbs->add_vertex(vpool->get_vertex(k)); - - if ( uClosed ) { - // add first uDegree verts to end of row - if ( (k % uRows) == ( uRows - 1) ) { - for ( i = 0; i < uDegree; i++ ) { - // add vref's to NURBS info - eggNurbs->add_vertex( vpool->get_vertex(i+((k/uRows)*uRows)) ); - } - } - } - } - - // check to see if the NURB is closed in v - if ( vClosed && !uClosed ) { - // add first vDegree rows of verts to end of list - for ( int i = 0; i < vDegree*uRows; i++ ) - eggNurbs->add_vertex( vpool->get_vertex(i) ); - } - // check to see if the NURB is closed in u and v - else if ( vClosed && uClosed ) { - // add the first (degree) v verts and a few extra - for good measure - for ( i = 0; i < vDegree; i++ ) { - // add first vDegree rows of verts to end of list - for ( j = 0; j < uRows; j++ ) - eggNurbs->add_vertex( vpool->get_vertex(j+(i*uRows)) ); - - // if u is closed to we have added uDegree verts onto the ends of - // the rows - add them here too - for ( k = 0; k < uDegree; k++ ) - eggNurbs->add_vertex( vpool->get_vertex(k+(i*uRows)+((k/uRows)*uRows)) ); - } - } - - // We add the NURBS to the group down here, after all of the vpools for - // the trim curves have been added. - egg_group->add_child(eggNurbs); - - // Now apply the shader. - if (node_desc->textures != nullptr) { - if (!strstr(node_desc->texNameArray[0], "noIcon")) - set_shader_attributes(node_desc, *eggNurbs, 0); - else - softegg_cat.spam() << "texname :" << node_desc->texNameArray[0] << endl; - } - - // if model has key shapes, generate vertex offsets - if ( numShapes > 0 && make_morph ) - node_desc->make_vertex_offsets( numShapes); - } -} - -/** - * Given a parametric surface, and its knots, create the appropriate egg - * structure by filling in Soft's implicit knots and assigning the rest to - * eggKnots. - */ -void SoftToEggConverter:: -add_knots( vector &eggKnots, double *knots, int numKnots, SAA_Boolean closed, int degree ) { - - int k = 0; - double lastKnot = knots[0]; - double *newKnots; - - // add initial implicit knot(s) - if ( closed ) { - int i = 0; - newKnots = new double[degree]; - - // need to add (degree) number of knots - for ( k = numKnots - 1; k >= numKnots - degree; k-- ) { - // we have to know these in order to calculate next knot value so hold - // them in temp array - newKnots[i] = lastKnot - (knots[k] - knots[k-1]); - lastKnot = newKnots[i]; - i++; - } - for ( k = degree - 1; k >= 0; k-- ) { - eggKnots.push_back( newKnots[k] ); - softegg_cat.spam() << "knots[" << k << "] = " << newKnots[k] << endl; - } - } - else { - eggKnots.push_back( knots[k] ); - softegg_cat.spam() << "knots[" << k << "] = " << knots[k] << endl; - } - - // add the regular complement of knots - for (k = 0; k < numKnots; k++) { - eggKnots.push_back( knots[k] ); - softegg_cat.spam() << "knots[" << k+1 << "] = " << knots[k] << endl; - } - - lastKnot = knots[numKnots-1]; - - // add trailing implicit knots - if ( closed ) { - // need to add (degree) number of knots - for ( k = 1; k <= degree; k++ ) { - eggKnots.push_back( lastKnot + (knots[k] - knots[k-1]) ); - softegg_cat.spam() << "knots[" << k << "] = " << lastKnot + (knots[k] - knots[k-1]) << endl; - lastKnot = lastKnot + (knots[k] - knots[k-1]); - } - } - else { - eggKnots.push_back( knots[k-1] ); - softegg_cat.spam() << "knots[" << k+1 << "] = " << knots[k-1] << endl; - } -} - -/** - * Given an egg vertex pool, map each vertex therein to a vertex within an - * array of SAA model vertices of size numVert. Mapping is done by closest - * proximity. - */ -int *SoftToEggConverter:: -FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert ) { - int i,j; - int *vertMap = nullptr; - int vpoolSize = (int)vpool->size(); - PN_stdfloat closestDist; - PN_stdfloat thisDist; - int closest; - - vertMap = new int[vpoolSize]; - i = 0; - EggVertexPool::iterator vi; - for (vi = vpool->begin(); vi != vpool->end(); ++vi, ++i) { - EggVertex *vert = (*vi); - softegg_cat.spam() << "vert external index = " << vert->get_external_index() << endl; - // softegg_cat.spam() << "found vert " << vert << endl; softegg_cat.spam() - // << "vert [" << i << "] " << vpool->get_vertex(i+1); - LPoint3d p3d = vert->get_pos3(); - - // find closest model vertex - for ( j = 0; j < numVert; j++ ) { - // calculate distance - thisDist = sqrtf( - powf( p3d[0] - vertices[j].x , 2 ) + - powf( p3d[1] - vertices[j].y , 2 ) + - powf( p3d[2] - vertices[j].z , 2 ) ); - - // remember this if its the closest so far - if ( !j || ( thisDist < closestDist ) ) { - closest = j; - closestDist = thisDist; - } - } - - vertMap[i] = closest; - softegg_cat.spam() << "mapping v " << i << " of " << vpoolSize-1 << ":( " - << p3d[0] << " " - << p3d[1] << " " - << p3d[2] << ")\n"; - - softegg_cat.spam() << " to cv " << closest << " of " << numVert-1 << ":( " - << vertices[closest].x << " " - << vertices[closest].y << " " - << vertices[closest].z << " )\tdelta = " << closestDist << endl; - } - return vertMap; -} - -/** - * make soft skin assignments to the mesh finally call cleanup_soft_skin to - * clean it up - */ -bool SoftToEggConverter:: -make_soft_skin() { - int num_nodes = _tree.get_num_nodes(); - SoftNodeDesc *node_desc; - SAA_Boolean isSkeleton; - - softegg_cat.spam() << endl << "----------------------------------------------------------------" << endl; - - for (int i = 0; i < num_nodes; i++) { - node_desc = _tree.get_node(i); - SAA_modelIsSkeleton( &scene, node_desc->get_model(), &isSkeleton ); - - softegg_cat.spam() << "??checking node " << node_desc->get_name() << " isSkel " << isSkeleton << " isJoint " << node_desc->is_joint() << endl; - if (isSkeleton && node_desc->is_joint()) { - - if (node_desc->is_partial(search_prefix)) - continue; - - // Now that we've added all the polygons (and created all the vertices), - // go back through the vertex pool and set up the appropriate joint - // membership for each of the vertices. - - // check for envelops - int numEnv; - SAA_ModelType type; - SAA_Elem *envelopes; - SAA_Elem *model = node_desc->get_model(); - EggGroup *joint = nullptr; - EggVertexPool *vpool; - - SAA_skeletonGetNbEnvelopes( &scene, model, &numEnv ); - if ( numEnv == 0 ) { - softegg_cat.spam() << "no soft skinning for joint " << node_desc->get_name() << endl; - continue; - } - - // it's got envelopes - must be soft skinned - softegg_cat.spam() << endl << "found skeleton part( " << node_desc->get_name() << ")!\n"; - softegg_cat.spam() << "numEnv = " << numEnv << endl; - // allocate envelope array - envelopes = new SAA_Elem[numEnv]; - if ( envelopes == nullptr ) { - softegg_cat.info() << "Out Of Memory" << endl; - exit(1); - } - int thisEnv; - SAA_EnvType envType; - bool hasEnvVertices = 0; - - SAA_skeletonGetEnvelopes( &scene, model, numEnv, envelopes ); - for ( thisEnv = 0; thisEnv < numEnv; thisEnv++ ) { - softegg_cat.spam() << "env[" << thisEnv << "]: "; - SAA_envelopeGetType( &scene, &envelopes[thisEnv], &envType ); - - if ( envType == SAA_ENVTYPE_NONE ) { - softegg_cat.spam() << "envType = none\n"; - } - else if ( envType == SAA_ENVTYPE_FLXLCL ) { - softegg_cat.spam() << "envType = flexible, local\n"; - hasEnvVertices = 1; - } - else if ( envType == SAA_ENVTYPE_FLXGLB ) { - softegg_cat.spam() << "envType = flexible, global\n"; - hasEnvVertices = 1; - } - else if ( envType == SAA_ENVTYPE_RGDGLB ) { - softegg_cat.spam() << "envType = rigid, global\n"; - hasEnvVertices = 1; - } - else { - softegg_cat.spam() << "envType = unknown\n"; - } - - } - if ( !hasEnvVertices ) - continue; - - SAA_SubElem *envVertices = nullptr; - int *numEnvVertices; - int i,j,k; - - numEnvVertices = new int[numEnv]; - - if ( numEnvVertices != nullptr ) { - SAA_envelopeGetNbCtrlVertices( &scene, model, numEnv, envelopes, numEnvVertices ); - int totalEnvVertices = 0; - for( i = 0; i < numEnv; i++ ) { - totalEnvVertices += numEnvVertices[i]; - softegg_cat.spam() << "numEnvVertices[" << i << "] = " << numEnvVertices[i] << endl; - } - softegg_cat.spam() << "total env verts = " << totalEnvVertices << endl; - if ( totalEnvVertices == 0 ) - continue; - - envVertices = new SAA_SubElem[totalEnvVertices]; - if ( envVertices != nullptr ) { - result = SAA_envelopeGetCtrlVertices( &scene, model, - numEnv, envelopes, numEnvVertices, envVertices); - if (result != SI_SUCCESS) { - softegg_cat.spam() << "error: GetCtrlVertices\n"; - exit(1); - } - // loop through for each envelope - for ( i = 0; i < numEnv; i++ ) { - PN_stdfloat *weights = nullptr; - int vertArrayOffset = 0; - softegg_cat.spam() << "envelope[" << i << "]: "; - weights = new PN_stdfloat[numEnvVertices[i]]; - if ( weights ) { - char *envName; - int *vpoolMap = nullptr; - for ( j = 0; j < i; j++ ) - vertArrayOffset += numEnvVertices[j]; - softegg_cat.spam() << "envVertArray offset = " << vertArrayOffset; - - /* - if (vertArrayOffset == totalEnvVertices) { - softegg_cat.spam() << endl; vpoolMap = FindClosestTriVert( vpool, globalModelVertices, modelNumVert ); - - break; - } - */ - - // get the weights of the envelope vertices - result = SAA_ctrlVertexGetEnvelopeWeights( &scene, model, &envelopes[i], - numEnvVertices[i], - &envVertices[vertArrayOffset], weights ); - - // Get the name of the envelope model - if ( use_prefix ) { - // Get the FULL name of the envelope - envName = _tree.GetFullName( &scene, &envelopes[i] ); - } - else { - // Get the name of the envelope - envName = _tree.GetName( &scene, &envelopes[i] ); - } - - softegg_cat.spam() << " envelop name is [" << envName << "]" << endl; - - if (result != SI_SUCCESS) { - softegg_cat.spam() << "warning: this envelop doesn't have any weights\n"; - continue; - } - - result = SAA_modelGetType( &scene, &envelopes[i], &type ); - if (result != SI_SUCCESS) { - softegg_cat.debug() << "choked on get type\n"; - exit(1); - } - - softegg_cat.spam() << "envelope model type "; - if ( type == SAA_MSMSH ) - softegg_cat.spam() << "MESH\n"; - else if ( type == SAA_MNSRF ) - softegg_cat.spam() << "NURBS\n"; - else - softegg_cat.spam() << "OTHER\n"; - - int *envVtxIndices = nullptr; - envVtxIndices = new int[numEnvVertices[i]]; - - // Get the envelope vertex indices - result = SAA_ctrlVertexGetIndices( &scene, &envelopes[i], numEnvVertices[i], - &envVertices[vertArrayOffset], envVtxIndices ); - - if (result != SI_SUCCESS) { - softegg_cat.debug() << "error: choked on get indices\n"; - exit(1); - } - - // find out how many vertices the model has - int modelNumVert; - - SAA_modelGetNbVertices( &scene, &envelopes[i], &modelNumVert ); - - SAA_DVector *modelVertices = nullptr; - modelVertices = new SAA_DVector[modelNumVert]; - - // get the model vertices - SAA_modelGetVertices( &scene, &envelopes[i], - SAA_GEOM_ORIGINAL, 0, modelNumVert, - modelVertices ); - - // create array of global model coords - SAA_DVector *globalModelVertices = nullptr; - globalModelVertices = new SAA_DVector[modelNumVert]; - PN_stdfloat matrix[4][4]; - - // tranform local model vert coords to global - - // first get the global matrix - SAA_modelGetMatrix( &scene, &envelopes[i], SAA_COORDSYS_GLOBAL, matrix ); - - // populate array of global model verts - for ( j = 0; j < modelNumVert; j++ ) { - _VCT_X_MAT( globalModelVertices[j], - modelVertices[j], matrix ); - } - - // Get the vpool - string s_name = envName; - SoftNodeDesc *mesh_node = find_node(s_name); - if (!mesh_node) { - softegg_cat.debug() << "error: node " << s_name << " not found in tree\n"; - exit(1); - } - string vpool_name = s_name + ".verts"; - EggNode *t = _tree.get_egg_root()->find_child(vpool_name); - if (t) - DCAST_INTO_R(vpool, t, nullptr); - - // find the mapping of the vertices that match this envelop - if (vpool) { - softegg_cat.spam() << "found vpool of size " << vpool->size() << endl; - if ( !make_nurbs || (type == SAA_MSMSH) ) { - vpoolMap = FindClosestTriVert( vpool, globalModelVertices, modelNumVert ); - } - } - else { - softegg_cat.debug() << "warning: vpool " << vpool_name << " not found\n"; - continue; // could be because of not visible - } - - joint = node_desc->get_egg_group(); - // for every envelope vertex - for (j = 0; j < numEnvVertices[i]; j++) { - double scaledWeight = weights[j]/ 100.0f; - - // make sure its in legal range - if (( envVtxIndices[j] < modelNumVert ) - && ( envVtxIndices[j] >= 0 )) { - if ( (type == SAA_MNSRF) && make_nurbs ) { - // assign all referenced control vertices - EggVertex *vert = vpool->get_vertex(envVtxIndices[j]); - if (!vert) { - softegg_cat.debug() << "possible error: index " << envVtxIndices[j] << ": vert is " << vert << endl; - continue; - } - joint->ref_vertex( vert, scaledWeight ); - softegg_cat.spam() << j << ": adding vref to cv " << envVtxIndices[j] - << " with weight " << scaledWeight << endl; - - /* - envPool->Vertex(envVtxIndices[j])->AddJoint( joint, scaledWeight ); - // set flag to show this vertex has been assigned - envPool->Vertex(envVtxIndices[j])->multipleJoints = 1; - */ - } - else { - // assign all the tri verts associated with this control - // vertex to joint - softegg_cat.spam() << j << "--trying to find " << envVtxIndices[j] << endl; - for ( k = 0; k < (int)vpool->size(); k++ ) { - if ( vpoolMap[k] == envVtxIndices[j] ) { - EggVertex *vert = vpool->get_vertex(k+1); - // EggVertex *vert = - // mesh_node->get_vpool()->get_vertex(vpoolMap[k]+1); - if (!vert) { - softegg_cat.debug() << "possible error: index " << k+1 << ": vert is " << vert << endl; - break; - } - - joint->ref_vertex(vert, scaledWeight); - softegg_cat.spam() << j << ": adding vref from cv " << envVtxIndices[j] - << " to vert " << k+1 << " with weight " << scaledWeight - << "(vpool)\n"; - /* - envPool->Vertex(k)->AddJoint( joint, scaledWeight ); - // set flag to show this vertex has been assigned - envPool->Vertex(k)->multipleJoints = 1; - */ - } - } - } - } - } - } - } - } - } - } - } - return true; -} -/** - * Given a model, make sure all its vertices have been soft assigned. If not - * hard assign to the last joint we saw. - */ -bool SoftToEggConverter:: -cleanup_soft_skin() -{ - int num_nodes = _tree.get_num_nodes(); - SoftNodeDesc *node_desc; - - softegg_cat.spam() << endl << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl; - - for (int i = 0; i < num_nodes; i++) { - node_desc = _tree.get_node(i); - if (node_desc->is_partial(search_prefix)) - continue; - - SAA_Elem *model = node_desc->get_model(); - EggGroup *joint = nullptr; - EggVertexPool *vpool = nullptr; - SAA_ModelType type; - - // find out what type of node we're dealing with - - SAA_modelGetType( &scene, model, &type ); - - softegg_cat.debug() << "Cleaning up model------- " << node_desc->get_name() << endl; - - // this step is weird - I think I want it here but it seems to break some - // models. Files like props-props_wh_cookietime.3-0 in - // fulrndpubvrmlchipchips_adventurecharzone1roomswarehouse_final need to - // do the "if (skel)" bit. - - // find the vpool for this model - string vpool_name = node_desc->get_name() + ".verts"; - EggNode *t = _tree.get_egg_root()->find_child(vpool_name); - if (t) - DCAST_INTO_R(vpool, t, nullptr); - - if (!vpool) { - // softegg_cat.spam() << "couldn't find vpool " << vpool_name << endl; - continue; - } - - int numVerts = (int)vpool->size(); - softegg_cat.spam() << "found vpool " << vpool_name << " w/ " << numVerts << " verts\n"; - - // if this node is a joint, then these vertices belong to this joint - if (node_desc->is_joint()) - joint = node_desc->get_egg_group(); - else { - // find the closest _parentJoint - SoftNodeDesc *parentJ = node_desc; - while( parentJ && !parentJ->_parentJoint) { - if ( parentJ->_parent) { - SAA_Boolean isSkeleton; - // softegg_cat.spam() << " checking parent " << - // parentJ->_parent->get_name() << endl; - if (parentJ->_parent->has_model()) - SAA_modelIsSkeleton( &scene, parentJ->_parent->get_model(), &isSkeleton ); - - if (isSkeleton) { - joint = parentJ->_parent->get_egg_group(); - softegg_cat.spam() << "parent to " << parentJ->_parent->get_name() << endl; - break; - } - - parentJ = parentJ->_parent; - } - else - break; - } - if (!joint && (!parentJ || !parentJ->_parentJoint)) { - softegg_cat.spam() << node_desc->get_name() << " has no _parentJoint?!" << endl; - continue; - } - - if (!joint) { - softegg_cat.spam() << "parent joint to " << parentJ->_parentJoint->get_name() << endl; - joint = parentJ->_parentJoint->get_egg_group(); - } - } - EggVertexPool::iterator vi; - double membership = 1.0f; - for ( vi = vpool->begin(); vi != vpool->end(); ++vi) { - EggVertex *vert = (*vi); - - // if this vertex has not been soft assigned, then hard assign it to the - // parentJoint - if ( vert->gref_size() == 0 ) { - - softegg_cat.spam() << "vert " << vert->get_external_index() << " not assigned!\n"; - - // hard skin this vertex - joint->ref_vertex( vert, 1.0f ); - } - } - } - return true; -} - -/** - * Applies the known shader attributes to the indicated egg primitive. - */ -void SoftToEggConverter:: -set_shader_attributes(SoftNodeDesc *node_desc, EggPrimitive &primitive, int idx) { - char *texName = node_desc->texNameArray[idx]; - EggTexture tex(texName, ""); - - Filename filename = Filename::from_os_specific(texName); - Filename fullpath = _path_replace->match_path(filename, get_model_path()); - tex.set_filename(_path_replace->store_path(fullpath)); - tex.set_fullpath(fullpath); - // tex.set_format(EggTexture::F_rgb); - apply_texture_properties(tex, node_desc->uRepeat[idx], node_desc->vRepeat[idx]); - - EggTexture *new_tex = _textures.create_unique_texture(tex, ~EggTexture::E_tref_name); - primitive.set_texture(new_tex); -} - -/** - * Applies all the appropriate texture properties to the EggTexture object, - * including wrap modes and texture matrix. - */ -void SoftToEggConverter:: -apply_texture_properties(EggTexture &tex, int uRepeat, int vRepeat) { - // Let's mipmap all textures by default. - tex.set_minfilter(EggTexture::FT_linear_mipmap_linear); - tex.set_magfilter(EggTexture::FT_linear); - - EggTexture::WrapMode wrap_u = uRepeat > 0 ? EggTexture::WM_repeat : EggTexture::WM_clamp; - EggTexture::WrapMode wrap_v = vRepeat > 0 ? EggTexture::WM_repeat : EggTexture::WM_clamp; - - tex.set_wrap_u(wrap_u); - tex.set_wrap_v(wrap_v); - /* - LMatrix3d mat = color_def.compute_texture_matrix(); - if (!mat.almost_equal(LMatrix3d::ident_mat())) { - tex.set_transform(mat); - } - */ -} -#if 0 -/** - * Compares the texture properties already on the texture (presumably set by a - * previous call to apply_texture_properties()) and returns false if they - * differ from that specified by the indicated color_def object, or true if - * they match. - */ -bool SoftToEggConverter:: -compare_texture_properties(EggTexture &tex, - const SoftShaderColorDef &color_def) { - bool okflag = true; - - EggTexture::WrapMode wrap_u = color_def._wrap_u ? EggTexture::WM_repeat : EggTexture::WM_clamp; - EggTexture::WrapMode wrap_v = color_def._wrap_v ? EggTexture::WM_repeat : EggTexture::WM_clamp; - - if (wrap_u != tex.determine_wrap_u()) { - // Choose the more general of the two. - if (wrap_u == EggTexture::WM_repeat) { - tex.set_wrap_u(wrap_u); - } - okflag = false; - } - if (wrap_v != tex.determine_wrap_v()) { - if (wrap_v == EggTexture::WM_repeat) { - tex.set_wrap_v(wrap_v); - } - okflag = false; - } - - LMatrix3d mat = color_def.compute_texture_matrix(); - if (!mat.almost_equal(tex.get_transform())) { - okflag = false; - } - - return okflag; -} -#endif -/** - * Recursively walks the egg hierarchy, reparenting "decal" type nodes below - * their corresponding "decalbase" type nodes, and setting the flags. - * - * Returns true on success, false if some nodes were incorrect. - */ -bool SoftToEggConverter:: -reparent_decals(EggGroupNode *egg_parent) { - bool okflag = true; - - // First, walk through all children of this node, looking for the one decal - // base, if any. - EggGroup *decal_base = nullptr; - pvector decal_children; - - EggGroupNode::iterator ci; - for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) { - EggNode *child = (*ci); - if (child->is_of_type(EggGroup::get_class_type())) { - EggGroup *child_group = DCAST(EggGroup, child); - if (child_group->has_object_type("decalbase")) { - if (decal_base != nullptr) { - softegg_cat.error() - << "Two children of " << egg_parent->get_name() - << " both have decalbase set: " << decal_base->get_name() - << " and " << child_group->get_name() << "\n"; - okflag = false; - } - child_group->remove_object_type("decalbase"); - decal_base = child_group; - - } else if (child_group->has_object_type("decal")) { - child_group->remove_object_type("decal"); - decal_children.push_back(child_group); - } - } - } - - if (decal_base == nullptr) { - if (!decal_children.empty()) { - softegg_cat.warning() - << decal_children.front()->get_name() - << " has decal, but no sibling node has decalbase.\n"; - } - - } else { - if (decal_children.empty()) { - softegg_cat.warning() - << decal_base->get_name() - << " has decalbase, but no sibling nodes have decal.\n"; - - } else { - // All the decal children get moved to be a child of decal base. This - // usually will not affect the vertex positions, but it could if the - // decal base has a transform and the decal child is an instance node. - // So don't do that. - pvector::iterator di; - for (di = decal_children.begin(); di != decal_children.end(); ++di) { - EggGroup *child_group = (*di); - decal_base->add_child(child_group); - } - - // Also set the decal state on the base. - decal_base->set_decal_flag(true); - } - } - - // Now recurse on each of the child nodes. - for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) { - EggNode *child = (*ci); - if (child->is_of_type(EggGroupNode::get_class_type())) { - EggGroupNode *child_group = DCAST(EggGroupNode, child); - if (!reparent_decals(child_group)) { - okflag = false; - } - } - } - - return okflag; -} - -/** - * Returns the TransformType value corresponding to the indicated string, or - * TT_invalid. - */ -SoftToEggConverter::TransformType SoftToEggConverter:: -string_transform_type(const string &arg) { - if (cmp_nocase(arg, "all") == 0) { - return TT_all; - } else if (cmp_nocase(arg, "model") == 0) { - return TT_model; - } else if (cmp_nocase(arg, "dcs") == 0) { - return TT_dcs; - } else if (cmp_nocase(arg, "none") == 0) { - return TT_none; - } else { - return TT_invalid; - } -} - -/** - * Invokes the softToEggConverter class - */ -extern "C" int init_soft2egg(int argc, char **argv) { - stec._commandName = argv[0]; - stec.rsrc_path = "c:\\Softimage\\SOFT3D_3.9.2\\3D\\rsrc"; - - if (stec.DoGetopts(argc, argv)) { - // Create a Filename object and convert the file - Filename softFile(argv[1]); - stec.convert_file(softFile); - } - - return 0; -} diff --git a/pandatool/src/softegg/softToEggConverter.h b/pandatool/src/softegg/softToEggConverter.h deleted file mode 100644 index 05c26fa60f..0000000000 --- a/pandatool/src/softegg/softToEggConverter.h +++ /dev/null @@ -1,179 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softToEggConverter.h - * @author masad - * @date 2003-09-25 - */ - -#ifndef SOFTTOEGGCONVERTER_H -#define SOFTTOEGGCONVERTER_H - -#include "pandatoolbase.h" -#include "somethingToEggConverter.h" -#include "softNodeTree.h" - -#include "eggTextureCollection.h" -#include "distanceUnit.h" -#include "coordinateSystem.h" - -#ifdef _MIN -#undef _MIN -#endif -#ifdef _MAX -#undef _MAX -#endif - -#include -#include - -class EggData; -class EggGroup; -class EggTable; -class EggVertexPool; -class EggNurbsCurve; -class EggPrimitive; -class EggXfmSAnim; -class EggSAnimData; - - -/** - * This class supervises the construction of an EggData structure from a - * single Softimage file, or from the data already in th cout << "egg name - * = " << eggFilename << endl;e global Softimage model space. - * - */ -class SoftToEggConverter : public SomethingToEggConverter { -public: - SoftToEggConverter(const std::string &program_name = ""); - SoftToEggConverter(const SoftToEggConverter ©); - virtual ~SoftToEggConverter(); - - void Help(); - void Usage(); - void ShowOpts(); - - bool HandleGetopts(int &idx, int argc, char **argv); - bool DoGetopts(int &argc, char **&argv); - - SoftNodeDesc *find_node(std::string name); - int *FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert ); - - virtual SomethingToEggConverter *make_copy(); - virtual std::string get_name() const; - virtual std::string get_extension() const; - - virtual bool convert_file(const Filename &filename); - bool convert_soft(bool from_selection); - bool open_api(); - void close_api(); - -private: - bool convert_flip(double start_frame, double end_frame, - double frame_inc, double output_frame_rate); - - bool make_soft_skin(); - bool cleanup_soft_skin(); - bool convert_char_chan(); - bool convert_char_model(); - bool convert_hierarchy(EggGroupNode *egg_root); - bool process_model_node(SoftNodeDesc *node_desc); - - void make_polyset(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type); - void make_nurb_surface(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type); - void add_knots( vector &eggKnots, double *knots, int numKnots, SAA_Boolean closed, int degree ); - - void set_shader_attributes(SoftNodeDesc *node_desc, EggPrimitive &primitive, int idx); - void apply_texture_properties(EggTexture &tex, int uRepeat, int vRepeat); - - bool reparent_decals(EggGroupNode *egg_parent); - - std::string _program_name; - bool _from_selection; - - SI_Error result; - SAA_Elem model; - SAA_Database database; - -public: - - SoftNodeTree _tree; - - SAA_Scene scene; - - char *_getopts; - - // This is argv[0]. - const char *_commandName; - - // This is the entire command line. - char _commandLine[4096]; - - char *rsrc_path; - char *database_name; - char *scene_name; - char *model_name; - char *eggFileName; - char *animFileName; - char *eggGroupName; - char *tex_path; - char *tex_filename; - char *search_prefix; - - int nurbs_step; - int anim_start; - int anim_end; - int anim_rate; - int pose_frame; - int verbose; - int flatten; - int shift_textures; - int ignore_tex_offsets; - int use_prefix; - - bool foundRoot; - bool geom_as_joint; - bool make_anim; - bool make_nurbs; - bool make_poly; - bool make_soft; - bool make_morph; - bool make_duv; - bool make_dart; - bool has_morph; - bool make_pose; - - - char *GetTextureName( SAA_Scene *scene, SAA_Elem *texture ); - - EggTextureCollection _textures; - - bool _polygon_output; - double _polygon_tolerance; - - enum TransformType { - TT_invalid, - TT_all, - TT_model, - TT_dcs, - TT_none, - }; - TransformType _transform_type; - - static TransformType string_transform_type(const std::string &arg); - - typedef pvector MorphTable; - MorphTable _morph_table; - - EggTable *morph_node; - EggSAnimData *find_morph_table(char *name); -}; - -extern const int TEX_PER_MAT; - -#endif diff --git a/pandatool/src/softprogs/softCVS.cxx b/pandatool/src/softprogs/softCVS.cxx deleted file mode 100644 index 478aa682d2..0000000000 --- a/pandatool/src/softprogs/softCVS.cxx +++ /dev/null @@ -1,588 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softCVS.cxx - * @author drose - * @date 2000-11-10 - */ - -#include "softCVS.h" - -#include "pnotify.h" -#include "multifile.h" - -#include - -using std::string; - -/** - * - */ -SoftCVS:: -SoftCVS() { - _cvs_binary = "cvs"; - - set_program_brief("prepare a SoftImage database directory for adding to CVS"); - set_program_description - ("softcvs is designed to prepare a directory hierarchy " - "representing a SoftImage database for adding to CVS. " - "First, it eliminates SoftImage's silly filename-based " - "versioning system by renaming versioned filenames higher " - "than 1-0 back to version 1-0. Then, it rolls up all the " - "files for each scene except the texture images into a Panda " - "multifile, which is added to CVS; the texture images are " - "directly added to CVS where they are.\n\n" - - "The reduction of hundreds of SoftImage files per scene down to one " - "multifile and a handle of texture images should greatly improve " - "the update and commit times of CVS.\n\n" - - "You must run this from within the root of a SoftImage database " - "directory; e.g. the directory that contains SCENES, PICTURES, MODELS, " - "and so on."); - - clear_runlines(); - add_runline("[opts]"); - - add_option - ("nc", "", 80, - "Do not attempt to add newly-created files to CVS. The default " - "is to add them.", - &SoftCVS::dispatch_none, &_no_cvs); - - add_option - ("cvs", "cvs_binary", 80, - "Specify how to run the cvs program for adding newly-created files. " - "The default is simply \"cvs\".", - &SoftCVS::dispatch_string, nullptr, &_cvs_binary); -} - - -/** - * - */ -void SoftCVS:: -run() { - // First, check for the scenes directory. If it doesn't exist, we must not - // be in the root of a soft database. - Filename scenes = "SCENES/."; - if (!scenes.exists()) { - nout << "No SCENES directory found; you are not in the root of a " - "SoftImage database.\n"; - exit(1); - } - - // Also, if we're expecting to use CVS, make sure the CVS directory exists. - Filename cvs_entries = "CVS/Entries"; - if (!_no_cvs && !cvs_entries.exists()) { - nout << "You do not appear to be within a CVS-controlled source " - "directory.\n"; - exit(1); - } - - // Scan all the files in the database. - traverse_root(); - - // Collapse out the higher-versioned scene files. - collapse_scene_files(); - - // Now determine which element files are actually referenced by at least one - // of the scene files. - if (!get_scenes()) { - exit(1); - } - - // Finally, remove all the element files that are no longer referenced by - // any scenes. - remove_unused_elements(); - - // Now do all the cvs adding and removing we need. - if (!_no_cvs) { - cvs_add_or_remove("remove", _cvs_remove); - cvs_add_or_remove("add -kb", _cvs_add); - } -} - -/** - * Reads all of the toplevel directory names, e.g. SCENES, MATERIALS, etc., - * and traverses them. - */ -void SoftCVS:: -traverse_root() { - Filename root("."); - - // Get the list of subdirectories. - vector_string subdirs; - if (!root.scan_directory(subdirs)) { - nout << "Unable to scan directory.\n"; - return; - } - - vector_string::const_iterator di; - for (di = subdirs.begin(); di != subdirs.end(); ++di) { - Filename subdir = (*di); - if (subdir.is_directory() && subdir != "CVS") { - traverse_subdir(subdir); - } - } -} - -/** - * Reads the directory indicated by prefix and identifies all of the SoftImage - * files stored there. - */ -void SoftCVS:: -traverse_subdir(const Filename &directory) { - // Get the list of files in the directory. - vector_string files; - if (!directory.scan_directory(files)) { - nout << "Unable to scan directory " << directory << "\n"; - return; - } - - // We need to know the set of files in this directory that are CVS elements. - pset cvs_elements; - bool in_cvs = false; - if (!_no_cvs) { - in_cvs = scan_cvs(directory, cvs_elements); - } - - bool is_scenes = false; - bool keep_all = false; - bool wants_cvs = false; - - // Now make some special-case behavior based on the particular SoftImage - // subdirectory we're in. - string dirname = directory.get_basename(); - if (dirname == "SCENES") { - is_scenes = true; - - } else if (dirname == "CAMERAS") { - // We don't want anything in the cameras directory. These may change - // arbitrarily and have no bearing on the model or animation that we will - // extract, so avoid them altogether. - return; - - } else if (dirname == "PICTURES") { - // In the pictures directory, we must keep everything, since the scene - // files don't explicitly reference these but they're still important. - // Textures that are no longer used will pile up; we leave this as the - // user's problem. - - // We not only keep the textures, but we also move them into CVS, since - // (again) they're not part of the scene files and thus won't get added to - // the multifiles. Also, some textures are shared between different - // scenes, and it would be wasteful to add them to each scene multifile; - // furthermore, some scenes are used for animation only, and we don't want - // to modify these multifiles when the textures change. - - keep_all = true; - wants_cvs = !_no_cvs; - } - - vector_string::const_iterator fi; - for (fi = files.begin(); fi != files.end(); ++fi) { - const string &filename = (*fi); - if (filename == "CVS") { - // This special filename is not to be considered. - - } else if (filename == "Chapter.rsrc") { - // This special filename should not be considered, except to add it to - // the multifiles. - _global_files.push_back(Filename(directory, filename)); - - } else { - SoftFilename soft(directory, filename); - - if (cvs_elements.count(filename) != 0) { - // This file is known to be in CVS. - soft.set_in_cvs(true); - } - - if (keep_all) { - soft.increment_use_count(); - } - if (wants_cvs && !in_cvs) { - // Try to CVSify the directory. - cvs_add(directory); - in_cvs = true; - } - soft.set_wants_cvs(wants_cvs); - - if (is_scenes && soft.has_version() && soft.get_extension() == ".dsc") { - _scene_files.push_back(soft); - } else { - _element_files.insert(soft); - } - } - } -} - -/** - * Walks through the list of scene files found, and renames the higher- - * versioned ones to version 1-0, removing the intervening versions. - */ -void SoftCVS:: -collapse_scene_files() { - // Get a copy of the scene files vector so we can modify it. Also empty out - // the _scene_files at the same time so we can fill it up again. - SceneFiles versions; - versions.swap(_scene_files); - - // And sort them into order so we can easily compare higher and lower - // versions. - sort(versions.begin(), versions.end()); - - SceneFiles::iterator vi; - vi = versions.begin(); - while (vi != versions.end()) { - SoftFilename &file = (*vi); - - if (!file.is_1_0()) { - // Here's a file that needs to be renamed. But first, identify all the - // other versions of the same file. - SceneFiles::iterator start_vi; - start_vi = vi; - while (vi != versions.end() && (*vi).is_same_file(file)) { - ++vi; - } - - rename_file(start_vi, vi); - - } else { - ++vi; - } - - file.make_1_0(); - _scene_files.push_back(file); - } -} - -/** - * Walks through the list of scene files and looks for the set of element - * files referenced by each one, updating multifile accordingly. - */ -bool SoftCVS:: -get_scenes() { - bool okflag = true; - - // We will be added the multifiles to CVS if they're not already added, so - // we have to know which files are in CVS already. - pset cvs_elements; - if (!_no_cvs) { - scan_cvs(".", cvs_elements); - } - - SceneFiles::const_iterator vi; - for (vi = _scene_files.begin(); vi != _scene_files.end(); ++vi) { - const SoftFilename &sf = (*vi); - Filename file(sf.get_dirname(), sf.get_filename()); - - file.set_text(); - std::ifstream in; - if (!file.open_read(in)) { - nout << "Unable to read " << file << "\n"; - } else { - nout << "Scanning " << file << "\n"; - - Multifile multifile; - Filename multifile_name = sf.get_base() + "mf"; - - if (!multifile.open_read_write(multifile_name)) { - nout << "Unable to open " << multifile_name << " for updating.\n"; - okflag = false; - - } else { - if (!scan_scene_file(in, multifile)) { - okflag = false; - } - - // Add all the global files to the multifile too. These probably - // can't take compression (since in SoftImage they're just the - // Chapter.rsrc files, each very tiny). - vector_string::const_iterator gi; - for (gi = _global_files.begin(); gi != _global_files.end(); ++gi) { - if (multifile.update_subfile((*gi), (*gi), 0).empty()) { - nout << "Unable to add " << (*gi) << "\n"; - okflag = false; - } - } - - // Also add the scene file itself. - if (multifile.update_subfile(file, file, 6).empty()) { - nout << "Unable to add " << file << "\n"; - okflag = false; - } - - bool flushed = false; - if (multifile.needs_repack()) { - flushed = multifile.repack(); - } else { - flushed = multifile.flush(); - } - if (!flushed) { - nout << "Failed to write " << multifile_name << ".\n"; - okflag = false; - } else { - nout << "Wrote " << multifile_name << ".\n"; - - if (!_no_cvs && cvs_elements.count(multifile_name) == 0) { - // Add the multifile to CVS. - _cvs_add.push_back(multifile_name); - } - } - } - } - } - - return okflag; -} - - -/** - * Remove all the element files that weren't referenced by any scene file. - * Also plan to cvs add all those that were referenced. - */ -void SoftCVS:: -remove_unused_elements() { - ElementFiles::const_iterator fi; - for (fi = _element_files.begin(); fi != _element_files.end(); ++fi) { - const SoftFilename &sf = (*fi); - Filename file(sf.get_dirname(), sf.get_filename()); - - if (sf.get_use_count() == 0) { - nout << file << " is unused.\n"; - - if (!file.unlink()) { - nout << "Unable to remove " << file << ".\n"; - - } else if (sf.get_in_cvs()) { - _cvs_remove.push_back(file); - } - - } else if (sf.get_wants_cvs() && !sf.get_in_cvs()) { - _cvs_add.push_back(file); - } - } -} - - -/** - * Renames the first file in the indicated list to a version 1-0 filename, - * superceding all the other files in the list. Returns true if the file is - * renamed, false otherwise. - */ -bool SoftCVS:: -rename_file(SoftCVS::SceneFiles::iterator begin, - SoftCVS::SceneFiles::iterator end) { - int length = end - begin; - nassertr(length > 0, false); - - SoftFilename &orig = (*begin); - - string dirname = orig.get_dirname(); - string source_filename = orig.get_filename(); - string dest_filename = orig.get_1_0_filename(); - - if (length > 2) { - nout << source_filename << " supercedes:\n"; - SceneFiles::const_iterator p; - for (p = begin + 1; p != end; ++p) { - nout << " " << (*p).get_filename() << "\n"; - } - - } else if (length == 2) { - nout << source_filename << " supercedes " - << (*(begin + 1)).get_filename() << ".\n"; - - } else { - nout << source_filename << " renamed.\n"; - } - - // Now remove all of the "wrong" files. - - SceneFiles::const_iterator p; - for (p = begin + 1; p != end; ++p) { - Filename file((*p).get_dirname(), (*p).get_filename()); - if (!file.unlink()) { - nout << "Unable to remove " << file << ".\n"; - } - } - - // And rename the good one. - Filename source(dirname, source_filename); - Filename dest(dirname, dest_filename); - - if (!source.rename_to(dest)) { - nout << "Unable to rename " << source << " to " << dest_filename << ".\n"; - exit(1); - } - - return true; -} - -/** - * Scans the CVS repository in the indicated directory to determine which - * files are already versioned elements. Returns true if the directory is - * CVS-controlled, false otherwise. - */ -bool SoftCVS:: -scan_cvs(const string &dirname, pset &cvs_elements) { - Filename cvs_entries = dirname + "/CVS/Entries"; - if (!cvs_entries.exists()) { - return false; - } - - std::ifstream in; - cvs_entries.set_text(); - if (!cvs_entries.open_read(in)) { - nout << "Unable to read CVS directory.\n"; - return true; - } - - string line; - std::getline(in, line); - while (!in.fail() && !in.eof()) { - if (!line.empty() && line[0] == '/') { - size_t slash = line.find('/', 1); - if (slash != string::npos) { - string filename = line.substr(1, slash - 1); - - if (line.substr(slash + 1, 2) == "-1") { - // If the first number after the slash is -1, the file used to be - // here but was recently cvs removed. It counts as no longer being - // an element. - } else { - cvs_elements.insert(filename); - } - } - } - - std::getline(in, line); - } - - return true; -} - -/** - * Reads a scene file, looking for references to element files. For each - * reference found, increments the appropriate element file's reference count. - */ -bool SoftCVS:: -scan_scene_file(std::istream &in, Multifile &multifile) { - bool okflag = true; - - int c = in.get(); - while (!in.eof() && !in.fail()) { - // Skip whitespace. - while (isspace(c) && !in.eof() && !in.fail()) { - c = in.get(); - } - - // Now begin a word. - string word; - while (!isspace(c) && !in.eof() && !in.fail()) { - word += c; - c = in.get(); - } - - if (!word.empty()) { - SoftFilename v("", word); - - // Increment the use count on all matching elements of the multiset. - std::pair range; - range = _element_files.equal_range(v); - - ElementFiles::iterator ei; - for (ei = range.first; ei != range.second; ++ei) { - // We cheat and get a non-const reference to the filename out of the - // set. We can safely do this because incrementing the use count - // won't change its position in the set. - SoftFilename &sf = (SoftFilename &)(*ei); - sf.increment_use_count(); - - Filename file(sf.get_dirname(), sf.get_filename()); - if (multifile.update_subfile(file, file, 6).empty()) { - nout << "Unable to add " << file << "\n"; - okflag = false; - } - } - } - } - - return okflag; -} - -/** - * Invokes CVS to add just the named file to the repository. Returns true on - * success, false on failure. - */ -bool SoftCVS:: -cvs_add(const string &path) { - string command = _cvs_binary + " add -kb " + path; - nout << command << "\n"; - int result = system(command.c_str()); - - if (result != 0) { - nout << "Failure invoking cvs.\n"; - return false; - } - return true; -} - -/** - * Invokes CVS to add (or remove) all of the files in the indicated vector. - * Returns true on success, false on failure. - */ -bool SoftCVS:: -cvs_add_or_remove(const string &cvs_command, const vector_string &paths) { - static const int max_command = 4096; - - if (!paths.empty()) { - string command = _cvs_binary + " " + cvs_command; - vector_string::const_iterator pi; - pi = paths.begin(); - while (pi != paths.end()) { - const string &path = (*pi); - - if ((int)command.length() + 1 + (int)path.length() >= max_command) { - // Fire off the command now. - nout << command << "\n"; - int result = system(command.c_str()); - - if (result != 0) { - nout << "Failure invoking cvs.\n"; - return false; - } - - command = _cvs_binary + " " + cvs_command; - } - - command += ' '; - command += path; - - ++pi; - } - nout << command << "\n"; - int result = system(command.c_str()); - - if (result != 0) { - nout << "Failure invoking cvs.\n"; - return false; - } - } - return true; -} - - -int main(int argc, char *argv[]) { - SoftCVS prog; - prog.parse_command_line(argc, argv); - prog.run(); - return 0; -} diff --git a/pandatool/src/softprogs/softCVS.h b/pandatool/src/softprogs/softCVS.h deleted file mode 100644 index adbd89efa6..0000000000 --- a/pandatool/src/softprogs/softCVS.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softCVS.h - * @author drose - * @date 2000-11-10 - */ - -#ifndef SOFTCVS_H -#define SOFTCVS_H - -#include "pandatoolbase.h" - -#include "softFilename.h" - -#include "programBase.h" -#include "vector_string.h" -#include "filename.h" - -#include "pvector.h" -#include "pset.h" - -class Multifile; - -/** - * This program prepares a SoftImage database for CVS by renaming everything - * to version 1-0, and adding new files to CVS. - */ -class SoftCVS : public ProgramBase { -public: - SoftCVS(); - - void run(); - -private: - typedef pvector SceneFiles; - typedef pmultiset ElementFiles; - - void traverse_root(); - void traverse_subdir(const Filename &directory); - - void collapse_scene_files(); - bool get_scenes(); - void remove_unused_elements(); - - bool rename_file(SceneFiles::iterator begin, SceneFiles::iterator end); - bool scan_cvs(const std::string &dirname, pset &cvs_elements); - bool scan_scene_file(std::istream &in, Multifile &multifile); - - bool cvs_add(const std::string &path); - bool cvs_add_or_remove(const std::string &cvs_command, - const vector_string &paths); - - SceneFiles _scene_files; - ElementFiles _element_files; - vector_string _global_files; - - vector_string _cvs_add; - vector_string _cvs_remove; - - bool _no_cvs; - std::string _cvs_binary; -}; - -#endif diff --git a/pandatool/src/softprogs/softFilename.cxx b/pandatool/src/softprogs/softFilename.cxx deleted file mode 100644 index 4c099c56be..0000000000 --- a/pandatool/src/softprogs/softFilename.cxx +++ /dev/null @@ -1,291 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softFilename.cxx - * @author drose - * @date 2000-11-10 - */ - -#include "softFilename.h" - -#include "pnotify.h" - -using std::string; - -/** - * - */ -SoftFilename:: -SoftFilename(const string &dirname, const string &filename) : - _dirname(dirname), - _filename(filename) -{ - _has_version = false; - _major = 0; - _minor = 0; - _in_cvs = false; - _wants_cvs = false; - _use_count = 0; - - _base = _filename; - - // Scan for a version number and an optional extension after each dot in the - // filename. - size_t dot = _filename.find('.'); - while (dot != string::npos) { - size_t m = dot + 1; - const char *fstr = _filename.c_str(); - char *endptr; - // Check for a numeric version number. - int major = strtol(fstr + m , &endptr, 10); - if (endptr != fstr + m && *endptr == '-') { - // We got a major number, is there a minor number? - m = (endptr - fstr) + 1; - int minor = strtol(fstr + m, &endptr, 10); - if (endptr != fstr + m && (*endptr == '.' || *endptr == '\0')) { - // We got a minor number too! - _has_version = true; - _base = _filename.substr(0, dot + 1); - _major = major; - _minor = minor; - _ext = endptr; - return; - } - } - - // That wasn't a version number. Is there more? - dot = _filename.find('.', dot + 1); - } -} - -/** - * - */ -SoftFilename:: -SoftFilename(const SoftFilename ©) : - _dirname(copy._dirname), - _filename(copy._filename), - _has_version(copy._has_version), - _base(copy._base), - _major(copy._major), - _minor(copy._minor), - _ext(copy._ext), - _in_cvs(copy._in_cvs), - _wants_cvs(copy._wants_cvs), - _use_count(copy._use_count) -{ -} - -/** - * - */ -void SoftFilename:: -operator = (const SoftFilename ©) { - _dirname = copy._dirname; - _filename = copy._filename; - _has_version = copy._has_version; - _base = copy._base; - _major = copy._major; - _minor = copy._minor; - _ext = copy._ext; - _in_cvs = copy._in_cvs; - _wants_cvs = copy._wants_cvs; - _use_count = copy._use_count; -} - -/** - * Returns the name of the directory this file was found in. - */ -const string &SoftFilename:: -get_dirname() const { - return _dirname; -} - -/** - * Returns the actual filename as found in the directory. - */ -const string &SoftFilename:: -get_filename() const { - return _filename; -} - -/** - * Returns true if the filename had a version number, false otherwise. - */ -bool SoftFilename:: -has_version() const { - return _has_version; -} - -/** - * Returns what the filename would be if it were version 1-0. - */ -string SoftFilename:: -get_1_0_filename() const { - nassertr(_has_version, string()); - return _base + "1-0" + _ext; -} - -/** - * Returns the base part of the filename. This is everything before the - * version number. - */ -const string &SoftFilename:: -get_base() const { - nassertr(_has_version, _filename); - return _base; -} - -/** - * Returns the major version number. - */ -int SoftFilename:: -get_major() const { - nassertr(_has_version, 0); - return _major; -} - -/** - * Returns the minor version number. - */ -int SoftFilename:: -get_minor() const { - nassertr(_has_version, 0); - return _minor; -} - -/** - * Returns the extension part of the filename. This is everything after the - * version number. - */ -const string &SoftFilename:: -get_extension() const { - nassertr(_has_version, _ext); - return _ext; -} - -/** - * Returns the filename part, without the extension. - */ -string SoftFilename:: -get_non_extension() const { - nassertr(_has_version, _filename); - nassertr(_ext.length() < _filename.length(), _filename); - return _filename.substr(0, _filename.length() - _ext.length()); -} - -/** - * Returns true if this is a version 1_0 filename, false otherwise. - */ -bool SoftFilename:: -is_1_0() const { - nassertr(_has_version, false); - return (_major == 1 && _minor == 0); -} - -/** - * Makes this a 1_0 filename. - */ -void SoftFilename:: -make_1_0() { - _has_version = true; - _major = 1; - _minor = 0; - _filename = get_1_0_filename(); -} - -/** - * Returns true if this file has the same base and extension as the other, - * disregarding the version number; false otherwise. - */ -bool SoftFilename:: -is_same_file(const SoftFilename &other) const { - return _base == other._base && _ext == other._ext; -} - -/** - * Puts filenames in order such that the files with the same base are sorted - * together, ignoring extension; and within files with the same base, files - * are sorted in decreasing version number order so that the most recent - * version appears first. - */ -bool SoftFilename:: -operator < (const SoftFilename &other) const { - if (_base != other._base) { - return _base < other._base; - } - - if (_has_version != other._has_version) { - // If one has a version and the other one doesn't, the one without a - // version comes first. - return _has_version < other._has_version; - } - - if (_has_version) { - if (_major != other._major) { - return _major > other._major; - } - if (_minor != other._minor) { - return _minor > other._minor; - } - } - - return false; -} - -/** - * Sets the flag that indicates whether this file is known to be entered into - * the CVS database. - */ -void SoftFilename:: -set_in_cvs(bool in_cvs) { - _in_cvs = in_cvs; -} - -/** - * Returns true if this file is known to be entered in the CVS database, false - * if it is not. - */ -bool SoftFilename:: -get_in_cvs() const { - return _in_cvs; -} - -/** - * Sets the flag that indicates whether this file should be entered into the - * CVS database. - */ -void SoftFilename:: -set_wants_cvs(bool wants_cvs) { - _wants_cvs = wants_cvs; -} - -/** - * Returns true if this file should be entered into the CVS database, false - * otherwise. - */ -bool SoftFilename:: -get_wants_cvs() const { - return _wants_cvs; -} - -/** - * Indicates that this filename is referenced by one more scene file. - */ -void SoftFilename:: -increment_use_count() { - _use_count++; -} - -/** - * Returns the number of scene files that referenced this filename. - */ -int SoftFilename:: -get_use_count() const { - return _use_count; -} diff --git a/pandatool/src/softprogs/softFilename.h b/pandatool/src/softprogs/softFilename.h deleted file mode 100644 index 0565eabf89..0000000000 --- a/pandatool/src/softprogs/softFilename.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softFilename.h - * @author drose - * @date 2000-11-10 - */ - -#ifndef SOFTFILENAME_H -#define SOFTFILENAME_H - -#include "pandatoolbase.h" - -/** - * This encapsulates a SoftImage versioned filename, of the form base.v-v.ext: - * it consists of a directory name, a base, a major and minor version number, - * and an optional extension. - * - * It also keeps track of whether the named file has been added to CVS, and - * how many scene files it is referenced by, - */ -class SoftFilename { -public: - SoftFilename(const std::string &dirname, const std::string &filename); - SoftFilename(const SoftFilename ©); - void operator = (const SoftFilename ©); - - const std::string &get_dirname() const; - const std::string &get_filename() const; - bool has_version() const; - - std::string get_1_0_filename() const; - - const std::string &get_base() const; - int get_major() const; - int get_minor() const; - const std::string &get_extension() const; - std::string get_non_extension() const; - - bool is_1_0() const; - void make_1_0(); - - bool is_same_file(const SoftFilename &other) const; - bool operator < (const SoftFilename &other) const; - - void set_in_cvs(bool in_cvs); - bool get_in_cvs() const; - - void set_wants_cvs(bool wants_cvs); - bool get_wants_cvs() const; - - void increment_use_count(); - int get_use_count() const; - -private: - std::string _dirname; - std::string _filename; - bool _has_version; - std::string _base; - int _major; - int _minor; - std::string _ext; - bool _in_cvs; - bool _wants_cvs; - int _use_count; -}; - -#endif diff --git a/pandatool/src/xfileegg/xFileMaterial.cxx b/pandatool/src/xfileegg/xFileMaterial.cxx index 11457ebcd5..9eaac25fbd 100644 --- a/pandatool/src/xfileegg/xFileMaterial.cxx +++ b/pandatool/src/xfileegg/xFileMaterial.cxx @@ -18,6 +18,7 @@ #include "eggTexture.h" #include "eggPrimitive.h" #include "datagram.h" +#include "config_xfile.h" #include // for strcmp, strdup diff --git a/pandatool/src/xfileegg/xFileMesh.cxx b/pandatool/src/xfileegg/xFileMesh.cxx index 4fad113ed4..e253ee385d 100644 --- a/pandatool/src/xfileegg/xFileMesh.cxx +++ b/pandatool/src/xfileegg/xFileMesh.cxx @@ -12,6 +12,7 @@ */ #include "xFileMesh.h" +#include "xFileToEggConverter.h" #include "xFileFace.h" #include "xFileVertex.h" #include "xFileNormal.h" @@ -22,6 +23,7 @@ #include "eggVertexPool.h" #include "eggVertex.h" #include "eggPolygon.h" +#include "eggGroup.h" #include "eggGroupNode.h" using std::min; diff --git a/pandatool/src/xfileegg/xFileMesh.h b/pandatool/src/xfileegg/xFileMesh.h index 417d7c4253..339ba2038f 100644 --- a/pandatool/src/xfileegg/xFileMesh.h +++ b/pandatool/src/xfileegg/xFileMesh.h @@ -22,6 +22,8 @@ #include "namable.h" #include "coordinateSystem.h" +#include "luse.h" + class XFileNode; class XFileDataNode; class XFileMesh; diff --git a/pandatool/src/xfileegg/xFileToEggConverter.cxx b/pandatool/src/xfileegg/xFileToEggConverter.cxx index 130c42546e..91ba21ba97 100644 --- a/pandatool/src/xfileegg/xFileToEggConverter.cxx +++ b/pandatool/src/xfileegg/xFileToEggConverter.cxx @@ -19,6 +19,7 @@ #include "eggData.h" #include "eggGroup.h" +#include "eggTable.h" #include "eggXfmSAnim.h" #include "eggGroupUniquifier.h" #include "datagram.h" diff --git a/tests/display/test_color_buffer.py b/tests/display/test_color_buffer.py index dab73cbbb8..d95913b0f7 100644 --- a/tests/display/test_color_buffer.py +++ b/tests/display/test_color_buffer.py @@ -113,14 +113,38 @@ def render_color_pixel(region, state, vertex_color=None): camera.node().get_lens(0).set_near_far(1, 3) camera.node().set_cull_bounds(core.OmniBoundingVolume()) - cm = core.CardMaker("card") - cm.set_frame(-1, 1, -1, 1) + if vertex_color is not None: + format = core.GeomVertexFormat.get_v3cp() + else: + format = core.GeomVertexFormat.get_v3() + + vdata = core.GeomVertexData("card", format, core.Geom.UH_static) + vdata.unclean_set_num_rows(4) + + vertex = core.GeomVertexWriter(vdata, "vertex") + vertex.set_data3(core.Vec3.rfu(-1, 0, 1)) + vertex.set_data3(core.Vec3.rfu(-1, 0, -1)) + vertex.set_data3(core.Vec3.rfu(1, 0, 1)) + vertex.set_data3(core.Vec3.rfu(1, 0, -1)) if vertex_color is not None: - cm.set_color(vertex_color) + color = core.GeomVertexWriter(vdata, "color") + color.set_data4(vertex_color) + color.set_data4(vertex_color) + color.set_data4(vertex_color) + color.set_data4(vertex_color) - card = scene.attach_new_node(cm.generate()) - card.set_state(state) + strip = core.GeomTristrips(core.Geom.UH_static) + strip.set_shade_model(core.Geom.SM_uniform) + strip.add_next_vertices(4) + strip.close_primitive() + + geom = core.Geom(vdata) + geom.add_primitive(strip) + + gnode = core.GeomNode("card") + gnode.add_geom(geom, state) + card = scene.attach_new_node(gnode) card.set_pos(0, 2, 0) card.set_scale(60) @@ -197,14 +221,13 @@ def test_color_empty_vertex(color_region, shader_attrib, material_attrib): def test_color_off_vertex(color_region, shader_attrib, material_attrib): - #XXX This behaviour is really odd. state = core.RenderState.make( core.ColorAttrib.make_off(), shader_attrib, material_attrib, ) result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR) - assert result.almost_equal(TEST_COLOR, FUZZ) + assert result == (1, 1, 1, 1) def test_scaled_color_empty(color_region, shader_attrib, material_attrib): @@ -259,7 +282,6 @@ def test_scaled_color_empty_vertex(color_region, shader_attrib, material_attrib) def test_scaled_color_off_vertex(color_region, shader_attrib, material_attrib): - #XXX This behaviour is really odd. state = core.RenderState.make( core.ColorAttrib.make_off(), core.ColorScaleAttrib.make(TEST_COLOR_SCALE), @@ -267,5 +289,5 @@ def test_scaled_color_off_vertex(color_region, shader_attrib, material_attrib): material_attrib, ) result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR) - assert result.almost_equal(TEST_SCALED_COLOR, FUZZ) + assert result.almost_equal(TEST_COLOR_SCALE, FUZZ) diff --git a/tests/display/test_glsl_shader.py b/tests/display/test_glsl_shader.py index 91816353f6..0a0a5f5737 100644 --- a/tests/display/test_glsl_shader.py +++ b/tests/display/test_glsl_shader.py @@ -10,6 +10,7 @@ from _pytest.outcomes import Failed # The reset() function serves to prevent the _triggered variable from being # optimized out in the case that the assertions are being optimized out. GLSL_COMPUTE_TEMPLATE = """#version {version} +{extensions} layout(local_size_x = 1, local_size_y = 1) in; @@ -37,7 +38,7 @@ void main() {{ """ -def run_glsl_test(gsg, body, preamble="", inputs={}, version=430): +def run_glsl_test(gsg, body, preamble="", inputs={}, version=130, exts=set()): """ Runs a GLSL test on the given GSG. The given body is executed in the main function and should call assert(). The preamble should contain all of the shader inputs. """ @@ -48,11 +49,20 @@ def run_glsl_test(gsg, body, preamble="", inputs={}, version=430): if not gsg.supports_buffer_texture: pytest.skip("buffer textures not supported") + exts = exts | {'GL_ARB_compute_shader', 'GL_ARB_shader_image_load_store'} + missing_exts = sorted(ext for ext in exts if not gsg.has_extension(ext)) + if missing_exts: + pytest.skip("missing extensions: " + ' '.join(missing_exts)) + + extensions = '' + for ext in exts: + extensions += '#extension {ext} : require\n'.format(ext=ext) + __tracebackhide__ = True preamble = preamble.strip() body = body.rstrip().lstrip('\n') - code = GLSL_COMPUTE_TEMPLATE.format(version=version, preamble=preamble, body=body) + code = GLSL_COMPUTE_TEMPLATE.format(version=version, extensions=extensions, preamble=preamble, body=body) line_offset = code[:code.find(body)].count('\n') + 1 shader = core.Shader.make_compute(core.Shader.SL_GLSL, code) assert shader, code @@ -122,7 +132,7 @@ def test_glsl_sampler(gsg): assert(texelFetch(tex1, 0, 0) == vec4(0, 2 / 255.0, 1, 1)); assert(texelFetch(tex2, ivec2(0, 0), 0) == vec4(1.0, 2.0, -3.14, 0.0)); """ - run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2}), code + run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2}) def test_glsl_image(gsg): @@ -142,7 +152,7 @@ def test_glsl_image(gsg): assert(imageLoad(tex1, 0) == vec4(0, 2 / 255.0, 1, 1)); assert(imageLoad(tex2, ivec2(0, 0)) == vec4(1.0, 2.0, -3.14, 0.0)); """ - run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2}), code + run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2}) def test_glsl_ssbo(gsg): @@ -164,7 +174,10 @@ def test_glsl_ssbo(gsg): assert(value1 == 1234567); assert(value2 == -1234567); """ - run_glsl_test(gsg, code, preamble, {'buffer1': buffer1, 'buffer2': buffer2}), code + run_glsl_test(gsg, code, preamble, {'buffer1': buffer1, 'buffer2': buffer2}, + exts={'GL_ARB_shader_storage_buffer_object', + 'GL_ARB_uniform_buffer_object', + 'GL_ARB_shading_language_420pack'}) def test_glsl_int(gsg): @@ -197,8 +210,8 @@ def test_glsl_uint(gsg): uniform uint intmax; """ code = """ - assert(zero == 0); - assert(intmax == 0x7fffffff); + assert(zero == 0u); + assert(intmax == 0x7fffffffu); """ run_glsl_test(gsg, code, preamble, inputs) @@ -243,7 +256,7 @@ def test_glsl_pta_int(gsg): assert(pta[2] == 2); assert(pta[3] == 3); """ - run_glsl_test(gsg, code, preamble, {'pta': pta}), code + run_glsl_test(gsg, code, preamble, {'pta': pta}) def test_glsl_pta_ivec4(gsg): @@ -256,7 +269,7 @@ def test_glsl_pta_ivec4(gsg): assert(pta[0] == ivec4(0, 1, 2, 3)); assert(pta[1] == ivec4(4, 5, 6, 7)); """ - run_glsl_test(gsg, code, preamble, {'pta': pta}), code + run_glsl_test(gsg, code, preamble, {'pta': pta}) def test_glsl_pta_mat4(gsg): @@ -278,7 +291,7 @@ def test_glsl_pta_mat4(gsg): assert(pta[1][2] == vec4(24, 25, 26, 27)); assert(pta[1][3] == vec4(28, 29, 30, 31)); """ - run_glsl_test(gsg, code, preamble, {'pta': pta}), code + run_glsl_test(gsg, code, preamble, {'pta': pta}) def test_glsl_write_extract_image_buffer(gsg): @@ -299,12 +312,12 @@ def test_glsl_write_extract_image_buffer(gsg): layout(r32i) uniform iimageBuffer tex2; """ code = """ - assert(imageLoad(tex1, 0).r == 0); + assert(imageLoad(tex1, 0).r == 0u); assert(imageLoad(tex2, 0).r == 0); imageStore(tex1, 0, uvec4(123)); imageStore(tex2, 0, ivec4(-456)); memoryBarrier(); - assert(imageLoad(tex1, 0).r == 123); + assert(imageLoad(tex1, 0).r == 123u); assert(imageLoad(tex2, 0).r == -456); """ diff --git a/tests/dtoolutil/test_textencoder.py b/tests/dtoolutil/test_textencoder.py new file mode 100644 index 0000000000..ef03c7d826 --- /dev/null +++ b/tests/dtoolutil/test_textencoder.py @@ -0,0 +1,101 @@ +import sys +import pytest +from panda3d.core import TextEncoder + +if sys.version_info >= (3, 0): + unichr = chr + xrange = range + + +def valid_characters(): + """Generator yielding all valid Unicode code points.""" + + for i in xrange(0xd800): + yield unichr(i) + + for i in xrange(0xe000, sys.maxunicode + 1): + if i != 0xfeff and i & 0xfffe != 0xfffe: + yield unichr(i) + + +def test_text_decode_iso8859(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_iso8859) + + for i in xrange(255): + enc = unichr(i).encode('latin-1') + assert len(enc) == 1 + + dec = encoder.decode_text(enc) + assert len(dec) == 1 + assert ord(dec) == i + + +def test_text_decode_utf8(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_utf8) + + for c in valid_characters(): + enc = c.encode('utf-8') + assert len(enc) <= 4 + + dec = encoder.decode_text(enc) + assert len(dec) == 1 + assert dec == c + + +def test_text_decode_utf16be(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_utf16be) + + for c in valid_characters(): + enc = c.encode('utf-16be') + + dec = encoder.decode_text(enc) + assert len(c) == len(dec) + assert c == dec + + +def test_text_encode_iso8859(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_iso8859) + + for i in xrange(255): + c = unichr(i) + enc = encoder.encode_wtext(c) + assert enc == c.encode('latin-1') + + +def test_text_encode_utf8(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_utf8) + + for c in valid_characters(): + enc = encoder.encode_wtext(c) + assert enc == c.encode('utf-8') + + +def test_text_encode_utf16be(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_utf16be) + + for c in valid_characters(): + enc = encoder.encode_wtext(c) + assert enc == c.encode('utf-16-be') + + +def test_text_append_unicode_char(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_iso8859) + + code_points = [] + for code_point in [0, 1, 127, 128, 255, 256, 0xfffd, 0x10000, 0x10ffff]: + if code_point <= sys.maxunicode: + code_points.append(code_point) + encoder.append_unicode_char(code_point) + + encoded = encoder.get_wtext() + assert len(encoded) == len(code_points) + + for a, b in zip(code_points, encoded): + assert a == ord(b) diff --git a/tests/event/test_futures.py b/tests/event/test_futures.py index e120a2ab8e..adef5b33fc 100644 --- a/tests/event/test_futures.py +++ b/tests/event/test_futures.py @@ -1,6 +1,5 @@ from panda3d import core import pytest -import threading import time import sys @@ -39,7 +38,11 @@ def test_future_timeout(): fut.result(0.001) +@pytest.mark.skipif(not core.Thread.is_threading_supported(), + reason="Threading support disabled") def test_future_wait(): + threading = pytest.importorskip("direct.stdpy.threading") + fut = core.AsyncFuture() # Launch a thread to set the result value. @@ -59,7 +62,11 @@ def test_future_wait(): assert fut.result() is None +@pytest.mark.skipif(not core.Thread.is_threading_supported(), + reason="Threading support disabled") def test_future_wait_cancel(): + threading = pytest.importorskip("direct.stdpy.threading") + fut = core.AsyncFuture() # Launch a thread to cancel the future. diff --git a/tests/text/test_textnode.py b/tests/text/test_textnode.py index e96c9e5371..bedc91b0da 100644 --- a/tests/text/test_textnode.py +++ b/tests/text/test_textnode.py @@ -1,6 +1,13 @@ from panda3d import core +def test_textnode_write(): + out = core.StringStream() + text = core.TextNode("test") + text.write(out, 0) + assert out.data.startswith(b"TextNode test") + + def test_textnode_card_as_margin(): text = core.TextNode("test") text.text = "Test"