Skip to main content
GameDev.net gamedev.net
🔒 Locked

GetGraphics

Started by BlueMonk Jan 19, 2008 at 9:26 PM 15 replies 4.5k views
Original Post
BlueMonk
BlueMonk
I'm using OpenTK and converting my application from using DirectX to using OpenGL (.NET). DirectX has a way to return a Graphics object which I can use to draw arbitrary graphics using the .NET Graphics methods. Does OpenGL provide something similar? How to I draw arbitrary graphics to an OpenGL display? (I want to draw an anti-aliased dashed line with an arrow head on the end; this is easy in .NET, but not using OpenGL primitives, as far as I can tell.)
"All you need to do to learn circular logic is learn circular logic"
_the_phantom_
_the_phantom_
You just issue OpenGL commands, they are automagically routed to the context which is current in the calling thread.
BlueMonk
BlueMonk
But there aren't any GL commands for drawing an anti-aliased dashed line with an arrowhead on the end are there? The reason I was using GetGraphics was to get an object that provided a richer set of drawing operations on a DirectX surface (in .NET). Is there some kind of interface which allows me to do all the same kinds of drawing operations that I would be doing in system memory but transfer them to video memory? (Do I have to do them in a system buffer and somehow copy that over?)
"All you need to do to learn circular logic is learn circular logic"
V-man
V-man
Quote:
Original post by BlueMonk
But there aren't any GL commands for drawing an anti-aliased dashed line with an arrowhead on the end are there?


Sounds like you need a higher level library or you need to code that yourself.

Quote:

The reason I was using GetGraphics was to get an object that provided a richer set of drawing operations on a DirectX surface (in .NET). Is there some kind of interface which allows me to do all the same kinds of drawing operations that I would be doing in system memory but transfer them to video memory? (Do I have to do them in a system buffer and somehow copy that over?)


You could prepare a memory buffer and draw it with glDrawPixels to the GL surface.
.NET is not a language but if you are using C++

unsigned char *buffer=new unsigned char[XXX];
//fill buffer then call glDrawPixels
glRasterPos2i(0, 0);
glDrawPixels(X, Y, GL_BGRA, GL_UNSIGNED_BYTE, buffer);
delete [] buffer;
stonemetal
stonemetal
since you are moving to opentk you will have to convert your .net drawing code into opentk drawing code. I haven't tried it myself but you should be able to draw on what ever surface you have in opentk.
BlueMonk
BlueMonk
Quote:
Original post by V-man
Sounds like you need a higher level library or you need to code that yourself.


It's unfortunate that it's not able to take advantage of existing libraries like DirectX is. As I understand it, there's a common concept of a device context (surely your familiar with it) which is shared by many technologies (printers, memory bitmaps, on-screen display, etc) that provides a common set of drawing features to all these technologies. DirectX participates in this, allowing drawing of arbitrary graphics using a familiar and powerful set of commands. The .NET Graphics object builds on this by providing an even more powerful set of commands for this shared set of objects (GDI+), and Managed DirectX participates in this. I'm surprised OpenGL has no way to take advantage of or interact with these drawing commands.

Quote:

You could prepare a memory buffer and draw it with glDrawPixels to the GL surface.
.NET is not a language but if you are using C++


With the term ".NET", I intended to convey that I am using the .NET framework. It doesn't really matter much which language I'm using on top of that because all .NET-based languages are so similar. The C++ code provided is not really .NET-friendly, but the suggestion of using glDrawPixels might be enough. I'm just concerned that I'll have to copy the pixels from display memory into a buffer, then draw on the buffer, then copy them back... or can I copy pixels with the alpha channel taken into account?

So there's really no way to perform higher level drawing operations on an OpenGL display? You can't even draw a circle without breaking it down into lines or pixels? Surely there's at least a way to draw text... I think I saw sample programs for that. Maybe if I look at those samples, I'll get some idea.

(I hope the plus characters in this message show up better in the actual post than they did in the preview. If not, there should be a plus after (GDI) and after C above.)
"All you need to do to learn circular logic is learn circular logic"
V-man
V-man
Even with D3D, if you will be rendering with GDI on the same surface, there is a performance penalty. I think microsoft renders to the front buffer directly when you do GDI calls and also they do some behind the scene tricks.

With GL, it is different. You need to ask for a pixelformat with GDI support. So you can't have double buffering. Worst of all, you don't get hw acceleration. You get the software renderer as written by microsoft.

So it is possible but I don't recommend it.

Quote:

So there's really no way to perform higher level drawing operations on an OpenGL display? You can't even draw a circle without breaking it down into lines or pixels? Surely there's at least a way to draw text... I think I saw sample programs for that. Maybe if I look at those samples, I'll get some idea.


With GL itself, no. It doesn't render text. It doesn't know what a font is. it doesn't know what a mouse or keyboard input is. It's a low level API.

If you don't feel like coding, then use 3rd party libraries that handle font and arrow, circle rendering on GL.
Fiddler
Fiddler
V-man hit the nail on its head - you could use GDI with OpenGL, but you'd lose performance, double buffering and many other things (including the ability for your program to run on Vista, Linux and almost anywhere else other than legacy Windows systems).

OpenTK.Fonts provides an interface to draw System.Drawing.Fonts with OpenGL. These are the only supported primitives other than the ones OpenGL provides (OpenTK is a low-level library!), so you will have to break your shapes down to textures/lines. Fortunately, OpenGL *does* support drawing antialiased lines (google search), so it is possible to draw this shape with only a little more effort than using GDI+.
[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]
BlueMonk
BlueMonk
I tried this code and couldn't see any effect except that the program was running at a much lower frame rate (I initialized bmpGfx with bmpGfx = new Bitmap(Width, Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);):
      using (Graphics gfx = Graphics.FromImage(bmpGfx))      {         gfx.Clear(Color.Transparent);         gfx.FillEllipse(SystemBrushes.ButtonFace, 0, 0, 50, 40);      }      var bits = bmpGfx.LockBits(new Rectangle(0, 0, bmpGfx.Width, bmpGfx.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);      GL.PixelStore(PixelStoreParameter.UnpackRowLength, bits.Stride);      try      {         GL.DrawPixel(20, 20, OpenTK.OpenGL.Enums.PixelFormat.Bgra, PixelType.UnsignedByte, bits.Scan0);      }      finally      {         bmpGfx.UnlockBits(bits);      }


I'm using a hard coded size of 20,20 because when I try to do anything larger (like 50,50 or Width, Height) I get memory protection errors or application hangs.
"All you need to do to learn circular logic is learn circular logic"
BlueMonk
BlueMonk
Quote:
Original post by Fiddler
V-man hit the nail on its head - you could use GDI with OpenGL, but you'd lose performance, double buffering and many other things (including the ability for your program to run on Vista, Linux and almost anywhere else other than legacy Windows systems).

I'm not too concerned about performance because all I want to do is draw a simple line on top of a rendered scene -- just a couple lines per frame, and it doesn't even need to be a very high frame rate because this is a design-time surface that only draws during an OnPaint event. I am, however, concerned about portability, because that's the whole point of converting to an OpenGL-based graphics system.

Quote:
(OpenTK is a low-level library!)

That's a good thing. I think I want a bare minimum wrapper around OpenGL because I don't want to be distributing a whole framework just to make this application function. I was afraid that the OpenTK.GameWindow was evidence that this was too high-level a library for my purposes. I have my own Display class which wraps the underlying graphics framework in a Control, and I don't want to be duplicating a bunch of code, but I do want control over what I'm doing at the control level. I see OpenTK.GLControl, so I'm deriving from that, and that already seems to take over a number of the functions I was performing manually on the DirectX system. But I have yet to get things working, so I'm not sure how well this will work out. I am after a low level library if anything though. I'm almost tempted to go directly at OpenGL with no managed library wrapper. I'm only using this for high-performance 2D graphics after all (and I like the hardware scaling, rotation, and blending).

"All you need to do to learn circular logic is learn circular logic"
Fiddler
Fiddler
Quote:
I see OpenTK.GLControl, so I'm deriving from that, and that already seems to take over a number of the functions I was performing manually on the DirectX system.

What kind of functions? The GLControl is pretty low-level - it only handles the creation of an OpenGL context (which is somewhat complicated on X11/Mono), everything else is pretty much a raw call to wgl/glx.

Quote:
I'm not too concerned about performance because all I want to do is draw a simple line on top of a rendered scene[...]

Quote:
I'm only using this for high-performance 2D graphics after all (and I like the hardware scaling, rotation, and blending).

Kinda conflicting :)

Anyway, the code you posted should work with a few tweaks. You could try creating a texture and upload the data through GL.TexSubImage (you'll need to call GL.TexImage once first, with null data, to create the texture itself).
[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]
BlueMonk
BlueMonk
Quote:
Original post by Fiddler
Quote:
I see OpenTK.GLControl, so I'm deriving from that, and that already seems to take over a number of the functions I was performing manually on the DirectX system.

What kind of functions? The GLControl is pretty low-level - it only handles the creation of an OpenGL context (which is somewhat complicated on X11/Mono), everything else is pretty much a raw call to wgl/glx.


The creation of the window setting the proper style bits for proper repainting, as well as (I think) the connection between the window and the OpenGL display. I think I had to do a lot of that manually with (even managed) DirectX.

Quote:

Quote:
I'm not too concerned about performance because all I want to do is draw a simple line on top of a rendered scene[...]

Quote:
I'm only using this for high-performance 2D graphics after all (and I like the hardware scaling, rotation, and blending).

Kinda conflicting :)


Well, to make sense of that, realize that I need good enough performance to draw a map full of tiles and scroll it smoothly in a design environment, so I need some acceleration. However, I don't need much acceleration when it comes to drawing the few lines on top of it.

However, I have opted for using the OpenGL functions for line drawing now that I realize they can be used to draw anti-aliased and thick lines. I'll just skip the dashed line appearance for now; maybe implement that later if it's worthwhile. I figure this will probably be more portable and not too bad a trade off.
"All you need to do to learn circular logic is learn circular logic"
Fiddler
Fiddler
Quote:
Original post by BlueMonk
Quote:
Original post by Fiddler
Quote:
I see OpenTK.GLControl, so I'm deriving from that, and that already seems to take over a number of the functions I was performing manually on the DirectX system.

What kind of functions? The GLControl is pretty low-level - it only handles the creation of an OpenGL context (which is somewhat complicated on X11/Mono), everything else is pretty much a raw call to wgl/glx.


The creation of the window setting the proper style bits for proper repainting, as well as (I think) the connection between the window and the OpenGL display. I think I had to do a lot of that manually with (even managed) DirectX.

Ah, I see. Yes, it abstracts away the window/context creation details, but in return you gain some cross-platform compatibility (Windows.Forms+OpenGL on X11, and - in the future - OSX). It's not difficult to roll your own version, but seeing that everything else is as close to the metal as it gets, there's not much point.

Quote:
Original post by BlueMonk
Quote:

Quote:
I'm not too concerned about performance because all I want to do is draw a simple line on top of a rendered scene[...]

Quote:
I'm only using this for high-performance 2D graphics after all (and I like the hardware scaling, rotation, and blending).

Kinda conflicting :)


Well, to make sense of that, realize that I need good enough performance to draw a map full of tiles and scroll it smoothly in a design environment, so I need some acceleration. However, I don't need much acceleration when it comes to drawing the few lines on top of it.

However, I have opted for using the OpenGL functions for line drawing now that I realize they can be used to draw anti-aliased and thick lines. I'll just skip the dashed line appearance for now; maybe implement that later if it's worthwhile. I figure this will probably be more portable and not too bad a trade off.

You can use GL.LineStipple for drawing dashed lines, but I don't know how well that works with antialiased primitives. If it works (and it probably will), you are just one call away from achieving the looks you wanted. If it doesn't, you can still apply a texture to emulate this.

All in all, I think moving all drawing to OpenGL is the right decision in this case ;)
[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]
BlueMonk
BlueMonk
Thanks for the valuable tips! I have a lot to learn about OpenGL. I had no idea what stipple was or that a line could be textured. (Is it possible/easy to orient a texture to follow the direction of a line if I need to go that route?)
"All you need to do to learn circular logic is learn circular logic"
BlueMonk
BlueMonk
I think I just figured out the question to which the first reply was giving me an answer (a completely unrelated question), but I still don't understand the answer, and now I actually have the question: I just noticed that none of the GL commands take any object or display or target as a parameter nor do they operate on any object. How does it know which display to route the commands to? What if I have multiple windowed GL displays and I'm drawing to all of them. How do I select which one I want to target?
"All you need to do to learn circular logic is learn circular logic"
Fiddler
Fiddler
Quote:
Original post by BlueMonk
Thanks for the valuable tips! I have a lot to learn about OpenGL. I had no idea what stipple was or that a line could be textured. (Is it possible/easy to orient a texture to follow the direction of a line if I need to go that route?)


This is the default behavior actually, but you can play with the texture matrix to change it. What you probably want is a 1-dimensional texture (e.g 1x64 pixels), and set its texture coordinates to "repeat" (i.e. texcoord 1.2 will map to 0.2). This way you can draw arbitrarily long dashed lines (think Win9x dashed selection rectangle).

Quote:
I just noticed that none of the GL commands take any object or display or target as a parameter nor do they operate on any object. How does it know which display to route the commands to? What if I have multiple windowed GL displays and I'm drawing to all of them. How do I select which one I want to target?


OpenGL works like a state machine: you set the state and it stays until you change it. For example, once you "bind" a texture, all texture commands will use this until you bind a different one. This is unlike direct3d or other more "object-oriented" API's, where you have to specify the object for each command.

The same thing applies to displays: to use OpenGL, you need an OpenGL context. Once you create a context, you make it "current" in a thread and all OpenGL commands in this thread are "routed" to this context. You can create multiple contexts if you wish, but only one can be active in any one thread. You can opt to make each context current in a different thread, so that you can use them all at the same time, or you can use only one thread and switch between contexts as needed (both solutions are relatively complex).

I don't know if my explanation makes any sense. You just need the OpenTK.GLControl.Context property and the MakeCurrent() method.
[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]
BlueMonk
BlueMonk
Quote:
Original post by Fiddler
I don't know if my explanation makes any sense. You just need the OpenTK.GLControl.Context property and the MakeCurrent() method.


That's the only part I needed. I think I already understood the rest (DirectX didn't have much of an opportunity to "corrupt" my perceptions permanently :)). By some strange coincidence, my IDE opened up to the OpenTK file this morning where MakeCurrent was defined, and I noticed that was the answer to my question. I don't know how that happened -- I don't recall looking at OpenTK source code recently. In any case, I think I have the answer I need.
"All you need to do to learn circular logic is learn circular logic"

Topic Locked

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

Sign in to reply to this topic.