Created
January 21, 2010 15:50
-
-
Save ousttrue/282897 to your computer and use it in GitHub Desktop.
c++ dds loader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <fstream> | |
#include <vector> | |
#include <boost/shared_ptr.hpp> | |
#include <boost/static_assert.hpp> | |
/////////////////////////////////////////////////////////////////////////////// | |
// RGBA | |
/////////////////////////////////////////////////////////////////////////////// | |
struct RGBA | |
{ | |
size_t w; | |
size_t h; | |
std::vector<unsigned char> buf; | |
void resize(size_t _w, size_t _h) | |
{ | |
w=_w; | |
h=_h; | |
buf.resize(w*h*4); | |
std::fill(buf.begin(), buf.end(), 0); | |
} | |
bool writePPM(const std::string &path) | |
{ | |
std::ofstream io(path.c_str(), std::ios::binary); | |
if(!io){ | |
std::cout << "fail to open: " << path << std::endl; | |
return false; | |
} | |
io | |
<< "P6\n" | |
<< w << ' ' << h << '\n' | |
<< 255 << '\n' | |
; | |
unsigned char *src=&buf[0]; | |
for(size_t y=0; y<h; ++y){ | |
for(size_t x=0; x<w; ++x, src+=4){ | |
io.write((char*)src, 3); // write rgb | |
} | |
} | |
return true; | |
} | |
}; | |
typedef boost::shared_ptr<RGBA> RGBAPtr; | |
/////////////////////////////////////////////////////////////////////////////// | |
// BinaryReader | |
/////////////////////////////////////////////////////////////////////////////// | |
class BinaryReader | |
{ | |
std::istream &io_; | |
public: | |
BinaryReader(std::istream &io) | |
: io_(io) | |
{} | |
std::string getString(size_t size) | |
{ | |
std::vector<char> buf(size); | |
io_.read(&buf[0], size); | |
return std::string(buf.begin(), buf.end()); | |
} | |
void read(void *p, size_t size) | |
{ | |
io_.read((char*)p, size); | |
} | |
template<typename T> | |
T get() | |
{ | |
T buf; | |
io_.read((char*)&buf, sizeof(T)); | |
return buf; | |
} | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// DDS struct | |
/////////////////////////////////////////////////////////////////////////////// | |
// from ddraw.h | |
#define DDSD_CAPS 0x00000001l // default | |
#define DDSD_HEIGHT 0x00000002l | |
#define DDSD_WIDTH 0x00000004l | |
#define DDSD_PITCH 0x00000008l | |
#define DDSD_PIXELFORMAT 0x00001000l | |
#define DDSD_LINEARSIZE 0x00080000l | |
#define DDPF_ALPHAPIXELS 0x00000001l | |
#define DDPF_FOURCC 0x00000004l | |
#define DDPF_RGB 0x00000040l | |
#ifdef _MSC_VER | |
#pragma pack(push, 1) | |
#else | |
typedef unsigned int DWORD; | |
#endif | |
struct DDPIXELFORMAT | |
{ | |
DWORD dwSize; | |
DWORD dwFlags; | |
DWORD dwFourCC; | |
union | |
{ | |
DWORD dwRGBBitCount; | |
DWORD dwYUVBitCount; | |
DWORD dwZBufferBitDepth; | |
DWORD dwAlphaBitDepth; | |
}; | |
union | |
{ | |
DWORD dwRBitMask; | |
DWORD dwYBitMask; | |
}; | |
union | |
{ | |
DWORD dwGBitMask; | |
DWORD dwUBitMask; | |
}; | |
union{ | |
DWORD dwBBitMask; | |
DWORD dwVBitMask; | |
}; | |
union | |
{ | |
DWORD dwRGBAlphaBitMask; | |
DWORD dwYUVAlphaBitMask; | |
}; | |
} | |
#ifdef __GNUG__ | |
__attribute__((packed)) | |
#endif | |
; | |
BOOST_STATIC_ASSERT(sizeof(DDPIXELFORMAT)==32); | |
struct DDSCAPS2 | |
{ | |
DWORD dwCaps1; | |
DWORD dwCaps2; | |
DWORD Reserved[2]; | |
} | |
#ifdef __GNUG__ | |
__attribute__((packed)) | |
#endif | |
; | |
BOOST_STATIC_ASSERT(sizeof(DDSCAPS2)==16); | |
struct DDSURFACEDESC2 | |
{ | |
DWORD dwSize; | |
DWORD dwFlags; | |
DWORD dwHeight; | |
DWORD dwWidth; | |
DWORD dwPitchOrLinearSize; | |
DWORD dwDepth; | |
DWORD dwMipMapCount; | |
DWORD dwReserved1[11]; | |
DDPIXELFORMAT ddpfPixelFormat; | |
DDSCAPS2 ddsCaps; | |
DWORD dwReserved2; | |
} | |
#ifdef __GNUG__ | |
__attribute__((packed)) | |
#endif | |
; | |
BOOST_STATIC_ASSERT(sizeof(DDSURFACEDESC2)==124); | |
#ifdef _MSC_VER | |
#pragma pack( pop ) | |
#endif | |
/////////////////////////////////////////////////////////////////////////////// | |
// load dds file | |
/////////////////////////////////////////////////////////////////////////////// | |
RGBAPtr load(const std::string &path) | |
{ | |
RGBAPtr image; | |
std::ifstream io(path.c_str(), std::ios::binary); | |
if(!io){ | |
return image; | |
} | |
BinaryReader reader(io); | |
// magic number | |
if(reader.getString(4)!="DDS "){ | |
return image; | |
} | |
// DDSURFACEDESC2 | |
DDSURFACEDESC2 header=reader.get<DDSURFACEDESC2>(); | |
assert(header.dwSize==124); | |
if(header.ddpfPixelFormat.dwFlags & DDPF_RGB){ | |
image=RGBAPtr(new RGBA); | |
image->resize(header.dwWidth, header.dwHeight); | |
size_t pitch=header.dwWidth * header.ddpfPixelFormat.dwRGBBitCount / 8; | |
std::cout | |
<< "<normal image>" << std::endl | |
<< "BitCount: " << header.ddpfPixelFormat.dwRGBBitCount << std::endl | |
; | |
// normal | |
if(header.dwFlags & DDSD_PITCH){ | |
std::cout << "specified line pitch" << std::endl; | |
pitch=header.dwPitchOrLinearSize; | |
} | |
switch(header.ddpfPixelFormat.dwRGBBitCount) | |
{ | |
case 32: | |
{ | |
assert(header.ddpfPixelFormat.dwRBitMask==0x00ff0000); | |
assert(header.ddpfPixelFormat.dwGBitMask==0x0000ff00); | |
assert(header.ddpfPixelFormat.dwBBitMask==0x000000ff); | |
if(header.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS){ | |
std::cout << "has alpha channel" << std::endl; | |
assert(header.ddpfPixelFormat.dwRGBAlphaBitMask==0xff000000); | |
} | |
unsigned char *dst=&image->buf[0]; | |
std::vector<unsigned char> pitchBuffer(pitch); | |
for(size_t y=0; y<header.dwHeight; ++y){ | |
reader.read(&pitchBuffer[0], pitch); | |
unsigned char *src=&pitchBuffer[0]; | |
for(size_t x=0; x<header.dwWidth; ++x, dst+=4, src+=4){ | |
dst[0]=src[2]; // R | |
dst[1]=src[1]; // G | |
dst[2]=src[0]; // B | |
dst[3]=src[3]; // A | |
} | |
} | |
} | |
break; | |
default: | |
std::cout << "not implemented: " | |
<< header.ddpfPixelFormat.dwRGBBitCount << std::endl; | |
break; | |
} | |
} | |
else if(header.ddpfPixelFormat.dwFlags & DDPF_FOURCC){ | |
// compress image | |
std::cout | |
<< "compress: " << header.ddpfPixelFormat.dwFourCC << std::endl; | |
} | |
else{ | |
std::cout << "invalid header." << std::endl; | |
assert(false); | |
} | |
return image; | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
RGBAPtr image=load(argv[1]); | |
if(!image){ | |
return 1; | |
} | |
std::string dstFile("tmp.ppm"); | |
if(!image->writePPM(dstFile)){ | |
return 2; | |
} | |
std::cout << "write to " << dstFile << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment