diff --git a/MaxNifPlugins_Readme.txt b/MaxNifPlugins_Readme.txt index 971f29c0f622152c1ea4a7fe240bc2cc9fcfea42..9573bf8e32d8cf89ea18274a0805f792084cac37 100644 --- a/MaxNifPlugins_Readme.txt +++ b/MaxNifPlugins_Readme.txt @@ -1,4 +1,4 @@ - MaxPlugins 0.1.5 + MaxPlugins 0.2.1 ================ @@ -27,7 +27,12 @@ Change log ---------- - + 0.2.1 + ----- + o Exporter + - Replace the Tri Stripper with a new version. + o The old version had some bugs which came when compiled with VS 2005. + 0.2 ----- o Importer @@ -44,11 +49,15 @@ - Dropped Official Max6 support because I do not have Max 6 to compile it o Try editing the MaxNifTools.ini and setting the MaxSDKVersion to 0x17700d00 - Fixed issue with importing glossiness setting on textures. - - Fixed issues with export of vertex color. Alpha map is now exported as part of the normal color map. + - Fixed issues with export of vertex color. Alpha map is now exported + as part of the normal color map. - No longer exports meshes associated with bone or biped nodes. - - No longer exports extra NiNode when exporting NiTriGeom-based objects (can be reset in ini file) - - Mass, Restitution(Ellasticity), and Friction now share values with Reactor(Havok) - - Modified UPB export to actually export the values in the UserPropBuffer not just a fixed list. + - No longer exports extra NiNode when exporting NiTriGeom-based objects + (can be reset in ini file) + - Mass, Restitution(Ellasticity), and Friction now share values with + Reactor(Havok) + - Modified UPB export to actually export the values in the UserPropBuffer + not just a fixed list. - Added Skin Modifier export - Added support for more material/texture properties - Added support for Civilization IV Shader, if installed @@ -78,7 +87,8 @@ o Importer - Fixed alignment issues when importing Morrowind Armor nifs - - Added initial animation support (only for animations internal to nif, no kf file support yet) + - Added initial animation support (only for animations internal to nif, + no kf file support yet) - Fixed numerous issues with bone system (biped is still broken) - Fixed issues with skin and doac nifs diff --git a/NifExport/NifExport.rc b/NifExport/NifExport.rc index efbb97acbaf89c7f9b54e300fcb1fe00dbc39d73..ddfcbb2a84d4a616844154dc7139a3c57d871fbd 100755 --- a/NifExport/NifExport.rc +++ b/NifExport/NifExport.rc @@ -138,13 +138,13 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,2,0,0 - PRODUCTVERSION 0,2,0,0 - FILEFLAGSMASK 0x37L + FILEVERSION 0,2,1,0 + PRODUCTVERSION 0,2,1,0 + FILEFLAGSMASK 0x17L #ifdef _DEBUG - FILEFLAGS 0x21L + FILEFLAGS 0x1L #else - FILEFLAGS 0x20L + FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x2L @@ -155,13 +155,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "3ds Max Nif Exporter" - VALUE "FileVersion", "0, 2, 0, 0" + VALUE "FileVersion", "0, 2, 1, 0" VALUE "InternalName", "NifExport.dle" VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved." VALUE "OriginalFilename", "NifExport.dle" VALUE "ProductName", "3ds Max Nif Exporter" - VALUE "ProductVersion", "0, 2, 0, 0" - VALUE "SpecialBuild", "Alpha" + VALUE "ProductVersion", "0, 2, 1, 0" END END BLOCK "VarFileInfo" diff --git a/NifExport/NifExport_VC80.vcproj b/NifExport/NifExport_VC80.vcproj index dda568d17180c761d47f363dfe57d6d4527b6597..b128f28abc3df8ecde4bdda6ac78165a12393e3c 100644 --- a/NifExport/NifExport_VC80.vcproj +++ b/NifExport/NifExport_VC80.vcproj @@ -898,6 +898,14 @@ <Filter Name="TriStripper" > + <File + RelativePath=".\TriStripper\connectivity_graph.cpp" + > + </File> + <File + RelativePath=".\TriStripper\policy.cpp" + > + </File> <File RelativePath="TriStripper\tri_stripper.cpp" > @@ -1003,6 +1011,10 @@ RelativePath="TriStripper\heap_array.h" > </File> + <File + RelativePath=".\TriStripper\public_types.h" + > + </File> <File RelativePath="TriStripper\tri_stripper.h" > diff --git a/NifExport/Strips.cpp b/NifExport/Strips.cpp index 8443bb7d7a049f1467b4a70e0b0eaa257131ff40..7ca4f350a6f5b75da98ca927bcb1eaede3a5f649 100755 --- a/NifExport/Strips.cpp +++ b/NifExport/Strips.cpp @@ -15,7 +15,7 @@ void Exporter::strippify(TriStrips &strips, vector<Vector3> &verts, vector<Vecto tri_stripper stripper(idcs); - tri_stripper::primitives_vector groups; + primitive_vector groups; stripper.Strip(&groups); // triangles left over @@ -23,22 +23,22 @@ void Exporter::strippify(TriStrips &strips, vector<Vector3> &verts, vector<Vecto for (i=0; i<groups.size(); i++) { - if (groups[i].m_Type == tri_stripper::PT_Triangle_Strip) + if (groups[i].Type == TRIANGLE_STRIP) { - strips.push_back(TriStrip(groups[i].m_Indices.size())); + strips.push_back(TriStrip(groups[i].Indices.size())); TriStrip &strip = strips.back(); - for (int j=0; j<groups[i].m_Indices.size(); j++) - strip[j] = groups[i].m_Indices[j]; + for (int j=0; j<groups[i].Indices.size(); j++) + strip[j] = groups[i].Indices[j]; } else { int size = stris.size(); - stris.resize(size + groups[i].m_Indices.size()/3); + stris.resize(size + groups[i].Indices.size()/3); for (int j=(size>0)?(size-1):0; j<stris.size(); j++) { - stris[j][0] = groups[i].m_Indices[j*3+0]; - stris[j][1] = groups[i].m_Indices[j*3+1]; - stris[j][2] = groups[i].m_Indices[j*3+2]; + stris[j][0] = groups[i].Indices[j*3+0]; + stris[j][1] = groups[i].Indices[j*3+1]; + stris[j][2] = groups[i].Indices[j*3+2]; } } } diff --git a/NifExport/TriStripper/connectivity_graph.cpp b/NifExport/TriStripper/connectivity_graph.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d0b3898a7b137f51e856381f54cd3b7b100bd0c --- /dev/null +++ b/NifExport/TriStripper/connectivity_graph.cpp @@ -0,0 +1,132 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// For conditions of distribution and use, +// see copyright notice in tri_stripper.h +// +////////////////////////////////////////////////////////////////////// +// SVN: $Id: connectivity_graph.cpp 86 2005-06-08 17:47:27Z gpsnoopy $ +////////////////////////////////////////////////////////////////////// + +#include "detail/connectivity_graph.h" + +#include <algorithm> + + + + +namespace triangle_stripper { + + namespace detail { + + + + +namespace +{ + + class tri_edge : public triangle_edge + { + public: + tri_edge(index A, index B, size_t TriPos) + : triangle_edge(A, B), m_TriPos(TriPos) { } + + size_t TriPos() const { return m_TriPos; } + + private: + size_t m_TriPos; + }; + + + class cmp_tri_edge_lt + { + public: + bool operator() (const tri_edge & a, const tri_edge & b) const; + }; + + + typedef std::vector<tri_edge> edge_map; + + + void LinkNeighbours(graph_array<triangle> & Triangles, const edge_map & EdgeMap, const tri_edge Edge); + +} + + + + +void make_connectivity_graph(graph_array<triangle> & Triangles, const indices & Indices) +{ + assert(Triangles.size() == (Indices.size() / 3)); + + // Fill the triangle data + for (size_t i = 0; i < Triangles.size(); ++i) + Triangles[i] = triangle(Indices[i * 3 + 0], Indices[i * 3 + 1], Indices[i * 3 + 2]); + + // Build an edge lookup table + edge_map EdgeMap; + EdgeMap.reserve(Triangles.size() * 3); + + for (size_t i = 0; i < Triangles.size(); ++i) { + + const triangle & Tri = * Triangles[i]; + + EdgeMap.push_back(tri_edge(Tri.A(), Tri.B(), i)); + EdgeMap.push_back(tri_edge(Tri.B(), Tri.C(), i)); + EdgeMap.push_back(tri_edge(Tri.C(), Tri.A(), i)); + } + + std::sort(EdgeMap.begin(), EdgeMap.end(), cmp_tri_edge_lt()); + + // Link neighbour triangles together using the lookup table + for (size_t i = 0; i < Triangles.size(); ++i) { + + const triangle & Tri = * Triangles[i]; + + LinkNeighbours(Triangles, EdgeMap, tri_edge(Tri.B(), Tri.A(), i)); + LinkNeighbours(Triangles, EdgeMap, tri_edge(Tri.C(), Tri.B(), i)); + LinkNeighbours(Triangles, EdgeMap, tri_edge(Tri.A(), Tri.C(), i)); + } +} + + + +namespace +{ + + inline bool cmp_tri_edge_lt::operator() (const tri_edge & a, const tri_edge & b) const + { + const index A1 = a.A(); + const index B1 = a.B(); + const index A2 = b.A(); + const index B2 = b.B(); + + if ((A1 < A2) || ((A1 == A2) && (B1 < B2))) + return true; + else + return false; + } + + + void LinkNeighbours(graph_array<triangle> & Triangles, const edge_map & EdgeMap, const tri_edge Edge) + { + // Find the first edge equal to Edge + edge_map::const_iterator it = std::lower_bound(EdgeMap.begin(), EdgeMap.end(), Edge, cmp_tri_edge_lt()); + + // See if there are any other edges that are equal + // (if so, it means that more than 2 triangles are sharing the same edge, + // which is unlikely but not impossible) + for (; (it != EdgeMap.end()) && (Edge == (* it)); ++it) + Triangles.insert_arc(Edge.TriPos(), it->TriPos()); + + // Note: degenerated triangles will also point themselves as neighbour triangles + } + +} + + + + + } // namespace detail + +} // namespace detail + diff --git a/NifExport/TriStripper/policy.cpp b/NifExport/TriStripper/policy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd62563ac80d4ef1ac6f75bac5ec0acdc8d2eb16 --- /dev/null +++ b/NifExport/TriStripper/policy.cpp @@ -0,0 +1,63 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// For conditions of distribution and use, +// see copyright notice in tri_stripper.h +// +////////////////////////////////////////////////////////////////////// +// SVN: $Id: policy.cpp 86 2005-06-08 17:47:27Z gpsnoopy $ +////////////////////////////////////////////////////////////////////// + +#include "detail/policy.h" + + + + +namespace triangle_stripper { + + namespace detail { + + + + +void policy::Challenge(strip Strip, size_t Degree, size_t CacheHits) +{ + if (Strip.Size() < m_MinStripSize) + return; + + // Cache is disabled, take the longest strip + if (! m_Cache) { + + if (Strip.Size() > m_Strip.Size()) + m_Strip = Strip; + + // Cache simulator enabled + } else { + + // Priority 1: Keep the strip with the best cache hit count + if (CacheHits > m_CacheHits) { + m_Strip = Strip; + m_Degree = Degree; + m_CacheHits = CacheHits; + + } else if (CacheHits == m_CacheHits) { + + // Priority 2: Keep the strip with the loneliest start triangle + if ((m_Strip.Size() != 0) && (Degree < m_Degree)) { + m_Strip = Strip; + m_Degree = Degree; + + // Priority 3: Keep the longest strip + } else if (Strip.Size() > m_Strip.Size()) { + m_Strip = Strip; + m_Degree = Degree; + } + } + } +} + + + + + } // namespace detail + +} // namespace triangle_stripper diff --git a/NifExport/TriStripper/public_types.h b/NifExport/TriStripper/public_types.h new file mode 100644 index 0000000000000000000000000000000000000000..5fc7cd15640254ce9fc78c3287daa9eb3c6dfd3a --- /dev/null +++ b/NifExport/TriStripper/public_types.h @@ -0,0 +1,43 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// For conditions of distribution and use, +// see copyright notice in tri_stripper.h +// +////////////////////////////////////////////////////////////////////// +// SVN: $Id: public_types.h 86 2005-06-08 17:47:27Z gpsnoopy $ +////////////////////////////////////////////////////////////////////// + +#ifndef TRI_STRIPPER_HEADER_GUARD_PUBLIC_TYPES_H +#define TRI_STRIPPER_HEADER_GUARD_PUBLIC_TYPES_H + +#include <vector> + + + + +namespace triangle_stripper +{ + + typedef size_t index; + typedef std::vector<index> indices; + + enum primitive_type + { + TRIANGLES = 0x0004, // = GL_TRIANGLES + TRIANGLE_STRIP = 0x0005 // = GL_TRIANGLE_STRIP + }; + + struct primitive_group + { + indices Indices; + primitive_type Type; + }; + + typedef std::vector<primitive_group> primitive_vector; + +} + + + + +#endif // TRI_STRIPPER_HEADER_GUARD_PUBLIC_TYPES_H diff --git a/NifExport/TriStripper/tri_stripper.cpp b/NifExport/TriStripper/tri_stripper.cpp index 3c1d44d3eee2f6f6f0021b171d8661bc5de6d5a7..feb17ac49db3c33cd7d19bd89ce5f0ec4a20beee 100755 --- a/NifExport/TriStripper/tri_stripper.cpp +++ b/NifExport/TriStripper/tri_stripper.cpp @@ -1,450 +1,379 @@ -// tri_stripper.cpp: implementation of the Tri Stripper class. // -// Copyright (C) 2002 Tanguy Fautré. +// Copyright (C) 2004 Tanguy Fautré. // For conditions of distribution and use, // see copyright notice in tri_stripper.h // ////////////////////////////////////////////////////////////////////// - - -#include <assert.h> -#include <deque> -#include <algorithm> -#include <fstream> -#include <iostream> -#include <list> -#include <map> -#include <string> -#include <vector> +// SVN: $Id: tri_stripper.cpp 86 2005-06-08 17:47:27Z gpsnoopy $ +////////////////////////////////////////////////////////////////////// #include "tri_stripper.h" +#include "detail/connectivity_graph.h" +#include "detail/policy.h" +#include <cassert> -// namespace triangle_stripper -namespace triangle_stripper { - +namespace triangle_stripper { -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// + using namespace detail; -////////////////////////////////////////////////////////////////////// -// Members Functions -////////////////////////////////////////////////////////////////////// -void tri_stripper::Strip(primitives_vector * out_pPrimitivesVector) +tri_stripper::tri_stripper(const indices & TriIndices) + : m_Triangles(TriIndices.size() / 3), // Silently ignore extra indices if (Indices.size() % 3 != 0) + m_StripID(0), + m_FirstRun(true) { - // verify that the number of indices is correct - if (m_TriIndices.size() % 3 != 0) - throw triangles_indices_error(); - - // clear possible garbage - m_PrimitivesVector.clear(); - out_pPrimitivesVector->clear(); - - // Initialize the triangle graph - InitTriGraph(); - - // Initialize the triangle priority queue - InitTriHeap(); - - // Reset the cache simulator - InitCache(); - - // Launch the triangle strip generator - Stripify(); - - // Add the triangles that couldn't be stripped - AddLeftTriangles(); + SetCacheSize(); + SetMinStripSize(); + SetBackwardSearch(); + SetPushCacheHits(); - // Free ressources - m_Triangles.clear(); - - // Put the results into the user's vector - std::swap(m_PrimitivesVector, (* out_pPrimitivesVector)); + make_connectivity_graph(m_Triangles, TriIndices); } -void tri_stripper::InitTriGraph() +void tri_stripper::Strip(primitive_vector * out_pPrimitivesVector) { - // Set up the graph size and complete the triangles data - // note: setsize() completely resets the graph as well as the node markers - m_Triangles.setsize(m_TriIndices.size() / 3); - - for (size_t i = 0; i < m_Triangles.size(); ++i) - m_Triangles[i] = triangle(m_TriIndices[i * 3 + 0], m_TriIndices[i * 3 + 1], m_TriIndices[i * 3 + 2]); - - // Build the edges lookup table - triangle_edges TriInterface; - TriInterface.reserve(m_Triangles.size() * 3); + assert(out_pPrimitivesVector); - for (size_t i = 0; i < m_Triangles.size(); ++i) { - TriInterface.push_back(triangle_edge(m_Triangles[i]->A(), m_Triangles[i]->B(), i)); - TriInterface.push_back(triangle_edge(m_Triangles[i]->B(), m_Triangles[i]->C(), i)); - TriInterface.push_back(triangle_edge(m_Triangles[i]->C(), m_Triangles[i]->A(), i)); - } - - // Sort the lookup table for faster searches - std::sort(TriInterface.begin(), TriInterface.end(), _cmp_tri_interface_lt()); - - // Link neighbour triangles together using the edges lookup table - for (size_t i = 0; i < m_Triangles.size(); ++i) { + if (! m_FirstRun) { + unmark_nodes(m_Triangles); + ResetStripIDs(); + m_Cache.reset(); + m_TriHeap.clear(); + m_Candidates.clear(); + m_StripID = 0; - const triangle_edge EdgeBA(m_Triangles[i]->B(), m_Triangles[i]->A(), i); - const triangle_edge EdgeCB(m_Triangles[i]->C(), m_Triangles[i]->B(), i); - const triangle_edge EdgeAC(m_Triangles[i]->A(), m_Triangles[i]->C(), i); - - LinkNeighboursTri(TriInterface, EdgeBA); - LinkNeighboursTri(TriInterface, EdgeCB); - LinkNeighboursTri(TriInterface, EdgeAC); + m_FirstRun = false; } -} + out_pPrimitivesVector->clear(); + InitTriHeap(); -void tri_stripper::LinkNeighboursTri(const triangle_edges & TriInterface, const triangle_edge Edge) -{ - typedef triangle_edges::const_iterator edge_const_it; - - // Find the first edge equal to Edge - edge_const_it It = std::lower_bound(TriInterface.begin(), TriInterface.end(), Edge, _cmp_tri_interface_lt()); - - // See if there are any other edges that are equal - // (if so, it means that more than 2 triangles are sharing the same edge, - // which is unlikely but not impossible) - for (; (It != TriInterface.end()) && ((It->A() == Edge.A()) && (It->B() == Edge.B())); ++It) - m_Triangles.insert(Edge.TriPos(), It->TriPos()); - - // Note: degenerated triangles will also point themselves as neighbour triangles + Stripify(); + AddLeftTriangles(); + + std::swap(m_PrimitivesVector, (* out_pPrimitivesVector)); } void tri_stripper::InitTriHeap() { - m_TriHeap.clear(); m_TriHeap.reserve(m_Triangles.size()); // Set up the triangles priority queue // The lower the number of available neighbour triangles, the higher the priority. for (size_t i = 0; i < m_Triangles.size(); ++i) - m_TriHeap.push(triangle_degree(i, m_Triangles[i].number_of_out_arcs())); + m_TriHeap.push(m_Triangles[i].out_size()); + + // We're not going to add new elements anymore + m_TriHeap.lock(); // Remove useless triangles - // (Note: we had to put all of them into the heap before to ensure coherency of the heap_array object) - while ((! m_TriHeap.empty()) && (m_TriHeap.top().Degree() == 0)) + // Note: we had to put all of them into the heap before to ensure coherency of the heap_array object + while ((! m_TriHeap.empty()) && (m_TriHeap.top() == 0)) m_TriHeap.pop(); } -void tri_stripper::InitCache() +void tri_stripper::ResetStripIDs() { - m_Cache.reset(); + for (triangle_graph::node_iterator it = m_Triangles.begin(); it != m_Triangles.end(); ++it) + (**it).ResetStripID(); } void tri_stripper::Stripify() { - // Reset the triangle strip id selector - m_StripID = 0; - - // Reset the candidate list - m_NextCandidates.clear(); - - // Loop untill there is no available candidate triangle left while (! m_TriHeap.empty()) { // There is no triangle in the candidates list, refill it with the loneliest triangle - const size_t HeapTop = m_TriHeap.top().TriPos(); - m_NextCandidates.push_back(HeapTop); + const size_t HeapTop = m_TriHeap.position(0); + m_Candidates.push_back(HeapTop); - // Loop while BuildStrip can find good candidates for us - while (! m_NextCandidates.empty()) { + while (! m_Candidates.empty()) { - // Choose the best strip containing that triangle - // Note: FindBestStrip empties m_NextCandidates - const triangle_strip TriStrip = FindBestStrip(); + // Note: FindBestStrip empties the candidate list, while BuildStrip refills it + const strip TriStrip = FindBestStrip(); - // Build it if it's long enough, otherwise discard it - // Note: BuildStrip refills m_NextCandidates if (TriStrip.Size() >= m_MinStripSize) BuildStrip(TriStrip); } - // We must discard the triangle we inserted in the candidate list from the heap - // if it led to nothing. (We simply removed it if it hasn't been removed by BuildStrip() yet) if (! m_TriHeap.removed(HeapTop)) m_TriHeap.erase(HeapTop); // Eliminate all the triangles that have now become useless - while ((! m_TriHeap.empty()) && (m_TriHeap.top().Degree() == 0)) + while ((! m_TriHeap.empty()) && (m_TriHeap.top() == 0)) m_TriHeap.pop(); } } -inline tri_stripper::triangle_strip tri_stripper::FindBestStrip() +inline strip tri_stripper::FindBestStrip() { - triangle_strip BestStrip; - size_t BestStripDegree = 0; - size_t BestStripCacheHits = 0; - - // Backup the cache, because it'll be erased during the simulations + // Allow to restore the cache (modified by ExtendTriToStrip) and implicitly reset the cache hit count const cache_simulator CacheBackup = m_Cache; - while (! m_NextCandidates.empty()) { + policy Policy(m_MinStripSize, Cache()); - // Discard useless triangles from the candidates list - if ((m_Triangles[m_NextCandidates.back()].marked()) || (m_TriHeap[m_NextCandidates.back()].Degree() == 0)) { - m_NextCandidates.pop_back(); + while (! m_Candidates.empty()) { - // "continue" is evil! But it really makes things easier here. - // The useless triangle is discarded, and the "while" just rebegins again - continue; - } + const size_t Candidate = m_Candidates.back(); + m_Candidates.pop_back(); - // Invariant: (CandidateTri's Degree() >= 1) && (CandidateTri is not marked). - // So it can directly be used. - const size_t CandidateTri = m_NextCandidates.back(); - m_NextCandidates.pop_back(); + // Discard useless triangles from the candidate list + if ((m_Triangles[Candidate].marked()) || (m_TriHeap[Candidate] == 0)) + continue; - // Try to extend the triangle in the 3 possible directions + // Try to extend the triangle in the 3 possible forward directions for (size_t i = 0; i < 3; ++i) { - // Try a new strip with that triangle in a particular direction - const triangle_strip TempStrip = ExtendTriToStrip(CandidateTri, triangle_strip::start_order(i)); - - // We want to keep the best strip - // Discard strips that don't match the minimum required size - if (TempStrip.Size() >= m_MinStripSize) { - - // Cache simulator disabled? - if (m_Cache.size() == 0) { - - // Cache is disabled, take the longest strip - if (TempStrip.Size() > BestStrip.Size()) - BestStrip = TempStrip; + const strip Strip = ExtendToStrip(Candidate, triangle_order(i)); + Policy.Challenge(Strip, m_TriHeap[Strip.Start()], m_Cache.hitcount()); + + m_Cache = CacheBackup; + } - // Cache simulator enabled - // Use other criteria to find the "best" strip - } else { + // Try to extend the triangle in the 6 possible backward directions + if (m_BackwardSearch) { - // Priority 1: Keep the strip with the best cache hit count - if (m_Cache.HitCount() > BestStripCacheHits) { - BestStrip = TempStrip; - BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree(); - BestStripCacheHits = m_Cache.HitCount(); + for (size_t i = 0; i < 3; ++i) { - } else if (m_Cache.HitCount() == BestStripCacheHits) { + const strip Strip = BackExtendToStrip(Candidate, triangle_order(i), false); + Policy.Challenge(Strip, m_TriHeap[Strip.Start()], m_Cache.hitcount()); + + m_Cache = CacheBackup; + } - // Priority 2: Keep the strip with the loneliest start triangle - if ((BestStrip.Size() != 0) && (m_TriHeap[TempStrip.StartTriPos()].Degree() < BestStripDegree)) { - BestStrip = TempStrip; - BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree(); + for (size_t i = 0; i < 3; ++i) { - // Priority 3: Keep the longest strip - } else if (TempStrip.Size() > BestStrip.Size()) { - BestStrip = TempStrip; - BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree(); - } - } - } + const strip Strip = BackExtendToStrip(Candidate, triangle_order(i), true); + Policy.Challenge(Strip, m_TriHeap[Strip.Start()], m_Cache.hitcount()); + + m_Cache = CacheBackup; } - - // Restore the cache (modified by ExtendTriToStrip) and implicitly reset the cache hit count - m_Cache = CacheBackup; } } - return BestStrip; + return Policy.BestStrip(); } -tri_stripper::triangle_strip tri_stripper::ExtendTriToStrip(const size_t StartTriPos, const triangle_strip::start_order StartOrder) +strip tri_stripper::ExtendToStrip(const size_t Start, triangle_order Order) { - typedef triangles_graph::const_out_arc_iterator const_tri_link_iter; - typedef triangles_graph::node_iterator tri_node_iter; + const triangle_order StartOrder = Order; + + // Begin a new strip + m_Triangles[Start]->SetStripID(++m_StripID); + AddTriangle(* m_Triangles[Start], Order, false); size_t Size = 1; bool ClockWise = false; - triangle_strip::start_order Order = StartOrder; - // Begin a new strip - ++m_StripID; + // Loop while we can further extend the strip + for (tri_iterator Node = (m_Triangles.begin() + Start); + (Node != m_Triangles.end()) && (!Cache() || ((Size + 2) < CacheSize())); + ++Size) { - // Mark the first triangle as used for this strip - m_Triangles[StartTriPos]->SetStripID(m_StripID); + const const_link_iterator Link = LinkToNeighbour(Node, ClockWise, Order, false); - // Update the cache - AddTriToCache((* m_Triangles[StartTriPos]), Order); + // Is it the end of the strip? + if (Link == Node->out_end()) { + Node = m_Triangles.end(); + --Size; - // Loop while we can further extend the strip - for (tri_node_iter TriNodeIt = (m_Triangles.begin() + StartTriPos); - (TriNodeIt != m_Triangles.end()) && ((m_Cache.size() == 0) || ((Size + 2) < m_Cache.size())); - ++Size) { + } else { - // Get the triangle edge that would lead to the next triangle - const triangle_edge Edge = GetLatestEdge(** TriNodeIt, Order); + Node = Link->terminal(); + (* Node)->SetStripID(m_StripID); + ClockWise = ! ClockWise; - // Link to a neighbour triangle - const_tri_link_iter LinkIt; - for (LinkIt = TriNodeIt->out_begin(); LinkIt != TriNodeIt->out_end(); ++LinkIt) { + } + } - // Get the reference to the possible next triangle - const triangle & Tri = (** (LinkIt->terminal())); + return strip(Start, StartOrder, Size); +} - // Check whether it's already been used - if ((Tri.StripID() != m_StripID) && (! (LinkIt->terminal()->marked()))) { - // Does the current candidate triangle match the required for the strip? - if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) { - Order = (ClockWise) ? triangle_strip::ABC : triangle_strip::BCA; - AddIndexToCache(Tri.C(), true); - break; - } +strip tri_stripper::BackExtendToStrip(size_t Start, triangle_order Order, bool ClockWise) +{ + // Begin a new strip + m_Triangles[Start]->SetStripID(++m_StripID); + BackAddIndex(LastEdge(* m_Triangles[Start], Order).B()); + size_t Size = 1; - else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) { - Order = (ClockWise) ? triangle_strip::BCA : triangle_strip::CAB; - AddIndexToCache(Tri.A(), true); - break; - } + tri_iterator Node; - else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) { - Order = (ClockWise) ? triangle_strip::CAB : triangle_strip::ABC; - AddIndexToCache(Tri.B(), true); - break; - } - } - } + // Loop while we can further extend the strip + for (Node = (m_Triangles.begin() + Start); + !Cache() || ((Size + 2) < CacheSize()); + ++Size) { + + const const_link_iterator Link = BackLinkToNeighbour(Node, ClockWise, Order); // Is it the end of the strip? - if (LinkIt == TriNodeIt->out_end()) { - TriNodeIt = m_Triangles.end(); - --Size; - } else { - TriNodeIt = LinkIt->terminal(); - - // Setup for the next triangle - (* TriNodeIt)->SetStripID(m_StripID); + if (Link == Node->out_end()) + break; + + else { + Node = Link->terminal(); + (* Node)->SetStripID(m_StripID); ClockWise = ! ClockWise; } } + // We have to start from a counterclockwise triangle. + // Simply return an empty strip in the case where the first triangle is clockwise. + // Even though we could discard the first triangle and start from the next counterclockwise triangle, + // this often leads to more lonely triangles afterward. + if (ClockWise) + return strip(); + + if (Cache()) { + m_Cache.merge(m_BackCache, Size); + m_BackCache.reset(); + } - return triangle_strip(StartTriPos, StartOrder, Size); + return strip(Node - m_Triangles.begin(), Order, Size); } -inline tri_stripper::triangle_edge tri_stripper::GetLatestEdge(const triangle & Triangle, const triangle_strip::start_order Order) const +void tri_stripper::BuildStrip(const strip Strip) { - switch (Order) { - case triangle_strip::ABC: - return triangle_edge(Triangle.B(), Triangle.C(), 0); - case triangle_strip::BCA: - return triangle_edge(Triangle.C(), Triangle.A(), 0); - case triangle_strip::CAB: - return triangle_edge(Triangle.A(), Triangle.B(), 0); - default: - return triangle_edge(0, 0, 0); - } -} + const size_t Start = Strip.Start(); + bool ClockWise = false; + triangle_order Order = Strip.Order(); + // Create a new strip + m_PrimitivesVector.push_back(primitive_group()); + m_PrimitivesVector.back().Type = TRIANGLE_STRIP; + AddTriangle(* m_Triangles[Start], Order, true); + MarkTriAsTaken(Start); -void tri_stripper::BuildStrip(const triangle_strip TriStrip) -{ - typedef triangles_graph::const_out_arc_iterator const_tri_link_iter; - typedef triangles_graph::node_iterator tri_node_iter; + // Loop while we can further extend the strip + tri_iterator Node = (m_Triangles.begin() + Start); - const size_t StartTriPos = TriStrip.StartTriPos(); + for (size_t Size = 1; Size < Strip.Size(); ++Size) { - bool ClockWise = false; - triangle_strip::start_order Order = TriStrip.StartOrder(); + const const_link_iterator Link = LinkToNeighbour(Node, ClockWise, Order, true); - // Create a new strip - m_PrimitivesVector.push_back(primitives()); - m_PrimitivesVector.back().m_Type = PT_Triangle_Strip; + assert(Link != Node->out_end()); - // Put the first triangle into the strip - AddTriToIndices((* m_Triangles[StartTriPos]), Order); + // Go to the next triangle + Node = Link->terminal(); + MarkTriAsTaken(Node - m_Triangles.begin()); + ClockWise = ! ClockWise; + } +} - // Mark the first triangle as used - MarkTriAsTaken(StartTriPos); - // Loop while we can further extend the strip - tri_node_iter TriNodeIt = (m_Triangles.begin() + StartTriPos); +inline tri_stripper::const_link_iterator tri_stripper::LinkToNeighbour(const const_tri_iterator Node, const bool ClockWise, triangle_order & Order, const bool NotSimulation) +{ + const triangle_edge Edge = LastEdge(** Node, Order); - for (size_t Size = 1; Size < TriStrip.Size(); ++Size) { + for (const_link_iterator Link = Node->out_begin(); Link != Node->out_end(); ++Link) { - // Get the triangle edge that would lead to the next triangle - const triangle_edge Edge = GetLatestEdge(** TriNodeIt, Order); + // Get the reference to the possible next triangle + const triangle & Tri = ** Link->terminal(); - // Link to a neighbour triangle - const_tri_link_iter LinkIt; - for (LinkIt = TriNodeIt->out_begin(); LinkIt != TriNodeIt->out_end(); ++LinkIt) { + // Check whether it's already been used + if (NotSimulation || (Tri.StripID() != m_StripID)) { - // Get the reference to the possible next triangle - const triangle & Tri = (** (LinkIt->terminal())); + if (! Link->terminal()->marked()) { - // Check whether it's already been used - if (! (LinkIt->terminal()->marked())) { + // Does the current candidate triangle match the required position for the strip? - // Does the current candidate triangle match the required for the strip? - // If it does, then add it to the Indices if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) { - Order = (ClockWise) ? triangle_strip::ABC : triangle_strip::BCA; - AddIndex(Tri.C()); - break; + Order = (ClockWise) ? ABC : BCA; + AddIndex(Tri.C(), NotSimulation); + return Link; } else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) { - Order = (ClockWise) ? triangle_strip::BCA : triangle_strip::CAB; - AddIndex(Tri.A()); - break; + Order = (ClockWise) ? BCA : CAB; + AddIndex(Tri.A(), NotSimulation); + return Link; } else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) { - Order = (ClockWise) ? triangle_strip::CAB : triangle_strip::ABC; - AddIndex(Tri.B()); - break; + Order = (ClockWise) ? CAB : ABC; + AddIndex(Tri.B(), NotSimulation); + return Link; } } } - // Debug check: we must have found the next triangle - assert(LinkIt != TriNodeIt->out_end()); + } + + return Node->out_end(); +} + + + +inline tri_stripper::const_link_iterator tri_stripper::BackLinkToNeighbour(const_tri_iterator Node, bool ClockWise, triangle_order & Order) +{ + const triangle_edge Edge = FirstEdge(** Node, Order); + + for (const_link_iterator Link = Node->out_begin(); Link != Node->out_end(); ++Link) { + + // Get the reference to the possible previous triangle + const triangle & Tri = ** Link->terminal(); + + // Check whether it's already been used + if ((Tri.StripID() != m_StripID) && ! Link->terminal()->marked()) { + + // Does the current candidate triangle match the required position for the strip? + + if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) { + Order = (ClockWise) ? CAB : BCA; + BackAddIndex(Tri.C()); + return Link; + } + + else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) { + Order = (ClockWise) ? ABC : CAB; + BackAddIndex(Tri.A()); + return Link; + } + + else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) { + Order = (ClockWise) ? BCA : ABC; + BackAddIndex(Tri.B()); + return Link; + } + } - // Go to the next triangle - TriNodeIt = LinkIt->terminal(); - MarkTriAsTaken(TriNodeIt - m_Triangles.begin()); - - // Setup for the next triangle - ClockWise = ! ClockWise; } + + return Node->out_end(); } void tri_stripper::MarkTriAsTaken(const size_t i) { - typedef triangles_graph::node_iterator tri_node_iter; - typedef triangles_graph::out_arc_iterator tri_link_iter; + typedef triangle_graph::node_iterator tri_node_iter; + typedef triangle_graph::out_arc_iterator tri_link_iter; // Mark the triangle node m_Triangles[i].mark(); @@ -454,88 +383,132 @@ void tri_stripper::MarkTriAsTaken(const size_t i) m_TriHeap.erase(i); // Adjust the degree of available neighbour triangles - for (tri_link_iter LinkIt = m_Triangles[i].out_begin(); LinkIt != m_Triangles[i].out_end(); ++LinkIt) { + for (tri_link_iter Link = m_Triangles[i].out_begin(); Link != m_Triangles[i].out_end(); ++Link) { - const size_t j = LinkIt->terminal() - m_Triangles.begin(); + const size_t j = Link->terminal() - m_Triangles.begin(); if ((! m_Triangles[j].marked()) && (! m_TriHeap.removed(j))) { - triangle_degree NewDegree = m_TriHeap.peek(j); - NewDegree.SetDegree(NewDegree.Degree() - 1); + size_t NewDegree = m_TriHeap.peek(j); + NewDegree = NewDegree - 1; m_TriHeap.update(j, NewDegree); // Update the candidate list if cache is enabled - if ((m_Cache.size() > 0) && (NewDegree.Degree() > 0)) - m_NextCandidates.push_back(j); + if (Cache() && (NewDegree > 0)) + m_Candidates.push_back(j); } } } -inline void tri_stripper::AddIndexToCache(const index i, bool CacheHitCount) +inline triangle_edge tri_stripper::FirstEdge(const triangle & Triangle, const triangle_order Order) { - // Cache simulator enabled? - if (m_Cache.size() > 0) - m_Cache.push(i, CacheHitCount); + switch (Order) + { + case ABC: + return triangle_edge(Triangle.A(), Triangle.B()); + + case BCA: + return triangle_edge(Triangle.B(), Triangle.C()); + + case CAB: + return triangle_edge(Triangle.C(), Triangle.A()); + + default: + assert(false); + return triangle_edge(0, 0); + } +} + + + +inline triangle_edge tri_stripper::LastEdge(const triangle & Triangle, const triangle_order Order) +{ + switch (Order) + { + case ABC: + return triangle_edge(Triangle.B(), Triangle.C()); + + case BCA: + return triangle_edge(Triangle.C(), Triangle.A()); + + case CAB: + return triangle_edge(Triangle.A(), Triangle.B()); + + default: + assert(false); + return triangle_edge(0, 0); + } } -inline void tri_stripper::AddIndex(const index i) +inline void tri_stripper::AddIndex(const index i, const bool NotSimulation) { - // Add the index to the current indices array - m_PrimitivesVector.back().m_Indices.push_back(i); + if (Cache()) + m_Cache.push(i, ! NotSimulation); + + if (NotSimulation) + m_PrimitivesVector.back().Indices.push_back(i); +} + + - // Run cache simulator - AddIndexToCache(i); +inline void tri_stripper::BackAddIndex(const index i) +{ + if (Cache()) + m_BackCache.push(i, true); } -inline void tri_stripper::AddTriToCache(const triangle & Tri, const triangle_strip::start_order Order) +inline void tri_stripper::AddTriangle(const triangle & Tri, const triangle_order Order, const bool NotSimulation) { - // Add Tri indices in the right order into the indices cache simulator. - // And enable the cache hit count - switch (Order) { - case triangle_strip::ABC: - AddIndexToCache(Tri.A(), true); - AddIndexToCache(Tri.B(), true); - AddIndexToCache(Tri.C(), true); - return; - case triangle_strip::BCA: - AddIndexToCache(Tri.B(), true); - AddIndexToCache(Tri.C(), true); - AddIndexToCache(Tri.A(), true); - return; - case triangle_strip::CAB: - AddIndexToCache(Tri.C(), true); - AddIndexToCache(Tri.A(), true); - AddIndexToCache(Tri.B(), true); - return; + switch (Order) + { + case ABC: + AddIndex(Tri.A(), NotSimulation); + AddIndex(Tri.B(), NotSimulation); + AddIndex(Tri.C(), NotSimulation); + break; + + case BCA: + AddIndex(Tri.B(), NotSimulation); + AddIndex(Tri.C(), NotSimulation); + AddIndex(Tri.A(), NotSimulation); + break; + + case CAB: + AddIndex(Tri.C(), NotSimulation); + AddIndex(Tri.A(), NotSimulation); + AddIndex(Tri.B(), NotSimulation); + break; } } -inline void tri_stripper::AddTriToIndices(const triangle & Tri, const triangle_strip::start_order Order) +inline void tri_stripper::BackAddTriangle(const triangle & Tri, const triangle_order Order) { - // Add Tri indices in the right order into the latest Indices vector. - switch (Order) { - case triangle_strip::ABC: - AddIndex(Tri.A()); - AddIndex(Tri.B()); - AddIndex(Tri.C()); - return; - case triangle_strip::BCA: - AddIndex(Tri.B()); - AddIndex(Tri.C()); - AddIndex(Tri.A()); - return; - case triangle_strip::CAB: - AddIndex(Tri.C()); - AddIndex(Tri.A()); - AddIndex(Tri.B()); - return; + switch (Order) + { + case ABC: + BackAddIndex(Tri.C()); + BackAddIndex(Tri.B()); + BackAddIndex(Tri.A()); + break; + + case BCA: + BackAddIndex(Tri.A()); + BackAddIndex(Tri.C()); + BackAddIndex(Tri.B()); + break; + + case CAB: + BackAddIndex(Tri.B()); + BackAddIndex(Tri.A()); + BackAddIndex(Tri.C()); + break; } } @@ -543,12 +516,11 @@ inline void tri_stripper::AddTriToIndices(const triangle & Tri, const triangle_s void tri_stripper::AddLeftTriangles() { - // Create the latest indices array - // and fill it with all the triangles that couldn't be stripped - primitives Primitives; - Primitives.m_Type = PT_Triangles; + // Create the last indices array and fill it with all the triangles that couldn't be stripped + primitive_group Primitives; + Primitives.Type = TRIANGLES; m_PrimitivesVector.push_back(Primitives); - indices & Indices = m_PrimitivesVector.back().m_Indices; + indices & Indices = m_PrimitivesVector.back().Indices; for (size_t i = 0; i < m_Triangles.size(); ++i) if (! m_Triangles[i].marked()) { @@ -564,5 +536,19 @@ void tri_stripper::AddLeftTriangles() +inline bool tri_stripper::Cache() const +{ + return (m_Cache.size() != 0); +} + + + +inline size_t tri_stripper::CacheSize() const +{ + return m_Cache.size(); +} + + + } // namespace triangle_stripper diff --git a/NifExport/TriStripper/tri_stripper.h b/NifExport/TriStripper/tri_stripper.h index 45e0f7a61802adee8a76621ab65b7add4a6ef8a5..feacf5ac5145692c0d1066ff62a9560bf9fff1d6 100755 --- a/NifExport/TriStripper/tri_stripper.h +++ b/NifExport/TriStripper/tri_stripper.h @@ -1,8 +1,7 @@ -// tri_stripper.h: interface for the tri_stripper class. -// + ////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2002 Tanguy Fautré. +// Copyright (C) 2004 Tanguy Fautré. // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -21,60 +20,48 @@ // 3. This notice may not be removed or altered from any source distribution. // // Tanguy Fautré -// softdev@pandora.be +// softdev@telenet.be // ////////////////////////////////////////////////////////////////////// // // Tri Stripper // ************ // -// Current version: 1.00 Final (23/04/2003) -// -// Comment: Triangle stripper in O(n.log(n)). -// -// Currently there are no protection against crazy values -// given via SetMinStripSize() and SetCacheSize(). -// So be careful. (Min. strip size should be equal or greater -// than 2, cache size should be about 10 for GeForce 256/2 -// and about 10-16 for GeForce 3/4.) +// Post TnL cache aware triangle stripifier in O(n.log(n)). // -// History: - 1.00 FINAL (23/04/2003) - Separated cache simulator into another class -// - Fixed English: "indice" -> "index" -// - Fixed one or two points for better compatibility -// with newer compilers (VC++ .NET 2003) -// - 1.00 BETA 5 (10/12/2002) - Fixed a bug in Stripify() that could sometimes -// cause it to go into an infinite loop. -// (thanks to Remy for the bug report) -// - 1.00 BETA 4 (18/11/2002) - Removed the dependency on OpenGL: -// modified gl_primitives to primitives, -// and gl_primitives_vector to primitives_vector; -// and added primitive_type. -// (thanks to Patrik for noticing this useless dependency) -// - 1.00 BETA 3 (18/11/2002) - Fixed a bug in LinkNeightboursTri() that could cause a crash -// (thanks to Nicolas for finding it) -// - 1.00 BETA 2 (16/11/2002) - Improved portability -// - 1.00 BETA 1 (27/10/2002) - First public release +// History: see ChangeLog // ////////////////////////////////////////////////////////////////////// +// SVN: $Id: tri_stripper.h 86 2005-06-08 17:47:27Z gpsnoopy $ +////////////////////////////////////////////////////////////////////// -#pragma once - +// Protection against old C habits +#if defined(max) +#error "'max' macro defined! It's against the C++ standard. Please use 'std::max' instead (undefine 'max' macro if it was defined in another library)." +#endif +// Protection against old C habits +#if defined(min) +#error "'min' macro defined! It's against the C++ standard. Please use 'std::min' instead (undefine 'min' macro if it was defined in another library)." +#endif -#include "cache_simulator.h" +#ifndef TRI_STRIPPER_HEADER_GUARD_TRI_STRIPPER_H +#define TRI_STRIPPER_HEADER_GUARD_TRI_STRIPPER_H +#include "public_types.h" +#include "detail/cache_simulator.h" +#include "detail/graph_array.h" +#include "detail/heap_array.h" +#include "detail/types.h" -// namespace triangle_stripper -namespace triangle_stripper { +namespace triangle_stripper { -#include "graph_array.h" -#include "heap_array.h" @@ -82,304 +69,122 @@ class tri_stripper { public: - // New Public types - typedef unsigned int index; - typedef std::vector<index> indices; - - enum primitive_type { - PT_Triangles = 0x0004, // = GL_TRIANGLES - PT_Triangle_Strip = 0x0005 // = GL_TRIANGLE_STRIP - }; - - struct primitives - { - indices m_Indices; - primitive_type m_Type; - }; - - typedef std::vector<primitives> primitives_vector; - - struct triangles_indices_error { }; + tri_stripper(const indices & TriIndices); + void Strip(primitive_vector * out_pPrimitivesVector); - // constructor/initializer - tri_stripper(const indices & TriIndices); + /* Stripifier Algorithm Settings */ + + // Set the post-T&L cache size (0 disables the cache optimizer). + void SetCacheSize(size_t CacheSize = 10); + + // Set the minimum size of a triangle strip (should be at least 2 triangles). + // The stripifier discard any candidate strips that does not satisfy the minimum size condition. + void SetMinStripSize(size_t MinStripSize = 2); + + // Set the backward search mode in addition to the forward search mode. + // In forward mode, the candidate strips are build with the current candidate triangle being the first + // triangle of the strip. When the backward mode is enabled, the stripifier also tests candidate strips + // where the current candidate triangle is the last triangle of the strip. + // Enable this if you want better results at the expense of being slightly slower. + // Note: Do *NOT* use this when the cache optimizer is enabled; it only gives worse results. + void SetBackwardSearch(bool Enabled = false); - // Settings functions - void SetCacheSize(const size_t CacheSize = 16); // = 0 will disable the cache optimizer - void SetMinStripSize(const size_t MinStripSize = 2); + // Set the cache simulator FIFO behavior (does nothing if the cache optimizer is disabled). + // When enabled, the cache is simulated as a simple FIFO structure. However, when + // disabled, indices that trigger cache hits are not pushed into the FIFO structure. + // This allows simulating some GPUs that do not duplicate cache entries (e.g. NV25 or greater). + void SetPushCacheHits(bool Enabled = true); - // Stripper - void Strip(primitives_vector * out_pPrimitivesVector); // throw triangles_indices_error(); + /* End Settings */ private: - friend struct _cmp_tri_interface_lt; - - - class triangle - { - public: - triangle(); - triangle(const index A, const index B, const index C); - - void SetStripID(const size_t StripID); - - index A() const; - index B() const; - index C() const; - size_t StripID() const; - - private: - index m_A; - index m_B; - index m_C; - size_t m_StripID; - }; - - - class triangle_edge - { - public: - triangle_edge(const index A, const index B, const size_t TriPos); - - index A() const; - index B() const; - size_t TriPos() const; - - private: - index m_A; - index m_B; - size_t m_TriPos; - }; - - - class triangle_degree - { - public: - triangle_degree(); - triangle_degree(const size_t TriPos, const size_t Degree); - - size_t Degree() const; - size_t TriPos() const; - - void SetDegree(const size_t Degree); - - private: - size_t m_TriPos; - size_t m_Degree; - }; + typedef detail::graph_array<detail::triangle> triangle_graph; + typedef detail::heap_array<size_t, std::greater<size_t> > triangle_heap; + typedef std::vector<size_t> candidates; + typedef triangle_graph::node_iterator tri_iterator; + typedef triangle_graph::const_node_iterator const_tri_iterator; + typedef triangle_graph::out_arc_iterator link_iterator; + typedef triangle_graph::const_out_arc_iterator const_link_iterator; - - class triangle_strip - { - public: - enum start_order { ABC = 0, BCA = 1, CAB = 2 }; - - triangle_strip(); - triangle_strip(size_t StartTriPos, start_order StartOrder, size_t Size); - - size_t StartTriPos() const; - start_order StartOrder() const; - size_t Size() const; - - private: - size_t m_StartTriPos; - start_order m_StartOrder; - size_t m_Size; - }; - - - struct _cmp_tri_interface_lt - { - bool operator() (const triangle_edge & a, const triangle_edge & b) const; - }; - - - struct _cmp_tri_degree_gt - { - bool operator () (const triangle_degree & a, const triangle_degree & b) const; - }; - - - typedef common_structures::graph_array<triangle, char> triangles_graph; - typedef common_structures::heap_array<triangle_degree, _cmp_tri_degree_gt> triangles_heap; - typedef std::vector<triangle_edge> triangle_edges; - typedef std::vector<size_t> triangle_indices; - typedef std::deque<index> indices_cache; - - - void InitCache(); - void InitTriGraph(); void InitTriHeap(); void Stripify(); void AddLeftTriangles(); - - void LinkNeighboursTri(const triangle_edges & TriInterface, const triangle_edge Edge); - void MarkTriAsTaken(const size_t i); - - triangle_edge GetLatestEdge(const triangle & Triangle, const triangle_strip::start_order Order) const; - - triangle_strip FindBestStrip(); - triangle_strip ExtendTriToStrip(const size_t StartTriPos, const triangle_strip::start_order StartOrder); - void BuildStrip(const triangle_strip TriStrip); - void AddIndex(const index i); - void AddIndexToCache(const index i, bool CacheHitCount = false); - void AddTriToCache(const triangle & Tri, const triangle_strip::start_order Order); - void AddTriToIndices(const triangle & Tri, const triangle_strip::start_order Order); - - const indices & m_TriIndices; - - size_t m_MinStripSize; -// size_t m_CacheSize; - - primitives_vector m_PrimitivesVector; - triangles_graph m_Triangles; - triangles_heap m_TriHeap; - triangle_indices m_NextCandidates; - cache_simulator m_Cache; -// indices_cache m_IndicesCache; - size_t m_StripID; -// size_t m_CacheHits; + void ResetStripIDs(); + + detail::strip FindBestStrip(); + detail::strip ExtendToStrip(size_t Start, detail::triangle_order Order); + detail::strip BackExtendToStrip(size_t Start, detail::triangle_order Order, bool ClockWise); + const_link_iterator LinkToNeighbour(const_tri_iterator Node, bool ClockWise, detail::triangle_order & Order, bool NotSimulation); + const_link_iterator BackLinkToNeighbour(const_tri_iterator Node, bool ClockWise, detail::triangle_order & Order); + void BuildStrip(const detail::strip Strip); + void MarkTriAsTaken(size_t i); + void AddIndex(index i, bool NotSimulation); + void BackAddIndex(index i); + void AddTriangle(const detail::triangle & Tri, detail::triangle_order Order, bool NotSimulation); + void BackAddTriangle(const detail::triangle & Tri, detail::triangle_order Order); + + bool Cache() const; + size_t CacheSize() const; + + static detail::triangle_edge FirstEdge(const detail::triangle & Triangle, detail::triangle_order Order); + static detail::triangle_edge LastEdge(const detail::triangle & Triangle, detail::triangle_order Order); + + primitive_vector m_PrimitivesVector; + triangle_graph m_Triangles; + triangle_heap m_TriHeap; + candidates m_Candidates; + detail::cache_simulator m_Cache; + detail::cache_simulator m_BackCache; + size_t m_StripID; + size_t m_MinStripSize; + bool m_BackwardSearch; + bool m_FirstRun; }; + ////////////////////////////////////////////////////////////////////////// -// tri_stripper Inline functions +// tri_stripper inline functions ////////////////////////////////////////////////////////////////////////// -inline tri_stripper::tri_stripper(const indices & TriIndices) : m_TriIndices(TriIndices) { - SetCacheSize(); - SetMinStripSize(); -} - - -inline void tri_stripper::SetCacheSize(const size_t CacheSize) { -// m_CacheSize = CacheSize; +inline void tri_stripper::SetCacheSize(const size_t CacheSize) +{ m_Cache.resize(CacheSize); + m_BackCache.resize(CacheSize); } -inline void tri_stripper::SetMinStripSize(const size_t MinStripSize) { - m_MinStripSize = MinStripSize; -} - - -inline tri_stripper::triangle::triangle() { } - - -inline tri_stripper::triangle::triangle(const index A, const index B, const index C) : m_A(A), m_B(B), m_C(C), m_StripID(0) { } - - -inline void tri_stripper::triangle::SetStripID(const size_t StripID) { - m_StripID = StripID; -} - - -inline tri_stripper::index tri_stripper::triangle::A() const { - return m_A; -} - - -inline tri_stripper::index tri_stripper::triangle::B() const { - return m_B; -} - - -inline tri_stripper::index tri_stripper::triangle::C() const { - return m_C; -} - - -inline size_t tri_stripper::triangle::StripID() const { - return m_StripID; -} - - -inline tri_stripper::triangle_edge::triangle_edge(const index A, const index B, const size_t TriPos) : m_A(A), m_B(B), m_TriPos(TriPos) { } - - -inline tri_stripper::index tri_stripper::triangle_edge::A() const { - return m_A; -} - - -inline tri_stripper::index tri_stripper::triangle_edge::B() const { - return m_B; -} - - -inline size_t tri_stripper::triangle_edge::TriPos() const { - return m_TriPos; -} - - -inline tri_stripper::triangle_degree::triangle_degree() { } - - -inline tri_stripper::triangle_degree::triangle_degree(const size_t TriPos, const size_t Degree) : m_TriPos(TriPos), m_Degree(Degree) { } - - -inline size_t tri_stripper::triangle_degree::Degree() const { - return m_Degree; -} - - -inline size_t tri_stripper::triangle_degree::TriPos() const { - return m_TriPos; -} - - -inline void tri_stripper::triangle_degree::SetDegree(const size_t Degree) { - m_Degree = Degree; -} - - -inline tri_stripper::triangle_strip::triangle_strip() : m_StartTriPos(0), m_StartOrder(ABC), m_Size(0) { } - - -inline tri_stripper::triangle_strip::triangle_strip(const size_t StartTriPos, const start_order StartOrder, const size_t Size) - : m_StartTriPos(StartTriPos), m_StartOrder(StartOrder), m_Size(Size) { } - - -inline size_t tri_stripper::triangle_strip::StartTriPos() const { - return m_StartTriPos; -} - - -inline tri_stripper::triangle_strip::start_order tri_stripper::triangle_strip::StartOrder() const { - return m_StartOrder; +inline void tri_stripper::SetMinStripSize(const size_t MinStripSize) +{ + if (MinStripSize < 2) + m_MinStripSize = 2; + else + m_MinStripSize = MinStripSize; } -inline size_t tri_stripper::triangle_strip::Size() const { - return m_Size; +inline void tri_stripper::SetBackwardSearch(const bool Enabled) +{ + m_BackwardSearch = Enabled; } -inline bool tri_stripper::_cmp_tri_interface_lt::operator() (const triangle_edge & a, const triangle_edge & b) const { - const tri_stripper::index A1 = a.A(); - const tri_stripper::index B1 = a.B(); - const tri_stripper::index A2 = b.A(); - const tri_stripper::index B2 = b.B(); - if ((A1 < A2) || ((A1 == A2) && (B1 < B2))) - return true; - else - return false; +inline void tri_stripper::SetPushCacheHits(bool Enabled) +{ + m_Cache.push_cache_hits(Enabled); } -inline bool tri_stripper::_cmp_tri_degree_gt::operator () (const triangle_degree & a, const triangle_degree & b) const { - // the triangle with a smaller degree has more priority - return a.Degree() > b.Degree(); -} +} // namespace triangle_stripper -} // namespace triangle_stripper +#endif // TRI_STRIPPER_HEADER_GUARD_TRI_STRIPPER_H diff --git a/NifExport/pch.h b/NifExport/pch.h index 3427c16c8ba6a8d8ffddc3ac43824d29ca521950..a965e1cc70218e5c7655f8f7efff909fd2b0f183 100755 --- a/NifExport/pch.h +++ b/NifExport/pch.h @@ -38,6 +38,9 @@ #include "obj/NiStringExtraData.h" #include "obj/bhkRigidBodyT.h" +// undef macros for tristripper +#undef max +#undef min #include "NvTriStrip/NvTriStrip.h" #include "TriStripper/tri_stripper.h" diff --git a/NifFurniture/NifFurniture.rc b/NifFurniture/NifFurniture.rc index b8a3219db6f2e95a826c4f395ec99ce88c32e06a..ef6495d21198cc60af5f6da2d99f7d03cebe53cb 100755 --- a/NifFurniture/NifFurniture.rc +++ b/NifFurniture/NifFurniture.rc @@ -13,7 +13,7 @@ #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// Deutsch (Deutschland) resources +// German (Germany) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) #ifdef _WIN32 @@ -35,12 +35,12 @@ END #endif // APSTUDIO_INVOKED -#endif // Deutsch (Deutschland) resources +#endif // German (Germany) resources ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -// Englisch (USA) resources +// English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 @@ -48,6 +48,26 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + ///////////////////////////////////////////////////////////////////////////// // // Dialog @@ -57,8 +77,7 @@ IDD_PANEL DIALOGEX 0, 0, 108, 38 STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN - COMBOBOX IDC_CB_TYPE,6,18,96,60,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP + COMBOBOX IDC_CB_TYPE,6,18,96,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "Type",IDC_STATIC,6,6,17,8 END @@ -82,25 +101,43 @@ END #endif // APSTUDIO_INVOKED -#ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // -// TEXTINCLUDE +// Version // -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,2,1,0 + PRODUCTVERSION 0,2,1,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L BEGIN - "#include ""afxres.h""\r\n" - "\0" + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "3ds Max Nif Furniture Plugin" + VALUE "FileVersion", "0, 2, 1, 0" + VALUE "InternalName", "NifFurniture.dlu" + VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved." + VALUE "OriginalFilename", "NifFurniture.dlu" + VALUE "ProductName", "3ds Max Nif Furniture Plugin" + VALUE "ProductVersion", "0, 2, 1, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END END -#endif // APSTUDIO_INVOKED - ///////////////////////////////////////////////////////////////////////////// // @@ -117,7 +154,7 @@ BEGIN IDS_FURNITURE_MARKER "Furniture Marker" END -#endif // Englisch (USA) resources +#endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/NifImport/MaxNifImport.rc b/NifImport/MaxNifImport.rc index 639490ea76e49e9d2968c9cae8afa0afcb4b3166..bbbac5231ce098bb6fe036e9c1b536e4215adff3 100644 --- a/NifImport/MaxNifImport.rc +++ b/NifImport/MaxNifImport.rc @@ -108,13 +108,13 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,2,0,0 - PRODUCTVERSION 0,2,0,0 - FILEFLAGSMASK 0x37L + FILEVERSION 0,2,1,0 + PRODUCTVERSION 0,2,1,0 + FILEFLAGSMASK 0x17L #ifdef _DEBUG - FILEFLAGS 0x21L + FILEFLAGS 0x1L #else - FILEFLAGS 0x20L + FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x2L @@ -125,13 +125,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "3ds Max Nif Importer" - VALUE "FileVersion", "0, 2, 0, 0" + VALUE "FileVersion", "0, 2, 1, 0" VALUE "InternalName", "MaxNifImport.dli" VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved." VALUE "OriginalFilename", "MaxNifImport.dli" VALUE "ProductName", "3ds Max Nif Importer" - VALUE "ProductVersion", "0, 2, 0, 0" - VALUE "SpecialBuild", "Alpha" + VALUE "ProductVersion", "0, 2, 1, 0" END END BLOCK "VarFileInfo" diff --git a/NifProps/NifProps.rc b/NifProps/NifProps.rc index 67b87a2ddcee11b3757ccd0b8c4a7c509b38207e..38a094a96d18a604a8446dc950c7324c2cdb49d8 100755 --- a/NifProps/NifProps.rc +++ b/NifProps/NifProps.rc @@ -13,7 +13,7 @@ #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// Deutsch (Deutschland) resources +// German (Germany) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) #ifdef _WIN32 @@ -35,12 +35,12 @@ END #endif // APSTUDIO_INVOKED -#endif // Deutsch (Deutschland) resources +#endif // German (Germany) resources ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -// Englisch (USA) resources +// English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 @@ -77,99 +77,53 @@ IDD_PANEL DIALOGEX 0, 0, 107, 401 STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN - COMBOBOX IDC_CB_MATERIAL,12,58,83,157,CBS_DROPDOWNLIST | - WS_DISABLED | WS_VSCROLL | WS_TABSTOP - CONTROL "Material",IDC_LBL_MATERIAL,"Static",SS_LEFTNOWORDWRAP | - SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,12,50,83,8 - COMBOBOX IDC_CB_LAYER,12,82,83,171,CBS_DROPDOWNLIST | WS_DISABLED | - WS_VSCROLL | WS_TABSTOP - CONTROL "Layer",IDC_LBL_LAYER,"Static",SS_LEFTNOWORDWRAP | - SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,12,74,83,8 + COMBOBOX IDC_CB_MATERIAL,12,58,83,157,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + CONTROL "Material",IDC_LBL_MATERIAL,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,12,50,83,8 + COMBOBOX IDC_CB_LAYER,12,82,83,171,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + CONTROL "Layer",IDC_LBL_LAYER,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,12,74,83,8 GROUPBOX "Havok",IDC_GRP_HAVOK,5,39,95,285,WS_DISABLED GROUPBOX "Object",IDC_GRP_OBJECT,5,5,95,32 - CONTROL "Is Collision Mesh",IDC_CHK_ISCOLL,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,14,18,80,10 + CONTROL "Is Collision Mesh",IDC_CHK_ISCOLL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,18,80,10 GROUPBOX "Global",IDC_STATIC,5,329,95,65,WS_DISABLED - EDITTEXT IDC_ED_BSXFLAGS,13,352,80,12,ES_AUTOHSCROLL | - WS_DISABLED - CONTROL "BSXFlags",IDC_LBL_BSXFLAGS,"Static",SS_LEFTNOWORDWRAP | - SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,13,340,80,8 - EDITTEXT IDC_ED_STRINGSEXTRA,13,374,80,12,ES_AUTOHSCROLL | - WS_DISABLED - CONTROL "Strings Extra Data",IDC_LBL_STRINGSEXTRA,"Static", - SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | - WS_GROUP,13,365,80,8 - CONTROL "Center",IDC_LBL_CENTER,"Static",SS_LEFTNOWORDWRAP | - SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,12,98,31,8 - CONTROL "Mass",IDC_LBL_MASS,"Static",SS_LEFTNOWORDWRAP | - WS_DISABLED | WS_GROUP,12,124,28,8 - CONTROL "Friction",IDC_LBL_FRICTION,"Static",SS_LEFTNOWORDWRAP | - WS_DISABLED | WS_GROUP,42,124,28,8 - LTEXT "Resti-\r\ntution",IDC_LBL_RESTITUTION,70,124,24,15, - WS_DISABLED - CONTROL "Motion System",IDC_LBL_MOTION_SYSTEM,"Static", - SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | - WS_GROUP,12,263,67,8 - COMBOBOX IDC_CB_MOTION_SYSTEM,12,273,83,74,CBS_DROPDOWNLIST | - WS_DISABLED | WS_VSCROLL | WS_TABSTOP - CONTROL "Quality Type",IDC_LBL_QUALITY_TYPE,"Static", - SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | - WS_GROUP,12,289,43,8 - COMBOBOX IDC_CB_QUALITY_TYPE,12,298,83,63,CBS_DROPDOWN | - WS_DISABLED | WS_VSCROLL | WS_TABSTOP - CONTROL "",IDC_ED_CENTER_X,"CustEdit",WS_DISABLED | WS_TABSTOP, - 12,109,20,10 - CONTROL "",IDC_SP_CENTER_X,"SpinnerControl",WS_DISABLED,30,109,7, - 10 - CONTROL "",IDC_ED_CENTER_Y,"CustEdit",WS_DISABLED | WS_TABSTOP, - 42,109,20,10 - CONTROL "",IDC_SP_CENTER_Y,"SpinnerControl",WS_DISABLED,60,109,7, - 10 - CONTROL "",IDC_ED_CENTER_Z,"CustEdit",WS_DISABLED | WS_TABSTOP, - 72,109,20,10 - CONTROL "",IDC_SP_CENTER_Z,"SpinnerControl",WS_DISABLED,92,109,7, - 10 - CONTROL "",IDC_ED_MASS,"CustEdit",WS_DISABLED | WS_TABSTOP,12, - 143,20,10 + EDITTEXT IDC_ED_BSXFLAGS,13,352,80,12,ES_AUTOHSCROLL | WS_DISABLED + CONTROL "BSXFlags",IDC_LBL_BSXFLAGS,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,13,340,80,8 + EDITTEXT IDC_ED_STRINGSEXTRA,13,374,80,12,ES_AUTOHSCROLL | WS_DISABLED + CONTROL "Strings Extra Data",IDC_LBL_STRINGSEXTRA,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,13,365,80,8 + CONTROL "Center",IDC_LBL_CENTER,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,12,98,31,8 + CONTROL "Mass",IDC_LBL_MASS,"Static",SS_LEFTNOWORDWRAP | WS_DISABLED | WS_GROUP,12,124,28,8 + CONTROL "Friction",IDC_LBL_FRICTION,"Static",SS_LEFTNOWORDWRAP | WS_DISABLED | WS_GROUP,42,124,28,8 + LTEXT "Resti-\r\ntution",IDC_LBL_RESTITUTION,70,124,24,15,WS_DISABLED + CONTROL "Motion System",IDC_LBL_MOTION_SYSTEM,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,12,263,67,8 + COMBOBOX IDC_CB_MOTION_SYSTEM,12,273,83,74,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + CONTROL "Quality Type",IDC_LBL_QUALITY_TYPE,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_DISABLED | WS_GROUP,12,289,43,8 + COMBOBOX IDC_CB_QUALITY_TYPE,12,298,83,63,CBS_DROPDOWN | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_ED_CENTER_X,"CustEdit",WS_DISABLED | WS_TABSTOP,12,109,20,10 + CONTROL "",IDC_SP_CENTER_X,"SpinnerControl",WS_DISABLED,30,109,7,10 + CONTROL "",IDC_ED_CENTER_Y,"CustEdit",WS_DISABLED | WS_TABSTOP,42,109,20,10 + CONTROL "",IDC_SP_CENTER_Y,"SpinnerControl",WS_DISABLED,60,109,7,10 + CONTROL "",IDC_ED_CENTER_Z,"CustEdit",WS_DISABLED | WS_TABSTOP,72,109,20,10 + CONTROL "",IDC_SP_CENTER_Z,"SpinnerControl",WS_DISABLED,92,109,7,10 + CONTROL "",IDC_ED_MASS,"CustEdit",WS_DISABLED | WS_TABSTOP,12,143,20,10 CONTROL "",IDC_SP_MASS,"SpinnerControl",WS_DISABLED,30,143,7,10 - CONTROL "",IDC_ED_FRICTION,"CustEdit",WS_DISABLED | WS_TABSTOP, - 42,143,20,10 - CONTROL "",IDC_SP_FRICTION,"SpinnerControl",WS_DISABLED,60,143,7, - 10 - CONTROL "",IDC_ED_RESTITUTION,"CustEdit",WS_DISABLED | - WS_TABSTOP,70,143,20,10 - CONTROL "",IDC_SP_RESTITUTION,"SpinnerControl",WS_DISABLED,90, - 143,7,10 - LTEXT "Linear\r\nDamping",IDC_LBL_LINEAR_DAMPING,12,159,30,17, - WS_DISABLED - CONTROL "",IDC_ED_LINEAR_DAMPING,"CustEdit",WS_DISABLED | - WS_TABSTOP,12,178,35,10 - CONTROL "",IDC_SP_LINEAR_DAMPING,"SpinnerControl",WS_DISABLED,45, - 178,7,10 - LTEXT "Angular\r\nDamping",IDC_LBL_ANGULAR_DAMPING,55,159,45, - 17,WS_DISABLED - CONTROL "",IDC_ED_ANGULAR_DAMPING,"CustEdit",WS_DISABLED | - WS_TABSTOP,55,178,35,10 - CONTROL "",IDC_SP_ANGULAR_DAMPING,"SpinnerControl",WS_DISABLED, - 90,178,7,10 - LTEXT "Max. Linear\r\nVelocity",IDC_LBL_MAX_LINEAR_VELOCITY,12, - 194,40,16,WS_DISABLED - CONTROL "",IDC_ED_MAX_LINEAR_VELOCITY,"CustEdit",WS_DISABLED | - WS_TABSTOP,12,214,35,10 - CONTROL "",IDC_SP_MAX_LINEAR_VELOCITY,"SpinnerControl", - WS_DISABLED,45,214,7,10 - LTEXT "Max. Angular\r\nVelocity",IDC_LBL_MAX_ANGULAR_VELOCITY, - 55,194,45,16,WS_DISABLED - CONTROL "",IDC_ED_MAX_ANGULAR_VELOCITY,"CustEdit",WS_DISABLED | - WS_TABSTOP,55,214,35,10 - CONTROL "",IDC_SP_MAX_ANGULAR_VELOCITY,"SpinnerControl", - WS_DISABLED,90,214,7,10 - LTEXT "Penetration\r\nDepth",IDC_LBL_PENETRATION_DEPTH,12,229, - 40,16,WS_DISABLED - CONTROL "",IDC_ED_PENETRATION_DEPTH,"CustEdit",WS_DISABLED | - WS_TABSTOP,12,249,35,10 - CONTROL "",IDC_SP_PENETRATION_DEPTH,"SpinnerControl",WS_DISABLED, - 45,249,7,10 + CONTROL "",IDC_ED_FRICTION,"CustEdit",WS_DISABLED | WS_TABSTOP,42,143,20,10 + CONTROL "",IDC_SP_FRICTION,"SpinnerControl",WS_DISABLED,60,143,7,10 + CONTROL "",IDC_ED_RESTITUTION,"CustEdit",WS_DISABLED | WS_TABSTOP,70,143,20,10 + CONTROL "",IDC_SP_RESTITUTION,"SpinnerControl",WS_DISABLED,90,143,7,10 + LTEXT "Linear\r\nDamping",IDC_LBL_LINEAR_DAMPING,12,159,30,17,WS_DISABLED + CONTROL "",IDC_ED_LINEAR_DAMPING,"CustEdit",WS_DISABLED | WS_TABSTOP,12,178,35,10 + CONTROL "",IDC_SP_LINEAR_DAMPING,"SpinnerControl",WS_DISABLED,45,178,7,10 + LTEXT "Angular\r\nDamping",IDC_LBL_ANGULAR_DAMPING,55,159,45,17,WS_DISABLED + CONTROL "",IDC_ED_ANGULAR_DAMPING,"CustEdit",WS_DISABLED | WS_TABSTOP,55,178,35,10 + CONTROL "",IDC_SP_ANGULAR_DAMPING,"SpinnerControl",WS_DISABLED,90,178,7,10 + LTEXT "Max. Linear\r\nVelocity",IDC_LBL_MAX_LINEAR_VELOCITY,12,194,40,16,WS_DISABLED + CONTROL "",IDC_ED_MAX_LINEAR_VELOCITY,"CustEdit",WS_DISABLED | WS_TABSTOP,12,214,35,10 + CONTROL "",IDC_SP_MAX_LINEAR_VELOCITY,"SpinnerControl",WS_DISABLED,45,214,7,10 + LTEXT "Max. Angular\r\nVelocity",IDC_LBL_MAX_ANGULAR_VELOCITY,55,194,45,16,WS_DISABLED + CONTROL "",IDC_ED_MAX_ANGULAR_VELOCITY,"CustEdit",WS_DISABLED | WS_TABSTOP,55,214,35,10 + CONTROL "",IDC_SP_MAX_ANGULAR_VELOCITY,"SpinnerControl",WS_DISABLED,90,214,7,10 + LTEXT "Penetration\r\nDepth",IDC_LBL_PENETRATION_DEPTH,12,229,40,16,WS_DISABLED + CONTROL "",IDC_ED_PENETRATION_DEPTH,"CustEdit",WS_DISABLED | WS_TABSTOP,12,249,35,10 + CONTROL "",IDC_SP_PENETRATION_DEPTH,"SpinnerControl",WS_DISABLED,45,249,7,10 END @@ -382,6 +336,44 @@ BEGIN END +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,2,1,0 + PRODUCTVERSION 0,2,1,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "3ds Max Nif Reactor Properites Plugin" + VALUE "FileVersion", "0, 2, 1, 0" + VALUE "InternalName", "NifProps.dlu" + VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved." + VALUE "OriginalFilename", "NifProps.dlu" + VALUE "ProductName", "3ds Max Nif Reactor Properites Plugin" + VALUE "ProductVersion", "0, 2, 1, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + ///////////////////////////////////////////////////////////////////////////// // // String Table @@ -396,7 +388,7 @@ BEGIN IDS_SPIN "Spin" END -#endif // Englisch (USA) resources +#endif // English (U.S.) resources /////////////////////////////////////////////////////////////////////////////