help function

BlitzMax Forums/OpenGL Module/help function

Cruis.In(Posted 2006) [#1]
Function setCenterAndZoom(x:Float , y:Float , Zoom:Float)


Local LeftGL:Float = x - ((GraphicsWidth() / newZoom) / 2)
Local RightGL:Float = x + ((GraphicsWidth() / newZoom) / 2)
Local ButtomGL:Float = y + ((GraphicsHeight() / newZoom) / 2)
Local TopGL:Float = y - ((GraphicsHeight() / newZoom) / 2)


glMatrixMode (GL_PROJECTION)
glLoadIdentity ()
gluOrtho2D (LeftGL, RightGL, ButtomGL,TopGL)

End Function

I am using this funciton to zoom in on the centre of the screen where my ship is located in a topdown space game. the problem is, as i zoom out, i see a viewport, where my starfield is culled... yet ships i have drawn as targetting bots, are still seen outside of this box.

so why are the stars being culled in this view box?
the view box is acting like a ship and moving away from the planet and the other two ships.

the function is called in the loop with certain parameters so the mouse wheel zooms it. i only posted the opengl code.

see this pic

i did a parallaxing field too, to see if the same thing happened with images, instead of a plotted starfield, and got the same box...

any ideas? i think the function is fine, doing what is should, but whats with the viewport thing...


Dreamora(Posted 2006) [#2]
the problem is that you divide by zoom and restrict the projection area to that resulting area.

If you zoom to a zoom level of 10 you can only use 1/100 (1/10 per axis) of your screen space ...

What you actually need to do is changing the projection matrix instead of the drawing area.


Cruis.In(Posted 2006) [#3]
What you actually need to do is changing the projection matrix instead of the drawing area.


is that much different that what i am doing?
how do i do this? commands?

why does it not block out the planet and the other two ships out of the viewport that it has created when I zoom out?

zooming in works fine btw..


Cruis.In(Posted 2008) [#4]
lol necro... any ideas on this?

still never got an answer from this guy about his suggestion

"What you actually need to do is changing the projection matrix instead of the drawing area. "

how do I do it?


ImaginaryHuman(Posted 2008) [#5]
First of all, your game world and `game world coordinates` exist in a kind of imaginary three dimensional space. This space has measurements for distances and sizes of objects but these measurements don't represent any particular `unit` of measurement. It doesn't represent inches or millimeters or miles or anything. It's just a number. If you were to place a cube in this 3D space you might decide to say okay, this cube is 100.0 along each side. But this 100.0 doesn't represent anything meaningful except for in relation to other objects in the 3D space. If you put a cube which has sides 100.0 in length next to a sphere with a diameter of 1000.0 the sphere is going to be 10 times bigger than the cube. So 3D world coordinates only really define relative sizes, comparing one object to another. It doesn't have any meaning outside of the 3D world. Giving it some meaning is the task of the projection matrix and the viewport.

A programmer has to decide how they want to translate measurements in the 3D world into some kind of `scale` that is desirable on the screen. A programmer also has to decide what kind of scale to measure objects with, given the maximum range of numbers representable with a Float or an Integer. If for example you made a small cube have sides which measure 1 million units, and you want that cube to be the same size as a set of house keys, and you want to have this set of keys sitting in an entire planet-earth-sized world, then chances are you might not even be able to fit the size of the planet into a single Float or Integer. So you have to think about what is the biggest area of space your 3D world is going to represent and what is a `reasonable` range of units to use to represent small objects. You might even decide that your cube's edges are only 1.0 units long. In floating point numbers that's quite acceptable. Then your `planet earth` could be possibly represented as 1,000,000 units.

Once you're decided on the scale of your units of measurement and what they mean to you in the overall picture, you have to then decide how this scale translates to the screen. This is done in a few separate steps. The first step is that you have to think in terms of looking at the world through a camera lens. The camera can only see a portion of the world at one time in most cases. You have to decide what the objects in your world represent and how much of the screen space you want them to consume. If you want your cube to fill a quarter of the overall screen space, then you need to say that your camera can `see` an area of the game world twice the width and height of your cube (assuming a square screen). So if your cube is 100 units wide then your camera lens can see an area 200 units wide.

So let's assume this is what you are planning to do, and lets say your camera can see a portion of the game world 200 units wide and 150 units high - roughly the same shape as your computer screen. The area of the world, ie the range of coordinates, that the camera can see is defined by glOrtho2D. What this does is it says the left edge of the camera lens allows me to see coordinate `Left` in the game world. The right edge of the camera lens allows me to see coordinate `Right` in the game world. And so on for the top and bottom. You're specifying what coordinate in the game world maps to exactly the edges of the camera lens. Ie when you look through the camera you see those exact coordinates in the game world right at the edges of what you can see. You set up this mapping between the world coordinates and `what the camera can see` using glOrtho2D. Since you're ignoring 3D perspective I'll ignore that part too.

At this point you don't know necessarily that a world area 200 units wide shows up at 200 pixels wide on the screen. If the programmer hasn't decided to make this happen it is not fixed. In fact, the next stage in the process is to define how to scale from what view the camera sees to what area of your screen it will be projected onto. This is done with the command glViewport. This command does something different to BlitzMax's SetViewport which I'll come to later. glViewport simply specifies how the edges of the camera's view maps to the screen or window. You could say to show the edges of the camera view stretched to fill the entire screen space. Or you could say that the camera's view only fills a small window on the screen. In OpenGL, specifying glViewport to set the size of this final image area *does not* clip your drawing. All it defines is the scaling relationship between the area of game world the camera can see and the area of screen space that this view occupies. If you say that the camera can see an area of the game world 200 units wide (with glOrtho2D) and that this 200-unit-width view scales to a box 500 pixels wide on the screen (with glViewport), then anything you draw which would normally be `outside of the view of the camera` *will still be drawn*. All you're doing with glOrtho2D and glViewport is defining scale factors and locking coordinates to the edges of the camera lens. You're not saying `don't show me anything outside of the camera lens`. You're just defining a relationship of proportions and view. So even though what's `inside` the camera's view would map to an area 500 pixels wide, if your screen is 1024 pixels wide then you will also see objects to the right of and below the camera lens in the space outside the viewport.

To stop this from happening, and to confine the view to only what is seen `within` the camera lens, you can use glScissor to define a `scissor box`, ie a clipping window, which you would just happen to (don't have to) specify at the same position and size as the viewport you defined with glViewport. When switching on the `scissor test`, anything outside the scissor box would not be drawn to the screen and the `viewport` would act more like what you'd expect - ie you can only see what is seen through the physical lens. Without the scissor clipping, the camera effectively has a completely transparent lens which allows you to see through the sides.

Now what BlitzMax does is it calls glOrtho2D or similar behind the scenes, because it wants to hide this from the average user. The authors of BlitzMax decided that you would only be using a 2D screen and that therefore it would be handy if the units and measurements of `objects` on the screen would be exactly a 1-to-1 mapping to the size of pixels. So what they did is they called glOrtho2D and specified that the camera lens can see an area the same number of units wide and high as the size of your screen resolution. So if you open an 800x600 screen, glOrtho is set up to say you have a camera lens which is able to see an area of the game world 800 units wide and 600 units high. The standard viewport is defined as filling the whole screen ie 800 units by 600 units. Since this exactly matches the coordinate range which the camera can see, there is no translation needed from camera view coordinates to screen coordinates. In other words, you can just assume that if you draw a rectangle 100 `units` wide and high it will turn into a rectangle on the screen 100 pixels wide and high. What you may not know is that under the hood BlitzMax uses your objects dimensions to define units in game-world-space, not pixels. It translates them into pixel measurements, which just happen to be the same units as the world units. So then you can just think of drawing into the game world as though it is exactly the same size as the screen is able to view, making the screen seem like IT is the camera and removing the whole translation step from the programmer's thoughts - ease of use.

So behind the scenes BlitzMax sets up the area of game world which the camera can see by calling glOrtho2D, and then provides you with a SetViewport command to handle the final 2 steps - that is, to translate from game world coordinates to screen coordinates, and to then apply clipping of anything outside the viewport using a scissor test. You can call SetViewport to set a different area of the screen to be the recipient of the scaled image from the camera's view, and blitz will internally adjust the actual specification of the viewed area to make it seem like the world itself does not move. In other words, you could say to set a viewport from 50,50 to 100,100, but what blitz will do is say that viewport is 50,50-100,100 AND the camera lens can see an area of the game world from 50,50 to 100,100. If it didn't change the camera's view as well as changing the viewport you would see the top left of the game world shift to fit inside the top left of the new viewport.

One thing to keep in mind, then, is that if you are using BlitzMax's SetViewport and are thinking that you can just mix-and-match this with glOrtho2D, you are going to get some strange results. You should either use SetViewport by itself, or use glOrtho2D in combination with glViewport. You shouldn't use SetViewport with glOrtho2D because you aren't considering the effect that the scissor clipping might have, or that the viewport bounds might not be changed. I am thinking that *possibly* the problem you're having in your code is that you're not specifying the viewport yourself. If you do a glViewport and set is to 0,0 through ScreenWidth,ScreenHeight, in addition to setting glOrtho2D, I think you should be seeing a larger game world area and all graphics outside the viewport. Also make sure you switch off the scissor test, something like glDisable (GL_SCISSOR_TEST). Then if you use a full-screen viewport you would just change glOrtho to set which coordinates the camera can see.

I think the problem you're having is that you do a glLoadIdentity() which totally wipes out the projection matrix. You should know that the projection matrix is *shared* between the viewport and the orthographic projection. Both definitions of scaling/space are combined into a single projection matrix. If you're wiping the matrix out and then only calling glOrtho2D without calling glViewport, the viewport-scaling-aspect of the matrix has not been defined. Without a defined viewport, the viewport is going to be some kind of default values or maybe will have no effect at all. If there is no viewport defined, when you shrink the view of the game world by saying that the camera can see more of the world it isn't going to know how to scale from the camera lens to the screen. It could possibly act as if your viewport is the same size as the area of space that you originally were able to see with it when the projection was at its default initial setting. Especially if the scissor clipping is active this might account for the weirdness you're experiencing. I would call glOrtho2D first and then glViewport, or the other way around, but you need both.

I don't think it matters at all that you're doing a divide to get your results. You could just as easily multiply if your zoom factor increases in the opposite direction.

One other thing to keep in mind is that you are performing scaling operations from game world proportions to the aspect ratio of the camera's view to the aspect ratio of the viewport, and if these aspect ratios do not match you will get stretching/squashing.

I'm not sure if this helps or whatever and maybe I'm mistaken but I hope you get it working.


Cruis.In(Posted 2008) [#6]
the thing is that unless I use glloadidentity, the image flicks on in the beginning, then never seen again.

currently I also use setorigin to make it so that my "camera" focuses on the centre of the screen where my ship is. i tried viewports before but the viewport always moved off the screen if i set it like so

setviewport (ship.x,ship.y, width, height)

and rightly so, cause thats what i did, create a moving viewport.

however if i created it fixed, then the ship flew out of the view port lol. it would STAY with the ship.