Vertex Declarations in OpenGL and DirectX ?

Started by
4 comments, last by xelanoimis 18 years, 1 month ago
Hi, What is the OpenGL echivalent for DirectX9 vertex declarations ? I know that OpenGL can use vertex arrays that are echivalent for vertexbuffers. But how to set vertex declarations, and can it use multiple streams (vertex arrays) ? I want to know this for use with CG effects or vertex programs available for OpenGL. Can anyone give a small code example (not necessarly functional, just curios about the functions used). I am also interested in a platform independent approach to meshes and effects. Can vertex shaders and vertex declarations be wraped in some engine classes to use with both OpenGL and DirectX effects (eventualy CG) ? Thanks
Advertisement
Moved to OpenGL

For the first part of your question you're more likely to get a better answer from the OpenGL experts - they're the guys who know the API best [wink]

AS for an API/platform independent method, yes it's probably possible - but you can't really take it any further until you know what form both API's can use (or require). From there you can either decide whether you want to take a subset approach (basic functionality that both API's can handle) or some higher-level approach that involves work-arounds/emulation for parts of the respective API's that don't natively handle what you want. For example, if you really want streams, but OpenGL can't do that you could (presumably) emulate it by creating your own Input Assembler - not necessarily efficient, but it'd probably work.

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

JollyJeffers,

i can't follow your explanation; so, plesae tell me, what do you mean exactly by the term "subset approach" ?

(do you mean splitting up the rendering-work into more/simple subsets by switching only the vertex-dec.format ?)
Alex BakerComputer science is dealing with computers as much as astronomy is dealing with telescopes.
about the vertex declaration in OpenGL, and multiple streams prepared for an effect, if anyone knows... please post some tips
What it comes down to in OpenGL is that you get to define vertex declarations yourself, and then you get to write the rendering backend code that translates a vertex declaration into BindBuffer and Pointer calls.

It's fairly simple to do. You define an array of structures that have all of the information about the vertex declaration -- what its usage is, what type it is, offset and stream index, etc. Then you loop through that array, calling BindBuffer and pointer as necessary.

I basically have a header that defines stuff for a declaration:
#ifndef _GEOMETRY_H#define _GEOMETRY_H#include "../HoverEngine.h"#include "RendererTypes.h"#include "VertexBuffer.h"#include "IndexBuffer.h"#include <vector>//type of element, i.e. what it specifiesenum VertexElementType{	VET_XYZ,	VET_NORMAL,	VET_DIFFUSE,	VET_SPECULAR,	VET_TEXCOORD,};//'format' of element, basically the data type//it's recommended that you avoid the INT64 types, as well as long doubleenum VertexElementFormat{	VEF_SIGNED_BYTE,	VEF_UNSIGNED_BYTE,	VEF_SIGNED_SHORT,	VEF_UNSIGNED_SHORT,	VEF_UNSIGNED_INT,	VEF_SIGNED_INT,	VEF_UNSIGNED_INT64,	VEF_SIGNED_INT64,	VEF_FLOAT,	VEF_DOUBLE,	VEF_LONG_DOUBLE,};//FVF quick-system#define		FVF_XYZ			0x00000001#define		FVF_NORMAL		0x00000002#define		FVF_DIFFUSE		0x00000004#define		FVF_SPECULAR	0x00000008#define		FVF_TEXTURE0	0x00010000#define		FVF_TEXTURE1	0x00020000#define		FVF_TEXTURE2	0x00040000#define		FVF_TEXTURE3	0x00080000#define		FVF_TEXTURE(X)	(0x00010000 << (X))//specifies a single part of a vertex, e.g. one position, or one texcoord, etc.struct VertexElement{	unsigned int Stream;	unsigned int Count;	std::size_t Offset;		//offset in the structure	VertexElementFormat Format;	VertexElementType Type;	//normal ctor	VertexElement() : Stream( 0 ), Count( 0 ), Format( VEF_FLOAT ), 		Type( VET_XYZ ), Offset( 0 )	{ }	//inline ctor for laziness	VertexElement( unsigned int vStream, unsigned int vCount, std::size_t vOffset, 		VertexElementFormat vFormat, VertexElementType vType )		: Stream( vStream ), Count( vCount ), Format( vFormat), Type( vType ),		Offset( vOffset )	{ }	static std::size_t FormatSize( VertexElementFormat vef );	//Compute the size of this element in bytes	std::size_t SizeBytes() { return FormatSize( Format ) * Count; }};//specifies a complete vertex, basically just a list of elementsstruct VertexDeclaration{	typedef std::vector<VertexElement> ElementList;	typedef ElementList::iterator Iterator;	ElementList Elements;	VertexDeclaration()	{		Elements.reserve( 4 );	}	static VertexDeclaration CreateFromFVF( unsigned int FVF );};//in D3D, streams will correspond to real streams//in OGL, the streams will be somewhat virtualised, but effectively the same#define MAX_VERTEX_STREAMS	8//holds all the data for a single streamstruct StreamSource{	VertexBuffer* Source;	std::size_t Offset;	std::size_t Stride;	StreamSource() : Source( NULL ), Offset( 0 ), Stride( 0 )	{ }};//holds everything geometric about an objectclass Geometry{protected:	VertexDeclaration	m_Decl;	RenderMode			m_Mode;	std::size_t			m_PrimitiveCount;	std::size_t			m_IndexCount;	StreamSource		m_Streams[MAX_VERTEX_STREAMS];	IndexBuffer*		m_Indices;	//if IB is NULL, use non-indexed primitive	std::size_t			m_IndexOffset;	std::size_t			m_FirstVertex;	std::size_t			m_NumVertices;public:	Geometry();	virtual ~Geometry();	//Sets the rendering mode and primitive count for this geom	void				SetRenderMode( RenderMode Mode, std::size_t IndexCount );	//Sets the vertex buffer for the specified stream	void				SetStreamSource( unsigned int Stream, VertexBuffer* Source, std::size_t Offset, std::size_t Stride );	//Sets the indices for this geom (NULL for no indexing -- Offset is used for VB)	void				SetIndices( IndexBuffer* Indices, std::size_t Offset );	//Sets the range of vertex used by the indices (ignored if not using indices)	void				SetRange( std::size_t First, std::size_t Count );	//used to access the vertex declaration	VertexDeclaration&	Decl() { return m_Decl; }	//access the streams	StreamSource*		Stream( unsigned int Idx ) { assert( Idx < MAX_VERTEX_STREAMS ); return &m_Streams[Idx]; }	//access the indices	IndexBuffer*		Indices() { return m_Indices; }	//index buffer offset	std::size_t			IndexOffset() const { return m_IndexOffset; }	//Primitive count	std::size_t			PrimitiveCount() const { return m_PrimitiveCount; }	std::size_t			IndexCount() const { return m_IndexCount; }	//render mode for this geom	RenderMode			Mode() const { return m_Mode; }	//Get the index range	void				GetRange( std::size_t& First, std::size_t& Count ) const { First = m_FirstVertex; Count = m_NumVertices; }};#endif

And then the function to parse this into OpenGL goes like this:
void OGLRenderer::BeginRender( Geometry* Geom ){	if( m_RenderBegun )		return;	if( Geom == NULL )		return;	//keeps track of tex coord sets in use	unsigned int TexCoord = 0;	//first, get the Geom's declaration and set stuff up	VertexDeclaration::Iterator it = Geom->Decl().Elements.begin();	while( it != Geom->Decl().Elements.end() )	{		if( m_CurrentVB != Geom->Stream( it->Stream )->Source )		{			m_CurrentVB = down_cast<OGLVertexBuffer*>( Geom->Stream( it->Stream )->Source );			if( m_CurrentVB != NULL )			{				m_CurrentVB->Bind();			}			else if( GLEE_ARB_vertex_buffer_object )			{				glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );			}		}		//initialize the pointers for this element		GLsizei Stride = (GLsizei) Geom->Stream( it->Stream )->Stride;		GLsizei StreamOffset = (GLsizei) Geom->Stream( it->Stream)->Offset;		switch( it->Type )		{		case VET_XYZ:			glEnableClientState( GL_VERTEX_ARRAY );			glVertexPointer( it->Count, TranslateVertexFormat( it->Format ), Stride, m_CurrentVB->GetPointer() + it->Offset + StreamOffset );			break;		case VET_NORMAL:			glEnableClientState( GL_NORMAL_ARRAY );			glNormalPointer( TranslateVertexFormat( it->Format ), Stride, m_CurrentVB->GetPointer() + it->Offset + StreamOffset );			break;		case VET_DIFFUSE:			glEnableClientState( GL_COLOR_ARRAY );			glColorPointer( it->Count, TranslateVertexFormat( it->Format ), Stride, m_CurrentVB->GetPointer() + it->Offset + StreamOffset );			break;		case VET_SPECULAR:			glEnableClientState( GL_SECONDARY_COLOR_ARRAY );			glSecondaryColorPointer( it->Count, TranslateVertexFormat( it->Format ), Stride, m_CurrentVB->GetPointer() + it->Offset + StreamOffset );			break;		case VET_TEXCOORD:			glClientActiveTexture( GL_TEXTURE0 + TexCoord );			glEnableClientState( GL_TEXTURE_COORD_ARRAY );			glTexCoordPointer( it->Count, TranslateVertexFormat( it->Format ), Stride, m_CurrentVB->GetPointer() + it->Offset + StreamOffset );			++TexCoord;			break;		}		++it;	}	//set up indices if we have any	if( m_Indices != Geom->Indices() )	{		m_Indices = down_cast<OGLIndexBuffer*>( Geom->Indices() );		if( m_Indices != NULL )		{			m_Indices->Bind();		}		else if( GLEE_ARB_vertex_buffer_object )		{			glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, NULL );		}	}	m_RenderBegun = true;	m_CurGeom = Geom;}

(Note: This appears to be an older version of my source. The newer version has some modifications that allow arbitrary VertexElementTypes, which is useful for shader stuff.)
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Thanks, this was exactly what I needed.

This topic is closed to new replies.

Advertisement