overlooked IMB_imbuf.h was already included inside an extern "C" section.
[blender-staging.git] / source / gameengine / Ketsji / BL_Texture.cpp
1 // ------------------------------------
2 #ifdef WIN32
3 #include <windows.h>
4 #endif // WIN32
5 #ifdef __APPLE__
6 #include <OpenGL/gl.h>
7 #include <OpenGL/glu.h>
8 #else
9 #include <GL/gl.h>
10 #include <GL/glu.h>
11 #endif
12
13 #include <iostream>
14
15 #include "BL_Material.h"
16 #include "BL_Texture.h"
17 #include "MT_assert.h"
18
19 #include "DNA_texture_types.h"
20 #include "DNA_image_types.h"
21 #include "IMB_imbuf_types.h"
22 #include "BKE_image.h"
23 #include "BLI_blenlib.h"
24
25 #include "RAS_GLExtensionManager.h"
26 using namespace bgl;
27
28 #define spit(x) std::cout << x << std::endl;
29
30 #include "MEM_guardedalloc.h"
31
32
33
34 extern "C" {
35         // envmaps
36         #include "IMB_imbuf.h"
37         
38         void my_envmap_split_ima(EnvMap *env);
39         void my_free_envmapdata(EnvMap *env);
40 }
41
42 // (n&(n-1)) zeros the least significant bit of n 
43 static int is_pow2(int num) {
44         return ((num)&(num-1))==0;
45 }
46 static int smaller_pow2(int num) {
47         while (!is_pow2(num))
48                 num= num&(num-1);
49         return num;     
50 }
51
52
53
54 BL_Texture::BL_Texture()
55 :       mTexture(0),
56         mError(0),
57         mOk(0),
58         mNeedsDeleted(0),
59         mType(0),
60         mName("")
61 {
62         // --
63 }
64
65 BL_Texture::~BL_Texture()
66 {
67         // --
68 }
69
70 void BL_Texture::DeleteTex()
71 {
72         if( mNeedsDeleted ) {
73                 glDeleteTextures(1, (GLuint*)&(*mTexture));
74                 mNeedsDeleted = 0;
75                 mOk = 0;
76         }
77 }
78
79
80 bool BL_Texture::InitFromImage( Image *img, bool mipmap)
81 {
82         if(!img || img->ok==0 ) {
83                 mError = true;
84                 mOk = false;
85                 return mOk;
86         }
87         if( img->ibuf==0 ) {
88                 load_image(img, IB_rect, "", 0);
89                 if(img->ibuf==0) {
90                         img->ok = 0;
91                         mError = true;
92                         mOk = false;
93                         return mOk;
94                 } 
95         }
96         mTexture = &img->bindcode;
97         mName = img->id.name;
98         mType = BL_TEX2D;
99         
100         // smoke em if we got em
101         if (*mTexture != 0) {
102                 glBindTexture(GL_TEXTURE_2D, *mTexture );
103                 Validate();
104                 return mOk;
105         }
106         glGenTextures(1, (GLuint*)mTexture);
107         InitGLTex(img->ibuf->rect, img->ibuf->x, img->ibuf->y, mipmap);
108         Validate();
109         return mOk;
110 }
111
112 void BL_Texture::InitGLTex(unsigned int *pix,int x,int y,bool mipmap)
113 {
114         if (!is_pow2(x) || !is_pow2(y) ) {
115                 InitNonPow2Tex(pix, x,y,mipmap);
116                 return;
117         }
118
119         glBindTexture(GL_TEXTURE_2D, *mTexture );
120         if( mipmap ) {
121                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
122                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
123                 gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, x, y, GL_RGBA, GL_UNSIGNED_BYTE, pix );
124         } 
125         else {
126                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
127                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
128                 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix );
129         }
130
131         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
132 }
133
134
135 void BL_Texture::InitNonPow2Tex(unsigned int *pix,int x,int y,bool mipmap)
136 {
137         int nx= smaller_pow2(x);
138         int ny= smaller_pow2(y);
139
140         unsigned int *newPixels = (unsigned int *)malloc(nx*ny*sizeof(unsigned int));
141         
142         gluScaleImage(GL_RGBA, x, y, GL_UNSIGNED_BYTE, pix, nx,ny, GL_UNSIGNED_BYTE, newPixels);
143         glBindTexture(GL_TEXTURE_2D, *mTexture );
144
145         if( mipmap ) {
146                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
147                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
148                 gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, nx, ny, GL_RGBA, GL_UNSIGNED_BYTE, newPixels );
149         }
150         else {
151                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
152                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
153                 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nx, ny, 0, GL_RGBA, GL_UNSIGNED_BYTE, newPixels );
154         }
155         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
156         free(newPixels);
157 }
158
159
160 bool BL_Texture::InitCubeMap( EnvMap *cubemap )
161 {
162 #ifdef GL_ARB_texture_cube_map
163         if(!RAS_EXT_support._ARB_texture_cube_map) {
164                 spit("cubemaps not supported");
165                 mError = true;
166                 mOk = false;
167                 return mOk;
168         }
169         
170         else if(!cubemap || cubemap->ima->ok==0 ) {
171                 mError = true;
172                 mOk = false;
173                 return mOk;
174         }
175
176         if( cubemap->ima->ibuf==0 )  {
177                 load_image(cubemap->ima, IB_rect, "", 0);
178                 if(cubemap->ima->ibuf==0) {
179                         cubemap->ima->ok = 0;
180                         mError = true;
181                         mOk = false;
182                         return mOk;
183                 }
184         }
185
186         EnvMap *CubeMap = cubemap;
187         mNeedsDeleted = 1;
188         mBlankTexture = 0;
189         mType = BL_TEXCUBE;
190         mTexture = &mBlankTexture;
191         mName = CubeMap->ima->id.name;
192
193         glGenTextures(1, (GLuint*)(mTexture));
194         glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, *mTexture );
195         bool needs_split = false;
196
197         if(!CubeMap->cube[0]) needs_split = true; 
198
199         if(needs_split){
200                 // split it
201                 my_envmap_split_ima(CubeMap);
202         }
203
204         int x = cubemap->ima->ibuf->x;
205         int y = cubemap->ima->ibuf->y;
206         unsigned int *data= (unsigned int *)malloc(x*y*sizeof(unsigned int));
207
208         // -----------------------------------
209         x       = CubeMap->cube[0]->ibuf->x;
210         y       = CubeMap->cube[0]->ibuf->y;
211
212         // check the first image, and assume the rest
213         if (!is_pow2(x) || !is_pow2(y))
214         {
215                 spit("invalid envmap size please render with CubeRes @ power of two");
216                 free(data);
217                 data = 0;
218                 mError = true;
219                 mOk = false;
220                 return mOk;
221         }
222         memcpy(data, CubeMap->cube[0]->ibuf->rect, (x*y*sizeof(unsigned int)));
223         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
224         
225         // -----------------------------------
226         x       = CubeMap->cube[1]->ibuf->x;
227         y       = CubeMap->cube[1]->ibuf->y;
228         memcpy(data, CubeMap->cube[1]->ibuf->rect, (x*y*sizeof(unsigned int)));
229         glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
230         
231         // -----------------------------------
232         x       = CubeMap->cube[2]->ibuf->x;
233         y       = CubeMap->cube[2]->ibuf->y;
234         memcpy(data, CubeMap->cube[2]->ibuf->rect, (x*y*sizeof(unsigned int)));
235         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
236         
237         // -----------------------------------
238         x       = CubeMap->cube[3]->ibuf->x;
239         y       = CubeMap->cube[3]->ibuf->y;
240         memcpy(data, CubeMap->cube[3]->ibuf->rect, (x*y*sizeof(unsigned int)));
241         glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
242         
243         // -----------------------------------
244         x       = CubeMap->cube[4]->ibuf->x;
245         y       = CubeMap->cube[4]->ibuf->y;
246         memcpy(data, CubeMap->cube[4]->ibuf->rect, (x*y*sizeof(unsigned int)));
247         glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
248         
249         // -----------------------------------
250         x       = CubeMap->cube[5]->ibuf->x;
251         y       = CubeMap->cube[5]->ibuf->y;
252         memcpy(data, CubeMap->cube[5]->ibuf->rect, (x*y*sizeof(unsigned int)));
253         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
254
255         glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
256         glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
257         glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S,     GL_REPEAT );
258         glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T,     GL_REPEAT );
259
260         if(data) {
261                 free(data);
262                 data = 0;
263         }
264         
265         if(needs_split) {
266                 // okay we allocated, swap back to orig and free used
267                 cubemap->ima = CubeMap->ima;
268                 my_free_envmapdata(CubeMap);
269         }
270         mOk = IsValid();
271         return mOk;
272
273 #else
274
275         mError = true;
276         mOk = false;
277         return mOk;
278
279 #endif//GL_ARB_texture_cube_map
280 }
281
282
283 STR_String BL_Texture::GetName() const
284 {
285         return mName;
286 }
287
288
289 bool BL_Texture::IsValid()
290 {
291         return (mTexture && *mTexture!= 0)?glIsTexture(*mTexture)!=0:false;
292 }
293
294
295 void BL_Texture::Validate()
296 {
297         mOk = IsValid();
298 }
299
300
301 bool BL_Texture::Ok()
302 {
303         return  ( mTexture?((!mError || mOk ) && *mTexture!= 0):0 ); 
304 }
305
306
307 unsigned int BL_Texture::GetTextureType() const
308 {
309         return mType;
310 }
311
312
313 BL_Texture::operator const unsigned int () const
314 {
315         return mTexture? *mTexture:0;
316 }
317
318 bool BL_Texture::SetGLTex(unsigned int tex)
319 {
320         return false;
321 }
322
323 extern "C" {
324
325 void my_envmap_split_ima(EnvMap *env)
326 {
327         ImBuf *ibuf;
328         Image *ima;
329         int dx, part;
330         
331         my_free_envmapdata(env);        
332         
333         dx= env->ima->ibuf->y;
334         dx/= 2;
335         if(3*dx != env->ima->ibuf->x) {
336                 printf("Incorrect envmap size\n");
337                 env->ok= 0;
338                 env->ima->ok= 0;
339         }
340         else {
341                 for(part=0; part<6; part++) {
342                         ibuf= IMB_allocImBuf(dx, dx, 24, IB_rect, 0);
343                         ima= (Image*)MEM_callocN(sizeof(Image), "image");
344                         ima->ibuf= ibuf;
345                         ima->ok= 1;
346                         env->cube[part]= ima;
347                 }
348                 IMB_rectop(env->cube[0]->ibuf, env->ima->ibuf, 
349                         0, 0, 0, 0, dx, dx, IMB_rectcpy, 0);
350                 IMB_rectop(env->cube[1]->ibuf, env->ima->ibuf, 
351                         0, 0, dx, 0, dx, dx, IMB_rectcpy, 0);
352                 IMB_rectop(env->cube[2]->ibuf, env->ima->ibuf, 
353                         0, 0, 2*dx, 0, dx, dx, IMB_rectcpy, 0);
354                 IMB_rectop(env->cube[3]->ibuf, env->ima->ibuf, 
355                         0, 0, 0, dx, dx, dx, IMB_rectcpy, 0);
356                 IMB_rectop(env->cube[4]->ibuf, env->ima->ibuf, 
357                         0, 0, dx, dx, dx, dx, IMB_rectcpy, 0);
358                 IMB_rectop(env->cube[5]->ibuf, env->ima->ibuf, 
359                         0, 0, 2*dx, dx, dx, dx, IMB_rectcpy, 0);
360                 env->ok= 2;
361         }
362 }
363
364
365 void my_free_envmapdata(EnvMap *env)
366 {
367         Image *ima;
368         unsigned int a, part;
369         
370         for(part=0; part<6; part++) {
371                 ima= env->cube[part];
372                 if(ima) {
373                         if(ima->ibuf) IMB_freeImBuf(ima->ibuf);
374
375                         for(a=0; a<BLI_ARRAY_NELEMS(ima->mipmap); a++) {
376                                 if(ima->mipmap[a]) IMB_freeImBuf(ima->mipmap[a]);
377                         }
378                         MEM_freeN(ima);
379                         env->cube[part]= 0;
380                 }
381         }
382         env->ok= 0;
383 }
384
385
386 }
387
388 unsigned int BL_Texture::mBlankTexture = 0;
389