LCOV - code coverage report
Current view: directory - frmts/dds - ddsdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 137 108 78.8 %
Date: 2013-03-30 Functions: 5 4 80.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: $
       3                 :  *
       4                 :  * Project:  DDS Driver
       5                 :  * Purpose:  Implement GDAL DDS Support
       6                 :  * Author:   Alan Boudreault, aboudreault@mapgears.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2013, Alan Boudreault
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ******************************************************************************
      29                 :  *
      30                 :  * THE CURRENT IMPLEMENTATION IS WRITE ONLY.
      31                 :  * 
      32                 :  */
      33                 : 
      34                 : #include "gdal_pam.h"
      35                 : #include "crnlib.h"
      36                 : #include "dds_defs.h"
      37                 : 
      38                 : CPL_CVSID("$Id: $");
      39                 : 
      40                 : CPL_C_START
      41                 : void  GDALRegister_DDS(void);
      42                 : CPL_C_END
      43                 : 
      44                 : using namespace crnlib;
      45                 : 
      46                 : enum { DDS_COLOR_TYPE_RGB,
      47                 :        DDS_COLOR_TYPE_RGB_ALPHA };
      48                 : 
      49                 : 
      50                 : /************************************************************************/
      51                 : /* ==================================================================== */
      52                 : /*        DDSDataset        */
      53                 : /* ==================================================================== */
      54                 : /************************************************************************/
      55                 : 
      56                 : class DDSDataset : public GDALPamDataset
      57               4 : {
      58                 : public:
      59                 :     static GDALDataset* CreateCopy(const char * pszFilename,
      60                 :                                    GDALDataset *poSrcDS,
      61                 :                                    int bStrict, char ** papszOptions,
      62                 :                                    GDALProgressFunc pfnProgress,
      63                 :                                    void * pProgressData);
      64                 : };
      65                 : 
      66                 : 
      67                 : /************************************************************************/
      68                 : /*                             CreateCopy()                             */
      69                 : /************************************************************************/
      70                 : 
      71                 : GDALDataset *
      72              20 : DDSDataset::CreateCopy(const char * pszFilename, GDALDataset *poSrcDS, 
      73                 :                        int bStrict, char ** papszOptions, 
      74                 :                        GDALProgressFunc pfnProgress, void * pProgressData)
      75                 : 
      76                 : {  
      77              20 :     int  nBands = poSrcDS->GetRasterCount();
      78              20 :     int  nXSize = poSrcDS->GetRasterXSize();
      79              20 :     int  nYSize = poSrcDS->GetRasterYSize();
      80                 :     
      81                 :     /* -------------------------------------------------------------------- */
      82                 :     /*      Some rudimentary checks                                         */
      83                 :     /* -------------------------------------------------------------------- */
      84              20 :     if (nBands != 3 && nBands != 4)
      85                 :     {
      86                 :         CPLError(CE_Failure, CPLE_NotSupported, 
      87                 :                  "DDS driver doesn't support %d bands. Must be 3 (rgb) \n"
      88                 :                  "or 4 (rgba) bands.\n", 
      89              16 :                  nBands);
      90                 :         
      91              16 :         return NULL;
      92                 :     }
      93                 : 
      94               4 :     if (poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte)
      95                 :     {
      96                 :         CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported, 
      97                 :                   "DDS driver doesn't support data type %s. "
      98                 :                   "Only eight bit (Byte) bands supported. %s\n", 
      99                 :                   GDALGetDataTypeName( 
     100                 :                                       poSrcDS->GetRasterBand(1)->GetRasterDataType()),
     101               0 :                   (bStrict) ? "" : "Defaulting to Byte" );
     102                 : 
     103               0 :         if (bStrict)
     104               0 :             return NULL;
     105                 :     }
     106                 : 
     107                 :     /* -------------------------------------------------------------------- */
     108                 :     /*      Setup some parameters.                                          */
     109                 :     /* -------------------------------------------------------------------- */
     110               4 :     int  nColorType = 0;
     111                 : 
     112               4 :     if (nBands == 3)
     113               2 :       nColorType = DDS_COLOR_TYPE_RGB;
     114               2 :     else if (nBands == 4)
     115               2 :       nColorType = DDS_COLOR_TYPE_RGB_ALPHA;
     116                 : 
     117                 :     /* -------------------------------------------------------------------- */
     118                 :     /*      Create the dataset.                                             */
     119                 :     /* -------------------------------------------------------------------- */
     120                 :     VSILFILE  *fpImage;
     121                 : 
     122               4 :     fpImage = VSIFOpenL(pszFilename, "wb");
     123               4 :     if (fpImage == NULL)
     124                 :     {
     125                 :         CPLError(CE_Failure, CPLE_OpenFailed, 
     126                 :                  "Unable to create dds file %s.\n", 
     127               2 :                  pszFilename);
     128               2 :         return NULL;
     129                 :     }
     130                 : 
     131                 :     /* -------------------------------------------------------------------- */
     132                 :     /*      Create the Crunch compressor                                    */
     133                 :     /* -------------------------------------------------------------------- */
     134                 :     
     135                 :     /* Default values */
     136               2 :     crn_format fmt = cCRNFmtDXT3; 
     137               2 :     const uint cDXTBlockSize = 4;    
     138               2 :     crn_dxt_quality dxt_quality = cCRNDXTQualityNormal;
     139               2 :     bool srgb_colorspace = true;    
     140               2 :     bool dxt1a_transparency = true;
     141                 :     
     142                 :     /* Check the texture format */
     143               2 :     const char *pszFormat = CSLFetchNameValue( papszOptions, "FORMAT" );
     144                 : 
     145               2 :     if (pszFormat)
     146                 :     {
     147               0 :         if (EQUAL(pszFormat, "dxt1"))
     148               0 :             fmt = cCRNFmtDXT1;
     149               0 :         else if (EQUAL(pszFormat, "dxt1a"))
     150               0 :             fmt = cCRNFmtDXT1;
     151               0 :         else if (EQUAL(pszFormat, "dxt3"))
     152               0 :             fmt = cCRNFmtDXT3;
     153               0 :         else if (EQUAL(pszFormat, "dxt5"))
     154               0 :             fmt = cCRNFmtDXT5;
     155                 :         else
     156                 :         {
     157                 :             CPLError( CE_Failure, CPLE_AppDefined,
     158                 :                       "Illegal FORMAT value '%s', should be DXT1, DXT1A, DXT3 or DXT5.",
     159               0 :                       pszFormat );
     160               0 :             return NULL;
     161                 :         }
     162                 :     }
     163                 : 
     164                 :     /* Check the compression quality */
     165               2 :     const char *pszQuality = CSLFetchNameValue( papszOptions, "QUALITY" );
     166                 : 
     167               2 :     if (pszQuality)
     168                 :     {
     169               0 :         if (EQUAL(pszQuality, "SUPERFAST"))
     170               0 :             dxt_quality = cCRNDXTQualitySuperFast;            
     171               0 :         else if (EQUAL(pszQuality, "FAST"))
     172               0 :             dxt_quality = cCRNDXTQualityFast;
     173               0 :         else if (EQUAL(pszQuality, "NORMAL"))
     174               0 :             dxt_quality = cCRNDXTQualityNormal;
     175               0 :         else if (EQUAL(pszQuality, "BETTER"))
     176               0 :             dxt_quality = cCRNDXTQualityBetter;
     177               0 :         else if (EQUAL(pszQuality, "UBER"))
     178               0 :             dxt_quality = cCRNDXTQualityUber;        
     179                 :         else
     180                 :         {
     181                 :             CPLError( CE_Failure, CPLE_AppDefined,
     182                 :                       "Illegal QUALITY value '%s', should be SUPERFAST, FAST, NORMAL, BETTER or UBER.",
     183               0 :                       pszQuality );
     184               0 :             return NULL;
     185                 :         }
     186                 :     }
     187                 : 
     188               2 :     if ((nXSize%4!=0) || (nYSize%4!=0)) {
     189                 :       CPLError(CE_Warning, CPLE_AppDefined,
     190                 :                "Raster size is not a multiple of 4: %dx%d. "
     191                 :                "Extra rows/colums will be ignored during the compression.",
     192               2 :                nXSize, nYSize);
     193                 :     }
     194                 :     
     195               2 :     crn_comp_params comp_params;
     196               2 :     comp_params.m_format = fmt;
     197               2 :     comp_params.m_dxt_quality = dxt_quality;
     198               2 :     comp_params.set_flag(cCRNCompFlagPerceptual, srgb_colorspace);
     199               2 :     comp_params.set_flag(cCRNCompFlagDXT1AForTransparency, dxt1a_transparency);
     200                 :     
     201               2 :     crn_block_compressor_context_t pContext = crn_create_block_compressor(comp_params);
     202                 :     
     203                 :     /* -------------------------------------------------------------------- */
     204                 :     /*      Write the DDS header to the file.                               */
     205                 :     /* -------------------------------------------------------------------- */
     206                 : 
     207                 :     VSIFWriteL(&crnlib::cDDSFileSignature, 1,
     208               2 :                sizeof(crnlib::cDDSFileSignature), fpImage);
     209                 :     
     210                 :     crnlib::DDSURFACEDESC2 ddsDesc;
     211               2 :     memset(&ddsDesc, 0, sizeof(ddsDesc));
     212               2 :     ddsDesc.dwSize = sizeof(ddsDesc);
     213               2 :     ddsDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
     214               2 :     ddsDesc.dwWidth = nXSize;
     215               2 :     ddsDesc.dwHeight = nYSize;
     216                 :     
     217               2 :     ddsDesc.ddpfPixelFormat.dwSize = sizeof(crnlib::DDPIXELFORMAT);
     218               2 :     ddsDesc.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
     219               2 :     ddsDesc.ddpfPixelFormat.dwFourCC = crn_get_format_fourcc(fmt);
     220               2 :     ddsDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
     221                 : 
     222                 :     // Set pitch/linearsize field (some DDS readers require this field to be non-zero).
     223               2 :     uint bits_per_pixel = crn_get_format_bits_per_texel(fmt);
     224               2 :     ddsDesc.lPitch = (((ddsDesc.dwWidth + 3) & ~3) * ((ddsDesc.dwHeight + 3) & ~3) * bits_per_pixel) >> 3;
     225               2 :     ddsDesc.dwFlags |= DDSD_LINEARSIZE;
     226                 : 
     227                 :     /* Endianness problems when serializing structure?? dds on-disk format
     228                 :        should be verified */
     229               2 :     VSIFWriteL(&ddsDesc, 1, sizeof(ddsDesc), fpImage);
     230                 :     
     231                 :     /* -------------------------------------------------------------------- */
     232                 :     /*      Loop over image, compressing image data.                        */
     233                 :     /* -------------------------------------------------------------------- */
     234               2 :     const uint bytesPerBlock = crn_get_bytes_per_dxt_block(fmt);
     235               2 :     CPLErr eErr = CE_None;
     236               2 :     const uint nYNumBlocks = (nYSize + cDXTBlockSize - 1) / cDXTBlockSize;  
     237               2 :     const uint num_blocks_x = (nXSize + cDXTBlockSize - 1) / cDXTBlockSize;
     238               2 :     const uint total_compressed_size = num_blocks_x * bytesPerBlock;
     239                 : 
     240               2 :     void *pCompressed_data = CPLMalloc(total_compressed_size);
     241               2 :     GByte* pabyScanlines = (GByte *) CPLMalloc(nBands * nXSize * cDXTBlockSize);
     242               2 :     crn_uint32 *pixels = (crn_uint32*) CPLMalloc(sizeof(crn_uint32)*cDXTBlockSize * cDXTBlockSize);
     243               2 :     crn_uint32 *src_image = NULL;
     244               2 :     if (nColorType == DDS_COLOR_TYPE_RGB)
     245               1 :         src_image = (crn_uint32*) CPLMalloc(sizeof(crn_uint32)*nXSize*cDXTBlockSize);
     246                 : 
     247               8 :     for (uint iLine = 0; iLine < nYNumBlocks && eErr == CE_None; iLine++)
     248                 :     {
     249                 :         const uint size_y = (iLine*cDXTBlockSize+cDXTBlockSize) < (uint)nYSize ?
     250               6 :                            cDXTBlockSize : (cDXTBlockSize-((iLine*cDXTBlockSize+cDXTBlockSize)-(uint)nYSize));
     251                 :         
     252                 :         eErr = poSrcDS->RasterIO(GF_Read, 0, iLine*cDXTBlockSize, nXSize, size_y, 
     253                 :                                  pabyScanlines, nXSize, size_y, GDT_Byte,
     254                 :                                  nBands, NULL,
     255                 :                                  nBands, 
     256               6 :                                  nBands * nXSize, 1);
     257                 : 
     258               6 :         if (eErr != CE_None)
     259               0 :             break;
     260                 :         
     261               6 :         crn_uint32 *pSrc_image = NULL;
     262               6 :         if (nColorType == DDS_COLOR_TYPE_RGB_ALPHA)
     263               3 :             pSrc_image = (crn_uint32*)pabyScanlines;
     264               3 :         else if (nColorType == DDS_COLOR_TYPE_RGB)
     265                 :         { /* crunch needs 32bits integers */
     266               3 :             int nPixels = nXSize*cDXTBlockSize;
     267             123 :             for (int i=0; i<nPixels;++i)
     268                 :             {
     269             120 :                 int y = (i*3);
     270             240 :                 src_image[i] = (255<<24) | (pabyScanlines[y+2]<<16) | (pabyScanlines[y+1]<<8) |
     271             240 :                   pabyScanlines[y];            
     272                 :             }
     273                 :             
     274               3 :             pSrc_image = &(src_image[0]);
     275                 :         }
     276                 : 
     277              24 :         for (crn_uint32 block_x = 0; block_x < num_blocks_x; block_x++)
     278                 :         {
     279                 :             // Exact block from image, clamping at the sides of non-divisible by
     280                 :             // 4 images to avoid artifacts.
     281              18 :             crn_uint32 *pDst_pixels = pixels;
     282              90 :             for (uint y = 0; y < cDXTBlockSize; y++)
     283                 :             {
     284              72 :                 const uint actual_y = MIN(cDXTBlockSize - 1U, y);
     285             360 :                 for (uint x = 0; x < cDXTBlockSize; x++)
     286                 :                 {
     287             288 :                     const uint actual_x = MIN(nXSize - 1U, (block_x * cDXTBlockSize) + x);
     288             288 :                     *pDst_pixels++ = pSrc_image[actual_x + actual_y * nXSize];
     289                 :                 }
     290                 :             }
     291                 :             
     292                 :             // Compress the DXTn block.
     293              18 :             crn_compress_block(pContext, pixels, static_cast<crn_uint8 *>(pCompressed_data) + block_x * bytesPerBlock);
     294                 :         }
     295                 : 
     296               6 :         if (eErr == CE_None)
     297               6 :             VSIFWriteL(pCompressed_data, 1, total_compressed_size, fpImage);
     298                 : 
     299               6 :         if (eErr == CE_None
     300                 :             && !pfnProgress( (iLine+1) / (double) nYNumBlocks,
     301                 :                              NULL, pProgressData))
     302                 :         {
     303               0 :             eErr = CE_Failure;
     304                 :             CPLError(CE_Failure, CPLE_UserInterrupt,
     305               0 :                       "User terminated CreateCopy()");
     306                 :         }
     307                 : 
     308                 :     }
     309                 : 
     310               2 :     CPLFree(src_image);
     311               2 :     CPLFree(pixels);
     312               2 :     CPLFree(pCompressed_data);
     313               2 :     CPLFree(pabyScanlines);
     314               2 :     crn_free_block_compressor(pContext);
     315               2 :     pContext = NULL;
     316                 :    
     317               2 :     VSIFCloseL(fpImage);
     318                 : 
     319               2 :     if (eErr != CE_None)
     320               0 :         return NULL;
     321                 : 
     322               2 :     DDSDataset *poDsDummy = new DDSDataset();
     323                 :     
     324               2 :     return poDsDummy;
     325                 : }
     326                 : 
     327                 : /************************************************************************/
     328                 : /*                          GDALRegister_DDS()                          */
     329                 : /************************************************************************/
     330                 : 
     331             610 : void GDALRegister_DDS()
     332                 : {
     333                 :     GDALDriver  *poDriver;
     334                 : 
     335             610 :     if (GDALGetDriverByName( "DDS" ) == NULL)
     336                 :     {
     337             588 :         poDriver = new GDALDriver();
     338                 :         
     339             588 :         poDriver->SetDescription("DDS");
     340                 :         poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, 
     341             588 :                                   "DirectDraw Surface");
     342             588 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_various.html#DDS" );        
     343             588 :         poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "dds");
     344             588 :         poDriver->SetMetadataItem(GDAL_DMD_MIMETYPE, "image/dds");
     345                 : 
     346                 :         poDriver->SetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST, 
     347                 :                                   "<CreationOptionList>\n"
     348                 :                                   "   <Option name='FORMAT' type='string-select' description='Texture format' default='DXT3'>\n"
     349                 :                                   "     <Value>DXT1</Value>\n"
     350                 :                                   "     <Value>DXT1A</Value>\n"
     351                 :                                   "     <Value>DXT3</Value>\n"
     352                 :                                   "     <Value>DXT5</Value>\n"                                                                    
     353                 :                                   "   </Option>\n"
     354                 :                                   "   <Option name='QUALITY' type='string-select' description='Compression Quality' default='NORMAL'>\n"
     355                 :                                   "     <Value>SUPERFAST</Value>\n"
     356                 :                                   "     <Value>FAST</Value>\n"
     357                 :                                   "     <Value>NORMAL</Value>\n"
     358                 :                                   "     <Value>BETTER</Value>\n"
     359                 :                                   "     <Value>UBER</Value>\n"                                                                                                      
     360                 :                                   "   </Option>\n"                                  
     361             588 :                                   "</CreationOptionList>\n" );
     362                 : 
     363             588 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
     364                 :         
     365             588 :         poDriver->pfnCreateCopy = DDSDataset::CreateCopy;
     366                 :         
     367             588 :         GetGDALDriverManager()->RegisterDriver(poDriver);
     368                 :     }
     369             610 : }

Generated by: LCOV version 1.7