PistonDevelopers / gfx_text

Draw text for gfx using freetype
http://docs.piston.rs/gfx_text/gfx_text/
MIT License
22 stars 12 forks source link

Multiple calls to draw_end on the same text seems to erase previous calls' result partially. #13

Closed LaylBongers closed 9 years ago

LaylBongers commented 9 years ago

The following example code:

extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate gfx_text;

use gfx::traits::{IntoCanvas, Stream};
use gfx_window_glutin as gfxw;
use glutin::{WindowBuilder, Event, VirtualKeyCode, GL_CORE};

const BROWN: [f32; 4] = [0.65, 0.16, 0.16, 1.0];
const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];

fn main() {
    let mut canvas = {
        let window = WindowBuilder::new()
            .with_dimensions(640, 480)
            .with_title(format!("gfx_text example"))
            .with_gl(GL_CORE)
            .build()
            .unwrap();
        gfxw::init(window).into_canvas()
    };

    let mut normal_text = gfx_text::new(&mut canvas.factory).unwrap();

    'main: loop {
        for event in canvas.output.window.poll_events() {
            match event {
                Event::Closed => break 'main,
                Event::KeyboardInput(_, _, Some(VirtualKeyCode::Escape)) => break 'main,
                _ => {},
            }
        }
        canvas.clear(gfx::ClearData {color: [1.0, 1.0, 1.0, 1.0], depth: 1.0, stencil: 0});

        normal_text.draw("The quick brown fox jumps over the lazy dog", [10, 10], BROWN);
        normal_text.draw_end(&mut canvas).unwrap();

        normal_text.draw("The quick brown fox jumps over the lazy dog", [30, 30], BROWN);
        normal_text.draw_end(&mut canvas).unwrap();

        normal_text.draw("The quick red fox jumps over the lazy dog", [50, 50], RED);
        normal_text.draw_end(&mut canvas).unwrap();

        canvas.present();
    }
}

Will give the following result:

This causes problems in applications where multiple calls to draw_end are done for layering.

kvark commented 9 years ago

Looks interesting. Is it a blocker for someone?

LaylBongers commented 9 years ago

It is for Phosphorus

kvark commented 9 years ago

@LaylConway first off, you are calling draw_end after each draw. I don't think it's meant to be used this way. draw_end should only be used once, I believe, but it's up to @Kagami to decide.

What's happening is - draw commands are queued but the vertex buffer gets rewritten multiple times before even the first command executes. The reason gfx-rs doesn't complain is this only "easy" bug - https://github.com/gfx-rs/gfx-rs/issues/139. Also, we are exploring better ways to make this kind of use case working in https://github.com/gfx-rs/gfx-rs/issues/730

The problem could be solved in one of the following ways:

  1. We force draw_end to only be called once per frame somehow
  2. We change the logic to queue buffer changes instead of modifying them instantly

I'm going to implement way-2 as the least restrictive one now in a PR.

LaylBongers commented 9 years ago

Calling draw_end only once in a frame is not an option when I need to do complex layering with text. It would mean I need a new text object for every single piece of text I need do draw. Trying this tanked the framerate way too bad.

Edit: To clarify, there's a reason I'm calling draw_end more often, it's just not shown in this quick example.

kvark commented 9 years ago

@LaylConway why would you need a new text object?

LaylBongers commented 9 years ago

@kvark If I can only call draw_end once on a text renderer object per frame, I would need multiple of them to draw multiple times per frame right?

kvark commented 9 years ago

@LaylConway no, you can call draw multiple times before calling draw_end. For example, remove all draw_end but the last in the code you posted - it works.

LaylBongers commented 9 years ago

But I assume draw_end does the actual drawing. This means that if I want to draw text, a square on top of it, then more text, I can't call draw_end at the end of it all.

kvark commented 9 years ago

I see what you mean. Fix is coming, hold on ;)

LaylBongers commented 9 years ago

I'm calling it a day for now, I'll tomorrow check on a fix, I'll have to merge it up with the changes I'm using to allow usage of a stream.

Kagami commented 9 years ago

I don't think it's meant to be used this way. draw_end should only be used once, I believe

Yes, it meant to be used that way: one draw_end for one text instance on each frame. But your fix is also nice.