Beispiel #1
0
void CMaterialViewer::Draw2D()
{
	guard(CMaterialViewer::Draw2D);
	CObjectViewer::Draw2D();

	if (IsTexture && ShowChannels)
	{
		UUnrealMaterial *Mat = static_cast<UUnrealMaterial*>(Object);
		Mat->SetMaterial();
		int width, height;
		Window->GetWindowSize(width, height);
		int w = min(width, height) / 2;
		for (int i = 0; i < 4; i++)
		{
			int x0 =  (i       & 1) * w;
			int y0 = ((i >> 1) & 1) * w;
			static const CVec3 colors[4] =
			{
				{ 1, 1, 1 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }	// normal, red, green, blue
			};
			glColor3fv(colors[i].v);
			glBegin(GL_QUADS);
			glTexCoord2f(1, 0);
			glVertex2f(x0+w, y0);
			glTexCoord2f(0, 0);
			glVertex2f(x0, y0);
			glTexCoord2f(0, 1);
			glVertex2f(x0, y0+w);
			glTexCoord2f(1, 1);
			glVertex2f(x0+w, y0+w);
			glEnd();
		}
	}
Beispiel #2
0
void CStatMeshInstance::Draw(unsigned flags)
{
	guard(CStatMeshInstance::Draw);
	int i;

	if (!pMesh->Lods.Num()) return;

	/*const*/ CStaticMeshLod& Mesh = pMesh->Lods[LodNum];	//?? not 'const' because of BuildTangents(); change this?
	int NumSections = Mesh.Sections.Num();
	if (!NumSections || !Mesh.NumVerts) return;

//	if (!Mesh.HasNormals)  Mesh.BuildNormals();
	if (!Mesh.HasTangents) Mesh.BuildTangents();

	// copy of CSkelMeshInstance::Draw sorting code
#if SORT_BY_OPACITY
	// sort sections by material opacity
	int SectionMap[MAX_MESHMATERIALS];
	int secPlace = 0;
	for (int opacity = 0; opacity < 2; opacity++)
	{
		for (i = 0; i < NumSections; i++)
		{
			UUnrealMaterial *Mat = Mesh.Sections[i].Material;
			int op = 0;			// sort value
			if (Mat && Mat->IsTranslucent()) op = 1;
			if (op == opacity) SectionMap[secPlace++] = i;
		}
	}
	assert(secPlace == NumSections);
#endif // SORT_BY_OPACITY

	// draw mesh
	glEnable(GL_LIGHTING);

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);

	glVertexPointer(3, GL_FLOAT, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Position);
	glNormalPointer(GL_FLOAT, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Normal);
	glTexCoordPointer(2, GL_FLOAT, sizeof(CStaticMeshVertex), &Mesh.Verts[0].UV[UVIndex].U);

	/*??
		Can move tangent/binormal setup here too, but this will require to force shader to use fixed attribute locations
		(use glBindAttribLocation before glLinkProgram instead of querying atttribute via glGetAtribLocation).
		In this case:
		- can remove GCurrentShader
		- can eliminate hasTangent checks below and always bind attributes (when supports GL2.0)
		- can share code between SkeletalMesh and StaticMesh:
		  - sort sections
		  - setup arrays; differences:
		    - position and normals are taken from different arrays in static and skeletal meshes
		    - ShowInfluences in SkeletalMeshInstance should disable material binding
		  - draw sections using glDrawElements()
		  - un-setup arrays
		  - use VAO+VBO for rendering
	*/

	for (i = 0; i < NumSections; i++)
	{
#if SORT_BY_OPACITY
		int MaterialIndex = SectionMap[i];
#else
		int MaterialIndex = i;
#endif
		const CMeshSection &Sec = Mesh.Sections[MaterialIndex];
		if (!Sec.NumFaces) continue;

		SetMaterial(Sec.Material, MaterialIndex);

		// check tangent space
		GLint aTangent = -1, aBinormal = -1;
		bool hasTangent = false;
		const CShader *Sh = GCurrentShader;
		if (Sh)
		{
			aTangent   = Sh->GetAttrib("tangent");
			aBinormal  = Sh->GetAttrib("binormal");
			hasTangent = (aTangent >= 0 && aBinormal >= 0);
		}
		if (hasTangent)
		{
			glEnableVertexAttribArray(aTangent);
			glEnableVertexAttribArray(aBinormal);
			glVertexAttribPointer(aTangent,  3, GL_FLOAT, GL_FALSE, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Tangent);
			glVertexAttribPointer(aBinormal, 3, GL_FLOAT, GL_FALSE, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Binormal);
		}
		// draw
		//?? place this code into CIndexBuffer?
		if (Mesh.Indices.Is32Bit())
			glDrawElements(GL_TRIANGLES, Sec.NumFaces * 3, GL_UNSIGNED_INT, &Mesh.Indices.Indices32[Sec.FirstIndex]);
		else
			glDrawElements(GL_TRIANGLES, Sec.NumFaces * 3, GL_UNSIGNED_SHORT, &Mesh.Indices.Indices16[Sec.FirstIndex]);

		// disable tangents
		if (hasTangent)
		{
			glDisableVertexAttribArray(aTangent);
			glDisableVertexAttribArray(aBinormal);
		}
	}

	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_NORMAL_ARRAY);

	glDisable(GL_LIGHTING);
	BindDefaultMaterial(true);

	// draw mesh normals
	if (flags & DF_SHOW_NORMALS)
	{
		int NumVerts = Mesh.NumVerts;
		glBegin(GL_LINES);
		glColor3f(0.5, 1, 0);
		for (i = 0; i < NumVerts; i++)
		{
			glVertex3fv(Mesh.Verts[i].Position.v);
			CVec3 tmp;
			VectorMA(Mesh.Verts[i].Position, 2, Mesh.Verts[i].Normal, tmp);
			glVertex3fv(tmp.v);
		}
#if SHOW_TANGENTS
		glColor3f(0, 0.5f, 1);
		for (i = 0; i < NumVerts; i++)
		{
			const CVec3 &v = Mesh.Verts[i].Position;
			glVertex3fv(v.v);
			CVec3 tmp;
			VectorMA(v, 2, Mesh.Verts[i].Tangent, tmp);
			glVertex3fv(tmp.v);
		}
		glColor3f(1, 0, 0.5f);
		for (i = 0; i < NumVerts; i++)
		{
			const CVec3 &v = Mesh.Verts[i].Position;
			glVertex3fv(v.v);
			CVec3 tmp;
			VectorMA(v, 2, Mesh.Verts[i].Binormal, tmp);
			glVertex3fv(tmp.v);
		}
#endif // SHOW_TANGENTS
		glEnd();
	}

	unguard;
}
Beispiel #3
0
void CMaterialViewer::Draw3D(float TimeDelta)
{
	if (IsTexture && ShowChannels) return;

	static const CVec3 origin = { -150, 100, 100 };
//	static const CVec3 origin = { -150, 50, 50 };
	CVec3 lightPosV;
	viewAxis.UnTransformVector(origin, lightPosV);

#if 0
	// show light source
	glDisable(GL_LIGHTING);
	BindDefaultMaterial(true);
	glBegin(GL_LINES);
	glColor3f(1, 0, 0);
	CVec3 tmp;
	tmp = lightPosV;
	tmp[0] -= 20; glVertex3fv(tmp.v); tmp[0] += 40; glVertex3fv(tmp.v);
	tmp = lightPosV;
	tmp[1] -= 20; glVertex3fv(tmp.v); tmp[1] += 40; glVertex3fv(tmp.v);
	tmp = lightPosV;
	tmp[2] -= 20; glVertex3fv(tmp.v); tmp[2] += 40; glVertex3fv(tmp.v);
	glEnd();
#endif

	glColor3f(1, 1, 1);

	if (!IsTexture)
	{
		glEnable(GL_LIGHTING);	// no lighting for textures
		float lightPos[4];
		lightPos[0] = lightPosV[0];
		lightPos[1] = lightPosV[1];
		lightPos[2] = lightPosV[2];
		lightPos[3] = 0;
		glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
//		glMaterialf(GL_FRONT, GL_SHININESS, 20);
	}

	// bind material
	UUnrealMaterial *Mat = static_cast<UUnrealMaterial*>(Object);
	Mat->SetMaterial();

	// check tangent space
	GLint aNormal = -1;
	GLint aTangent = -1;
//	GLint aBinormal = -1;
	const CShader *Sh = GCurrentShader;
	if (Sh)
	{
		aNormal    = Sh->GetAttrib("normal");
		aTangent   = Sh->GetAttrib("tangent");
//		aBinormal  = Sh->GetAttrib("binormal");
	}

	// and draw box ...
#define A 100
// vertex
#define V000 {-A, -A, -A}
#define V001 {-A, -A,  A}
#define V010 {-A,  A, -A}
#define V011 {-A,  A,  A}
#define V100 { A, -A, -A}
#define V101 { A, -A,  A}
#define V110 { A,  A, -A}
#define V111 { A,  A,  A}
	static const CVec3 box[] =
	{
		V001, V000, V010, V011,		// near   (x=-A)
		V111, V110,	V100, V101,		// far    (x=+A)
		V101, V100, V000, V001,		// left   (y=-A)
		V011, V010, V110, V111,		// right  (y=+A)
		V010, V000, V100, V110,		// bottom (z=-A)
		V001, V011, V111, V101,		// top    (z=+A)
#undef A
	};
#define REP4(...)	{__VA_ARGS__},{__VA_ARGS__},{__VA_ARGS__},{__VA_ARGS__}
	static const CVec4 normal[] =
	{
		REP4(-1, 0, 0, 1 ),
		REP4( 1, 0, 0, 1 ),
		REP4( 0,-1, 0, 1 ),
		REP4( 0, 1, 0, 1 ),
		REP4( 0, 0,-1, 1 ),
		REP4( 0, 0, 1, 1 )
	};
	static const CVec3 tangent[] =
	{
		REP4( 0,-1, 0 ),
		REP4( 0, 1, 0 ),
		REP4( 1, 0, 0 ),
		REP4(-1, 0, 0 ),
		REP4( 1, 0, 0 ),
		REP4(-1, 0, 0 )
	};
//	static const CVec3 binormal[] =
//	{
//		REP4( 0, 0, 1 ),
//		REP4( 0, 0, 1 ),
//		REP4( 0, 0, 1 ),
//		REP4( 0, 0, 1 ),
//		REP4( 0,-1, 0 ),
//		REP4( 0,-1, 0 )
//	};
#undef REP4
	static const float tex[][2] =
	{
		{0, 0}, {0, 1}, {1, 1}, {1, 0},
		{0, 0}, {0, 1}, {1, 1}, {1, 0},
		{0, 0}, {0, 1}, {1, 1}, {1, 0},
		{0, 0}, {0, 1}, {1, 1}, {1, 0},
		{0, 0}, {0, 1}, {1, 1}, {1, 0},
		{0, 0}, {0, 1}, {1, 1}, {1, 0}
	};
	static const int inds[] =
	{
		 0, 1, 2, 3,
		 4, 5, 6, 7,
		 8, 9,10,11,
		12,13,14,15,
		16,17,18,19,
		20,21,22,23
	};

#if 0
	// verify tangents, should be suitable for binormal computation in shaders
	// (note: we're not verifying correspondence with UV coordinates)
	for (int i = 0; i < 24; i++)
	{
		CVec4 n4 = normal[i];
		CVec3 n = n4.ToVec3();
		CVec3 t = tangent[i];
		CVec3 b = binormal[i];
		CVec3 b2;
		cross(n, t, b2);
		VectorScale(b2, n4[3], b2);
		float dd = VectorDistance(b2, b);
		if (dd > 0.001f) appPrintf("dist[%d] = %g\n", i, dd);
	}
#endif

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);

	glVertexPointer(3, GL_FLOAT, sizeof(CVec3), box);
	glNormalPointer(GL_FLOAT, sizeof(CVec4), normal);
	glTexCoordPointer(2, GL_FLOAT, 0, tex);

	if (aNormal >= 0)
	{
		glEnableVertexAttribArray(aNormal);
		// send 4 components to decode binormal in shader
		glVertexAttribPointer(aNormal, 4, GL_FLOAT, GL_FALSE, sizeof(CVec4), normal);
	}
	if (aTangent >= 0)
	{
		glEnableVertexAttribArray(aTangent);
		glVertexAttribPointer(aTangent,  3, GL_FLOAT, GL_FALSE, sizeof(CVec3), tangent);
	}
//	if (aBinormal >= 0)
//	{
//		glEnableVertexAttribArray(aBinormal);
//		glVertexAttribPointer(aBinormal, 3, GL_FLOAT, GL_FALSE, sizeof(CVec3), binormal);
//	}

	glDrawElements(GL_QUADS, ARRAY_COUNT(inds), GL_UNSIGNED_INT, inds);

	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_NORMAL_ARRAY);
	// disable tangents
	if (aNormal >= 0)
		glDisableVertexAttribArray(aNormal);
	if (aTangent >= 0)
		glDisableVertexAttribArray(aTangent);
//	if (aBinormal >= 0)
//		glDisableVertexAttribArray(aBinormal);

	BindDefaultMaterial(true);

#if 0
	glBegin(GL_LINES);
	glColor3f(0.2, 0.2, 1);
	for (int i = 0; i < ARRAY_COUNT(box); i++)
	{
		glVertex3fv(box[i].v);
		CVec3 tmp;
		VectorMA(box[i], 20, normal[i], tmp);
		glVertex3fv(tmp.v);
	}
	glEnd();
	glColor3f(1, 1, 1);
#endif
}
void CStatMeshInstance::Draw(unsigned flags)
{
	guard(CStatMeshInstance::Draw);
	int i;

	if (!pMesh->Lods.Num()) return;

	/*const*/ CStaticMeshLod& Mesh = pMesh->Lods[LodNum];	//?? not 'const' because of BuildTangents(); change this?
	int NumSections = Mesh.Sections.Num();
	if (!NumSections || !Mesh.NumVerts) return;

//	if (!Mesh.HasNormals)  Mesh.BuildNormals();
	if (!Mesh.HasTangents) Mesh.BuildTangents();

	// copy of CSkelMeshInstance::Draw sorting code
#if SORT_BY_OPACITY
	// sort sections by material opacity
	int SectionMap[MAX_MESHMATERIALS];
	int secPlace = 0;
	for (int opacity = 0; opacity < 2; opacity++)
	{
		for (i = 0; i < NumSections; i++)
		{
			UUnrealMaterial *Mat = Mesh.Sections[i].Material;
			int op = 0;			// sort value
			if (Mat && Mat->IsTranslucent()) op = 1;
			if (op == opacity) SectionMap[secPlace++] = i;
		}
	}
	assert(secPlace == NumSections);
#endif // SORT_BY_OPACITY

	// draw mesh
	glEnable(GL_LIGHTING);

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);

	glVertexPointer(3, GL_FLOAT, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Position);
	glNormalPointer(GL_BYTE, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Normal);
	if (UVIndex == 0)
	{
		glTexCoordPointer(2, GL_FLOAT, sizeof(CStaticMeshVertex), &Mesh.Verts[0].UV.U);
	}
	else
	{
		glTexCoordPointer(2, GL_FLOAT, sizeof(CMeshUVFloat), &Mesh.ExtraUV[UVIndex-1][0].U);
	}

	/*??
		Can move tangent/binormal setup here too, but this will require to force shader to use fixed attribute locations
		(use glBindAttribLocation before glLinkProgram instead of querying atttribute via glGetAtribLocation).
		In this case:
		- can remove GCurrentShader
		- can eliminate hasTangent checks below and always bind attributes (when supports GL2.0)
		- can share code between SkeletalMesh and StaticMesh:
		  - sort sections
		  - setup arrays; differences:
		    - position and normals are taken from different arrays in static and skeletal meshes
		    - ShowInfluences in SkeletalMeshInstance should disable material binding
		  - draw sections using glDrawElements()
		  - un-setup arrays
		  - use VAO+VBO for rendering
	*/

	for (i = 0; i < NumSections; i++)
	{
#if SORT_BY_OPACITY
		int MaterialIndex = SectionMap[i];
#else
		int MaterialIndex = i;
#endif
		const CMeshSection &Sec = Mesh.Sections[MaterialIndex];
		if (!Sec.NumFaces) continue;

		SetMaterial(Sec.Material, MaterialIndex);

		// check tangent space
		GLint aNormal = -1;
		GLint aTangent = -1;
//		GLint aBinormal = -1;
		const CShader *Sh = GCurrentShader;
		if (Sh)
		{
			aNormal    = Sh->GetAttrib("normal");
			aTangent   = Sh->GetAttrib("tangent");
//			aBinormal  = Sh->GetAttrib("binormal");
		}
		if (aNormal >= 0)
		{
			glEnableVertexAttribArray(aNormal);
			// send 4 components to decode binormal in shader
			glVertexAttribPointer(aNormal, 4, GL_BYTE, GL_FALSE, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Normal);
		}
		if (aTangent >= 0)
		{
			glEnableVertexAttribArray(aTangent);
			glVertexAttribPointer(aTangent, 3, GL_BYTE, GL_FALSE, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Tangent);
		}
/*		if (aBinormal >= 0)
		{
			glEnableVertexAttribArray(aBinormal);
			glVertexAttribPointer(aBinormal, 3, GL_BYTE, GL_FALSE, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Binormal);
		} */
		// draw
		//?? place this code into CIndexBuffer?
		if (Mesh.Indices.Is32Bit())
			glDrawElements(GL_TRIANGLES, Sec.NumFaces * 3, GL_UNSIGNED_INT, &Mesh.Indices.Indices32[Sec.FirstIndex]);
		else
			glDrawElements(GL_TRIANGLES, Sec.NumFaces * 3, GL_UNSIGNED_SHORT, &Mesh.Indices.Indices16[Sec.FirstIndex]);

		// disable tangents
		if (aNormal >= 0)
			glDisableVertexAttribArray(aNormal);
		if (aTangent >= 0)
			glDisableVertexAttribArray(aTangent);
//		if (aBinormal >= 0)
//			glDisableVertexAttribArray(aBinormal);
	}

	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_NORMAL_ARRAY);

	glDisable(GL_LIGHTING);
	BindDefaultMaterial(true);

	// draw mesh normals
	if (flags & DF_SHOW_NORMALS)
	{
		//!! TODO: performance issues when displaying a large mesh (1M+ triangles) with normals/tangents.
		//!! Possible solution:
		//!! 1. use vertex buffer for normals, use single draw call
		//!! 2. cache normal data between render frames
		//!! 3. DecodeTangents() will do Unpack() for normal and tangent too, so this work is duplicated here
		int NumVerts = Mesh.NumVerts;
		glBegin(GL_LINES);
		glColor3f(0.5, 1, 0);
		CVecT tmp, unpacked;
		const float VisualLength = 2.0f;
		for (i = 0; i < NumVerts; i++)
		{
			glVertex3fv(Mesh.Verts[i].Position.v);
			Unpack(unpacked, Mesh.Verts[i].Normal);
			VectorMA(Mesh.Verts[i].Position, VisualLength, unpacked, tmp);
			glVertex3fv(tmp.v);
		}
#if SHOW_TANGENTS
		glColor3f(0, 0.5f, 1);
		for (i = 0; i < NumVerts; i++)
		{
			const CVec3 &v = Mesh.Verts[i].Position;
			glVertex3fv(v.v);
			Unpack(unpacked, Mesh.Verts[i].Tangent);
			VectorMA(v, VisualLength, unpacked, tmp);
			glVertex3fv(tmp.v);
		}
		glColor3f(1, 0, 0.5f);
		for (i = 0; i < NumVerts; i++)
		{
			const CMeshVertex& vert = Mesh.Verts[i];
			// decode binormal
			CVecT normal, tangent, binormal;
			vert.DecodeTangents(normal, tangent, binormal);
			// render
			const CVecT &v = vert.Position;
			glVertex3fv(v.v);
			VectorMA(v, VisualLength, binormal, tmp);
			glVertex3fv(tmp.v);
		}
#endif // SHOW_TANGENTS
		glEnd();
	}

	unguard;
}