1 /* GG is a GUI for OpenGL.
2 Copyright (C) 2003-2008 T. Zachary Laine
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public License
6 as published by the Free Software Foundation; either version 2.1
7 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA
18
19 If you do not wish to comply with the terms of the LGPL please
20 contact the author as other terms are available for a fee.
21
22 Zach Laine
23 whatwasthataddress@gmail.com */
24
25 #include <GG/Texture.h>
26
27 #include <GG/GLClientAndServerBuffer.h>
28 #include <GG/Config.h>
29 #include <GG/utf8/checked.h>
30
31 #include <boost/filesystem/operations.hpp>
32 #include <boost/gil/extension/dynamic_image/any_image.hpp>
33 #if GG_HAVE_LIBTIFF
34 # include <boost/gil/extension/io/tiff_dynamic_io.hpp>
35 #endif
36 #include <boost/algorithm/string/case_conv.hpp>
37
38 #if GG_HAVE_LIBPNG
39 # if GIGI_CONFIG_USE_OLD_IMPLEMENTATION_OF_GIL_PNG_IO
40 # include "gilext/io/png_dynamic_io.hpp"
41 # include "gilext/io/png_io_v2_compat.hpp"
42 # else
43 # include <boost/gil/extension/io/png.hpp>
44 # endif
45 #endif
46
47 #include <iostream>
48 #include <iomanip>
49
50 #if BOOST_VERSION >= 107400
51 #include <boost/variant2/variant.hpp>
52 #elif BOOST_VERSION >= 107000
53 #include <boost/variant/get.hpp>
54 #endif
55
56
57 using namespace GG;
58
59 namespace {
60 template <typename T>
PowerOfTwo(T input)61 T PowerOfTwo(T input)
62 {
63 T value(1);
64 while (value < input)
65 value *= 2;
66 return value;
67 }
68 }
69
70 ///////////////////////////////////////
71 // class GG::Texture
72 ///////////////////////////////////////
Texture()73 Texture::Texture()
74 { Clear(); }
75
~Texture()76 Texture::~Texture()
77 { Clear(); }
78
Path() const79 const boost::filesystem::path& Texture::Path() const
80 { return m_path; }
81
WrapS() const82 GLenum Texture::WrapS() const
83 { return m_wrap_s; }
84
WrapT() const85 GLenum Texture::WrapT() const
86 { return m_wrap_t; }
87
MinFilter() const88 GLenum Texture::MinFilter() const
89 { return m_min_filter; }
90
MagFilter() const91 GLenum Texture::MagFilter() const
92 { return m_mag_filter; }
93
BytesPP() const94 unsigned int Texture::BytesPP() const
95 { return m_bytes_pp; }
96
Width() const97 X Texture::Width() const
98 { return m_width; }
99
Height() const100 Y Texture::Height() const
101 { return m_height; }
102
MipMapped() const103 bool Texture::MipMapped() const
104 { return m_mipmaps; }
105
OpenGLId() const106 GLuint Texture::OpenGLId() const
107 { return m_opengl_id; }
108
DefaultTexCoords() const109 const GLfloat* Texture::DefaultTexCoords() const
110 { return m_tex_coords; }
111
DefaultWidth() const112 X Texture::DefaultWidth() const
113 { return m_default_width; }
114
DefaultHeight() const115 Y Texture::DefaultHeight() const
116 { return m_default_height; }
117
OrthoBlit(const Pt & pt1,const Pt & pt2,const GLfloat * tex_coords) const118 void Texture::OrthoBlit(const Pt& pt1, const Pt& pt2,
119 const GLfloat* tex_coords/* = 0*/) const
120 {
121 if (m_opengl_id == 0)
122 return;
123
124 if (!tex_coords) // use default texture coords when not given any others
125 tex_coords = m_tex_coords;
126
127 // HACK! This code ensures that unscaled textures are reproduced exactly, even
128 // though they theoretically should be even when using non-GL_NEAREST* scaling.
129 bool render_scaled = (pt2.x - pt1.x) != m_default_width || (pt2.y - pt1.y) != m_default_height;
130 bool need_min_filter_change = !render_scaled && m_min_filter != GL_NEAREST;
131 bool need_mag_filter_change = !render_scaled && m_mag_filter != GL_NEAREST;
132 if (need_min_filter_change)
133 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
134 if (need_mag_filter_change)
135 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
136
137 // render texture
138 GL2DVertexBuffer vertex_buffer;
139 vertex_buffer.reserve(4);
140 vertex_buffer.store(pt2.x, pt1.y);
141 vertex_buffer.store(pt1.x, pt1.y);
142 vertex_buffer.store(pt2.x, pt2.y);
143 vertex_buffer.store(pt1.x, pt2.y);
144
145 GLTexCoordBuffer tex_coord_buffer;
146 tex_coord_buffer.reserve(4);
147 if (tex_coords) {
148 tex_coord_buffer.store(tex_coords[2], tex_coords[1]);
149 tex_coord_buffer.store(tex_coords[0], tex_coords[1]);
150 tex_coord_buffer.store(tex_coords[2], tex_coords[3]);
151 tex_coord_buffer.store(tex_coords[0], tex_coords[3]);
152 } else {
153 tex_coord_buffer.store(1.0f, 0.0f);
154 tex_coord_buffer.store(0.0f, 0.0f);
155 tex_coord_buffer.store(1.0f, 1.0f);
156 tex_coord_buffer.store(0.0f, 1.0f);
157 }
158
159 glPushAttrib(GL_ENABLE_BIT);
160 glEnable(GL_TEXTURE_2D);
161
162 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
163 glEnableClientState(GL_VERTEX_ARRAY);
164 glDisableClientState(GL_COLOR_ARRAY);
165 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
166
167 glBindTexture(GL_TEXTURE_2D, m_opengl_id);
168 vertex_buffer.activate();
169 tex_coord_buffer.activate();
170 glDrawArrays(GL_TRIANGLE_STRIP, 0, vertex_buffer.size());
171
172 //glDisableClientState(GL_VERTEX_ARRAY);
173 //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
174
175 if (need_min_filter_change)
176 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_min_filter);
177 if (need_mag_filter_change)
178 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_mag_filter);
179
180 glPopClientAttrib();
181
182 glPopAttrib();
183 }
184
OrthoBlit(const Pt & pt) const185 void Texture::OrthoBlit(const Pt& pt) const
186 { OrthoBlit(pt, pt + Pt(m_default_width, m_default_height), m_tex_coords); }
187
Load(const boost::filesystem::path & path,bool mipmap)188 void Texture::Load(const boost::filesystem::path& path, bool mipmap/* = false*/)
189 {
190 namespace gil = boost::gil;
191 namespace fs = boost::filesystem;
192
193 if (m_opengl_id)
194 Clear();
195
196 if (!fs::exists(path)) {
197 std::cerr << "Texture::Load passed non-existant path: " << path.generic_string() << std::endl;
198 throw BadFile("Texture file \"" + path.generic_string() + "\" does not exist");
199 }
200 if (!fs::is_regular_file(path)) {
201 std::cerr << "Texture::Load passed non-file path: " << path.generic_string() << std::endl;
202 throw BadFile("Texture \"file\" \"" + path.generic_string() + "\" is not a file");
203 }
204
205 // convert path into UTF-8 format filename string
206 #if defined (_WIN32)
207 boost::filesystem::path::string_type path_native = path.native();
208 std::string filename;
209 utf8::utf16to8(path_native.begin(), path_native.end(), std::back_inserter(filename));
210 #else
211 std::string filename = path.generic_string();
212 #endif
213
214 static_assert(sizeof(gil::gray8_pixel_t) == 1, "gray8 pixel type does not match expected type size");
215 static_assert(sizeof(gil::gray_alpha8_pixel_t) == 2, "gray_alpha8 pixel type does not match expected type size");
216 static_assert(sizeof(gil::rgb8_pixel_t) == 3, "rgb8 pixel type does not match expected type size");
217 static_assert(sizeof(gil::rgba8_pixel_t) == 4, "rgba8 pixel type does not match expected type size");
218
219 #if BOOST_VERSION >= 107400
220 typedef gil::any_image<gil::gray8_image_t,
221 gil::gray_alpha8_image_t,
222 gil::rgb8_image_t,
223 gil::rgba8_image_t> ImageType;
224 #else
225 # ifdef BOOST_GIL_USES_MP11
226 typedef boost::mp11::mp_list<
227 # else
228 typedef boost::mpl::vector4<
229 # endif
230 gil::gray8_image_t,
231 gil::gray_alpha8_image_t,
232 gil::rgb8_image_t,
233 gil::rgba8_image_t
234 > ImageTypes;
235 typedef gil::any_image<ImageTypes> ImageType;
236 #endif
237 if (!fs::exists(path))
238 throw BadFile("Texture file \"" + filename + "\" does not exist");
239 if (!fs::is_regular_file(path))
240 throw BadFile("Texture \"file\" \"" + filename + "\" is not a file");
241
242 std::string extension = boost::algorithm::to_lower_copy(path.extension().string());
243
244 ImageType image;
245 try {
246 // First attempt -- try just to read the file in one of the default
247 // formats above.
248 #if GG_HAVE_LIBPNG
249 if (extension == ".png")
250 gil::read_image(filename, image, gil::image_read_settings<gil::png_tag>());
251 else
252 #endif
253 #if GG_HAVE_LIBTIFF
254 if (extension == ".tif" || extension == ".tiff")
255 gil::read_image(filename, image, gil::image_read_settings<gil::tiff_tag>());
256 else
257 #endif
258 throw BadFile("Texture file \"" + filename + "\" does not have a supported file extension");
259 } catch (const std::ios_base::failure&) {
260 // Second attempt -- If *_read_image() throws, see if we can convert
261 // the image to RGBA. This is needed for color-indexed images.
262 #if GG_HAVE_LIBPNG
263 if (extension == ".png") {
264 gil::rgba8_image_t rgba_image;
265 gil::read_and_convert_image(filename, rgba_image, gil::image_read_settings<gil::png_tag>());
266 image = std::move(rgba_image);
267 }
268 #endif
269 #if GG_HAVE_LIBTIFF
270 if (extension == ".tif" || extension == ".tiff") {
271 gil::rgba8_image_t rgba_image;
272 gil::read_and_convert_image(filename, rgba_image, gil::image_read_settings<gil::tiff_tag>());
273 image = std::move(rgba_image);
274 }
275 #endif
276 }
277
278 m_path = path;
279 m_default_width = X(image.width());
280 m_default_height = Y(image.height());
281 m_type = GL_UNSIGNED_BYTE;
282
283 #if BOOST_VERSION >= 107400
284 #define IF_IMAGE_TYPE_IS(image_prefix) \
285 if (boost::variant2::get_if<image_prefix ## _image_t>(&image)) { \
286 m_bytes_pp = sizeof(image_prefix ## _pixel_t); \
287 image_data = interleaved_view_get_raw_data( \
288 const_view(boost::variant2::get<image_prefix ## _image_t>(image))); \
289 }
290 #elif BOOST_VERSION >= 107000
291 #define IF_IMAGE_TYPE_IS(image_prefix) \
292 if (boost::get<image_prefix ## _image_t>(&image)) { \
293 m_bytes_pp = sizeof(image_prefix ## _pixel_t); \
294 image_data = interleaved_view_get_raw_data( \
295 const_view(boost::get<image_prefix ## _image_t>(image))); \
296 }
297 #else
298 #define IF_IMAGE_TYPE_IS(image_prefix) \
299 if (image.current_type_is<image_prefix ## _image_t>()) { \
300 m_bytes_pp = sizeof(image_prefix ## _pixel_t); \
301 image_data = interleaved_view_get_raw_data( \
302 const_view(image._dynamic_cast<image_prefix ## _image_t>())); \
303 }
304 #endif
305
306 const unsigned char* image_data = nullptr;
307
308 IF_IMAGE_TYPE_IS(gil::gray8)
309 else IF_IMAGE_TYPE_IS(gil::gray_alpha8)
310 else IF_IMAGE_TYPE_IS(gil::rgb8)
311 else IF_IMAGE_TYPE_IS(gil::rgba8)
312
313 #undef IF_IMAGE_TYPE_IS
314
315 switch (m_bytes_pp) {
316 case 1: m_format = GL_LUMINANCE; break;
317 case 2: m_format = GL_LUMINANCE_ALPHA; break;
318 case 3: m_format = GL_RGB; break;
319 case 4: m_format = GL_RGBA; break;
320 default: throw BadFile("Texture file \"" + filename + "\" does not have a supported number of color channels (1-4)");
321 }
322
323 assert(image_data);
324 Init(m_default_width, m_default_height, image_data, m_format, m_type, m_bytes_pp, mipmap);
325 }
326
Init(X width,Y height,const unsigned char * image,GLenum format,GLenum type,unsigned int bytes_per_pixel,bool mipmap)327 void Texture::Init(X width, Y height, const unsigned char* image, GLenum format, GLenum type,
328 unsigned int bytes_per_pixel, bool mipmap/* = false*/)
329 {
330 glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
331 glPixelStorei(GL_UNPACK_SWAP_BYTES, false);
332 glPixelStorei(GL_UNPACK_LSB_FIRST, false);
333 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
334 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
335 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
336 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
337
338 try {
339 InitFromRawData(width, height, image, format, type, bytes_per_pixel, mipmap);
340 } catch (...) {
341 glPopClientAttrib();
342 throw;
343 }
344
345 glPopClientAttrib();
346 }
347
SetFilters(GLenum min,GLenum mag)348 void Texture::SetFilters(GLenum min, GLenum mag)
349 {
350 m_min_filter = min;
351 m_mag_filter = mag;
352 if (m_opengl_id) {
353 glBindTexture(GL_TEXTURE_2D, m_opengl_id);
354 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_min_filter);
355 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_mag_filter);
356 }
357 }
358
Clear()359 void Texture::Clear()
360 {
361 if (m_opengl_id)
362 glDeleteTextures(1, &m_opengl_id);
363
364 m_path.clear();
365
366 m_bytes_pp = 4;
367 m_default_width = m_width = X0;
368 m_default_height = m_height = Y0;
369
370 m_wrap_s = m_wrap_t = GL_REPEAT;
371 m_min_filter = GL_LINEAR_MIPMAP_LINEAR;
372 m_mag_filter = GL_LINEAR;
373
374 m_mipmaps = false;
375 m_opengl_id = 0;
376 m_format = GL_INVALID_ENUM;
377 m_type = GL_INVALID_ENUM;
378
379 m_tex_coords[0] = m_tex_coords[1] = 0.0f; // min x, y
380 m_tex_coords[2] = m_tex_coords[3] = 1.0f; // max x, y
381 }
382
InitFromRawData(X width,Y height,const unsigned char * image,GLenum format,GLenum type,unsigned int bytes_per_pixel,bool mipmap)383 void Texture::InitFromRawData(X width, Y height, const unsigned char* image, GLenum format, GLenum type,
384 unsigned int bytes_per_pixel, bool mipmap)
385 {
386 if (!image)
387 return;
388
389 if (m_opengl_id)
390 Clear();
391
392 X GL_texture_width = PowerOfTwo(width);
393 Y GL_texture_height = PowerOfTwo(height);
394
395 glGenTextures(1, &m_opengl_id);
396 glBindTexture(GL_TEXTURE_2D, m_opengl_id);
397 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
398 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_min_filter);
399 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_mag_filter);
400 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrap_s);
401 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrap_t);
402
403 if (mipmap) {
404 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
405 } else {
406 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
407 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
408 }
409
410 glTexImage2D(GL_PROXY_TEXTURE_2D, 0, format, Value(GL_texture_width), Value(GL_texture_height), 0, format, type, nullptr);
411 GLint checked_format;
412 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &checked_format);
413 if (!checked_format)
414 throw InsufficientResources("Insufficient resources to create requested OpenGL texture");
415 bool image_is_power_of_two = width == GL_texture_width && height == GL_texture_height;
416 if (image_is_power_of_two) {
417 glTexImage2D(GL_TEXTURE_2D, 0, format, Value(width), Value(height), 0, format, type, image);
418 } else {
419 std::vector<unsigned char> zero_data(bytes_per_pixel * Value(GL_texture_width) * Value(GL_texture_height));
420 glTexImage2D(GL_TEXTURE_2D, 0, format, Value(GL_texture_width), Value(GL_texture_height), 0, format, type, &zero_data[0]);
421 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Value(width), Value(height), format, type, image);
422 }
423
424 m_mipmaps = mipmap;
425 m_default_width = width;
426 m_default_height = height;
427 m_bytes_pp = bytes_per_pixel;
428 {
429 GLint w, h;
430 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
431 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
432 m_width = X(w);
433 m_height = Y(h);
434 }
435 m_tex_coords[2] = Value(1.0 * m_default_width / m_width);
436 m_tex_coords[3] = Value(1.0 * m_default_height / m_height);
437 }
438
GetRawBytes()439 unsigned char* Texture::GetRawBytes()
440 {
441 unsigned char* retval = nullptr;
442 glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
443 glPixelStorei(GL_PACK_SWAP_BYTES, false);
444 glPixelStorei(GL_PACK_LSB_FIRST, false);
445 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
446 glPixelStorei(GL_PACK_SKIP_ROWS, 0);
447 glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
448 glPixelStorei(GL_PACK_ALIGNMENT, 1);
449
450 // get pixel data
451 typedef unsigned char uchar;
452 retval = new uchar[Value(m_width) * Value(m_height) * m_bytes_pp];
453 glGetTexImage(GL_TEXTURE_2D, 0, m_format, m_type, retval);
454 glPopClientAttrib();
455 return retval;
456 }
457
458
459 ///////////////////////////////////////
460 // class GG::SubTexture
461 ///////////////////////////////////////
SubTexture()462 SubTexture::SubTexture() :
463 m_width(0),
464 m_height(0),
465 m_tex_coords()
466 {}
467
SubTexture(const std::shared_ptr<const Texture> & texture,X x1,Y y1,X x2,Y y2)468 SubTexture::SubTexture(const std::shared_ptr<const Texture>& texture, X x1, Y y1, X x2, Y y2) :
469 m_texture(texture),
470 m_width(x2 - x1),
471 m_height(y2 - y1),
472 m_tex_coords()
473 {
474 if (!m_texture) throw BadTexture("Attempted to contruct subtexture from invalid texture");
475 if (x2 < x1 || y2 < y1) throw InvalidTextureCoordinates("Attempted to contruct subtexture from invalid coordinates");
476
477 m_tex_coords[0] = Value(x1 * 1.0 / texture->Width());
478 m_tex_coords[1] = Value(y1 * 1.0 / texture->Height());
479 m_tex_coords[2] = Value(x2 * 1.0 / texture->Width());
480 m_tex_coords[3] = Value(y2 * 1.0 / texture->Height());
481 }
482
SubTexture(const std::shared_ptr<const Texture> & texture)483 SubTexture::SubTexture(const std::shared_ptr<const Texture>& texture) :
484 m_texture(texture),
485 m_width(GG::X1),
486 m_height(GG::Y1),
487 m_tex_coords()
488 {
489 if (!m_texture) throw BadTexture("Attempted to contruct subtexture from invalid texture");
490
491 m_width = texture->Width();
492 m_height = texture->Height();
493
494 m_tex_coords[0] = 0.0f;
495 m_tex_coords[1] = 0.0f;
496 m_tex_coords[2] = 1.0f;
497 m_tex_coords[3] = 1.0f;
498 }
499
~SubTexture()500 SubTexture::~SubTexture()
501 {}
502
SubTexture(const SubTexture & rhs)503 SubTexture::SubTexture(const SubTexture& rhs)
504 { *this = rhs; }
505
operator =(const SubTexture & rhs)506 const SubTexture& SubTexture::operator=(const SubTexture& rhs)
507 {
508 if (this != &rhs) {
509 m_texture = rhs.m_texture;
510 m_width = rhs.m_width;
511 m_height = rhs.m_height;
512 m_tex_coords[0] = rhs.m_tex_coords[0];
513 m_tex_coords[1] = rhs.m_tex_coords[1];
514 m_tex_coords[2] = rhs.m_tex_coords[2];
515 m_tex_coords[3] = rhs.m_tex_coords[3];
516 }
517 return *this;
518 }
519
Empty() const520 bool SubTexture::Empty() const
521 { return !m_texture; }
522
TexCoords() const523 const GLfloat* SubTexture::TexCoords() const
524 { return m_tex_coords; }
525
Width() const526 X SubTexture::Width() const
527 { return m_width; }
528
Height() const529 Y SubTexture::Height() const
530 { return m_height; }
531
GetTexture() const532 const Texture* SubTexture::GetTexture() const
533 { return m_texture.get(); }
534
OrthoBlit(const Pt & pt1,const Pt & pt2) const535 void SubTexture::OrthoBlit(const Pt& pt1, const Pt& pt2) const
536 { if (m_texture) m_texture->OrthoBlit(pt1, pt2, m_tex_coords); }
537
OrthoBlit(const Pt & pt) const538 void SubTexture::OrthoBlit(const Pt& pt) const
539 { if (m_texture) m_texture->OrthoBlit(pt, pt + Pt(m_width, m_height), m_tex_coords); }
540
Clear()541 void SubTexture::Clear()
542 {
543 m_texture.reset();
544 m_width = X0;
545 m_height = Y0;
546 m_tex_coords[0] = 0.0f;
547 m_tex_coords[1] = 0.0f;
548 m_tex_coords[2] = 1.0f;
549 m_tex_coords[3] = 1.0f;
550 }
551
552 ///////////////////////////////////////
553 // class GG::TextureManager
554 ///////////////////////////////////////
TextureManager()555 TextureManager::TextureManager()
556 {}
557
Textures() const558 const std::map<std::string, std::shared_ptr<Texture>>& TextureManager::Textures() const
559 { return m_textures; }
560
StoreTexture(Texture * texture,const std::string & texture_name)561 std::shared_ptr<Texture> TextureManager::StoreTexture(Texture* texture, const std::string& texture_name)
562 {
563 std::shared_ptr<Texture> temp(texture);
564 return StoreTexture(temp, texture_name);
565 }
566
StoreTexture(const std::shared_ptr<Texture> & texture,const std::string & texture_name)567 std::shared_ptr<Texture> TextureManager::StoreTexture(const std::shared_ptr<Texture>& texture, const std::string& texture_name)
568 { return (m_textures[texture_name] = texture); }
569
GetTexture(const boost::filesystem::path & path,bool mipmap)570 std::shared_ptr<Texture> TextureManager::GetTexture(const boost::filesystem::path& path, bool mipmap/* = false*/)
571 {
572 std::map<std::string, std::shared_ptr<Texture>>::iterator it = m_textures.find(path.generic_string());
573 if (it == m_textures.end()) { // if no such texture was found, attempt to load it now, using name as the filename
574 //std::cout << "TextureManager::GetTexture storing new texture under name: " << path.generic_string();
575 return (m_textures[path.generic_string()] = LoadTexture(path, mipmap));
576 } else { // otherwise, just return the texture we found
577 return it->second;
578 }
579 }
580
FreeTexture(const boost::filesystem::path & path)581 void TextureManager::FreeTexture(const boost::filesystem::path& path)
582 { FreeTexture(path.generic_string()); }
583
FreeTexture(const std::string & name)584 void TextureManager::FreeTexture(const std::string& name)
585 {
586 std::map<std::string, std::shared_ptr<Texture>>::iterator it = m_textures.find(name);
587 if (it != m_textures.end())
588 m_textures.erase(it);
589 }
590
LoadTexture(const boost::filesystem::path & path,bool mipmap)591 std::shared_ptr<Texture> TextureManager::LoadTexture(const boost::filesystem::path& path, bool mipmap)
592 {
593 auto temp = std::make_shared<Texture>();
594 temp->Load(path, mipmap);
595 return (m_textures[path.generic_string()] = temp);
596 }
597
GetTextureManager()598 TextureManager& GG::GetTextureManager()
599 {
600 static TextureManager manager;
601 return manager;
602 }
603