PDA

View Full Version : is OpenGL what I need?



ScottM
12-16-2007, 09:30 AM
This isn't an invitation to flame, or debate openGL vs anything else. I have a particular application, written in C++ for Windows (XP and Vista, and no immediate need to run it elsewhere), and it makes a whole lot of calls to the GDI, basically Rectangle, Polygon (always for triangles), and LineTo. Purely 2D work, and the polygons drawn are numerous and typically tiny (in some occasionally useful situations, they reduce to single pixels).

Performance is utterly abysmal. I can watch the window repaint, and times of 2-5 seconds are not uncommon. (On a laptop with what is probably crummy, integrated video). I'd really like the repaint time to be a handful of milliseconds. The worst-case scenario is about a million triangles (one pixel each at 1280x960). So I'm assuming I really, really want hardware acceleration for this.

So here's my wishlist and not wished-list. Is openGL a good fit?

1. Trivial to install and build and call, using straight C++ in Microsoft Dev Studio 7.1.
2. Will work today, will work tomorrow without modification. This is not a tool I want to revisit over and over. I just want it to work.
3. Fast; a worst-case scenario of a million triangles in, say, 0.2 seconds, isn't laughable. (This worst case is extreme; often I have whole regions without any triangles to draw (ie, left black) and the triangles to be drawn are usually larger than a pixel.) If all it's going to do is paint a bitmap using the CPU, and then flip the bitmap, I'm not sure that will cut it.
4. I only need 2D primitives (am happy to use ortho projection in 3D).
5. My "textures" are simply colors, and few of those; I don't need shading or bitmaps. No alpha blending, fog, complex stuff.
6. Ideally, I could tell openGL not to cull triangles because I didn't specify them with the right winding. But if forced, I can organize all my triangles to be counterclockwise. (The layout of the triangles is generated once, and saved; all I have to do at runtime is figure out which ones are in the bounding rectangle, and draw those with the right colors.)
7. The same code should work on XP and Vista(Aero).
8. Will work over multiple displays (aka extended desktop) on the same system (caveat: really only has to work on one display or the other, but I have to be able to move it.)
9. Will work reasonably well if handed the triangles individually (I know fans are probably faster and move less data, but I hope not to do that much work. I do know when two triangles are adjacent and tile a rectangle, and the same color, but that's as far as I want to push it.)
10. Will let me have a "regular" window frame. (I have menus and I want to keep them.)
11. Dropping text on the screen, specifying a starting pixel x,y position, isn't too hard.

I know I could probably do this in DirectX. The last time I played with DirectX was years ago; it was hard, and I think the interface has changed multiple times since then. DirectX is too much learning curve and debugging hell.

Is openGL going to work for me? Please, no flames, be gentle.

Zengar
12-16-2007, 10:14 AM
Yes

ScottM
12-16-2007, 10:33 AM
Awesome. I see there are several openGL-ish package out there. Is there one in particular that's known to be Windows-friendly (eg, works with DevStudio 7.1) and stable?

Thanks!

Zengar
12-16-2007, 10:44 AM
What do you mean by "openGL-ish package"? I have no idea what DevStudio is, but I assume it is some sort of C++ IDE. You will just need some basic libraries and header files, then you should go through teh NeHe tutorials and in about a week you should be able to start writing you own programs.

juglarx
12-16-2007, 11:07 AM
OpenGL is for you... here is a tutorial about how to use OpenGL and MFC ....
http://www.gamedev.net/reference/articles/article1358.asp

ScottM
12-16-2007, 11:19 AM
juglarx: No MFC. Never touch the stuff. I go straight to the Windows SDK when I need a system function.

Zengar: Well, just on this site, under libraries, I see:

Equalizer
GLee
GLEW
OpenSceneGraph

But nothing that calls itself openGL. Are these all implementations of a Standard? Is one of them a better starting point for my (admittedly simple) needs?

Zengar
12-16-2007, 11:52 AM
Well, this are "utility" libraries. OpenGL is an API and resides in the opengl32.dll on windows. So basically, you don't need to install anything (besides the correct drivers). Your compiler probably has the basic lib and h files for OpenGL. The problem on Windows is, that some of functions (all extensions and core functions after OpenGL 1.1)cannot be accessed using static linking (as the DLL doesn't export this functions). One has to query this functions at runtime. This is what GLee and GLEW do: they manage the runtime dynamic linking behind the stage. The SceneGraph is a high-level scenegraph implementation that uses OpenGL. No idea about Equalizer.

Trenki
12-16-2007, 11:58 AM
The OpenGL library is already included with your compiler, so you don't have to download anything! The <GL/gl.h> header file provides only declarations for OpenGL 1.1. If you even want to use newer functionality (which I doubt in your specific case) you could use GLEW to get easy access to them.

[ www.trenki.net (http://www.trenki.net) | vector_math (3d math library) (http://www.trenki.net/content/view/16/36/) | software renderer (http://www.trenki.net/content/view/18/38/) ]

-NiCo-
12-16-2007, 12:10 PM
I would recommend you start by installing the GLUT and GLEW libraries. GLUT allows you to create a basic OpenGL context while GLEW provides access to all OpenGL functionality. You'll only need 10 lines of code to do this.
Once you have determined whether OpenGL is what you need, you can move on to creating your OpenGL contexts in another way and selection of the OpenGL functionality you need.

N.

pudman
12-16-2007, 12:16 PM
All of this information has already been provided at:
http://www.opengl.org/wiki/index.php/Getting_started

ScottM
12-19-2007, 08:13 AM
OK.. I'm starting to experiment; thanks for all the pointers so far. I'm getting the speed I need, and I've worked out getting colored triangles, rectangles, lines, text (Windows, so I'm using wglUseFontBitmaps) up in 2D.

A couple of remaining how do I's... the existing code I'm porting to openGL, calculates everything in terms of pixels. By design, resizing the window doesn't change the size of the objects being drawn, it just shows more or less of the map to be displayed. I need to preserve that behaviour.

glViewport doesn't operate that way; when I call it after a window resize, it merrily scales all the triangles. How do I lock the coordinate system to pixels?

I appreciate the help; I know I'm off the cool, 3D object beaten path here and doing relatively boring and oddish things. But openGL's performance is just what I need, and getting an app up and running in one day wouldn't have happened with DirectX, so I'm committed to openGL for this. Pointers always appreciated!

ZbuffeR
12-19-2007, 08:38 AM
you can set the projection matrix, using glOrtho for ex, with the appropriate coordinates, when you have a viewportresize.

ScottM
12-19-2007, 03:12 PM
>you can set the projection matrix, using glOrtho for ex, with the appropriate coordinates, when you have a viewportresize.

That's why I tried first. Calling glOrtho() during WM_SIZE causes a black screen.

I realize posting code is lame, but the references I'm hitting aren't covering my situation. Is anything obviously wrong here?

//setting up the window, lifted with mods from a demo:
void EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC)
{
PIXELFORMATDESCRIPTOR pfd;
int format;
// get the device context (DC)
*hDC = GetDC( hWnd );
// set the pixel format for the DC
ZeroMemory( &pfd, sizeof( pfd ) );
pfd.nSize = sizeof( pfd );
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
format = ChoosePixelFormat( *hDC, &pfd );
SetPixelFormat( *hDC, format, &pfd );

// create and enable the render context (RC)
*hRC = wglCreateContext( *hDC );
wglMakeCurrent( *hDC, *hRC );
//draw all my polygons always
glDisable(GL_CULL_FACE);

//get font glyphs at list 1000
SelectObject (*hDC, GetStockObject (SYSTEM_FONT));
wglUseFontBitmaps (*hDC, 0, 255, 1000);
//get my 2D coordinate system to match window size
RECT r;
GetClientRect(hWnd, &r);
width = r.right;
height = r.bottom;
glOrtho(0, width, 0, height, -1, 1);
}

That works, and I can try triangles to my heart's content, until I cause a resize event:

case WM_SIZE:
{
RECT r;
GetClientRect(hWnd, &r);
//
glOrtho(0, r.right, 0, r.bottom, -1, 1);
}
return 0;

No more triangles after that. Yes, r is being filled in with reasonable values, and yes I do hit the drawing code after that, sending it values in range for those bounds. Anything obviously wrong here?

-NiCo-
12-19-2007, 03:28 PM
Matrix calls such as glOrtho,glFrustum,etc... generate matrix transforms which are multiplied with the current matrix on the top of the stack. The correct way to call it is:

//perform matrix operations on the projection matrix
glMatrixMode(GL_PROJECTION)
//set the (projection) matrix to the identity matrix
glLoadIdentity()
//multiply the identity matrix with the matrix from glOrtho
glOrtho(...)

If you only perform glOrtho calls without loading the identity matrix you're actually multiplying an orth-view matrix with another ortho-view matrix which was on the top of the GL_PROJECTION_MATRIX stack, which obviously produces incorrect results.

N.

ZbuffeR
12-19-2007, 03:31 PM
As described in the documentation,
glOrtho multiplies the current matrix (http://www.opengl.org/sdk/docs/man/xhtml/glOrtho.xml).

You need to select the projection matrix, and reset it to the default with glLoadIdentity() before using glOrtho. Else the changes are cumulated, and that is not what you want.
Have a look here :
http://www.opengl.org/resources/faq/technical/transformations.htm#tran0030

ScottM
12-19-2007, 04:45 PM
Yup. Documentation helps...

Thanks, people! I might be back, but I think I have what I need now.

ScottM
12-26-2007, 03:52 PM
Okay! I've ported both my 2D applications over to openGL. The screen update is far, far faster and for the most part, looks better as well. I had to do some song and dance to get text to wrap within rectangles, but I'm very pleased with the result.

One infuriating problem. The code works exactly as I'd expect under Windows Vista. I just ran the executable on Windows XP - and all the lines were drawn thicker than specified. Since I've got the projection mapped so that one unit is one pixel, glLineWidth(1) should be giving me one pixel wide lines, and does on Vista. On XP it looks like at least 2. ANY clue why XP would be different - and what I can do to fix this? It's not messing up triangles, fonts, or anything but lines..

ScottM
12-30-2007, 07:04 PM
After a huge amount of headbanging.. it appears that glLineWidth and/or GL_LINES simply doesn't work as expected on an XP system with an Intel Mobile 945GM video chipset, even with the latest drivers. It's possible to get thin horizontal and vertical straight lines by drawing skinny rectangles, but drawing lines the usual way bloats the line width, in all cases.

Zengar
12-31-2007, 08:26 AM
Ah, you should have said that you have an intel video :) Intel is known for very poor OpenGL support, unfortunately.

ScottM
01-14-2008, 08:52 AM
For folk in the same miserable situation, I get decent (not perfect) results with this C++ code. If you draw a lot of lines, performance probably improves if you move the begin and end calls out.

//Windows XP, Intel Mobile 945GM chipset - glLineWidth() simply doesn't
// work. The lines are far too fat. No idea why, but it's just totally
// broken.
//This junk is a workaround.

static void drawLineWithQuad(float fromx, float fromy, float tox, float toy, float width = 1)
{
//horizontal or vertical rectange is fastest, even for width 1
//also, the tilted rectangle code wont' work for horizontal lines
if (fromx == tox) //vertical
{
const float offsetForWidth = width * 0.5f;
glBegin(GL_QUADS);
glVertex2f(fromx - offsetForWidth, fromy);
glVertex2f(fromx + offsetForWidth, fromy);
glVertex2f(fromx + offsetForWidth, toy);
glVertex2f(fromx - offsetForWidth, toy);
glEnd();
return;
}
if (fromy == toy) //horisontal
{
const float offsetForWidth = width * 0.5f;
glBegin(GL_QUADS);
glVertex2f(fromx, fromy - offsetForWidth);
glVertex2f(fromx, fromy + offsetForWidth);
glVertex2f(tox, fromy + offsetForWidth);
glVertex2f(tox, fromy - offsetForWidth);
glEnd();
return;
}
float perpm = (tox - fromx) / (fromy - toy);
float x = 0.5f * width / sqrtf(perpm * perpm + 1.f);
float y = x * perpm;
glBegin(GL_QUADS);
glVertex2f(fromx + x, fromy + y);
glVertex2f(tox + x, toy + y);
glVertex2f(tox - x, toy - y);
glVertex2f(fromx - x, fromy - y);
glEnd();
}

ScottM
01-14-2008, 08:57 AM
Ah, you should have said that you have an intel video :) Intel is known for very poor OpenGL support, unfortunately.

In which case, %^$&%& Intel. That probably means my application, which is of most use to people on laptops, which often have integrated intel video, isn't likely to work for others.

There ought to be a law. Other than Microsoft's, I mean...