2019-01-30 22:31:29 -05:00
|
|
|
// pathfinder/gl/src/debug.rs
|
2019-01-30 17:42:06 -05:00
|
|
|
//
|
|
|
|
// Copyright © 2019 The Pathfinder Project Developers.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2019-01-30 22:31:29 -05:00
|
|
|
//! A debug overlay.
|
2019-01-30 17:42:06 -05:00
|
|
|
//!
|
|
|
|
//! We don't render the demo UI text using Pathfinder itself so that we can use the debug UI to
|
|
|
|
//! debug Pathfinder if it's totally busted.
|
|
|
|
//!
|
|
|
|
//! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/
|
|
|
|
|
|
|
|
use crate::device::{Buffer, BufferTarget, BufferUploadMode, Program, Texture, Uniform, VertexAttr};
|
2019-02-05 13:55:01 -05:00
|
|
|
use euclid::Size2D;
|
2019-01-30 17:42:06 -05:00
|
|
|
use gl::types::{GLfloat, GLint, GLsizei, GLuint};
|
|
|
|
use gl;
|
2019-02-05 13:55:01 -05:00
|
|
|
use pathfinder_geometry::basic::point::Point2DI32;
|
|
|
|
use pathfinder_geometry::basic::rect::RectI32;
|
2019-01-30 17:42:06 -05:00
|
|
|
use pathfinder_renderer::paint::ColorU;
|
|
|
|
use serde_json;
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::fs::File;
|
|
|
|
use std::io::BufReader;
|
|
|
|
use std::ptr;
|
|
|
|
use std::time::Duration;
|
|
|
|
|
2019-02-06 23:59:29 -05:00
|
|
|
const DEBUG_TEXTURE_VERTEX_SIZE: GLint = 8;
|
|
|
|
const DEBUG_SOLID_VERTEX_SIZE: GLint = 4;
|
2019-01-30 17:42:06 -05:00
|
|
|
|
2019-02-07 17:07:05 -05:00
|
|
|
const PERF_WINDOW_WIDTH: i32 = 300;
|
|
|
|
const PERF_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 2 + PADDING + 2;
|
|
|
|
const EFFECTS_WINDOW_WIDTH: i32 = 400;
|
|
|
|
const EFFECTS_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 3 + PADDING + 2;
|
2019-02-05 13:55:01 -05:00
|
|
|
const PADDING: i32 = 12;
|
|
|
|
const FONT_ASCENT: i32 = 28;
|
|
|
|
const LINE_HEIGHT: i32 = 42;
|
2019-02-06 23:59:29 -05:00
|
|
|
const ICON_SIZE: i32 = 48;
|
|
|
|
const BUTTON_WIDTH: i32 = PADDING * 2 + ICON_SIZE;
|
|
|
|
const BUTTON_HEIGHT: i32 = PADDING * 2 + ICON_SIZE;
|
2019-02-07 17:07:05 -05:00
|
|
|
const SWITCH_HALF_SIZE: i32 = 64;
|
|
|
|
const SWITCH_SIZE: i32 = PADDING * 2 + SWITCH_HALF_SIZE * 2 - 1;
|
2019-01-30 17:42:06 -05:00
|
|
|
|
2019-02-07 17:07:05 -05:00
|
|
|
static WINDOW_COLOR: ColorU = ColorU { r: 30, g: 30, b: 30, a: 255 - 30 };
|
|
|
|
static TEXT_COLOR: ColorU = ColorU { r: 255, g: 255, b: 255, a: 255 };
|
2019-01-30 17:42:06 -05:00
|
|
|
|
|
|
|
static JSON_PATH: &'static str = "resources/debug-font.json";
|
2019-02-06 23:59:29 -05:00
|
|
|
|
2019-02-07 17:07:05 -05:00
|
|
|
static EFFECTS_PNG_NAME: &'static str = "debug-effects";
|
2019-02-06 23:59:29 -05:00
|
|
|
static FONT_PNG_NAME: &'static str = "debug-font";
|
2019-02-07 17:07:05 -05:00
|
|
|
static OPEN_PNG_NAME: &'static str = "debug-open";
|
2019-01-30 17:42:06 -05:00
|
|
|
|
|
|
|
static QUAD_INDICES: [u32; 6] = [0, 1, 3, 1, 2, 3];
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
#[allow(dead_code)]
|
|
|
|
pub struct DebugFont {
|
|
|
|
name: String,
|
|
|
|
size: i32,
|
|
|
|
bold: bool,
|
|
|
|
italic: bool,
|
|
|
|
width: u32,
|
|
|
|
height: u32,
|
|
|
|
characters: HashMap<char, DebugCharacter>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
struct DebugCharacter {
|
2019-02-05 13:55:01 -05:00
|
|
|
x: i32,
|
|
|
|
y: i32,
|
|
|
|
width: i32,
|
|
|
|
height: i32,
|
2019-01-30 17:42:06 -05:00
|
|
|
#[serde(rename = "originX")]
|
2019-02-05 13:55:01 -05:00
|
|
|
origin_x: i32,
|
2019-01-30 17:42:06 -05:00
|
|
|
#[serde(rename = "originY")]
|
2019-02-05 13:55:01 -05:00
|
|
|
origin_y: i32,
|
|
|
|
advance: i32,
|
2019-01-30 17:42:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DebugFont {
|
|
|
|
fn load() -> DebugFont {
|
|
|
|
serde_json::from_reader(BufReader::new(File::open(JSON_PATH).unwrap())).unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct DebugRenderer {
|
|
|
|
framebuffer_size: Size2D<u32>,
|
2019-02-06 23:59:29 -05:00
|
|
|
texture_program: DebugTextureProgram,
|
|
|
|
texture_vertex_array: DebugTextureVertexArray,
|
2019-01-30 17:42:06 -05:00
|
|
|
font: DebugFont,
|
|
|
|
solid_program: DebugSolidProgram,
|
|
|
|
solid_vertex_array: DebugSolidVertexArray,
|
2019-02-06 23:59:29 -05:00
|
|
|
font_texture: Texture,
|
2019-02-07 17:07:05 -05:00
|
|
|
effects_texture: Texture,
|
|
|
|
open_texture: Texture,
|
2019-01-30 17:42:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DebugRenderer {
|
|
|
|
pub fn new(framebuffer_size: &Size2D<u32>) -> DebugRenderer {
|
2019-02-06 23:59:29 -05:00
|
|
|
let texture_program = DebugTextureProgram::new();
|
|
|
|
let texture_vertex_array = DebugTextureVertexArray::new(&texture_program);
|
2019-01-30 17:42:06 -05:00
|
|
|
let font = DebugFont::load();
|
|
|
|
|
|
|
|
let solid_program = DebugSolidProgram::new();
|
|
|
|
let solid_vertex_array = DebugSolidVertexArray::new(&solid_program);
|
|
|
|
solid_vertex_array.index_buffer.upload(&QUAD_INDICES,
|
|
|
|
BufferTarget::Index,
|
|
|
|
BufferUploadMode::Static);
|
|
|
|
|
2019-02-06 23:59:29 -05:00
|
|
|
let font_texture = Texture::from_png(FONT_PNG_NAME);
|
2019-02-07 17:07:05 -05:00
|
|
|
let effects_texture = Texture::from_png(EFFECTS_PNG_NAME);
|
|
|
|
let open_texture = Texture::from_png(OPEN_PNG_NAME);
|
2019-02-06 23:59:29 -05:00
|
|
|
|
2019-01-30 17:42:06 -05:00
|
|
|
DebugRenderer {
|
|
|
|
framebuffer_size: *framebuffer_size,
|
2019-02-06 23:59:29 -05:00
|
|
|
texture_program,
|
|
|
|
texture_vertex_array,
|
2019-01-30 17:42:06 -05:00
|
|
|
font,
|
|
|
|
solid_program,
|
|
|
|
solid_vertex_array,
|
2019-02-06 23:59:29 -05:00
|
|
|
font_texture,
|
2019-02-07 17:07:05 -05:00
|
|
|
effects_texture,
|
|
|
|
open_texture,
|
2019-01-30 17:42:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_framebuffer_size(&mut self, window_size: &Size2D<u32>) {
|
|
|
|
self.framebuffer_size = *window_size;
|
|
|
|
}
|
|
|
|
|
2019-02-02 14:36:42 -05:00
|
|
|
pub fn draw(&self, tile_time: Duration, rendering_time: Option<Duration>) {
|
2019-02-06 23:59:29 -05:00
|
|
|
// Draw performance window.
|
|
|
|
let bottom = self.framebuffer_size.height as i32 - PADDING;
|
2019-02-05 13:55:01 -05:00
|
|
|
let window_rect = RectI32::new(
|
2019-02-07 17:07:05 -05:00
|
|
|
Point2DI32::new(self.framebuffer_size.width as i32 - PADDING - PERF_WINDOW_WIDTH,
|
|
|
|
bottom - PERF_WINDOW_HEIGHT),
|
|
|
|
Point2DI32::new(PERF_WINDOW_WIDTH, PERF_WINDOW_HEIGHT));
|
2019-02-05 13:55:01 -05:00
|
|
|
self.draw_solid_rect(window_rect, WINDOW_COLOR);
|
2019-02-06 23:59:29 -05:00
|
|
|
self.draw_text(&format!("CPU: {:.3} ms", duration_ms(tile_time)),
|
2019-02-05 13:55:01 -05:00
|
|
|
Point2DI32::new(window_rect.min_x() + PADDING,
|
|
|
|
window_rect.min_y() + PADDING + FONT_ASCENT));
|
2019-01-30 18:30:40 -05:00
|
|
|
if let Some(rendering_time) = rendering_time {
|
2019-02-06 23:59:29 -05:00
|
|
|
self.draw_text(&format!("GPU: {:.3} ms", duration_ms(rendering_time)),
|
2019-02-05 13:55:01 -05:00
|
|
|
Point2DI32::new(
|
|
|
|
window_rect.min_x() + PADDING,
|
|
|
|
window_rect.min_y() + PADDING + FONT_ASCENT + LINE_HEIGHT));
|
2019-01-30 18:30:40 -05:00
|
|
|
}
|
2019-02-06 23:59:29 -05:00
|
|
|
|
2019-02-07 17:07:05 -05:00
|
|
|
// Draw effects button.
|
2019-02-06 23:59:29 -05:00
|
|
|
self.draw_solid_rect(RectI32::new(Point2DI32::new(PADDING, bottom - BUTTON_HEIGHT),
|
|
|
|
Point2DI32::new(BUTTON_WIDTH, BUTTON_HEIGHT)),
|
|
|
|
WINDOW_COLOR);
|
|
|
|
self.draw_texture(Point2DI32::new(PADDING + PADDING, bottom - BUTTON_HEIGHT + PADDING),
|
2019-02-07 17:07:05 -05:00
|
|
|
&self.effects_texture);
|
|
|
|
|
|
|
|
// Draw open button.
|
|
|
|
let open_button_x = PADDING + BUTTON_WIDTH + PADDING;
|
|
|
|
self.draw_solid_rect(RectI32::new(Point2DI32::new(open_button_x, bottom - BUTTON_HEIGHT),
|
|
|
|
Point2DI32::new(BUTTON_WIDTH, BUTTON_HEIGHT)),
|
|
|
|
WINDOW_COLOR);
|
|
|
|
self.draw_texture(Point2DI32::new(open_button_x + PADDING,
|
|
|
|
bottom - BUTTON_HEIGHT + PADDING),
|
|
|
|
&self.open_texture);
|
|
|
|
|
|
|
|
// Draw 3D switch.
|
|
|
|
let threed_switch_x = PADDING + (BUTTON_WIDTH + PADDING) * 2;
|
|
|
|
self.draw_switch(Point2DI32::new(threed_switch_x, bottom - BUTTON_HEIGHT), "2D", "3D");
|
|
|
|
|
|
|
|
// Draw effects window.
|
|
|
|
let effects_window_y = bottom - (BUTTON_HEIGHT + PADDING + EFFECTS_WINDOW_HEIGHT);
|
|
|
|
self.draw_solid_rect(RectI32::new(Point2DI32::new(PADDING, effects_window_y),
|
|
|
|
Point2DI32::new(EFFECTS_WINDOW_WIDTH,
|
|
|
|
EFFECTS_WINDOW_HEIGHT)),
|
|
|
|
WINDOW_COLOR);
|
|
|
|
let effects_text_origin = effects_window_y + PADDING + FONT_ASCENT;
|
|
|
|
self.draw_text("Gamma Correction", Point2DI32::new(PADDING * 2, effects_text_origin));
|
|
|
|
self.draw_text("Stem Darkening",
|
|
|
|
Point2DI32::new(PADDING * 2, effects_text_origin + LINE_HEIGHT));
|
|
|
|
self.draw_text("Subpixel AA",
|
|
|
|
Point2DI32::new(PADDING * 2, effects_text_origin + LINE_HEIGHT * 2));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw_switch(&self, origin: Point2DI32, off_text: &str, on_text: &str) {
|
|
|
|
//self.draw_solid_rect(RectI32::new(origin, Point2DI32::new(SWITCH_SIZE), WINDOW_COLOR);
|
|
|
|
self.draw_rect_outline(RectI32::new(origin, Point2DI32::new(SWITCH_SIZE, BUTTON_HEIGHT)),
|
|
|
|
TEXT_COLOR);
|
|
|
|
self.draw_solid_rect(RectI32::new(origin + Point2DI32::new(SWITCH_HALF_SIZE, 0),
|
|
|
|
Point2DI32::new(SWITCH_HALF_SIZE, BUTTON_HEIGHT)),
|
|
|
|
TEXT_COLOR);
|
|
|
|
self.draw_text(off_text, origin + Point2DI32::new(PADDING, PADDING + FONT_ASCENT));
|
|
|
|
self.draw_text(on_text, origin + Point2DI32::new(SWITCH_HALF_SIZE + PADDING,
|
|
|
|
PADDING + FONT_ASCENT));
|
2019-01-30 17:42:06 -05:00
|
|
|
}
|
|
|
|
|
2019-02-05 13:55:01 -05:00
|
|
|
fn draw_solid_rect(&self, rect: RectI32, color: ColorU) {
|
2019-02-07 17:07:05 -05:00
|
|
|
self.draw_rect(rect, color, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw_rect_outline(&self, rect: RectI32, color: ColorU) {
|
|
|
|
self.draw_rect(rect, color, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw_rect(&self, rect: RectI32, color: ColorU, filled: bool) {
|
2019-01-30 17:42:06 -05:00
|
|
|
let vertex_data = [
|
2019-02-05 13:55:01 -05:00
|
|
|
DebugSolidVertex::new(rect.origin()),
|
|
|
|
DebugSolidVertex::new(rect.upper_right()),
|
|
|
|
DebugSolidVertex::new(rect.lower_right()),
|
|
|
|
DebugSolidVertex::new(rect.lower_left()),
|
2019-01-30 17:42:06 -05:00
|
|
|
];
|
|
|
|
self.solid_vertex_array
|
|
|
|
.vertex_buffer
|
|
|
|
.upload(&vertex_data, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
gl::BindVertexArray(self.solid_vertex_array.gl_vertex_array);
|
|
|
|
gl::UseProgram(self.solid_program.program.gl_program);
|
|
|
|
gl::Uniform2f(self.solid_program.framebuffer_size_uniform.location,
|
|
|
|
self.framebuffer_size.width as GLfloat,
|
|
|
|
self.framebuffer_size.height as GLfloat);
|
|
|
|
gl::Uniform4f(self.solid_program.color_uniform.location,
|
|
|
|
color.r as f32 * (1.0 / 255.0),
|
|
|
|
color.g as f32 * (1.0 / 255.0),
|
|
|
|
color.b as f32 * (1.0 / 255.0),
|
|
|
|
color.a as f32 * (1.0 / 255.0));
|
|
|
|
gl::BlendEquation(gl::FUNC_ADD);
|
|
|
|
gl::BlendFunc(gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
|
|
|
|
gl::Enable(gl::BLEND);
|
2019-02-07 17:07:05 -05:00
|
|
|
if filled {
|
|
|
|
gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null());
|
|
|
|
} else {
|
|
|
|
gl::DrawArrays(gl::LINE_LOOP, 0, 4);
|
|
|
|
}
|
2019-01-30 17:42:06 -05:00
|
|
|
gl::Disable(gl::BLEND);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-05 13:55:01 -05:00
|
|
|
fn draw_text(&self, string: &str, origin: Point2DI32) {
|
|
|
|
let mut next = origin;
|
2019-01-30 17:42:06 -05:00
|
|
|
let char_count = string.chars().count();
|
|
|
|
let mut vertex_data = Vec::with_capacity(char_count * 4);
|
|
|
|
let mut index_data = Vec::with_capacity(char_count * 6);
|
|
|
|
for mut character in string.chars() {
|
|
|
|
if !self.font.characters.contains_key(&character) {
|
|
|
|
character = '?';
|
|
|
|
}
|
2019-02-05 13:55:01 -05:00
|
|
|
|
2019-01-30 17:42:06 -05:00
|
|
|
let info = &self.font.characters[&character];
|
|
|
|
let position_rect =
|
2019-02-05 13:55:01 -05:00
|
|
|
RectI32::new(Point2DI32::new(next.x() - info.origin_x, next.y() - info.origin_y),
|
|
|
|
Point2DI32::new(info.width as i32, info.height as i32));
|
|
|
|
let tex_coord_rect = RectI32::new(Point2DI32::new(info.x, info.y),
|
|
|
|
Point2DI32::new(info.width, info.height));
|
2019-01-30 17:42:06 -05:00
|
|
|
let first_vertex_index = vertex_data.len();
|
|
|
|
vertex_data.extend_from_slice(&[
|
2019-02-06 23:59:29 -05:00
|
|
|
DebugTextureVertex::new(position_rect.origin(), tex_coord_rect.origin()),
|
|
|
|
DebugTextureVertex::new(position_rect.upper_right(), tex_coord_rect.upper_right()),
|
|
|
|
DebugTextureVertex::new(position_rect.lower_right(), tex_coord_rect.lower_right()),
|
|
|
|
DebugTextureVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()),
|
2019-01-30 17:42:06 -05:00
|
|
|
]);
|
|
|
|
index_data.extend(QUAD_INDICES.iter().map(|&i| i + first_vertex_index as u32));
|
2019-02-05 13:55:01 -05:00
|
|
|
|
|
|
|
let next_x = next.x() + info.advance;
|
|
|
|
next.set_x(next_x);
|
2019-01-30 17:42:06 -05:00
|
|
|
}
|
|
|
|
|
2019-02-06 23:59:29 -05:00
|
|
|
self.draw_texture_with_vertex_data(&vertex_data, &index_data, &self.font_texture);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw_texture(&self, origin: Point2DI32, texture: &Texture) {
|
|
|
|
let size = Point2DI32::new(texture.size.width as i32, texture.size.height as i32);
|
|
|
|
let position_rect = RectI32::new(origin, size);
|
|
|
|
let tex_coord_rect = RectI32::new(Point2DI32::default(), size);
|
|
|
|
let vertex_data = [
|
|
|
|
DebugTextureVertex::new(position_rect.origin(), tex_coord_rect.origin()),
|
|
|
|
DebugTextureVertex::new(position_rect.upper_right(), tex_coord_rect.upper_right()),
|
|
|
|
DebugTextureVertex::new(position_rect.lower_right(), tex_coord_rect.lower_right()),
|
|
|
|
DebugTextureVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()),
|
|
|
|
];
|
|
|
|
|
|
|
|
self.draw_texture_with_vertex_data(&vertex_data, &QUAD_INDICES, texture);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw_texture_with_vertex_data(&self,
|
|
|
|
vertex_data: &[DebugTextureVertex],
|
|
|
|
index_data: &[u32],
|
|
|
|
texture: &Texture) {
|
|
|
|
self.texture_vertex_array
|
2019-01-30 17:42:06 -05:00
|
|
|
.vertex_buffer
|
|
|
|
.upload(&vertex_data, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
2019-02-06 23:59:29 -05:00
|
|
|
self.texture_vertex_array
|
2019-01-30 17:42:06 -05:00
|
|
|
.index_buffer
|
|
|
|
.upload(&index_data, BufferTarget::Index, BufferUploadMode::Dynamic);
|
|
|
|
|
|
|
|
unsafe {
|
2019-02-06 23:59:29 -05:00
|
|
|
gl::BindVertexArray(self.texture_vertex_array.gl_vertex_array);
|
|
|
|
gl::UseProgram(self.texture_program.program.gl_program);
|
|
|
|
gl::Uniform2f(self.texture_program.framebuffer_size_uniform.location,
|
2019-01-30 17:42:06 -05:00
|
|
|
self.framebuffer_size.width as GLfloat,
|
|
|
|
self.framebuffer_size.height as GLfloat);
|
2019-02-06 23:59:29 -05:00
|
|
|
gl::Uniform2f(self.texture_program.texture_size_uniform.location,
|
|
|
|
texture.size.width as GLfloat,
|
|
|
|
texture.size.height as GLfloat);
|
|
|
|
texture.bind(0);
|
|
|
|
gl::Uniform1i(self.texture_program.texture_uniform.location, 0);
|
2019-01-30 17:42:06 -05:00
|
|
|
gl::BlendEquation(gl::FUNC_ADD);
|
|
|
|
gl::BlendFunc(gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
|
|
|
|
gl::Enable(gl::BLEND);
|
|
|
|
gl::DrawElements(gl::TRIANGLES,
|
|
|
|
index_data.len() as GLsizei,
|
|
|
|
gl::UNSIGNED_INT,
|
|
|
|
ptr::null());
|
|
|
|
gl::Disable(gl::BLEND);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-06 23:59:29 -05:00
|
|
|
struct DebugTextureVertexArray {
|
2019-01-30 17:42:06 -05:00
|
|
|
gl_vertex_array: GLuint,
|
|
|
|
vertex_buffer: Buffer,
|
|
|
|
index_buffer: Buffer,
|
|
|
|
}
|
|
|
|
|
2019-02-06 23:59:29 -05:00
|
|
|
impl DebugTextureVertexArray {
|
|
|
|
fn new(debug_texture_program: &DebugTextureProgram) -> DebugTextureVertexArray {
|
2019-01-30 17:42:06 -05:00
|
|
|
let vertex_buffer = Buffer::new();
|
|
|
|
let index_buffer = Buffer::new();
|
|
|
|
let mut gl_vertex_array = 0;
|
|
|
|
unsafe {
|
2019-02-06 23:59:29 -05:00
|
|
|
let position_attr = VertexAttr::new(&debug_texture_program.program, "Position");
|
|
|
|
let tex_coord_attr = VertexAttr::new(&debug_texture_program.program, "TexCoord");
|
2019-01-30 17:42:06 -05:00
|
|
|
|
|
|
|
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
|
|
|
gl::BindVertexArray(gl_vertex_array);
|
2019-02-06 23:59:29 -05:00
|
|
|
gl::UseProgram(debug_texture_program.program.gl_program);
|
2019-01-30 17:42:06 -05:00
|
|
|
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
|
|
|
position_attr.configure_float(2,
|
|
|
|
gl::UNSIGNED_SHORT,
|
|
|
|
false,
|
2019-02-06 23:59:29 -05:00
|
|
|
DEBUG_TEXTURE_VERTEX_SIZE,
|
2019-01-30 17:42:06 -05:00
|
|
|
0,
|
|
|
|
0);
|
|
|
|
tex_coord_attr.configure_float(2,
|
|
|
|
gl::UNSIGNED_SHORT,
|
|
|
|
false,
|
2019-02-06 23:59:29 -05:00
|
|
|
DEBUG_TEXTURE_VERTEX_SIZE,
|
2019-01-30 17:42:06 -05:00
|
|
|
4,
|
|
|
|
0);
|
|
|
|
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer.gl_buffer);
|
|
|
|
}
|
|
|
|
|
2019-02-06 23:59:29 -05:00
|
|
|
DebugTextureVertexArray { gl_vertex_array, vertex_buffer, index_buffer }
|
2019-01-30 17:42:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-06 23:59:29 -05:00
|
|
|
impl Drop for DebugTextureVertexArray {
|
2019-01-30 17:42:06 -05:00
|
|
|
#[inline]
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct DebugSolidVertexArray {
|
|
|
|
gl_vertex_array: GLuint,
|
|
|
|
vertex_buffer: Buffer,
|
|
|
|
index_buffer: Buffer,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DebugSolidVertexArray {
|
|
|
|
fn new(debug_solid_program: &DebugSolidProgram) -> DebugSolidVertexArray {
|
|
|
|
let vertex_buffer = Buffer::new();
|
|
|
|
let index_buffer = Buffer::new();
|
|
|
|
let mut gl_vertex_array = 0;
|
|
|
|
unsafe {
|
|
|
|
let position_attr = VertexAttr::new(&debug_solid_program.program, "Position");
|
|
|
|
|
|
|
|
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
|
|
|
gl::BindVertexArray(gl_vertex_array);
|
|
|
|
gl::UseProgram(debug_solid_program.program.gl_program);
|
|
|
|
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
|
|
|
position_attr.configure_float(2,
|
|
|
|
gl::UNSIGNED_SHORT,
|
|
|
|
false,
|
|
|
|
DEBUG_SOLID_VERTEX_SIZE,
|
|
|
|
0,
|
|
|
|
0);
|
|
|
|
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer.gl_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
DebugSolidVertexArray { gl_vertex_array, vertex_buffer, index_buffer }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for DebugSolidVertexArray {
|
|
|
|
#[inline]
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-06 23:59:29 -05:00
|
|
|
struct DebugTextureProgram {
|
2019-01-30 17:42:06 -05:00
|
|
|
program: Program,
|
|
|
|
framebuffer_size_uniform: Uniform,
|
2019-02-06 23:59:29 -05:00
|
|
|
texture_size_uniform: Uniform,
|
|
|
|
texture_uniform: Uniform,
|
2019-01-30 17:42:06 -05:00
|
|
|
}
|
|
|
|
|
2019-02-06 23:59:29 -05:00
|
|
|
impl DebugTextureProgram {
|
|
|
|
fn new() -> DebugTextureProgram {
|
|
|
|
let program = Program::new("debug_texture");
|
2019-01-30 17:42:06 -05:00
|
|
|
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
2019-02-06 23:59:29 -05:00
|
|
|
let texture_size_uniform = Uniform::new(&program, "TextureSize");
|
|
|
|
let texture_uniform = Uniform::new(&program, "Texture");
|
|
|
|
DebugTextureProgram {
|
2019-01-30 17:42:06 -05:00
|
|
|
program,
|
|
|
|
framebuffer_size_uniform,
|
2019-02-06 23:59:29 -05:00
|
|
|
texture_size_uniform,
|
|
|
|
texture_uniform,
|
2019-01-30 17:42:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct DebugSolidProgram {
|
|
|
|
program: Program,
|
|
|
|
framebuffer_size_uniform: Uniform,
|
|
|
|
color_uniform: Uniform,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DebugSolidProgram {
|
|
|
|
fn new() -> DebugSolidProgram {
|
|
|
|
let program = Program::new("debug_solid");
|
|
|
|
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
|
|
|
let color_uniform = Uniform::new(&program, "Color");
|
|
|
|
DebugSolidProgram { program, framebuffer_size_uniform, color_uniform }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
#[allow(dead_code)]
|
2019-02-06 23:59:29 -05:00
|
|
|
struct DebugTextureVertex {
|
2019-01-30 17:42:06 -05:00
|
|
|
position_x: i16,
|
|
|
|
position_y: i16,
|
|
|
|
tex_coord_x: u16,
|
|
|
|
tex_coord_y: u16,
|
|
|
|
}
|
|
|
|
|
2019-02-06 23:59:29 -05:00
|
|
|
impl DebugTextureVertex {
|
|
|
|
fn new(position: Point2DI32, tex_coord: Point2DI32) -> DebugTextureVertex {
|
|
|
|
DebugTextureVertex {
|
2019-02-05 13:55:01 -05:00
|
|
|
position_x: position.x() as i16,
|
|
|
|
position_y: position.y() as i16,
|
|
|
|
tex_coord_x: tex_coord.x() as u16,
|
|
|
|
tex_coord_y: tex_coord.y() as u16,
|
2019-01-30 17:42:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
#[allow(dead_code)]
|
|
|
|
struct DebugSolidVertex {
|
|
|
|
position_x: i16,
|
|
|
|
position_y: i16,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DebugSolidVertex {
|
2019-02-05 13:55:01 -05:00
|
|
|
fn new(position: Point2DI32) -> DebugSolidVertex {
|
|
|
|
DebugSolidVertex { position_x: position.x() as i16, position_y: position.y() as i16 }
|
2019-01-30 17:42:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn duration_ms(time: Duration) -> f64 {
|
|
|
|
time.as_secs() as f64 * 1000.0 + time.subsec_nanos() as f64 / 1000000.0
|
|
|
|
}
|