Simple Code to load DXT textures

Hello, I was looking for a simple sample, showing how to load a DXT texture (made with Nvidia photoshop plugin or Ati Compressonator).

I didn’t find exactly what i searched.
So I wrote my own code, based on code found.

I have a Segmentation fault when the glCompressedTexImage2DARB is called

Please can someone help me ?

 
const unsigned long FOURCC_DXT1 = 0x31545844; //(MAKEFOURCC('D','X','T','1'))
const unsigned long FOURCC_DXT3 = 0x33545844; //(MAKEFOURCC('D','X','T','3'))
const unsigned long FOURCC_DXT5 = 0x35545844; //(MAKEFOURCC('D','X','T','5'))

typedef struct
{
  GLsizei  width;
  GLsizei  height;
  GLint    components;
  GLenum   format;
  int      numMipMaps;
  GLubyte *pixels;
}
DDS_IMAGE_DATA;

typedef struct
{
  unsigned long dwSize;
  unsigned long dwFlags;
  unsigned long dwFourCC;
  unsigned long dwRGBBitCount;
  unsigned long dwRBitMask;
  unsigned long dwGBitMask;
  unsigned long dwBBitMask;
  unsigned long dwABitMask;
}
DDS_PIXELFORMAT;

typedef struct
{
  unsigned long dwSize;
  unsigned long dwFlags;
  unsigned long dwHeight;
  unsigned long dwWidth;
  unsigned long dwLinearSize;
  unsigned long dwDepth;
  unsigned long dwMipMapCount;
  unsigned long dwReserved1[11];
  DDS_PIXELFORMAT ddpfPixelFormat;
  unsigned long dwCaps1;
  unsigned long dwCaps2;
  unsigned long dwReserved2[3];
}
DDSURFACEDESC2;

PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB;

DDS_IMAGE_DATA* loadDDSTextureFile( const char *filename )
{
  DDS_IMAGE_DATA *pDDSImageData;
  DDSURFACEDESC2 ddsd;
  char filecode[4];
  FILE *pFile;
  int factor;
  int bufferSize;

  // Open the file
  pFile = fopen( filename, "rb" );

  if( pFile == NULL )
  {
    fclose( pFile );return 0;
  }

  // Verify the file is a true .dds file
  fread( filecode, 1, 4, pFile );

  if( strncmp( filecode, "DDS ", 4 ) != 0 )
  {
    fclose( pFile );
    return 0;
  }

  // Get the surface descriptor
  fread( &ddsd, sizeof(ddsd), 1, pFile );

  pDDSImageData = (DDS_IMAGE_DATA*) malloc(sizeof(DDS_IMAGE_DATA));

  memset( pDDSImageData, 0, sizeof(DDS_IMAGE_DATA) );

  if( ddsd.ddpfPixelFormat.dwFourCC ==FOURCC_DXT1)
  {
    // DXT1's compression ratio is 8:1
    pDDSImageData->format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
    factor = 2;
    pDDSImageData->components = 3;
  }
  else
  {
    if( ddsd.ddpfPixelFormat.dwFourCC ==FOURCC_DXT3)
    {
      // DXT3's compression ratio is 4:1
      pDDSImageData->format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
      factor = 4;
      pDDSImageData->components = 4;
    }
    else
    {
      if( ddsd.ddpfPixelFormat.dwFourCC ==FOURCC_DXT5)
      {
        // DXT5's compression ratio is 4:1
        pDDSImageData->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
        factor = 4;
        pDDSImageData->components = 4;
      }
      else
      {
        return 0;
      }
    }
  }

  if( ddsd.dwLinearSize == 0 )
  {
    return 0;
  }

  if( ddsd.dwMipMapCount > 1 )
    bufferSize = ddsd.dwLinearSize * factor;
  else
    bufferSize = ddsd.dwLinearSize;

  pDDSImageData->pixels = (unsigned char*)malloc(bufferSize * sizeof(unsigned char));

  fread( pDDSImageData->pixels, 1, bufferSize, pFile );

  // Close the file
  fclose( pFile );

  pDDSImageData->width      = ddsd.dwWidth;
  pDDSImageData->height     = ddsd.dwHeight;
  pDDSImageData->numMipMaps = ddsd.dwMipMapCount;
  return pDDSImageData;
}


int loadImage(int *l, char *file,int blur)
{
  int f;
  DDS_IMAGE_DATA *pDDSImageData;
  if (blur) f=GL_LINEAR; else f=GL_NEAREST;

  pDDSImageData = loadDDSTextureFile(file);

  if( pDDSImageData != NULL )
  {
    int nHeight     = pDDSImageData->height;
    int nWidth      = pDDSImageData->width;
    int nNumMipMaps = pDDSImageData->numMipMaps;
    int nSize;
    int nOffset = 0;
    int i;
    GLuint g_compressedTextureID = -1;
    int nBlockSize;

    if( pDDSImageData->format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT )
      nBlockSize = 8;
    else
      nBlockSize = 16;

    glGenTextures( 1, &g_compressedTextureID );
    glBindTexture( GL_TEXTURE_2D, g_compressedTextureID );
    *l = g_compressedTextureID;

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, f );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, f );

    // Load the mip-map levels

    unsigned int size = (((nWidth >> 2) + 3) & ~3) * (((nHeight >> 2) + 3) & ~3) * nBlockSize;
    if (pDDSImageData->pixels != NULL)
    {

      glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, pDDSImageData->format,
                                nWidth, nHeight, 0,
                                size,
                                pDDSImageData->pixels);

    }
    for(i = 0; i < nNumMipMaps; ++i )
    {
      if( nWidth  == 0 ) nWidth  = 1;
      if( nHeight == 0 ) nHeight = 1;

      nSize = ((nWidth+3)/4) * ((nHeight+3)/4) * nBlockSize;

      glCompressedTexImage2DARB( GL_TEXTURE_2D,
                                 i,
                                 pDDSImageData->format,
                                 nWidth,
                                 nHeight,
                                 0,
                                 nSize,
                                 pDDSImageData->pixels + nOffset );

      nOffset += nSize;

      // Half the image size for the next mip-map level...
      nWidth  = (nWidth  / 2);
      nHeight = (nHeight / 2);
    }
  }

  if( pDDSImageData != NULL )
  {
    if( pDDSImageData->pixels != NULL )
      free( pDDSImageData->pixels );

    free( pDDSImageData );
  }

  return 1;
}

 

do you think this question could be answered in the “OpenGL coding: advanced” ?