From d2860508c04688d9c3893b2e9cdd76bd705549fc Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Tue, 22 Jul 2014 20:34:45 -0700 Subject: [PATCH 1/2] Abstract away more details of shaders into structs This allows RenderContext to not care about more details of programs in preparation for supporting more varieties. --- rendergl.rs | 273 ++++++++++++++++++++++++--------------------------- texturegl.rs | 49 +++------ 2 files changed, 144 insertions(+), 178 deletions(-) diff --git a/rendergl.rs b/rendergl.rs index c036bec..b1f1154 100755 --- a/rendergl.rs +++ b/rendergl.rs @@ -121,7 +121,7 @@ struct Buffers { flipped_texture_coordinate_buffer: GLuint, } -struct Program2D { +struct Texture2DProgram { id: GLuint, vertex_position_attr: c_int, texture_coord_attr: c_int, @@ -130,7 +130,45 @@ struct Program2D { sampler_uniform: c_int, } -struct ProgramRectangle { +impl Texture2DProgram { + fn new() -> Texture2DProgram { + let vertex_shader = load_shader(VERTEX_SHADER_SOURCE, VERTEX_SHADER); + let fragment_shader = load_shader(FRAGMENT_2D_SHADER_SOURCE, FRAGMENT_SHADER); + let program_id = init_program(vertex_shader, fragment_shader); + + Texture2DProgram { + id: program_id, + vertex_position_attr: get_attrib_location(program_id, "aVertexPosition"), + texture_coord_attr: get_attrib_location(program_id, "aTextureCoord"), + modelview_uniform: get_uniform_location(program_id, "uMVMatrix"), + projection_uniform: get_uniform_location(program_id, "uPMatrix"), + sampler_uniform: get_uniform_location(program_id, "uSampler"), + } + } + + fn bind_uniforms_and_attributes(&self, + texture: &Texture, + transform: &Matrix4, + projection_matrix: &Matrix4, + buffers: &Buffers) { + uniform_1i(self.sampler_uniform, 0); + uniform_matrix_4fv(self.modelview_uniform, false, transform.to_array()); + uniform_matrix_4fv(self.projection_uniform, false, projection_matrix.to_array()); + + bind_buffer(ARRAY_BUFFER, buffers.vertex_buffer); + vertex_attrib_pointer_f32(self.vertex_position_attr as GLuint, 3, false, 0, 0); + + bind_texture_coordinate_buffer(buffers, texture.flip); + vertex_attrib_pointer_f32(self.texture_coord_attr as GLuint, 2, false, 0, 0); + } + + fn enable_attribute_arrays(&self) { + enable_vertex_attrib_array(self.vertex_position_attr as GLuint); + enable_vertex_attrib_array(self.texture_coord_attr as GLuint); + } +} + +struct TextureRectangleProgram { id: GLuint, vertex_position_attr: c_int, texture_coord_attr: c_int, @@ -140,9 +178,64 @@ struct ProgramRectangle { size_uniform: c_int, } +impl TextureRectangleProgram { + fn new() -> TextureRectangleProgram { + let vertex_shader = load_shader(VERTEX_SHADER_SOURCE, VERTEX_SHADER); + let fragment_shader = load_shader(FRAGMENT_RECTANGLE_SHADER_SOURCE, FRAGMENT_SHADER); + let program_id = init_program(vertex_shader, fragment_shader); + + TextureRectangleProgram { + id: program_id, + vertex_position_attr: get_attrib_location(program_id, "aVertexPosition"), + texture_coord_attr: get_attrib_location(program_id, "aTextureCoord"), + modelview_uniform: get_uniform_location(program_id, "uMVMatrix"), + projection_uniform: get_uniform_location(program_id, "uPMatrix"), + sampler_uniform: get_uniform_location(program_id, "uSampler"), + size_uniform: get_uniform_location(program_id, "uSize"), + } + } + + #[cfg(target_os="linux")] + #[cfg(target_os="macos")] + fn create_if_necessary() -> Option { + use opengles::gl2::TEXTURE_RECTANGLE_ARB; + enable(TEXTURE_RECTANGLE_ARB); + Some(TextureRectangleProgram::new()) + } + + #[cfg(target_os="android")] + fn create_if_necessary() -> Option { + None + } + + fn bind_uniforms_and_attributes(&self, + texture: &Texture, + transform: &Matrix4, + projection_matrix: &Matrix4, + buffers: &Buffers) { + uniform_1i(self.sampler_uniform, 0); + uniform_2f(self.size_uniform, + texture.size.width as GLfloat, + texture.size.height as GLfloat); + uniform_matrix_4fv(self.modelview_uniform, false, transform.to_array()); + uniform_matrix_4fv(self.projection_uniform, false, projection_matrix.to_array()); + + bind_buffer(ARRAY_BUFFER, buffers.vertex_buffer); + vertex_attrib_pointer_f32(self.vertex_position_attr as GLuint, 3, false, 0, 0); + + bind_texture_coordinate_buffer(buffers, texture.flip); + vertex_attrib_pointer_f32(self.texture_coord_attr as GLuint, 2, false, 0, 0); + } + + fn enable_attribute_arrays(&self) { + enable_vertex_attrib_array(self.vertex_position_attr as GLuint); + enable_vertex_attrib_array(self.texture_coord_attr as GLuint); + } +} + pub struct RenderContext { - program_2d: Option, - program_rectangle: Option, + texture_2d_program: Texture2DProgram, + texture_rectangle_program: Option, buffers: Buffers, /// The platform-specific graphics context. @@ -150,58 +243,26 @@ pub struct RenderContext { } impl RenderContext { - fn new(compositing_context: NativeCompositingGraphicsContext, - program_2d: Option, - program_rectangle: Option) -> RenderContext { - let render_context = RenderContext { - program_2d: match program_2d { - Some(program) => { - Some(Program2D { - id: program, - vertex_position_attr: get_attrib_location(program, "aVertexPosition"), - texture_coord_attr: get_attrib_location(program, "aTextureCoord"), - modelview_uniform: get_uniform_location(program, "uMVMatrix"), - projection_uniform: get_uniform_location(program, "uPMatrix"), - sampler_uniform: get_uniform_location(program, "uSampler"), - }) - }, - None => None, - }, - program_rectangle: match program_rectangle { - Some(program) => { - Some(ProgramRectangle { - id: program, - vertex_position_attr: get_attrib_location(program, "aVertexPosition"), - texture_coord_attr: get_attrib_location(program, "aTextureCoord"), - modelview_uniform: get_uniform_location(program, "uMVMatrix"), - projection_uniform: get_uniform_location(program, "uPMatrix"), - sampler_uniform: get_uniform_location(program, "uSampler"), - size_uniform: get_uniform_location(program, "uSize"), - }) - }, - None => None, - }, - buffers: RenderContext::init_buffers(), - compositing_context: compositing_context, - }; - - match render_context.program_2d { - Some(program) => { - enable_vertex_attrib_array(program.vertex_position_attr as GLuint); - enable_vertex_attrib_array(program.texture_coord_attr as GLuint); - }, - None => {} + pub fn new(compositing_context: NativeCompositingGraphicsContext) -> RenderContext { + enable(TEXTURE_2D); + enable(BLEND); + blend_func(SRC_ALPHA, ONE_MINUS_SRC_ALPHA); + + let texture_2d_program = Texture2DProgram::new(); + texture_2d_program.enable_attribute_arrays(); + + let texture_rectangle_program = TextureRectangleProgram::create_if_necessary(); + match texture_rectangle_program { + Some(program) => program.enable_attribute_arrays(), + None => {}, } - match render_context.program_rectangle { - Some(program) => { - enable_vertex_attrib_array(program.vertex_position_attr as GLuint); - enable_vertex_attrib_array(program.texture_coord_attr as GLuint); - }, - None=> {} + RenderContext { + texture_2d_program: texture_2d_program, + texture_rectangle_program: texture_rectangle_program, + buffers: RenderContext::init_buffers(), + compositing_context: compositing_context, } - - render_context } fn init_buffers() -> Buffers { @@ -237,45 +298,11 @@ pub fn init_program(vertex_shader: GLuint, fragment_shader: GLuint) -> GLuint { program } -#[cfg(target_os="linux")] -#[cfg(target_os="macos")] -pub fn init_render_context(compositing_context: NativeCompositingGraphicsContext) -> RenderContext { - use opengles::gl2::TEXTURE_RECTANGLE_ARB; - - let vertex_2d_shader = load_shader(VERTEX_SHADER_SOURCE, VERTEX_SHADER); - let fragment_2d_shader = load_shader(FRAGMENT_2D_SHADER_SOURCE, FRAGMENT_SHADER); - let program_2d = init_program(vertex_2d_shader, fragment_2d_shader); - - let vertex_rectangle_shader = load_shader(VERTEX_SHADER_SOURCE, VERTEX_SHADER); - let fragment_rectangle_shader = load_shader(FRAGMENT_RECTANGLE_SHADER_SOURCE, FRAGMENT_SHADER); - let program_rectangle = init_program(vertex_rectangle_shader, fragment_rectangle_shader); - - enable(TEXTURE_2D); - enable(TEXTURE_RECTANGLE_ARB); - enable(BLEND); - blend_func(SRC_ALPHA, ONE_MINUS_SRC_ALPHA); - - RenderContext::new(compositing_context, Some(program_2d), Some(program_rectangle)) -} - -#[cfg(target_os="android")] -pub fn init_render_context(compositing_context: NativeCompositingGraphicsContext) -> RenderContext { - let vertex_2d_shader = load_shader(VERTEX_SHADER_SOURCE, VERTEX_SHADER); - let fragment_2d_shader = load_shader(FRAGMENT_2D_SHADER_SOURCE, FRAGMENT_SHADER); - let program_2d = init_program(vertex_2d_shader, fragment_2d_shader); - - enable(TEXTURE_2D); - enable(BLEND); - blend_func(SRC_ALPHA, ONE_MINUS_SRC_ALPHA); - - RenderContext::new(compositing_context, Some(program_2d), None) -} - -fn bind_texture_coordinate_buffer(render_context: RenderContext, flip: Flip) { +fn bind_texture_coordinate_buffer(buffers: &Buffers, flip: Flip) { match flip { - NoFlip => bind_buffer(ARRAY_BUFFER, render_context.buffers.texture_coordinate_buffer), + NoFlip => bind_buffer(ARRAY_BUFFER, buffers.texture_coordinate_buffer), VerticalFlip => { - bind_buffer(ARRAY_BUFFER, render_context.buffers.flipped_texture_coordinate_buffer) + bind_buffer(ARRAY_BUFFER, buffers.flipped_texture_coordinate_buffer) } } } @@ -285,11 +312,8 @@ pub fn bind_and_render_quad(render_context: RenderContext, transform: &Matrix4, scene_size: Size2D) { let program_id = match texture.target { - TextureTarget2D => match render_context.program_2d { - Some(program) => {program.id}, - None => {fail!("There is no shader program for texture 2D");} - }, - TextureTargetRectangle(..) => match render_context.program_rectangle { + TextureTarget2D => render_context.texture_2d_program.id, + TextureTargetRectangle(..) => match render_context.texture_rectangle_program { Some(program) => {program.id}, None => {fail!("There is no shader program for texture rectangle");} }, @@ -305,55 +329,18 @@ pub fn bind_and_render_quad(render_context: RenderContext, // Set uniforms and vertex attribute pointers. match texture.target { TextureTarget2D => { - uniform_1i(render_context.program_2d.unwrap().sampler_uniform, 0); - uniform_matrix_4fv(render_context.program_2d.unwrap().modelview_uniform, - false, - transform.to_array()); - uniform_matrix_4fv(render_context.program_2d.unwrap().projection_uniform, - false, - projection_matrix.to_array()); - - bind_buffer(ARRAY_BUFFER, render_context.buffers.vertex_buffer); - vertex_attrib_pointer_f32(render_context.program_2d.unwrap().vertex_position_attr as GLuint, - 3, - false, - 0, - 0); - - bind_texture_coordinate_buffer(render_context, texture.flip); - vertex_attrib_pointer_f32(render_context.program_2d.unwrap().texture_coord_attr as GLuint, - 2, - false, - 0, - 0); + render_context.texture_2d_program. + bind_uniforms_and_attributes(texture, + transform, + &projection_matrix, + &render_context.buffers); } - TextureTargetRectangle(size) => { - uniform_1i(render_context.program_rectangle.unwrap().sampler_uniform, 0); - uniform_2f(render_context.program_rectangle.unwrap().size_uniform, - size.width as GLfloat, - size.height as GLfloat); - uniform_matrix_4fv(render_context.program_rectangle.unwrap().modelview_uniform, - false, - transform.to_array()); - uniform_matrix_4fv(render_context.program_rectangle.unwrap().projection_uniform, - false, - projection_matrix.to_array()); - - bind_buffer(ARRAY_BUFFER, render_context.buffers.vertex_buffer); - vertex_attrib_pointer_f32(render_context.program_rectangle.unwrap().vertex_position_attr as - GLuint, - 3, - false, - 0, - 0); - - bind_texture_coordinate_buffer(render_context, texture.flip); - vertex_attrib_pointer_f32(render_context.program_rectangle.unwrap().texture_coord_attr as - GLuint, - 2, - false, - 0, - 0); + TextureTargetRectangle => { + render_context.texture_rectangle_program.unwrap(). + bind_uniforms_and_attributes(texture, + transform, + &projection_matrix, + &render_context.buffers); } } diff --git a/texturegl.rs b/texturegl.rs index e7fd6d9..8acacdc 100644 --- a/texturegl.rs +++ b/texturegl.rs @@ -36,14 +36,14 @@ pub enum TextureTarget { /// TEXTURE_2D. TextureTarget2D, /// TEXTURE_RECTANGLE_ARB, with the size included. - TextureTargetRectangle(Size2D), + TextureTargetRectangle, } impl TextureTarget { fn as_gl_target(self) -> GLenum { match self { TextureTarget2D => TEXTURE_2D, - TextureTargetRectangle(_) => TEXTURE_RECTANGLE_ARB, + TextureTargetRectangle => TEXTURE_RECTANGLE_ARB, } } } @@ -64,6 +64,9 @@ pub struct Texture { // Whether or not this texture needs to be flipped upon display. pub flip: Flip, + + // The size of this texture in device pixels. + pub size: Size2D } impl Drop for Texture { @@ -89,6 +92,7 @@ impl Zero for Texture { target: TextureTarget2D, weak: true, flip: NoFlip, + size: Size2D(0u, 0u), } } fn is_zero(&self) -> bool { @@ -110,39 +114,39 @@ impl Drop for BoundTexture { impl Texture { /// Creates a new blank texture. - pub fn new(target: TextureTarget) -> Texture { + pub fn new(target: TextureTarget, size: Size2D) -> Texture { let this = Texture { id: *gl2::gen_textures(1).get(0), target: target, weak: false, flip: NoFlip, + size: size, }; this.set_default_params(); this } pub fn new_with_buffer(buffer: &Box) -> Texture { - let (flip, target) = - Texture::texture_flip_and_target(buffer.painted_with_cpu, buffer.screen_pos.size); - let mut texture = Texture::new(target); + let (flip, target) = Texture::texture_flip_and_target(buffer.painted_with_cpu); + let mut texture = Texture::new(target, buffer.screen_pos.size); texture.flip = flip; return texture; } // Returns whether the layer should be vertically flipped. #[cfg(target_os="macos")] - fn texture_flip_and_target(cpu_painting: bool, size: Size2D) -> (Flip, TextureTarget) { + fn texture_flip_and_target(cpu_painting: bool) -> (Flip, TextureTarget) { let flip = if cpu_painting { NoFlip } else { VerticalFlip }; - (flip, TextureTargetRectangle(size)) + (flip, TextureTargetRectangle) } #[cfg(target_os="android")] - fn texture_flip_and_target(cpu_painting: bool, _: Size2D) -> (Flip, TextureTarget) { + fn texture_flip_and_target(cpu_painting: bool) -> (Flip, TextureTarget) { let flip = if cpu_painting { NoFlip } else { @@ -153,35 +157,10 @@ impl Texture { } #[cfg(target_os="linux")] - fn texture_flip_and_target(_: bool, _: Size2D) -> (Flip, TextureTarget) { + fn texture_flip_and_target(_: bool) -> (Flip, TextureTarget) { (NoFlip, TextureTarget2D) } - /// Creates a texture from an existing OpenGL texture. The texture will be deleted when this - /// `Texture` object goes out of scope. - pub fn adopt_native_texture(native_texture_id: GLuint, target: TextureTarget) -> Texture { - let this = Texture { - id: native_texture_id, - target: target, - weak: false, - flip: NoFlip, - }; - this - } - - /// Creates a texture from an existing OpenGL texture. The texture will *not* be deleted when - /// this `Texture` object goes out of scope. - pub fn wrap_native_texture(native_texture_id: GLuint, target: TextureTarget) -> Texture { - let this = Texture { - id: native_texture_id, - target: target, - weak: true, - flip: NoFlip, - }; - this.set_default_params(); - this - } - /// Returns the raw OpenGL texture underlying this texture. pub fn native_texture(&self) -> GLuint { self.id From 7e6501fbb3f2825fb0bd3c9c9044cb953fb2e4fb Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Wed, 23 Jul 2014 18:20:46 -0700 Subject: [PATCH 2/2] Add support for showing debug borders These borders show the edges of layers and tiles, to aid in debugging the layer tree. --- rendergl.rs | 187 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 163 insertions(+), 24 deletions(-) diff --git a/rendergl.rs b/rendergl.rs index b1f1154..adc181e 100755 --- a/rendergl.rs +++ b/rendergl.rs @@ -7,6 +7,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use color::Color; use layers::Layer; use layers; use scene::Scene; @@ -21,13 +22,13 @@ use libc::c_int; use opengles::gl2::{ARRAY_BUFFER, BLEND, COLOR_BUFFER_BIT, COMPILE_STATUS, FRAGMENT_SHADER}; use opengles::gl2::{LINK_STATUS, NO_ERROR, ONE_MINUS_SRC_ALPHA}; use opengles::gl2::{SRC_ALPHA, STATIC_DRAW, TEXTURE_2D, TEXTURE0}; -use opengles::gl2::{TRIANGLE_STRIP, VERTEX_SHADER, GLenum, GLfloat, GLint, GLsizei}; +use opengles::gl2::{LINE_STRIP, TRIANGLE_STRIP, VERTEX_SHADER, GLenum, GLfloat, GLint, GLsizei}; use opengles::gl2::{GLuint, active_texture, attach_shader, bind_buffer, bind_texture, blend_func}; use opengles::gl2::{buffer_data, create_program, clear, clear_color, compile_shader}; -use opengles::gl2::{create_shader, draw_arrays, enable, enable_vertex_attrib_array}; +use opengles::gl2::{create_shader, draw_arrays, enable, enable_vertex_attrib_array, disable_vertex_attrib_array}; use opengles::gl2::{gen_buffers, get_attrib_location, get_error, get_program_iv}; -use opengles::gl2::{get_shader_info_log, get_shader_iv, get_uniform_location}; -use opengles::gl2::{link_program, shader_source, uniform_1i, uniform_2f}; +use opengles::gl2::{get_shader_info_log, get_shader_iv, get_uniform_location, line_width}; +use opengles::gl2::{link_program, shader_source, uniform_1i, uniform_2f, uniform_4f}; use opengles::gl2::{uniform_matrix_4fv, use_program, vertex_attrib_pointer_f32, viewport}; use std::num::Zero; use std::rc::Rc; @@ -61,6 +62,13 @@ static FRAGMENT_RECTANGLE_SHADER_SOURCE: &'static str = " } "; +static SOLID_COLOR_FRAGMENT_SHADER_SOURCE: &'static str = " + uniform vec4 uColor; + void main(void) { + gl_FragColor = uColor; + } +"; + static VERTEX_SHADER_SOURCE: &'static str = " attribute vec3 aVertexPosition; attribute vec2 aTextureCoord; @@ -76,7 +84,7 @@ static VERTEX_SHADER_SOURCE: &'static str = " } "; -static VERTICES: [f32, ..12] = [ +static TEXTURED_QUAD_VERTICES: [f32, ..12] = [ 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, @@ -97,6 +105,19 @@ static FLIPPED_TEXTURE_COORDINATES: [f32, ..8] = [ 1.0, 0.0, ]; +static LINE_QUAD_VERTICES: [f32, ..15] = [ + 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 1.0, 1.0, 0.0, + 1.0, 0.0, 0.0, + 0.0, 0.0, 0.0, +]; + +static TILE_DEBUG_BORDER_COLOR: Color = Color { r: 0., g: 1., b: 1., a: 1.0 }; +static TILE_DEBUG_BORDER_THICKNESS: uint = 1; +static LAYER_DEBUG_BORDER_COLOR: Color = Color { r: 1., g: 0.5, b: 0., a: 1.0 }; +static LAYER_DEBUG_BORDER_THICKNESS: uint = 2; + pub fn load_shader(source_string: &str, shader_type: GLenum) -> GLuint { let shader_id = create_shader(shader_type); shader_source(shader_id, [ source_string.as_bytes() ]); @@ -116,9 +137,10 @@ pub fn load_shader(source_string: &str, shader_type: GLenum) -> GLuint { } struct Buffers { - vertex_buffer: GLuint, + textured_quad_vertex_buffer: GLuint, texture_coordinate_buffer: GLuint, flipped_texture_coordinate_buffer: GLuint, + line_quad_vertex_buffer: GLuint, } struct Texture2DProgram { @@ -155,7 +177,7 @@ impl Texture2DProgram { uniform_matrix_4fv(self.modelview_uniform, false, transform.to_array()); uniform_matrix_4fv(self.projection_uniform, false, projection_matrix.to_array()); - bind_buffer(ARRAY_BUFFER, buffers.vertex_buffer); + bind_buffer(ARRAY_BUFFER, buffers.textured_quad_vertex_buffer); vertex_attrib_pointer_f32(self.vertex_position_attr as GLuint, 3, false, 0, 0); bind_texture_coordinate_buffer(buffers, texture.flip); @@ -166,6 +188,11 @@ impl Texture2DProgram { enable_vertex_attrib_array(self.vertex_position_attr as GLuint); enable_vertex_attrib_array(self.texture_coord_attr as GLuint); } + + fn disable_attribute_arrays(&self) { + disable_vertex_attrib_array(self.vertex_position_attr as GLuint); + disable_vertex_attrib_array(self.texture_coord_attr as GLuint); + } } struct TextureRectangleProgram { @@ -220,7 +247,7 @@ impl TextureRectangleProgram { uniform_matrix_4fv(self.modelview_uniform, false, transform.to_array()); uniform_matrix_4fv(self.projection_uniform, false, projection_matrix.to_array()); - bind_buffer(ARRAY_BUFFER, buffers.vertex_buffer); + bind_buffer(ARRAY_BUFFER, buffers.textured_quad_vertex_buffer); vertex_attrib_pointer_f32(self.vertex_position_attr as GLuint, 3, false, 0, 0); bind_texture_coordinate_buffer(buffers, texture.flip); @@ -231,44 +258,104 @@ impl TextureRectangleProgram { enable_vertex_attrib_array(self.vertex_position_attr as GLuint); enable_vertex_attrib_array(self.texture_coord_attr as GLuint); } + + fn disable_attribute_arrays(&self) { + disable_vertex_attrib_array(self.vertex_position_attr as GLuint); + disable_vertex_attrib_array(self.texture_coord_attr as GLuint); + } +} + +struct SolidLineProgram { + id: GLuint, + vertex_position_attr: c_int, + modelview_uniform: c_int, + projection_uniform: c_int, + color_uniform: c_int, +} + +impl SolidLineProgram { + fn new() -> SolidLineProgram { + let vertex_shader = load_shader(VERTEX_SHADER_SOURCE, VERTEX_SHADER); + let fragment_shader = load_shader(SOLID_COLOR_FRAGMENT_SHADER_SOURCE, FRAGMENT_SHADER); + let program_id = init_program(vertex_shader, fragment_shader); + + SolidLineProgram { + id: program_id, + vertex_position_attr: get_attrib_location(program_id, "aVertexPosition"), + modelview_uniform: get_uniform_location(program_id, "uMVMatrix"), + projection_uniform: get_uniform_location(program_id, "uPMatrix"), + color_uniform: get_uniform_location(program_id, "uColor"), + } + } + + fn bind_uniforms_and_attributes(&self, + transform: &Matrix4, + projection_matrix: &Matrix4, + buffers: &Buffers, + color: Color) { + uniform_matrix_4fv(self.modelview_uniform, false, transform.to_array()); + uniform_matrix_4fv(self.projection_uniform, false, projection_matrix.to_array()); + uniform_4f(self.color_uniform, + color.r as GLfloat, + color.g as GLfloat, + color.b as GLfloat, + color.a as GLfloat); + + bind_buffer(ARRAY_BUFFER, buffers.line_quad_vertex_buffer); + vertex_attrib_pointer_f32(self.vertex_position_attr as GLuint, 3, false, 0, 0); + } + + fn enable_attribute_arrays(&self) { + enable_vertex_attrib_array(self.vertex_position_attr as GLuint); + } + + fn disable_attribute_arrays(&self) { + disable_vertex_attrib_array(self.vertex_position_attr as GLuint); + } } pub struct RenderContext { texture_2d_program: Texture2DProgram, texture_rectangle_program: Option, + solid_line_program: SolidLineProgram, buffers: Buffers, /// The platform-specific graphics context. compositing_context: NativeCompositingGraphicsContext, + + /// Whether to show lines at border and tile boundaries for debugging purposes. + show_debug_borders: bool, } impl RenderContext { - pub fn new(compositing_context: NativeCompositingGraphicsContext) -> RenderContext { + pub fn new(compositing_context: NativeCompositingGraphicsContext, + show_debug_borders: bool) -> RenderContext { enable(TEXTURE_2D); enable(BLEND); blend_func(SRC_ALPHA, ONE_MINUS_SRC_ALPHA); let texture_2d_program = Texture2DProgram::new(); - texture_2d_program.enable_attribute_arrays(); - + let solid_line_program = SolidLineProgram::new(); let texture_rectangle_program = TextureRectangleProgram::create_if_necessary(); - match texture_rectangle_program { - Some(program) => program.enable_attribute_arrays(), - None => {}, - } RenderContext { texture_2d_program: texture_2d_program, texture_rectangle_program: texture_rectangle_program, + solid_line_program: solid_line_program, buffers: RenderContext::init_buffers(), compositing_context: compositing_context, + show_debug_borders: show_debug_borders, } } fn init_buffers() -> Buffers { - let vertex_buffer = *gen_buffers(1).get(0); - bind_buffer(ARRAY_BUFFER, vertex_buffer); - buffer_data(ARRAY_BUFFER, VERTICES, STATIC_DRAW); + let textured_quad_vertex_buffer = *gen_buffers(1).get(0); + bind_buffer(ARRAY_BUFFER, textured_quad_vertex_buffer); + buffer_data(ARRAY_BUFFER, TEXTURED_QUAD_VERTICES, STATIC_DRAW); + + let line_quad_vertex_buffer = *gen_buffers(1).get(0); + bind_buffer(ARRAY_BUFFER, line_quad_vertex_buffer); + buffer_data(ARRAY_BUFFER, LINE_QUAD_VERTICES, STATIC_DRAW); let texture_coordinate_buffer = *gen_buffers(1).get(0); bind_buffer(ARRAY_BUFFER, texture_coordinate_buffer); @@ -279,9 +366,10 @@ impl RenderContext { buffer_data(ARRAY_BUFFER, FLIPPED_TEXTURE_COORDINATES, STATIC_DRAW); Buffers { - vertex_buffer: vertex_buffer, + textured_quad_vertex_buffer: textured_quad_vertex_buffer, texture_coordinate_buffer: texture_coordinate_buffer, flipped_texture_coordinate_buffer: flipped_texture_coordinate_buffer, + line_quad_vertex_buffer: line_quad_vertex_buffer, } } } @@ -312,10 +400,16 @@ pub fn bind_and_render_quad(render_context: RenderContext, transform: &Matrix4, scene_size: Size2D) { let program_id = match texture.target { - TextureTarget2D => render_context.texture_2d_program.id, + TextureTarget2D => { + render_context.texture_2d_program.enable_attribute_arrays(); + render_context.texture_2d_program.id + } TextureTargetRectangle(..) => match render_context.texture_rectangle_program { - Some(program) => {program.id}, - None => {fail!("There is no shader program for texture rectangle");} + Some(program) => { + program.enable_attribute_arrays(); + program.id + } + None => fail!("There is no shader program for texture rectangle"), }, }; @@ -347,6 +441,32 @@ pub fn bind_and_render_quad(render_context: RenderContext, // Draw! draw_arrays(TRIANGLE_STRIP, 0, 4); bind_texture(TEXTURE_2D, 0); + + match texture.target { + TextureTarget2D => render_context.texture_2d_program.disable_attribute_arrays(), + TextureTargetRectangle(..) => match render_context.texture_rectangle_program { + Some(program) => program.disable_attribute_arrays(), + None => {}, + }, + }; +} + +pub fn bind_and_render_quad_lines(render_context: RenderContext, + transform: &Matrix4, + scene_size: Size2D, + color: Color, + line_thickness: uint) { + let solid_line_program = render_context.solid_line_program; + solid_line_program.enable_attribute_arrays(); + use_program(solid_line_program.id); + let projection_matrix = ortho(0.0, scene_size.width, scene_size.height, 0.0, -10.0, 10.0); + solid_line_program.bind_uniforms_and_attributes(transform, + &projection_matrix, + &render_context.buffers, + color); + line_width(line_thickness as GLfloat); + draw_arrays(LINE_STRIP, 0, 5); + solid_line_program.disable_attribute_arrays(); } // Layer rendering @@ -363,17 +483,28 @@ impl Render for layers::Layer { render_context: RenderContext, transform: Matrix4, scene_size: Size2D) { - let origin = self.bounds.borrow().origin; - let transform = transform.translate(origin.x, origin.y, 0.0).mul(&*self.transform.borrow()); + let bounds = self.bounds.borrow(); + let transform = transform.translate(bounds.origin.x, bounds.origin.y, 0.0) + .mul(&*self.transform.borrow()); self.create_textures(&render_context.compositing_context); self.do_for_all_tiles(|tile: &Tile| { tile.render(render_context, transform, scene_size) }); + if render_context.show_debug_borders { + let quad_transform = transform.scale(bounds.size.width, bounds.size.height, 1.); + bind_and_render_quad_lines(render_context, + &quad_transform, + scene_size, + LAYER_DEBUG_BORDER_COLOR, + LAYER_DEBUG_BORDER_THICKNESS); + } + for child in self.children().iter() { child.render(render_context, transform, scene_size) } + } } @@ -388,6 +519,14 @@ impl Render for Tile { let transform = transform.mul(&self.transform); bind_and_render_quad(render_context, &self.texture, &transform, scene_size); + + if render_context.show_debug_borders { + bind_and_render_quad_lines(render_context, + &transform, + scene_size, + TILE_DEBUG_BORDER_COLOR, + TILE_DEBUG_BORDER_THICKNESS); + } } }