gl_texture.h
9.63 KB
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#ifndef STIM_GL_TEXTURE_H
#define STIM_GL_TEXTURE_H
#include <math.h>
#include <iostream>
#include <vector>
#include "../grids/image_stack.h"
//Visual Studio requires GLEW
#ifdef _WIN32
#include <GL/glew.h>
#endif
//#include <GL/glut.h>
#include <stim/gl/error.h>
namespace stim{
/*
class gl_texture
Uses image_stack class in order to create a texture object.
*/
template<typename T, typename F = float>
class gl_texture : public virtual image_stack<T, F>
{
protected:
//std::string path;
GLuint texID; //OpenGL object
GLenum texture_type; //1D, 2D, 3D
GLint interpolation;
GLint wrap;
GLenum cpu_type;
GLenum gpu_type;
GLenum format; //format for the texture (GL_RGBA, GL_LUMINANCE, etc.)
using image_stack<T>::R;
//using image_stack<T>::S;
using image_stack<T>::ptr;
/// Sets the internal texture_type, based on the data dimensions
void setTextureType(){
if (R[3] > 1) //if the third dimension is greater than 1
texture_type = GL_TEXTURE_3D; //this is a 3D texture
else if (R[2] > 1) //if the second dimension is greater than 1
texture_type = GL_TEXTURE_2D; //this is a 2D texture
else if (R[1] > 1) //if the dimension value is greater than 1
texture_type = GL_TEXTURE_1D; //this is a 1D texture
}
//initializes important variables
void init() {
texID = 0; //initialize texture ID to zero, default if OpenGL returns an error
//memset(R, 0, sizeof(size_t));
//memset(grid<T, 4, F>::S, 0, sizeof(F));
}
//guesses the color format of the texture
GLenum guess_format(){
size_t channels = R[0];
switch(channels){
case 1:
return GL_LUMINANCE;
case 2:
return GL_RG;
case 3:
return GL_RGB;
case 4:
return GL_RGBA;
default:
std::cout<<"Error in stim::gl_texture - unable to guess texture format based on number of channels ("<<R[4]<<")"<<std::endl;
exit(1);
}
}
//guesses the OpenGL CPU data type based on T
GLenum guess_cpu_type(){
// The following is C++ 11 code, but causes problems on some compilers (ex. nvcc). Below is my best approximation to a solution
//if(std::is_same<T, unsigned char>::value) return CV_MAKETYPE(CV_8U, (int)C());
//if(std::is_same<T, char>::value) return CV_MAKETYPE(CV_8S, (int)C());
//if(std::is_same<T, unsigned short>::value) return CV_MAKETYPE(CV_16U, (int)C());
//if(std::is_same<T, short>::value) return CV_MAKETYPE(CV_16S, (int)C());
//if(std::is_same<T, int>::value) return CV_MAKETYPE(CV_32S, (int)C());
//if(std::is_same<T, float>::value) return CV_MAKETYPE(CV_32F, (int)C());
//if(std::is_same<T, double>::value) return CV_MAKETYPE(CV_64F, (int)C());
if(typeid(T) == typeid(unsigned char)) return GL_UNSIGNED_BYTE;
if(typeid(T) == typeid(char)) return GL_BYTE;
if(typeid(T) == typeid(unsigned short)) return GL_UNSIGNED_SHORT;
if(typeid(T) == typeid(short)) return GL_SHORT;
if(typeid(T) == typeid(unsigned int)) return GL_UNSIGNED_INT;
if(typeid(T) == typeid(int)) return GL_INT;
if(typeid(T) == typeid(float)) return GL_FLOAT;
std::cout<<"ERROR in stim::gl_texture - no valid data type found"<<std::endl;
exit(1);
}
//Guesses the "internal format" of the texture to closely approximate the original format
GLint guess_gpu_type(){
switch(format){
case GL_LUMINANCE:
switch(cpu_type){
case GL_BYTE:
case GL_UNSIGNED_BYTE:
return GL_LUMINANCE8;
case GL_SHORT:
case GL_UNSIGNED_SHORT:
return GL_LUMINANCE16;
case GL_INT:
case GL_UNSIGNED_INT:
return GL_LUMINANCE32I_EXT;
case GL_FLOAT:
return GL_LUMINANCE32F_ARB;
default:
std::cout<<"error in stim::gl_texture - unable to guess GPU internal format"<<std::endl;
exit(1);
}
case GL_RGB:
switch(cpu_type){
case GL_BYTE:
case GL_UNSIGNED_BYTE:
return GL_RGB8;
case GL_SHORT:
case GL_UNSIGNED_SHORT:
return GL_RGB16;
case GL_INT:
case GL_UNSIGNED_INT:
return GL_RGB32I;
case GL_FLOAT:
return GL_RGB32F;
default:
std::cout<<"error in stim::gl_texture - unable to guess GPU internal format"<<std::endl;
exit(1);
}
case GL_RGBA:
switch(cpu_type){
case GL_BYTE:
case GL_UNSIGNED_BYTE:
return GL_RGBA8;
case GL_SHORT:
case GL_UNSIGNED_SHORT:
return GL_RGBA16;
case GL_INT:
case GL_UNSIGNED_INT:
return GL_RGBA32I;
case GL_FLOAT:
return GL_RGBA32F;
default:
std::cout<<"error in stim::gl_texture - unable to guess GPU internal format"<<std::endl;
exit(1);
}
default:
std::cout<<"error in stim::gl_texture - unable to guess GPU internal format"<<std::endl;
exit(1);
}
}
/// creates this texture in the current OpenGL context
void generate_texture(){
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
CHECK_OPENGL_ERROR
glGenTextures(1, &texID);
CHECK_OPENGL_ERROR
glBindTexture(texture_type, texID);
CHECK_OPENGL_ERROR
glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, interpolation);
CHECK_OPENGL_ERROR
glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, interpolation);
CHECK_OPENGL_ERROR
switch(texture_type){
case GL_TEXTURE_3D:
glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, wrap);
glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, wrap);
glTexParameteri(texture_type, GL_TEXTURE_WRAP_R, wrap);
glTexImage3D(texture_type, 0, gpu_type, (GLsizei)R[1], (GLsizei)R[2], (GLsizei)R[3], 0, format, cpu_type, ptr);
break;
case GL_TEXTURE_2D:
glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, wrap);
CHECK_OPENGL_ERROR
glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, wrap);
CHECK_OPENGL_ERROR
glTexImage2D(texture_type, 0, gpu_type, (GLsizei)R[1], (GLsizei)R[2], 0, format, cpu_type, ptr);
CHECK_OPENGL_ERROR
break;
case GL_TEXTURE_1D:
glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, wrap);
CHECK_OPENGL_ERROR
glTexImage1D(texture_type, 0, gpu_type, (GLsizei)R[1], 0, format, cpu_type, ptr);
CHECK_OPENGL_ERROR
break;
default:
std::cout<<"Error in stim::gl_texture - unrecognized texture target when generating texture"<<std::endl;
exit(1);
break;
}
CHECK_OPENGL_ERROR
}
void guess_parameters(){
setTextureType(); //set the texture type: 1D, 2D, 3D
format = guess_format(); //guess the texture format based on the number of image channels
cpu_type = guess_cpu_type(); //guess the CPU type based on the template
gpu_type = guess_gpu_type(); //guess the GPU type based on the format and template
}
public:
///default constructor
gl_texture( GLint interp = GL_LINEAR, //default to linear interpolation
GLint twrap = GL_REPEAT) //default repeating the texture at the edges
: image_stack<T>() {
init(); //initialize the texture with NULL values
interpolation = interp; //store the interpolation type
wrap = twrap; //store the wrap type
}
///@param is a mask indicating the files to load
///Creates an instance of the gl_texture object and initializes it with a file list
gl_texture(std::string file_mask, GLint interp = GL_LINEAR, GLint twrap = GL_REPEAT){
init();
interpolation = interp; //store interpolation type
wrap = twrap; //store wrap type
load_images(file_mask);
}
///Creates an instance of gl_texture and initializes with a file list
///@param file_list is a list of files
///@param interp is the type of texture interpolation (GL_LINEAR, GL_NEAREST)
///@param twrap is the type of texture wrapping
gl_texture(std::vector<std::string> file_list, GLint interp = GL_LINEAR, GLint twrap = GL_REPEAT){
init();
interpolation = interp;
wrap = twrap;
load_images(file_list);
}
///Attaches the texture to the current OpenGL context and makes it ready to render
void attach(){
if(texID == 0) generate_texture(); //generate the texture if it doesn't already exist
else{
std::cout<<"Texture has already been attached to a context."<<std::endl;
exit(1);
}
}
//binds a texture to be the current render source
void bind(){
glBindTexture(texture_type, texID); //bind the texture to the appropriate texture target
CHECK_OPENGL_ERROR
}
///returns the dimentions of the data in the x, y, z directions.
vec<int> getSize(){
stim::vec<int> size(R[1], R[2], R[3]);
return size;
}
void getSize(size_t& x, size_t& y, size_t& z) {
x = R[0]; y = R[1]; z = R[2];
}
///@param x size of the voxel in x direction
///@param y size of the voxel in y direction
///@param z size of the voxel in z direction
/// Sets the dimenstions of the voxels.
void setSpacing(float sx, float sy, float sz){
grid<T, 4, F>::S[1] = sx;
grid<T, 4, F>::S[2] = sy;
grid<T, 4, F>::S[3] = sz;
}
///Returns a stim::vec that contains the x, y, z sizes of the voxel.
vec<float> getDims(){
vec<float> dims(grid<T, 4, F>::S[1], grid<T, 4, F>::S[2], grid<T, 4, F>::S[3]);
return dims;
}
/// Loads a series of files specified by a list of strings
/// @param file_list is the vector of file names as strings
void load_images(std::vector<std::string> file_list){
image_stack<T, F>::load_images(file_list); //load the images
guess_parameters();
}
///@param file_mask specifies the file(s) to be loaded
/// Sets the path and calls the loader on that path.
void load_images(std::string file_mask){
image_stack<T>::load_images(file_mask); //load images
guess_parameters();
}
/// Returns the GLuint id of the texture created by/associated with the
/// instance of the gl_texture class.
GLuint getTexture(){
return texID;
}
T* getData(){
return ptr;
}
};
}
#endif