145 changes: 145 additions & 0 deletions source/Irrlicht/CImageWriterTGA.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h

#include "CImageWriterTGA.h"

#ifdef _IRR_COMPILE_WITH_TGA_WRITER_

#include "CImageLoaderTGA.h"
#include "IWriteFile.h"
#include "CColorConverter.h"
#include "irrString.h"
#include "os.h"

namespace irr
{
namespace video
{

IImageWriter* createImageWriterTGA()
{
return new CImageWriterTGA;
}

CImageWriterTGA::CImageWriterTGA()
{
#ifdef _DEBUG
setDebugName("CImageWriterTGA");
#endif
}

bool CImageWriterTGA::isAWriteableFileExtension(const io::path& filename) const
{
return core::hasFileExtension ( filename, "tga" );
}

bool CImageWriterTGA::writeImage(io::IWriteFile *file, IImage *image,u32 param) const
{
STGAHeader imageHeader;
imageHeader.IdLength = 0;
imageHeader.ColorMapType = 0;
imageHeader.ImageType = 2;
imageHeader.FirstEntryIndex[0] = 0;
imageHeader.FirstEntryIndex[1] = 0;
imageHeader.ColorMapLength = 0;
imageHeader.ColorMapEntrySize = 0;
imageHeader.XOrigin[0] = 0;
imageHeader.XOrigin[1] = 0;
imageHeader.YOrigin[0] = 0;
imageHeader.YOrigin[1] = 0;
imageHeader.ImageWidth = image->getDimension().Width;
imageHeader.ImageHeight = image->getDimension().Height;

// top left of image is the top. the image loader needs to
// be fixed to only swap/flip
imageHeader.ImageDescriptor = (1 << 5);

// chances are good we'll need to swizzle data, so i'm going
// to convert and write one scan line at a time. it's also
// a bit cleaner this way
void (*CColorConverter_convertFORMATtoFORMAT)(const void*, s32, void*) = 0;
switch(image->getColorFormat())
{
case ECF_A8R8G8B8:
CColorConverter_convertFORMATtoFORMAT
= CColorConverter::convert_A8R8G8B8toA8R8G8B8;
imageHeader.PixelDepth = 32;
imageHeader.ImageDescriptor |= 8;
break;
case ECF_A1R5G5B5:
CColorConverter_convertFORMATtoFORMAT
= CColorConverter::convert_A1R5G5B5toA1R5G5B5;
imageHeader.PixelDepth = 16;
imageHeader.ImageDescriptor |= 1;
break;
case ECF_R5G6B5:
CColorConverter_convertFORMATtoFORMAT
= CColorConverter::convert_R5G6B5toA1R5G5B5;
imageHeader.PixelDepth = 16;
imageHeader.ImageDescriptor |= 1;
break;
case ECF_R8G8B8:
CColorConverter_convertFORMATtoFORMAT
= CColorConverter::convert_R8G8B8toR8G8B8;
imageHeader.PixelDepth = 24;
imageHeader.ImageDescriptor |= 0;
break;
default:
os::Printer::log("CImageWriterTGA does not support image format", ColorFormatNames[image->getColorFormat()], ELL_WARNING);
break;
}

// couldn't find a color converter
if (!CColorConverter_convertFORMATtoFORMAT)
return false;

if (file->write(&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader))
return false;

u8* scan_lines = (u8*)image->getData();
if (!scan_lines)
return false;

// size of one pixel in bytes
u32 pixel_size = image->getBytesPerPixel();

// length of one row of the source image in bytes
u32 row_stride = (pixel_size * imageHeader.ImageWidth);

// length of one output row in bytes
size_t row_size = ((imageHeader.PixelDepth / 8) * imageHeader.ImageWidth);

// allocate a row do translate data into
u8* row_pointer = new u8[row_size];

u32 y;
for (y = 0; y < imageHeader.ImageHeight; ++y)
{
// source, length [pixels], destination
if (image->getColorFormat()==ECF_R8G8B8)
CColorConverter::convert24BitTo24Bit(&scan_lines[y * row_stride], row_pointer, imageHeader.ImageWidth, 1, 0, 0, true);
else
CColorConverter_convertFORMATtoFORMAT(&scan_lines[y * row_stride], imageHeader.ImageWidth, row_pointer);
if (file->write(row_pointer, row_size) != row_size)
break;
}

delete [] row_pointer;

STGAFooter imageFooter;
imageFooter.ExtensionOffset = 0;
imageFooter.DeveloperOffset = 0;
strncpy(imageFooter.Signature, "TRUEVISION-XFILE.", 18);

if (file->write(&imageFooter, sizeof(imageFooter)) < (s32)sizeof(imageFooter))
return false;

return imageHeader.ImageHeight <= y;
}

} // namespace video
} // namespace irr

#endif

37 changes: 37 additions & 0 deletions source/Irrlicht/CImageWriterTGA.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h

#ifndef _C_IMAGE_WRITER_TGA_H_INCLUDED__
#define _C_IMAGE_WRITER_TGA_H_INCLUDED__

#include "IrrCompileConfig.h"

#ifdef _IRR_COMPILE_WITH_TGA_WRITER_

#include "IImageWriter.h"

namespace irr
{
namespace video
{

class CImageWriterTGA : public IImageWriter
{
public:
//! constructor
CImageWriterTGA();

//! return true if this writer can write a file with the given extension
virtual bool isAWriteableFileExtension(const io::path& filename) const _IRR_OVERRIDE_;

//! write image to file
virtual bool writeImage(io::IWriteFile *file, IImage *image,u32 param) const _IRR_OVERRIDE_;
};

} // namespace video
} // namespace irr

#endif // _C_IMAGE_WRITER_TGA_H_INCLUDED__
#endif

2 changes: 2 additions & 0 deletions source/Irrlicht/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,10 @@ set(IRRIMAGEOBJ
CImageLoaderBMP.cpp
CImageLoaderJPG.cpp
CImageLoaderPNG.cpp
CImageLoaderTGA.cpp
CImageWriterJPG.cpp
CImageWriterPNG.cpp
CImageWriterTGA.cpp
)

add_library(IRRVIDEOOBJ OBJECT
Expand Down