<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href='http://feed.feedsky.com/styles/temp01.xsl' type='text/xsl' ?><!--这是一个由Feedsy提供技术支持的Feed，为了提高读者阅读的体验，以及满足用户美化自己Feed的需要，我们设计了多种精美的Feed模板，提供给大家选择，所有最终呈现出来的样式，皆由用户自愿选择使用，未经许可，任何团体和个人，请不要擅自修改样式或者盗用，这是对于用户选择权的尊重。--><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fs="http://www.feedsky.com/namespace/feed" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link href="http://feed.feedsky.com/NeverSayEver" type="application/rss+xml" rel="self"></atom:link><fs:self_link href="http://feed.feedsky.com/NeverSayEver" type="application/rss+xml"></fs:self_link><lastBuildDate>Tue, 15 May 2012 10:08:53 GMT</lastBuildDate><title>NeverSayEver</title><description>永远不要说永远，我就喜欢这个悖论~</description><link>http://neversayever.com</link><sy:updatePeriod>hourly</sy:updatePeriod><sy:updateFrequency>1</sy:updateFrequency><xhtml:meta name="robots" content="noindex"></xhtml:meta><language>en</language><pubDate>Tue, 15 May 2012 11:39:30 GMT</pubDate><item><title>C++ 中的单例类</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638710121/6973417/1/item.html</link><content:encoded>&lt;p&gt;C++中的单例模式已经看过很多遍了，不过自己实现一个简单的单例类的时候还是出现了一些问题，参考了网上的一些文章，整理如下。&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;#include&amp;lt;memory&amp;gt;
#include&amp;lt;iostream&amp;gt;
class Singleton
{
  private:
  Singleton()
  {
    std::cout&amp;lt;&amp;lt;&quot;Singleton Created!\n&quot;;
    m_number++;
  }
  static Singleton* m_stance;
  static int m_number;

public:
  static Singleton* getInstance()
  {
  if(m_stance == NULL)
    m_stance = new Singleton();
  std::cout&amp;lt;&amp;lt;&quot;instance num: &quot;&amp;lt;&amp;lt;m_number&amp;lt;&amp;lt;std::endl;
  return m_stance;
}
  ~Singleton()
  {
    delete m_stance;
    m_number = 0;
    std::cout&amp;lt;&amp;lt;&quot;Singleton Deleted!\n&quot;;
  }
};

Singleton* Singleton::m_stance = NULL;
int Singleton::m_number = 0;&lt;/pre&gt;
&lt;p&gt;最初版本的单例实现，主要注意几项：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;构造函数私有；&lt;/li&gt;
&lt;li&gt;静态成员变量在类外初始化；&lt;/li&gt;
&lt;li&gt;getInstance()函数为静态函数，只能访问静态成员变量。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;其实最终结果Singleton类的析构函数在程序结束时也没有被调用，所以就有一个疑问，如何才能析构掉这个唯一的单个实例呢？ 由于程序在结束时会自动析构所有全局变量，所有类的静态成员变量，所以根据这个特性可以修改上面的单例类.&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;class CSingleton
{
public:
  static CSingleton&amp;amp; getInstance()
  {
    static CSingleton inst;
    return inst;
  }
  virtual ~CSingleton()
  {
    std::cout&amp;lt;&amp;lt;&quot;CSingleton deleted!\n&quot;;
  }
  CSingleton(const CSingleton&amp;amp; a_inst)
  {
    std::cout&amp;lt;&amp;lt;&quot;copy constructor used!\n&quot;;
  }
private:
  CSingleton()
  {
    std::cout&amp;lt;&amp;lt;&quot;CSingleton created!\n&quot;;
  }

};

int main()
{
  //Singleton* instance = Singleton::getInstance();
  //Singleton* instance2 = Singleton::getInstance();

  CSingleton instance3 = CSingleton::getInstance();

  system(&quot;pause&quot;);
}&lt;/pre&gt;
&lt;p&gt;结果是这样的&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://neversayever.com/wp-content/uploads/2012/05/singleton.jpg&quot;&gt;&lt;img class=&quot;aligncenter size-full wp-image-2218&quot; title=&quot;singleton&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/05/singleton.jpg&quot; alt=&quot;&quot; width=&quot;299&quot; height=&quot;141&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;使用了拷贝构造函数，并且在最后关闭程序时，出现了2句“CSingleton deleted！”，这就违反了我们使用单例类的目的，我仅需要一个实例！不过有一个简单的解决办法：&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;static CSingleton* getInstance()
  {
    static CSingleton inst;
    return &amp;amp;inst;
  }&lt;/pre&gt;
&lt;p&gt;这个单例类适用于单线程，本地静态对象实例inst是第一次调用getInstance()时被构造，一直保持活动状态直到应用程序终止，类中不需要再定义一个静态实例指针。与动态分配对象不同，静态对象当应用程序终止时会被自动销毁，所以不必再手动销毁实例了。&lt;/p&gt;
&lt;p&gt;另一个简单的解决办法是申明拷贝构造函数和申明=号重载，并且只申明不实现。&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;template&amp;lt;class T&amp;gt;
class Singleton
{
public:
  static inline T&amp;amp; instance()
  {
    static T _instance;
    return _instance;
  } 

private:
  Singleton(void);
  ~Singleton(void);
  Singleton(const Singleton&amp;amp;);//不实现
  Singleton&amp;amp; operator= (const Singleton &amp;amp;);//不实现
};&lt;/pre&gt;
&lt;p&gt;另外还有一种方法,可以达到程序结束自动销毁实例的目的,就是用智能指针auto_ptr。&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;#include&amp;lt;memory&amp;gt;
#include&amp;lt;iostream&amp;gt;
using namespace std;
class ASingleton
{
public:
  static ASingleton * Instance()
  {
    if( 0== _instance.get())
    {
      _instance.reset( new ASingleton);
    }
    return _instance.get();
  }
  void run()
  {
        cout&amp;lt;&amp;lt;&quot;call functions of instance!\n&quot;;
  }
protected:
  ASingleton(void)
  {
    cout &amp;lt;&amp;lt;&quot;Create Singleton\n&quot;;
  }
  virtual ~ASingleton(void)
  {
    cout &amp;lt;&amp;lt;&quot;Destroy Singleton\n&quot;;
  }
  friend class auto_ptr&amp;lt;ASingleton&amp;gt;;
  static auto_ptr&amp;lt;ASingleton&amp;gt; _instance;
};
//initialize
auto_ptr&amp;lt;ASingleton&amp;gt; ASingleton::_instance;&lt;/pre&gt;
&lt;p&gt;但是如果每个类要写成单例类都要写这么多代码就太麻烦了，下面的是项目里目前在用的一个单例模板！&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;template&amp;lt;class T&amp;gt;
class Singleton {
public:
    static void init(T* pInstance) {
        Assert(!singletonInstance, &quot;singletonClass has already been intitialized.&quot;);
        singletonInstance = pInstance;
    }
    static void deinit() {
	Assert(singletonInstance != 0, &quot;singletonClass has not been intitialized.&quot;);
        delete singletonInstance;
        singletonInstance = 0;
    }
    static T* getPtr() {
        Assert(singletonInstance != 0, &quot;singletonClass has not been intitialized.&quot;);
        return singletonInstance;
    }
    static T&amp;amp; getRef() {
        Assert(singletonInstance != 0, &quot;singletonClass has not been intitialized.&quot;);
        return *singletonInstance;
    }
    static bool isInited() {
        return (singletonInstance != 0);
    }
private:
    static T* singletonInstance;
};

// init static pointers with 0
template&amp;lt;class T&amp;gt;
T* Singleton&amp;lt;T&amp;gt;::singletonInstance = 0;&lt;/pre&gt;
&lt;p&gt;调用的话需要这么写：&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;Myclass *inst = new Myclass();
typedef Singleton SMyclass;
SMyclass smc;
smc.init(inst);
smc.getPtr()-&amp;gt;......Orz
smc.deInit();&lt;/pre&gt;
&lt;p&gt;很麻烦，初始化，析构什么的都要用户操心，但是却解决了2个问题，一个是线程安全，一个是析构。还有一个优点是不必修改原来的类。但是我很懒，我就想找个用起来方便的，那么咱们继续。&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;#include &amp;lt;memory&amp;gt;
#include &amp;lt;iostream&amp;gt;
using namespace std;
template &amp;lt;class T&amp;gt;
class Singleton
{
public:
  static inline T* instance();

private:
  Singleton(void){}
  ~Singleton(void){}
  Singleton(const Singleton&amp;amp;);
  Singleton &amp;amp; operator= (const Singleton &amp;amp;);

  static auto_ptr&amp;lt;T&amp;gt; _instance;
};

template &amp;lt;class T&amp;gt;
auto_ptr&amp;lt;T&amp;gt; Singleton&amp;lt;T&amp;gt;::_instance;

template &amp;lt;class T&amp;gt;
inline T* Singleton&amp;lt;T&amp;gt;::instance()
{
  if( 0 == _instance.get() )
  {
    //thread lock here
    if( 0== _instance.get())
    {
      _instance.reset ( new T);
    }
  }
  return _instance.get();
}

//Class that will implement the singleton mode,
//must use the macro in it's delare file
#define DECLARE_SINGLETON_CLASS( type ) \
  friend class auto_ptr&amp;lt; type &amp;gt;;\
  friend class Singleton&amp;lt; type &amp;gt;;

class myclass
{
public:
  void run()
  {
    cout&amp;lt;&amp;lt;&quot;call function!\n&quot;;
  }

private:
  myclass(){}
  virtual ~myclass(){}
  DECLARE_SINGLETON_CLASS(myclass);
};&lt;/pre&gt;
&lt;p&gt;用于线程安全的技术是Double-Checked Locking，不过实际上这个方法有缺陷，编译器可能会混乱代码的执行次序，即先设置_instance指针的内容再执行构造函数。&lt;br /&gt;
另外，auto_ptr在某些情况下会出问题，假设有某个单例类A在析构时调用另外一个单例类Log来记录一些日志信息，因为在程序结束时静态成员的析构可能会是任意次序，单例类Log很有可能在A调用析构函数之前就析构了，后果就不用说吧。&lt;/p&gt;
&lt;p&gt;最后附一个boost中的Singleton实现&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;

template &amp;lt;typename T&amp;gt;
class BSingleton
{
private:
  class object_creator
  {
  public:
    object_creator() { BSingleton&amp;lt;T&amp;gt;::instance(); }
    inline void do_nothing() const { }
  };
  static object_creator _object;
  BSingleton();
public:
  typedef T object_type;
  static object_type &amp;amp; instance()
  {
    static object_type obj;
    _object.do_nothing();
    return obj;
  }
};

template &amp;lt;typename T&amp;gt;
typename BSingleton&amp;lt;T&amp;gt;::object_creator BSingleton&amp;lt;T&amp;gt;::_object;

class myclass
{
public:
  void run()
  {
    std::cout&amp;lt;&amp;lt;&quot;call function!\n&quot;;
  }

  myclass()
  {
    std::cout&amp;lt;&amp;lt;&quot;call constructor!\n&quot;;
  }
  virtual ~myclass(){}
};

//in main()
//BSingleton&amp;lt;myclass&amp;gt;::instance().run();&lt;/pre&gt;
&lt;p&gt;在单例类中嵌套一个局部类型，并申明一个静态变量，在main函数执行之前就预先初始化了单例类，所以应该是线程安全的并且也能够很好的析构，因为静态或全局变量会在程序退出的时候执行它的析构函数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PS：&lt;/strong&gt; typename 用于使用嵌套依赖类型，这里由于 object_creator 是在 BSingleton 中定义的，所以作用域符号”::”前需要写上typename。&lt;/p&gt;
&lt;p&gt;参考文档：&lt;a href=&quot;http://www.cppblog.com/dyj057/archive/2005/09/20/346.html&quot;&gt;1&lt;/a&gt;&lt;a href=&quot;http://www.360doc.com/content/12/0215/18/1317564_186881516.shtml&quot;&gt;2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;本文固定链接：&lt;a href=&quot;http://neversayever.com/blog/2012/05/2213/&quot;&gt;http://neversayever.com/blog/2012/05/2213/&lt;/a&gt;，如非特殊说明均为原创，转载请保留此句。&lt;/p&gt;
&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/05/2213/&quot;&gt;C++ 中的单例类&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638710121/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638710121/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://neversayever.com/blog/2012/05/2213/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&lt;p&gt;C++中的单例模式已经看过很多遍了，不过自己实现一个简单的单例类的时候还是出现了一些问题，参考了网上的一些文章，整理如下。
&lt;pre class=&quot;brush:cpp&quot;&gt;#include&amp;#60;memory&amp;#62;
#include&amp;#60;iostream&amp;#62;
class Singleton
{
  private:
  Singleton()
  {
    std::cout&amp;#60;&amp;#60;&quot;Singleton Created!\n&quot;;
    m_number++;
  }
  static Singleton* m_stance;
  static int m_number;

public:
  static Singleton* getInstance()
  {
  if(m_stance == NULL)
    m_stance = new Singleton();
  std::cout&amp;#60;&amp;#60;&quot;instance num: &quot;&amp;#60;&amp;#60;m_number&amp;#60;&amp;#60;std::endl;
  return m_stance;
}
  ~Singleton()
  {
    delete m_stance;
    m_number = 0;
    std::cout&amp;#60;&amp;#60;&quot;Singleton Deleted!\n&quot;;
  }
};

Singleton* Singleton::m_stance = NULL;
int Singleton::m_number = 0;&lt;/pre&gt;
最初版本的单例实现，主要注意几项：
&lt;ol&gt;
	&lt;li&gt;构造函数私有；&lt;/li&gt;
	&lt;li&gt;静态成员变量在类外初始化；&lt;/li&gt;
	&lt;li&gt;getInstance()函数为静态函数，只能访问静态成员变量。&lt;/li&gt;
&lt;/ol&gt;
其实最终结果Singleton类的析构函数在程序结束时也没有被调用，所以就有一个疑问，如何才能析构掉这个唯一的单个实例呢？ 由于程序在结束时会自动析构所有全局变量，所有类的静态成员变量，所以根据这个特性可以修改上面的单例类.
&lt;pre class=&quot;brush:cpp&quot;&gt;class CSingleton
{
public:
  static CSingleton&amp;#38; getInstance()
  {
    static CSingleton inst;
    return inst;
  }
  virtual ~CSingleton()
  {
    std::cout&amp;#60;&amp;#60;&quot;CSingleton deleted!\n&quot;;
  }
  CSingleton(const CSingleton&amp;#38; a_inst)
  {
    std::cout&amp;#60;&amp;#60;&quot;copy constructor used!\n&quot;;
  }
private:
  CSingleton()
  {
    std::cout&amp;#60;&amp;#60;&quot;CSingleton created!\n&quot;;
  }

};

int main()
{
  //Singleton* instance = Singleton::getInstance();
  //Singleton* instance2 = Singleton::getInstance();

  CSingleton instance3 = CSingleton::getInstance();

  system(&quot;pause&quot;);
}&lt;/pre&gt;
结果是这样的

&lt;a href=&quot;http://neversayever.com/wp-content/uploads/2012/05/singleton.jpg&quot;&gt;&lt;img class=&quot;aligncenter size-full wp-image-2218&quot; title=&quot;singleton&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/05/singleton.jpg&quot; alt=&quot;&quot; width=&quot;299&quot; height=&quot;141&quot; /&gt;&lt;/a&gt;

使用了拷贝构造函数，并且在最后关闭程序时，出现了2句“CSingleton deleted！”，这就违反了我们使用单例类的目的，我仅需要一个实例！不过有一个简单的解决办法：
&lt;pre class=&quot;brush:cpp&quot;&gt;static CSingleton* getInstance()
  {
    static CSingleton inst;
    return &amp;#38;inst;
  }&lt;/pre&gt;
这个单例类适用于单线程，本地静态对象实例inst是第一次调用getInstance()时被构造，一直保持活动状态直到应用程序终止，类中不需要再定义一个静态实例指针。与动态分配对象不同，静态对象当应用程序终止时会被自动销毁，所以不必再手动销毁实例了。

另一个简单的解决办法是申明拷贝构造函数和申明=号重载，并且只申明不实现。
&lt;pre class=&quot;brush:cpp&quot;&gt;template&amp;#60;class T&amp;#62; 
class Singleton 
{ 
public: 
  static inline T&amp;#38; instance() 
  { 
    static T _instance; 
    return _instance; 
  } 

private: 
  Singleton(void); 
  ~Singleton(void); 
  Singleton(const Singleton&amp;#38;);//不实现
  Singleton&amp;#38; operator= (const Singleton &amp;#38;);//不实现 
};&lt;/pre&gt;
另外还有一种方法,可以达到程序结束自动销毁实例的目的,就是用智能指针auto_ptr。
&lt;pre class=&quot;brush:cpp&quot;&gt;#include&amp;#60;memory&amp;#62;
#include&amp;#60;iostream&amp;#62;
using namespace std;
class ASingleton
{
public:
  static ASingleton * Instance()
  {
    if( 0== _instance.get())
    {
      _instance.reset( new ASingleton);
    }
    return _instance.get();
  }
  void run()
  {
        cout&amp;#60;&amp;#60;&quot;call functions of instance!\n&quot;;
  }
protected:
  ASingleton(void)
  {
    cout &amp;#60;&amp;#60;&quot;Create Singleton\n&quot;;
  }
  virtual ~ASingleton(void)
  {
    cout &amp;#60;&amp;#60;&quot;Destroy Singleton\n&quot;;
  }
  friend class auto_ptr&amp;#60;ASingleton&amp;#62;;
  static auto_ptr&amp;#60;ASingleton&amp;#62; _instance;
};
//initialize
auto_ptr&amp;#60;ASingleton&amp;#62; ASingleton::_instance;&lt;/pre&gt;
但是如果每个类要写成单例类都要写这么多代码就太麻烦了，下面的是项目里目前在用的一个单例模板！
&lt;pre class=&quot;brush:cpp&quot;&gt;template&amp;#60;class T&amp;#62;
class Singleton {
public:
    static void init(T* pInstance) {
        Assert(!singletonInstance, &quot;singletonClass has already been intitialized.&quot;);
        singletonInstance = pInstance;
    }
    static void deinit() {
	Assert(singletonInstance != 0, &quot;singletonClass has not been intitialized.&quot;);
        delete singletonInstance;
        singletonInstance = 0;
    }
    static T* getPtr() {
        Assert(singletonInstance != 0, &quot;singletonClass has not been intitialized.&quot;);
        return singletonInstance;
    }
    static T&amp;#38; getRef() {
        Assert(singletonInstance != 0, &quot;singletonClass has not been intitialized.&quot;);
        return *singletonInstance;
    }
    static bool isInited() {
        return (singletonInstance != 0);
    }
private:
    static T* singletonInstance;
};

// init static pointers with 0
template&amp;#60;class T&amp;#62;
T* Singleton&amp;#60;T&amp;#62;::singletonInstance = 0;&lt;/pre&gt;
调用的话需要这么写：
&lt;pre class=&quot;brush:cpp&quot;&gt;Myclass *inst = new Myclass();
typedef Singleton SMyclass;
SMyclass smc;
smc.init(inst);
smc.getPtr()-&amp;#62;......Orz
smc.deInit();&lt;/pre&gt;
很麻烦，初始化，析构什么的都要用户操心，但是却解决了2个问题，一个是线程安全，一个是析构。还有一个优点是不必修改原来的类。但是我很懒，我就想找个用起来方便的，那么咱们继续。
&lt;pre class=&quot;brush:cpp&quot;&gt;#include &amp;#60;memory&amp;#62;
#include &amp;#60;iostream&amp;#62;
using namespace std;
template &amp;#60;class T&amp;#62;
class Singleton
{
public:
  static inline T* instance();

private:
  Singleton(void){}
  ~Singleton(void){}
  Singleton(const Singleton&amp;#38;);
  Singleton &amp;#38; operator= (const Singleton &amp;#38;);

  static auto_ptr&amp;#60;T&amp;#62; _instance;
};

template &amp;#60;class T&amp;#62;
auto_ptr&amp;#60;T&amp;#62; Singleton&amp;#60;T&amp;#62;::_instance;

template &amp;#60;class T&amp;#62;
inline T* Singleton&amp;#60;T&amp;#62;::instance()
{
  if( 0 == _instance.get() )
  {
    //thread lock here
    if( 0== _instance.get())
    {
      _instance.reset ( new T);
    }
  }
  return _instance.get();
}

//Class that will implement the singleton mode,
//must use the macro in it's delare file
#define DECLARE_SINGLETON_CLASS( type ) \
  friend class auto_ptr&amp;#60; type &amp;#62;;\
  friend class Singleton&amp;#60; type &amp;#62;;

class myclass
{
public:
  void run()
  {
    cout&amp;#60;&amp;#60;&quot;call function!\n&quot;;
  }

private:
  myclass(){}
  virtual ~myclass(){}
  DECLARE_SINGLETON_CLASS(myclass);
};&lt;/pre&gt;
用于线程安全的技术是Double-Checked Locking，不过实际上这个方法有缺陷，编译器可能会混乱代码的执行次序，即先设置_instance指针的内容再执行构造函数。
另外，auto_ptr在某些情况下会出问题，假设有某个单例类A在析构时调用另外一个单例类Log来记录一些日志信息，因为在程序结束时静态成员的析构可能会是任意次序，单例类Log很有可能在A调用析构函数之前就析构了，后果就不用说吧。

最后附一个boost中的Singleton实现
&lt;pre class=&quot;brush:cpp&quot;&gt;#include &amp;#60;iostream&amp;#62;

template &amp;#60;typename T&amp;#62; 
class BSingleton 
{ 
private: 
  class object_creator 
  {
  public:
    object_creator() { BSingleton&amp;#60;T&amp;#62;::instance(); } 
    inline void do_nothing() const { } 
  };
  static object_creator _object; 
  BSingleton(); 
public: 
  typedef T object_type; 
  static object_type &amp;#38; instance() 
  { 
    static object_type obj; 
    _object.do_nothing(); 
    return obj; 
  } 
};

template &amp;#60;typename T&amp;#62; 
typename BSingleton&amp;#60;T&amp;#62;::object_creator BSingleton&amp;#60;T&amp;#62;::_object;

class myclass
{
public:
  void run()
  {
    std::cout&amp;#60;&amp;#60;&quot;call function!\n&quot;;
  }

  myclass()
  {
    std::cout&amp;#60;&amp;#60;&quot;call constructor!\n&quot;;
  }
  virtual ~myclass(){}
};

//in main()
//BSingleton&amp;#60;myclass&amp;#62;::instance().run();&lt;/pre&gt;
在单例类中嵌套一个局部类型，并申明一个静态变量，在main函数执行之前就预先初始化了单例类，所以应该是线程安全的并且也能够很好的析构，因为静态或全局变量会在程序退出的时候执行它的析构函数。

&lt;strong&gt;PS：&lt;/strong&gt; typename 用于使用嵌套依赖类型，这里由于 object_creator 是在 BSingleton 中定义的，所以作用域符号&quot;::&quot;前需要写上typename。

参考文档：&lt;a href=&quot;http://www.cppblog.com/dyj057/archive/2005/09/20/346.html&quot;&gt;1&lt;/a&gt;&lt;a href=&quot;http://www.360doc.com/content/12/0215/18/1317564_186881516.shtml&quot;&gt;2&lt;/a&gt;

本文固定链接：&lt;a href=&quot;http://neversayever.com/blog/2012/05/2213/&quot;&gt;http://neversayever.com/blog/2012/05/2213/&lt;/a&gt;，如非特殊说明均为原创，转载请保留此句。&lt;/p&gt;&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/05/2213/&quot;&gt;C++ 中的单例类&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638710121/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638710121/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>C++ Singleton 单例类</category><category>技术</category><pubDate>Tue, 15 May 2012 18:08:53 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/05/2213/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2213</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/05/2213/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/638710121/6973417</fs:itemid></item><item><title>C++ 的 RTTI</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307175/6973417/1/item.html</link><content:encoded>&lt;p&gt;&lt;strong&gt;RTTI：Run Time Type Information&lt;/strong&gt;&lt;br /&gt;
参见：&lt;a href=&quot;http://en.wikipedia.org/wiki/Run-time_type_information&quot;&gt;维基百科RTTI&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在《大话设计模式》中有一章是抽象工厂模式，由于抽象工厂模式在使用时，当需要添加具体加工任务的时候，需要修改很多工厂类，非常麻烦，所以“大鸟”（一个在面向对象界脸不红心不跳，战果累累的家伙）就提出说用“反射”结合抽象工厂实现。&lt;/p&gt;
&lt;p&gt;反射主要用在当你需要写一些通用的代码，这些代码处理的对象在你写 code 的时候你还不知道，仅当程序运行了才会知道，但你需要知道程序运行的时候这些对象到底是什么你才能做下一步的任务，比如调用它的方法什么的。很多地方会用到这种特性，比如处理不同的数据库，需要不同的方法，具体用哪种数据库（Oracle，SqlServer，Access）不知道；不同对象的序列化等等。所以需要有一个对类的描述，你可以动态查找这个对象到底是什么类型。很多语言有这种内建反射机制，比如java，c#。&lt;/p&gt;
&lt;p&gt;作者用的C#，C#的 System.Reflection 定义了这种方法，可以在运行时决定实例化哪个类。客户端无需任何修改，看得我是羡慕嫉妒恨啊，于是google之，C++ 的 Reflect 有木有呢？&lt;/p&gt;
&lt;p&gt;答案是&lt;strong&gt;木有&lt;/strong&gt;，但C++ 有RTTI。RTTI主要用在C++多态的特性上，通过在内存中存储变量类型，程序就可以在运行时动态确定基类的指针指的到底是哪个子类了。&lt;/p&gt;
&lt;p&gt;但是，&lt;strong&gt;为什么C++没有反射这个特性呢？&lt;/strong&gt;&lt;br /&gt;
参见：&lt;a href=&quot;http://stackoverflow.com/questions/359237/why-does-c-not-have-reflection&quot;&gt;why-does-c-not-have-reflection&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;添加这个特性需要做很多工作，显然C++委员会是比较保守的，在权衡完利弊，这个特性并非具有很高优先级之前他们是不会加进去的。&lt;/li&gt;
&lt;li&gt;添加反射特性使最后编译完的程序携带很多不必要的元数据，既然程序用不到为什么要带着呢，就像明明是晴天并且你确定不会下雨，但你还是带了雨伞，穿了雨鞋一样。&lt;/li&gt;
&lt;li&gt;C++对编译后的代码做的限制非常少，因而编译器很自由，编译器可以爱怎么编就怎么编，只要最后程序能给出预期的结果。比如只调用了一个类的inline函数，编译器也许就压根没把这个类编译进去，只需替换inline函数就完事了。vector中的[]运算符效率能比得上数组寻址是因为编译器直接把这个操作编译成了数组寻址。C++要实现反射就必须再最终可执行程序中保存所有类的信息。&lt;/li&gt;
&lt;li&gt;C++有模板类，每个模板的实例化都创建了新的类型，vector&amp;lt;int&amp;gt;和vector&amp;lt;float&amp;gt;完全是两个类，还有各种iterator，要都保存这些信息，&lt;/li&gt;
&lt;li&gt;最后，反射对C++来说不是必须的，因为有模板元编程。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本文固定链接：&lt;a href=&quot;http://neversayever.com/blog/2012/05/2204/&quot;&gt;http://neversayever.com/blog/2012/05/2204/&lt;/a&gt; 如非特殊说明，均为原创，转载请注明出处。&lt;/p&gt;
&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/05/2204/&quot;&gt;C++ 的 RTTI&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307175/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307175/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://neversayever.com/blog/2012/05/2204/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&lt;p&gt;&lt;strong&gt;RTTI：Run Time Type Information&lt;/strong&gt;
参见：&lt;a href=&quot;http://en.wikipedia.org/wiki/Run-time_type_information&quot;&gt;维基百科RTTI&lt;/a&gt;

在《大话设计模式》中有一章是抽象工厂模式，由于抽象工厂模式在使用时，当需要添加具体加工任务的时候，需要修改很多工厂类，非常麻烦，所以“大鸟”（一个在面向对象界脸不红心不跳，战果累累的家伙）就提出说用“反射”结合抽象工厂实现。

反射主要用在当你需要写一些通用的代码，这些代码处理的对象在你写 code 的时候你还不知道，仅当程序运行了才会知道，但你需要知道程序运行的时候这些对象到底是什么你才能做下一步的任务，比如调用它的方法什么的。很多地方会用到这种特性，比如处理不同的数据库，需要不同的方法，具体用哪种数据库（Oracle，SqlServer，Access）不知道；不同对象的序列化等等。所以需要有一个对类的描述，你可以动态查找这个对象到底是什么类型。很多语言有这种内建反射机制，比如java，c#。

作者用的C#，C#的 System.Reflection 定义了这种方法，可以在运行时决定实例化哪个类。客户端无需任何修改，看得我是羡慕嫉妒恨啊，于是google之，C++ 的 Reflect 有木有呢？

答案是&lt;strong&gt;木有&lt;/strong&gt;，但C++ 有RTTI。RTTI主要用在C++多态的特性上，通过在内存中存储变量类型，程序就可以在运行时动态确定基类的指针指的到底是哪个子类了。

但是，&lt;strong&gt;为什么C++没有反射这个特性呢？&lt;/strong&gt;
参见：&lt;a href=&quot;http://stackoverflow.com/questions/359237/why-does-c-not-have-reflection&quot;&gt;why-does-c-not-have-reflection&lt;/a&gt;
&lt;ol&gt;
	&lt;li&gt;添加这个特性需要做很多工作，显然C++委员会是比较保守的，在权衡完利弊，这个特性并非具有很高优先级之前他们是不会加进去的。&lt;/li&gt;
	&lt;li&gt;添加反射特性使最后编译完的程序携带很多不必要的元数据，既然程序用不到为什么要带着呢，就像明明是晴天并且你确定不会下雨，但你还是带了雨伞，穿了雨鞋一样。&lt;/li&gt;
	&lt;li&gt;C++对编译后的代码做的限制非常少，因而编译器很自由，编译器可以爱怎么编就怎么编，只要最后程序能给出预期的结果。比如只调用了一个类的inline函数，编译器也许就压根没把这个类编译进去，只需替换inline函数就完事了。vector中的[]运算符效率能比得上数组寻址是因为编译器直接把这个操作编译成了数组寻址。C++要实现反射就必须再最终可执行程序中保存所有类的信息。&lt;/li&gt;
	&lt;li&gt;C++有模板类，每个模板的实例化都创建了新的类型，vector&amp;#60;int&amp;#62;和vector&amp;#60;float&amp;#62;完全是两个类，还有各种iterator，要都保存这些信息，&lt;/li&gt;
	&lt;li&gt;最后，反射对C++来说不是必须的，因为有模板元编程。&lt;/li&gt;
&lt;/ol&gt;
本文固定链接：&lt;a href=&quot;http://neversayever.com/blog/2012/05/2204/&quot;&gt;http://neversayever.com/blog/2012/05/2204/&lt;/a&gt; 如非特殊说明，均为原创，转载请注明出处。&lt;/p&gt;&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/05/2204/&quot;&gt;C++ 的 RTTI&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307175/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307175/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>C++</category><category>RTTI</category><category>Reflection</category><category>反射</category><category>技术</category><pubDate>Mon, 14 May 2012 21:15:23 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/05/2204/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2204</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/05/2204/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/638307175/6973417</fs:itemid></item><item><title>hello windows phone 7</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307176/6973417/1/item.html</link><content:encoded>&lt;p&gt;昨天看到微软联合诺记在北京搞了个“春”phone，windows phone 7 开发学习计划。帮主开发者能迅速掌握开发wp7 app的技能。&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/03/windows-phone-7.jpg&quot; width=&quot;382&quot; height=&quot;258&quot; /&gt;&lt;/p&gt;
&lt;p&gt;我就去凑了个热闹，其中要在marketPlace发布自己编写的APP需要有开发者认证的账号，并且需要支付99美金。但是学生有优惠，只要认证你是学生，就可以免费发布app。在中国高校，只要有学校的edu.cn邮箱就可以顺利认证了。&lt;/p&gt;
&lt;p&gt;昨天装完了windows phone 7.1 SDK，今天下午就着第一个下载的教程“hello Phone”完成了编写wp7 app的初体验。&lt;/p&gt;
&lt;p&gt;这个“hello phone”教程有59页，在教授过程中，包含了使用sdk中2个主要软件(vs 2010 express for wp &amp;amp; blend 4)的方法，从界面设计，逻辑代码编写，最浅显的事件机制都有说明，并且图文并茂，深入浅出。主要介绍了利用sliverLight framework 设计和定制界面，自定义控件模板，添加动画效果。并且在模拟器上运行程序效果也很好。&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/03/图片1.png&quot; width=&quot;157&quot; height=&quot;286&quot; /&gt;&lt;/p&gt;
&lt;p&gt;3月底marketPlace将进驻包括中国的其他23个国家，windows phone 来势汹汹啊。&lt;/p&gt;
&lt;p&gt;由于实验室网络，或者景德镇网络的问题，今天才能上网站，于是~~~&lt;/p&gt;
&lt;p&gt;截止发稿，MarketPlace已经开放。windows 8 consumer preview也发布了。&lt;/p&gt;
&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/03/2198/&quot;&gt;hello windows phone 7&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307176/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307176/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://neversayever.com/blog/2012/03/2198/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&lt;p&gt;&lt;p&gt;昨天看到微软联合诺记在北京搞了个“春”phone，windows phone 7 开发学习计划。帮主开发者能迅速掌握开发wp7 app的技能。&lt;/p&gt;  &lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/03/windows-phone-7.jpg&quot; width=&quot;382&quot; height=&quot;258&quot; /&gt;&lt;/p&gt;  &lt;p&gt;我就去凑了个热闹，其中要在marketPlace发布自己编写的APP需要有开发者认证的账号，并且需要支付99美金。但是学生有优惠，只要认证你是学生，就可以免费发布app。在中国高校，只要有学校的edu.cn邮箱就可以顺利认证了。&lt;/p&gt;  &lt;p&gt;昨天装完了windows phone 7.1 SDK，今天下午就着第一个下载的教程“hello Phone”完成了编写wp7 app的初体验。&lt;/p&gt;  &lt;p&gt;这个“hello phone”教程有59页，在教授过程中，包含了使用sdk中2个主要软件(vs 2010 express for wp &amp;#38; blend 4)的方法，从界面设计，逻辑代码编写，最浅显的事件机制都有说明，并且图文并茂，深入浅出。主要介绍了利用sliverLight framework 设计和定制界面，自定义控件模板，添加动画效果。并且在模拟器上运行程序效果也很好。&lt;/p&gt;  &lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/03/图片1.png&quot; width=&quot;157&quot; height=&quot;286&quot; /&gt;&lt;/p&gt;  &lt;p&gt;3月底marketPlace将进驻包括中国的其他23个国家，windows phone 来势汹汹啊。&lt;/p&gt;  &lt;p&gt;由于实验室网络，或者景德镇网络的问题，今天才能上网站，于是~~~&lt;/p&gt;  &lt;p&gt;截止发稿，MarketPlace已经开放。windows 8 consumer preview也发布了。&lt;/p&gt;&lt;/p&gt;&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/03/2198/&quot;&gt;hello windows phone 7&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307176/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307176/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>Windows Phone 7</category><category>杂七杂八</category><pubDate>Thu, 01 Mar 2012 13:18:03 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/03/2198/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2198</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/03/2198/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/638307176/6973417</fs:itemid></item><item><title>mesh 模型层次结构</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307177/6973417/1/item.html</link><content:encoded>&lt;h2&gt;层次结构&lt;/h2&gt;
&lt;p&gt;Assmip中的readFile函数将model读入到了scene（场景）中，并且有一套树状层次结构，在别的软件中，model读入后内部的数据结构应该也大同小异，所以我就由Assimp的数据结构总结一下：&lt;/p&gt;
&lt;p&gt;node节点是scene中有名字的小实体，有一个地方存放指向其父亲的指针。从scene的root node开始，每一个node可以由0到n个子node，这样就形成了一个层次结构。&lt;/p&gt;
&lt;p&gt;一个node中有0到n个mesh，mesh能够被骨骼引用，或者能够通过一系列的动画驱动。DirectX称之为“frames”帧，其他称之为“objects”物体，在Assimp中称之为aiNode。&lt;/p&gt;
&lt;p&gt;一个节点能够引用到一个或多个mesh，但是mesh并不是存储在node里面的，而是aiScene中的一个aiMesh数组。node只存储了指向mesh数组的下标，所以是int*，或者unsigned int*。然后你要通过scene获得具体数据。这也表示了不同的node可能会引用同一个mesh。&lt;/p&gt;
&lt;p&gt;通过node引用的mesh将存在于node局部坐标系内。如果你想将mesh定位到全局坐标，你不得不连接从当前node和它所有父亲的变换矩阵。所以每个node里面存储了一个将当前node转换到其父亲node坐标系的变换矩阵。&lt;/p&gt;
&lt;p&gt;然而，许多文件格式不支持复杂场景，只有单个的模型。但是还是有很多复杂的格式，例如.3ds，.x或者.collada，这些场景或许会包含任意复杂的，由节点和网格组成的层次结构。于是需要一个递归调用的函数来遍历整个scene&lt;/p&gt;
&lt;h2&gt;Mesh&lt;/h2&gt;
&lt;p&gt;一个mesh在任何地方仅适用单个的material，如果模型的一部分适用了不同的材质，则这一部分mesh将会移动到相同node 的不同mesh上。mesh引用材质和node引用mesh是同一个道理：material存储在aiScene中的一个数组内，mesh只保存了这个数组下标的引用。&lt;/p&gt;
&lt;p&gt;一个aiMesh是由很多数据通道组成的，这些数据有些来自模型文件，有些是后期处理得到的。2个一定会有的数据通道是vertices和faces。Importer::ReadFile()中的post processing标志可以计算或重新计算一些数据，例如法向量，三角化等。&lt;/p&gt;
&lt;p&gt;一个vertex总是有一个3维坐标，除此之外，也许有一个法向量，一个切向量，或双切向量，材质坐标，颜色。其他还可能含有骨骼信息。&lt;/p&gt;
&lt;h2&gt;texture&lt;/h2&gt;
&lt;p&gt;通常模型的材质文件和模型文件分开存放，但也有一些文件格式将材质嵌入到了模型文件中。这些材质被加载进了aiTexture结构中。&lt;/p&gt;
&lt;p&gt;有2种情况：&lt;/p&gt;
&lt;p&gt;1）材质没有被压缩。那么它的颜色信息直接存储在aiTexture中，是一个宽度*高度的2维数组。Assimp中这个2维数组每个元素为一个aiTexel，代表材质图片的一个像素。颜色信息存储在unsigned RGBA8888格式中。适用于D3D和OpenGL。&lt;/p&gt;
&lt;p&gt;2）如果材质的高度=0，那么材质图片存储在压缩格式，如DDS或者PNG中，那么需要一些图片库来读取这些文件，比如开源的图片库DevIL（&lt;a href=&quot;http://openil.sourceforge.net/about.php&quot; target=&quot;_blank&quot;&gt;developer&amp;#8217;s Image Library&lt;/a&gt;）或者&lt;a href=&quot;http://freeimage.sourceforge.net/&quot; target=&quot;_blank&quot;&gt;freeimage&lt;/a&gt;。aiTexture::mWidth表示图片有多少字节，aiTexture::pcData是一个指向raw图片数据的指针，aiTexture::achFormathint表示材质后缀。&lt;/p&gt;
&lt;p&gt;示例程序中的材质使用是用DevIL库读取文件后，直接用glGenTextures()，glBindTexture()，glTexParameteri()，glTexImage2D()做好了opengl材质。跟Assimp木有关系。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;纹理和材质到底干嘛的&lt;/h2&gt;
&lt;p&gt;网上找来的一段关于texture 和 material 的说明&lt;/p&gt;
&lt;p style=&quot;text-align: left; widows: 2; text-transform: none; background-color: #ffffff; text-indent: 0px; margin: 0px 0px 1em; letter-spacing: normal; font: 14px/18px 'WenQuanYi Micro Hei Mono', 'WenQuanYi Micro Hei', 'Microsoft Yahei Mono', 'Microsoft Yahei', sans-serif; word-wrap: break-word; white-space: normal; orphans: 2; color: #000000; clear: both; vertical-align: baseline; word-spacing: 0px; border-image: initial; background-origin: initial; background-clip: initial; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; border-width: 0px; padding: 0px;&quot;&gt;In OpenGL, a&lt;span class=&quot;Apple-converted-space&quot;&gt; &lt;/span&gt;&lt;strong style=&quot;background-color: transparent; margin: 0px; font-family: 'WenQuanYi Micro Hei Mono', 'WenQuanYi Micro Hei', 'Microsoft Yahei Mono', 'Microsoft Yahei', sans-serif !important; font-size: 14px; vertical-align: baseline; font-weight: bold; border-image: initial; background-origin: initial; background-clip: initial; border-width: 0px; padding: 0px;&quot;&gt;material&lt;/strong&gt;&lt;span class=&quot;Apple-converted-space&quot;&gt; &lt;/span&gt;is a set of coefficients that define how the lighting model interacts with the surface. In particular, ambient, diffuse, and specular coefficients for each color component (R,G,B) are defined and applied to a surface and effectively multiplied by the amount of light of each kind/color that strikes the surface. A final emmisivity coefficient is then added to each color component that allows objects to appear luminous without actually interacting with other objects.&lt;/p&gt;
&lt;p style=&quot;text-align: left; widows: 2; text-transform: none; background-color: #ffffff; text-indent: 0px; margin: 0px 0px 1em; letter-spacing: normal; font: 14px/18px 'WenQuanYi Micro Hei Mono', 'WenQuanYi Micro Hei', 'Microsoft Yahei Mono', 'Microsoft Yahei', sans-serif; word-wrap: break-word; white-space: normal; orphans: 2; color: #000000; clear: both; vertical-align: baseline; word-spacing: 0px; border-image: initial; background-origin: initial; background-clip: initial; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; border-width: 0px; padding: 0px;&quot;&gt;A&lt;span class=&quot;Apple-converted-space&quot;&gt; &lt;/span&gt;&lt;strong style=&quot;background-color: transparent; margin: 0px; font-family: 'WenQuanYi Micro Hei Mono', 'WenQuanYi Micro Hei', 'Microsoft Yahei Mono', 'Microsoft Yahei', sans-serif !important; font-size: 14px; vertical-align: baseline; font-weight: bold; border-image: initial; background-origin: initial; background-clip: initial; border-width: 0px; padding: 0px;&quot;&gt;texture&lt;/strong&gt;, on the other hand, is a set of 1-, 2-, 3-, or 4- dimensional bitmap (image) data that is applied and interpolated on to a surface according to texture coordinates at the vertices. Texture data alters the color of the surface whether or not lighting is enabled (and depending on the texture mode, e.g. decal, modulate, etc.). Textures are used frequently to provide sub-polygon level detail to a surface, e.g. applying a repeating brick and mortar texture to a quad to simulate a brick wall, rather than modeling the geometry of each individual brick.&lt;/p&gt;
&lt;p style=&quot;text-align: left; widows: 2; text-transform: none; background-color: #ffffff; text-indent: 0px; margin: 0px 0px 1em; letter-spacing: normal; font: 14px/18px 'WenQuanYi Micro Hei Mono', 'WenQuanYi Micro Hei', 'Microsoft Yahei Mono', 'Microsoft Yahei', sans-serif; word-wrap: break-word; white-space: normal; orphans: 2; color: #000000; clear: both; vertical-align: baseline; word-spacing: 0px; border-image: initial; background-origin: initial; background-clip: initial; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; border-width: 0px; padding: 0px;&quot;&gt;In the classical (fixed-pipeline) OpenGL model, textures and materials are somewhat orthogonal. In the new programmable shader world, the line has blurred quite a bit. Frequently textures are used to influence lighting in other ways. For example, bump maps are textures that are used to perturb surface normals to effect lighting, rather than modifying pixel color directly as a regular “image” texture would.&lt;/p&gt;
&lt;h2&gt;material&lt;/h2&gt;
&lt;p&gt;所有material存储在aiScene中aiMaterial数组中。由于材质定义各不相同，所以没有一个固定的数据结构。材质事实上通过一系列的属性来定义，并由一个名字索引而得到。&lt;/p&gt;
&lt;p&gt;Assimp中获得材质属性的函数很简单（一个模板函数）get();&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;aiMaterial* mat = ...
// The generic way
if(AI_SUCCESS != mat-&amp;gt;Get((material-key,where-to-store)){
   // handle epic failure here
}&lt;/pre&gt;
&lt;p&gt;悲催的是我的Qt版模型读取和显式程序调试了下午+晚上还是没有搞定。Assimp库是C实现，提供C++和C接口，源代码看着也不是很爽快，各种数组和指针的混淆也造成了VS debug的困难。今天不搞了，明天继续&amp;#8230;&lt;/p&gt;
&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2190/&quot;&gt;mesh 模型层次结构&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307177/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307177/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://neversayever.com/blog/2012/02/2190/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&lt;p&gt;&lt;h2&gt;层次结构&lt;/h2&gt;
Assmip中的readFile函数将model读入到了scene（场景）中，并且有一套树状层次结构，在别的软件中，model读入后内部的数据结构应该也大同小异，所以我就由Assimp的数据结构总结一下：

node节点是scene中有名字的小实体，有一个地方存放指向其父亲的指针。从scene的root node开始，每一个node可以由0到n个子node，这样就形成了一个层次结构。

一个node中有0到n个mesh，mesh能够被骨骼引用，或者能够通过一系列的动画驱动。DirectX称之为“frames”帧，其他称之为“objects”物体，在Assimp中称之为aiNode。

一个节点能够引用到一个或多个mesh，但是mesh并不是存储在node里面的，而是aiScene中的一个aiMesh数组。node只存储了指向mesh数组的下标，所以是int*，或者unsigned int*。然后你要通过scene获得具体数据。这也表示了不同的node可能会引用同一个mesh。

通过node引用的mesh将存在于node局部坐标系内。如果你想将mesh定位到全局坐标，你不得不连接从当前node和它所有父亲的变换矩阵。所以每个node里面存储了一个将当前node转换到其父亲node坐标系的变换矩阵。

然而，许多文件格式不支持复杂场景，只有单个的模型。但是还是有很多复杂的格式，例如.3ds，.x或者.collada，这些场景或许会包含任意复杂的，由节点和网格组成的层次结构。于是需要一个递归调用的函数来遍历整个scene
&lt;h2&gt;Mesh&lt;/h2&gt;
一个mesh在任何地方仅适用单个的material，如果模型的一部分适用了不同的材质，则这一部分mesh将会移动到相同node 的不同mesh上。mesh引用材质和node引用mesh是同一个道理：material存储在aiScene中的一个数组内，mesh只保存了这个数组下标的引用。

一个aiMesh是由很多数据通道组成的，这些数据有些来自模型文件，有些是后期处理得到的。2个一定会有的数据通道是vertices和faces。Importer::ReadFile()中的post processing标志可以计算或重新计算一些数据，例如法向量，三角化等。

一个vertex总是有一个3维坐标，除此之外，也许有一个法向量，一个切向量，或双切向量，材质坐标，颜色。其他还可能含有骨骼信息。
&lt;h2&gt;texture&lt;/h2&gt;
通常模型的材质文件和模型文件分开存放，但也有一些文件格式将材质嵌入到了模型文件中。这些材质被加载进了aiTexture结构中。

有2种情况：

1）材质没有被压缩。那么它的颜色信息直接存储在aiTexture中，是一个宽度*高度的2维数组。Assimp中这个2维数组每个元素为一个aiTexel，代表材质图片的一个像素。颜色信息存储在unsigned RGBA8888格式中。适用于D3D和OpenGL。

2）如果材质的高度=0，那么材质图片存储在压缩格式，如DDS或者PNG中，那么需要一些图片库来读取这些文件，比如开源的图片库DevIL（&lt;a href=&quot;http://openil.sourceforge.net/about.php&quot; target=&quot;_blank&quot;&gt;developer's Image Library&lt;/a&gt;）或者&lt;a href=&quot;http://freeimage.sourceforge.net/&quot; target=&quot;_blank&quot;&gt;freeimage&lt;/a&gt;。aiTexture::mWidth表示图片有多少字节，aiTexture::pcData是一个指向raw图片数据的指针，aiTexture::achFormathint表示材质后缀。

示例程序中的材质使用是用DevIL库读取文件后，直接用glGenTextures()，glBindTexture()，glTexParameteri()，glTexImage2D()做好了opengl材质。跟Assimp木有关系。

&amp;#160;
&lt;h2&gt;纹理和材质到底干嘛的&lt;/h2&gt;
网上找来的一段关于texture 和 material 的说明
&lt;p style=&quot;text-align: left; widows: 2; text-transform: none; background-color: #ffffff; text-indent: 0px; margin: 0px 0px 1em; letter-spacing: normal; font: 14px/18px 'WenQuanYi Micro Hei Mono', 'WenQuanYi Micro Hei', 'Microsoft Yahei Mono', 'Microsoft Yahei', sans-serif; word-wrap: break-word; white-space: normal; orphans: 2; color: #000000; clear: both; vertical-align: baseline; word-spacing: 0px; border-image: initial; background-origin: initial; background-clip: initial; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; border-width: 0px; padding: 0px;&quot;&gt;In OpenGL, a&lt;span class=&quot;Apple-converted-space&quot;&gt; &lt;/span&gt;&lt;strong style=&quot;background-color: transparent; margin: 0px; font-family: 'WenQuanYi Micro Hei Mono', 'WenQuanYi Micro Hei', 'Microsoft Yahei Mono', 'Microsoft Yahei', sans-serif !important; font-size: 14px; vertical-align: baseline; font-weight: bold; border-image: initial; background-origin: initial; background-clip: initial; border-width: 0px; padding: 0px;&quot;&gt;material&lt;/strong&gt;&lt;span class=&quot;Apple-converted-space&quot;&gt; &lt;/span&gt;is a set of coefficients that define how the lighting model interacts with the surface. In particular, ambient, diffuse, and specular coefficients for each color component (R,G,B) are defined and applied to a surface and effectively multiplied by the amount of light of each kind/color that strikes the surface. A final emmisivity coefficient is then added to each color component that allows objects to appear luminous without actually interacting with other objects.&lt;/p&gt;
&lt;p style=&quot;text-align: left; widows: 2; text-transform: none; background-color: #ffffff; text-indent: 0px; margin: 0px 0px 1em; letter-spacing: normal; font: 14px/18px 'WenQuanYi Micro Hei Mono', 'WenQuanYi Micro Hei', 'Microsoft Yahei Mono', 'Microsoft Yahei', sans-serif; word-wrap: break-word; white-space: normal; orphans: 2; color: #000000; clear: both; vertical-align: baseline; word-spacing: 0px; border-image: initial; background-origin: initial; background-clip: initial; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; border-width: 0px; padding: 0px;&quot;&gt;A&lt;span class=&quot;Apple-converted-space&quot;&gt; &lt;/span&gt;&lt;strong style=&quot;background-color: transparent; margin: 0px; font-family: 'WenQuanYi Micro Hei Mono', 'WenQuanYi Micro Hei', 'Microsoft Yahei Mono', 'Microsoft Yahei', sans-serif !important; font-size: 14px; vertical-align: baseline; font-weight: bold; border-image: initial; background-origin: initial; background-clip: initial; border-width: 0px; padding: 0px;&quot;&gt;texture&lt;/strong&gt;, on the other hand, is a set of 1-, 2-, 3-, or 4- dimensional bitmap (image) data that is applied and interpolated on to a surface according to texture coordinates at the vertices. Texture data alters the color of the surface whether or not lighting is enabled (and depending on the texture mode, e.g. decal, modulate, etc.). Textures are used frequently to provide sub-polygon level detail to a surface, e.g. applying a repeating brick and mortar texture to a quad to simulate a brick wall, rather than modeling the geometry of each individual brick.&lt;/p&gt;
&lt;p style=&quot;text-align: left; widows: 2; text-transform: none; background-color: #ffffff; text-indent: 0px; margin: 0px 0px 1em; letter-spacing: normal; font: 14px/18px 'WenQuanYi Micro Hei Mono', 'WenQuanYi Micro Hei', 'Microsoft Yahei Mono', 'Microsoft Yahei', sans-serif; word-wrap: break-word; white-space: normal; orphans: 2; color: #000000; clear: both; vertical-align: baseline; word-spacing: 0px; border-image: initial; background-origin: initial; background-clip: initial; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; border-width: 0px; padding: 0px;&quot;&gt;In the classical (fixed-pipeline) OpenGL model, textures and materials are somewhat orthogonal. In the new programmable shader world, the line has blurred quite a bit. Frequently textures are used to influence lighting in other ways. For example, bump maps are textures that are used to perturb surface normals to effect lighting, rather than modifying pixel color directly as a regular &quot;image&quot; texture would.&lt;/p&gt;

&lt;h2&gt;material&lt;/h2&gt;
所有material存储在aiScene中aiMaterial数组中。由于材质定义各不相同，所以没有一个固定的数据结构。材质事实上通过一系列的属性来定义，并由一个名字索引而得到。

Assimp中获得材质属性的函数很简单（一个模板函数）get();
&lt;pre class=&quot;brush:cpp&quot;&gt;aiMaterial* mat = ...
// The generic way
if(AI_SUCCESS != mat-&amp;#62;Get((material-key,where-to-store)){
   // handle epic failure here
}&lt;/pre&gt;
悲催的是我的Qt版模型读取和显式程序调试了下午+晚上还是没有搞定。Assimp库是C实现，提供C++和C接口，源代码看着也不是很爽快，各种数组和指针的混淆也造成了VS debug的困难。今天不搞了，明天继续...&lt;/p&gt;&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2190/&quot;&gt;mesh 模型层次结构&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307177/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307177/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>未分类</category><pubDate>Sat, 25 Feb 2012 22:13:00 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/02/2190/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2190</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/02/2190/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/638307177/6973417</fs:itemid></item><item><title>Symbol Server 和 Symbol File 等基本概念总结</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307178/6973417/1/item.html</link><content:encoded>&lt;p&gt;所有这些概念的引出，收集，都是源自用Qt Creator调试程序出错造成，最终通过安装Windows Debugging Tools解决问题，不过从中发现一个不熟悉的概念，Symbol Server。于是搜集了网上这方面的资料和 Debugging Tools for Windows 帮助文件。整理下这方面的基本概念。&lt;/p&gt;
&lt;h2&gt;简介&lt;/h2&gt;
&lt;p&gt;当你使用各种 Microsoft 工具调试应用程序时，必须拥有符号信息。你用vs链接完程序后，能够在程序路径debug文件夹或者release文件夹下面找到youProgram.pdb 文件就是包含了符号的符号文件了。&lt;/p&gt;
&lt;p&gt;符号文件提供包含在可执行文件和动态链接库 (DLL) 中的函数的占位空间。此外，符号文件还可以表示达到失败点的函数调用路线图。例如，当您转储调试器内的调用堆栈时，必须拥有符号。&lt;/p&gt;
&lt;p&gt;你可以在调试工具中设置调试服务器路径，使用 Microsoft Symbol Server：&lt;a href=&quot;http://msdl.microsoft.com/download/symbols&quot;&gt;http://msdl.microsoft.com/download/symbols&lt;/a&gt; 这是微软为其产品提供的一个符号服务器。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;&lt;strong&gt;http://msdl.microsoft.com/download/symbols&lt;/strong&gt; 是不可浏览的，并且仅适用于由调试器访问。&lt;/p&gt;
&lt;p&gt;另外，&lt;a href=&quot;http://blogs.msdn.com/b/camerons/archive/2011/04/01/debugging-series-symbol-server.aspx&quot;&gt;这里&lt;/a&gt;有一篇简单介绍Symbol Server到底干嘛的MSDN博文。作者Cameron Skinner是Visual Studio team的product unit manager。&lt;/p&gt;
&lt;h2&gt;Symbols and Symbol Files&lt;/h2&gt;
&lt;p&gt;当应用程序，库，驱动程序，或者操作系统链接(link)的时候，那个创建 .exe 和 .dll 链接器也将创建一些额外的文件，就是符号文件。符号文件保存(维护)很多实际运行二进制程序并不需要的数据，但是这些数据在调试的时候就非常有帮助。&lt;/p&gt;
&lt;p&gt;一个典型的符号文件会包含这些信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全局变量&lt;/li&gt;
&lt;li&gt;局部变量&lt;/li&gt;
&lt;li&gt;函数名和入口指针的地址&lt;/li&gt;
&lt;li&gt;Frame pointer omission (FPO) 记录&lt;/li&gt;
&lt;li&gt;源文件行号&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每一个item分别叫做一个符号。例如，一个符号文件 myProgram.pdb 也许包含几百个符号，包括全局变量，函数名和成百上千的局部变量。软件公司常常会发布2个版本的符号文件：一个完整的包含公共符号和私有符号的文件，一个消减的只含有公共符号的文件。&lt;/p&gt;
&lt;p&gt;私有符号数据包含更多信息：函数，全局变量，局部变量，用户定义的类，结构，数据类型，源文件名，行号。而公共符号表则只有很少的内容：函数，全局变量。&lt;/p&gt;
&lt;p&gt;vc++6.0之前版本的链接器还会创建.dbg的符号文件，之后（包括vc++6.0）的链接器将所有符号都放到了.pdb(program debug database)文件中。&lt;/p&gt;
&lt;h2&gt;Symbol store and Symbol Server&lt;/h2&gt;
&lt;p&gt;为调试工作正确设置符号信息有些困难，特别是对于内核调试。你经常需要知道你电脑上所有软件产品的名字和发行版本。调试器必须根据软件发行版本和service pack 来定位每一个符号文件。于是你就有很长很长的一串符号路径，&lt;del&gt;已经&lt;/del&gt;以及很长很长的目录列表。然后你就丢了~&lt;/p&gt;
&lt;p&gt;为了简化如此繁重的工作，为了很好地管理符号文件，这些文件就被收集到了一个符号商店(symbol store)了，这个商店可以通过symbol server来“购买”文件。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Symbol store&lt;/strong&gt; 是一个符号文件的集合。管理员可以通过这个工具，或者说这个索引，来添加和删除符号文件。你可以通过唯一的参数例如时间戳或者镜像尺寸来索引文件。Symbol store也可以保存可执行镜像文件，这些可执行文件也能够被Symbol server提取。&lt;/p&gt;
&lt;p&gt;Debugging Tools for Windows包含了一个创建symbol store的工具叫：SymStore。如果你的软件很大，发行了很多个版本，当用户报告或提交了一些旧版本的出错信息时，你需要用那个版本的调试信息来调试软件，于是，自己搭建一个符号商店就比较靠谱了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Symbol Server &lt;/strong&gt;能够让调试器自动从“符号商店”获取正确的符号文件，用户不必知道这些符号文件的具体细节。Debugging Tools for Windows包含了一个Symbol server叫：SymSrv。它能够让你事前获取符号文件，将这些文件缓存到你指定的本地路径下。你不用这个工具的话，在调试的时候，Symbol server会下载符号文件，于是会造成等待，第一次调试就比较慢，以后的调试就无影响了。&lt;/p&gt;
&lt;p&gt;【使用 SymChk.exe 实用工具下载符号】&lt;br /&gt;
您可以使用 SymChk.exe 实用工具，验证符号并以便捷、非侵入的方式生成本地符号高速缓存。SymChk.exe 实用程序随 Debugging Tools for Windows 软件包提供。SymChk.exe 是一种命令行工具。您可能需要将 Debugging Tools for Windows 软件包的文件夹添加到系统上的 PATH 环境变量，以便从任意命令提示符下访问该工具。&lt;br /&gt;
要使用 SymChk.exe 实用程序下载 Windows\System32 文件夹中所有组件的符号文件，请使用以下命令行命令：&lt;br /&gt;
symchk /r c:\windows\system32 /s SRV*c:\symbols\*http://msdl.microsoft.com/download/symbols&lt;br /&gt;
在此示例中：&lt;br /&gt;
• “/r c:\windows\system32”查找 System32 文件夹和所有子文件夹中的所有符号文件。&lt;br /&gt;
• “/s SRV*c:*http://msdl.microsoft.com/download/symbols”指定用于符号解析的符号路径。在此例中，“c:\symbols”是将在其中从符号服务器复制符号的本地文件夹。&lt;br /&gt;
要获取 SymChk.exe 命令行选项的更多信息，请在命令提示符下键入 symchk /?。&lt;/p&gt;
&lt;h2&gt;使用 Symbol Server 技术&lt;/h2&gt;
&lt;p&gt;Microsoft Symbol Server 是使用随 Debugging Tools for Windows 软件包一起提供的 SymSrv 技术 (SymSrv.dll) 构建的。SymSrv 会生成本地符号高速缓存，以进行快速、自动的符号解析。&lt;br /&gt;
使用 Symbol Server 就像在符号路径中使用相应的语法一样简单。通常，语法的格式如下：&lt;/p&gt;
&lt;p&gt;SRV*&lt;var&gt;your local symbol folder&lt;/var&gt;*http://msdl.microsoft.com/download/symbols&lt;/p&gt;
&lt;p&gt;其中 &lt;var&gt;your local symbol folder&lt;/var&gt; 是用作符号目标的的任何驱动器或共享。&lt;br /&gt;
例如，要在 WinDbg 调试器中设置符号路径，请在该调试器的命令窗口中键入以下命令：&lt;/p&gt;
&lt;p&gt;.sympath SRV*f:\localsymbols*http://msdl.microsoft.com/download/symbols&lt;/p&gt;
&lt;p&gt;要在VS2008中添加Symbol server路径才能获取MS系统文件的符号文件。如下，新建一个路径，写上MS的符号商店路径，下面在填上你准备存放符号文件的本地缓存路径，按确定就启用了。再下一次编译程序的时候，server会自动下载的。&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none;&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/QQ截图20120223143907.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;编译的时候会弹出协议给你看。点确定。结果就是这样了，至于调试信息多了哪些，自己慢慢体会吧~~&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none;&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/QQ截图20120223150829.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2186/&quot;&gt;Symbol Server 和 Symbol File 等基本概念总结&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307178/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307178/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://neversayever.com/blog/2012/02/2186/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&lt;p&gt;所有这些概念的引出，收集，都是源自用Qt Creator调试程序出错造成，最终通过安装Windows Debugging Tools解决问题，不过从中发现一个不熟悉的概念，Symbol Server。于是搜集了网上这方面的资料和 Debugging Tools for Windows 帮助文件。整理下这方面的基本概念。
&lt;h2&gt;简介&lt;/h2&gt;
当你使用各种 Microsoft 工具调试应用程序时，必须拥有符号信息。你用vs链接完程序后，能够在程序路径debug文件夹或者release文件夹下面找到youProgram.pdb 文件就是包含了符号的符号文件了。

符号文件提供包含在可执行文件和动态链接库 (DLL) 中的函数的占位空间。此外，符号文件还可以表示达到失败点的函数调用路线图。例如，当您转储调试器内的调用堆栈时，必须拥有符号。

你可以在调试工具中设置调试服务器路径，使用 Microsoft Symbol Server：&lt;a href=&quot;http://msdl.microsoft.com/download/symbols&quot;&gt;http://msdl.microsoft.com/download/symbols&lt;/a&gt; 这是微软为其产品提供的一个符号服务器。

&lt;strong&gt;注意&lt;/strong&gt;&lt;strong&gt;http://msdl.microsoft.com/download/symbols&lt;/strong&gt; 是不可浏览的，并且仅适用于由调试器访问。

另外，&lt;a href=&quot;http://blogs.msdn.com/b/camerons/archive/2011/04/01/debugging-series-symbol-server.aspx&quot;&gt;这里&lt;/a&gt;有一篇简单介绍Symbol Server到底干嘛的MSDN博文。作者Cameron Skinner是Visual Studio team的product unit manager。
&lt;h2&gt;Symbols and Symbol Files&lt;/h2&gt;
当应用程序，库，驱动程序，或者操作系统链接(link)的时候，那个创建 .exe 和 .dll 链接器也将创建一些额外的文件，就是符号文件。符号文件保存(维护)很多实际运行二进制程序并不需要的数据，但是这些数据在调试的时候就非常有帮助。

一个典型的符号文件会包含这些信息：
&lt;ul&gt;
	&lt;li&gt;全局变量&lt;/li&gt;
	&lt;li&gt;局部变量&lt;/li&gt;
	&lt;li&gt;函数名和入口指针的地址&lt;/li&gt;
	&lt;li&gt;Frame pointer omission (FPO) 记录&lt;/li&gt;
	&lt;li&gt;源文件行号&lt;/li&gt;
&lt;/ul&gt;
每一个item分别叫做一个符号。例如，一个符号文件 myProgram.pdb 也许包含几百个符号，包括全局变量，函数名和成百上千的局部变量。软件公司常常会发布2个版本的符号文件：一个完整的包含公共符号和私有符号的文件，一个消减的只含有公共符号的文件。

私有符号数据包含更多信息：函数，全局变量，局部变量，用户定义的类，结构，数据类型，源文件名，行号。而公共符号表则只有很少的内容：函数，全局变量。

vc++6.0之前版本的链接器还会创建.dbg的符号文件，之后（包括vc++6.0）的链接器将所有符号都放到了.pdb(program debug database)文件中。
&lt;h2&gt;Symbol store and Symbol Server&lt;/h2&gt;
为调试工作正确设置符号信息有些困难，特别是对于内核调试。你经常需要知道你电脑上所有软件产品的名字和发行版本。调试器必须根据软件发行版本和service pack 来定位每一个符号文件。于是你就有很长很长的一串符号路径，&lt;del&gt;已经&lt;/del&gt;以及很长很长的目录列表。然后你就丢了~

为了简化如此繁重的工作，为了很好地管理符号文件，这些文件就被收集到了一个符号商店(symbol store)了，这个商店可以通过symbol server来“购买”文件。

&lt;strong&gt;Symbol store&lt;/strong&gt; 是一个符号文件的集合。管理员可以通过这个工具，或者说这个索引，来添加和删除符号文件。你可以通过唯一的参数例如时间戳或者镜像尺寸来索引文件。Symbol store也可以保存可执行镜像文件，这些可执行文件也能够被Symbol server提取。

Debugging Tools for Windows包含了一个创建symbol store的工具叫：SymStore。如果你的软件很大，发行了很多个版本，当用户报告或提交了一些旧版本的出错信息时，你需要用那个版本的调试信息来调试软件，于是，自己搭建一个符号商店就比较靠谱了。

&lt;strong&gt;Symbol Server &lt;/strong&gt;能够让调试器自动从“符号商店”获取正确的符号文件，用户不必知道这些符号文件的具体细节。Debugging Tools for Windows包含了一个Symbol server叫：SymSrv。它能够让你事前获取符号文件，将这些文件缓存到你指定的本地路径下。你不用这个工具的话，在调试的时候，Symbol server会下载符号文件，于是会造成等待，第一次调试就比较慢，以后的调试就无影响了。

【使用 SymChk.exe 实用工具下载符号】
您可以使用 SymChk.exe 实用工具，验证符号并以便捷、非侵入的方式生成本地符号高速缓存。SymChk.exe 实用程序随 Debugging Tools for Windows 软件包提供。SymChk.exe 是一种命令行工具。您可能需要将 Debugging Tools for Windows 软件包的文件夹添加到系统上的 PATH 环境变量，以便从任意命令提示符下访问该工具。
要使用 SymChk.exe 实用程序下载 Windows\System32 文件夹中所有组件的符号文件，请使用以下命令行命令：
symchk /r c:\windows\system32 /s SRV*c:\symbols\*http://msdl.microsoft.com/download/symbols
在此示例中：
• “/r c:\windows\system32”查找 System32 文件夹和所有子文件夹中的所有符号文件。
• “/s SRV*c:*http://msdl.microsoft.com/download/symbols”指定用于符号解析的符号路径。在此例中，“c:\symbols”是将在其中从符号服务器复制符号的本地文件夹。
要获取 SymChk.exe 命令行选项的更多信息，请在命令提示符下键入 symchk /?。
&lt;h2&gt;使用 Symbol Server 技术&lt;/h2&gt;
Microsoft Symbol Server 是使用随 Debugging Tools for Windows 软件包一起提供的 SymSrv 技术 (SymSrv.dll) 构建的。SymSrv 会生成本地符号高速缓存，以进行快速、自动的符号解析。
使用 Symbol Server 就像在符号路径中使用相应的语法一样简单。通常，语法的格式如下：

SRV*&lt;var&gt;your local symbol folder&lt;/var&gt;*http://msdl.microsoft.com/download/symbols

其中 &lt;var&gt;your local symbol folder&lt;/var&gt; 是用作符号目标的的任何驱动器或共享。
例如，要在 WinDbg 调试器中设置符号路径，请在该调试器的命令窗口中键入以下命令：

.sympath SRV*f:\localsymbols*http://msdl.microsoft.com/download/symbols

要在VS2008中添加Symbol server路径才能获取MS系统文件的符号文件。如下，新建一个路径，写上MS的符号商店路径，下面在填上你准备存放符号文件的本地缓存路径，按确定就启用了。再下一次编译程序的时候，server会自动下载的。

&lt;img style=&quot;margin: 10px auto; display: block; float: none;&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/QQ截图20120223143907.jpg&quot; alt=&quot;&quot; /&gt;

编译的时候会弹出协议给你看。点确定。结果就是这样了，至于调试信息多了哪些，自己慢慢体会吧~~

&lt;img style=&quot;margin: 10px auto; display: block; float: none;&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/QQ截图20120223150829.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2186/&quot;&gt;Symbol Server 和 Symbol File 等基本概念总结&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307178/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307178/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>其他</category><category>Symbol</category><category>Debug</category><pubDate>Thu, 23 Feb 2012 16:31:30 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/02/2186/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2186</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/02/2186/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/638307178/6973417</fs:itemid></item><item><title>Qt Creator + vc++ compiler 配置Qt环境</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307179/6973417/1/item.html</link><content:encoded>&lt;p&gt;我一直用的都是vs2008 + Qt4.7.x + Qt vs addin 来编写Qt程序的，不过QtCreator我一直认为是一个很好的IDE，“环境优美，空气清新”，高亮，提示，debug等操作都做得很到位，而且你可以一边写代码，一边在creator里面看Qt assistant，另外看Qt Demo也非常方便。另一方面，vs是一个强大的工具，也是一个非常人性化的工具，但人性化带来的就是方便，而当一个好奇的程序员想深入探索程序世界奥秘的时候，“方便”可不是他们（其实就是哥嘿嘿~）所追求的。&lt;/p&gt;
&lt;p&gt;于是我就折腾了一下Qt Creator，以前一直有个问题，Qt Creator不能调试程序。以前也搜了好久，查了很多文档，因为我的笔记本没装VS，但又想看看qt代码，就装了个Qt Creator和Qt opensource vs2008的sdk，不过不能调试的问题一直没解决。&lt;/p&gt;
&lt;p&gt;这个问题昨天在搜索了很久之后终于解决。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://doc.qt.nokia.com/qtcreator-snapshot/creator-debugger-engines.html&quot;&gt;这里&lt;/a&gt;是Qt官方参考文档给出的设置调试器的页面。&lt;/p&gt;
&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;2&quot; width=&quot;617&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;80&quot;&gt;Platform&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;279&quot;&gt;Compiler&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;20&quot;&gt;Native Debugger&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;74&quot;&gt;Python&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;162&quot;&gt;debugger Modes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;80&quot;&gt;Windows/MinGW&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;279&quot;&gt;GCC&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;20&quot;&gt;GDB&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;74&quot;&gt;yes&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;162&quot;&gt;Plain,Terminal,Attach,Remote,Core&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;80&quot;&gt;Windows/MSVC&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;279&quot;&gt;Microsoft Visual C++ Compiler&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;20&quot;&gt;Debugging Tools for Widows/CDB&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;74&quot;&gt;Not applicable&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;162&quot;&gt;Plain,Terminal,Attach,Post-Mortem&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这意思也就是你装Qt Creator的时候没装MinGW的话，你就得用vc++编译器，和microsoft提供的windows调试工具。你装了MinGW的话，你就可以用MinGW提供的GCC和Qt Creator安装时已经有的GDB。（早知道我装个MinGW就不用这么麻烦了&amp;#8230;）&lt;/p&gt;
&lt;p&gt;然后我安装了Debugging Tools for windows：&lt;/p&gt;
&lt;p&gt;下载地址在此：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx&quot;&gt;http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx&lt;/a&gt; &lt;a href=&quot;http://www.microsoft.com/whdc/devtools/debugging/install64bit.Mspx&quot;&gt;http://www.microsoft.com/whdc/devtools/debugging/install64bit.Mspx&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;这两个不是最新的调试工具，因为最新的工具集成到了windows SDK，不再单独提供。vs中没有提供这些工具，所以你要自己装。另外我虽然是64位系统，但还是装了X86的，它说CPU架构是X86不支持64位&amp;#8230;囧。另外，网上很多教程贴说你在安装Qt Creator的时候安装程序会让你下载windows debugger tools并安装，但我表示啥提示都没出现。&lt;/p&gt;
&lt;p&gt;到此为止其实你就可以调试运行程序了，只不过看惯了vs的编译调试信息，Qt Creator的信息略有些不适应而已。我昨天调试没发现，因为我直接加上了下面所说的符号服务器(Symbol server)，今天我把这去掉，在编译程序的时候 Qt Creator 会弹出一个窗口提示你设置它。&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/creatorInforSymbol.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;点击是，它直接给你个路径，你只要点确定就行了。&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/symbolSetUp.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It is highly recommended that you add the Symbol Server provided by Microsoft to the symbol search path of the debugger. The Symbol Server provides you with debugging informaton for the operating system libraries for debugging Windows applications. For more information, see &lt;a href=&quot;http://doc.qt.nokia.com/qtcreator-snapshot/creator-debugger-engines.html#setting-the-symbol-server-in-windows&quot;&gt;Setting the Symbol Server in Windows&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;他说强烈建议我设置符号服务器，我连符号服务器是神马玩意儿都不知道。我将在下一篇总结一下我搜来的和自己理解的Symbol Server和PBD的概念。&lt;/p&gt;
&lt;p&gt;要手动设置的话，到工具-&amp;gt;选项-&amp;gt;调试器-&amp;gt;CDB，Symbol paths右边点击插入-&amp;gt;符号服务器，然后自己选个路径，确定就行了。&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/QtCreatorDebugger.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;另外如果还有问题的话需要看一下工具链(Tool Chains)，里面的编译器是否配置正确，如果没有自动识别，就需要手动添加。&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/QtCreatorToolChains.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2181/&quot;&gt;Qt Creator + vc++ compiler 配置Qt环境&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307179/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307179/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://neversayever.com/blog/2012/02/2181/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&lt;p&gt;&lt;p&gt;我一直用的都是vs2008 + Qt4.7.x + Qt vs addin 来编写Qt程序的，不过QtCreator我一直认为是一个很好的IDE，“环境优美，空气清新”，高亮，提示，debug等操作都做得很到位，而且你可以一边写代码，一边在creator里面看Qt assistant，另外看Qt Demo也非常方便。另一方面，vs是一个强大的工具，也是一个非常人性化的工具，但人性化带来的就是方便，而当一个好奇的程序员想深入探索程序世界奥秘的时候，“方便”可不是他们（其实就是哥嘿嘿~）所追求的。&lt;/p&gt;  &lt;p&gt;于是我就折腾了一下Qt Creator，以前一直有个问题，Qt Creator不能调试程序。以前也搜了好久，查了很多文档，因为我的笔记本没装VS，但又想看看qt代码，就装了个Qt Creator和Qt opensource vs2008的sdk，不过不能调试的问题一直没解决。&lt;/p&gt;  &lt;p&gt;这个问题昨天在搜索了很久之后终于解决。&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;http://doc.qt.nokia.com/qtcreator-snapshot/creator-debugger-engines.html&quot;&gt;这里&lt;/a&gt;是Qt官方参考文档给出的设置调试器的页面。&lt;/p&gt;  &lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;2&quot; width=&quot;617&quot;&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;80&quot;&gt;Platform&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;279&quot;&gt;Compiler&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;20&quot;&gt;Native Debugger&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;74&quot;&gt;Python&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;162&quot;&gt;debugger Modes&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;80&quot;&gt;Windows/MinGW&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;279&quot;&gt;GCC&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;20&quot;&gt;GDB&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;74&quot;&gt;yes&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;162&quot;&gt;Plain,Terminal,Attach,Remote,Core&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;80&quot;&gt;Windows/MSVC&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;279&quot;&gt;Microsoft Visual C++ Compiler&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;20&quot;&gt;Debugging Tools for Widows/CDB&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;74&quot;&gt;Not applicable&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;162&quot;&gt;Plain,Terminal,Attach,Post-Mortem&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;这意思也就是你装Qt Creator的时候没装MinGW的话，你就得用vc++编译器，和microsoft提供的windows调试工具。你装了MinGW的话，你就可以用MinGW提供的GCC和Qt Creator安装时已经有的GDB。（早知道我装个MinGW就不用这么麻烦了...）&lt;/p&gt;  &lt;p&gt;然后我安装了Debugging Tools for windows：&lt;/p&gt;  &lt;p&gt;下载地址在此：&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx&quot;&gt;http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx&lt;/a&gt; &lt;a href=&quot;http://www.microsoft.com/whdc/devtools/debugging/install64bit.Mspx&quot;&gt;http://www.microsoft.com/whdc/devtools/debugging/install64bit.Mspx&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;这两个不是最新的调试工具，因为最新的工具集成到了windows SDK，不再单独提供。vs中没有提供这些工具，所以你要自己装。另外我虽然是64位系统，但还是装了X86的，它说CPU架构是X86不支持64位...囧。另外，网上很多教程贴说你在安装Qt Creator的时候安装程序会让你下载windows debugger tools并安装，但我表示啥提示都没出现。&lt;/p&gt;  &lt;p&gt;到此为止其实你就可以调试运行程序了，只不过看惯了vs的编译调试信息，Qt Creator的信息略有些不适应而已。我昨天调试没发现，因为我直接加上了下面所说的符号服务器(Symbol server)，今天我把这去掉，在编译程序的时候 Qt Creator 会弹出一个窗口提示你设置它。&lt;/p&gt;  &lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/creatorInforSymbol.jpg&quot; /&gt;&lt;/p&gt;  &lt;p&gt;点击是，它直接给你个路径，你只要点确定就行了。&lt;/p&gt;  &lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/symbolSetUp.jpg&quot; /&gt;&lt;/p&gt;  &lt;p&gt;It is highly recommended that you add the Symbol Server provided by Microsoft to the symbol search path of the debugger. The Symbol Server provides you with debugging informaton for the operating system libraries for debugging Windows applications. For more information, see &lt;a href=&quot;http://doc.qt.nokia.com/qtcreator-snapshot/creator-debugger-engines.html#setting-the-symbol-server-in-windows&quot;&gt;Setting the Symbol Server in Windows&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;他说强烈建议我设置符号服务器，我连符号服务器是神马玩意儿都不知道。我将在下一篇总结一下我搜来的和自己理解的Symbol Server和PBD的概念。&lt;/p&gt;  &lt;p&gt;要手动设置的话，到工具-&amp;#62;选项-&amp;#62;调试器-&amp;#62;CDB，Symbol paths右边点击插入-&amp;#62;符号服务器，然后自己选个路径，确定就行了。&lt;/p&gt;  &lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/QtCreatorDebugger.jpg&quot; /&gt;&lt;/p&gt;  &lt;p&gt;另外如果还有问题的话需要看一下工具链(Tool Chains)，里面的编译器是否配置正确，如果没有自动识别，就需要手动添加。&lt;/p&gt;  &lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/QtCreatorToolChains.jpg&quot; /&gt;&lt;/p&gt;&lt;/p&gt;&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2181/&quot;&gt;Qt Creator + vc++ compiler 配置Qt环境&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307179/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307179/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>编译环境</category><category>Qt</category><category>Qt Creator</category><pubDate>Thu, 23 Feb 2012 11:04:46 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/02/2181/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2181</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/02/2181/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/638307179/6973417</fs:itemid></item><item><title>Assimp中的post process step flag</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307180/6973417/1/item.html</link><content:encoded>&lt;p&gt;Assimp::Importer类里面主要用到的一个载入模型文件的API。
&lt;pre class=&quot;brush:cpp&quot;&gt;const aiScene* ReadFile(const std::string &amp;amp;pFile, unsigned int pFlags);
//pFlags 就是post process steps 的标志，上一篇示例中使用了aiProcessPreset_TargetRealtime_Quality&lt;/pre&gt;
&lt;p&gt;aiPostProcess.h文件里面定义了所有载入时需要设置的后处理步骤的flag，简单小结一下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_CalcTangentSpace&lt;/strong&gt; 计算切线，双切线（留待补充切空间的定义）。如果mesh没有法向，则不执行这步。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_JoinIdenticalVertices&lt;/strong&gt; 合并相同节点。执行此步后，mesh中相同的点坐标只出现唯一一次。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_MakeLeftHanded&lt;/strong&gt; 将数据转换到左手坐标系空间。 &lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ff0000&quot;&gt;&lt;strong&gt;aiProcess_Triangulate&lt;/strong&gt;&lt;/span&gt; 三角化mesh的所有面。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_RemoveComponent&lt;/strong&gt; 移除一些不需要的数据，动画，材质，光源，镜头，贴图等。这步有时候很有用，比如强制Assimp重新计算法向，这时候需要先移除已存在的法向。这步骤需要在AI_CONFIG_PP_RVC_FLAGS中定义好设置选项。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;font color=&quot;#ff0000&quot;&gt;aiProcess_GenNormals&lt;/font&gt;&lt;/strong&gt; 计算法向，这个标志表示计算的是面法向，因而最终效果网格表面不是平滑的。不能和 aiProcess_GenSmoothNormals 一起使用。已存在法向时不会计算。 &lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;font color=&quot;#ff0000&quot;&gt;aiProcess_GenSmoothNormals&lt;/font&gt;&lt;/strong&gt; 也是计算法向，计算点法向，因而效果是平滑的。 &lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_SplitLargeMeshes&lt;/strong&gt; 将大网格分割成小网格，具体分割细节一定要在 AI_CONFIG_PP_SLM_VERTEX_LIMIT 和 AI_CONFIG_PP_SLM_TRIANGLE_LIMIT 中设置，默认为AI_SLM_DEFAULT_MAX_VERTICES 和 AI_SLM_DEFAULT_MAX_TRIANGLES。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_PreTransformVertices&lt;/strong&gt; 预先根据局部变换矩阵变换node中的结点。note：AI_CONFIG_PP_PTV_NORMALIZE 能将整个场景的空间尺度放在(-1,1)之间。它说通过这个属性，你可以简单地依次渲染所有mesh，而不必在意局部的变换和node的层次结构，意思好像是不用像上一篇中的例子里面那样将递归渲染写这么复杂？(这个属性不是很明白，待我写个C++版本的就知道了。) &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_LimitBoneWeights&lt;/strong&gt; 将联系到一个结点上的bone的数量降低到所设置的值大小，超过的话将会根据权重去掉权重最小的，并且重新归一化。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_ValidateDataStructure &lt;/strong&gt;验证数据结构是否正确，比如所有结点索引是否正确，动画，骨骼是否连接正确，材质的引用是否正确等，通过这个你能够在log中看到到底哪里出错了，使用这个标识不是必须的，但推荐使用。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_ImproveCacheLocality &lt;/strong&gt;重新排序三角形，以优化结点的局部存储。算法是减少平均后期转换结点缓存的miss率。技术论文在&lt;a href=&quot;http://gfx.cs.princeton.edu/pubs/Sander_2007_%3ETR/tipsy.pdf&quot;&gt;这里&lt;/a&gt;，有空要看下。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_RemoveRedundantMaterials &lt;/strong&gt;移除冗余材质信息。有时候不需要用到，具体看下AI_CONFIG_PP_RRM_EXCLUDE_LIST，我对材质这方面一直没怎么整明白，再说吧。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_FixInfacingNormals &lt;/strong&gt;这个步骤试图修复一些朝物体内部的反方向的面法向，并将其反转。注意，它是按一个mesh 算的，并不是mesh中某些点或面的法向反了，而是整个反了。算法是：所有（点+法向）构成的包围盒的体积 vs 所有点构成的包围盒的体积，一比便知。据说有时会造成错误，但推荐使用。Orz=3 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_SortByPType &lt;/strong&gt;说是能将网格分割成不止一种primitive类型，比如使之同时具有点，线，面类型。要在三角化后使用，一般不再import函数中加上。（没看明白！） &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_FindDegenerates &lt;/strong&gt;一个degenerated face指的是这个面中有至少2个点是相同的，这是面退化为线或者点，这个标志能将其转变成点或线，要将这个面直接删除需要进一步设置。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_FindInvalidData &lt;/strong&gt;寻找一些失效的数据，为0的法向，错误的UV坐标等。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_GenUVCoords &lt;/strong&gt;能够将非UV映射（比如球面映射，柱面映射）转变成合适的纹理坐标通道。效果不一定非常好，用3ds max,maya等软件才是王道。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_TransformUVCoords &lt;/strong&gt;应用每个材质的UV转换，并将它们调整成独立的vtexture坐标通道（囧~）。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_FindInstances &lt;/strong&gt;寻找重复的mesh，并用第一次找到的mesh的引用替换掉重复的mesh。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_OptimizeMeshes &lt;/strong&gt;减少mesh数量？！它将减少绘制函数的调用次数。最好和aiProcess_OptimizeGraph 一起使用。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_OptimizeGraph &lt;/strong&gt;优化场景的层次结构，一些没有动画，骨骼，灯光，相机的node将会合并。大多数的简单文件将被合并成单个的node，层次结构完全丢失，如果你要编辑数据，这不是个好选择，但如果仅仅为了获得数据，并且要显示或者转换成自定义数据结构，这就是一个很有效的方法了。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_FlipUVs &lt;/strong&gt;根据y轴反转UV坐标，使原本原点处于左下角的翻转到左上角。 &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;aiProcess_FlipWindingOrder &lt;/strong&gt;将面的围绕方向转换为顺时针。 &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;累死爹了~&lt;/p&gt;
&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2175/&quot;&gt;Assimp中的post process step flag&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307180/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307180/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://neversayever.com/blog/2012/02/2175/feed/</wfw:commentRss><slash:comments>2</slash:comments><description>&lt;p&gt;Assimp::Importer类里面主要用到的一个载入模型文件的API。   &lt;pre class=&quot;brush:cpp&quot;&gt;const aiScene* ReadFile(const std::string &amp;#38;pFile, unsigned int pFlags);
//pFlags 就是post process steps 的标志，上一篇示例中使用了aiProcessPreset_TargetRealtime_Quality&lt;/pre&gt;

&lt;p&gt;aiPostProcess.h文件里面定义了所有载入时需要设置的后处理步骤的flag，简单小结一下：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;aiProcess_CalcTangentSpace&lt;/strong&gt; 计算切线，双切线（留待补充切空间的定义）。如果mesh没有法向，则不执行这步。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_JoinIdenticalVertices&lt;/strong&gt; 合并相同节点。执行此步后，mesh中相同的点坐标只出现唯一一次。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_MakeLeftHanded&lt;/strong&gt; 将数据转换到左手坐标系空间。 &lt;/li&gt;

  &lt;li&gt;&lt;span style=&quot;color: #ff0000&quot;&gt;&lt;strong&gt;aiProcess_Triangulate&lt;/strong&gt;&lt;/span&gt; 三角化mesh的所有面。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_RemoveComponent&lt;/strong&gt; 移除一些不需要的数据，动画，材质，光源，镜头，贴图等。这步有时候很有用，比如强制Assimp重新计算法向，这时候需要先移除已存在的法向。这步骤需要在AI_CONFIG_PP_RVC_FLAGS中定义好设置选项。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;&lt;font color=&quot;#ff0000&quot;&gt;aiProcess_GenNormals&lt;/font&gt;&lt;/strong&gt; 计算法向，这个标志表示计算的是面法向，因而最终效果网格表面不是平滑的。不能和 aiProcess_GenSmoothNormals 一起使用。已存在法向时不会计算。 &lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;&lt;font color=&quot;#ff0000&quot;&gt;aiProcess_GenSmoothNormals&lt;/font&gt;&lt;/strong&gt; 也是计算法向，计算点法向，因而效果是平滑的。 &lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_SplitLargeMeshes&lt;/strong&gt; 将大网格分割成小网格，具体分割细节一定要在 AI_CONFIG_PP_SLM_VERTEX_LIMIT 和 AI_CONFIG_PP_SLM_TRIANGLE_LIMIT 中设置，默认为AI_SLM_DEFAULT_MAX_VERTICES 和 AI_SLM_DEFAULT_MAX_TRIANGLES。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_PreTransformVertices&lt;/strong&gt; 预先根据局部变换矩阵变换node中的结点。note：AI_CONFIG_PP_PTV_NORMALIZE 能将整个场景的空间尺度放在(-1,1)之间。它说通过这个属性，你可以简单地依次渲染所有mesh，而不必在意局部的变换和node的层次结构，意思好像是不用像上一篇中的例子里面那样将递归渲染写这么复杂？(这个属性不是很明白，待我写个C++版本的就知道了。) &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_LimitBoneWeights&lt;/strong&gt; 将联系到一个结点上的bone的数量降低到所设置的值大小，超过的话将会根据权重去掉权重最小的，并且重新归一化。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_ValidateDataStructure &lt;/strong&gt;验证数据结构是否正确，比如所有结点索引是否正确，动画，骨骼是否连接正确，材质的引用是否正确等，通过这个你能够在log中看到到底哪里出错了，使用这个标识不是必须的，但推荐使用。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_ImproveCacheLocality &lt;/strong&gt;重新排序三角形，以优化结点的局部存储。算法是减少平均后期转换结点缓存的miss率。技术论文在&lt;a href=&quot;http://gfx.cs.princeton.edu/pubs/Sander_2007_%3ETR/tipsy.pdf&quot;&gt;这里&lt;/a&gt;，有空要看下。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_RemoveRedundantMaterials &lt;/strong&gt;移除冗余材质信息。有时候不需要用到，具体看下AI_CONFIG_PP_RRM_EXCLUDE_LIST，我对材质这方面一直没怎么整明白，再说吧。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_FixInfacingNormals &lt;/strong&gt;这个步骤试图修复一些朝物体内部的反方向的面法向，并将其反转。注意，它是按一个mesh 算的，并不是mesh中某些点或面的法向反了，而是整个反了。算法是：所有（点+法向）构成的包围盒的体积 vs 所有点构成的包围盒的体积，一比便知。据说有时会造成错误，但推荐使用。Orz=3 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_SortByPType &lt;/strong&gt;说是能将网格分割成不止一种primitive类型，比如使之同时具有点，线，面类型。要在三角化后使用，一般不再import函数中加上。（没看明白！） &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_FindDegenerates &lt;/strong&gt;一个degenerated face指的是这个面中有至少2个点是相同的，这是面退化为线或者点，这个标志能将其转变成点或线，要将这个面直接删除需要进一步设置。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_FindInvalidData &lt;/strong&gt;寻找一些失效的数据，为0的法向，错误的UV坐标等。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_GenUVCoords &lt;/strong&gt;能够将非UV映射（比如球面映射，柱面映射）转变成合适的纹理坐标通道。效果不一定非常好，用3ds max,maya等软件才是王道。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_TransformUVCoords &lt;/strong&gt;应用每个材质的UV转换，并将它们调整成独立的vtexture坐标通道（囧~）。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_FindInstances &lt;/strong&gt;寻找重复的mesh，并用第一次找到的mesh的引用替换掉重复的mesh。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_OptimizeMeshes &lt;/strong&gt;减少mesh数量？！它将减少绘制函数的调用次数。最好和aiProcess_OptimizeGraph 一起使用。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_OptimizeGraph &lt;/strong&gt;优化场景的层次结构，一些没有动画，骨骼，灯光，相机的node将会合并。大多数的简单文件将被合并成单个的node，层次结构完全丢失，如果你要编辑数据，这不是个好选择，但如果仅仅为了获得数据，并且要显示或者转换成自定义数据结构，这就是一个很有效的方法了。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_FlipUVs &lt;/strong&gt;根据y轴反转UV坐标，使原本原点处于左下角的翻转到左上角。 &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;aiProcess_FlipWindingOrder &lt;/strong&gt;将面的围绕方向转换为顺时针。 &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;累死爹了~&lt;/p&gt;&lt;/p&gt;&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2175/&quot;&gt;Assimp中的post process step flag&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307180/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307180/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>Mesh</category><category>Assimp</category><pubDate>Wed, 22 Feb 2012 15:03:14 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/02/2175/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2175</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/02/2175/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/638307180/6973417</fs:itemid></item><item><title>SimpleOpenGL 使用Assimp及glut实现的简单示例</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307181/6973417/1/item.html</link><content:encoded>&lt;p&gt;SimpleOpenGL示例程序是Assimp中自带的一个基于c实现的最简单的程序，我看了一遍，觉得虽然没有C++实现那么漂亮，不过倒是提供了很多Assimp用法的示例，还是记录一下。&lt;/p&gt;
&lt;p&gt;程序功能及其简单，模型的载入及显示，另外演示了一下Assimp提供的log stream系统，这个倒是挺不错。&lt;/p&gt;
&lt;p&gt;几个变量的定义&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;//the global Assimp scene object
const struct aiScene* scene = NULL;
GLuint scene_list = 0;
struct aiVector3D scene_min, scene_max, scene_center;&lt;/pre&gt;
&lt;p&gt;main函数&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;
int main(int argc, char **argv)
{
 //aiLogStream表示一个日志系统，可以看到Assimp的API以ai开头
 //C实现让我很不爽的是前面都加个Struct，对于我等有代码洁癖的人来说，看起来真心不爽
	struct aiLogStream stream;

	glutInitWindowSize(900,600);
	glutInitWindowPosition(100,100);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	glutInit(&amp;amp;argc, argv);

	glutCreateWindow(&quot;Assimp - Very simple OpenGL sample&quot;);
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);

	//将一个预定义的STDOUT Stream指针绑定到日志系统，信息将输出到控制台窗口
        //日志将记录以后所有的导入模型文件及后处理API的调用
        stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL);
	aiAttachLogStream(&amp;#038;stream);
        //继续绑定一个log，不过这个log将记录信息到文件assimp_log.txt中
	stream = aiGetPredefinedLogStream(aiDefaultLogStream_FILE,&quot;assimp_log.txt&quot;);
	aiAttachLogStream(&amp;amp;stream);
        //载入模型文件，看着很是DT，是不
	if( 0 != loadasset( argc &gt;= 2 ? argv[1] : &quot;../../test/models-nonbsd/X/dwarf.x&quot;))
        {
		if( argc != 1 || 0 != loadasset(&quot;../../../../test/models-nonbsd/X/dwarf.x&quot;)
                        &amp;#038;&amp;#038; 0 != loadasset( &quot;../../test/models/X/Testwuson.X&quot;))
                {
			return -1;
		}
	}
	glClearColor(0.1f,0.1f,0.1f,1.f);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);    // Uses default lighting parameters
	glEnable(GL_DEPTH_TEST);
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
	glEnable(GL_NORMALIZE);
	// XXX docs say all polygons are emitted CCW, but tests show that some aren't.
	if(getenv(&quot;MODEL_IS_BROKEN&quot;))
		glFrontFace(GL_CW);
	glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
	glutGet(GLUT_ELAPSED_TIME);
	glutMainLoop();

	//释放资源，C实现是手动挡，C++的话在这里将自动调用析构函数销毁资源，
        //释放资源这种事情在实例化后就可以let it go out of scope.
	aiReleaseImport(scene);
	aiDetachAllLogStreams();
	return 0;
}
&lt;/pre&gt;
&lt;p&gt;loadassert是个自定义的函数，做了2件事情，调用aiImportFile将模型载入场景，计算bounding box。其中的参数aiPorcessPreset_TargetRealtime_Quality是后续处理的标志位设置参数，能提供实时渲染优化，这是一个复合flag，实际是合并了20多个标志位，用于提供高质量，而不是追求速度（渲染帧数或载入速度）的设置。&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;
int loadasset (const char* path)
{
	// we are taking one of the postprocessing presets to avoid
	// writing 20 single postprocessing flags here.
	scene = aiImportFile(path,aiProcessPreset_TargetRealtime_Quality);
	if (scene) {
		get_bounding_box(&amp;amp;scene_min,&amp;amp;scene_max);
		scene_center.x = (scene_min.x + scene_max.x) / 2.0f;
		scene_center.y = (scene_min.y + scene_max.y) / 2.0f;
		scene_center.z = (scene_min.z + scene_max.z) / 2.0f;
		return 0;
	}
	return 1;
}
&lt;/pre&gt;
&lt;p&gt;get_bounding_box() 递归调用了get_bounding_box_for_node()，用于计算包围盒，这两个函数不用多说，我觉得挺有用的，顺便倒是可以去看看组里用八叉树实现的mesh管理，如何计算包围盒。&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;
// ----------------------------------------------------
void get_bounding_box_for_node (const struct aiNode* nd,
	struct aiVector3D* min,
	struct aiVector3D* max,
	struct aiMatrix4x4* trafo
){
	struct aiMatrix4x4 prev;
	unsigned int n = 0, t;

	prev = *trafo;
	aiMultiplyMatrix4(trafo,&amp;amp;nd-&amp;gt;mTransformation);

	for (; n &lt; nd-&gt;mNumMeshes; ++n) {
		const struct aiMesh* mesh = scene-&gt;mMeshes[nd-&gt;mMeshes[n]];
		for (t = 0; t &lt; mesh-&gt;mNumVertices; ++t)
                {
			struct aiVector3D tmp = mesh-&amp;gt;mVertices[t];
			aiTransformVecByMatrix4(&amp;amp;tmp,trafo);

			min-&amp;gt;x = aisgl_min(min-&amp;gt;x,tmp.x);
			min-&amp;gt;y = aisgl_min(min-&amp;gt;y,tmp.y);
			min-&amp;gt;z = aisgl_min(min-&amp;gt;z,tmp.z);

			max-&amp;gt;x = aisgl_max(max-&amp;gt;x,tmp.x);
			max-&amp;gt;y = aisgl_max(max-&amp;gt;y,tmp.y);
			max-&amp;gt;z = aisgl_max(max-&amp;gt;z,tmp.z);
		}
	}

	for (n = 0; n &lt; nd-&gt;mNumChildren; ++n) {
		get_bounding_box_for_node(nd-&amp;gt;mChildren[n],min,max,trafo);
	}
	*trafo = prev;
}

// -----------------------------------------------------------------
void get_bounding_box (struct aiVector3D* min, struct aiVector3D* max)
{
	struct aiMatrix4x4 trafo;
	aiIdentityMatrix4(&amp;amp;trafo);

	min-&amp;gt;x = min-&amp;gt;y = min-&amp;gt;z =  1e10f;
	max-&amp;gt;x = max-&amp;gt;y = max-&amp;gt;z = -1e10f;
	get_bounding_box_for_node(scene-&amp;gt;mRootNode,min,max,&amp;amp;trafo);
}
&lt;/pre&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;
void display(void)
{
	float tmp;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.f,0.f,3.f,0.f,0.f,-5.f,0.f,1.f,0.f);

	// rotate it around the y axis
	glRotatef(angle,0.f,1.f,0.f);

	// scale the whole asset to fit into our view frustum
	tmp = scene_max.x-scene_min.x;
	tmp = aisgl_max(scene_max.y - scene_min.y,tmp);
	tmp = aisgl_max(scene_max.z - scene_min.z,tmp);
	tmp = 1.f / tmp;
	glScalef(tmp, tmp, tmp);

        // center the model
	glTranslatef( -scene_center.x, -scene_center.y, -scene_center.z );

        // if the display list has not been made yet, create a new one and
        // fill it with scene contents
	if(scene_list == 0) {
	    scene_list = glGenLists(1);
	    glNewList(scene_list, GL_COMPILE);
       // now begin at the root node of the imported data and traverse
       // the scenegraph by multiplying subsequent local transforms
       // together on GL's matrix stack.
	    recursive_render(scene, scene-&amp;gt;mRootNode);
	    glEndList();
	}
	glCallList(scene_list);
	glutSwapBuffers();
	do_motion();
}
&lt;/pre&gt;
&lt;p&gt;遍历mesh并显示输出的函数。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;首先是应用模型视图矩阵，glPushMatrix()将复制当前顶部矩阵，并把它压到堆栈中，递归函数中首先掉用这个函数将使得上一级node的变换将影响其孩子node 的变换，而孩子node 的变换将不会影响其父亲node 的变换。&lt;/li&gt;
&lt;li&gt;然后说一下aiNode和aiMesh的数据结构：一个aiNode是一个导入的层次化结构，包含name，parent node(root 除外)，a transformation。简单的模型格式导入到scene后，将只有一个没有任何孩子的 root node。&lt;/li&gt;
&lt;li&gt;一个aiNode中包含一个mMeshes数组，存储了由aiScene保存的aiMesh数组的下标。aiScene存储有一个root node，一个内容为aiMesh*的数组，及其他材质，动画，光照等信息。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;
void recursive_render (const struct aiScene *sc, const struct aiNode* nd)
{
	int i;
	unsigned int n = 0, t;
	struct aiMatrix4x4 m = nd-&gt;mTransformation;

	// update transform
	aiTransposeMatrix4(&amp;#038;m);
	glPushMatrix();
	glMultMatrixf((float*)&amp;#038;m);

	// draw all meshes assigned to this node
	for (; n &lt; nd-&gt;mNumMeshes; ++n) {
                //nd-&gt;mMeshes[n]获得下标
		const struct aiMesh* mesh = scene-&amp;gt;mMeshes[nd-&amp;gt;mMeshes[n]];
		apply_material(sc-&amp;gt;mMaterials[mesh-&amp;gt;mMaterialIndex]);
                //应用材质及颜色信息
		if(mesh-&gt;mNormals == NULL) {
			glDisable(GL_LIGHTING);
		} else {
			glEnable(GL_LIGHTING);
		}
		if(mesh-&gt;mColors[0] != NULL) {
			glEnable(GL_COLOR_MATERIAL);
		} else {
			glDisable(GL_COLOR_MATERIAL);
		}
                //显示模式判定
		for (t = 0; t &lt; mesh-&gt;mNumFaces; ++t) {
			const struct aiFace* face = &amp;amp;mesh-&gt;mFaces[t];
			GLenum face_mode;
			switch(face-&gt;mNumIndices) {
				case 1: face_mode = GL_POINTS; break;
				case 2: face_mode = GL_LINES; break;
				case 3: face_mode = GL_TRIANGLES; break;
				default: face_mode = GL_POLYGON; break;
			}
                        //开始绘制，mesh中若没有normal是可以调用api计算的
			glBegin(face_mode);
			for(i = 0; i &lt; face-&gt;mNumIndices; i++) {
				int index = face-&gt;mIndices[i];
				if(mesh-&gt;mColors[0] != NULL)
					Color4f(&amp;#038;mesh-&gt;mColors[0][index]);
				if(mesh-&gt;mNormals != NULL)
					glNormal3fv(&amp;#038;mesh-&gt;mNormals[index].x);
				glVertex3fv(&amp;#038;mesh-&gt;mVertices[index].x);
			}
			glEnd();
		}

	}
// draw all children
	for (n = 0; n &amp;lt; nd-&amp;gt;mNumChildren; ++n) {
		recursive_render(sc, nd-&amp;gt;mChildren[n]);
	}
	glPopMatrix();
}&lt;/pre&gt;
&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2157/&quot;&gt;SimpleOpenGL 使用Assimp及glut实现的简单示例&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307181/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307181/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://neversayever.com/blog/2012/02/2157/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&lt;p&gt;SimpleOpenGL示例程序是Assimp中自带的一个基于c实现的最简单的程序，我看了一遍，觉得虽然没有C++实现那么漂亮，不过倒是提供了很多Assimp用法的示例，还是记录一下。

程序功能及其简单，模型的载入及显示，另外演示了一下Assimp提供的log stream系统，这个倒是挺不错。

几个变量的定义
&lt;pre class=&quot;brush:cpp&quot;&gt;//the global Assimp scene object
const struct aiScene* scene = NULL;
GLuint scene_list = 0;
struct aiVector3D scene_min, scene_max, scene_center;&lt;/pre&gt;
main函数
&lt;pre class=&quot;brush:cpp&quot;&gt;
int main(int argc, char **argv)
{
 //aiLogStream表示一个日志系统，可以看到Assimp的API以ai开头
 //C实现让我很不爽的是前面都加个Struct，对于我等有代码洁癖的人来说，看起来真心不爽
	struct aiLogStream stream;

	glutInitWindowSize(900,600);
	glutInitWindowPosition(100,100);
	glutInitDisplayMode(GLUT_RGB &amp;#124; GLUT_DOUBLE &amp;#124; GLUT_DEPTH);
	glutInit(&amp;#38;argc, argv);

	glutCreateWindow(&quot;Assimp - Very simple OpenGL sample&quot;);
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);

	//将一个预定义的STDOUT Stream指针绑定到日志系统，信息将输出到控制台窗口
        //日志将记录以后所有的导入模型文件及后处理API的调用
        stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL);
	aiAttachLogStream(&amp;#038;stream);
        //继续绑定一个log，不过这个log将记录信息到文件assimp_log.txt中
	stream = aiGetPredefinedLogStream(aiDefaultLogStream_FILE,&quot;assimp_log.txt&quot;);
	aiAttachLogStream(&amp;#38;stream);
        //载入模型文件，看着很是DT，是不
	if( 0 != loadasset( argc &gt;= 2 ? argv[1] : &quot;../../test/models-nonbsd/X/dwarf.x&quot;))
        {
		if( argc != 1 &amp;#124;&amp;#124; 0 != loadasset(&quot;../../../../test/models-nonbsd/X/dwarf.x&quot;) 
                        &amp;#038;&amp; 0 != loadasset( &quot;../../test/models/X/Testwuson.X&quot;)) 
                {
			return -1;
		}
	}
	glClearColor(0.1f,0.1f,0.1f,1.f);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);    // Uses default lighting parameters
	glEnable(GL_DEPTH_TEST);
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
	glEnable(GL_NORMALIZE);
	// XXX docs say all polygons are emitted CCW, but tests show that some aren't.
	if(getenv(&quot;MODEL_IS_BROKEN&quot;))
		glFrontFace(GL_CW);
	glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
	glutGet(GLUT_ELAPSED_TIME);
	glutMainLoop();

	//释放资源，C实现是手动挡，C++的话在这里将自动调用析构函数销毁资源，
        //释放资源这种事情在实例化后就可以let it go out of scope.
	aiReleaseImport(scene);
	aiDetachAllLogStreams();
	return 0;
}
&lt;/pre&gt;
&lt;p&gt;loadassert是个自定义的函数，做了2件事情，调用aiImportFile将模型载入场景，计算bounding box。其中的参数aiPorcessPreset_TargetRealtime_Quality是后续处理的标志位设置参数，能提供实时渲染优化，这是一个复合flag，实际是合并了20多个标志位，用于提供高质量，而不是追求速度（渲染帧数或载入速度）的设置。&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;
int loadasset (const char* path)
{
	// we are taking one of the postprocessing presets to avoid
	// writing 20 single postprocessing flags here.
	scene = aiImportFile(path,aiProcessPreset_TargetRealtime_Quality);
	if (scene) {
		get_bounding_box(&amp;#38;scene_min,&amp;#38;scene_max);
		scene_center.x = (scene_min.x + scene_max.x) / 2.0f;
		scene_center.y = (scene_min.y + scene_max.y) / 2.0f;
		scene_center.z = (scene_min.z + scene_max.z) / 2.0f;
		return 0;
	}
	return 1;
}
&lt;/pre&gt;
&lt;p&gt;get_bounding_box() 递归调用了get_bounding_box_for_node()，用于计算包围盒，这两个函数不用多说，我觉得挺有用的，顺便倒是可以去看看组里用八叉树实现的mesh管理，如何计算包围盒。&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;
// ----------------------------------------------------
void get_bounding_box_for_node (const struct aiNode* nd,
	struct aiVector3D* min,
	struct aiVector3D* max,
	struct aiMatrix4x4* trafo
){
	struct aiMatrix4x4 prev;
	unsigned int n = 0, t;

	prev = *trafo;
	aiMultiplyMatrix4(trafo,&amp;#38;nd-&amp;#62;mTransformation);

	for (; n &lt; nd-&gt;mNumMeshes; ++n) {
		const struct aiMesh* mesh = scene-&gt;mMeshes[nd-&gt;mMeshes[n]];
		for (t = 0; t &lt; mesh-&gt;mNumVertices; ++t) 
                {
			struct aiVector3D tmp = mesh-&amp;#62;mVertices[t];
			aiTransformVecByMatrix4(&amp;#38;tmp,trafo);

			min-&amp;#62;x = aisgl_min(min-&amp;#62;x,tmp.x);
			min-&amp;#62;y = aisgl_min(min-&amp;#62;y,tmp.y);
			min-&amp;#62;z = aisgl_min(min-&amp;#62;z,tmp.z);

			max-&amp;#62;x = aisgl_max(max-&amp;#62;x,tmp.x);
			max-&amp;#62;y = aisgl_max(max-&amp;#62;y,tmp.y);
			max-&amp;#62;z = aisgl_max(max-&amp;#62;z,tmp.z);
		}
	}

	for (n = 0; n &lt; nd-&gt;mNumChildren; ++n) {
		get_bounding_box_for_node(nd-&amp;#62;mChildren[n],min,max,trafo);
	}
	*trafo = prev;
}

// -----------------------------------------------------------------
void get_bounding_box (struct aiVector3D* min, struct aiVector3D* max)
{
	struct aiMatrix4x4 trafo;
	aiIdentityMatrix4(&amp;#38;trafo);

	min-&amp;#62;x = min-&amp;#62;y = min-&amp;#62;z =  1e10f;
	max-&amp;#62;x = max-&amp;#62;y = max-&amp;#62;z = -1e10f;
	get_bounding_box_for_node(scene-&amp;#62;mRootNode,min,max,&amp;#38;trafo);
}
&lt;/pre&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;
void display(void)
{
	float tmp;

	glClear(GL_COLOR_BUFFER_BIT &amp;#124; GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.f,0.f,3.f,0.f,0.f,-5.f,0.f,1.f,0.f);

	// rotate it around the y axis
	glRotatef(angle,0.f,1.f,0.f);

	// scale the whole asset to fit into our view frustum
	tmp = scene_max.x-scene_min.x;
	tmp = aisgl_max(scene_max.y - scene_min.y,tmp);
	tmp = aisgl_max(scene_max.z - scene_min.z,tmp);
	tmp = 1.f / tmp;
	glScalef(tmp, tmp, tmp);

        // center the model
	glTranslatef( -scene_center.x, -scene_center.y, -scene_center.z );

        // if the display list has not been made yet, create a new one and
        // fill it with scene contents
	if(scene_list == 0) {
	    scene_list = glGenLists(1);
	    glNewList(scene_list, GL_COMPILE);
       // now begin at the root node of the imported data and traverse
       // the scenegraph by multiplying subsequent local transforms
       // together on GL's matrix stack.
	    recursive_render(scene, scene-&amp;#62;mRootNode);
	    glEndList();
	}
	glCallList(scene_list);
	glutSwapBuffers();
	do_motion();
}
&lt;/pre&gt;
&lt;p&gt;遍历mesh并显示输出的函数。&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;首先是应用模型视图矩阵，glPushMatrix()将复制当前顶部矩阵，并把它压到堆栈中，递归函数中首先掉用这个函数将使得上一级node的变换将影响其孩子node 的变换，而孩子node 的变换将不会影响其父亲node 的变换。&lt;/li&gt;
	&lt;li&gt;然后说一下aiNode和aiMesh的数据结构：一个aiNode是一个导入的层次化结构，包含name，parent node(root 除外)，a transformation。简单的模型格式导入到scene后，将只有一个没有任何孩子的 root node。&lt;/li&gt;
	&lt;li&gt;一个aiNode中包含一个mMeshes数组，存储了由aiScene保存的aiMesh数组的下标。aiScene存储有一个root node，一个内容为aiMesh*的数组，及其他材质，动画，光照等信息。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;
void recursive_render (const struct aiScene *sc, const struct aiNode* nd)
{
	int i;
	unsigned int n = 0, t;
	struct aiMatrix4x4 m = nd-&gt;mTransformation;

	// update transform
	aiTransposeMatrix4(&amp;#038;m);
	glPushMatrix();
	glMultMatrixf((float*)&amp;#038;m);

	// draw all meshes assigned to this node
	for (; n &lt; nd-&gt;mNumMeshes; ++n) {
                //nd-&gt;mMeshes[n]获得下标
		const struct aiMesh* mesh = scene-&amp;#62;mMeshes[nd-&amp;#62;mMeshes[n]];
		apply_material(sc-&amp;#62;mMaterials[mesh-&amp;#62;mMaterialIndex]);
                //应用材质及颜色信息
		if(mesh-&gt;mNormals == NULL) {
			glDisable(GL_LIGHTING);
		} else {
			glEnable(GL_LIGHTING);
		}
		if(mesh-&gt;mColors[0] != NULL) {
			glEnable(GL_COLOR_MATERIAL);
		} else {
			glDisable(GL_COLOR_MATERIAL);
		}
                //显示模式判定
		for (t = 0; t &lt; mesh-&gt;mNumFaces; ++t) {
			const struct aiFace* face = &amp;#38;mesh-&gt;mFaces[t];
			GLenum face_mode;
			switch(face-&gt;mNumIndices) {
				case 1: face_mode = GL_POINTS; break;
				case 2: face_mode = GL_LINES; break;
				case 3: face_mode = GL_TRIANGLES; break;
				default: face_mode = GL_POLYGON; break;
			}
                        //开始绘制，mesh中若没有normal是可以调用api计算的
			glBegin(face_mode);
			for(i = 0; i &lt; face-&gt;mNumIndices; i++) {
				int index = face-&gt;mIndices[i];
				if(mesh-&gt;mColors[0] != NULL)
					Color4f(&amp;#038;mesh-&gt;mColors[0][index]);
				if(mesh-&gt;mNormals != NULL)
					glNormal3fv(&amp;#038;mesh-&gt;mNormals[index].x);
				glVertex3fv(&amp;#038;mesh-&gt;mVertices[index].x);
			}
			glEnd();
		}

	}
// draw all children
	for (n = 0; n &amp;#60; nd-&amp;#62;mNumChildren; ++n) {
		recursive_render(sc, nd-&amp;#62;mChildren[n]);
	}
	glPopMatrix();
}&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2157/&quot;&gt;SimpleOpenGL 使用Assimp及glut实现的简单示例&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307181/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307181/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>Mesh</category><category>Assimp</category><category>OpenGL</category><pubDate>Tue, 21 Feb 2012 16:13:15 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/02/2157/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2157</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/02/2157/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/638307181/6973417</fs:itemid></item><item><title>assimp 一个mesh相关的模型导入及场景资源维护的库</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307182/6973417/1/item.html</link><content:encoded>&lt;p&gt;&lt;img style=&quot;background-image: none; margin: 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; padding-top: 0px; border-width: 0px;&quot; src=&quot;http://assimp.sourceforge.net/images/splash_a1.png&quot; alt=&quot;&quot; align=&quot;right&quot; border=&quot;0&quot; /&gt;&lt;/p&gt;
&lt;p&gt;时不时遇到需要处理mesh的相关任务，但是每次拿到模型总是苦于没有现成的高效的代码可以用，一次，两次从基础开始自己写导入，自己写显示还能接受，次数多了实在受不了。&lt;/p&gt;
&lt;p&gt;网上搜处理mesh的开源库也有很多，Assimp(Open Assert Import Library)只是其中一个，专门用于模型的导入，其支持的模型格式很多，&lt;a href=&quot;http://assimp.sourceforge.net/index.html&quot;&gt;主页&lt;/a&gt;上列出的有这些：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Collada&lt;/strong&gt; ( &lt;em&gt;*.dae;*.xml&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;Blender&lt;/strong&gt; ( &lt;em&gt;*.blend&lt;/em&gt; ) &lt;sup&gt;3&lt;/sup&gt;&lt;br /&gt;
&lt;strong&gt;Biovision BVH &lt;/strong&gt;( &lt;em&gt;*.bvh&lt;/em&gt; )&lt;br /&gt;
&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;3D Studio Max 3DS&lt;/strong&gt; ( &lt;em&gt;*.3ds&lt;/em&gt; )&lt;br /&gt;
&lt;/span&gt;&lt;strong&gt;3D Studio Max ASE&lt;/strong&gt; ( &lt;em&gt;*.ase&lt;/em&gt; )&lt;br /&gt;
&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;Wavefront Object&lt;/strong&gt; ( &lt;em&gt;*.obj&lt;/em&gt; )&lt;/span&gt;&lt;br /&gt;
&lt;strong&gt;Stanford Polygon Library&lt;/strong&gt; ( &lt;em&gt;*.ply&lt;/em&gt; )&lt;br /&gt;
&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;AutoCAD DXF&lt;/strong&gt; ( &lt;em&gt;*.dxf&lt;/em&gt; ) &lt;sup&gt;2&lt;/sup&gt;&lt;br /&gt;
&lt;/span&gt;&lt;strong&gt;Neutral File Format&lt;/strong&gt; ( &lt;em&gt;*.nff&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;Sense8 WorldToolkit&lt;/strong&gt; ( &lt;em&gt;*.nff&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;Valve Model&lt;/strong&gt; ( &lt;em&gt;*.smd,*.vta&lt;/em&gt; ) &lt;sup&gt;3&lt;/sup&gt;&lt;br /&gt;
&lt;strong&gt;Quake I&lt;/strong&gt; ( &lt;em&gt;*.mdl&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;Quake II&lt;/strong&gt; ( &lt;em&gt;*.md2&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;Quake III&lt;/strong&gt; ( &lt;em&gt;*.md3&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;Quake 3 BSP&lt;/strong&gt; ( &lt;em&gt;*.pk3&lt;/em&gt; ) &lt;sup&gt;1&lt;/sup&gt;&lt;br /&gt;
&lt;strong&gt;RtCW&lt;/strong&gt; ( &lt;em&gt;*.mdc&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;Doom 3&lt;/strong&gt; ( &lt;em&gt;*.md5mesh;*.md5anim;*.md5camera&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;DirectX X &lt;/strong&gt;( &lt;em&gt;*.x&lt;/em&gt; ).&lt;br /&gt;
&lt;strong&gt;Quick3D &lt;/strong&gt;( &lt;em&gt;*.q3o;*q3s&lt;/em&gt; ).&lt;br /&gt;
&lt;strong&gt;Raw Triangles &lt;/strong&gt;( &lt;em&gt;*.raw&lt;/em&gt; ).&lt;br /&gt;
&lt;strong&gt;AC3D &lt;/strong&gt;( &lt;em&gt;*.ac&lt;/em&gt; ).&lt;br /&gt;
&lt;strong&gt;Stereolithography &lt;/strong&gt;( &lt;em&gt;*.stl&lt;/em&gt; ).&lt;br /&gt;
&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;Autodesk DXF &lt;/strong&gt;( &lt;em&gt;*.dxf&lt;/em&gt; ).&lt;/span&gt;&lt;br /&gt;
&lt;strong&gt;Irrlicht Mesh &lt;/strong&gt;( &lt;em&gt;*.irrmesh;*.xml&lt;/em&gt; ).&lt;br /&gt;
&lt;strong&gt;Irrlicht Scene &lt;/strong&gt;( &lt;em&gt;*.irr;*.xml&lt;/em&gt; ).&lt;br /&gt;
&lt;strong&gt;Object File Format &lt;/strong&gt;( &lt;em&gt;*.off&lt;/em&gt; ).&lt;br /&gt;
&lt;strong&gt;Terragen Terrain &lt;/strong&gt;( &lt;em&gt;*.ter&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;3D GameStudio Model &lt;/strong&gt;( &lt;em&gt;*.mdl&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;3D GameStudio Terrain&lt;/strong&gt; ( &lt;em&gt;*.hmp&lt;/em&gt; )&lt;br /&gt;
&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;Ogre&lt;/strong&gt; (&lt;em&gt;*.mesh.xml, *.skeleton.xml, *.material&lt;/em&gt;)&lt;sup&gt;3&lt;/sup&gt;&lt;/span&gt;&lt;br /&gt;
&lt;strong&gt;Milkshape 3D&lt;/strong&gt; ( &lt;em&gt;*.ms3d&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;LightWave Model&lt;/strong&gt; ( &lt;em&gt;*.lwo&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;LightWave Scene&lt;/strong&gt; ( &lt;em&gt;*.lws&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;Modo Model&lt;/strong&gt; ( &lt;em&gt;*.lxo&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;CharacterStudio Motion&lt;/strong&gt; ( &lt;em&gt;*.csm&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;Stanford Ply&lt;/strong&gt; ( &lt;em&gt;*.ply&lt;/em&gt; )&lt;br /&gt;
&lt;strong&gt;TrueSpace&lt;/strong&gt; ( &lt;em&gt;*.cob, *.scn&lt;/em&gt; )&lt;sup&gt;2&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;目前的的库版本支持两个模型格式的导出：&lt;br /&gt;
&lt;strong&gt;Collada(.dae)&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;3ds Max 3DS (.3ds)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Assimp遵循BSD开源协议，可以拿来使用，修改，并可以用于商业用途，只是所造成的后果要自己承担。Assimp用C++写成，建议使用C++格式调用它的API。除C++以外，它也有C，Python，D接口。它也提供了命令行工具，可以快速执行一些如文件状态，模型转换，材质提取等操作。&lt;/p&gt;
&lt;p&gt;Assimp也拥有一些后续处理(post-processing)能力，例如&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从右手坐标系转换到左手坐标系&lt;/li&gt;
&lt;li&gt;三角化多边形&lt;/li&gt;
&lt;li&gt;&lt;del&gt;添加相同节点以利于索引&lt;/del&gt;合并相同节点优化索引&lt;/li&gt;
&lt;li&gt;寻找错误的，低效的多边形&lt;/li&gt;
&lt;li&gt;分割大型多边形以克服GPU限制&lt;/li&gt;
&lt;li&gt;计算面的法向，可以计算平滑的和粗糙（hard）的法向。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;wiki在&lt;a href=&quot;http://assimp.sourceforge.net/lib_html/index.html&quot;&gt;这里&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;安装：&lt;/p&gt;
&lt;p&gt;下载sdk，我下载的是2.0版本的sdk，因为sdk已经编译好的库能很好地支持vs2005和vs2008，所以不需要使用源代码重新编译。1.添加ASSIMP/include路径到你的vs include path(在Menu-&amp;gt;Extras-&amp;gt;Options-&amp;gt;Projects and Solutions-&amp;gt;VC++ Directories-&amp;gt;Include files)。2.添加ASSIMP/lib/&amp;lt;Compiler&amp;gt; 路径到你的 linker paths (在Menu-&amp;gt;Extras-&amp;gt;Options-&amp;gt;Projects and Solutions-&amp;gt;VC++ Directories-&amp;gt;Library files)。这是一步到位的做法，你也可以单个在每个工程里面包含这些额外路径，lib主要用到的是&lt;strong&gt;assimp.lib&lt;/strong&gt;，头文件主要用到&lt;/p&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;
// assimp include files. These three are usually needed.
#include &quot;assimp.h&quot;
#include &quot;aiPostProcess.h&quot;
#include &quot;aiScene.h&quot;&lt;/pre&gt;
&lt;p&gt;其他编译环境或者自己编译库文件，请参考&lt;a href=&quot;http://assimp.sourceforge.net/lib_html/install.html&quot;&gt;这里&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;sdk里面自带一些例子，这是SimpleOpengl的截图，用了glut。&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;margin: 10px auto; display: block; float: none;&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/glut_assimp.jpg&quot; alt=&quot;&quot; width=&quot;618&quot; height=&quot;433&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2151/&quot;&gt;assimp 一个mesh相关的模型导入及场景资源维护的库&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307182/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307182/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://neversayever.com/blog/2012/02/2151/feed/</wfw:commentRss><slash:comments>1</slash:comments><description>&lt;p&gt;&lt;img style=&quot;background-image: none; margin: 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; padding-top: 0px; border-width: 0px;&quot; src=&quot;http://assimp.sourceforge.net/images/splash_a1.png&quot; alt=&quot;&quot; align=&quot;right&quot; border=&quot;0&quot; /&gt;

时不时遇到需要处理mesh的相关任务，但是每次拿到模型总是苦于没有现成的高效的代码可以用，一次，两次从基础开始自己写导入，自己写显示还能接受，次数多了实在受不了。

网上搜处理mesh的开源库也有很多，Assimp(Open Assert Import Library)只是其中一个，专门用于模型的导入，其支持的模型格式很多，&lt;a href=&quot;http://assimp.sourceforge.net/index.html&quot;&gt;主页&lt;/a&gt;上列出的有这些：

&lt;strong&gt;Collada&lt;/strong&gt; ( &lt;em&gt;*.dae;*.xml&lt;/em&gt; )
&lt;strong&gt;Blender&lt;/strong&gt; ( &lt;em&gt;*.blend&lt;/em&gt; ) &lt;sup&gt;3&lt;/sup&gt;
&lt;strong&gt;Biovision BVH &lt;/strong&gt;( &lt;em&gt;*.bvh&lt;/em&gt; )
&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;3D Studio Max 3DS&lt;/strong&gt; ( &lt;em&gt;*.3ds&lt;/em&gt; )
&lt;/span&gt;&lt;strong&gt;3D Studio Max ASE&lt;/strong&gt; ( &lt;em&gt;*.ase&lt;/em&gt; )
&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;Wavefront Object&lt;/strong&gt; ( &lt;em&gt;*.obj&lt;/em&gt; )&lt;/span&gt;
&lt;strong&gt;Stanford Polygon Library&lt;/strong&gt; ( &lt;em&gt;*.ply&lt;/em&gt; )
&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;AutoCAD DXF&lt;/strong&gt; ( &lt;em&gt;*.dxf&lt;/em&gt; ) &lt;sup&gt;2&lt;/sup&gt;
&lt;/span&gt;&lt;strong&gt;Neutral File Format&lt;/strong&gt; ( &lt;em&gt;*.nff&lt;/em&gt; )
&lt;strong&gt;Sense8 WorldToolkit&lt;/strong&gt; ( &lt;em&gt;*.nff&lt;/em&gt; )
&lt;strong&gt;Valve Model&lt;/strong&gt; ( &lt;em&gt;*.smd,*.vta&lt;/em&gt; ) &lt;sup&gt;3&lt;/sup&gt;
&lt;strong&gt;Quake I&lt;/strong&gt; ( &lt;em&gt;*.mdl&lt;/em&gt; )
&lt;strong&gt;Quake II&lt;/strong&gt; ( &lt;em&gt;*.md2&lt;/em&gt; )
&lt;strong&gt;Quake III&lt;/strong&gt; ( &lt;em&gt;*.md3&lt;/em&gt; )
&lt;strong&gt;Quake 3 BSP&lt;/strong&gt; ( &lt;em&gt;*.pk3&lt;/em&gt; ) &lt;sup&gt;1&lt;/sup&gt;
&lt;strong&gt;RtCW&lt;/strong&gt; ( &lt;em&gt;*.mdc&lt;/em&gt; )
&lt;strong&gt;Doom 3&lt;/strong&gt; ( &lt;em&gt;*.md5mesh;*.md5anim;*.md5camera&lt;/em&gt; )
&lt;strong&gt;DirectX X &lt;/strong&gt;( &lt;em&gt;*.x&lt;/em&gt; ).
&lt;strong&gt;Quick3D &lt;/strong&gt;( &lt;em&gt;*.q3o;*q3s&lt;/em&gt; ).
&lt;strong&gt;Raw Triangles &lt;/strong&gt;( &lt;em&gt;*.raw&lt;/em&gt; ).
&lt;strong&gt;AC3D &lt;/strong&gt;( &lt;em&gt;*.ac&lt;/em&gt; ).
&lt;strong&gt;Stereolithography &lt;/strong&gt;( &lt;em&gt;*.stl&lt;/em&gt; ).
&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;Autodesk DXF &lt;/strong&gt;( &lt;em&gt;*.dxf&lt;/em&gt; ).&lt;/span&gt;
&lt;strong&gt;Irrlicht Mesh &lt;/strong&gt;( &lt;em&gt;*.irrmesh;*.xml&lt;/em&gt; ).
&lt;strong&gt;Irrlicht Scene &lt;/strong&gt;( &lt;em&gt;*.irr;*.xml&lt;/em&gt; ).
&lt;strong&gt;Object File Format &lt;/strong&gt;( &lt;em&gt;*.off&lt;/em&gt; ).
&lt;strong&gt;Terragen Terrain &lt;/strong&gt;( &lt;em&gt;*.ter&lt;/em&gt; )
&lt;strong&gt;3D GameStudio Model &lt;/strong&gt;( &lt;em&gt;*.mdl&lt;/em&gt; )
&lt;strong&gt;3D GameStudio Terrain&lt;/strong&gt; ( &lt;em&gt;*.hmp&lt;/em&gt; )
&lt;span style=&quot;color: #ff0000;&quot;&gt;&lt;strong&gt;Ogre&lt;/strong&gt; (&lt;em&gt;*.mesh.xml, *.skeleton.xml, *.material&lt;/em&gt;)&lt;sup&gt;3&lt;/sup&gt;&lt;/span&gt;
&lt;strong&gt;Milkshape 3D&lt;/strong&gt; ( &lt;em&gt;*.ms3d&lt;/em&gt; )
&lt;strong&gt;LightWave Model&lt;/strong&gt; ( &lt;em&gt;*.lwo&lt;/em&gt; )
&lt;strong&gt;LightWave Scene&lt;/strong&gt; ( &lt;em&gt;*.lws&lt;/em&gt; )
&lt;strong&gt;Modo Model&lt;/strong&gt; ( &lt;em&gt;*.lxo&lt;/em&gt; )
&lt;strong&gt;CharacterStudio Motion&lt;/strong&gt; ( &lt;em&gt;*.csm&lt;/em&gt; )
&lt;strong&gt;Stanford Ply&lt;/strong&gt; ( &lt;em&gt;*.ply&lt;/em&gt; )
&lt;strong&gt;TrueSpace&lt;/strong&gt; ( &lt;em&gt;*.cob, *.scn&lt;/em&gt; )&lt;sup&gt;2&lt;/sup&gt;

目前的的库版本支持两个模型格式的导出：
&lt;strong&gt;Collada(.dae)&lt;/strong&gt;
&lt;strong&gt;3ds Max 3DS (.3ds)&lt;/strong&gt;

Assimp遵循BSD开源协议，可以拿来使用，修改，并可以用于商业用途，只是所造成的后果要自己承担。Assimp用C++写成，建议使用C++格式调用它的API。除C++以外，它也有C，Python，D接口。它也提供了命令行工具，可以快速执行一些如文件状态，模型转换，材质提取等操作。

Assimp也拥有一些后续处理(post-processing)能力，例如
&lt;ul&gt;
	&lt;li&gt;从右手坐标系转换到左手坐标系&lt;/li&gt;
	&lt;li&gt;三角化多边形&lt;/li&gt;
	&lt;li&gt;&lt;del&gt;添加相同节点以利于索引&lt;/del&gt;合并相同节点优化索引&lt;/li&gt;
	&lt;li&gt;寻找错误的，低效的多边形&lt;/li&gt;
	&lt;li&gt;分割大型多边形以克服GPU限制&lt;/li&gt;
	&lt;li&gt;计算面的法向，可以计算平滑的和粗糙（hard）的法向。&lt;/li&gt;
&lt;/ul&gt;
wiki在&lt;a href=&quot;http://assimp.sourceforge.net/lib_html/index.html&quot;&gt;这里&lt;/a&gt;。

安装：

下载sdk，我下载的是2.0版本的sdk，因为sdk已经编译好的库能很好地支持vs2005和vs2008，所以不需要使用源代码重新编译。1.添加ASSIMP/include路径到你的vs include path(在Menu-&amp;#62;Extras-&amp;#62;Options-&amp;#62;Projects and Solutions-&amp;#62;VC++ Directories-&amp;#62;Include files)。2.添加ASSIMP/lib/&amp;#60;Compiler&amp;#62; 路径到你的 linker paths (在Menu-&amp;#62;Extras-&amp;#62;Options-&amp;#62;Projects and Solutions-&amp;#62;VC++ Directories-&amp;#62;Library files)。这是一步到位的做法，你也可以单个在每个工程里面包含这些额外路径，lib主要用到的是&lt;strong&gt;assimp.lib&lt;/strong&gt;，头文件主要用到
&lt;pre class=&quot;brush:cpp&quot;&gt; 
// assimp include files. These three are usually needed. 
#include &quot;assimp.h&quot; 
#include &quot;aiPostProcess.h&quot; 
#include &quot;aiScene.h&quot;&lt;/pre&gt;
其他编译环境或者自己编译库文件，请参考&lt;a href=&quot;http://assimp.sourceforge.net/lib_html/install.html&quot;&gt;这里&lt;/a&gt;。

sdk里面自带一些例子，这是SimpleOpengl的截图，用了glut。

&lt;img style=&quot;margin: 10px auto; display: block; float: none;&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/02/glut_assimp.jpg&quot; alt=&quot;&quot; width=&quot;618&quot; height=&quot;433&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2151/&quot;&gt;assimp 一个mesh相关的模型导入及场景资源维护的库&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307182/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307182/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>Mesh</category><category>Assimp</category><category>Mesh导入</category><pubDate>Tue, 21 Feb 2012 10:05:36 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/02/2151/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2151</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/02/2151/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/638307182/6973417</fs:itemid></item><item><title>Android 开发入门 笔记</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307183/6973417/1/item.html</link><content:encoded>&lt;p&gt;我只是随便看看~~~&lt;img style=&quot;background-image: none; border-right-width: 0px; margin: 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px&quot; border=&quot;0&quot; align=&quot;right&quot; src=&quot;http://developer.android.com/images/home/android-design.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;OLE_LINK2&quot;&gt;&lt;/a&gt;&lt;a name=&quot;OLE_LINK1&quot;&gt;android&lt;/a&gt;是移动设备的软件层，包括操作系统，中间层和关键程序。Android SDK 提供了工具和所需的 API 帮主开发者进行 Android 程序开发。SDK使用Java编程语言，google后来推出的NDK （Native Development Kit）使程序员能够使用C/C++ 开发Android程序。不过NDK存在一些局限性，NDK并没有提供各种系统事件处理支持，也没有提供应用程序生命周期维护。此外，应用程序UI方面的API也没有提供。至少目前来说，使用纯C、C++开发一个完整应用的条件还不完备。（目前版本r7版到底支持如何待查看文档）&lt;/p&gt;
&lt;p&gt;Android平台从诞生起，就已经支持C、C++开发。Android的SDK基于Java实现，这意味着基于Android SDK进行开发的第三方应用都必须使用Java语言。但这并不等同于“第三方应用只能使用Java”。在Android SDK首次发布时，Google就宣称其虚拟机Dalvik支持JNI编程方式，也就是第三方应用完全可以通过JNI调用自己的C动态库，即在Android平台上，“Java+C”的编程方式是一直都可以实现的。但是在Android SDK文档里，找不到任何JNI方面的帮助。即使第三方应用开发者使用JNI完成了自己的C动态链接库（so）开发，但是so如何和应用程序一起打包成apk并发布？这里面也存在技术障碍。&lt;/p&gt;
&lt;p&gt;Dalvik虚拟机是Google等厂商合作开发的&lt;a href=&quot;http://zh.wikipedia.org/wiki/Android&quot;&gt;Android&lt;/a&gt;移动设备平台的核心组成部分之一。它可以支持已转换为.dex（即Dalvik Executable）格式的&lt;a href=&quot;http://zh.wikipedia.org/wiki/Java&quot;&gt;Java&lt;/a&gt;应用程序的运行，.dex格式是专为Dalvik设计的一种压缩格式，适合&lt;a href=&quot;http://zh.wikipedia.org/wiki/%E5%86%85%E5%AD%98&quot;&gt;内存&lt;/a&gt;和&lt;a href=&quot;http://zh.wikipedia.org/wiki/%E5%A4%84%E7%90%86%E5%99%A8&quot;&gt;处理器&lt;/a&gt;速度有限的系统。&lt;/p&gt;
&lt;p&gt;dx 是一套工具，可以将 Java .class 转换成 .dex 格式. 一个dex档通常会有多个.class。由于dex有时必须进行最佳化，会使档案大小增加1-4倍，以ODEX结尾。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;font size=&quot;5&quot;&gt;Android特性&lt;/font&gt;&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;l 应用程序框架，支持重用和替换程序组件。&lt;/p&gt;
&lt;p&gt;l Dalivk 虚拟机：为移动设备优化。&lt;/p&gt;
&lt;p&gt;l 集成浏览器：一个开源的基于webKit引擎的浏览器。Android 4.0加入了chrome lite。&lt;/p&gt;
&lt;p&gt;l 优化的图形库：有一个自定义的2D图形库，一个基于OpenGL ES 1.0（可用硬件加速）的3D图形库。&lt;/p&gt;
&lt;p&gt;l SQLite：存储机构化数据。&lt;/p&gt;
&lt;p&gt;l 多媒体支持：支持多种音频，视频，静态图像格式。GIF supported&lt;/p&gt;
&lt;p&gt;l 多种通信模式支持。&lt;/p&gt;
&lt;p&gt;l 照相机，GPS，电子罗盘，加速计支持。&lt;/p&gt;
&lt;p&gt;l 丰富的开发环境：提供设备模拟器，调试工具，内存和性能剖析。&lt;/p&gt;
&lt;p&gt;l Android将搭载一些常用的应用程序，如SMS，联系人，邮件，日历，浏览器等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;font size=&quot;5&quot;&gt;应用程序框架&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;开发者能够获得所有核心应用所使用的API，并且开发者发布的应用程序功能能够被其他开发者重用。&lt;/p&gt;
&lt;p&gt;在应用程序之下的是一系列&lt;strong&gt;服务和系统&lt;/strong&gt;。包括：&lt;/p&gt;
&lt;p&gt;l Views，相当于UI组件。&lt;/p&gt;
&lt;p&gt;l Content Providers 使应用程序能够使用别的程序的数据，例如联系人数据。&lt;/p&gt;
&lt;p&gt;l Resource Manager 能够使用非代码的资源，本地语句（用于翻译），图形和布局文件等。&lt;/p&gt;
&lt;p&gt;l Notification Manager 使应用程序能够在状态栏显示自定义的警告。&lt;/p&gt;
&lt;p&gt;l Activity Manager 能够管理应用程序生命周期，提供一个常用的返回栈。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;font size=&quot;4&quot;&gt;库&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Android包含的C/C++库有：&lt;/p&gt;
&lt;p&gt;l System C library&lt;/p&gt;
&lt;p&gt;l Media Libraries&lt;/p&gt;
&lt;p&gt;l Surface Manager&lt;/p&gt;
&lt;p&gt;l LibWebCore&lt;/p&gt;
&lt;p&gt;l SGL&lt;/p&gt;
&lt;p&gt;l 3D libraries&lt;/p&gt;
&lt;p&gt;l FreeType&lt;/p&gt;
&lt;p&gt;l SQLite&lt;/p&gt;
&lt;p&gt;Dalvik 虚拟机依赖于linux内核（2.6版本）的一些基本功能，比如线程，低级内存管理。&lt;/p&gt;
&lt;p&gt;1、android开发网站：&lt;a href=&quot;http://developer.android.com/&quot;&gt;http://developer.android.com&lt;/a&gt;，这上面有SDK下载，介绍；开发指导，一些有关应用程序格式，显示方式，约定方法的叙述吧；Resource下面有完整的教程，从helloworld开始，Video可能存在于YouTube，反正刷不出来。&lt;/p&gt;
&lt;p&gt;安装SDK后，可能需要安装IDE开发环境：&lt;a href=&quot;http://www.eclipse.org/downloads/&quot;&gt;http://www.eclipse.org/downloads/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2、android market&lt;/p&gt;
&lt;p&gt;在google 官方的安卓市场发布应用程序需要先支付注册费用，而且邮寄账单的国家没有中国，只有香港和台湾。选择美国的话，注册费为25刀，要绑定信用卡什么的。学习的话，自己写写就行了，另外用SDK提供的模拟器运行测试一下就OK了。&lt;/p&gt;
&lt;p&gt;Android 4.0就要来了，可以先看一下4.0的新特性：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://developer.android.com/sdk/android-4.0-highlights.html&quot;&gt;http://developer.android.com/sdk/android-4.0-highlights.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2148/&quot;&gt;Android 开发入门 笔记&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307183/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307183/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://neversayever.com/blog/2012/02/2148/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&lt;p&gt;&lt;p&gt;我只是随便看看~~~&lt;img style=&quot;background-image: none; border-right-width: 0px; margin: 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px&quot; border=&quot;0&quot; align=&quot;right&quot; src=&quot;http://developer.android.com/images/home/android-design.png&quot; /&gt;&lt;/p&gt;  &lt;p&gt;&lt;a name=&quot;OLE_LINK2&quot;&gt;&lt;/a&gt;&lt;a name=&quot;OLE_LINK1&quot;&gt;android&lt;/a&gt;是移动设备的软件层，包括操作系统，中间层和关键程序。Android SDK 提供了工具和所需的 API 帮主开发者进行 Android 程序开发。SDK使用Java编程语言，google后来推出的NDK （Native Development Kit）使程序员能够使用C/C++ 开发Android程序。不过NDK存在一些局限性，NDK并没有提供各种系统事件处理支持，也没有提供应用程序生命周期维护。此外，应用程序UI方面的API也没有提供。至少目前来说，使用纯C、C++开发一个完整应用的条件还不完备。（目前版本r7版到底支持如何待查看文档）&lt;/p&gt;  &lt;p&gt;Android平台从诞生起，就已经支持C、C++开发。Android的SDK基于Java实现，这意味着基于Android SDK进行开发的第三方应用都必须使用Java语言。但这并不等同于“第三方应用只能使用Java”。在Android SDK首次发布时，Google就宣称其虚拟机Dalvik支持JNI编程方式，也就是第三方应用完全可以通过JNI调用自己的C动态库，即在Android平台上，“Java+C”的编程方式是一直都可以实现的。但是在Android SDK文档里，找不到任何JNI方面的帮助。即使第三方应用开发者使用JNI完成了自己的C动态链接库（so）开发，但是so如何和应用程序一起打包成apk并发布？这里面也存在技术障碍。&lt;/p&gt;  &lt;p&gt;Dalvik虚拟机是Google等厂商合作开发的&lt;a href=&quot;http://zh.wikipedia.org/wiki/Android&quot;&gt;Android&lt;/a&gt;移动设备平台的核心组成部分之一。它可以支持已转换为.dex（即Dalvik Executable）格式的&lt;a href=&quot;http://zh.wikipedia.org/wiki/Java&quot;&gt;Java&lt;/a&gt;应用程序的运行，.dex格式是专为Dalvik设计的一种压缩格式，适合&lt;a href=&quot;http://zh.wikipedia.org/wiki/%E5%86%85%E5%AD%98&quot;&gt;内存&lt;/a&gt;和&lt;a href=&quot;http://zh.wikipedia.org/wiki/%E5%A4%84%E7%90%86%E5%99%A8&quot;&gt;处理器&lt;/a&gt;速度有限的系统。&lt;/p&gt;  &lt;p&gt;dx 是一套工具，可以将 Java .class 转换成 .dex 格式. 一个dex档通常会有多个.class。由于dex有时必须进行最佳化，会使档案大小增加1-4倍，以ODEX结尾。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;font size=&quot;5&quot;&gt;Android特性&lt;/font&gt;&lt;/strong&gt;：&lt;/p&gt;  &lt;p&gt;l 应用程序框架，支持重用和替换程序组件。&lt;/p&gt;  &lt;p&gt;l Dalivk 虚拟机：为移动设备优化。&lt;/p&gt;  &lt;p&gt;l 集成浏览器：一个开源的基于webKit引擎的浏览器。Android 4.0加入了chrome lite。&lt;/p&gt;  &lt;p&gt;l 优化的图形库：有一个自定义的2D图形库，一个基于OpenGL ES 1.0（可用硬件加速）的3D图形库。&lt;/p&gt;  &lt;p&gt;l SQLite：存储机构化数据。&lt;/p&gt;  &lt;p&gt;l 多媒体支持：支持多种音频，视频，静态图像格式。GIF supported&lt;/p&gt;  &lt;p&gt;l 多种通信模式支持。&lt;/p&gt;  &lt;p&gt;l 照相机，GPS，电子罗盘，加速计支持。&lt;/p&gt;  &lt;p&gt;l 丰富的开发环境：提供设备模拟器，调试工具，内存和性能剖析。&lt;/p&gt;  &lt;p&gt;l Android将搭载一些常用的应用程序，如SMS，联系人，邮件，日历，浏览器等。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;font size=&quot;5&quot;&gt;应用程序框架&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;开发者能够获得所有核心应用所使用的API，并且开发者发布的应用程序功能能够被其他开发者重用。&lt;/p&gt;  &lt;p&gt;在应用程序之下的是一系列&lt;strong&gt;服务和系统&lt;/strong&gt;。包括：&lt;/p&gt;  &lt;p&gt;l Views，相当于UI组件。&lt;/p&gt;  &lt;p&gt;l Content Providers 使应用程序能够使用别的程序的数据，例如联系人数据。&lt;/p&gt;  &lt;p&gt;l Resource Manager 能够使用非代码的资源，本地语句（用于翻译），图形和布局文件等。&lt;/p&gt;  &lt;p&gt;l Notification Manager 使应用程序能够在状态栏显示自定义的警告。&lt;/p&gt;  &lt;p&gt;l Activity Manager 能够管理应用程序生命周期，提供一个常用的返回栈。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;font size=&quot;4&quot;&gt;库&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Android包含的C/C++库有：&lt;/p&gt;  &lt;p&gt;l System C library&lt;/p&gt;  &lt;p&gt;l Media Libraries&lt;/p&gt;  &lt;p&gt;l Surface Manager&lt;/p&gt;  &lt;p&gt;l LibWebCore&lt;/p&gt;  &lt;p&gt;l SGL&lt;/p&gt;  &lt;p&gt;l 3D libraries&lt;/p&gt;  &lt;p&gt;l FreeType&lt;/p&gt;  &lt;p&gt;l SQLite&lt;/p&gt;  &lt;p&gt;Dalvik 虚拟机依赖于linux内核（2.6版本）的一些基本功能，比如线程，低级内存管理。&lt;/p&gt;  &lt;p&gt;1、android开发网站：&lt;a href=&quot;http://developer.android.com/&quot;&gt;http://developer.android.com&lt;/a&gt;，这上面有SDK下载，介绍；开发指导，一些有关应用程序格式，显示方式，约定方法的叙述吧；Resource下面有完整的教程，从helloworld开始，Video可能存在于YouTube，反正刷不出来。&lt;/p&gt;  &lt;p&gt;安装SDK后，可能需要安装IDE开发环境：&lt;a href=&quot;http://www.eclipse.org/downloads/&quot;&gt;http://www.eclipse.org/downloads/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;2、android market&lt;/p&gt;  &lt;p&gt;在google 官方的安卓市场发布应用程序需要先支付注册费用，而且邮寄账单的国家没有中国，只有香港和台湾。选择美国的话，注册费为25刀，要绑定信用卡什么的。学习的话，自己写写就行了，另外用SDK提供的模拟器运行测试一下就OK了。&lt;/p&gt;  &lt;p&gt;Android 4.0就要来了，可以先看一下4.0的新特性：&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;http://developer.android.com/sdk/android-4.0-highlights.html&quot;&gt;http://developer.android.com/sdk/android-4.0-highlights.html&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;p&gt;&lt;p&gt;&lt;b&gt;本文来自&lt;a href=&quot;http://neversayever.com/blog/2012/02/2148/&quot;&gt;Android 开发入门 笔记&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;想逛逛我的博客？&lt;a href=&quot;http://neversayever.com&quot;&gt;NeverSayEver&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/638307183/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/638307183/6973417/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>笔记</category><category>开发</category><category>Android</category><category>入门</category><category>杂七杂八</category><pubDate>Mon, 13 Feb 2012 22:18:25 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/02/2148/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2148</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/02/2148/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/638307183/6973417</fs:itemid></item></channel></rss>
