Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Camera2D.render_target is upside-down #171

Open
brianwp3000 opened this issue Mar 16, 2021 · 12 comments
Open

Camera2D.render_target is upside-down #171

brianwp3000 opened this issue Mar 16, 2021 · 12 comments

Comments

@brianwp3000
Copy link
Contributor

The render_target field of a Camera2D is upside-down. I have included a repro--the gist is that if you draw a texture to a render_target and then draw that render_target to the screen the texture appears upside-down.

use macroquad::prelude::*;

#[macroquad::main("Texture")]
async fn main() {
    let mut render_target_camera = Camera2D::from_display_rect(Rect::new(0., 0., 800., 600.));
    render_target_camera.render_target = Some(render_target(800, 600));

    let ferris_texture: Texture2D = load_texture("examples/ferris.png").await;

    loop {
        // draw Ferris to the render_target texture
        set_camera(render_target_camera);

        clear_background(RED);
        draw_texture(
            ferris_texture,
            0.,
            0.,
            WHITE,
        );

        // draw the render_target texture to the screen
        set_camera(Camera2D::from_display_rect(Rect::new(0., 0., 800., 600.)));

        draw_texture(
            render_target_camera.render_target.unwrap().texture,
            0.,
            0.,
            WHITE,
        );

        next_frame().await
    }
}

image

@nicolas-sabbatini
Copy link

I have the same issue in macroquad version 0.3.0-alpha.15.

For now I am using:

draw_texture_ex(
      TEXTURE,
      0.0,
      0.0,
      WHITE,
      DrawTextureParams {
        flip_y: true,
        ..Default::default()
      },
    );

As a temporary solution works.

@martin-t
Copy link
Contributor

The behavior depends on whether there's a render target or not.

use macroquad::prelude::*;

#[macroquad::main("Camera bug")]
async fn main() {
    let render_target = render_target(600, 400);
    let rect = Rect::new(0.0, 0.0, 600.0, 400.0);
    let mut camera = Camera2D::from_display_rect(rect);
    //camera.zoom.y = -camera.zoom.y; // uncomment this to fix
    camera.render_target = Some(render_target); // or comment out this to fix

    loop {
        set_camera(&camera);

        clear_background(BLANK);
        draw_text("test", 50.0, 50.0, 32.0, GREEN);
        draw_line(0.0, 0.0, 300.0, 300.0, 1.0, GREEN);

        set_default_camera();
        draw_texture(render_target.texture, 0.0, 0.0, WHITE);

        next_frame().await
    }
}

When using a camera without a render_target set, from_display_rect works correctly. When there is a render target, however, it needs to be flipped (either when rendering it to screen or when setting up the camera).

I thought the culprit is the minus sign in zoom: vec2(1. / rect.w * 2., -1. / rect.h * 2.), in Camera2D::from_display_rect but and reported it on Discord but was dismissed - i didn't know at the time it only happened when using a render target. It seems the fix needs to be somewhere else because removing the minus sign would break rendering to screen directly.

@eboatwright
Copy link
Contributor

This is definitely an issue, but yeah you can just work around it :)

@GreenSlimeStudios
Copy link

I have experienced the same issue but you can just set the camera rotation to 180 degrees (or +180 degrees if you want to rotate it around in the game)

@not-fl3
Copy link
Owner

not-fl3 commented Aug 24, 2022

The problem here - there are way too many projects already that have this scale: vec2(1, -1)(or flip_y: true) in their cameras.

So we are waiting for the fix for some major macroquad update, to break all the things altogether.

@eboatwright
Copy link
Contributor

@not-fl3 That makes sense

@not-fl3
Copy link
Owner

not-fl3 commented Jul 19, 2023

I just runned the OP code in macroquad 0.4

use macroquad::prelude::*;

#[macroquad::test]
async fn test_camera_y() {
    let mut render_target_camera = Camera2D::from_display_rect(Rect::new(0., 0., 800., 600.));
    render_target_camera.render_target = Some(render_target(800, 600));

    let ferris_texture = load_texture("examples/ferris.png").await.unwrap();

    for _ in 0..100 {
        // draw Ferris to the render_target texture
        set_camera(&render_target_camera);

        clear_background(RED);
        draw_texture(&ferris_texture, 0., 0., WHITE);

        // draw the render_target texture to the screen
        set_camera(&Camera2D::from_display_rect(Rect::new(0., 0., 800., 600.)));

        draw_texture(
            &render_target_camera.render_target.as_ref().unwrap().texture,
            0.,
            0.,
            WHITE,
        );

        next_frame().await
    }
}

and the ferris is not upside down:

image

But there are reports on discord that the issue still persists?
If someone knows how I can reproduce it in 0.4 - please, post it here :)

@ollej
Copy link
Contributor

ollej commented Jul 19, 2023

This works for me with 0.4.1 on a Mac.

It looks like it's flipped when using set_default_camera() though.

use macroquad::prelude::*;

#[macroquad::main("Test")]
async fn main() {
    let mut render_target_camera = Camera2D::from_display_rect(Rect::new(0., 0., 800., 600.));
    render_target_camera.render_target = Some(render_target(800, 600));

    let ferris_texture = load_texture("ferris.png").await.unwrap();

    for _ in 0..100 {
        // draw Ferris to the render_target texture
        set_camera(&render_target_camera);

        clear_background(RED);
        draw_texture(&ferris_texture, 0., 0., WHITE);

        // draw the render_target texture to the screen
        //set_camera(&Camera2D::from_display_rect(Rect::new(0., 0., 800., 600.)));
        set_default_camera();

        draw_texture(
            &render_target_camera.render_target.as_ref().unwrap().texture,
            0.,
            0.,
            WHITE,
        );

        next_frame().await
    }
}

@martin-t
Copy link
Contributor

Confirming that the issue still happens in ollej's example using set_default_camera but not in not-fl3's example with set_camera.

@mandroll
Copy link
Contributor

mandroll commented May 8, 2024

I have just updated my project from 0.3.24 to 0.4.5 and ran into this. The y-axis of my program has been reversed.

Here is a minimal example:

use macroquad::prelude::*;

#[macroquad::main("example")]
async fn main() {
    let camera = Camera2D {
        target: vec2(0.0, 0.0),
        zoom: vec2(1.0 / screen_width() * 2., -1.0 / screen_height() * 2.),
        offset: vec2(0., 0.),
        rotation: 0.,
        render_target: None,
        viewport: None,
    };
    let top_left = camera.screen_to_world(vec2(0.0, 0.0));
    println!("top left: {:?}", top_left);
}
# 0.3.24
top left: Vec2(-400.0, -300.0)
# 0.4.5
top left: Vec2(-400.0, 300.0)

@profan
Copy link
Sponsor Contributor

profan commented May 8, 2024

I have just updated my project from 0.3.24 to 0.4.5 and ran into this. The y-axis of my program has been reversed.

Here is a minimal example:

use macroquad::prelude::*;

#[macroquad::main("example")]
async fn main() {
    let camera = Camera2D {
        target: vec2(0.0, 0.0),
        zoom: vec2(1.0 / screen_width() * 2., -1.0 / screen_height() * 2.),
        offset: vec2(0., 0.),
        rotation: 0.,
        render_target: None,
        viewport: None,
    };
    let top_left = camera.screen_to_world(vec2(0.0, 0.0));
    println!("top left: {:?}", top_left);
}
# 0.3.24
top left: Vec2(-400.0, -300.0)
# 0.4.5
top left: Vec2(-400.0, 300.0)

Ha, I too performed the same upgrade and ended up experiencing the same change not long ago!

It's extra funky because I'm using Camera2D for some render target stuff as well and it seems like just flipping it everywhere doesn't do quite the right thing, for example here: https:/profan/some-macroquad-things/blob/master/territory/src/main.rs

I have my own Camera2DExt::from_display_rect_fixed but use the normal old from_display_rect for my render target case, so I wonder what caused this upstream?

@PSteinhaus
Copy link

PSteinhaus commented Jun 4, 2024

I have my own Camera2DExt::from_display_rect_fixed but use the normal old from_display_rect for my render target case, so I wonder what caused this upstream?

I'd guess the relevant change was 3887953, as it flips the zoom only for from_display_rect while leaving the default unflipped.

Also just ran into this by accident, playing around with the camera for the first time.

Reminds me of how we broke source rects in draw params between versions back then in ggez. Good times.

EDIT: I also just stumbled over these lines in the matrix function for Camera2D:

macroquad/src/camera.rs

Lines 96 to 100 in 4e27d18

let invert_y = if self.render_target.is_some() {
1.0
} else {
-1.0
};

What they do seems to fit the definition of turning everything upside down if there's a render_target ^^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants