Jump to content
  • Advertisement
Sign in to follow this  
null;

SDL 2 Zooming In and Out

This topic is 606 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I recently got into SDL 2 in C++. I've implemented a camera into the game, and was wondering how I would go about zooming. I've tried doing many things, but I won't go into detail because I don't think I'm on the right track at all.

 

If any of you have implemented zooming in/out into your game, can you specify how you actually did it?

 

Thanks to everyone who replies.

Share this post


Link to post
Share on other sites
Advertisement
The trick is to think in terms of coordinate spaces. The screen space is different from the world space. The screen is measured in pixels (px), where +X is to the right, +Y is toward the bottom of the screen, and (0 px,0 px) is the top left corner of the screen. The world is measured in units or meters (m) as defined by a camera. The camera then sets up the world space such that (cam.x m, cam.y m) is the center of the screen, +X is toward the right, and +Y is toward the top of the screen, and 1 m is some number of pixels. Drawing an 1 m sized object at (0, 0) should draw an object of N pixels centered to the screen.


So, now comes the actual transformation. I like to use matrices:
# assuming:  cam = {x: 0,  y: 0,  scale: gfx_w/40}

# these transforms are executed from last to first, because math
mvp =  mat3.identity!
mvp *= mat3.scale      1, -1             # invert the Y axis
mvp *= mat3.translate  gfx_w/2, gfx_h/2  # translate to center of screen
mvp *= mat3.rotate     cam.rotation      # rotate camera
mvp *= mat3.scale      cam.scale         # convert from units to pixels, 1 unit = gfx_w/40 pixels
mvp *= mat3.translate  -cam.x, -cam.y    # make (cam.x, cam.y) the center of the screen

# the result of (mvp * player.pos) transforms the player’s position in world space to screen space
# with respect to the camera— this is typically done in a shader
shader.set     "transform", mvp
graphics.draw  player.shape, player.pos.x, player.pos.y, player.size

Matrices can make these transformations easier to read, though you can carry these transformations out by hand:
float2 center = float2   gfx_w/2, gfx_h/2
float2 inv_y  = float2   1, -1
float2 cam_u  = float2   (cos cam.rotation), (sin cam.rotation)
float2 cam_v  = float2  -(sin cam.rotation), (cos cam.rotation)


float2 pos_cam    = player.pos - cam.pos
float2 pos_px     = (cam_u*pos_cam.x + cam_v*pos_cam.y) * cam.scale
float2 pos_screen = pos_px * inv_y + center
Then, controlling the zoom is just a matter of changing `cam.scale` :^) Edited by fastcall22

Share this post


Link to post
Share on other sites

The trick is to think in terms of coordinate spaces. The screen space is different from the world space. The screen is measured in pixels (px), where +X is to the right, +Y is toward the bottom of the screen, and (0 px,0 px) is the top left corner of the screen. The world is measured in units or meters (m) as defined by a camera. The camera then sets up the world space such that (cam.x m, cam.y m) is the center of the screen, +X is toward the right, and +Y is toward the top of the screen, and 1 m is some number of pixels. Drawing an 1 m sized object at (0, 0) should draw an object of N pixels centered to the screen.


So, now comes the actual transformation. I like to use matrices:

# assuming:  cam = {x: 0,  y: 0,  scale: gfx_w/40}

# these transforms are executed from last to first, because math
mvp =  mat3.identity!
mvp *= mat3.scale      1, -1             # invert the Y axis
mvp *= mat3.translate  gfx_w/2, gfx_h/2  # translate to center of screen
mvp *= mat3.rotate     cam.rotation      # rotate camera
mvp *= mat3.scale      cam.scale         # convert from units to pixels, 1 unit = gfx_w/40 pixels
mvp *= mat3.translate  -cam.x, -cam.y    # make (cam.x, cam.y) the center of the screen

# the result of (mvp * player.pos) transforms the player’s position in world space to screen space
# with respect to the camera— this is typically done in a shader
shader.set     "transform", mvp
graphics.draw  player.shape, player.pos.x, player.pos.y, player.size

Matrices can make these transformations easier to read, though you can carry these transformations out by hand:
float2 center = float2   gfx_w/2, gfx_h/2
float2 inv_y  = float2   1, -1
float2 cam_u  = float2   (cos cam.rotation), (sin cam.rotation)
float2 cam_v  = float2  -(sin cam.rotation), (cos cam.rotation)


float2 pos_cam    = player.pos - cam.pos
float2 pos_px     = (cam_u*pos_cam.x + cam_v*pos_cam.y) * cam.scale
float2 pos_screen = pos_px * inv_y + center
Then, controlling the zoom is just a matter of changing `cam.scale` :^)

 

Wow... I mean, I really appreciate the detailed reply and code examples; I just... don't really understand a lot of it.

 

I mean, here's the way I'm currently doing it (pseudocode):

 SDL_Rect camerRect = { 0, 0, 640, 480 };

in game loop:

        camerRect.x = player1.positionRect.x - 290;        camerRect.y = player1.positionRect.y - 170;


        player1.Draw(renderTarget, camerRect);
        SDL_RenderPresent(renderTarget);
        SDL_RenderClear(renderTarget);


        SDL_RenderCopy(renderTarget, mapTexture, &camerRect, NULL);
 
player draw method in player class:
 
       
 void Player::Draw(SDL_Renderer *renderTarget, SDL_Rect camerRect) {
                SDL_Rect drawingRect = { positionRect.x - camerRect.x, positionRect.y - camerRect.y, positionRect.w * 2, positionRect.h * 2};
                SDL_RenderCopy(renderTarget, texture, &cropRect, &drawingRect);
        }
 
I don't think the kind of stuff you're talking about applies to how I'm doing it - if it did, I don't really understand it...
 
Again, I really appreciate the detailed reply. I apologize for my noobness at this, lol.
Edited by Debz

Share this post


Link to post
Share on other sites

As far as I remember, that's basically x, y, width, height -- correct?

To zoom, you need to adjust width and height. It will still display on the same window, but a smaller or larger area will be used to fill the window.

 

So at 2x zoom, you'll probably want something like 0, 0, 320, 240. (2x scale = divide width and height by 2)

That said, you might have to mess around a bit with also offsetting the camera as you zoom in/out, to keep things centered. It's been a while since I used SDL for this, so I don't remember anything more specific right now.

Hope that helps =)

Share this post


Link to post
Share on other sites

As far as I remember, that's basically x, y, width, height -- correct?

To zoom, you need to adjust width and height. It will still display on the same window, but a smaller or larger area will be used to fill the window.

 

So at 2x zoom, you'll probably want something like 0, 0, 320, 240. (2x scale = divide width and height by 2)

That said, you might have to mess around a bit with also offsetting the camera as you zoom in/out, to keep things centered. It's been a while since I used SDL for this, so I don't remember anything more specific right now.

Hope that helps =)

Yeah, it really helped with the first part. I'm mad at myself for not thinking of that!

 

The problem is, this kind of only works with the background image, since the way the player is rendered differs to the way the background is rendered. I'm having a hard time explaining it at the moment, I'll post another reply when I can.

Edited by Debz

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!