1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use std::cell::RefCell;
use std::mem;
use std::rc::Rc;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::path::Path;
use gl;
use gl::types::*;
use image::{self, DynamicImage};
#[path = "../error.rs"]
mod error;
pub struct Texture {
id: GLuint
}
impl Texture {
pub fn new() -> Rc<Texture> {
let mut id: GLuint = 0;
unsafe { verify!(gl::GenTextures(1, &mut id)); }
Rc::new(Texture { id: id })
}
pub fn id(&self) -> GLuint {
self.id
}
}
impl Drop for Texture {
fn drop(&mut self) {
unsafe { verify!(gl::DeleteTextures(1, &self.id)); }
}
}
thread_local!(static KEY_TEXTURE_MANAGER: RefCell<TextureManager> = RefCell::new(TextureManager::new()));
pub struct TextureManager {
default_texture: Rc<Texture>,
textures: HashMap<String, Rc<Texture>>,
}
impl TextureManager {
pub fn new() -> TextureManager {
let default_tex = Texture::new();
let default_tex_pixels: [ GLfloat; 3 ] = [ 1.0, 1.0, 1.0 ];
verify!(gl::ActiveTexture(gl::TEXTURE0));
verify!(gl::BindTexture(gl::TEXTURE_2D, default_tex.id()));
verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_BASE_LEVEL, 0));
verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAX_LEVEL, 0));
verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32));
verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32));
verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32));
verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR as i32));
unsafe {
verify!(gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGB as i32, 1, 1, 0, gl::RGB, gl::FLOAT,
mem::transmute(&default_tex_pixels[0])));
}
TextureManager {
textures: HashMap::new(),
default_texture: default_tex
}
}
pub fn get_global_manager<T, F: FnMut(&mut TextureManager) -> T>(mut f: F) -> T {
KEY_TEXTURE_MANAGER.with(|manager| f(&mut *manager.borrow_mut()))
}
pub fn get_default(&self) -> Rc<Texture> {
self.default_texture.clone()
}
pub fn get(&mut self, name: &str) -> Option<Rc<Texture>> {
self.textures.get(&name.to_string()).map(|t| t.clone())
}
pub fn add_empty(&mut self, name: &str) -> Rc<Texture> {
match self.textures.entry(name.to_string()) {
Entry::Occupied(entry) => entry.into_mut().clone(),
Entry::Vacant(entry) => entry.insert(Texture::new()).clone()
}
}
fn load_texture(path: &Path) -> Rc<Texture> {
let tex = Texture::new();
unsafe {
verify!(gl::ActiveTexture(gl::TEXTURE0));
verify!(gl::BindTexture(gl::TEXTURE_2D, tex.id()));
match image::open(path).unwrap() {
DynamicImage::ImageRgb8(image) => {
verify!(gl::TexImage2D(
gl::TEXTURE_2D, 0,
gl::RGB as GLint,
image.width() as GLsizei,
image.height() as GLsizei,
0, gl::RGB, gl::UNSIGNED_BYTE,
mem::transmute(&image.into_raw()[0])));
},
DynamicImage::ImageRgba8(image) => {
verify!(gl::TexImage2D(
gl::TEXTURE_2D, 0,
gl::RGBA as GLint,
image.width() as GLsizei,
image.height() as GLsizei,
0, gl::RGBA, gl::UNSIGNED_BYTE,
mem::transmute(&image.into_raw()[0])));
}
_ => {
panic!("Failed to load texture {}, unsuported pixel format.", path.to_str().unwrap());
}
}
verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint));
verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint));
verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint));
verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint));
}
tex
}
pub fn add(&mut self, path: &Path, name: &str) -> Rc<Texture> {
self.textures.entry(name.to_string()).or_insert_with(|| TextureManager::load_texture(path)).clone()
}
}