| 1 | /* |
|---|
| 2 | * Filename : image2.cpp |
|---|
| 3 | * Author(s) : Chris Thielen (chris@epiar.net) |
|---|
| 4 | * Date Created : Saturday, January 31, 2009 |
|---|
| 5 | * Purpose : Image loading and display |
|---|
| 6 | * Notes : See this note section in image2.h for an important clarification about the handling |
|---|
| 7 | * of non-power of two image sizes and the difference between virtual/effective dimensions |
|---|
| 8 | * and real dimensions. |
|---|
| 9 | */ |
|---|
| 10 | |
|---|
| 11 | #include "Graphics/image2.h" |
|---|
| 12 | #include "Utilities/log.h" |
|---|
| 13 | |
|---|
| 14 | // Create instance by loading image from file |
|---|
| 15 | Image2::Image2( string filename ) { |
|---|
| 16 | // Initialize variables |
|---|
| 17 | w = h = rw = rh = image = 0; |
|---|
| 18 | scale_w = scale_h = 1.; |
|---|
| 19 | |
|---|
| 20 | Load(filename); |
|---|
| 21 | } |
|---|
| 22 | |
|---|
| 23 | // Load image from file |
|---|
| 24 | bool Image2::Load( string filename ) { |
|---|
| 25 | SDL_Surface *s = NULL; |
|---|
| 26 | |
|---|
| 27 | if( ( s = IMG_Load( filename.c_str() ) ) == NULL ) { |
|---|
| 28 | Log::Warning( "Failed to load %s", filename.c_str() ); |
|---|
| 29 | return( false ); |
|---|
| 30 | } |
|---|
| 31 | |
|---|
| 32 | // virtual/effective w/h is whatever the original file intended (eg ignoring canvas expansion) |
|---|
| 33 | w = s->w; |
|---|
| 34 | h = s->h; |
|---|
| 35 | |
|---|
| 36 | if( ConvertToTexture( s ) == false ) { |
|---|
| 37 | Log::Warning( "Failed to load %s", filename.c_str() ); |
|---|
| 38 | SDL_FreeSurface( s ); |
|---|
| 39 | |
|---|
| 40 | return( false ); |
|---|
| 41 | } |
|---|
| 42 | |
|---|
| 43 | return( true ); |
|---|
| 44 | } |
|---|
| 45 | |
|---|
| 46 | // Load image from buffer |
|---|
| 47 | bool Image2::Load( unsigned char *buf, int bufSize ) { |
|---|
| 48 | |
|---|
| 49 | } |
|---|
| 50 | |
|---|
| 51 | // Draw the image |
|---|
| 52 | void Image2::Draw( int x, int y, float angle ) { |
|---|
| 53 | |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | // Draw the image centered on (x,y) |
|---|
| 57 | void Image2::DrawCentered( int x, int y, float angle ) { |
|---|
| 58 | |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | // Returns the next highest power of two if num is not a power of two |
|---|
| 62 | int Image2::PowerOfTwo(int num) { |
|---|
| 63 | float q = (float)num; |
|---|
| 64 | |
|---|
| 65 | if(q != 1.) |
|---|
| 66 | while( !((int)( q /= 2. ) % 2) && q != 1. ); |
|---|
| 67 | |
|---|
| 68 | if(q != 1.) { |
|---|
| 69 | // num is not a power of two |
|---|
| 70 | int c = 1; |
|---|
| 71 | while(c < num) c *= 2; |
|---|
| 72 | return(c); |
|---|
| 73 | } else { |
|---|
| 74 | // num is a power of two |
|---|
| 75 | return(num); |
|---|
| 76 | } |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | // Converts an SDL surface to an OpenGL texture |
|---|
| 80 | bool Image2::ConvertToTexture( SDL_Surface *s ) { |
|---|
| 81 | assert(s); |
|---|
| 82 | |
|---|
| 83 | // delete an old loaded image if one eixsts |
|---|
| 84 | if( image ) { |
|---|
| 85 | glDeleteTextures( 1, &image ); |
|---|
| 86 | image = 0; |
|---|
| 87 | |
|---|
| 88 | Log::Warning( "Loading an image after another is loaded already. Deleting old ... " ); |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | // Check to see if we need to expand the image |
|---|
| 92 | int expanded_w = PowerOfTwo(s->w); |
|---|
| 93 | int expanded_h = PowerOfTwo(s->h); |
|---|
| 94 | |
|---|
| 95 | if(expanded_w == 1) expanded_w = 2; // many cards won't accept 1 as a power of two |
|---|
| 96 | if(expanded_h == 1) expanded_h = 2; |
|---|
| 97 | |
|---|
| 98 | if((expanded_w != s->w) || (expanded_h != s->h)) { |
|---|
| 99 | // Expand the canvas (needed) |
|---|
| 100 | SDL_Surface *newSurface = NULL; |
|---|
| 101 | newSurface = ExpandCanvas( s, expanded_w, expanded_h ); // ExpandCavas will set new scale_w/scale_h |
|---|
| 102 | s = newSurface; |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | // real width/height always equal the expanded canvas (or original canvas if no expansion)'s w/h |
|---|
| 106 | rw = s->w; |
|---|
| 107 | rh = s->h; |
|---|
| 108 | |
|---|
| 109 | // check the pixel format, since it could depend on the file format: |
|---|
| 110 | GLenum internal_format; |
|---|
| 111 | GLenum img_format, img_type; |
|---|
| 112 | switch (s->format->BitsPerPixel) { |
|---|
| 113 | case 32: img_format = GL_RGBA; img_type = GL_UNSIGNED_BYTE; |
|---|
| 114 | internal_format = GL_RGBA8; break; |
|---|
| 115 | case 24: img_format = GL_RGB; img_type = GL_UNSIGNED_BYTE; |
|---|
| 116 | internal_format = GL_RGB8; break; |
|---|
| 117 | case 16: img_format = GL_RGBA; img_type = GL_UNSIGNED_SHORT; |
|---|
| 118 | internal_format = GL_RGB5_A1; break; |
|---|
| 119 | default: img_format = GL_LUMINANCE; img_type = GL_UNSIGNED_BYTE; |
|---|
| 120 | internal_format=GL_LUMINANCE8; break; |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | // generate the texture |
|---|
| 124 | glGenTextures( 1, &image ); |
|---|
| 125 | |
|---|
| 126 | // use the bitmap data stored in the SDL_Surface |
|---|
| 127 | glBindTexture( GL_TEXTURE_2D, (unsigned int)image ); |
|---|
| 128 | |
|---|
| 129 | // these settings depend entirely on how you intend to use the texture! |
|---|
| 130 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); |
|---|
| 131 | glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); |
|---|
| 132 | |
|---|
| 133 | // turn on linear filtering |
|---|
| 134 | // upload the texture data, letting OpenGL do any required conversion. |
|---|
| 135 | glTexImage2D( GL_TEXTURE_2D, 0, internal_format, w, h, 0, img_format, img_type, s->pixels ); |
|---|
| 136 | |
|---|
| 137 | return( true ); |
|---|
| 138 | } |
|---|
| 139 | |
|---|
| 140 | SDL_Surface *Image2::ExpandCanvas( SDL_Surface *s, int w, int h ) { |
|---|
| 141 | SDL_Surface *expanded = NULL; |
|---|
| 142 | SDL_Surface *original = s; |
|---|
| 143 | |
|---|
| 144 | // create the expanded surface |
|---|
| 145 | expanded = SDL_CreateRGBSurface(original->flags, w, h, original->format->BitsPerPixel, |
|---|
| 146 | original->format->Rmask, original->format->Gmask, original->format->Bmask, |
|---|
| 147 | original->format->Amask); |
|---|
| 148 | assert( expanded ); |
|---|
| 149 | |
|---|
| 150 | // make sure alpha values are copied properly |
|---|
| 151 | SDL_SetAlpha( original, 0, SDL_ALPHA_OPAQUE ); |
|---|
| 152 | |
|---|
| 153 | // copy the old image to the upper-left corner of the expanded canvas |
|---|
| 154 | SDL_Rect area; |
|---|
| 155 | area.x = 0; |
|---|
| 156 | area.y = 0; |
|---|
| 157 | area.w = original->w; |
|---|
| 158 | area.h = original->h; |
|---|
| 159 | SDL_BlitSurface( original, &area, expanded, &area ); |
|---|
| 160 | |
|---|
| 161 | // re-calculate the texture coordinates given to opengl during drawing (u/v coordinates) |
|---|
| 162 | scale_w = (float)original->w / (float)w; |
|---|
| 163 | scale_h = (float)original->h / (float)h; |
|---|
| 164 | |
|---|
| 165 | // update the callee's pointer to the new image and free the old one |
|---|
| 166 | SDL_FreeSurface( original ); |
|---|
| 167 | |
|---|
| 168 | return( expanded ); |
|---|
| 169 | } |
|---|
| 170 | |
|---|