use libc;
use log::LogLevel;
use std::slice;
use {gl, tex};
use gfx::device as d;
use gfx::device::handle;
use gfx::device::handle::Producer;
use gfx::device::mapping::Builder;
use GlDevice;
use GlResources as R;
pub fn make_default_frame_buffer(handles: &mut handle::Manager<R>)
-> handle::FrameBuffer<R> {
handles.make_frame_buffer(0)
}
#[allow(raw_pointer_derive)]
#[derive(Copy, Clone)]
pub struct RawMapping {
pub pointer: *mut libc::c_void,
target: gl::types::GLenum,
}
impl d::mapping::Raw for RawMapping {
unsafe fn set<T>(&self, index: usize, val: T) {
*(self.pointer as *mut T).offset(index as isize) = val;
}
unsafe fn to_slice<T>(&self, len: usize) -> &[T] {
slice::from_raw_parts(self.pointer as *const T, len)
}
unsafe fn to_mut_slice<T>(&self, len: usize) -> &mut [T] {
slice::from_raw_parts_mut(self.pointer as *mut T, len)
}
}
impl d::Factory<R> for GlDevice {
type Mapper = RawMapping;
fn create_buffer_raw(&mut self, size: usize, usage: d::BufferUsage)
-> handle::RawBuffer<R> {
let name = self.create_buffer_internal();
let info = d::BufferInfo {
role: d::BufferRole::Vertex,
usage: usage,
size: size,
};
self.init_buffer(name, &info);
self.handles.make_buffer(name, info)
}
fn create_buffer_static_raw(&mut self, data: &[u8], role: d::BufferRole)
-> handle::RawBuffer<R> {
let name = self.create_buffer_internal();
let info = d::BufferInfo {
role: role,
usage: d::BufferUsage::Static,
size: data.len(),
};
self.init_buffer(name, &info);
self.update_sub_buffer(name, data.as_ptr(), data.len(), 0, role);
self.handles.make_buffer(name, info)
}
fn create_array_buffer(&mut self) -> Result<handle::ArrayBuffer<R>, ()> {
if self.caps.array_buffer_supported {
let mut name = 0 as ::ArrayBuffer;
unsafe {
self.gl.GenVertexArrays(1, &mut name);
}
info!("\tCreated array buffer {}", name);
Ok(self.handles.make_array_buffer(name))
} else {
error!("\tarray buffer creation unsupported, ignored");
Err(())
}
}
fn create_shader(&mut self, stage: d::shade::Stage, code: &[u8])
-> Result<handle::Shader<R>, d::shade::CreateShaderError> {
let (name, info) = ::shade::create_shader(&self.gl, stage, code);
info.map(|info| {
let level = if name.is_err() { LogLevel::Error } else { LogLevel::Warn };
log!(level, "\tShader compile log: {}", info);
});
name.map(|sh| self.handles.make_shader(sh, stage))
}
fn create_program(&mut self, shaders: &[handle::Shader<R>],
targets: Option<&[&str]>)
-> Result<handle::Program<R>, ()> {
let objects: Vec<::Shader> = shaders.iter()
.map(|h| self.frame_handles.ref_shader(h))
.collect();
let (prog, log) = ::shade::create_program(&self.gl, &self.caps,
objects.into_iter(), targets);
log.map(|log| {
let level = if prog.is_err() { LogLevel::Error } else { LogLevel::Warn };
log!(level, "\tProgram link log: {}", log);
});
prog.map(|(name, info)| self.handles.make_program(name, info))
}
fn create_frame_buffer(&mut self) -> handle::FrameBuffer<R> {
if !self.caps.render_targets_supported {
panic!("No framebuffer objects, can't make a new one!");
}
let mut name = 0 as ::FrameBuffer;
unsafe {
self.gl.GenFramebuffers(1, &mut name);
}
info!("\tCreated frame buffer {}", name);
self.handles.make_frame_buffer(name)
}
fn create_surface(&mut self, info: d::tex::SurfaceInfo) ->
Result<handle::Surface<R>, d::tex::SurfaceError> {
tex::make_surface(&self.gl, &info)
.map(|suf| self.handles.make_surface(suf, info))
}
fn create_texture(&mut self, info: d::tex::TextureInfo) ->
Result<handle::Texture<R>, d::tex::TextureError> {
if info.width == 0 || info.height == 0 || info.levels == 0 {
return Err(d::tex::TextureError::InvalidTextureInfo(info))
}
let name = if self.caps.immutable_storage_supported {
tex::make_with_storage(&self.gl, &info)
} else {
tex::make_without_storage(&self.gl, &info)
};
name.map(|tex| self.handles.make_texture(tex, info))
}
fn create_sampler(&mut self, info: d::tex::SamplerInfo)
-> handle::Sampler<R> {
let sam = if self.caps.sampler_objects_supported {
tex::make_sampler(&self.gl, &info)
} else {
0
};
self.handles.make_sampler(sam, info)
}
fn get_main_frame_buffer(&self) -> handle::FrameBuffer<R> {
self.main_fbo.clone()
}
fn update_buffer_raw(&mut self, buffer: &handle::RawBuffer<R>,
data: &[u8], offset_bytes: usize) {
debug_assert!(offset_bytes + data.len() <= buffer.get_info().size);
let raw_handle = self.frame_handles.ref_buffer(buffer);
self.update_sub_buffer(raw_handle, data.as_ptr(), data.len(),
offset_bytes, buffer.get_info().role)
}
fn update_texture_raw(&mut self, texture: &handle::Texture<R>,
img: &d::tex::ImageInfo, data: &[u8])
-> Result<(), d::tex::TextureError> {
tex::update_texture(&self.gl, texture.get_info().kind,
self.frame_handles.ref_texture(texture),
img, data.as_ptr(), data.len())
}
fn generate_mipmap(&mut self, texture: &handle::Texture<R>) {
tex::generate_mipmap(&self.gl, texture.get_info().kind,
self.frame_handles.ref_texture(texture));
}
fn map_buffer_raw(&mut self, buf: &handle::RawBuffer<R>,
access: d::MapAccess) -> RawMapping {
let raw_handle = self.frame_handles.ref_buffer(buf);
unsafe { self.gl.BindBuffer(gl::ARRAY_BUFFER, raw_handle) };
let ptr = unsafe { self.gl.MapBuffer(gl::ARRAY_BUFFER, match access {
d::MapAccess::Readable => gl::READ_ONLY,
d::MapAccess::Writable => gl::WRITE_ONLY,
d::MapAccess::RW => gl::READ_WRITE
}) } as *mut libc::c_void;
RawMapping {
pointer: ptr,
target: gl::ARRAY_BUFFER
}
}
fn unmap_buffer_raw(&mut self, map: RawMapping) {
unsafe { self.gl.UnmapBuffer(map.target) };
}
fn map_buffer_readable<T: Copy>(&mut self, buf: &handle::Buffer<R, T>)
-> d::mapping::Readable<T, R, GlDevice> {
let map = self.map_buffer_raw(buf.raw(), d::MapAccess::Readable);
self.map_readable(map, buf.len())
}
fn map_buffer_writable<T: Copy>(&mut self, buf: &handle::Buffer<R, T>)
-> d::mapping::Writable<T, R, GlDevice> {
let map = self.map_buffer_raw(buf.raw(), d::MapAccess::Writable);
self.map_writable(map, buf.len())
}
fn map_buffer_rw<T: Copy>(&mut self, buf: &handle::Buffer<R, T>)
-> d::mapping::RW<T, R, GlDevice> {
let map = self.map_buffer_raw(buf.raw(), d::MapAccess::RW);
self.map_read_write(map, buf.len())
}
fn cleanup(&mut self) {
self.handles.clean_with(&mut self.gl,
|gl, v| unsafe { gl.DeleteBuffers(1, v) },
|gl, v| unsafe { gl.DeleteVertexArrays(1, v) },
|gl, v| unsafe { gl.DeleteShader(*v) },
|gl, v| unsafe { gl.DeleteProgram(*v) },
|gl, v| unsafe { gl.DeleteFramebuffers(1, v) },
|gl, v| unsafe { gl.DeleteRenderbuffers(1, v) },
|gl, v| unsafe { gl.DeleteTextures(1, v) },
|gl, v| unsafe { gl.DeleteSamplers(1, v) })
}
}