Skip to main content
gamedev.net
🔒 Locked

DirectX-based OGL implementation?

Started by smitty1276 Aug 29, 2006 at 8:12 AM 9 replies 1.4k views
Original Post
smitty1276
smitty1276
I know this approaches heresy, to some [grin], but I'm wondering if anyone knows of an implementation of basic OGL (simple matrix and primitive drawing ops, lots of lines, etc) that actually uses DirectX to render (similar to what Vista was going to do). If your wondering, I have a very, very large codebase in GL, but almost everything it does is lines and that sort of thing. I'd like to be able to use it in a DX app without rewriting tens of thousands of lines of gl calls.
Mushu
Mushu
Wait, so you're looking for a wrapper which converts OpenGL calls to their D3D equivalents? [wow]

This was the most related thing Google turned up; would only be helpful if you wanted to write the wrapper yourself though :P
smitty1276
smitty1276
Quote:
Original post by Mushu
Wait, so you're looking for a wrapper which converts OpenGL calls to their D3D equivalents? [wow]


Yes. [embarrass]

It is a very, very, large codebase, but doesn't do anything too complicated. It probably does occasionally manipulates the viewport, pushes/pops the matrix stack, does some translating and rotation... lots of ortho stuff with many lines.

I can't talk too much about it, unfortunately, but it's used to render the avionics on a digital display in a cockpit. It's very big and complicated, so I don't want to have to recode it. The drawing is very unfortunately tightly coupled with the logic, so it would essentially be a rewrite (which is out of the question).

I thought about coding it myself, but I thought that someone here may know of a decent one. I'll check out that link, thanks!
Promit
Promit
Ehm. I guess I wrote the linked article.

I've written a much better version of that code since. The current one is much faster, and costs very little apart from the repeated function calls. It's in MDX rather than native D3D, but a backport to C++ should be trivial. It's not complex code.
using System;using System.Collections.Generic;using System.Runtime.InteropServices;using Microsoft.DirectX;using Microsoft.DirectX.Direct3D;using Microsoft.DirectX.Generic;namespace Inductor{	internal class VertexStreamer : IDisposable	{		[StructLayout( LayoutKind.Sequential, Pack = 4 )]		private struct VertexData		{			public float X, Y, Z;			public float Nx, Ny, Nz;			public int ColorValue;			public float U, V;			public const VertexFormats Format = VertexFormats.PositionNormal | VertexFormats.Diffuse | VertexFormats.Texture1;			public static int StrideSize			{				get { return Marshal.SizeOf( typeof( VertexData ) ); }			}		};		private Device m_Device;		private VertexBuffer m_Vb;		private VertexData[] m_Vertices;		private bool m_Rendering = false;		private PrimitiveType m_PrimitiveType = PrimitiveType.PointList;		private int m_VertexCount;		public VertexStreamer( Device device )			: this( device, 3000 )		{ }		public VertexStreamer( Device device, int bufferSize )		{			if( device == null )				throw new ArgumentNullException( "device" );			if( bufferSize < 3 )				throw new ArgumentOutOfRangeException( "initialSize", bufferSize, "Buffer size must be at least 3." );			m_Vertices = new VertexData[bufferSize];			m_Device = device;			m_Vb = new VertexBuffer( device, bufferSize * VertexData.StrideSize, Usage.Dynamic | Usage.WriteOnly,				VertexData.Format, Pool.Default, null );		}		#region Private Utility Functions		private static int ComputePrimitiveCount( PrimitiveType primitiveType, int vertexCount )		{			switch( primitiveType )			{				case PrimitiveType.PointList:					return vertexCount;				case PrimitiveType.LineList:					return vertexCount / 2;				case PrimitiveType.LineStrip:					return vertexCount - 1;				case PrimitiveType.TriangleList:					return vertexCount / 3;				case PrimitiveType.TriangleStrip:				case PrimitiveType.TriangleFan:					return vertexCount - 2;				default:					return 0;			}		}		private void RestartRendering()		{			//render what we've got so far			End();			//we may need to re-issue certain vertices			int[] v = { -1, -1 };			switch( m_PrimitiveType )			{				case PrimitiveType.LineStrip:					//re-issue the last vertex					v[0] = m_VertexCount - 1;					break;				case PrimitiveType.LineList:					//re-issue the last vertex if our size is odd					if( m_VertexCount % 2 == 1 )						v[0] = m_VertexCount - 1;					break;				case PrimitiveType.TriangleList:					//re-issue the last 1 or 2 left-over vertices					for( int i = 0; i < m_VertexCount % 3; ++i )					{						v = m_VertexCount - 2 + i;					}					break;				case PrimitiveType.TriangleStrip:					//re-issue the last two vertices					v[0] = m_VertexCount - 2;					v[1] = m_VertexCount - 1;					break;				case PrimitiveType.TriangleFan:					//re-issue the first and last vertices					v[0] = 0;					v[1] = m_VertexCount - 1;					break;			}			//now actually submit the new vertices			Begin( m_PrimitiveType );			foreach( int i in v )			{				if( i > -1 )				{					Normal( m_Vertices.Nx, m_Vertices.Ny, m_Vertices.Nz );					Color( m_Vertices.ColorValue );					TexCoord( m_Vertices.U, m_Vertices.V );					Vertex( m_Vertices.X, m_Vertices.Y, m_Vertices.Z );				}			}		}		#endregion		public void Begin( PrimitiveType primitiveType )		{			if( m_Rendering )				throw new InvalidCallException( "VertexStreamer.Begin() called multiple times." );			//set up a new state			m_PrimitiveType = primitiveType;			m_VertexCount = 0;			m_Rendering = true;		}		public void Color( int colorValue )		{			if( !m_Rendering )				throw new InvalidCallException( "VertexStreamer.Color() called outside of Begin/End pair." );			m_Vertices[m_VertexCount].ColorValue = colorValue;		}		public void Color( System.Drawing.Color color )		{			Color( color.ToArgb() );		}		public void Normal( float nx, float ny, float nz )		{			if( !m_Rendering )				throw new InvalidCallException( "VertexStreamer.Normal() called outside of Begin/End pair." );			m_Vertices[m_VertexCount].Nx = nx;			m_Vertices[m_VertexCount].Ny = ny;			m_Vertices[m_VertexCount].Nz = nz;		}		public void Normal( Vector3 normal )		{			Normal( normal.X, normal.Y, normal.Z );		}		public void TexCoord( float tu, float tv )		{			if( !m_Rendering )				throw new InvalidCallException( "VertexStreamer.TexCoord() called outside of Begin/End pair." );			m_Vertices[m_VertexCount].U = tu;			m_Vertices[m_VertexCount].V = tv;		}		public void Vertex( float x, float y, float z )		{			if( !m_Rendering )				throw new InvalidCallException( "VertexStreamer.Vertex() called outside of Begin/End pair." );			m_Vertices[m_VertexCount].X = x;			m_Vertices[m_VertexCount].Y = y;			m_Vertices[m_VertexCount].Z = z;			++m_VertexCount;			if( m_VertexCount == m_Vertices.Length )				RestartRendering();		}		public void Vertex( Vector3 position )		{			Vertex( position.X, position.Y, position.Z );		}		public void End()		{			if( !m_Rendering )				throw new InvalidCallException( "VertexStreamer.End() called without matching Begin()." );			GraphicsBuffer<VertexData> stream = m_Vb.Lock<VertexData>( 0, 0, LockFlags.Discard );			stream.Write( m_Vertices );			m_Vb.Unlock();			//set up critical device states			m_Device.VertexFormat = VertexData.Format;			m_Device.SetStreamSource( 0, m_Vb, 0, VertexData.StrideSize );			//Get the correct primitive count and issue a draw call			m_Device.DrawPrimitives( m_PrimitiveType, 0, ComputePrimitiveCount( m_PrimitiveType, m_VertexCount ) );			//we're done now			m_Rendering = false;		}		#region IDisposable Members		public void Dispose()		{			m_Vb.Dispose();		}		#endregion	}}

Significant differences from the original:
* No reallocation of memory, either system or video
* Uses a single dynamic VB. No UP calls.
* Tweakable buffer size.
* Handles any primitive count, regardless of buffer size.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
smitty1276
smitty1276
Promit, your stuff looks really cool, actually, and I'll probably play with it a bit for my own use. But I really "need" (I use that word loosely... this is an experimental idea I'm working with) something that will simply replace the current GL libs with one that renders using DX so that I don't have to change any code.

Unfortunately, nothing with this code is trivial. Some of it dates back 15 years or more, and it's written in the nastiest, most stereotypically hideous flavor of straight C you can imagine [sick]... enormous static data structures shared by 20 or 30 different components, etc... there are something like 5000 calls to glBegin, a couple of thousand glTranslate calls etc.

But, since it is primarily just a handful of functions that it uses, maybe I can implement those myself.

Promit
Promit
Well, now is probably a good time to point out ID3DXMatrixStack.

So if you need this in D3D, your only option is to write this layer yourself. If the variety in calls is as minimal as you make it sound, then you're going to need the following:
A static device pointer
A static matrix stack pointer
A stack vertex streamer pointer (assuming you implement it as a C++ class)

Then you actually need to rewrite the calls. A couple things to make note of:
You are going to have to switch the front face for D3D; the opposite is default for the two APIs.
You will want to set up an RH projection matrix, presumably via D3DXMatrixLookAtRH.
Probably more stuff I forgot.

Rewriting mine as OpenGL calls is going to be fairly easy. Either do it as a class and give the calls a file scope pointer, or just pull everything out and make it all file scope. Or if you really, really want to bootstrap this quickly, you can use the older version -- I've used that code to port OpenGL apps quick and dirty before. Then you can alter the internal implementation to the new version after it all works.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
ViLiO
ViLiO
By the sounds of it the system you already have is working and has been working for a long time ...why now would you want to port the rendering over to DirectX?

It sounds like it would be a lot easier to build on top of the legacy code and continue to use OpenGL or throw the whole thing away and start from scratch.

Basically, I am just curious why you'd want to change APIs now [smile]

Regards,
ViLiO
Richard 'ViLiO' Thomasv.net | Twitter | YouTube
smitty1276
smitty1276
Quote:
Original post by ViLiO
Basically, I am just curious why you'd want to change APIs now [smile]


Well, what we have, essentially, is a simulator... which, of course, is much, much more than the graphics (unfortunately, though, the two are nearly inseperable in this case). What some people are becoming more interested in is the application of video game technology to simulation and vice versa.

Some of us were thinking it might be cool to prototype something that might run on the XB360. A first step (in the early phases) would be coercing the old code to run DX without going to the trouble of rewriting any of it... especially since a lot of this will be done just in spare time (to the extent that we actually have any).
Promit
Promit
Quote:
Original post by smitty1276
Some of us were thinking it might be cool to prototype something that might run on the XB360. A first step (in the early phases) would be coercing the old code to run DX without going to the trouble of rewriting any of it... especially since a lot of this will be done just in spare time (to the extent that we actually have any).
A word of warning -- a reimplementation in DX for Xbox will be much more difficult than a reimplementation for PC, given what you've said so far.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
smitty1276
smitty1276
Yeah... the thinking here is that we prototype it on PC. If anybody's interested, we can take care of the more difficult stuff later.
PlayerX
PlayerX
Sounds like a rewrite of the rendering code is in order anyway. Using glBegin, etc. to render in is pretty slow even in OpenGL. You'll certainly want to redo all that if it's going to appear on the XBox. Might as well do it now and save yourself the hassle of doing an OpenGL wrapper. :)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.