tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

boilerplate.rs (8553B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 use api::ImageFormat;
      6 use euclid::{Transform3D, UnknownUnit};
      7 use glutin::{self, PossiblyCurrent};
      8 use gleam::gl;
      9 use wr_glyph_rasterizer::{RasterizedGlyph, GlyphFormat};
     10 
     11 use std::{ffi::CStr, rc::Rc};
     12 
     13 #[allow(unused)]
     14 pub struct Gl {
     15    pub gl: Rc<dyn gl::Gl>,
     16    program: gl::GLuint,
     17    vb: gl::GLuint,
     18    vao: gl::GLuint,
     19    vs: gl::GLuint,
     20    fs: gl::GLuint,
     21    textures: Vec<gl::GLuint>,
     22    u_transform: i32,
     23    u_text_color: i32,
     24    u_sampler_color: i32,
     25    glyphs: Vec<RasterizedGlyph>,
     26 }
     27 
     28 pub fn load(gl_context: &glutin::Context<PossiblyCurrent>, glyphs: Vec<RasterizedGlyph>) -> Gl {
     29    env_logger::init();
     30 
     31    #[cfg(target_os = "macos")]
     32    {
     33        use core_foundation::{self as cf, base::TCFType};
     34        let i = cf::bundle::CFBundle::main_bundle().info_dictionary();
     35        let mut i = unsafe { i.to_mutable() };
     36        i.set(
     37            cf::string::CFString::new("NSSupportsAutomaticGraphicsSwitching"),
     38            cf::boolean::CFBoolean::true_value().into_CFType(),
     39        );
     40    }
     41 
     42    let gl = match gl_context.get_api() {
     43        glutin::Api::OpenGl => unsafe {
     44            gl::GlFns::load_with(|symbol| gl_context.get_proc_address(symbol) as *const _)
     45        },
     46        glutin::Api::OpenGlEs => unsafe {
     47            gl::GlesFns::load_with(|symbol| gl_context.get_proc_address(symbol) as *const _)
     48        },
     49        glutin::Api::WebGl => unimplemented!(),
     50    };
     51 
     52    let version = unsafe {
     53        let data = CStr::from_ptr(gl.get_string(gl::VERSION).as_ptr() as *const _)
     54            .to_bytes()
     55            .to_vec();
     56        String::from_utf8(data).unwrap()
     57    };
     58 
     59    println!("OpenGL version {}", version);
     60 
     61    let vs = gl.create_shader(gl::VERTEX_SHADER);
     62    gl.shader_source(vs, &[VS_SRC]);
     63    gl.compile_shader(vs);
     64 
     65    let fs = gl.create_shader(gl::FRAGMENT_SHADER);
     66    gl.shader_source(fs, &[FS_SRC]);
     67    gl.compile_shader(fs);
     68 
     69    let program = gl.create_program();
     70    gl.attach_shader(program, vs);
     71    gl.attach_shader(program, fs);
     72    gl.link_program(program);
     73    gl.use_program(program);
     74 
     75    let vb = gl.gen_buffers(1)[0];
     76    gl.bind_buffer(gl::ARRAY_BUFFER, vb);
     77    gl.buffer_data_untyped(
     78        gl::ARRAY_BUFFER,
     79        (6 * 4 * std::mem::size_of::<f32>()) as gl::types::GLsizeiptr,
     80        std::ptr::null(),
     81        gl::DYNAMIC_DRAW,
     82    );
     83 
     84    let vao = gl.gen_vertex_arrays(1)[0];
     85    gl.bind_vertex_array(vao);
     86 
     87    let u_transform = gl.get_uniform_location(program, "uTransform");
     88    let u_text_color = gl.get_uniform_location(program, "uTextColor");
     89    let u_sampler_color = gl.get_uniform_location(program, "uSamplerColor");
     90    let i_position = gl.get_attrib_location(program, "iPosition");
     91    let i_tex_coords = gl.get_attrib_location(program, "iTexCoords");
     92    gl.vertex_attrib_pointer(
     93        i_position as gl::types::GLuint,
     94        2,
     95        gl::FLOAT,
     96        false,
     97        4 * std::mem::size_of::<f32>() as gl::types::GLsizei,
     98        0,
     99    );
    100    gl.vertex_attrib_pointer(
    101        i_tex_coords as gl::types::GLuint,
    102        2,
    103        gl::FLOAT,
    104        false,
    105        4 * std::mem::size_of::<f32>() as gl::types::GLsizei,
    106        (2 * std::mem::size_of::<f32>()) as gl::types::GLuint,
    107    );
    108    gl.enable_vertex_attrib_array(i_position as gl::types::GLuint);
    109    gl.enable_vertex_attrib_array(i_tex_coords as gl::types::GLuint);
    110 
    111    let textures = create_texture(&gl, &glyphs);
    112 
    113    gl.bind_buffer(gl::ARRAY_BUFFER, 0);
    114    gl.bind_vertex_array(0);
    115 
    116    unsafe { log_shader(&gl, vs) };
    117    unsafe { log_shader(&gl, fs) };
    118 
    119    Gl {
    120        gl,
    121        program,
    122        vb,
    123        vao,
    124        u_transform,
    125        u_text_color,
    126        u_sampler_color,
    127        glyphs,
    128        textures,
    129        vs,
    130        fs,
    131    }
    132 }
    133 
    134 fn create_texture(gl: &Rc<dyn gl::Gl>, glyphs: &[RasterizedGlyph]) -> Vec<gl::GLuint> {
    135    let textures = gl.gen_textures(glyphs.len() as gl::types::GLsizei);
    136    for (i, glyph) in glyphs.iter().enumerate() {
    137        let (internal_format, external_format) = get_texture_format(&glyph.format);
    138        let texture = textures[i];
    139        gl.bind_texture(gl::TEXTURE_2D, texture);
    140        gl.tex_parameter_i(
    141            gl::TEXTURE_2D,
    142            gl::TEXTURE_MAG_FILTER,
    143            gl::LINEAR as gl::GLint,
    144        );
    145        gl.tex_parameter_i(
    146            gl::TEXTURE_2D,
    147            gl::TEXTURE_MIN_FILTER,
    148            gl::LINEAR as gl::GLint,
    149        );
    150        gl.tex_parameter_i(
    151            gl::TEXTURE_2D,
    152            gl::TEXTURE_WRAP_S,
    153            gl::CLAMP_TO_EDGE as gl::GLint,
    154        );
    155        gl.tex_parameter_i(
    156            gl::TEXTURE_2D,
    157            gl::TEXTURE_WRAP_T,
    158            gl::CLAMP_TO_EDGE as gl::GLint,
    159        );
    160        // TODO: use tex_storage_2d
    161        gl.tex_image_2d(
    162            gl::TEXTURE_2D,
    163            0,
    164            internal_format as gl::GLint,
    165            glyph.width,
    166            glyph.height,
    167            0,
    168            external_format,
    169            gl::UNSIGNED_BYTE,
    170            Some(&glyph.bytes),
    171        );
    172 
    173        gl.pixel_store_i(gl::UNPACK_ALIGNMENT, 1);
    174        gl.enable(gl::BLEND);
    175        gl.blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    176    }
    177 
    178    textures
    179 }
    180 
    181 fn get_texture_format(format: &GlyphFormat) -> (gl::GLuint, gl::GLuint) {
    182    match format.image_format(false) {
    183        ImageFormat::BGRA8 => (gl::RGBA, gl::BGRA),
    184        _ => unimplemented!(),
    185    }
    186 }
    187 
    188 unsafe fn log_shader(gl: &Rc<dyn gl::Gl>, shader: gl::GLuint) {
    189    let log = gl.get_shader_info_log(shader);
    190    if log.len() != 0 {
    191        println!("[ERROR] {}", log);
    192    }
    193 }
    194 
    195 impl Gl {
    196    pub fn draw_frame(
    197        &self,
    198        width: f32,
    199        height: f32,
    200        text_color: [f32; 4],
    201        background_color: [f32; 4],
    202        scale_factor: f32,
    203    ) {
    204        let projection: Transform3D<f32, UnknownUnit, UnknownUnit> =
    205            Transform3D::ortho(0., width, height, 0., -1., 1.);
    206        self.gl
    207            .uniform_matrix_4fv(self.u_transform, false, &projection.to_array());
    208        self.gl.uniform_4fv(self.u_text_color, &text_color);
    209 
    210        self.gl.active_texture(gl::TEXTURE0);
    211 
    212        self.gl.bind_vertex_array(self.vao);
    213 
    214        self.gl.clear_color(
    215            background_color[0],
    216            background_color[1],
    217            background_color[2],
    218            background_color[3],
    219        );
    220        self.gl.clear(gl::COLOR_BUFFER_BIT);
    221 
    222        let mut ax = 0.;
    223        for (i, glyph) in self.glyphs.iter().enumerate() {
    224            let texture = self.textures[i];
    225 
    226            let x = ax + glyph.left;
    227            let y = glyph.top;
    228 
    229            let w = (glyph.width as f32) * scale_factor;
    230            let h = (glyph.height as f32) * scale_factor;
    231 
    232            #[rustfmt::skip]
    233            let vertices = [
    234                x,     y,      0.0, 0.0,
    235                x,     y + h,  0.0, 1.0,
    236                x + w, y + h,  1.0, 1.0,
    237 
    238                x,     y,      0.0, 0.0,
    239                x + w, y + h,  1.0, 1.0,
    240                x + w, y,      1.0, 0.0
    241            ];
    242 
    243            self.gl.uniform_1i(self.u_sampler_color, 0);
    244            self.gl.bind_texture(gl::TEXTURE_2D, texture);
    245            self.gl.bind_buffer(gl::ARRAY_BUFFER, self.vb);
    246            self.gl.buffer_data_untyped(
    247                gl::ARRAY_BUFFER,
    248                (vertices.len() * std::mem::size_of::<f32>()) as gl::GLsizeiptr,
    249                vertices.as_ptr() as *const _,
    250                gl::DYNAMIC_DRAW,
    251            );
    252            self.gl.bind_buffer(gl::ARRAY_BUFFER, 0);
    253 
    254            self.gl.draw_arrays(gl::TRIANGLES, 0, 6);
    255 
    256            ax += (glyph.left * scale_factor) + (glyph.width as f32 * scale_factor);
    257        }
    258        self.gl.bind_vertex_array(0);
    259        self.gl.bind_texture(gl::TEXTURE_2D, 0);
    260 
    261        unsafe {
    262            log_shader(&self.gl, self.vs);
    263            log_shader(&self.gl, self.fs);
    264        };
    265    }
    266 }
    267 
    268 const VS_SRC: &[u8] = b"
    269 #version 150
    270 
    271 in vec2 iPosition;
    272 in vec2 iTexCoords;
    273 
    274 uniform mat4 uTransform;
    275 
    276 out vec2 vColorTexCoord;
    277 
    278 void main() {
    279    gl_Position = uTransform * vec4(iPosition, 0.0, 1.0);
    280    vColorTexCoord = iTexCoords;
    281 }
    282 \0";
    283 
    284 const FS_SRC: &[u8] = b"
    285 #version 150
    286 
    287 in vec2 vColorTexCoord;
    288 
    289 uniform sampler2D uSamplerColor;
    290 uniform vec4 uTextColor;
    291 
    292 out vec4 oFragmentColor;
    293 
    294 void main() {
    295    vec4 alpha = vec4(1.0, 1.0, 1.0, texture(uSamplerColor, vColorTexCoord).r);
    296    oFragmentColor = uTextColor * alpha;
    297 }
    298 \0";