From Jason Daly, "'ve been busy working on the Source engine plugins. There are several contributions in this submission:

osgDB/FileUtils.cpp:
Needed this extra code to allow a true case-insensitive search.  This is because the HL2 map and model files are often sloppy with case.  For example, the file might look for materials/models/alyx/alyx_sheet.vtf, but the file is actually in materials/Models/Alyx/alyx_sheet.vtf.  In case-insensitive mode, the new code recursively disassembles the path and checks each path element without regard to case.  In case-sensitive mode, the code behaves exactly as it used to.  The new code is also mostly skipped on Windows because of the case-insensitive file system.  Previously, I did all of this with custom search code in the .bsp plugin, but this allows the user to tailor the search using OSGFILEPATH.  There are some instructions in the plugins' README files about this.

osgPlugins/mdl:
This is a new plug-in for Half-Life 2 models (as opposed to maps).  This allows you to load Source models individually, as well as allowing the .bsp plugin to load models (props) that are embedded into maps.  Mdl files can contain simple object (crates, barrels, bottles), as well as fully articulated characters with skeletal animations.  Currently, it can load the simple objects.  It can also load the characters, but it can't load the skeletons or animations.

osgPlugins/bsp:
This contains all of the changes needed to load props along with the basic map geometry.  There are also
several bugs fixed.

osgPlugins/vtf:
This is the loader for Valve's texture format.  Previously, we had agreed to put this in with the bsp plugin, but I didn't think of the .mdl plugin at that time.  It's conceivable that a user might want to load models individually (not as part of a map), so the vtf reader does have to be separate.  I also fixed a rather significant bug.

I tested all of this code on RHEL 5.2 (32-bit), and Fedora 9 (64-bit).  I'll be testing on Windows soon.

I also attached a simple .mdl file, along with it's associated files and textures.  Just extract the tarball into it's own directory, set your OSGFILEPATH to point at that directory, and load the model like this:

 osgviewer models/props_junk/gascan001a.mdl"
This commit is contained in:
Robert Osfield
2008-12-20 13:35:49 +00:00
parent 05cb054140
commit 28ca8277f8
34 changed files with 4608 additions and 670 deletions

View File

@@ -0,0 +1,783 @@
/**********************************************************************
*
* FILE: ReaderWriterVTF.cpp
*
* DESCRIPTION: Class for reading a Valve Texture Format (VTF) file
* into an osg::Image.
*
* Borrows heavily from the DDS plugin for OSG, as well
* as the Valve Source SDK
*
* CREATED BY: Jason Daly (jdaly@ist.ucf.edu)
*
* HISTORY: Created 27.10.2008
*
**********************************************************************/
#include <osg/Texture>
#include <osg/Notify>
#include <osgDB/Registry>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <iomanip>
#include <stdio.h>
enum VTFFlags
{
VTF_FLAGS_POINTSAMPLE = 0x00000001,
VTF_FLAGS_TRILINEAR = 0x00000002,
VTF_FLAGS_CLAMP_S = 0x00000004,
VTF_FLAGS_CLAMP_T = 0x00000008,
VTF_FLAGS_ANISOTROPIC = 0x00000010,
VTF_FLAGS_HINT_DXT5 = 0x00000020,
VTF_FLAGS_NOCOMPRESS = 0x00000040,
VTF_FLAGS_NORMAL = 0x00000080,
VTF_FLAGS_NOMIP = 0x00000100,
VTF_FLAGS_NOLOD = 0x00000200,
VTF_FLAGS_MINMIP = 0x00000400,
VTF_FLAGS_PROCEDURAL = 0x00000800,
VTF_FLAGS_ONEBITALPHA = 0x00001000,
VTF_FLAGS_EIGHTBITALPHA = 0x00002000,
VTF_FLAGS_ENVMAP = 0x00004000,
VTF_FLAGS_RENDERTARGET = 0x00008000,
VTF_FLAGS_DEPTHRENDERTARGET = 0x00010000,
VTF_FLAGS_NODEBUGOVERRIDE = 0x00020000,
VTF_FLAGS_SINGLECOPY = 0x00040000,
VTF_FLAGS_ONEOVERMIPLEVELINALPHA = 0x00080000,
VTF_FLAGS_PREMULTCOLORBYONEOVERMIPLEVEL = 0x00100000,
VTF_FLAGS_NORMALTODUDV = 0x00200000,
VTF_FLAGS_ALPHATESTMIPGENERATION = 0x00400000,
VTF_FLAGS_NODEPTHBUFFER = 0x00800000,
VTF_FLAGS_NICEFILTERED = 0x01000000,
VTF_FLAGS_CLAMP_U = 0x02000000,
VTF_FLAGS_PRESWIZZLED = 0x04000000,
VTF_FLAGS_CACHEABLE = 0x08000000,
VTF_FLAGS_UNFILTERABLE_OK = 0x10000000,
VTF_FLAGS_LASTFLAG = 0x10000000
};
enum VTFCubeMapFaceIndex
{
VTF_CUBEMAP_FACE_RIGHT = 0,
VTF_CUBEMAP_FACE_LEFT,
VTF_CUBEMAP_FACE_BACK,
VTF_CUBEMAP_FACE_FRONT,
VTF_CUBEMAP_FACE_UP,
VTF_CUBEMAP_FACE_DOWN,
VTF_CUBEMAP_FACE_SPHEREMAP,
VTF_CUBEMAP_FACE_COUNT
};
enum VTFLookDir
{
VTF_LOOK_DOWN_X = 0,
VTF_LOOK_DOWN_NEGX,
VTF_LOOK_DOWN_Y = 0,
VTF_LOOK_DOWN_NEGY,
VTF_LOOK_DOWN_Z = 0,
VTF_LOOK_DOWN_NEGZ
};
enum VTFImageFormat
{
VTF_FORMAT_UNKNOWN = -1,
VTF_FORMAT_RGBA8888 = 0,
VTF_FORMAT_ABGR8888,
VTF_FORMAT_RGB888,
VTF_FORMAT_BGR888,
VTF_FORMAT_RGB565,
VTF_FORMAT_I8,
VTF_FORMAT_IA88,
VTF_FORMAT_P8,
VTF_FORMAT_A8,
VTF_FORMAT_RGB888_BLUESCREEN,
VTF_FORMAT_BGR888_BLUESCREEN,
VTF_FORMAT_ARGB8888,
VTF_FORMAT_BGRA8888,
VTF_FORMAT_DXT1,
VTF_FORMAT_DXT3,
VTF_FORMAT_DXT5,
VTF_FORMAT_BGRX8888,
VTF_FORMAT_BGR565,
VTF_FORMAT_BGRX5551,
VTF_FORMAT_BGRA4444,
VTF_FORMAT_DXT1_ONEBITALPHA,
VTF_FORMAT_BGRA5551,
VTF_FORMAT_UV88,
VTF_FORMAT_UVWQ8888,
VTF_FORMAT_RGBA16161616F,
VTF_FORMAT_RGBA16161616,
VTF_FORMAT_UVLX8888,
VTF_FORMAT_R32F,
VTF_FORMAT_RGB323232F,
VTF_FORMAT_RGBA32323232F,
VTF_NUM_IMAGE_FORMATS
};
#define VTF_FORMAT_DEFAULT ((VTFImageFormat)-2)
struct VTFFileHeader
{
char magic_number[4];
unsigned int file_version[2];
unsigned int header_size;
unsigned short image_width;
unsigned short image_height;
unsigned int image_flags;
unsigned short num_frames;
unsigned short start_frame;
unsigned char padding_0[4];
osg::Vec3f reflectivity_value;
unsigned char padding_1[4];
float bump_scale;
unsigned int image_format;
unsigned char num_mip_levels;
unsigned char low_res_image_format;
unsigned char padding_2[3];
unsigned char low_res_image_width;
unsigned char low_res_image_height;
unsigned short image_depth;
};
//
// Structure of a DXT-1 compressed texture block
// see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/Opaque_and_1_Bit_Alpha_Textures.asp
//
struct DXT1TexelsBlock
{
unsigned short color_0; // colors at their
unsigned short color_1; // extreme
unsigned int texels4x4; // interpolated colors (2 bits per texel)
};
bool ConvertImageFormat(unsigned int vtfFormat, int& internalFormat,
int& pixelFormat, int& dataType)
{
bool supported;
// Assume a supported format to start
supported = true;
// Decode the format
switch (vtfFormat)
{
case VTF_FORMAT_DEFAULT:
supported = false;
break;
case VTF_FORMAT_UNKNOWN:
supported = false;
break;
case VTF_FORMAT_RGBA8888:
internalFormat = GL_RGBA;
pixelFormat = GL_RGBA;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_ABGR8888:
internalFormat = GL_RGBA;
pixelFormat = GL_ABGR_EXT;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_RGB888:
internalFormat = GL_RGB;
pixelFormat = GL_RGB;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_BGR888:
internalFormat = GL_RGB;
pixelFormat = GL_BGR;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_RGB565:
internalFormat = GL_RGB;
pixelFormat = GL_RGB;
dataType = GL_UNSIGNED_SHORT_5_6_5;
break;
case VTF_FORMAT_I8:
internalFormat = GL_LUMINANCE;
pixelFormat = GL_LUMINANCE;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_IA88:
internalFormat = GL_LUMINANCE_ALPHA;
pixelFormat = GL_LUMINANCE_ALPHA;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_P8:
// 8-bit paletted image, not supported
supported = false;
break;
case VTF_FORMAT_A8:
internalFormat = GL_ALPHA;
pixelFormat = GL_ALPHA;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_RGB888_BLUESCREEN:
// Ignore the "bluescreen" specification for now
internalFormat = GL_RGB;
pixelFormat = GL_RGB;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_BGR888_BLUESCREEN:
// Ignore the "bluescreen" specification for now
internalFormat = GL_RGB;
pixelFormat = GL_BGR;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_ARGB8888:
// ARGB not supported
supported = false;
break;
case VTF_FORMAT_BGRA8888:
internalFormat = GL_RGBA;
pixelFormat = GL_BGRA;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_DXT1:
internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
pixelFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_DXT3:
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
pixelFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_DXT5:
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
pixelFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_BGRX8888:
internalFormat = GL_RGB;
pixelFormat = GL_BGRA;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_BGR565:
internalFormat = GL_RGB;
pixelFormat = GL_BGR;
dataType = GL_UNSIGNED_SHORT_5_6_5_REV;
break;
case VTF_FORMAT_BGRX5551:
internalFormat = GL_RGB;
pixelFormat = GL_BGRA;
dataType = GL_UNSIGNED_SHORT_5_5_5_1;
break;
case VTF_FORMAT_BGRA4444:
internalFormat = GL_RGBA;
pixelFormat = GL_BGRA;
dataType = GL_UNSIGNED_SHORT_4_4_4_4;
break;
case VTF_FORMAT_DXT1_ONEBITALPHA:
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
pixelFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
dataType = GL_UNSIGNED_BYTE;
break;
case VTF_FORMAT_BGRA5551:
internalFormat = GL_RGBA;
pixelFormat = GL_BGRA;
dataType = GL_UNSIGNED_SHORT_5_5_5_1;
break;
case VTF_FORMAT_UV88:
supported = false;
break;
case VTF_FORMAT_UVWQ8888:
supported = false;
break;
case VTF_FORMAT_RGBA16161616F:
internalFormat = GL_RGBA;
pixelFormat = GL_RGBA;
dataType = GL_HALF_FLOAT_NV;
break;
case VTF_FORMAT_RGBA16161616:
internalFormat = GL_RGBA;
pixelFormat = GL_RGBA;
dataType = GL_UNSIGNED_SHORT;
break;
case VTF_FORMAT_UVLX8888:
supported = false;
break;
default:
supported = false;
break;
}
// Return whether or not the format is supported
return supported;
}
osg::Image* ReadVTFFile(std::istream& _istream)
{
VTFFileHeader vtf_header;
bool supported;
int internalFormat;
int pixelFormat;
int dataType;
int s, t, r;
unsigned int lrSize;
unsigned char * imageData;
unsigned char * imageDataPtr;
unsigned int base;
unsigned int size;
int mip;
int mipSize;
int mipOffset;
// Validate the file with the 'VTF\0' magic number
_istream.read(&vtf_header.magic_number[0], 4);
if ((vtf_header.magic_number[0] != 'V') ||
(vtf_header.magic_number[1] != 'T') ||
(vtf_header.magic_number[2] != 'F') ||
(vtf_header.magic_number[3] != 0))
{
// Not a VTF file, so bail
osg::notify(osg::WARN) << "VTF file is invalid" << std::endl;
return NULL;
}
// Read next two fields of the header (which includes the header size)
_istream.read((char *)&vtf_header.file_version[0], 12);
// Now, read the rest of the header
_istream.read((char *)&vtf_header.image_width, vtf_header.header_size - 16);
// No depth in textures earlier than version 7.2
if ((vtf_header.file_version[0] < 7) ||
((vtf_header.file_version[0] == 7) &&
(vtf_header.file_version[1] < 2)))
vtf_header.image_depth = 1;
// Environment maps not supported
if (vtf_header.image_flags & VTF_FLAGS_ENVMAP)
{
osg::notify(osg::WARN) << "VTF Environment maps not supported";
osg::notify(osg::WARN) << std::endl;
return NULL;
}
osg::notify(osg::INFO) << "VTF Header: (" << sizeof(VTFFileHeader);
osg::notify(osg::INFO) << " bytes)" << std::endl;
osg::notify(osg::INFO) << " magic_number = ";
osg::notify(osg::INFO) << vtf_header.magic_number[0];
osg::notify(osg::INFO) << vtf_header.magic_number[1];
osg::notify(osg::INFO) << vtf_header.magic_number[2];
osg::notify(osg::INFO) << vtf_header.magic_number[3] << std:: endl;
osg::notify(osg::INFO) << " file_version = ";
osg::notify(osg::INFO) << vtf_header.file_version[0] << ".";
osg::notify(osg::INFO) << vtf_header.file_version[1] << std:: endl;
osg::notify(osg::INFO) << " header_size = ";
osg::notify(osg::INFO) << vtf_header.header_size << std::endl;
osg::notify(osg::INFO) << " image_width = ";
osg::notify(osg::INFO) << vtf_header.image_width << std::endl;
osg::notify(osg::INFO) << " image_height = ";
osg::notify(osg::INFO) << vtf_header.image_height << std::endl;
osg::notify(osg::INFO) << " num_frames = ";
osg::notify(osg::INFO) << vtf_header.num_frames << std::endl;
osg::notify(osg::INFO) << " start_frame = ";
osg::notify(osg::INFO) << vtf_header.start_frame << std::endl;
osg::notify(osg::INFO) << " reflectivity = ";
osg::notify(osg::INFO) << vtf_header.reflectivity_value.x() << ", ";
osg::notify(osg::INFO) << vtf_header.reflectivity_value.y() << ", ";
osg::notify(osg::INFO) << vtf_header.reflectivity_value.z() << std::endl;
osg::notify(osg::INFO) << " bump_scale = ";
osg::notify(osg::INFO) << vtf_header.bump_scale << std::endl;
osg::notify(osg::INFO) << " image_format = ";
osg::notify(osg::INFO) << vtf_header.image_format << std::endl;
osg::notify(osg::INFO) << " num_mip_lvls = ";
osg::notify(osg::INFO) << (int)vtf_header.num_mip_levels << std::endl;
osg::notify(osg::INFO) << " lr_image_fmt = ";
osg::notify(osg::INFO) << (int)vtf_header.low_res_image_format << std::endl;
osg::notify(osg::INFO) << " lr_width = ";
osg::notify(osg::INFO) << (int)vtf_header.low_res_image_width << std::endl;
osg::notify(osg::INFO) << " lr_height = ";
osg::notify(osg::INFO) << (int)vtf_header.low_res_image_height << std::endl;
osg::notify(osg::INFO) << " image_depth = ";
osg::notify(osg::INFO) << (int)vtf_header.image_depth << std::endl;
// Before we get to the real image, we need to skip over the "low res"
// image that's often stored along with VTF textures, so get the
// low-res image dimensions
s = vtf_header.low_res_image_width;
t = vtf_header.low_res_image_height;
r = 1;
osg::notify(osg::INFO) << "Low-res s = " << s << std::endl;
osg::notify(osg::INFO) << "Low-res t = " << t << std::endl;
// See if the low-res image is there
lrSize = 0;
if ((s > 0) && (t > 0))
{
supported = ConvertImageFormat(vtf_header.low_res_image_format,
internalFormat, pixelFormat, dataType);
// If we don't recognize the format, we can't locate the real image
// in the file, so we have to bail
if (!supported)
{
osg::notify(osg::WARN) << "Low-res image format is not supported";
osg::notify(osg::WARN) << " (" << vtf_header.low_res_image_format;
osg::notify(osg::WARN) << ")" << std::endl;
return NULL;
}
// Allocate an osg::Image for the lo-res image metadata
osg::ref_ptr<osg::Image> loResImage = new osg::Image();
// Set the image metadata, and figure out how many bytes to read
loResImage->setImage(s, t, r, internalFormat, pixelFormat, dataType,
0, osg::Image::USE_NEW_DELETE);
lrSize = loResImage->getTotalSizeInBytes();
// Skip over the low-res image data
osg::notify(osg::INFO) << "Low-res size = " << lrSize << std::endl;
_istream.ignore(lrSize);
}
// Compute the base position of the high-res image data
base = vtf_header.header_size + lrSize;
// Now, get the internal format, pixel format, and data type from the
// full-size image format, and check whether the format is supported
supported = ConvertImageFormat(vtf_header.image_format, internalFormat,
pixelFormat, dataType);
// Bail if the format isn't supported
if (!supported)
{
osg::notify(osg::WARN) << "Image format is not supported (";
osg::notify(osg::WARN) << vtf_header.image_format << ")";
osg::notify(osg::WARN) << std::endl;
return NULL;
}
// Get the dimensions of the image
s = vtf_header.image_width;
t = vtf_header.image_height;
r = vtf_header.image_depth;
// VTF allows either 0 or 1 for 2D images
if (r == 0)
r = 1;
// NOTE: VTF supports animated textures and cube maps. Currently, we
// only handle a single frame of data, so multiple frames
// are ignored. Same for cube maps (only one face is loaded).
// Create the mipmap offsets vector
osg::Image::MipmapDataType mipmaps;
// Deal with mipmaps, if necessary
if (vtf_header.num_mip_levels > 1)
{
// Set up the offsets vector
float power2_s = logf((float)s)/logf((float)2);
float power2_t = logf((float)t)/logf((float)2);
mipmaps.resize((unsigned int)osg::maximum(power2_s,power2_t),0);
// Calculate the dimensions of each mipmap
if ((vtf_header.image_format == VTF_FORMAT_DXT1) ||
(vtf_header.image_format == VTF_FORMAT_DXT1_ONEBITALPHA) ||
(vtf_header.image_format == VTF_FORMAT_DXT3) ||
(vtf_header.image_format == VTF_FORMAT_DXT5))
{
// Handle S3TC compressed mipmaps
int width = vtf_header.image_width;
int height = vtf_header.image_height;
int blockSize;
if ((vtf_header.image_format == VTF_FORMAT_DXT1) ||
(vtf_header.image_format == VTF_FORMAT_DXT1_ONEBITALPHA))
blockSize = 8;
else
blockSize = 16;
int offset = 0;
for (unsigned int k = 1;
(k < vtf_header.num_mip_levels) && (width || height);
++k)
{
// Clamp dimensions to 1
if (width == 0)
width = 1;
if (height == 0)
height = 1;
// Compute and store the offset into the final image data
offset += (((width+3)/4) * ((height+3)/4) * blockSize);
mipmaps[k-1] = offset;
// Get the next level's dimensions
width >>= 1;
height >>= 1;
}
}
else
{
// Handle uncompressed mipmaps
int offset = 0;
int width = vtf_header.image_width;
int height = vtf_header.image_height;
int depth = vtf_header.image_depth;
for (unsigned int k = 1;
(k < vtf_header.num_mip_levels) && (width || height || depth);
++k)
{
if (width == 0)
width = 1;
if (height == 0)
height = 1;
if (depth == 0)
depth = 1;
// Compute and store the offset into the final image data
offset += depth * height *
osg::Image::computeRowWidthInBytes(width, pixelFormat,
dataType, 1 );
mipmaps[k-1] = offset;
// Get the next level's dimensions
width >>= 1;
height >>= 1;
depth >>= 1;
}
}
}
// Allocate the resulting osg::Image
osg::ref_ptr<osg::Image> osgImage = new osg::Image();
// Set the image meta-data, including dimensions, format, data type,
// and mipmap levels. Everything but the image data itself. We'll use
// this to compute the total image size, so we know how much data to read
// from the file
osgImage->setImage(s, t, r, internalFormat, pixelFormat, dataType,
0, osg::Image::USE_NEW_DELETE);
if (mipmaps.size() > 0)
osgImage->setMipmapLevels(mipmaps);
// Compute the total image size
size = osgImage->getTotalSizeInBytesIncludingMipmaps();
osg::notify(osg::INFO) << "ReadVTFFile info : size = " << size << std::endl;
if(size <= 0)
{
osg::notify(osg::WARN) << "ReadVTFFile warning: size <= 0" << std::endl;
return NULL;
}
// Prepare to read the image data
imageData = new unsigned char [size];
if(!imageData)
{
osg::notify(osg::WARN) << "ReadVTFFile warning: imageData == NULL";
osg::notify(osg::WARN) << std::endl;
return NULL;
}
// See if we have mipmaps
if (vtf_header.num_mip_levels > 1)
{
// VTF stores the mipmaps in reverse order from what OpenGL expects, so
// we need to read them from the file and store them in order in the
// image data array
for (mip = vtf_header.num_mip_levels - 2; mip >= 0; mip--)
{
// Look up the offset for this mip level
mipOffset = mipmaps[mip];
// Calculate the size of the mipmap
if (mip == vtf_header.num_mip_levels-2)
mipSize = size - mipOffset;
else
mipSize = mipmaps[mip+1] - mipOffset;
// Read the image data
_istream.read((char*)&imageData[mipOffset], mipSize);
}
// We've read all of the mipmaps except the largest (the original,
// image), so do that now
mipSize = mipmaps[1];
_istream.read((char*)imageData, mipSize);
}
else
{
// Just read the image data
_istream.read((char*)imageData, size);
}
/*
// Check if alpha information embedded in the 8-byte encoding blocks
if (checkIfUsingOneBitAlpha)
{
const DXT1TexelsBlock *texelsBlock =
reinterpret_cast<const DXT1TexelsBlock*>(imageData);
// Only do the check on the first mipmap level
unsigned int numBlocks = mipmaps.size()>0 ? mipmaps[0] / 8 : size / 8;
for (int i=numBlocks; i>0; --i, ++texelsBlock)
{
if (texelsBlock->color_0<=texelsBlock->color_1)
{
// Texture is using the 1-bit alpha encoding, so we need to
// update the assumed pixel format
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
pixelFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
break;
}
}
}
*/
// Now, set the actual image data and mipmap levels
osgImage->setImage(s,t,r, internalFormat, pixelFormat, dataType,
imageData, osg::Image::USE_NEW_DELETE);
if (mipmaps.size()>0) osgImage->setMipmapLevels(mipmaps);
// Finally, return the image
return osgImage.release();
}
bool WriteVTFFile(const osg::Image *img, std::ostream& fout)
{
// Not supported
return false;
}
class ReaderWriterVTF : public osgDB::ReaderWriter
{
public:
virtual const char* className() const
{
return "VTF Image Reader/Writer";
}
virtual bool acceptsExtension(const std::string& extension) const
{
return osgDB::equalCaseInsensitive(extension, "vtf");
}
virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const
{
return readImage(file,options);
}
virtual ReadResult readObject(std::istream& fin, const Options* options) const
{
return readImage(fin,options);
}
virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
{
std::string ext = osgDB::getLowerCaseFileExtension(file);
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
std::string fileName = osgDB::findDataFile( file, options );
if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
std::ifstream stream(fileName.c_str(), std::ios::in | std::ios::binary);
if(!stream) return ReadResult::FILE_NOT_HANDLED;
ReadResult rr = readImage(stream, options);
if(rr.validImage()) rr.getImage()->setFileName(file);
return rr;
}
virtual ReadResult readImage(std::istream& fin, const Options* options) const
{
osg::Image* osgImage = ReadVTFFile(fin);
if (osgImage==NULL) return ReadResult::FILE_NOT_HANDLED;
if (options && options->getOptionString().find("vtf_flip")!=std::string::npos)
{
osgImage->flipVertical();
}
return osgImage;
}
virtual WriteResult writeObject(const osg::Object& object,const std::string& file, const osgDB::ReaderWriter::Options* options) const
{
const osg::Image* image = dynamic_cast<const osg::Image*>(&object);
if (!image) return WriteResult::FILE_NOT_HANDLED;
return writeImage(*image,file,options);
}
virtual WriteResult writeObject(const osg::Object& object,std::ostream& fout,const Options* options) const
{
const osg::Image* image = dynamic_cast<const osg::Image*>(&object);
if (!image) return WriteResult::FILE_NOT_HANDLED;
return writeImage(*image,fout,options);
}
virtual WriteResult writeImage(const osg::Image &image,const std::string& file, const osgDB::ReaderWriter::Options* options) const
{
std::string ext = osgDB::getFileExtension(file);
if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
std::ofstream fout(file.c_str(), std::ios::out | std::ios::binary);
if(!fout) return WriteResult::ERROR_IN_WRITING_FILE;
return writeImage(image,fout,options);
}
virtual WriteResult writeImage(const osg::Image& image,std::ostream& fout,const Options*) const
{
bool success = WriteVTFFile(&image, fout);
if(success)
return WriteResult::FILE_SAVED;
else
return WriteResult::ERROR_IN_WRITING_FILE;
}
};
// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(vtf, ReaderWriterVTF)