-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTexture.cpp
177 lines (148 loc) · 6.34 KB
/
Texture.cpp
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include "Texture.h"
#include <iostream>
#include <FreeImage.h>
Texture::TextureIdHolder::TextureIdHolder(GLuint textureId) {
this->textureId = textureId;
}
Texture::TextureIdHolder::~TextureIdHolder() {
glDeleteTextures(1, &this->textureId);
}
Texture::Texture(GLuint textureId)
: textureIdHolder(new TextureIdHolder(textureId))
{
}
GLuint Texture::loadTextureFromFile(const char * fileName, GLenum minificationFilter, GLenum magnificationFilter) {
using namespace std;
// Determine the format of the image.
// Note: The second paramter ('size') is currently unused, and we should use 0 for it.
FREE_IMAGE_FORMAT format = FreeImage_GetFileType(fileName, 0);
// Image not found? Abort! Without this section we get a 0 by 0 image with 0 bits-per-pixel but we don't abort, which
// you might find preferable to dumping the user back to the desktop.
if (format == -1)
{
cout << "Could not find image: " << fileName << " - Aborting." << endl;
exit(-1);
}
// Found image, but couldn't determine the file format? Try again...
if (format == FIF_UNKNOWN)
{
cout << "Couldn't determine file format - attempting to get from file extension..." << endl;
// ...by getting the filetype from the filename extension (i.e. .PNG, .GIF etc.)
// Note: This is slower and more error-prone that getting it from the file itself,
// also, we can't use the 'U' (unicode) variant of this method as that's Windows only.
format = FreeImage_GetFIFFromFilename(fileName);
// Check that the plugin has reading capabilities for this format (if it's FIF_UNKNOWN,
// for example, then it won't have) - if we can't read the file, then we bail out =(
if (!FreeImage_FIFSupportsReading(format))
{
cout << "Detected image format cannot be read!" << endl;
exit(-1);
}
}
// If we're here we have a known image format, so load the image into a bitap
FIBITMAP* bitmap = FreeImage_Load(format, fileName);
// How many bits-per-pixel is the source image?
int bitsPerPixel = FreeImage_GetBPP(bitmap);
// Convert our image up to 32 bits (8 bits per channel, Red/Green/Blue/Alpha) -
// but only if the image is not already 32 bits (i.e. 8 bits per channel).
// Note: ConvertTo32Bits returns a CLONE of the image data - so if we
// allocate this back to itself without using our bitmap32 intermediate
// we will LEAK the original bitmap data, and valgrind will show things like this:
//
// LEAK SUMMARY:
// definitely lost: 24 bytes in 2 blocks
// indirectly lost: 1,024,874 bytes in 14 blocks <--- Ouch.
//
// Using our intermediate and cleaning up the initial bitmap data we get:
//
// LEAK SUMMARY:
// definitely lost: 16 bytes in 1 blocks
// indirectly lost: 176 bytes in 4 blocks
//
// All above leaks (192 bytes) are caused by XGetDefault (in /usr/lib/libX11.so.6.3.0) - we have no control over this.
//
FIBITMAP* bitmap32;
if (bitsPerPixel == 32)
{
cout << "Source image has " << bitsPerPixel << " bits per pixel. Skipping conversion." << endl;
bitmap32 = bitmap;
}
else
{
cout << "Source image has " << bitsPerPixel << " bits per pixel. Converting to 32-bit colour." << endl;
bitmap32 = FreeImage_ConvertTo32Bits(bitmap);
}
// Some basic image info - strip it out if you don't care
int imageWidth = FreeImage_GetWidth(bitmap32);
int imageHeight = FreeImage_GetHeight(bitmap32);
cout << "Image: " << fileName << " is size: " << imageWidth << "x" << imageHeight << "." << endl;
// Get a pointer to the texture data as an array of unsigned bytes.
// Note: At this point bitmap32 ALWAYS holds a 32-bit colour version of our image - so we get our data from that.
// Also, we don't need to delete or delete[] this textureData because it's not on the heap (so attempting to do
// so will cause a crash) - just let it go out of scope and the memory will be returned to the stack.
GLubyte* textureData = FreeImage_GetBits(bitmap32);
// Generate a texture ID and bind to it
GLuint tempTextureID;
glGenTextures(1, &tempTextureID);
glBindTexture(GL_TEXTURE_2D, tempTextureID);
// Construct the texture.
// Note: The 'Data format' is the format of the image data as provided by the image library. FreeImage decodes images into
// BGR/BGRA format, but we want to work with it in the more common RGBA format, so we specify the 'Internal format' as such.
glTexImage2D(GL_TEXTURE_2D, // Type of texture
0, // Mipmap level (0 being the top level i.e. full size)
GL_RGBA, // Internal format
imageWidth, // Width of the texture
imageHeight, // Height of the texture,
0, // Border in pixels
GL_BGRA, // Data format
GL_UNSIGNED_BYTE, // Type of texture data
textureData); // The image data to use for this texture
// Specify our minification and magnification filters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minificationFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magnificationFilter);
// If we're using MipMaps, then we'll generate them here.
// Note: The glGenerateMipmap call requires OpenGL 3.0 as a minimum.
if (minificationFilter == GL_LINEAR_MIPMAP_LINEAR ||
minificationFilter == GL_LINEAR_MIPMAP_NEAREST ||
minificationFilter == GL_NEAREST_MIPMAP_LINEAR ||
minificationFilter == GL_NEAREST_MIPMAP_NEAREST)
{
glGenerateMipmap(GL_TEXTURE_2D);
}
// Check for OpenGL texture creation errors
GLenum glError = glGetError();
if (glError)
{
cout << "There was an error loading the texture: " << fileName << endl;
switch (glError)
{
case GL_INVALID_ENUM:
cout << "Invalid enum." << endl;
break;
case GL_INVALID_VALUE:
cout << "Invalid value." << endl;
break;
case GL_INVALID_OPERATION:
cout << "Invalid operation." << endl;
default:
cout << "Unrecognised GLenum." << endl;
break;
}
cout << "See https://www.opengl.org/sdk/docs/man/html/glTexImage2D.xhtml for further details." << endl;
}
// Unload the 32-bit colour bitmap
FreeImage_Unload(bitmap32);
// If we had to do a conversion to 32-bit colour, then unload the original
// non-32-bit-colour version of the image data too. Otherwise, bitmap32 and
// bitmap point at the same data, and that data's already been free'd, so
// don't attempt to free it again! (or we'll crash).
if (bitsPerPixel != 32)
{
FreeImage_Unload(bitmap);
}
// Finally, return the texture ID
return tempTextureID;
}
GLuint Texture::getTextureId() const {
return this->textureIdHolder->textureId;
}