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