PDA

View Full Version : Zooming, glDrawPixels and Invalid Raster Position



kanet77
03-19-2003, 03:13 PM
Hello fellow OpenGL experts, enthusiasts, and confused folk such as me.

I've looked for three days online and I found a lot of useful and related information, but I can't find the answer to my problem.

I'm using glDrawPixels() with some success to display a bitmap image. The problem is that I can't control the placement of the image do the degree that I desire.

I'm dealing only with 2D. The images I'm using are quite large so I don't think I want to draw a texture on a quad. Every time I need to change the image it's the difference between copying to the texture memory or copying to the frame buffer using glDrawPixels(). I don't see much difference between them and I'm pretty happy with the performace of glDrawPixels() at this point. (Or I was until I came across this problem)

I use glPixelZoom() to set the zoom factor, then copy to the screen from the bitmap in memory using glDrawPixels().

It works fine except that I want to control the placement of the image down to screen pixel precision and I can't seem to do it.

For example, if the zoom factor is 16, each image pixel will be 16x16 screen pixels. As it is, glDrawPixels() starts drawing on the image pixel boundary in the lower-left corner. But there are times when I want to draw, say, only 3/4 of the pixel in the x-dimension. In this case I want to "skip over" the left-most 4 screen pixels and draw only 12 screen pixels for image pixels along the left edge of the screen.

Here's a bare-bones version of what I'm doing:



// Set "copy from" location in the image
glPixelStorei( GL_UNPACK_SKIP_ROWS, imageY ) ;
glPixelStorei( GL_UNPACK_SKIP_PIXELS, imageX ) ;
glPixelStorei( GL_UNPACK_ROW_LENGTH, bitmapWidth ) ;

// Set zoom factor
glPixelZoom( zoomFactor, zoomFactor ) ;

// Set "draw to" location in frame buffer
glRasterPos2i( drawX, drawY ) ;

// Draw it
glDrawPixels( imageWidth, // width of displayed region
imageHeight, // height
GL_BGR_EXT, // format (24-bit BGR DIB)
GL_UNSIGNED_BYTE, // source array type
(GLvoid*)lpBitmap ) ; // pointer to image


This works as long as I don't need to begin drawing in the middle of a pixel. I should mention that the image can start in the middle of the window also. (For example, if the user zooms out so far that the entire image is visible in the window) This means my problem only occurs when part of the bitmap is "outside" of the window to the left or bottom.

I tried setting the raster position outside the window. This resulted in an invalid raster position and nothing was drawn. Before the call to glDrawPixels() I tried using this hack I found online:



// Set raster position to lower-left corner (valid raster position)
glRasterPos2i( 0, 0 ) ;

// Move to "draw to" location
glBitmap( 0, 0, 0.0f, 0.0f, (GLfloat)drawX, (GLfloat)drawY, NULL ) ;

The hack effectively starts drawing outside of the window. But it isn't working for me.

The following is how I set up my viewport and perspective, since it may be related.



void OpenGLWindow::OnSize(UINT nType, int cx, int cy)

...

// Set viewport
glViewport( 0, 0, (GLsizei) cx, (GLsizei) cy ) ;

// Set up 2D orthographic projection
glMatrixMode( GL_PROJECTION ) ;
glLoadIdentity();
gluOrtho2D( 0.0f, (GLdouble) cx, 0.0f, (GLdouble) cy ) ;

// Set up Modelview matrix
glMatrixMode( GL_MODELVIEW ) ;
glLoadIdentity() ;

...

}

So here are my questions:

1) How can I start drawing in the middle of a pixel, or alternatively, draw whole pixels but start drawing outside the window.

2) Can I use the glBitmap() trick? Why won't it work for me?

3) Does the raster position after the glBitmap() call need to be valid also? If so, can I extend my "valid raster space" past the boundaries of the window?

Wow.. I just re-read this. Sorry it's so long. I hope it doesn't scare anyone away, I just wanted to be thorough in explaining the problem.

Thanks in advance,
-tom

[This message has been edited by kanet77 (edited 03-19-2003).]

john
03-19-2003, 04:01 PM
Hello,

firstly, congratulations on a detailed description of your problem and kudos on trying to find a solution.

The simple answer to your problem is to get with the times ;-) New to OpenGL 1.3/4 (I forget which) is the ARB extension glWindowPos* -- you can set the raster position to a specific window coordinate and it ~isn't~ upset if that position is outside the window: c.f. http://oss.sgi.com/projects/ogl-sample/registry/ARB/window_pos.txt

I'm not sure why your glBitmap trickery isn't working for you. Can you elaborate on what you mean that it doesn't work? Does your rasterposition suddenly become invalidated if you move it off the window? (If this is the case, then maybe that's the properly defined behaviour, anyway.)

Anyway; try glWindowPos. It'll undoubtably make your life a lot, lot easier.

cheers,
John

(p.s., just for completeness and to give you an idea of what's going on: here is a code fragment from my project that does pretty much what you're describing: it has pixel zoom and it allows bitmaps to be scrolled off the edge of the viewport:



voidPreProcessor::renderCurrentFrame(void)
{
ImageGL img=getVisibleFrame();

/* the bottom left corner of the image is <-w/2, -h/2> */
Point3D rp=Point3D(-(double)(img.width())/2.0,
-(double)(img.height())/2.0, 0.0);

Point3D rpimg=gfxstate.getProjection()*gfxstate.getModelvi ew()*rp;

int halfvpx=gfxstate.vpDim(2)/2;
int halfvpy=gfxstate.vpDim(3)/2;

double imgpt[2]={ rpimg.x()*halfvpx+halfvpx+gfxstate.vpDim(0),
rpimg.y()*halfvpy+halfvpy+gfxstate.vpDim(1)
};

glWindowPos2fARB(imgpt[0], imgpt[1]);
glPixelZoom(getViewZoom(), getViewZoom());
img.drawPixels();
}

kanet77
03-20-2003, 11:12 AM
John,

Thank you very much for your response. I'm glad to know about the glWindowPos*() ARB extension. However, although it is the simple solution I'm not sure I can use it right now(naturally :-P). I tried simply using glWindowPos*() on the long shot it would work. When my complier reported it as an undefined identifier I started actually looking into what you suggested.

I have no experience using ARB extensions, but from what I have seen I understand the extensions at my disposal are determined by my hardware and the driver. (Correct me if I'm wrong.) I'm using a 3DLabs Oxygen GVX1. I'm using this card specifically because it supports stereo vision. Unfortunately, the latest driver is from March, 2002. Even worse, I believe 3DLabs is putting all its effort into the newer Wildcat cards and has stopped supporting the Oxygen cards.

This is the info I got using glGetString() :



Vendor: 3Dlabs

Renderer: GLINT R3 PT + GLINT Gamma

Version: 1.1.28 PT

Extensions:
GL_EXT_bgra
GL_EXT_texture_object
GL_EXT_polygon_offset
GL_WIN_swap_hint
GL_EXT_vertex_array
GL_EXT_rescale_normal
GL_EXT_texture_edge_clamp
GL_EXT_texture_env_add
GL_EXT_texture_env_combine
GL_EXT_blend_subtract
GL_EXT_blend_minmax
GL_EXT_paletted_texture
GL_EXT_shared_texture_palette
GL_HP_occlusion_test
GL_KTX_buffer_region
GL_Autodesk_valid_back_buffer_hint
GL_EXT_multi_draw_arrays


I don't know exactly what extension I'm looking for, but I don't think I have what I need. Is there a way to install other extensions? I suspect not.




glRasterPos2i( 0, 0 ) ;
glBitmap( 0, 0, 0.0f, 0.0f, -1.0f, -1.0f, NULL ) ;


This tried to set the raster position to (-1, -1) before drawing. It immediately froze my computer every time I tried. This is when I finally got fed up with the problem. And of course I couldn't output any debugging info because the program froze as soon as the problem presented itself. Even stranger, if I stepped through my code there was no problem, but when I took out the breakpoints and let it rip, the program would freeze the instant it tried to display. I had a breakpoint in the OnPaint() method. A side effect of this was that the window was never actually displayed when I stepped through my program. The point is that I've had a hard time determining the problem.

I learned a lot when I tried to answer your question about the details of my problems. For example, I had the same freeze problem if the 'dispWidth' (the number of pixels to be copied from the image) was so great that it extended past the edge of the bitmap. This happened even if the entire drawn image was contained within the window.

This made me suspect that the glBitmap() trick may not be my problem. I decided to isolate the problem so I made a copy of my whole project and stripped out everything other than the display code. For some reason I believe I got it working. I'll have to try the whole shebang to really determine. I had tried the same thing earlier with no success. I'm sure this means that I've changed some other part of my code in the interim. This is the problem with diagnosis: too many variables changing at once so it's hard to pin down a cause..


Originally posted by john:

...congratulations on a detailed description of your problem and kudos on trying to find a solution.



Well I'm glad someone appreciates it. If only I had been as thorough in my diagnosis... http://www.opengl.org/discussion_boards/ubb/rolleyes.gif

But don't feel your response was in vain. For one thing, I'll always check the extensions before I ask a question again. Additionally, this program is only a prototype and when the program is finished it will run on PCs with a newer video card. This means I may have the glWindowPos*() extension and I'll be able to take advantage of it.

Thanks again for your insight,

Cheers,
-tom

[This message has been edited by kanet77 (edited 03-20-2003).]

kanet77
03-31-2003, 02:01 PM
The video card I'm using is the only one in the office with stereo capabilities. But if I can draw one image correctly then I can draw the other one.

I tried my program out on a couple other computers and it looks like my problem is just a limitation of the video card I'm using. We're planning to get a new video card and hopefully that will fix the problem. If nothing else, we should be able to use the glWindowPos* extension, which will make life easier and take away the need to use the glBitmap hack.

My program is just a prototype. The finished product needs a video card with more RAM and higher refresh rate anyway.

Thanks for the help.

Cheers,
-tom