1
//========================================================================
2
// GLFW - An OpenGL framework
6
// WWW: http://glfw.sourceforge.net
7
//------------------------------------------------------------------------
8
// Copyright (c) 2002-2006 Camilla Berglund
10
// This software is provided 'as-is', without any express or implied
11
// warranty. In no event will the authors be held liable for any damages
12
// arising from the use of this software.
14
// Permission is granted to anyone to use this software for any purpose,
15
// including commercial applications, and to alter it and redistribute it
16
// freely, subject to the following restrictions:
18
// 1. The origin of this software must not be misrepresented; you must not
19
// claim that you wrote the original software. If you use this software
20
// in a product, an acknowledgment in the product documentation would
21
// be appreciated but is not required.
23
// 2. Altered source versions must be plainly marked as such, and must not
24
// be misrepresented as being the original software.
26
// 3. This notice may not be removed or altered from any source
29
//========================================================================
31
//========================================================================
34
// This module acts as an interface for different image file formats (the
35
// image file format is detected automatically).
37
// By default the loaded image is rescaled (using bilinear interpolation)
38
// to the next higher 2^N x 2^M resolution, unless it has a valid
39
// 2^N x 2^M resolution. The interpolation is quite slow, even if the
40
// routine has been optimized for speed (a 200x200 RGB image is scaled to
41
// 256x256 in ~30 ms on a P3-500).
43
// Paletted images are converted to RGB/RGBA images.
45
// A convenience function is also included (glfwLoadTexture2D), which
46
// loads a texture image from a file directly to OpenGL texture memory,
47
// with an option to generate all mipmap levels. GL_SGIS_generate_mipmap
48
// is used whenever available, which should give an optimal mipmap
49
// generation speed (possibly performed in hardware). A software fallback
50
// method is included when GL_SGIS_generate_mipmap is not supported (it
51
// generates all mipmaps of a 256x256 RGB texture in ~3 ms on a P3-500).
53
//========================================================================
59
// We want to support automatic mipmap generation
60
#ifndef GL_SGIS_generate_mipmap
61
#define GL_GENERATE_MIPMAP_SGIS 0x8191
62
#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192
63
#define GL_SGIS_generate_mipmap 1
64
#endif // GL_SGIS_generate_mipmap
67
//************************************************************************
68
//**** GLFW internal functions ****
69
//************************************************************************
71
//========================================================================
72
// _glfwUpsampleImage() - Upsample image, from size w1 x h1 to w2 x h2
73
//========================================================================
75
static void _glfwUpsampleImage( unsigned char *src, unsigned char *dst,
76
int w1, int h1, int w2, int h2, int bpp )
78
int m, n, k, x, y, col8;
79
float dx, dy, xstep, ystep, col, col1, col2;
80
unsigned char *src1, *src2, *src3, *src4;
82
// Calculate scaling factor
83
xstep = (float)(w1-1) / (float)(w2-1);
84
ystep = (float)(h1-1) / (float)(h2-1);
86
// Copy source data to destination data with bilinear interpolation
87
// Note: The rather strange look of this routine is a direct result of
88
// my attempts at optimizing it. Improvements are welcome!
91
for( n = 0; n < h2; n ++ )
94
src1 = &src[ y*w1*bpp ];
95
src3 = y < (h1-1) ? src1 + w1*bpp : src1;
99
for( m = 0; m < w2; m ++ )
101
for( k = 0; k < bpp; k ++ )
105
col = col1 + (col2 - col1) * dx;
108
col2 = col1 + (col2 - col1) * dx;
109
col += (col2 - col) * dy;
110
col8 = (int) (col + 0.5);
111
if( col8 >= 256 ) col8 = 255;
112
*dst++ = (unsigned char) col8;
143
//========================================================================
144
// _glfwHalveImage() - Build the next mip-map level
145
//========================================================================
147
static int _glfwHalveImage( GLubyte *src, int *width, int *height,
150
int halfwidth, halfheight, m, n, k, idx1, idx2;
154
if( *width <= 1 && *height <= 1 )
159
// Calculate new width and height (handle 1D case)
160
halfwidth = *width > 1 ? *width / 2 : 1;
161
halfheight = *height > 1 ? *height / 2 : 1;
163
// Downsample image with a simple box-filter
165
if( *width == 1 || *height == 1 )
168
for( m = 0; m < halfwidth+halfheight-1; m ++ )
170
for( k = 0; k < components; k ++ )
172
*dst ++ = (GLubyte) (((int)*src +
173
(int)src[components] + 1) >> 1);
182
idx1 = *width*components;
183
idx2 = (*width+1)*components;
184
for( m = 0; m < halfheight; m ++ )
186
for( n = 0; n < halfwidth; n ++ )
188
for( k = 0; k < components; k ++ )
190
*dst ++ = (GLubyte) (((int)*src +
191
(int)src[components] +
193
(int)src[idx2] + 2) >> 2);
198
src += components * (*width);
202
// Return new width and height
204
*height = halfheight;
210
//========================================================================
211
// _glfwRescaleImage() - Rescales an image into power-of-two dimensions
212
//========================================================================
214
static int _glfwRescaleImage( GLFWimage* image )
216
int width, height, log2, newsize;
219
// Calculate next larger 2^N width
220
for( log2 = 0, width = image->Width; width > 1; width >>= 1, log2 ++ )
222
width = (int) 1 << log2;
223
if( width < image->Width )
228
// Calculate next larger 2^M height
229
for( log2 = 0, height = image->Height; height > 1; height >>= 1, log2 ++ )
231
height = (int) 1 << log2;
232
if( height < image->Height )
237
// Do we really need to rescale?
238
if( width != image->Width || height != image->Height )
240
// Allocate memory for new (upsampled) image data
241
newsize = width * height * image->BytesPerPixel;
242
data = (unsigned char *) malloc( newsize );
249
// Copy old image data to new image data with interpolation
250
_glfwUpsampleImage( image->Data, data, image->Width, image->Height,
251
width, height, image->BytesPerPixel );
253
// Free memory for old image data (not needed anymore)
256
// Set pointer to new image data, and set new image dimensions
258
image->Width = width;
259
image->Height = height;
266
//************************************************************************
267
//**** GLFW user functions ****
268
//************************************************************************
270
//========================================================================
271
// glfwReadImage() - Read an image from a named file
272
//========================================================================
274
GLFWAPI int GLFWAPIENTRY glfwReadImage( const char *name, GLFWimage *img,
279
// Is GLFW initialized?
280
if( !_glfwInitialized )
285
// Start with an empty image descriptor
288
img->BytesPerPixel = 0;
292
if( !_glfwOpenFileStream( &stream, name, "rb" ) )
297
// We only support TGA files at the moment
298
if( !_glfwReadTGA( &stream, img, flags ) )
300
_glfwCloseStream( &stream );
305
_glfwCloseStream( &stream );
307
// Should we rescale the image to closest 2^N x 2^M resolution?
308
if( !(flags & GLFW_NO_RESCALE_BIT) )
310
if( !_glfwRescaleImage( img ) )
316
// Interpret BytesPerPixel as an OpenGL format
317
switch( img->BytesPerPixel )
321
if( flags & GLFW_ALPHA_MAP_BIT )
323
img->Format = GL_ALPHA;
327
img->Format = GL_LUMINANCE;
331
img->Format = GL_RGB;
334
img->Format = GL_RGBA;
342
//========================================================================
343
// glfwReadMemoryImage() - Read an image file from a memory buffer
344
//========================================================================
346
GLFWAPI int GLFWAPIENTRY glfwReadMemoryImage( const void *data, long size, GLFWimage *img, int flags )
350
// Is GLFW initialized?
351
if( !_glfwInitialized )
356
// Start with an empty image descriptor
359
img->BytesPerPixel = 0;
363
if( !_glfwOpenBufferStream( &stream, (void*) data, size ) )
368
// We only support TGA files at the moment
369
if( !_glfwReadTGA( &stream, img, flags ) )
371
_glfwCloseStream( &stream );
376
_glfwCloseStream( &stream );
378
// Should we rescale the image to closest 2^N x 2^M resolution?
379
if( !(flags & GLFW_NO_RESCALE_BIT) )
381
if( !_glfwRescaleImage( img ) )
387
// Interpret BytesPerPixel as an OpenGL format
388
switch( img->BytesPerPixel )
392
if( flags & GLFW_ALPHA_MAP_BIT )
394
img->Format = GL_ALPHA;
398
img->Format = GL_LUMINANCE;
402
img->Format = GL_RGB;
405
img->Format = GL_RGBA;
413
//========================================================================
414
// glfwFreeImage() - Free allocated memory for an image
415
//========================================================================
417
GLFWAPI void GLFWAPIENTRY glfwFreeImage( GLFWimage *img )
419
// Is GLFW initialized?
420
if( !_glfwInitialized )
426
if( img->Data != NULL )
436
img->BytesPerPixel = 0;
440
//========================================================================
441
// glfwLoadTexture2D() - Read an image from a file, and upload it to
443
//========================================================================
445
GLFWAPI int GLFWAPIENTRY glfwLoadTexture2D( const char *name, int flags )
449
// Is GLFW initialized?
450
if( !_glfwInitialized || !_glfwWin.Opened )
455
// Force rescaling if necessary
456
if( !_glfwWin.Has_GL_ARB_texture_non_power_of_two )
458
flags &= (~GLFW_NO_RESCALE_BIT);
461
// Read image from file
462
if( !glfwReadImage( name, &img, flags ) )
467
if( !glfwLoadTextureImage2D( &img, flags ) )
472
// Data buffer is not needed anymore
473
glfwFreeImage( &img );
479
//========================================================================
480
// glfwLoadMemoryTexture2D() - Read an image from a buffer, and upload it to
482
//========================================================================
484
GLFWAPI int GLFWAPIENTRY glfwLoadMemoryTexture2D( const void *data, long size, int flags )
488
// Is GLFW initialized?
489
if( !_glfwInitialized || !_glfwWin.Opened )
494
// Force rescaling if necessary
495
if( !_glfwWin.Has_GL_ARB_texture_non_power_of_two )
497
flags &= (~GLFW_NO_RESCALE_BIT);
500
// Read image from file
501
if( !glfwReadMemoryImage( data, size, &img, flags ) )
506
if( !glfwLoadTextureImage2D( &img, flags ) )
511
// Data buffer is not needed anymore
512
glfwFreeImage( &img );
518
//========================================================================
519
// glfwLoadTextureImage2D() - Upload an image object to texture memory
520
//========================================================================
522
GLFWAPI int GLFWAPIENTRY glfwLoadTextureImage2D( GLFWimage *img, int flags )
524
GLint UnpackAlignment, GenMipMap;
525
int level, format, AutoGen, newsize, n;
526
unsigned char *data, *dataptr;
528
// Is GLFW initialized?
529
if( !_glfwInitialized || !_glfwWin.Opened )
534
// TODO: Use GL_MAX_TEXTURE_SIZE or GL_PROXY_TEXTURE_2D to determine
535
// whether the image size is valid.
536
// NOTE: May require box filter downsampling routine.
538
// Do we need to convert the alpha map to RGBA format (OpenGL 1.0)?
539
if( (_glfwWin.GLVerMajor == 1) && (_glfwWin.GLVerMinor == 0) &&
540
(img->Format == GL_ALPHA) )
542
// We go to RGBA representation instead
543
img->BytesPerPixel = 4;
545
// Allocate memory for new RGBA image data
546
newsize = img->Width * img->Height * img->BytesPerPixel;
547
data = (unsigned char *) malloc( newsize );
554
// Convert Alpha map to RGBA
556
for( n = 0; n < (img->Width*img->Height); ++ n )
561
*dataptr ++ = img->Data[n];
564
// Free memory for old image data (not needed anymore)
567
// Set pointer to new image data
571
// Set unpack alignment to one byte
572
glGetIntegerv( GL_UNPACK_ALIGNMENT, &UnpackAlignment );
573
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
575
// Should we use automatic mipmap generation?
576
AutoGen = ( flags & GLFW_BUILD_MIPMAPS_BIT ) &&
577
_glfwWin.Has_GL_SGIS_generate_mipmap;
579
// Enable automatic mipmap generation
582
glGetTexParameteriv( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,
584
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,
588
// Format specification is different for OpenGL 1.0
589
if( _glfwWin.GLVerMajor == 1 && _glfwWin.GLVerMinor == 0 )
591
format = img->BytesPerPixel;
595
format = img->Format;
598
// Upload to texture memeory
602
// Upload this mipmap level
603
glTexImage2D( GL_TEXTURE_2D, level, format,
604
img->Width, img->Height, 0, format,
605
GL_UNSIGNED_BYTE, (void*) img->Data );
607
// Build next mipmap level manually, if required
608
if( ( flags & GLFW_BUILD_MIPMAPS_BIT ) && !AutoGen )
610
level = _glfwHalveImage( img->Data, &img->Width,
611
&img->Height, img->BytesPerPixel ) ?
617
// Restore old automatic mipmap generation state
620
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,
624
// Restore old unpack alignment
625
glPixelStorei( GL_UNPACK_ALIGNMENT, UnpackAlignment );