<?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: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>Wed, 22 Feb 2012 07:03:14 GMT</lastBuildDate><title>NeverSayEver</title><description>永远不要说永远，我就喜欢这个悖论~</description><link>http://neversayever.com</link><sy:updatePeriod>hourly</sy:updatePeriod><sy:updateFrequency>1</sy:updateFrequency><language>en</language><pubDate>Wed, 22 Feb 2012 07:03:14 GMT</pubDate><item><title>Assimp中的post process step flag</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608544601/6973417/1/item.html</link><wfw:commentRss>http://neversayever.com/blog/2012/02/2175/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>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;img src=&quot;http://www1.feedsky.com/t1/608544601/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608544601/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/608544601/6973417</fs:itemid></item><item><title>SimpleOpenGL 使用Assimp及glut实现的简单示例</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608221644/6973417/1/item.html</link><wfw:commentRss>http://neversayever.com/blog/2012/02/2157/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>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;img src=&quot;http://www1.feedsky.com/t1/608221644/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608221644/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/608221644/6973417</fs:itemid></item><item><title>assimp 一个mesh相关的模型导入及场景资源维护的库</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100859/6973417/1/item.html</link><wfw:commentRss>http://neversayever.com/blog/2012/02/2151/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&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;img src=&quot;http://www1.feedsky.com/t1/608100859/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100859/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/608100859/6973417</fs:itemid></item><item><title>Android 开发入门 笔记</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100860/6973417/1/item.html</link><wfw:commentRss>http://neversayever.com/blog/2012/02/2148/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&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;img src=&quot;http://www1.feedsky.com/t1/608100860/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100860/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/608100860/6973417</fs:itemid></item><item><title>关于Qt Designer中的Action</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100861/6973417/1/item.html</link><wfw:commentRss>http://neversayever.com/blog/2012/02/2145/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&lt;p&gt;今天在用Qt Designer设计主窗口的ToolBar时遇到一个很诡异的问题，首先从menu菜单里面新建一个Actionpen，把它拖动到了ToolBar里面，并且为这个action定义了图标，tooltip等信息。&lt;/p&gt;  &lt;p&gt;后来发现action不能用buttongroup来定义互斥的check，而且toolbar里面无法拖入QPushButton，只能拖入Action。于是想了一想把所有从Qt Designer定义的Action都删了，删掉ToolBar里面的action我用右击-&amp;#62;remove action ‘xxx’，只留下一个空的QToolBar。其他在程序里面写。&lt;/p&gt;  &lt;p&gt;好吧，这还不是高潮~&lt;/p&gt;  &lt;p&gt;然后我发现还是QPushButton在程序里面写，QAction在Designer里面写算了 ，于是重新写一个actionpen，但是Designer死活是actionpen_2，不能重命名成actionpen。好吧，换了个人可能也就将就了，但哥是那种人么。&lt;/p&gt;  &lt;p&gt;在Qt Moc出来的ui_mainwindow.h里面看，发现QAction* actionpen赫然在目，翻到后面，还有new出来，并且有完整的定义。我以为是designer出问题了，于是各种修改，关闭，打开，不管用。然后我所性把toolbar也删了，这你action总不会有了吧，但是照旧…&lt;/p&gt;  &lt;p&gt;google之，这也不好搜。然后我一不小心就发现了这个：&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/Qt_designer_action_editor.jpg&quot; /&gt;   &lt;p&gt;所有的action都在这里，包括使用的和未使用的，好吧，我凹凸了。&lt;/p&gt;  &lt;p&gt;另外在mainwindow的空白处右击，可以添加toolbar。好吧，我又凹凸了。&lt;/p&gt;  &lt;p&gt;用Qt designer ，使得toolbar有一个不能，就是不能添加pushbutton和别的类似comboBox等Widget。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/608100861/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100861/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>QToolBar</category><category>Qt Designer</category><category>Qt</category><pubDate>Mon, 13 Feb 2012 22:04:25 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/02/2145/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2145</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/02/2145/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/608100861/6973417</fs:itemid></item><item><title>Qt Graphics View 框架</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100862/6973417/1/item.html</link><wfw:commentRss>http://neversayever.com/blog/2012/01/2062/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>【&lt;a href=&quot;http://blog.csdn.net/doctorsc/article/details/6774983&quot; target=&quot;_blank&quot;&gt;来自我的CSDN博客&lt;/a&gt;】

这几天做**设计相关编程用了很多QPainter相关的操作，写了不少Qt代码让我对Qt又有了进一步的认识。最近翻看Qt 的 Demos and Examples 发现在Graphics view里面有一个elastic node的示例，程序仅仅定义了背景和小球绘制操作便完成了复杂的鼠标，键盘等交互。在让我大为惊叹Qt 强大的同时，也决定学一学。查找了Qt 帮助文档，这一系列操作都用到了Qt Graphics View Framework。

Graphics View 框架提供了一个界面，用于管理和交互大量的用户自定义的2D图形物件，并且有一个view widget（QGraphicsView）用户可视化这些物件，支持zoom和rotate。这个框架包含了一个事件传播构架，允许了double精度的场景中物体交互能力。物件的键盘，鼠标的按下，移动，松开，双击事件都已经定义好了，并且可以跟踪鼠标移动。
&lt;h2&gt;Graphics view 构架&lt;/h2&gt;
所有的item都被绘制到了一个场景中用于显示，这个场景就是QGraphicsScene，这个场景有如下功能：
&lt;ol&gt;
	&lt;li&gt;为管理大量item提供了一个快速交互界面。&lt;/li&gt;
	&lt;li&gt;能够将键盘，鼠标等事件传递到每个item。&lt;/li&gt;
	&lt;li&gt;可以管理item的状态，例如选择，焦点等。&lt;/li&gt;
	&lt;li&gt;提供了不变形的绘制，主要用于打印绘画结果。&lt;/li&gt;
&lt;/ol&gt;
场景就像一个容易囊括了所有item，可以通过addItem()添加物体，可以通过item()查找物体，itemAt()返回最上面的item，所有item按照降序堆栈排列。第一个加入的在栈顶，最后一个加入的在栈底。

QGraphicsScene的事件传递架构非常给力，能够将场景获得的事件精确传递到相应item，例如鼠标在某点点击了一下，Scene能够将这个事件传递给在这个点上的item(最上面的那个item)，于是这个item被选中或者执行别的动作，具体取决于item的mousePressEvent函数的处理。

QGraphicsScene中，你可以用setSelectionArea()选择区域中的许多个item，仅仅需要调用这个函数你就能获得选中item的结果，真是太强大了，如果要自己写函数鼠标选择的区域选了哪些item，你需要遍历每个item，对于每个item又要判断是否全部在区域内，于是item要包围核，要范围面积等等变量来表示。想想就觉得真心麻烦。这个函数确实为开发者节约了不少时间。
&lt;h2&gt;View&lt;/h2&gt;
QGraphicsView提供了用于显示的widget，用于显示scene，你可以将多个view联系到同一个scene，给相同的数据提供多个视口，视口支持openGL，甚至可以将QGLWidget作为视口，只要调用一下QGraphicsView::setViewport()。View接收交互事件，进行坐标转换后变成scene event交给场景。QGraphicsView::mapToScene(), QGraphicsView::mapFromScene()等多个函数可以在view和scene之间转换坐标系。
&lt;pre class=&quot;brush:cpp&quot;&gt;QGraphicsScene scene;
myPopulateScene(&amp;#38;scene);
QGraphicsView view(&amp;#38;scene);
view.show();&lt;/pre&gt;
&lt;h2&gt;Item&lt;/h2&gt;
QGraphicsItem是场景中所有物件的基类，GraphicsView也提供了一些标准item，例如矩形QGraphicsRectItem，椭圆QGraphicsEllipseItem，还有文本，QGraphicsTextItem，最给力的当然是你自定义的item，item支持以下操作：
&lt;ul&gt;
	&lt;li&gt;鼠标点击，移动，松开，双击，飞越，滚轮，菜单事件。&lt;/li&gt;
	&lt;li&gt;键盘输入。&lt;/li&gt;
	&lt;li&gt;拖拽&lt;/li&gt;
	&lt;li&gt;Group，可以通过父子关系或者QGraphicsItemGroup&lt;/li&gt;
	&lt;li&gt;碰撞检测&lt;/li&gt;
&lt;/ul&gt;
每个Item都有一个局部坐标系，可以通过这个坐标系进行选择，移动等操作，transform()函数通过控制矩阵可以轻松实现这些操作。

有一个很NB的功能就是item支持碰撞检测，怎么检测呢，首先需要为每一类item定义好它的bounding box，同过boundingRect()函数可以设置这个item外围矩形包围盒，而更精确的是用shape()函数定义item外边框路径，这个路径是QPainterPath，这个路径可以是直接，贝塞尔曲线等任何线条，collidesWith()是一个虚函数，定义完成后便能完成碰撞检测功能了。
&lt;h2&gt;其他的Graphics类&lt;/h2&gt;
QGraphicsAnchorLayout是用于将几个widget以锚点的形式随意排列的layout。
QGraphicsEffect提供了一些图形特效。
主要有以下4个标准特效:
&lt;pre class=&quot;brush:cpp&quot;&gt;//Qt provides the following standardeffects:
QGraphicsBlurEffect                // blurs the item by a given radius
QGraphicsDropShadowEffect  // renders a dropshadow behind the item
QGraphicsColorizeEffect          // renders the item in shades of any given color
QGraphicsOpacityEffect          // renders the item with an opacity&lt;/pre&gt;
&lt;h2&gt;Graphics view 坐标系&lt;/h2&gt;
坐标系由(x,y)表示，一个单位就是屏幕上一个像素。在这个框架内一共有3个坐标系，item局部坐标系，场景坐标系，view坐标系，有函数用于在这些坐标系之间进行映射。

Item coordinates
Item的坐标建立在它的中心点（0,0）附近，这也是所有变形的中心位置，几何图元常常由局部坐标系中的点，线，矩形来构建。

构建自定义的item时，仅仅需要考虑局部坐标就行了，QGraphicsView和QGraphicsScene会进行其他所有的变形。鼠标事件用于item时，会自动将点转换到item坐标系中。Item的bounding rect 和 shape都在局部坐标系中定义。

子item的中心位置将会保存到父item的坐标系中用于自动查找判断，最上层item的中心坐标将会保存到scene坐标系中。

父item的旋转缩放操作将会影响子item跟着一起变，但不会影响子item与父Item的坐标系，例如，有父子2个item，在父坐标系中，子的位置在（10，0）。于是，子坐标系中位置为（0,10）的点在父坐标系下的坐标是（10,10）。然后，我对父item进行了旋转和缩放，子坐标系下（0,10）的点在父坐标系下仍然是（10,10），但是在scene坐标系下就会产生变化了，子item会随着父产生形变，如果父进行了缩放为（2x,2x），在scene坐标系下，子的位置为（20，0），子坐标系中（10,0）的点在scene下的坐标为（40,0）。QGraphicsItem：：pos()是少数几个例外的，它返回item在父坐标系下的坐标.

旋转和缩放操作相当简单，在QGraphicsView中调用ratate()和scale()函数。

光说不练嘴把式，必须随便搞个test project。
GraphicWidget继承自QGraphicsView，重载了一个函数，drawBackground().
EllipseItem继承自QGraphicsItem，重载了若干函数：
&lt;pre class=&quot;brush:cpp&quot;&gt;QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem*option, QWidget *widget);
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &amp;#38;value);
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);&lt;/pre&gt;
boundingRect必须得重载，不然编译器说这个是抽象类，不能够实例化。
在mousePressEvent()中调用QGraphicsItem::mousePressEvent(event);便万事大吉，方便shi了。
其他雷同。
在EllipseItem中保存了父节点指针。
在graphicWidget构造函数中new一个scene，设置一下，然后new一个EllipseItem出来，放入scene，指定位置，就可以了。
出来的结果是，你可以任意移动出现的小圆球。

本文固定链接：&lt;a href=&quot;http://neversayever.com/blog/2012/01/2062/&quot; target=&quot;_blank&quot;&gt;http://neversayever.com/blog/2012/01/2062/&lt;/a&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/608100862/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100862/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>Qt Graphics Framework</category><category>Qt</category><pubDate>Thu, 12 Jan 2012 21:50:38 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/01/2062/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2062</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/01/2062/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/608100862/6973417</fs:itemid></item><item><title>Qt Graphics Framework 学习笔记</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100863/6973417/1/item.html</link><wfw:commentRss>http://neversayever.com/blog/2012/01/2056/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&lt;a href=&quot;http://neversayever.com/2012/01/2062/&quot; target=&quot;_blank&quot;&gt;这里&lt;/a&gt;有一篇我从我CSDN博客搬来的原来做的Graphics Framework的笔记。

最近在用Qt的Graphics Framwork作一些类似illustrator矢量作图的小程序，用户需要做的是使用自定义关键点（鼠标点击）绘制一个由贝塞尔曲线构成的带颜色的斑点，可以在之后移动关键点，可以根据关键点2边的控制点改变曲线形状，在此基础上在添加一些算法。

之前也同样用Qt绘制过相似的功能，不过那个是直接用QWidget的Painter实现的，也就是什么都是自己画的，初步交互还可以，但例如缩放，移动，旋转这些操作，相想就比较麻烦，自己实现可能效率还不高。后来在Qt demo里面看到哥用Qt Graphics Framework做的画图程序，各种心痒，代码各种简单，API各种丰富，苦于原本代码写了很多了不想重写，这次BOSS催促，我觉得也需要提高一下，就当是学习呗，于是，重写！

原本不想重写除了以上提到的已经有一些工作量不想推翻外，还有一个原因，这个Framework我不懂啊，一个帮助文档，什么乱七八糟的类都蹦出来了，我各种头晕，一个字，慌~当然，现在写感想写心得的时候，已经拿下了~

Qt Graphics Framework 下次稍微详细介绍一下，Assist翻译一下也没啥意思，写一点如何入门可能比较有用。这里就写写这个小工具实现时遇到的一些问题。
&lt;a href=&quot;http://neversayever.com/wp-content/uploads/2012/01/camo.jpg&quot;&gt;&lt;img class=&quot;aligncenter size-medium wp-image-2057&quot; title=&quot;camo&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/01/camo-289x300.jpg&quot; alt=&quot;&quot; width=&quot;289&quot; height=&quot;300&quot; /&gt;&lt;/a&gt;

根据需要实现的功能，需要3个类，一个斑点spot类，一个关键点keypoint类，一个控制手柄controlhandle类，这是场景里面的物体，外面的窗口继承自QGraphicsView，它里面就是一个用于显示2D物体的场景——QGraphicsScene。3个物体类继承自QGraphicsItem。
&lt;h3&gt;坐标系&lt;/h3&gt;

3个物体有父子关系，首先spot是爷爷辈，keypoint是父亲辈，controlhandle是孙子辈，起先我没想好它们的父子关系，以为也没啥大关系，反正都放在一个场景里面，后来实现到一半就吃了亏了，遇到整个graphic体系的坐标系问题。

外面灰色的正方形是定义了场景的一个rect，其实斑点也可以在这外面显示，但是当缩放之后，窗口四周的滚动条的出现是按这个rect区域来的，外面白的即使你缩放到看不见，它也没有滚动条。这个scene的坐标是在rect的左上角，为（0,0）。朝右为x正方形，朝下为y正方向。

spot既然最大，其坐标原点初始和scene重合，方向也一样，于是用户用鼠标指定的关键点的坐标是在哪个坐标系下的呢？
没错，是scene坐标系下的。

所有的键鼠交互最初响应这个事件的永远是view。
如果没有定义斧子关系，各个物件之间就没有关系，于是移动spot的时候，要想keypoint一起动，你要写些代码。keypoint动的时候，要想controlhandle动，你还要写一些代码。还有缩放呢，还有旋转呢~ @_@

不过这个定义父子关系我也想了一下下的，你想，你直接在构造函数里面写spot(QGraphicsItem* parent)，然后把parent传进去，在类里保存这个指针，你当回事儿，Qt才不当回事儿呢，要做的是在构造函数参数列表先调用其父类的构造函数QGraphicsItem(parent)，搞定。

父亲移动，儿子会跟着一起移动。说白了，就是坐标系一起变换，相对位置不变。Qt给你都弄好了。

根据用户指定的关键点生成spot的路径我是经过变换的，将原点translate到了spot中心，以后旋转比较像那么回事了。
于是在spot下面生成的控制点坐标要相应变换成本地坐标系下的。
接着生成keypoint item，其本地坐标系原点在关键点位置，用mapFromScene或者MapFromParent（如果前面已经将所有点变换到spot坐标系下的话）
接着在keypoint里面生成controlhandle，控制点要变成controlhandle本地坐标，好在handle的原点和keypoint重合，并且不允许controlhandle移动（移动指坐标系和keypoint坐标系产生偏移，控制手柄本身可以改变形状）。
上图里面十字便是我测试用的显示它们原点位置的。包括spot的和keypoint的。

&lt;h3&gt;键鼠事件&lt;/h3&gt;

最初接收是在QGraphicsView下，然后，按照z值大小从上往下传递，这里z值，controlhandle是1，keypoint是0.5，spot是0，background以后可以设为-1。
要往下传递，重载键鼠事件的函数后，在函数最后要加一句类似
&lt;pre class=&quot;brush:cpp&quot;&gt;
QGraphicsView::contextMenuEvent(event);
&lt;/pre&gt;
右键菜单我想点在空白处有一个菜单，点在spot有另一个菜单怎么办？
在view下重载的contextMenuEvent中加入判断，当前鼠标位置所在item是不是spot item，点到keypoint上我不管，我只管是不是点在spot上。
qgraphicsitem_cast(要判断的类)，我使用这句话判断的，这是一个转换QGraphicsItem的专用cast，能转过来，你就获得了那个类型的指针，不能转过来，返回0。

另外，QPainterPath是一个很强大的类，各种你需要的曲线操作都有，曲线游走：PointAtPercent(qreal )，百分比获得曲线上的点。slopeAtPercent(qreal)，获得某个点上的斜率。contains()判断某个点是否在曲线里面，注意path的contains不是指一个点是不是在曲线上，而是在曲线包围的area里面，如果不闭合，Qt自动将首点和末点连线产生需要的闭合区域。

斑点可以做体积碰撞检测，你需要先定义好这个形状的boundingRect()，shpe()，Rect是形状外的能包含整个形状的矩形范围，shape是指围绕形状的一条QPainterPath，更精确，当你setFlag(ItemClipsToShape)，后，鼠标响应就会精确到这条shape曲线里面。

移动一个Item，它的位置在局部坐标系下不变，变的是其在parent或scene下的坐标。
缩放一个item，其整个坐标系进行缩放，item相对局部坐标系仍然不变。

新建一个item，如何让局部坐标原点在这个item中心？
&lt;ol&gt;
	&lt;li&gt;将使用scene坐标系，从鼠标事件获得的点的信息构成item形状。&lt;/li&gt;
	&lt;li&gt;从item的path获得boundingRect，从中获得item形状的中心点位置。&lt;/li&gt;
	&lt;li&gt;将item的path（即形状）用translate反向移动boundingRect.center距离。&lt;/li&gt;
	&lt;li&gt;至此，item为一个围绕局部坐标原点的形状&lt;/li&gt;
	&lt;li&gt;用setPos，将item移到场景下原位置。&lt;/li&gt;
&lt;/ol&gt;
新生成的item，其局部坐标系原点与其父亲坐标系原点重合。

要形成自定义item的父子关系，最好在构造函数初始化列表里面先调用父类构造函数QGraphicsItem(parent)

父亲移动，儿子会跟着一起移动。

儿子会自动添加到父亲所在的scene。&lt;img src=&quot;http://www1.feedsky.com/t1/608100863/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100863/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>QGraphicsItem</category><category>Qt Graphics Framework</category><category>QPainterPath</category><category>QGraphicsScene</category><category>Qt</category><pubDate>Thu, 12 Jan 2012 21:31:17 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/01/2056/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2056</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/01/2056/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/608100863/6973417</fs:itemid></item><item><title>Qt itemview中delegate的用法</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100864/6973417/1/item.html</link><wfw:commentRss>http://neversayever.com/blog/2012/01/2046/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>Qt中当用到QTreeView和QTableView等用于显示item的视图时，你要编辑一个item用到的编辑工具可能是除了默认文字编辑lineEdit以外的工具，例如button，spinBox，甚至Slider，很有可能是自定义的widget，比如自己写一个用于打开文件的item，你可能会新建一个widget，里面封装一个lineEdit用于显示打开文件的文件名，后面添加一个button，用来打开一个dialog窗口，使用QHBoxLayout布局，分配好长宽比例。

看了Qt Demos里面一个用spinbox的例子，讲了几个最基本的用法。我总结了一下从这个例子学到的：
&lt;ol&gt;
	&lt;li&gt;自定义的delegate继承自QItemDelegate。&lt;/li&gt;
	&lt;li&gt;需要重载的一些函数：&lt;/li&gt;
&lt;pre class=&quot;brush:cpp&quot;&gt;
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &amp;#38;option,const QModelIndex &amp;#38;index) const;
void setEditorData(QWidget *editor, const QModelIndex &amp;#38;index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &amp;#38;index) const;
void updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &amp;#38;option, const QModelIndex &amp;#38;index) const;
&lt;/pre&gt;
	&lt;li&gt;在createEditor创建自定义widget并返回之。&lt;/li&gt;
	&lt;li&gt;setEditorData是将model中当前有的数据设置到代理上。自己从model取出数据，自己setValue到editor上。&lt;/li&gt;
	&lt;li&gt;setModelData是将editor上的数据保存到Model中。&lt;/li&gt;
	&lt;li&gt;updateEditorGeometry就是将editor设置到一定位置，并且有一定大小，使这个editor看起来像是正好嵌入到格子里面一样。用的是option.rect。&lt;/li&gt;
	&lt;li&gt;其他地方用到的函数是setModel()，setItemDelegate()。&lt;/li&gt;
&lt;/ol&gt;

自从Qt4.4，出现了两个delegate基类，&lt;strong&gt;&lt;a href=&quot;http://doc.qt.nokia.com/4.7-snapshot/qstyleditemdelegate.html&quot; target=&quot;_blank&quot;&gt;QStyledItemDelegate&lt;/a&gt;&lt;/strong&gt; vs. &lt;strong&gt;&lt;a href=&quot;http://doc.qt.nokia.com/4.7-snapshot/qitemdelegate.html&quot; target=&quot;_blank&quot;&gt;QItemDelegate&lt;/a&gt;&lt;/strong&gt;。默认的delegate是QStyledItemDelegate，即你不自己写delegate的时候，默认那个lineEdit是来自QStyledItemDelegate。Qt Assist建议用户如果自定义delegate或者用到了Qt style sheets的话，最好继承自QStyledItemDelegate，为什么呢？首先这两个类在绘制代理和为item提供编辑器上面是独立的，没什么联系，互不影响；不同的是QStyledItemDelegate使用当前style来绘制item（的代理），即如果程序设置了总体的风格（用QSS或其他定义方式），QStyledItemDelegate会使用这个风格设置。

Q1：如果我用的是QTreeWidget，而不是QTreeView呢？
A：事实证明你都不用setModel()了。oyeah~

Q2:如何让特定的item使用特定的delegate呢？
A：QModelIndex提供item的位置，在createEditor里面判断一下，可以让某一个位置的item用代理，别的无视，也可以为不同位置的item配置不同的代理。&lt;img src=&quot;http://www1.feedsky.com/t1/608100864/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100864/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>delegate</category><category>Qt</category><pubDate>Thu, 12 Jan 2012 20:08:00 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/01/2046/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=2046</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/01/2046/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/608100864/6973417</fs:itemid></item><item><title>WordPress 代码高亮插件</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100865/6973417/1/item.html</link><wfw:commentRss>http://neversayever.com/blog/2012/01/1950/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>WordPress的代码高亮插件我一共用了4种，分别是：WP-CodeBox，SyntaxHighlighter Evolved，auto-syntaxHighlighter，wp-syntax。

选择插件是有条件的：
&lt;ol&gt;
	&lt;li&gt;首先能够高亮的语言要够齐全吧，虽然现在只用到了CPP，保不齐以后用个“撸一把”“抓哇”等等。&lt;/li&gt;
	&lt;li&gt;然后高亮效果要漂亮。&lt;/li&gt;
	&lt;li&gt;接着方便编辑&lt;/li&gt;
	&lt;li&gt;最后一个也算比较重要的一个：RSS输出最好能高亮，不济也得保留着格式吧。&lt;/li&gt;
&lt;/ol&gt;
一个个看：

&lt;strong&gt;&lt;a href=&quot;http://wordpress.org/extend/plugins/wp-codebox/&quot; target=&quot;_blank&quot;&gt;WP-CodeBox&lt;/a&gt;&lt;/strong&gt;

&lt;a href=&quot;http://neversayever.com/wp-content/uploads/2012/01/codebox_test.jpg&quot;&gt;&lt;img class=&quot;aligncenter size-medium wp-image-1951&quot; title=&quot;codebox_test&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/01/codebox_test-300x258.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;258&quot; /&gt;&lt;/a&gt;

&amp;#160;
&lt;ul&gt;
	&lt;li&gt;用的标签是&amp;#60;pre lang=&quot;LANGUAGE&quot;&amp;#62;code here&amp;#60;/pre&amp;#62;。&lt;/li&gt;
	&lt;li&gt;file=&quot;download.txt&quot; 这个标签可以在代码上方显示一个下载链接。&lt;/li&gt;
	&lt;li&gt;line=&quot;N&quot;设置行号。&lt;/li&gt;
	&lt;li&gt;colla=&quot;+/-&quot;设置折叠。&lt;/li&gt;
&lt;/ul&gt;
因为用的标签是&amp;#60;pre&amp;#62;&amp;#60;/pre&amp;#62;，是一种通用的定义格式化文本的标签，被RSS和RSS reader广泛支持，所以不用担心RSS输出一堆字符。界面吧，只能说一般，不过那个可以展开/折叠的小按钮很可爱。支持的代码貌似没有其他3个多。

&lt;a href=&quot;http://wordpress.org/extend/plugins/syntaxhighlighter/&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;SyntaxHighlighter Envolved&lt;/strong&gt;&lt;/a&gt;

&lt;a href=&quot;http://neversayever.com/wp-content/uploads/2012/01/syntaxhighlighter_evolved.jpg&quot;&gt;&lt;img class=&quot;aligncenter size-medium wp-image-1952&quot; title=&quot;syntaxhighlighter_evolved&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/01/syntaxhighlighter_evolved-300x152.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;152&quot; /&gt;&lt;/a&gt;

&amp;#160;

用的标签可以像图中一样[cpp]code here[/cpp]，也可以用[code lang=&quot;js&quot;]这里写你的代码[/code]这样的，不过就是没有&amp;#60;pre&amp;#62;code here&amp;#60;/pre&amp;#62;这样的，人家不支持，我原来用的就是这个插件，结果悲剧了，RSS输出的就是一堆...那啥啊，我都看不下去了。不过自个网站上的效果还不错，人家也支持collapse这些标签折叠代码框。

&lt;strong&gt;&lt;a href=&quot;http://wordpress.org/extend/plugins/wp-syntax/&quot; target=&quot;_blank&quot;&gt;WP-Syntax&lt;/a&gt;&lt;/strong&gt;

&lt;a href=&quot;http://neversayever.com/wp-content/uploads/2012/01/wp_syntax.jpg&quot;&gt;&lt;img class=&quot;aligncenter size-medium wp-image-1953&quot; title=&quot;wp_syntax&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/01/wp_syntax-300x274.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;274&quot; /&gt;&lt;/a&gt;

用的标签是&amp;#60;pre lang=&quot;cpp&quot;&amp;#62;code here&amp;#60;/pre&amp;#62;，它这个代码高亮支持没有行号，据说它是在服务器端直接格式化并高亮好的，所以即使到了RSS这面，它还是高亮了！牛逼！虽然稍稍加重了点服务器的负担，但效果好哇！心动不如行动，听名字感觉还是官方的，兼容应该比较好。支持的语言各种多啊！其实我觉得这个已经很不错了，但是各种尝试以后，我还是用了下面的。挥泪抛弃了你——这RSS也能高亮的NB插件~

&lt;strong&gt;&lt;a href=&quot;http://wordpress.org/extend/plugins/auto-syntaxhighlighter/&quot; target=&quot;_blank&quot;&gt;auto-syntaxhighlighter&lt;/a&gt;&lt;/strong&gt;

为嘛我还是选它了尼，还不是因为哥是菜鸟，具体原因见下图：

&lt;a href=&quot;http://neversayever.com/wp-content/uploads/2012/01/auto_syntaxhighlighter.jpg&quot;&gt;&lt;img class=&quot;aligncenter size-medium wp-image-1954&quot; title=&quot;auto_syntaxhighlighter&quot; src=&quot;http://neversayever.com/wp-content/uploads/2012/01/auto_syntaxhighlighter-300x247.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;247&quot; /&gt;&lt;/a&gt;

&amp;#160;

它带了一个代码编辑器！其实它的标签挺简单的，也就是&amp;#60;pre class=&quot;brush:LANGUAGE&quot;&amp;#62;code here&amp;#60;/pre&amp;#62;

但是有一点比较麻烦，就是代码中的&amp;#60;，&amp;#62;，&amp;#60;&amp;#60;，&amp;#62;&amp;#62;等这些符号你如果直接在HTML编辑器下写需要用转义符替换的，可是我不知道啊，在试了好多次之后，没办法，我投奔了她怀抱。

WordPress的可视化编辑器还是很悲剧的，有时候完全不能按照自己的意愿格式化文字，然后你切换到HTML编辑器，辛辛苦苦把格式换过来，然后切回可视化编辑器，可是，他喵的格式自动又给你变回来了！

另外，auto-SyntaxHighLighter的那个代码输入按钮在可视化编辑器这边~这略微DT...

&amp;#160;&lt;img src=&quot;http://www1.feedsky.com/t1/608100865/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100865/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>WordPress</category><pubDate>Sat, 07 Jan 2012 23:51:41 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/01/1950/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=1950</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/01/1950/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/608100865/6973417</fs:itemid></item><item><title>如何使用glew</title><link>http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100866/6973417/1/item.html</link><wfw:commentRss>http://neversayever.com/blog/2012/01/1935/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>&lt;h3&gt;使用glew&lt;/h3&gt;
glew也是一个扩展库，包含了OpenGL中许多核心及扩展函数，现在的版本是1.7，支持OpenGL4.2，可以到这里下载：&lt;a href=&quot;http://glew.sourceforge.net/&quot;&gt;http://glew.sourceforge.net/&lt;/a&gt;

下载了glew库的话，那么可以直接使用该扩展，但是使用之前首先要确定你的显卡是否支持该扩展。方法如下：

&lt;strong&gt;如何判断显卡所支持的扩展： &lt;/strong&gt;
使用函数glGetString，看一下它的原型：
&lt;pre class=&quot;brush:cpp&quot;&gt;const GLubyte *glGetString( GLenum name );&lt;/pre&gt;
我们以GL_EXTENSIONS为参数调用该函数，就能获得当前显卡所支持的所有扩展，像下面这样:
&lt;pre class=&quot;brush:cpp&quot;&gt;const GLubyte *str = glGetString(GL_EXTENSIONS);
cout&amp;#60;&amp;#60;str&amp;#60;&amp;#60;endl;&lt;/pre&gt;
&lt;ol&gt;
&lt;/ol&gt;&lt;ol&gt;
	&lt;li&gt;包含头文件glew.h，注意这里和上面不同，这回glut.h要放在glew.h的后面了像下面这样：&lt;/li&gt;
&lt;/ol&gt;

&lt;pre class=&quot;brush:cpp&quot;&gt;#include &amp;#60;GL/glew.h&amp;#62;
#include &amp;#60;GL/glut.h&amp;#62;&lt;/pre&gt;
&lt;ol&gt;
&lt;/ol&gt;&lt;ol&gt;
	&lt;li&gt;然后就可以在程序中直接使用glBlendEquation了，其他扩展的判断和使用方法与此类似。&lt;/li&gt;
	&lt;li&gt;最后还有一点切记！那就是还要调用glewInit() ;来初始化一下方可使用扩展，如下：&lt;/li&gt;
&lt;/ol&gt;

&lt;pre class=&quot;brush:cpp&quot;&gt;GLenum err = glewInit();
if (GLEW_OK != err)
{
   MessageBoxA(NULL, &quot;error&quot;, &quot;My Window&quot;, 1);
}&lt;/pre&gt;
&lt;ol&gt;
	&lt;li&gt;在project-&amp;#62;setting中,打开link选项卡,加上glew.lib 或在文件中加上#progmma comment(lib, &quot;glew.lib&quot;)&lt;/li&gt;
&lt;/ol&gt;
好了，现在可以放心使用扩展了，赶快继续你的OpenGL之旅吧！

为了查看显卡到底支持哪些扩展，折腾了好久。
&lt;pre class=&quot;brush:cpp&quot;&gt;#include &amp;#60;iostream&amp;#62;
#include &amp;#60;GL/glew.h&amp;#62;
using namespace std;  

int main()
{
  GLenum err = glewInit();
  if (err != GLEW_OK )
  {
     fprintf(stderr, &quot;Error: %s\n&quot;, glewGetErrorString(err));
    exit (-2);
  }
  int NumberOfExtensions;
  glGetIntegerv(GL_NUM_EXTENSIONS, &amp;#38;NumberOfExtensions);
  for(int i=0; i&amp;#60;NumberOfExtensions; i++)
  {
    const GLubyte *ccc=glGetStringi(GL_EXTENSIONS, i);
    //Now, do something with ccc
    cout &amp;#60;&amp;#60; ccc &amp;#60;&amp;#60; endl;
  }
  system(&quot;pause&quot;);
}&lt;/pre&gt;
这是最初的代码，前面所说的glGetString函数在OpenGL3.0之后废除了，为了使用最新的OpenGL4.2，在官网查到了最新使用方法。

在&lt;strong&gt;link-&amp;#62;input&lt;/strong&gt;中写入glew32.lib，编译报link错误，不认识glGetIntegerv函数，但是在glew.h能发现这个函数。google了好久没发现好的解决方案。不过后来在glew官网&amp;#60;&lt;a href=&quot;http://glew.sourceforge.net/basic.html&quot;&gt;说明链接&lt;/a&gt;&amp;#62;查到了问题所在，使用glew必须有一个opengl context。最简单的方案是用glut创建一个context。增加了2句话后得到结果。
&lt;pre class=&quot;brush:cpp&quot;&gt;#include &amp;#60;iostream&amp;#62;
#include &amp;#60;GL/glew.h&amp;#62;
#include &amp;#60;gl/glut.h&amp;#62;
using namespace std;  

int main()
{
  glutCreateWindow(&quot;GLEW Test&quot;);//get an openGL context
  GLenum err = glewInit();
  if (err != GLEW_OK )
  {
     fprintf(stderr, &quot;Error: %s\n&quot;, glewGetErrorString(err));
    exit (-2);  

  }
  int NumberOfExtensions;
  glGetIntegerv(GL_NUM_EXTENSIONS, &amp;#38;NumberOfExtensions);
  for(int i=0; i&amp;#60;NumberOfExtensions; i++)
  {
    const GLubyte *ccc=glGetStringi(GL_EXTENSIONS, i);
    //Now, do something with ccc
    cout &amp;#60;&amp;#60; ccc &amp;#60;&amp;#60; endl;
  }  

  system(&quot;pause&quot;);
}&lt;/pre&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/608100866/NeverSayEver/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/NeverSayEver/~8854696/608100866/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>OpenGL</category><pubDate>Sat, 07 Jan 2012 21:30:47 +0800</pubDate><author>羽中</author><comments>http://neversayever.com/blog/2012/01/1935/#comments</comments><guid isPermaLink="false">http://neversayever.com/?p=1935</guid><dc:creator>羽中</dc:creator><fs:srclink>http://neversayever.com/blog/2012/01/1935/</fs:srclink><fs:srcfeed>http://www.neversayever.com/feed/</fs:srcfeed><fs:itemid>feedsky/NeverSayEver/~8854696/608100866/6973417</fs:itemid></item></channel></rss>
