OpenGL hacks.
[dcpomatic.git] / hacks / gl / image_loader.cc
diff --git a/hacks/gl/image_loader.cc b/hacks/gl/image_loader.cc
new file mode 100644 (file)
index 0000000..76df14e
--- /dev/null
@@ -0,0 +1,176 @@
+#include "image_loader.h"
+#include <cmath>
+
+#include "wx/image.h"
+#include "wx/wx.h"
+
+
+GLuint* loadImage(wxString path, int* imageWidth, int* imageHeight, int* textureWidth, int* textureHeight)
+{
+
+       GLuint* ID=new GLuint[1];
+       glGenTextures( 1, &ID[0] );
+
+       glBindTexture( GL_TEXTURE_2D, *ID );
+
+       // the first time, init image handlers (remove this part if you do it somewhere else in your app)
+       static bool is_first_time = true;
+       if(is_first_time)
+       {
+               wxInitAllImageHandlers();
+
+               is_first_time = false;
+       }
+
+       // check the file exists
+       if(!wxFileExists(path))
+       {
+               wxMessageBox( _("Failed to load resource image") );
+               exit(1);
+       }
+
+       wxImage* img=new wxImage( path );
+
+       (*imageWidth)=img->GetWidth();
+       (*imageHeight)=img->GetHeight();
+
+       glPixelStorei(GL_UNPACK_ALIGNMENT,   1   );
+
+    /*
+     * Many graphics card require that textures be power of two.
+     * Below is a simple implementation, probably not optimal but working.
+     * If your texture sizes are not restricted to power of 2s, you can
+     * of course adapt the bit below as needed.
+     */
+
+       float power_of_two_that_gives_correct_width=std::log((float)(*imageWidth))/std::log(2.0);
+       float power_of_two_that_gives_correct_height=std::log((float)(*imageHeight))/std::log(2.0);
+
+        // check if image dimensions are a power of two
+        if( (int)power_of_two_that_gives_correct_width == power_of_two_that_gives_correct_width &&
+            (int)power_of_two_that_gives_correct_height == power_of_two_that_gives_correct_height)
+        {
+                // note: must make a local copy before passing the data to OpenGL, as GetData() returns RGB
+                // and we want the Alpha channel if it's present. Additionally OpenGL seems to interpret the
+                // data upside-down so we need to compensate for that.
+                GLubyte *bitmapData=img->GetData();
+                GLubyte *alphaData=img->GetAlpha();
+
+                int bytesPerPixel = img->HasAlpha() ?  4 : 3;
+
+                int imageSize = (*imageWidth) * (*imageHeight) * bytesPerPixel;
+                GLubyte *imageData=new GLubyte[imageSize];
+
+                int rev_val=(*imageHeight)-1;
+
+                for(int y=0; y<(*imageHeight); y++)
+                {
+                        for(int x=0; x<(*imageWidth); x++)
+                        {
+                                imageData[(x+y*(*imageWidth))*bytesPerPixel+0]=
+                                        bitmapData[( x+(rev_val-y)*(*imageWidth))*3];
+
+                                imageData[(x+y*(*imageWidth))*bytesPerPixel+1]=
+                                        bitmapData[( x+(rev_val-y)*(*imageWidth))*3 + 1];
+
+                                imageData[(x+y*(*imageWidth))*bytesPerPixel+2]=
+                                        bitmapData[( x+(rev_val-y)*(*imageWidth))*3 + 2];
+
+                                if(bytesPerPixel==4) imageData[(x+y*(*imageWidth))*bytesPerPixel+3]=
+                                        alphaData[ x+(rev_val-y)*(*imageWidth) ];
+                        }//next
+                }//next
+
+                // if yes, everything is fine
+                glTexImage2D(GL_TEXTURE_2D,
+                             0,
+                             bytesPerPixel,
+                             *imageWidth,
+                             *imageHeight,
+                             0,
+                             img->HasAlpha() ?  GL_RGBA : GL_RGB,
+                             GL_UNSIGNED_BYTE,
+                             imageData);
+
+                (*textureWidth)  = (*imageWidth);
+                (*textureHeight) = (*imageHeight);
+
+                delete [] imageData;
+        }
+       else // texture is not a power of two. We need to resize it
+       {
+
+               int newWidth=(int)std::pow( 2.0, (int)(std::ceil(power_of_two_that_gives_correct_width)) );
+               int newHeight=(int)std::pow( 2.0, (int)(std::ceil(power_of_two_that_gives_correct_height)) );
+
+               //printf("Unsupported image size. Recommand values: %i %i\n",newWidth,newHeight);
+
+               GLubyte *bitmapData=img->GetData();
+               GLubyte        *alphaData=img->GetAlpha();
+
+               int old_bytesPerPixel = 3;
+               int bytesPerPixel = img->HasAlpha() ?  4 : 3;
+
+               int imageSize = newWidth * newHeight * bytesPerPixel;
+               GLubyte *imageData=new GLubyte[imageSize];
+
+               int rev_val=(*imageHeight)-1;
+
+               for(int y=0; y<newHeight; y++)
+               {
+                       for(int x=0; x<newWidth; x++)
+                       {
+
+                               if( x<(*imageWidth) && y<(*imageHeight) ){
+                                       imageData[(x+y*newWidth)*bytesPerPixel+0]=
+                                       bitmapData[( x+(rev_val-y)*(*imageWidth))*old_bytesPerPixel + 0];
+
+                                       imageData[(x+y*newWidth)*bytesPerPixel+1]=
+                                               bitmapData[( x+(rev_val-y)*(*imageWidth))*old_bytesPerPixel + 1];
+
+                                       imageData[(x+y*newWidth)*bytesPerPixel+2]=
+                                               bitmapData[( x+(rev_val-y)*(*imageWidth))*old_bytesPerPixel + 2];
+
+                                       if(bytesPerPixel==4) imageData[(x+y*newWidth)*bytesPerPixel+3]=
+                                               alphaData[ x+(rev_val-y)*(*imageWidth) ];
+
+                               }
+                               else
+                               {
+
+                                       imageData[(x+y*newWidth)*bytesPerPixel+0] = 0;
+                                       imageData[(x+y*newWidth)*bytesPerPixel+1] = 0;
+                                       imageData[(x+y*newWidth)*bytesPerPixel+2] = 0;
+                                       if(bytesPerPixel==4) imageData[(x+y*newWidth)*bytesPerPixel+3] = 0;
+                               }
+
+                       }//next
+               }//next
+
+
+               glTexImage2D(GL_TEXTURE_2D,
+                                        0,
+                                        img->HasAlpha() ?  4 : 3,
+                                        newWidth,
+                                        newHeight,
+                                        0,
+                                        img->HasAlpha() ?  GL_RGBA : GL_RGB,
+                                        GL_UNSIGNED_BYTE,
+                                        imageData);
+
+               (*textureWidth)=newWidth;
+               (*textureHeight)=newHeight;
+
+               delete [] imageData;
+       }
+
+       // set texture parameters as you wish
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // GL_LINEAR
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // GL_LINEAR
+
+       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+       return ID;
+
+}