From e6120238c7aa4cf8a7e3d671d0816c1247eb491f Mon Sep 17 00:00:00 2001 From: Bob Date: Wed, 17 Feb 2010 19:52:54 +1300 Subject: [PATCH] inverting the Engine <-> GL project dependency. --- .gitignore | 2 + .../Graphics/IGraphicsDevice.cs | 80 +++++++++++ OpenRa.FileFormats/OpenRa.FileFormats.csproj | 1 + OpenRa.Game/Graphics/LineRenderer.cs | 10 +- OpenRa.Game/Graphics/Renderer.cs | 53 +++++--- OpenRa.Game/Graphics/Sheet.cs | 8 +- OpenRa.Game/Graphics/SpriteRenderer.cs | 18 +-- OpenRa.Game/Graphics/TerrainRenderer.cs | 11 +- OpenRa.Game/Graphics/Vertex.cs | 3 - OpenRa.Game/OpenRa.Game.csproj | 4 - OpenRa.Gl/GraphicsDevice.cs | 126 ++++++++++-------- OpenRa.Gl/OpenRa.Gl.csproj | 9 ++ 12 files changed, 214 insertions(+), 111 deletions(-) create mode 100755 OpenRa.FileFormats/Graphics/IGraphicsDevice.cs diff --git a/.gitignore b/.gitignore index c96b870526..7ea2b993b6 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ log.txt cg.dll cgGL.dll glfw.dll + +/OpenRa.Gl.dll \ No newline at end of file diff --git a/OpenRa.FileFormats/Graphics/IGraphicsDevice.cs b/OpenRa.FileFormats/Graphics/IGraphicsDevice.cs new file mode 100755 index 0000000000..4936b1947e --- /dev/null +++ b/OpenRa.FileFormats/Graphics/IGraphicsDevice.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using System.IO; + +namespace OpenRa.FileFormats.Graphics +{ + [AttributeUsage( AttributeTargets.Assembly )] + public class RendererAttribute : Attribute + { + public readonly Type Type; + + public RendererAttribute( Type graphicsDeviceType ) + { + if( !typeof( IGraphicsDevice ).IsAssignableFrom( graphicsDeviceType ) ) + throw new InvalidOperationException( "Incorrect type in RendererAttribute" ); + Type = graphicsDeviceType; + } + } + + public interface IGraphicsDevice + { + IVertexBuffer CreateVertexBuffer( int length ) where T : struct; + IIndexBuffer CreateIndexBuffer( int length ); + ITexture CreateTexture( Bitmap bitmap ); + + IShader CreateShader( Stream stream ); + + void Begin(); + void End(); + void Clear( Color color ); + void Present(); + + void DrawIndexedPrimitives( PrimitiveType type, Range vertexRange, Range indexRange ); + void DrawIndexedPrimitives( PrimitiveType type, int vertexPool, int numPrimitives ); + + void EnableScissor( int left, int top, int width, int height ); + void DisableScissor(); + } + + public interface IVertexBuffer + { + void Bind(); + void SetData( T[] vertices ); + } + + public interface IIndexBuffer + { + void Bind(); + void SetData( ushort[] indices ); + } + + public interface IShader + { + void SetValue( string name, float x, float y ); + void SetValue( string param, ITexture texture ); + void Commit(); + void Render( Action a ); + } + + public interface ITexture + { + void SetData( Bitmap bitmap ); + } + + public enum PrimitiveType + { + PointList, + LineList, + TriangleList, + } + + public struct Range + { + public readonly T Start, End; + public Range( T start, T end ) { Start = start; End = end; } + } +} diff --git a/OpenRa.FileFormats/OpenRa.FileFormats.csproj b/OpenRa.FileFormats/OpenRa.FileFormats.csproj index e3e81c355f..d631870623 100644 --- a/OpenRa.FileFormats/OpenRa.FileFormats.csproj +++ b/OpenRa.FileFormats/OpenRa.FileFormats.csproj @@ -59,6 +59,7 @@ + diff --git a/OpenRa.Game/Graphics/LineRenderer.cs b/OpenRa.Game/Graphics/LineRenderer.cs index fe50b4c5c1..2be4f0d9a3 100644 --- a/OpenRa.Game/Graphics/LineRenderer.cs +++ b/OpenRa.Game/Graphics/LineRenderer.cs @@ -19,15 +19,15 @@ #endregion using System.Drawing; -using OpenRa.GlRenderer; +using OpenRa.FileFormats.Graphics; namespace OpenRa.Graphics { class LineRenderer { Renderer renderer; - VertexBuffer vertexBuffer; - IndexBuffer indexBuffer; /* kindof a waste of space, but the GPU likes indexing, oh well */ + IVertexBuffer vertexBuffer; + IIndexBuffer indexBuffer; /* kindof a waste of space, but the GPU likes indexing, oh well */ const int linesPerBatch = 1024; @@ -39,8 +39,8 @@ namespace OpenRa.Graphics public LineRenderer( Renderer renderer ) { this.renderer = renderer; - vertexBuffer = new VertexBuffer( renderer.Device, vertices.Length, Vertex.Format ); - indexBuffer = new IndexBuffer( renderer.Device, indices.Length ); + vertexBuffer = renderer.Device.CreateVertexBuffer(vertices.Length ); + indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length ); } public void Flush() diff --git a/OpenRa.Game/Graphics/Renderer.cs b/OpenRa.Game/Graphics/Renderer.cs index 7968a5f927..f59f505582 100644 --- a/OpenRa.Game/Graphics/Renderer.cs +++ b/OpenRa.Game/Graphics/Renderer.cs @@ -18,12 +18,15 @@ */ #endregion +using System; using System.Drawing; using System.Drawing.Text; +using System.Reflection; using System.Windows.Forms; using OpenRa.FileFormats; -using OpenRa.GlRenderer; +using OpenRa.FileFormats.Graphics; using OpenRa.Support; +using System.IO; namespace OpenRa.Graphics { @@ -31,14 +34,14 @@ namespace OpenRa.Graphics { internal static int SheetSize; - readonly GraphicsDevice device; + readonly IGraphicsDevice device; - public Shader SpriteShader { get; private set; } /* note: shared shader params */ - public Shader LineShader { get; private set; } - public Shader RgbaSpriteShader { get; private set; } - public Shader WorldSpriteShader { get; private set; } + public IShader SpriteShader { get; private set; } /* note: shared shader params */ + public IShader LineShader { get; private set; } + public IShader RgbaSpriteShader { get; private set; } + public IShader WorldSpriteShader { get; private set; } - public Texture PaletteTexture; + public ITexture PaletteTexture; readonly Font fDebug, fTitle; @@ -49,16 +52,12 @@ namespace OpenRa.Graphics public Renderer(Control control, Size resolution, bool windowed) { control.ClientSize = resolution; - device = new GraphicsDevice(control, resolution.Width, resolution.Height, windowed, false); + device = CreateDevice( Assembly.LoadFile( Path.GetFullPath( "OpenRa.Gl.dll" ) ), control, resolution.Width, resolution.Height, windowed, false ); - SpriteShader = new Shader(device, FileSystem.Open("world-shp.fx")); - SpriteShader.Quality = ShaderQuality.Low; - LineShader = new Shader(device, FileSystem.Open("line.fx")); - LineShader.Quality = ShaderQuality.High; - RgbaSpriteShader = new Shader(device, FileSystem.Open("chrome-rgba.fx")); - RgbaSpriteShader.Quality = ShaderQuality.High; - WorldSpriteShader = new Shader(device, FileSystem.Open("chrome-shp.fx")); - WorldSpriteShader.Quality = ShaderQuality.High; + SpriteShader = device.CreateShader(FileSystem.Open("world-shp.fx")); + LineShader = device.CreateShader(FileSystem.Open("line.fx")); + RgbaSpriteShader = device.CreateShader(FileSystem.Open("chrome-rgba.fx")); + WorldSpriteShader = device.CreateShader(FileSystem.Open("chrome-shp.fx")); fDebug = new Font("Tahoma", 10, FontStyle.Regular); fTitle = new Font("Tahoma", 10, FontStyle.Bold); @@ -67,6 +66,16 @@ namespace OpenRa.Graphics textSprite = new Sprite(textSheet, new Rectangle(0, 0, 256, 256), TextureChannel.Alpha); } + IGraphicsDevice CreateDevice( Assembly rendererDll, Control control, int width, int height, bool fullscreen, bool vsync ) + { + foreach( RendererAttribute r in rendererDll.GetCustomAttributes( typeof( RendererAttribute ), false ) ) + { + return (IGraphicsDevice)r.Type.GetConstructor( new Type[] { typeof( Control ), typeof( int ), typeof( int ), typeof( bool ), typeof( bool ) } ) + .Invoke( new object[] { control, width, height, fullscreen, vsync } ); + } + throw new NotImplementedException(); + } + Bitmap RenderTextToBitmap(string s, Font f, Color c) { Bitmap b = new Bitmap(256, 256); @@ -86,7 +95,7 @@ namespace OpenRa.Graphics return new int2(g.MeasureString(s, f).ToSize()); } - public GraphicsDevice Device { get { return device; } } + public IGraphicsDevice Device { get { return device; } } public void BeginFrame(float2 r1, float2 r2, float2 scroll) { @@ -99,7 +108,7 @@ namespace OpenRa.Graphics SetShaderParams( WorldSpriteShader, r1, r2, scroll ); } - private void SetShaderParams( Shader s, float2 r1, float2 r2, float2 scroll ) + private void SetShaderParams( IShader s, float2 r1, float2 r2, float2 scroll ) { s.SetValue( "Palette", PaletteTexture ); s.SetValue( "Scroll", scroll.X, scroll.Y ); @@ -114,8 +123,8 @@ namespace OpenRa.Graphics device.Present(); } - public void DrawBatch(VertexBuffer vertices, IndexBuffer indices, - Range vertexRange, Range indexRange, Texture texture, PrimitiveType type, Shader shader) + public void DrawBatch(IVertexBuffer vertices, IIndexBuffer indices, + Range vertexRange, Range indexRange, ITexture texture, PrimitiveType type, IShader shader) where T : struct { shader.SetValue("DiffuseTexture", texture); @@ -129,8 +138,8 @@ namespace OpenRa.Graphics PerfHistory.Increment("batches", 1); } - public void DrawBatch(VertexBuffer vertices, IndexBuffer indices, - int vertexPool, int numPrimitives, Texture texture, PrimitiveType type) + public void DrawBatch(IVertexBuffer vertices, IIndexBuffer indices, + int vertexPool, int numPrimitives, ITexture texture, PrimitiveType type) where T : struct { SpriteShader.SetValue("DiffuseTexture", texture); diff --git a/OpenRa.Game/Graphics/Sheet.cs b/OpenRa.Game/Graphics/Sheet.cs index 9f75828d21..6feb2bd0aa 100644 --- a/OpenRa.Game/Graphics/Sheet.cs +++ b/OpenRa.Game/Graphics/Sheet.cs @@ -20,7 +20,7 @@ using System.Drawing; using OpenRa.FileFormats; -using OpenRa.GlRenderer; +using OpenRa.FileFormats.Graphics; namespace OpenRa.Graphics { @@ -29,7 +29,7 @@ namespace OpenRa.Graphics readonly Renderer renderer; protected readonly Bitmap bitmap; - Texture texture; + ITexture texture; internal Sheet(Renderer renderer, Size size) { @@ -45,10 +45,10 @@ namespace OpenRa.Graphics void Resolve() { - texture = new Texture(renderer.Device, bitmap); + texture = renderer.Device.CreateTexture(bitmap); } - public Texture Texture + public ITexture Texture { get { diff --git a/OpenRa.Game/Graphics/SpriteRenderer.cs b/OpenRa.Game/Graphics/SpriteRenderer.cs index 0e74184ef3..4550f52753 100644 --- a/OpenRa.Game/Graphics/SpriteRenderer.cs +++ b/OpenRa.Game/Graphics/SpriteRenderer.cs @@ -18,16 +18,16 @@ */ #endregion -using OpenRa.GlRenderer; +using OpenRa.FileFormats.Graphics; namespace OpenRa.Graphics { class SpriteRenderer { - VertexBuffer vertexBuffer; - IndexBuffer indexBuffer; + IVertexBuffer vertexBuffer; + IIndexBuffer indexBuffer; Renderer renderer; - Shader shader; + IShader shader; const int spritesPerBatch = 1024; @@ -35,18 +35,15 @@ namespace OpenRa.Graphics ushort[] indices = new ushort[6 * spritesPerBatch]; Sheet currentSheet = null; int sprites = 0; - ShaderQuality quality; int nv = 0, ni = 0; - public SpriteRenderer(Renderer renderer, bool allowAlpha, Shader shader) + public SpriteRenderer(Renderer renderer, bool allowAlpha, IShader shader) { this.renderer = renderer; this.shader = shader; - vertexBuffer = new VertexBuffer(renderer.Device, vertices.Length, Vertex.Format); - indexBuffer = new IndexBuffer(renderer.Device, indices.Length); - - quality = allowAlpha ? ShaderQuality.High : ShaderQuality.Low; + vertexBuffer = renderer.Device.CreateVertexBuffer( vertices.Length ); + indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length ); } public SpriteRenderer(Renderer renderer, bool allowAlpha) @@ -56,7 +53,6 @@ namespace OpenRa.Graphics { if (sprites > 0) { - shader.Quality = quality; shader.SetValue( "DiffuseTexture", currentSheet.Texture ); shader.Render(() => { diff --git a/OpenRa.Game/Graphics/TerrainRenderer.cs b/OpenRa.Game/Graphics/TerrainRenderer.cs index b066214ac4..bce0114ecd 100644 --- a/OpenRa.Game/Graphics/TerrainRenderer.cs +++ b/OpenRa.Game/Graphics/TerrainRenderer.cs @@ -20,14 +20,14 @@ using System.Drawing; using OpenRa.FileFormats; -using OpenRa.GlRenderer; +using OpenRa.FileFormats.Graphics; namespace OpenRa.Graphics { class TerrainRenderer { - VertexBuffer vertexBuffer; - IndexBuffer indexBuffer; + IVertexBuffer vertexBuffer; + IIndexBuffer indexBuffer; Sheet terrainSheet; Renderer renderer; @@ -62,10 +62,10 @@ namespace OpenRa.Graphics terrainSheet = tileMapping[map.MapTiles[map.XOffset, map.YOffset]].sheet; - vertexBuffer = new VertexBuffer( renderer.Device, vertices.Length, Vertex.Format ); + vertexBuffer = renderer.Device.CreateVertexBuffer( vertices.Length ); vertexBuffer.SetData( vertices ); - indexBuffer = new IndexBuffer( renderer.Device, indices.Length ); + indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length ); indexBuffer.SetData( indices ); overlayRenderer = new OverlayRenderer( renderer, map ); @@ -97,7 +97,6 @@ namespace OpenRa.Graphics firstRow = r.Bottom - map.YOffset; } - renderer.SpriteShader.Quality = ShaderQuality.Low; renderer.SpriteShader.SetValue( "DiffuseTexture", terrainSheet.Texture ); renderer.SpriteShader.Render(() => renderer.DrawBatch(vertexBuffer, indexBuffer, diff --git a/OpenRa.Game/Graphics/Vertex.cs b/OpenRa.Game/Graphics/Vertex.cs index 8cea985bd8..e0229a8025 100644 --- a/OpenRa.Game/Graphics/Vertex.cs +++ b/OpenRa.Game/Graphics/Vertex.cs @@ -19,7 +19,6 @@ #endregion using System.Runtime.InteropServices; -using OpenRa.GlRenderer; namespace OpenRa.Graphics { @@ -35,7 +34,5 @@ namespace OpenRa.Graphics this.u = uv.X; this.v = uv.Y; this.p = pc.X; this.c = pc.Y; } - - public const VertexFormat Format = VertexFormat.Position | VertexFormat.Texture2; } } diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index da75c2cd7b..99d00154a8 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -272,10 +272,6 @@ {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA} OpenRa.FileFormats - - {67CF1A10-C5F6-48FA-B1A7-FE83BE4CE2CC} - OpenRa.Gl - diff --git a/OpenRa.Gl/GraphicsDevice.cs b/OpenRa.Gl/GraphicsDevice.cs index 2f07cb967e..014a632d45 100644 --- a/OpenRa.Gl/GraphicsDevice.cs +++ b/OpenRa.Gl/GraphicsDevice.cs @@ -27,10 +27,13 @@ using System.Windows.Forms; using Tao.Cg; using Tao.OpenGl; using Tao.Platform.Windows; +using OpenRa.FileFormats.Graphics; + +[assembly: Renderer( typeof( OpenRa.GlRenderer.GraphicsDevice ))] namespace OpenRa.GlRenderer { - public class GraphicsDevice + public class GraphicsDevice : IGraphicsDevice { Size windowSize; Graphics g; @@ -39,7 +42,7 @@ namespace OpenRa.GlRenderer internal IntPtr cgContext; internal int vertexProfile, fragmentProfile; - public static void CheckGlError() + internal static void CheckGlError() { var n = Gl.glGetError(); if (n != Gl.GL_NO_ERROR) @@ -125,17 +128,28 @@ namespace OpenRa.GlRenderer CheckGlError(); } - public void DrawIndexedPrimitives(PrimitiveType pt, Range vertices, Range indices) - { - Gl.glDrawElements( (int)pt, indices.End - indices.Start, Gl.GL_UNSIGNED_SHORT, new IntPtr( indices.Start * 2 ) ); - CheckGlError(); - } - - public void DrawIndexedPrimitives(PrimitiveType pt, int numVerts, int numPrimitives) - { - Gl.glDrawElements((int)pt, numPrimitives * IndicesPerPrimitive( pt ), Gl.GL_UNSIGNED_SHORT, IntPtr.Zero); - CheckGlError(); - } + public void DrawIndexedPrimitives( PrimitiveType pt, Range vertices, Range indices ) + { + Gl.glDrawElements( ModeFromPrimitiveType( pt ), indices.End - indices.Start, Gl.GL_UNSIGNED_SHORT, new IntPtr( indices.Start * 2 ) ); + CheckGlError(); + } + + public void DrawIndexedPrimitives( PrimitiveType pt, int numVerts, int numPrimitives ) + { + Gl.glDrawElements( ModeFromPrimitiveType( pt ), numPrimitives * IndicesPerPrimitive( pt ), Gl.GL_UNSIGNED_SHORT, IntPtr.Zero ); + CheckGlError(); + } + + static int ModeFromPrimitiveType( PrimitiveType pt ) + { + switch( pt ) + { + case PrimitiveType.PointList: return Gl.GL_POINTS; + case PrimitiveType.LineList: return Gl.GL_LINES; + case PrimitiveType.TriangleList: return Gl.GL_TRIANGLES; + } + throw new NotImplementedException(); + } static int IndicesPerPrimitive( PrimitiveType pt ) { @@ -147,19 +161,39 @@ namespace OpenRa.GlRenderer } throw new NotImplementedException(); } - } - public struct Range - { - public readonly T Start, End; - public Range(T start, T end) { Start = start; End = end; } - } + #region IGraphicsDevice Members - public class VertexBuffer where T : struct + public IVertexBuffer CreateVertexBuffer( int size ) + where T : struct + { + return new VertexBuffer( this, size ); + } + + public IIndexBuffer CreateIndexBuffer( int size ) + { + return new IndexBuffer( this, size ); + } + + public ITexture CreateTexture( Bitmap bitmap ) + { + return new Texture( this, bitmap ); + } + + public IShader CreateShader( Stream stream ) + { + return new Shader( this, stream ); + } + + #endregion + } + + public class VertexBuffer : IVertexBuffer, IDisposable + where T : struct { int buffer; - public VertexBuffer(GraphicsDevice dev, int size, VertexFormat fmt) + public VertexBuffer(GraphicsDevice dev, int size) { Gl.glGenBuffers(1, out buffer); GraphicsDevice.CheckGlError(); @@ -196,7 +230,7 @@ namespace OpenRa.GlRenderer //~VertexBuffer() { Dispose(); } } - public class IndexBuffer : IDisposable + public class IndexBuffer : IIndexBuffer, IDisposable { int buffer; @@ -233,11 +267,10 @@ namespace OpenRa.GlRenderer //~IndexBuffer() { Dispose(); } } - public class Shader + public class Shader : IShader { IntPtr effect; - IntPtr highTechnique; - IntPtr lowTechnique; + IntPtr technique; GraphicsDevice dev; public Shader(GraphicsDevice dev, Stream s) @@ -256,31 +289,22 @@ namespace OpenRa.GlRenderer string.Format("Cg compile failed ({0}):\n{1}", err, results)); } - lowTechnique = Cg.cgGetNamedTechnique(effect, "low_quality"); - highTechnique = Cg.cgGetNamedTechnique(effect, "high_quality"); - - if (lowTechnique != IntPtr.Zero && 0 == Cg.cgValidateTechnique(lowTechnique)) - lowTechnique = IntPtr.Zero; - if (highTechnique != IntPtr.Zero && 0 == Cg.cgValidateTechnique(highTechnique)) - highTechnique = IntPtr.Zero; - - if (highTechnique == IntPtr.Zero && lowTechnique == IntPtr.Zero) - throw new InvalidOperationException("No valid techniques"); - - if( highTechnique == IntPtr.Zero ) - highTechnique = lowTechnique; - if( lowTechnique == IntPtr.Zero ) - lowTechnique = highTechnique; + technique = Cg.cgGetFirstTechnique( effect ); + if( technique == IntPtr.Zero ) + throw new InvalidOperationException("No techniques"); + while( Cg.cgValidateTechnique( technique ) == 0 ) + { + technique = Cg.cgGetNextTechnique( technique ); + if( technique == IntPtr.Zero ) + throw new InvalidOperationException("No valid techniques"); + } } - public ShaderQuality Quality { get; set; } - public void Render(Action a) { CgGl.cgGLEnableProfile(dev.vertexProfile); CgGl.cgGLEnableProfile(dev.fragmentProfile); - var technique = Quality == ShaderQuality.High ? highTechnique : lowTechnique; var pass = Cg.cgGetFirstPass(technique); while (pass != IntPtr.Zero) { @@ -294,8 +318,9 @@ namespace OpenRa.GlRenderer CgGl.cgGLDisableProfile(dev.vertexProfile); } - public void SetValue(string name, Texture texture) + public void SetValue(string name, ITexture t) { + var texture = (Texture)t; var param = Cg.cgGetNamedEffectParameter( effect, name ); if( param != IntPtr.Zero && texture != null ) CgGl.cgGLSetupSampler( param, texture.texture ); @@ -311,7 +336,7 @@ namespace OpenRa.GlRenderer public void Commit() { } } - public class Texture + public class Texture : ITexture { internal int texture; @@ -343,15 +368,4 @@ namespace OpenRa.GlRenderer bitmap.UnlockBits(bits); } } - - [Flags] - public enum VertexFormat { Position, Texture2 } - - public enum ShaderQuality { Low, High } - public enum PrimitiveType - { - PointList = Gl.GL_POINTS, - LineList = Gl.GL_LINES, - TriangleList = Gl.GL_TRIANGLES - } } diff --git a/OpenRa.Gl/OpenRa.Gl.csproj b/OpenRa.Gl/OpenRa.Gl.csproj index 0a299eafbc..fb3caf6559 100644 --- a/OpenRa.Gl/OpenRa.Gl.csproj +++ b/OpenRa.Gl/OpenRa.Gl.csproj @@ -59,6 +59,12 @@ + + + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA} + OpenRa.FileFormats + + + + copy "$(TargetPath)" "$(SolutionDir)" + \ No newline at end of file