mqsdx  310.0.1
MQPluginSDK Extention Library / mqsdkをC++またはCLI(.Net)拡張するサポートライブラリ
 全て クラス 関数 変数 型定義 プロパティ グループ ページ
MQ0x.hpp
1 /*
2 First author tiritomato 2013.
3 
4 mqsdx is distributed under the GNU Lesser General Public License 3.0(LGPLv3).
5 
6 support blog (Japanese only)
7 http://d.hatena.ne.jp/tiri_tomato/
8 */
9 
10 #ifndef __MQSDKPlugIn0x_11_h__
11 #define __MQSDKPlugIn0x_11_h__
12 
13 #define _USE_MATH_DEFINES
14 #include <math.h>
15 #include <stdint.h>
16 #include <string.h>
17 
18 #include <algorithm>
19 #include <cmath>
20 #include <functional>
21 #include <iomanip>
22 #include <regex>
23 #include <sstream>
24 #include <utility>
25 #include <vector>
26 
27 #define NOMINMAX
28 #define WIN32_LEAN_AND_MEAN
29 #include <windows.h>
30 
31 #include <MQSetting.h>
32 #include <MQBasePlugin.h>
33 #include <MQPlugin.h>
34 #include <MQ3DLib.h>
35 
36 #include "impl/MQ0x_11.hpp"
37 
38 // Plugin Version Checker
39 #ifdef MQPLUGIN_VERSION
40  #if MQPLUGIN_VERSION < 0x0300
41  "MQx" need newer than mqsdk300
42  #endif
43 #else
44  "MQx" need newer than mqsdk300
45 #endif
46 
47 namespace MQ0x {
48 
78  template <typename T_OUT, const size_t default_seed = 17> struct CollectionHashCode {
79  public:
81  static const T_OUT defaultSeed = (T_OUT)default_seed;
83  CollectionHashCode( const T_OUT seed = defaultSeed ) : m_val( seed ) {}
89  template <typename T_IN> CollectionHashCode( const T_IN *pSrc, const size_t ct, const T_OUT seed = defaultSeed ) : m_val(seed) {
90  if ( pSrc != NULL ) for ( size_t i = 0; i < ct; i++ ) m_val = (m_val * (T_OUT)(sizeof(T_IN) * 8 - 1)) ^ pSrc[i];
91  }
96  CollectionHashCode( const char *pSrc, const T_OUT seed = defaultSeed ) : m_val(FromTrailCodeCollection(pSrc,'\0',seed)) {}
101  CollectionHashCode( const wchar_t *pSrc, const T_OUT seed = defaultSeed ) : m_val(FromTrailCodeCollection(pSrc,L'\0',seed)) {}
107  template <typename T_IN> static CollectionHashCode FromTrailCodeCollection( const T_IN *pSrc, const T_IN trailCode, const T_OUT seed = defaultSeed ) {
108  CollectionHashCode ret(seed);
109  if ( pSrc != NULL ) while ( (*pSrc) != trailCode ) ret.m_val = (ret.m_val * (T_OUT)(sizeof(T_IN) * 8 - 1)) ^ (*(pSrc++));
110  return ret;
111  }
113  operator T_OUT() { return m_val; }
114  private:
115  T_OUT m_val;
116  };
117 
120  template <typename T> struct HSV {
121  typedef T value_type;
122  T h;
123  T s;
124  T v;
125  HSV() : h(T(0)), s(T(0)), v(T(0)) {}
126  HSV(T h_, T s_, T v_) : h(h_), s(s_), v(v_) {}
127  HSV( const HSV& src ) : h(src.h), s(src.s), v(src.v) {}
128  HSV( const MQColor& rgb ) : h(T(0)), s(T(0)), v(T(0)) {
130  const T min = T(std::min(std::min(rgb.r,rgb.g),rgb.b));
131  const T max = T(std::max(std::max(rgb.r,rgb.g),rgb.b));
132  const T delta = max - min;
133  v = max;
134  if(delta!=T(0)) {
135  s = delta / max;
136  if ( rgb.r == max ) h = (rgb.g-rgb.b) / delta;
137  else if (rgb.g == max) h = T(2) + (rgb.b-rgb.r) / delta;
138  else h = T(4) + (rgb.r-rgb.g) / delta;
139  h /= T(6);
140  if ( h < T(0) ) h += T(1);
141  }
142  }
146  bool isGrayScale( T threshold ) const { return threshold < s; }
149  bool isGrayScale() const { return isGrayScale(std::numeric_limits<T>::epsilon()); }
152  void normalize() {
153  h -= std::floor(h);
154  s = clamp01(s);
155  v = clamp01(v);
156  }
158  MQColor toMQColor() const {
159  const HSV normal = toNormalized(); // to [0,1]
160  if ( normal.isGrayScale() ) return MQColor( normal.v );
161  const T H = normal.h * T(6);
162  const int Hi = static_cast<int>(H);
163  const T fr = H - T(Hi);
164  const T m = normal.v * (T(1)-normal.s);
165  const T n = normal.v * (T(1)-normal.s*fr);
166  const T p = normal.v * (T(1)-normal.s*(T(1)-fr));
167  switch(Hi) {
168  case 0: return MQColor( float(normal.v), float(p), float(m) );
169  case 1: return MQColor( float(n), float(normal.v), float(m) );
170  case 2: return MQColor( float(m), float(normal.v), float(p) );
171  case 3: return MQColor( float(m), float(n), float(normal.v) );
172  case 4: return MQColor( float(p), float(m), float(normal.v) );
173  default: return MQColor( float(normal.v), float(m), float(n) );
174  }
175  }
177  HSV toNormalized() const { return HSV( h - std::floor(h), Clamp01(s), Clamp01(v) ); }
178  };
179 
193  struct SettingProxy {
194  public:
196  struct Handle {
198  friend struct SettingProxy;
199  template <typename T_MQPLUGIN> friend class PluginBase;
201  static Handle Empty() { return Handle(NULL); }
202  public:
203  Handle( MQBasePlugin* plugin ) { this->plugin = plugin; }
204  MQBasePlugin* plugin;
205  };
206  SettingProxy( Handle handle );
207  ~SettingProxy() { Close(); }
208  void Close();
209  bool Load(const char *name, bool& value, bool default_value=false);
210  bool Load(const char *name, int& value, int default_value=0);
211  bool Load(const char *name, unsigned int& value, unsigned int default_value=0);
212  bool Load(const char *name, float& value, float default_value=0.0f);
213  bool Load(const char *name, std::string& value, std::string default_value="");
214  bool Save(const char *name, const bool& value);
215  bool Save(const char *name, const int& value);
216  bool Save(const char *name, const unsigned int& value);
217  bool Save(const char *name, const float& value);
218  bool Save(const char *name, const char* value);
219  bool Save(const char *name, const std::string& value);
220  private:
221  SettingProxy(const SettingProxy&); // kill copy
222  SettingProxy& operator=(const SettingProxy&); // kill copy
223  MQBasePlugin* m_plugin;
224  MQSetting* m_setting;
225  };
226 
262  template <typename T_MQPLUGIN> class PluginBase : public T_MQPLUGIN {
263  public:
264  PluginBase( const char* productName, const char* pluginFullName, const char* pluginString ) :
265  m_productName( productName ),
266  m_pluginFullName( pluginFullName ),
267  m_pluginString( pluginString ),
268  m_idProduct( CollectionHashCode<DWORD>(productName) ),
269  m_idPlugin( CollectionHashCode<DWORD>(pluginFullName) )
270  {
271  }
272 
273  PluginBase( const char* productName, const char* pluginFullName, const char* pluginString,
274  const DWORD idProduct, const DWORD idPlugin ) :
275  m_productName( productName ),
276  m_pluginFullName( pluginFullName ),
277  m_pluginString( pluginString ),
278  m_idProduct( idProduct ),
279  m_idPlugin( idPlugin )
280  {
281  }
282 
284  virtual void GetPlugInID(DWORD *Product, DWORD *ID) {
285  *Product = m_idProduct;
286  *ID = m_idPlugin;
287  }
289  virtual const char *GetPlugInName() { return m_pluginFullName.c_str(); }
291  virtual const char *EnumString() { return m_pluginString.c_str(); }
293  const char* GetProductName() { return m_productName.c_str(); }
295  MQBasePlugin* BasePlugin() { return this; }
299  DWORD ProductID() { return m_idProduct; }
301  DWORD PluginID() { return m_idPlugin; }
302  protected:
303  const std::string m_productName;
304  const std::string m_pluginFullName;
305  const std::string m_pluginString;
306  const DWORD m_idProduct;
307  const DWORD m_idPlugin;
308  };
309 
310  namespace Math {
313 
315  template <typename T> inline T Ceil( T src ) { return src; }
317  template <> inline float Ceil( float src ) { return std::ceil(src); }
318  template <> inline double Ceil( double src ) { return std::ceil(src); }
319  template <> inline long double Ceil( long double src ) { return std::ceil(src); }
321 
323  template <typename T> inline T Clamp( T src, T min, T max ) {
324  return std::min( std::max(min,max), std::max( std::min(min,max), src) );
325  }
326 
328  template <typename T> inline T Clamp01( T src ) { return std::min(T(1),std::max(T(0),src)); }
329 
331  template <typename T> inline T Floor( T src ) { return src; }
333  template <> inline float Floor( float src ) { return std::floor(src); }
334  template <> inline double Floor( double src ) { return std::floor(src); }
335  template <> inline long double Floor( long double src ) { return std::floor(src); }
337 
340  template <typename T> inline T Lerp(T from, T to, T t) { return from + (to - from) * clamp01(t); }
341 
343  template <typename T> inline T MoveTo( T from, T to, T mov ) {
344  mov = std::abs(mov);
345  if ( std::abs(from - to) < mov ) return to;
346  return from += ( from < to ? mov : -mov );
347  }
348 
350  template <typename T> inline T Pi() { return (T)M_PI; }
352  template <> long double Pi();
354 
360  template <typename T> inline T Deg2Rad() { return Pi<T>() / (T)180; }
362  template <typename T> inline T Deg2Rad(T degree) { return Deg2Rad<T>() * degree; }
363 
369  template <typename T> inline T Rad2Deg() { return (T)180 / Pi<T>(); }
371  template <typename T> inline T Rad2Deg(T degree) { return Rad2Deg() * degree; }
372 
374  template <typename T> inline T Repeat( T t, T length ) { return t - std::floor(t/length)*length; }
375 
377  template <typename T> inline T Trunc( T src ) { if ( T(0) < src ) return floor(src); return ceil(src); }
379  }
380  using namespace Math;
381 
382 
383  namespace Polygon {
386 
388  struct VertexNormalBuffer;
390 
396  typedef std::vector<MQPoint>::size_type size_type;
398  static bool IsInvalid( const MQPoint& src ) { return src.x >= std::numeric_limits<float>::infinity(); }
400  FaceNormalBuffer() : m_obj(NULL), m_buffer(0), invalid_value( std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() ) {}
402  FaceNormalBuffer( const ::MQObject obj ) : m_obj( obj ), m_buffer(0),
403  invalid_value( std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() ) {
404  if ( obj != NULL ) {
405  const int ctFaceMax = obj->GetFaceCount();
406  m_buffer.resize( ctFaceMax );
407  for ( int ctFace = 0; ctFace < ctFaceMax; ctFace++ ) m_buffer[ctFace].x = invalid_value.x;
408  }
409  }
413  void Clear( const bool isCompact = false ) {
414  if ( isCompact ) {
415  size_type sz = 0; if ( m_obj != NULL ) sz = size_type(m_obj->GetFaceCount());
416  std::vector<MQPoint>(sz).swap( m_buffer );
417  }
418  for ( size_type ctFace = 0; ctFace < m_buffer.size(); ctFace++ ) m_buffer[ctFace].x = invalid_value.x;
419  }
423  void Clear( const ::MQObject obj, const bool isCompact = false ) { m_obj = obj; Clear(isCompact); }
425  void Compact() {
426  size_type sz = 0; if ( m_obj != NULL ) sz = size_type(m_obj->GetFaceCount());
427  m_buffer.resize(sz);
428  m_buffer.shrink_to_fit();
429  }
431  const ::MQObject MQObject() const { return m_obj; }
438  const MQPoint& operator [] ( size_type index ) {
439  if ( m_obj == NULL ) {
440  if ( (index < m_buffer.size()) && (IsInvalid(m_buffer[index])==false) ) return m_buffer[index];
441  }
442  else {
443  const size_type ctFaceMax = size_type(m_obj->GetFaceCount());
444  if ( index < ctFaceMax ) {
445  const size_type registedSize = m_buffer.size();
446  if ( registedSize < ctFaceMax ) {
447  m_buffer.resize( ctFaceMax );
448  for ( size_type ct = registedSize; ct < ctFaceMax; ct++ ) m_buffer[ct].x = invalid_value.x;
449  }
450  if ( IsInvalid(m_buffer[index]) ) {
451  const int ctFacePointMax = m_obj->GetFacePointCount( index );
452  if ( (ctFacePointMax==3) || (ctFacePointMax==4) ) {
453  int v[4];
454  m_obj->GetFacePointArray( index, v );
455  if ( ctFacePointMax==3 )
456  m_buffer[index] = GetNormal( m_obj->GetVertex(v[0]), m_obj->GetVertex(v[1]), m_obj->GetVertex(v[2]) );
457  else if ( ctFacePointMax==4 )
458  m_buffer[index] = GetQuadNormal( m_obj->GetVertex(v[0]), m_obj->GetVertex(v[1]), m_obj->GetVertex(v[2]), m_obj->GetVertex(v[3]) );
459  }
460  }
461  return m_buffer[index];
462  }
463  }
464  return invalid_value;
465  }
466  private:
468  friend struct Polygon::VertexNormalBuffer;
470  const MQPoint invalid_value;
471  ::MQObject m_obj;
472  std::vector<MQPoint> m_buffer;
473  };
474 
480  typedef std::vector<MQPoint>::size_type size_type;
482  static bool IsInvalid( const MQPoint& src ) { return FaceNormalBuffer::IsInvalid(src); }
484  VertexNormalBuffer() : m_face_normals( NULL ), m_buffer(0) {}
486  VertexNormalBuffer( const ::MQObject obj ) : m_face_normals( obj ), m_buffer(0) { if (obj != NULL) Clear(obj); }
490  void Clear( const bool isCompact = false ) {
491  if ( isCompact ) {
492  size_type sz = 0;
493  if ( m_face_normals.m_obj != NULL ) sz = size_type(m_face_normals.m_obj->GetVertexCount());
494  std::vector<MQPoint>(sz).swap( m_buffer );
495  }
496  for ( size_type ctFace = 0; ctFace < m_buffer.size(); ctFace++ ) m_buffer[ctFace].x = m_face_normals.invalid_value.x;
497  m_face_normals.Clear(isCompact);
498  }
502  void Clear( const ::MQObject obj, const bool isCompact = false ) {
503  if ( isCompact ) {
504  size_type sz = 0; if ( obj != NULL ) sz = size_type(obj->GetVertexCount());
505  std::vector<MQPoint>(sz).swap( m_buffer );
506  }
507  for ( size_type ctFace = 0; ctFace < m_buffer.size(); ctFace++ ) m_buffer[ctFace].x = m_face_normals.invalid_value.x;
508  m_face_normals.Clear(obj,isCompact);
509  }
512  void Compact() {
513  size_type sz = 0;
514  if ( m_face_normals.m_obj != NULL ) sz = size_type(m_face_normals.m_obj->GetVertexCount());
515  m_buffer.resize(sz);
516  m_buffer.shrink_to_fit();
517  m_face_normals.Compact();
518  }
526  const MQPoint& FaceNormal( FaceNormalBuffer::size_type index ) { return m_face_normals[index]; }
528  const ::MQObject MQObject() const { return m_face_normals.MQObject(); }
535  const MQPoint& VertexNormal( size_type index ) {
536  if ( m_face_normals.m_obj == NULL ) {
537  if ( (index < m_buffer.size()) && (IsInvalid(m_buffer[index])==false) ) return m_buffer[index];
538  }
539  else {
540  const size_type ctVertexMax = size_type(m_face_normals.m_obj->GetVertexCount());
541  if ( index < ctVertexMax ) {
542  const size_type registedSize = m_buffer.size();
543  if ( registedSize < ctVertexMax ) {
544  m_buffer.resize( ctVertexMax );
545  for ( size_type ct = registedSize; ct < ctVertexMax; ct++ ) m_buffer[ct].x = m_face_normals.invalid_value.x;
546  }
547  MQPoint& ret = m_buffer[index]; // get [in,out] reference
548  if ( IsInvalid(ret) ) {
549  const std::vector<int>::size_type ctFaceMax = std::vector<int>::size_type(m_face_normals.m_obj->GetVertexRelatedFaces( index, NULL ));
550  if (ctFaceMax == 1)
551  {
552  int face_index;
553  m_face_normals.m_obj->GetVertexRelatedFaces( index, &face_index );
554  ret = FaceNormal(FaceNormalBuffer::size_type(face_index));
555  }
556  else if ( 1 < ctFaceMax ) {
557  std::vector<int> face_indexes( ctFaceMax );
558  std::vector<int> vertexIndexesOfFace(4);
559  m_face_normals.m_obj->GetVertexRelatedFaces( index, &face_indexes[0] );
560  unsigned int ctAdd = 0;
561  ret.zero(); // ret reference clear
562  for ( std::vector<int>::size_type ct = 0; ct < ctFaceMax; ct++ ) // all check of related face
563  {
564  const MQPoint& n = FaceNormal(FaceNormalBuffer::size_type(face_indexes[ct]));
565  if ( FaceNormalBuffer::IsInvalid(n) == false )
566  {
567  const std::vector<int>::size_type vertexCountOfFace = std::vector<int>::size_type(m_face_normals.m_obj->GetFacePointCount(face_indexes[ct]));
568  if (vertexIndexesOfFace.size() < vertexCountOfFace) vertexIndexesOfFace.resize(vertexCountOfFace);
569  m_face_normals.m_obj->GetFacePointArray(face_indexes[ct], &vertexIndexesOfFace[0]);
570  int findCt = 0;
571  std::vector<int>::size_type findPosition;
572  for (std::vector<int>::size_type ct = 0; ct < vertexCountOfFace; ct++)
573  {
574  if (index == vertexIndexesOfFace[ct]) if (findCt++ == 0) findPosition = ct;
575  }
576  if (findCt != 1) continue;
577  const int prevVertexIndex = vertexIndexesOfFace[(findPosition <= 0 ? vertexCountOfFace : findPosition) - 1];
578  const int nextVertexIndex = vertexIndexesOfFace[(findPosition + 1) < vertexCountOfFace ? (findPosition + 1) : 0];
579  const MQPoint vertex = m_face_normals.m_obj->GetVertex(index);
580  MQPoint toPrevVertex = m_face_normals.m_obj->GetVertex(prevVertexIndex) - vertex;
581  MQPoint toNextVertex = m_face_normals.m_obj->GetVertex(nextVertexIndex) - vertex;
582  float cos = GetInnerProduct(toPrevVertex, toNextVertex) / (GetSize(toPrevVertex) * GetSize(toNextVertex));
583  ret += (n * (1.0f - cos)); // n * (2.0 - (cos + 1.0))
584  ctAdd++;
585  }
586  }
587  if (0 < ctAdd) ret.normalize();
588  else ret.x = m_face_normals.invalid_value.x;
589  }
590  }
591  return ret;
592  }
593  }
594  return m_face_normals.invalid_value;
595  }
597  const MQPoint& operator [] ( size_type index ) { return VertexNormal(index); }
598  private:
599  FaceNormalBuffer m_face_normals;
600  std::vector<MQPoint> m_buffer;
601  };
602 
604  class UVFaceBuffer {
605  public:
606 
608  struct UVPoint {
609  MQCoordinate uv;
610  UVPoint( const MQCoordinate& initial_uv ) : uv(initial_uv) {}
616  struct Buffer {
617  typedef uint16_t resolution_type;
618  static const resolution_type resolution = 10;
619  private:
620  typedef std::vector<UVPoint> base_buffer_type;
621  base_buffer_type m_buffer[resolution];
623  friend struct Index;
625  public:
629  struct Index : public std::pair<resolution_type, base_buffer_type::size_type> {
633  typedef std::pair<resolution_type, base_buffer_type::size_type> base_type;
634  Index() : base_type( resolution, 0 ) {}
635  private:
636  Index( resolution_type first, base_buffer_type::size_type second ) : base_type(first, second) {}
637  resolution_type first() const { return base_type::first; }
638  base_buffer_type::size_type second() const { return base_type::second; }
639  };
642  const UVPoint* GetAccessAt( const Index& index ) const {
643  if ( ( index.first() < resolution ) && ( index.second() < m_buffer[index.first()].size() ) ) return &(m_buffer[index.first()][index.second()]);
644  return NULL;
645  }
649  const Index GetIndexOf( const MQCoordinate &uv, const float epsilon ) {
650  const float abs_e = std::abs(epsilon);
651  const resolution_type first = std::min( resolution_type(std::max( uv.u * float(resolution), 0.0f)), resolution_type(resolution - 1) );
652  const base_buffer_type::size_type size = m_buffer[first].size();
653  for ( base_buffer_type::size_type ct = 0; ct < size; ct++ ) {
654  const MQCoordinate& buffer_uv = m_buffer[first][ct].uv;
655  if ( (std::abs(uv.u - buffer_uv.u) < abs_e) && (std::abs(uv.v - buffer_uv.v) < abs_e) ) return Index( first, ct );
656  }
657  m_buffer[first].push_back( UVPoint(uv) );
658  return Index( first, size );
659  }
662  void Clear( const bool isCompact = false ) {
663  for ( int ct = 0; ct < resolution; ct++ ) {
664  if ( isCompact ) base_buffer_type().swap( m_buffer[ct] );
665  else m_buffer[ct].clear();
666  }
667  }
669  void Compact() { for ( int ct = 0; ct < resolution; ct++ ) m_buffer[ct].shrink_to_fit(); }
671  UVPoint& operator [] ( const Index& index ) { return m_buffer[index.first()][index.second()]; }
672  };
673  };
674 
676  struct Face {
678  struct Point {
680  uint32_t color;
681  };
682 
684  struct Buffer {
685  private:
686  typedef std::vector<Face> buffer_type;
687  friend class Polygon::UVFaceBuffer;
688  public:
690  typedef buffer_type::size_type Index;
693  struct IndexBuffer {
695  typedef std::vector<Index>::size_type Index;
697  typedef std::vector<Index>::const_iterator ConstIterator;
699  Face::Buffer::Index operator[] ( IndexBuffer::Index index ) const { return m_buffer[index]; }
703  IndexBuffer::Index ret;
704  if ( Contains( index, &ret ) == false ) {
705  ret = m_buffer.size();
706  m_buffer.push_back(index);
707  }
708  return ret;
709  }
711  ConstIterator Begin() const { return m_buffer.begin(); }
713  bool Contains( const Face::Buffer::Index src, IndexBuffer::Index* find_index = NULL ) const {
714  for ( Index index = 0; index < m_buffer.size(); index++ ) {
715  if ( m_buffer[index] == src ) { if ( find_index != NULL ) *find_index = index; return true; }
716  }
717  return false;
718  }
720  IndexBuffer::Index Count() const { return m_buffer.size(); }
722  ConstIterator End() const { return m_buffer.end(); }
723  private:
724  std::vector<Face::Buffer::Index> m_buffer;
725  };
727  const Face* operator [] ( Index index ) const { if ( index < m_buffer.size() ) return &m_buffer[index]; return NULL; }
729  void Add( const Face& add_item ) { m_buffer.push_back( add_item ); }
731  Index BeginIndex() const { return 0; }
733  void Clear( const bool isCompact = false ) { if ( isCompact ) std::vector<Face>().swap( m_buffer ); else m_buffer.clear(); }
735  void Compact() { m_buffer.shrink_to_fit(); }
737  Index Count() const { return m_buffer.size(); }
739  Index EndIndex() const { return m_buffer.size(); }
741  void Reserve( const Index size ) { m_buffer.reserve( size ); }
742  private:
743  buffer_type m_buffer;
744  };
748  UINT face_uid;
750  std::size_t PointsCount() const { return m_szPoints; }
752  const Point* GetPointFrom( const UVPoint::Buffer::Index& search_index ) const {
753  for ( std::size_t ct = 0; ct < m_szPoints; ct++ ) if ( m_points[ct].index == search_index ) return (m_points + ct);
754  return NULL;
755  }
757  const Point& Points(std::size_t index) const { return m_points[index]; }
758  Face() : m_szPoints(0) {}
759  private:
761  friend class Polygon::UVFaceBuffer;
763  std::size_t m_szPoints;
764  Face::Point m_points[4];
765  };
766 
768  struct Edge {
769 
774  struct VertexPair : public std::pair<UVPoint::Buffer::Index, UVPoint::Buffer::Index> {
775  typedef std::pair<UVPoint::Buffer::Index, UVPoint::Buffer::Index> base_type;
777  : base_type( std::min(first, second), std::max(first, second) ) {}
778  VertexPair( const VertexPair& src ) : base_type( src[0], src[1] ) {}
779  VertexPair( const UVPoint::Buffer::Index* pSrc ) { *this = pSrc; }
780  VertexPair& operator = ( const UVPoint::Buffer::Index* pSrc ) {
782  if ( pSrc != NULL ) {
783  if ( pSrc[0] < pSrc[1] ) {
784  base_type::first = pSrc[0];
785  base_type::second = pSrc[1];
786  }
787  else {
788  base_type::first = pSrc[1];
789  base_type::second = pSrc[0];
790  }
791  }
792  return *this;
793  }
795  VertexPair& operator = ( const VertexPair& src ) { base_type::first = src[0]; base_type::second = src[1]; return *this; }
797  UVPoint::Buffer::Index operator [](int index) const { return index == 0 ? base_type::first : base_type::second; }
799  bool Contains( const UVPoint::Buffer::Index& index ) const { return (base_type::first == index) || (base_type::second == index); }
800  private:
801  UVPoint::Buffer::Index first(); // kill access
802  UVPoint::Buffer::Index second(); // kill access
803  };
804 
806  struct Buffer {
807  private:
808  typedef std::vector<Edge> buffer_type;
809  public:
810  typedef buffer_type::const_iterator ConstIterator;
811  void Add( const VertexPair& vertex_pair, const Face::Buffer::Index& index );
814  ConstIterator Begin() const { return m_buffer.begin(); }
815  void Clear( const bool isCompact = false ) { if ( isCompact ) std::vector<Edge>().swap( m_buffer ); else m_buffer.clear(); }
817  void Compact() { m_buffer.shrink_to_fit(); }
818  ConstIterator End() const { return m_buffer.end(); }
819  private:
820  buffer_type m_buffer;
821  };
822 
823  Edge( const VertexPair& v_pair, Face::Buffer::Index face_index ) : m_vertex_pair(v_pair) { m_owner_faces.Add(face_index); }
824  Edge( const UVPoint::Buffer::Index* pSrc, Face::Buffer::Index face_index ) : m_vertex_pair(pSrc) {
825  if ( pSrc != NULL ) m_owner_faces.Add(face_index);
826  }
828  bool operator == ( const VertexPair& src ) const { return (const VertexPair::base_type&)m_vertex_pair == (const VertexPair::base_type&)src; }
830  const VertexPair& IndexPair() const { return m_vertex_pair; }
833  UVPoint::Buffer::Index IndexPair(int index) const { return m_vertex_pair[index]; }
836  const Face::Buffer::IndexBuffer& Owners() const { return m_owner_faces; }
839  Face::Buffer::Index Owners( const Face::Buffer::IndexBuffer::Index& index ) const { return m_owner_faces[index]; }
840  private:
842  friend struct Edge::Buffer;
844  VertexPair m_vertex_pair;
845  Face::Buffer::IndexBuffer m_owner_faces;
846  };
847 
848  struct Functors {
860  bool operator()( MQCoordinate* const uv_coorinates, DWORD* const colors,
861  const MQObject obj, const int count_of_points, const int face_index, const UINT face_uid ) { return true; }
862  };
863 
877  bool operator()( MQCoordinate* const uv_coorinates, DWORD* const colors,
878  const MQObject obj, const int count_of_points, const int face_index, const UINT face_uid,
879  const MQPoint& normal, MQPoint* const point_normals ) { return true; }
880  };
881 
882  template <class _NormaledCoordinateTransformFunctor> struct CoordinateTransformFunctorFromNormaled {
883  _NormaledCoordinateTransformFunctor functor;
886  MQCoordinate* const uv_coorinates, DWORD* const colors,
887  const MQObject obj, const int count_of_points, const int face_index, const UINT face_uid )
888  {
889  MQPoint v_normal_buffer[4];
890  int v_index_buffer[4];
891  obj->GetFacePointArray( face_index, v_index_buffer );
892  for ( int ctFacePoint = 0; ctFacePoint < count_of_points; ctFacePoint++ ) {
893  v_normal_buffer[ctFacePoint] = m_normal_buffer.VertexNormal( VertexNormalBuffer::size_type(v_index_buffer[ctFacePoint]) );
894  }
895  return functor( uv_coorinates, colors, obj, count_of_points, face_index, face_uid, m_normal_buffer.FaceNormal(face_index), v_normal_buffer );
896  }
897  private:
898  VertexNormalBuffer m_normal_buffer;
899  };
900  };
901 
903  UVFaceBuffer() : m_epsilon( std::numeric_limits<float>::epsilon() ) {}
904 
907  template <class _BasicUVTransformFunctor> void AddObject( const MQObject obj, _BasicUVTransformFunctor& coordinateTrans ) {
908  if ( obj == NULL ) return;
909  MQCoordinate coordinate_buffer[4];
910  DWORD vertex_color_buffer[4];
911  Face add_face;
912  const int ctFaceMax = obj->GetFaceCount();
913  const UINT obj_uid = obj->GetUniqueID();
914  const float eps = m_epsilon;
915  m_face_buffer.Reserve( m_face_buffer.Count() + (Face::Buffer::Index)ctFaceMax );
916  add_face.object_uid = obj_uid;
917  for ( int ctFace = 0; ctFace < ctFaceMax; ctFace++ ) {
918  const UINT uidFace = obj->GetFaceUniqueID( ctFace );
919  const int ctFacePointMax = obj->GetFacePointCount( ctFace );
920  if ( (ctFacePointMax<3)||(4<ctFacePointMax) ) continue;
921  obj->GetFaceCoordinateArray( ctFace, coordinate_buffer );
922  for ( int ctFacePoint = 0; ctFacePoint < ctFacePointMax; ctFacePoint++ ) {
923  vertex_color_buffer[ctFacePoint] = obj->GetFaceVertexColor( ctFace, ctFacePoint );
924  }
925  if ( coordinateTrans( coordinate_buffer, vertex_color_buffer, obj, ctFacePointMax, ctFace, uidFace ) == false ) continue;
926  add_face.face_uid = uidFace;
927  add_face.m_szPoints = ctFacePointMax;
928  for ( int ctFacePoint = 0; ctFacePoint < ctFacePointMax; ctFacePoint++ ) {
929  add_face.m_points[ctFacePoint].index = m_uv_buffer.GetIndexOf( coordinate_buffer[ctFacePoint], eps );
930  add_face.m_points[ctFacePoint].color = vertex_color_buffer[ctFacePoint];
931  }
932  m_face_buffer.Add(add_face);
933  for ( int ctFacePoint = 0; ctFacePoint < ctFacePointMax; ctFacePoint++ ) {
934  int ctFacePointNext = (ctFacePoint < (ctFacePointMax-1)) ? ctFacePoint + 1 : 0;
935  const Edge::VertexPair add_edge( add_face.m_points[ctFacePoint].index, add_face.m_points[ctFacePointNext].index );
936  m_edge_buffer.Add( add_edge, m_face_buffer.Count()-1 );
937  }
938  }
939  }
941  void AddObject( const MQObject obj ) { AddObject( obj, Functors::BasicUVTransformFunctor() ); }
943  template <class _BasicUVTransformFunctor> void AddObjectRecursive(const MQDocument doc, const MQObject obj, _BasicUVTransformFunctor& coordinateTrans)
944  {
945  if ( (doc == NULL) || (obj == NULL) ) return;
946  AddObject( obj, coordinateTrans );
947  const int ctChild = doc->GetChildObjectCount(obj);
948  for ( int indexCh = 0; indexCh < ctChild; indexCh++ ) AddObjectRecursive( doc, doc->GetChildObject( obj, indexCh ), coordinateTrans );
949  }
951  void AddObjectRecursive(const MQDocument doc, const MQObject obj) { AddObjectRecursive(doc, obj, Functors::BasicUVTransformFunctor()); }
952 
955  void Clear( const bool isCompact = false ) { m_edge_buffer.Clear(isCompact); m_face_buffer.Clear(isCompact); m_uv_buffer.Clear(isCompact); }
957  void Compact() { m_uv_buffer.Compact(); m_face_buffer.Compact(); m_edge_buffer.Compact(); }
959  const Edge::Buffer& EdgeBuffer() const { return m_edge_buffer; }
961  float Epsilon() const { return m_epsilon; }
963  float Epsilon( float setValue ) { return m_epsilon = std::abs(setValue); }
965  const Face* FaceBuffer( const Face::Buffer::Index& index ) const { return m_face_buffer[index]; }
967  const Face::Buffer& FaceBuffer() const { return m_face_buffer; }
969  const UVPoint* UVBuffer( const UVPoint::Buffer::Index& index ) const { return m_uv_buffer.GetAccessAt(index); }
970 
971  private:
972  float m_epsilon;
973  UVPoint::Buffer m_uv_buffer;
974  Face::Buffer m_face_buffer;
975  Edge::Buffer m_edge_buffer;
976  };
979 
981  inline void UVFaceBuffer::Edge::Buffer::Add( const Edge::VertexPair& vertex_pair, const Face::Buffer::Index& index ) {
982  for ( buffer_type::iterator itr = m_buffer.begin(); itr != m_buffer.end(); itr++ ) {
983  if ( *itr == vertex_pair ) { itr->m_owner_faces.Add( index ); return; }
984  }
985  m_buffer.push_back( Edge(vertex_pair, index ) );
986  }
988  }
989 
993 #ifdef _DEBUG
995  static const std::vector<char>::size_type GetNameInitialBufferSize = 2;
996 #else
997  static const std::vector<char>::size_type GetNameInitialBufferSize = 32;
998 #endif
999 
1002  inline bool DeleteMaterial( const MQDocument doc, const MQMaterial mat ) {
1003  int index = prv_impl::GetIdentifiedIndex(doc, mat);
1004  if ( index < 0 ) return false;
1005  doc->DeleteMaterial(index); return true;
1006  }
1009  inline bool DeleteObject( const MQDocument doc, const MQObject obj ) {
1010  int index = prv_impl::GetIdentifiedIndex(doc, obj);
1011  if ( index < 0 ) return false;
1012  doc->DeleteObject(index); return true;
1013  }
1026  inline std::string GetCountUpCloneableUniqueName( const MQDocument doc, const MQMaterial src, std::vector<char>* const buf = NULL ) {
1027  return prv_impl::GetCountUpCloneableUniqueName(doc,src,buf);
1028  }
1041  inline std::string GetCountUpCloneableUniqueName( const MQDocument doc, const MQObject src, std::vector<char>* const buf = NULL ) {
1042  return prv_impl::GetCountUpCloneableUniqueName(doc,src,buf);
1043  }
1046  inline MQMaterial GetMaterial( const MQDocument doc, const char* name ) { return prv_impl::GetNamed<MQMaterial>( doc, name ); }
1051  inline MQMaterial GetMaterial( const MQDocument doc, const UINT id ) {
1052  #if 0x0310 <= MQPLUGIN_VERSION
1053  if ( doc != NULL ) return doc->GetMaterialFromUniqueID(id);
1054  return NULL;
1055  #else
1056  return prv_impl::GetIdentified<MQMaterial>( doc, id );
1057  #endif
1058  }
1059 
1061  std::string GetMaterialTextureName( const MQMaterial, DWORD );
1063 
1065  inline std::string GetMaterialAlphaName( const MQMaterial mat ) { return GetMaterialTextureName(mat,MQMAPPING_ALPHA); }
1067  inline std::string GetMaterialBumpName( const MQMaterial mat ) { return GetMaterialTextureName(mat,MQMAPPING_BUMP); }
1070  inline int GetMaterialIndex( const MQDocument doc, const char* name ) { return prv_impl::GetNamedIndex<MQMaterial>( doc, name ); }
1073  inline int GetMaterialIndex( const MQDocument doc, const UINT id ) { return prv_impl::GetIdentifiedIndex<MQMaterial>( doc, id ); }
1081  inline std::string GetMaterialTextureName( const MQMaterial mat, const DWORD map_type = MQMAPPING_TEXTURE ) {
1082  if ( mat != NULL )
1083  {
1084  std::vector<char> buf;
1085  prv_impl::GetMaterialTextureName(&buf, mat, map_type);
1086  return std::string(&buf[0]);
1087  }
1088  return "";
1089  }
1092  inline std::string GetName( const MQMaterial mat ){ return prv_impl::GetName( mat ); }
1095  inline std::string GetName( const MQObject obj ){ return prv_impl::GetName( obj ); }
1098  inline MQObject GetObject( const MQDocument doc, const char* name ) { return prv_impl::GetNamed<MQObject>( doc, name ); }
1103  inline MQObject GetObject( const MQDocument doc, const UINT id ) {
1104  #if 0x0310 <= MQPLUGIN_VERSION
1105  if ( doc != NULL ) return doc->GetObjectFromUniqueID(id);
1106  return NULL;
1107  #else
1108  return prv_impl::GetIdentified<MQObject>(doc, id );
1109  #endif
1110  }
1113  inline int GetObjectIndex( const MQDocument doc, const char* name ) { return prv_impl::GetNamedIndex<MQObject>( doc, name ); }
1116  inline int GetObjectIndex( const MQDocument doc, const UINT id ) { return prv_impl::GetIdentifiedIndex<MQObject>(doc, id ); }
1117 
1118 #if 0x0310 <= MQPLUGIN_VERSION
1119 
1123  inline std::string GetUnusedMaterialName( const MQDocument doc, const char* base_name = NULL ) {
1124  return prv_impl::GetUnusedNameString<MQMaterial>( doc, base_name );
1125  }
1130  inline std::string GetUnusedMaterialName( const MQDocument doc, const MQMaterial base_name_material ) {
1131  if ( base_name_material == NULL ) return prv_impl::GetUnusedNameString<MQMaterial>( doc );
1132  return prv_impl::GetUnusedNameString<MQMaterial>( doc, GetName( base_name_material ).c_str() );
1133  }
1137  inline std::string GetUnusedObjectName( const MQDocument doc, const char* base_name = NULL ) {
1138  return prv_impl::GetUnusedNameString<MQObject>( doc, base_name );
1139  }
1144  inline std::string GetUnusedObjectName( const MQDocument doc, const MQObject base_name_object ) {
1145  if ( base_name_object == NULL ) return prv_impl::GetUnusedNameString<MQMaterial>( doc );
1146  return prv_impl::GetUnusedNameString<MQMaterial>( doc, GetName( base_name_object ).c_str() );
1147  }
1148 
1149 #endif
1150 
1152 
1154 
1155  namespace prv_impl {}; // kill prv_impl access ( to private header implement trap )
1156 };
1157 
1158 #endif