rust/lib-hedgewars-engine/src/render/gl.rs
changeset 14726 19122a329774
parent 14723 29dbe9ce8b7d
child 14728 5237b4c44d11
equal deleted inserted replaced
14725:12db7e435ea6 14726:19122a329774
     1  use integral_geometry::Rect;
     1 
     2 
     2 use integral_geometry::Rect;
     3 use std::{
     3 
     4     mem,
     4 use std::{ffi, ffi::CString, mem, ptr, slice};
     5     slice,
       
     6     ptr,
       
     7     ffi,
       
     8     ffi::CString,
       
     9 };
       
    10 
     5 
    11 #[derive(Debug)]
     6 #[derive(Debug)]
    12 pub struct Texture2D {
     7 pub struct Texture2D {
    13     pub handle: u32,
     8     pub handle: u32,
    14 }
     9 }
    30         width: u32,
    25         width: u32,
    31         height: u32,
    26         height: u32,
    32         internal_format: u32,
    27         internal_format: u32,
    33         format: u32,
    28         format: u32,
    34         ty: u32,
    29         ty: u32,
    35         filter: u32
    30         filter: u32,
    36     ) -> Self {
    31     ) -> Self {
    37         let mut handle = 0;
    32         let mut handle = 0;
    38         
    33 
    39         unsafe {
    34         unsafe {
    40             gl::GenTextures(1, &mut handle);
    35             gl::GenTextures(1, &mut handle);
    41             
    36 
    42             gl::BindTexture(gl::TEXTURE_2D, handle);
    37             gl::BindTexture(gl::TEXTURE_2D, handle);
    43             gl::PixelStorei(gl::UNPACK_ROW_LENGTH, data_stride as i32);
    38             gl::PixelStorei(gl::UNPACK_ROW_LENGTH, data_stride as i32);
    44             gl::TexImage2D(
    39             gl::TexImage2D(
    45                 gl::TEXTURE_2D,
    40                 gl::TEXTURE_2D,
    46                 0,
    41                 0,
    48                 width as i32,
    43                 width as i32,
    49                 height as i32,
    44                 height as i32,
    50                 0,
    45                 0,
    51                 format as u32,
    46                 format as u32,
    52                 ty,
    47                 ty,
    53                 data.as_ptr() as *const _
    48                 data.as_ptr() as *const _,
    54             );
    49             );
    55 
    50 
    56             gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
    51             gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
    57             gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
    52             gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
    58             gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, filter as i32);
    53             gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, filter as i32);
    59             gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, filter as i32);
    54             gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, filter as i32);
    60         }
    55         }
    61 
    56 
    62         Texture2D {
    57         Texture2D { handle }
    63             handle
       
    64         }
       
    65     }
    58     }
    66 
    59 
    67     pub fn update(&self, region: Rect, data: &[u8], data_stride: u32, format: u32, ty: u32) {
    60     pub fn update(&self, region: Rect, data: &[u8], data_stride: u32, format: u32, ty: u32) {
    68         unsafe {
    61         unsafe {
    69             gl::BindTexture(gl::TEXTURE_2D, self.handle);
    62             gl::BindTexture(gl::TEXTURE_2D, self.handle);
    70             gl::PixelStorei(gl::UNPACK_ROW_LENGTH, data_stride as i32);
    63             gl::PixelStorei(gl::UNPACK_ROW_LENGTH, data_stride as i32);
    71             gl::TexSubImage2D(
    64             gl::TexSubImage2D(
    72                 gl::TEXTURE_2D,
    65                 gl::TEXTURE_2D,
    73                 0, // texture level
    66                 0,             // texture level
    74                 region.left(), // texture region
    67                 region.left(), // texture region
    75                 region.top(),
    68                 region.top(),
    76                 region.width() as i32 - 1,
    69                 region.width() as i32 - 1,
    77                 region.height() as i32 - 1,
    70                 region.height() as i32 - 1,
    78                 format, // data format
    71                 format,                    // data format
    79                 ty, // data type
    72                 ty,                        // data type
    80                 data.as_ptr() as *const _, // data ptr
    73                 data.as_ptr() as *const _, // data ptr
    81             );
    74             );
    82         }
    75         }
    83     }
    76     }
    84 }
    77 }
   108             handle: buffer,
   101             handle: buffer,
   109             ty,
   102             ty,
   110             usage,
   103             usage,
   111         }
   104         }
   112     }
   105     }
   113     
   106 
   114     fn with_data(
   107     fn with_data(ty: u32, usage: u32, data: &[u8]) -> Buffer {
   115         ty: u32,
       
   116         usage: u32,
       
   117         data: &[u8]
       
   118     ) -> Buffer {
       
   119         let mut buffer = 0;
   108         let mut buffer = 0;
   120 
   109 
   121         unsafe {
   110         unsafe {
   122             gl::GenBuffers(1, &mut buffer);
   111             gl::GenBuffers(1, &mut buffer);
   123             gl::BindBuffer(ty, buffer);
   112             gl::BindBuffer(ty, buffer);
   125         }
   114         }
   126 
   115 
   127         Buffer {
   116         Buffer {
   128             handle: buffer,
   117             handle: buffer,
   129             ty,
   118             ty,
   130             usage
   119             usage,
   131         }
   120         }
   132     }
   121     }
   133 
   122 
   134     pub fn ty(&self) -> u32 {
   123     pub fn ty(&self) -> u32 {
   135         self.ty
   124         self.ty
   139         self.handle
   128         self.handle
   140     }
   129     }
   141 
   130 
   142     pub fn write_typed<T>(&self, data: &[T]) {
   131     pub fn write_typed<T>(&self, data: &[T]) {
   143         unsafe {
   132         unsafe {
   144             let data = slice::from_raw_parts(
   133             let data =
   145                 data.as_ptr() as *const u8,
   134                 slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::<T>());
   146                 data.len() * mem::size_of::<T>(),
   135 
       
   136             gl::BindBuffer(self.ty, self.handle);
       
   137             gl::BufferData(
       
   138                 self.ty,
       
   139                 data.len() as isize,
       
   140                 data.as_ptr() as *const _ as *const _,
       
   141                 self.usage,
   147             );
   142             );
   148             
   143         }
       
   144     }
       
   145 
       
   146     pub fn write(&self, data: &[u8]) {
       
   147         unsafe {
   149             gl::BindBuffer(self.ty, self.handle);
   148             gl::BindBuffer(self.ty, self.handle);
   150             gl::BufferData(self.ty, data.len() as isize, data.as_ptr() as *const _ as *const _, self.usage);
   149             gl::BufferData(
   151         }
   150                 self.ty,
   152     }
   151                 data.len() as isize,
   153     
   152                 data.as_ptr() as *const _ as *const _,
   154     pub fn write(&self, data: &[u8]) {        
   153                 self.usage,
   155         unsafe {
   154             );
   156             gl::BindBuffer(self.ty, self.handle);
       
   157             gl::BufferData(self.ty, data.len() as isize, data.as_ptr() as *const _ as *const _, self.usage);
       
   158         }
   155         }
   159     }
   156     }
   160 }
   157 }
   161 
   158 
   162 impl Drop for Buffer {
   159 impl Drop for Buffer {
   190 
   187 
   191 impl Shader {
   188 impl Shader {
   192     pub fn new<'a>(
   189     pub fn new<'a>(
   193         vs: &str,
   190         vs: &str,
   194         ps: Option<&str>,
   191         ps: Option<&str>,
   195         bindings: &[VariableBinding<'a>]
   192         bindings: &[VariableBinding<'a>],
   196     ) -> Result<Self, String> {
   193     ) -> Result<Self, String> {
   197         unsafe fn compile_shader(ty: u32, shdr: &str) -> Result<u32, String> {
   194         unsafe fn compile_shader(ty: u32, shdr: &str) -> Result<u32, String> {
   198             let shader = gl::CreateShader(ty);
   195             let shader = gl::CreateShader(ty);
   199             let len = shdr.len() as i32;
   196             let len = shdr.len() as i32;
   200             let shdr = shdr.as_ptr() as *const i8;
   197             let shdr = shdr.as_ptr() as *const i8;
   215                 Err(String::from_utf8_unchecked(log))
   212                 Err(String::from_utf8_unchecked(log))
   216             } else {
   213             } else {
   217                 Ok(shader)
   214                 Ok(shader)
   218             }
   215             }
   219         }
   216         }
   220         
   217 
   221         let vs = unsafe { compile_shader(gl::VERTEX_SHADER, vs)? };
   218         let vs = unsafe { compile_shader(gl::VERTEX_SHADER, vs)? };
   222         let ps = if let Some(ps) = ps {
   219         let ps = if let Some(ps) = ps {
   223             Some(unsafe { compile_shader(gl::FRAGMENT_SHADER, ps)? })
   220             Some(unsafe { compile_shader(gl::FRAGMENT_SHADER, ps)? })
   224         } else {
   221         } else {
   225             None
   222             None
   226         };
   223         };
   227 
   224 
   228         unsafe {
   225         unsafe {
   229             let program = gl::CreateProgram();
   226             let program = gl::CreateProgram();
   230             
   227 
   231             gl::AttachShader(program, vs);
   228             gl::AttachShader(program, vs);
   232             if let Some(ps) = ps {
   229             if let Some(ps) = ps {
   233                 gl::AttachShader(program, ps);
   230                 gl::AttachShader(program, ps);
   234             }
   231             }
   235 
   232 
   236             for bind in bindings {
   233             for bind in bindings {
   237                 match bind {
   234                 match bind {
   238                     &VariableBinding::Attribute(ref name, id) => {
   235                     &VariableBinding::Attribute(ref name, id) => {
   239                         let c_str = CString::new(name.as_bytes()).unwrap();
   236                         let c_str = CString::new(name.as_bytes()).unwrap();
   240                         gl::BindAttribLocation(program, id, c_str.to_bytes_with_nul().as_ptr() as *const _);     
   237                         gl::BindAttribLocation(
   241                     },
   238                             program,
       
   239                             id,
       
   240                             c_str.to_bytes_with_nul().as_ptr() as *const _,
       
   241                         );
       
   242                     }
   242                     _ => {}
   243                     _ => {}
   243                 }
   244                 }
   244             }
   245             }
   245 
   246 
   246             gl::LinkProgram(program);
   247             gl::LinkProgram(program);
   268             // after linking we setup sampler bindings as specified in the shader
   269             // after linking we setup sampler bindings as specified in the shader
   269             for bind in bindings {
   270             for bind in bindings {
   270                 match bind {
   271                 match bind {
   271                     VariableBinding::Uniform(name, id) => {
   272                     VariableBinding::Uniform(name, id) => {
   272                         let c_str = CString::new(name.as_bytes()).unwrap();
   273                         let c_str = CString::new(name.as_bytes()).unwrap();
   273                         let index = gl::GetUniformLocation(program, c_str.to_bytes_with_nul().as_ptr() as *const _);
   274                         let index = gl::GetUniformLocation(
       
   275                             program,
       
   276                             c_str.to_bytes_with_nul().as_ptr() as *const _,
       
   277                         );
   274 
   278 
   275                         // TODO: impl for block?
   279                         // TODO: impl for block?
   276                     },
   280                     }
   277                     VariableBinding::UniformBlock(name, id) => {
   281                     VariableBinding::UniformBlock(name, id) => {
   278                         let c_str = CString::new(name.as_bytes()).unwrap();
   282                         let c_str = CString::new(name.as_bytes()).unwrap();
   279                         let index = gl::GetUniformBlockIndex(program, c_str.to_bytes_with_nul().as_ptr() as *const _);
   283                         let index = gl::GetUniformBlockIndex(
       
   284                             program,
       
   285                             c_str.to_bytes_with_nul().as_ptr() as *const _,
       
   286                         );
   280 
   287 
   281                         gl::UniformBlockBinding(program, index, *id);
   288                         gl::UniformBlockBinding(program, index, *id);
   282                     }
   289                     }
   283                     VariableBinding::Sampler(name, id) => {
   290                     VariableBinding::Sampler(name, id) => {
   284                         let c_str = CString::new(name.as_bytes()).unwrap();
   291                         let c_str = CString::new(name.as_bytes()).unwrap();
   285                         let index = gl::GetUniformLocation(program, c_str.to_bytes_with_nul().as_ptr() as *const _);
   292                         let index = gl::GetUniformLocation(
   286                         
   293                             program,
       
   294                             c_str.to_bytes_with_nul().as_ptr() as *const _,
       
   295                         );
       
   296 
   287                         gl::Uniform1i(index, *id as i32);
   297                         gl::Uniform1i(index, *id as i32);
   288                     },
   298                     }
   289                     _ => {}
   299                     _ => {}
   290                 }
   300                 }
   291             }
   301             }
   292 
   302 
   293             Ok(Shader {
   303             Ok(Shader { program })
   294                 program
       
   295             })
       
   296         }
   304         }
   297     }
   305     }
   298 
   306 
   299     pub fn bind(&self) {
   307     pub fn bind(&self) {
   300         unsafe {
   308         unsafe {
   303     }
   311     }
   304 
   312 
   305     pub fn set_matrix(&self, name: &str, matrix: *const f32) {
   313     pub fn set_matrix(&self, name: &str, matrix: *const f32) {
   306         unsafe {
   314         unsafe {
   307             let c_str = CString::new(name).unwrap();
   315             let c_str = CString::new(name).unwrap();
   308             let index = gl::GetUniformLocation(self.program, c_str.to_bytes_with_nul().as_ptr() as *const _);
   316             let index = gl::GetUniformLocation(
   309             
   317                 self.program,
       
   318                 c_str.to_bytes_with_nul().as_ptr() as *const _,
       
   319             );
       
   320 
   310             gl::UniformMatrix4fv(index, 1, gl::FALSE, matrix);
   321             gl::UniformMatrix4fv(index, 1, gl::FALSE, matrix);
   311         }
   322         }
   312     }
   323     }
   313 
   324 
   314     pub fn bind_texture_2d(&self, index: u32, texture: &Texture2D) {
   325     pub fn bind_texture_2d(&self, index: u32, texture: &Texture2D) {
   315         self.bind();
   326         self.bind();
   316         
   327 
   317         unsafe {
   328         unsafe {
   318             gl::ActiveTexture(gl::TEXTURE0 + index);
   329             gl::ActiveTexture(gl::TEXTURE0 + index);
   319             gl::BindTexture(gl::TEXTURE_2D, texture.handle);
   330             gl::BindTexture(gl::TEXTURE_2D, texture.handle);
   320         }
   331         }
   321     }
   332     }
   333     pub components: u32,
   344     pub components: u32,
   334     pub stride: u32,
   345     pub stride: u32,
   335     pub offset: u32,
   346     pub offset: u32,
   336 }
   347 }
   337 
   348 
   338 // TODO: 
   349 // TODO:
   339 pub struct InputLayout {
   350 pub struct InputLayout {
   340     pub elements: Vec<InputElement>,
   351     pub elements: Vec<InputElement>,
   341 }
   352 }
   342 
   353 
   343 pub struct LayoutGuard {
   354 pub struct LayoutGuard {
   344     vao: u32
   355     vao: u32,
   345 }
   356 }
   346 
   357 
   347 impl Drop for LayoutGuard {
   358 impl Drop for LayoutGuard {
   348     fn drop(&mut self) {
   359     fn drop(&mut self) {
   349         unsafe {
   360         unsafe {
   353     }
   364     }
   354 }
   365 }
   355 
   366 
   356 impl InputLayout {
   367 impl InputLayout {
   357     pub fn new(elements: Vec<InputElement>) -> Self {
   368     pub fn new(elements: Vec<InputElement>) -> Self {
   358         InputLayout {
   369         InputLayout { elements }
   359             elements,
   370     }
   360         }
   371 
   361     }
   372     pub fn bind(
   362 
   373         &mut self,
   363     pub fn bind(&mut self, buffers: &[(u32, &Buffer)], index_buffer: Option<&Buffer>) -> LayoutGuard {
   374         buffers: &[(u32, &Buffer)],
       
   375         index_buffer: Option<&Buffer>,
       
   376     ) -> LayoutGuard {
   364         let mut vao = 0;
   377         let mut vao = 0;
   365         
   378 
   366         unsafe {
   379         unsafe {
   367             gl::GenVertexArrays(1, &mut vao);
   380             gl::GenVertexArrays(1, &mut vao);
   368             gl::BindVertexArray(vao);
   381             gl::BindVertexArray(vao);
   369         }
   382         }
   370         
   383 
   371         for &(slot, ref buffer) in buffers {
   384         for &(slot, ref buffer) in buffers {
   372             unsafe {
   385             unsafe {
   373                 gl::BindBuffer(buffer.ty(), buffer.handle());
   386                 gl::BindBuffer(buffer.ty(), buffer.handle());
   374             }
   387             }
   375             
   388 
   376             for attr in self.elements.iter().filter(|a| a.buffer_slot == slot) {
   389             for attr in self.elements.iter().filter(|a| a.buffer_slot == slot) {
   377                 unsafe {
   390                 unsafe {
   378                     gl::EnableVertexAttribArray(attr.shader_slot);
   391                     gl::EnableVertexAttribArray(attr.shader_slot);
   379                     match attr.format {
   392                     match attr.format {
   380                         InputFormat::Float(fmt, normalized) => {
   393                         InputFormat::Float(fmt, normalized) => {
   381                             gl::VertexAttribPointer(
   394                             gl::VertexAttribPointer(
   382                                 attr.shader_slot,
   395                                 attr.shader_slot,
   383                                 attr.components as i32,
   396                                 attr.components as i32,
   384                                 fmt,
   397                                 fmt,
   385                                 if normalized {
   398                                 if normalized { gl::TRUE } else { gl::FALSE },
   386                                     gl::TRUE
       
   387                                 } else {
       
   388                                     gl::FALSE
       
   389                                 },
       
   390                                 attr.stride as i32,
   399                                 attr.stride as i32,
   391                                 attr.offset as *const _
   400                                 attr.offset as *const _,
   392                             );
   401                             );
   393                         }
   402                         }
   394                         InputFormat::Integer(fmt) => {
   403                         InputFormat::Integer(fmt) => {
   395                             gl::VertexAttribIPointer(
   404                             gl::VertexAttribIPointer(
   396                                 attr.shader_slot,
   405                                 attr.shader_slot,
   397                                 attr.components as i32,
   406                                 attr.components as i32,
   398                                 fmt,
   407                                 fmt,
   399                                 attr.stride as i32,
   408                                 attr.stride as i32,
   400                                 attr.offset as *const _
   409                                 attr.offset as *const _,
   401                             );
   410                             );
   402                         }
   411                         }
   403                     }
   412                     }
   404 
       
   405                 }
   413                 }
   406             }
   414             }
   407         }
   415         }
   408 
   416 
   409         if let Some(buf) = index_buffer {
   417         if let Some(buf) = index_buffer {
   410             unsafe {
   418             unsafe {
   411                 gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, buf.handle());
   419                 gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, buf.handle());
   412             }
   420             }
   413         }
   421         }
   414 
   422 
   415         LayoutGuard {
   423         LayoutGuard { vao }
   416             vao
   424     }
   417         }
   425 }
   418     }
       
   419 }