mirror of
https://github.com/love2d/megasource.git
synced 2026-08-17 11:11:35 +02:00
326 lines
9.2 KiB
C
326 lines
9.2 KiB
C
//-----------------------------------------------------------------------------
|
|
//
|
|
// ImageLib Sources
|
|
// Copyright (C) 2000-2009 by Denton Woods
|
|
// Last modified: 02/26/2009
|
|
//
|
|
// Filename: src-IL/src/il_dpx.c
|
|
//
|
|
// Description: Reads from a Digital Picture Exchange (.dpx) file.
|
|
// Specifications for this format were found at
|
|
// http://www.cineon.com/ff_draft.php and
|
|
// http://www.fileformat.info/format/dpx/.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "il_internal.h"
|
|
#ifndef IL_NO_DPX
|
|
#include "il_dpx.h"
|
|
#include "il_bits.h"
|
|
|
|
ILboolean iLoadDpxInternal(void);
|
|
|
|
|
|
//! Reads a DPX file
|
|
ILboolean ilLoadDpx(ILconst_string FileName)
|
|
{
|
|
ILHANDLE DpxFile;
|
|
ILboolean bDpx = IL_FALSE;
|
|
|
|
DpxFile = iopenr(FileName);
|
|
if (DpxFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return bDpx;
|
|
}
|
|
|
|
bDpx = ilLoadDpxF(DpxFile);
|
|
icloser(DpxFile);
|
|
|
|
return bDpx;
|
|
}
|
|
|
|
|
|
//! Reads an already-opened DPX file
|
|
ILboolean ilLoadDpxF(ILHANDLE File)
|
|
{
|
|
ILuint FirstPos;
|
|
ILboolean bRet;
|
|
|
|
iSetInputFile(File);
|
|
FirstPos = itell();
|
|
bRet = iLoadDpxInternal();
|
|
iseek(FirstPos, IL_SEEK_SET);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
//! Reads from a memory "lump" that contains a DPX
|
|
ILboolean ilLoadDpxL(const void *Lump, ILuint Size)
|
|
{
|
|
iSetInputLump(Lump, Size);
|
|
return iLoadDpxInternal();
|
|
}
|
|
|
|
|
|
ILboolean DpxGetFileInfo(DPX_FILE_INFO *FileInfo)
|
|
{
|
|
//if (iread(FileInfo, 768, 1) != 1)
|
|
// return IL_FALSE;
|
|
|
|
FileInfo->MagicNum = GetBigUInt();
|
|
FileInfo->Offset = GetBigUInt();
|
|
iread(FileInfo->Vers, 8, 1);
|
|
FileInfo->FileSize = GetBigUInt();
|
|
FileInfo->DittoKey = GetBigUInt();
|
|
FileInfo->GenHdrSize = GetBigUInt();
|
|
FileInfo->IndHdrSize = GetBigUInt();
|
|
FileInfo->UserDataSize = GetBigUInt();
|
|
iread(FileInfo->FileName, 100, 1);
|
|
iread(FileInfo->CreateTime, 24, 1);
|
|
iread(FileInfo->Creator, 100, 1);
|
|
iread(FileInfo->Project, 200, 1);
|
|
if (iread(FileInfo->Copyright, 200, 1) != 1)
|
|
return IL_FALSE;
|
|
FileInfo->Key = GetBigUInt();
|
|
iseek(104, IL_SEEK_CUR); // Skip reserved section.
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
ILboolean GetImageElement(DPX_IMAGE_ELEMENT *ImageElement)
|
|
{
|
|
ImageElement->DataSign = GetBigUInt();
|
|
ImageElement->RefLowData = GetBigUInt();
|
|
iread(&ImageElement->RefLowQuantity, 1, 4);
|
|
ImageElement->RefHighData = GetBigUInt();
|
|
iread(&ImageElement->RefHighQuantity, 1, 4);
|
|
ImageElement->Descriptor = igetc();
|
|
ImageElement->Transfer = igetc();
|
|
ImageElement->Colorimetric = igetc();
|
|
ImageElement->BitSize = igetc();
|
|
ImageElement->Packing = GetBigUShort();
|
|
ImageElement->Encoding = GetBigUShort();
|
|
ImageElement->DataOffset = GetBigUInt();
|
|
ImageElement->EolPadding = GetBigUInt();
|
|
ImageElement->EoImagePadding = GetBigUInt();
|
|
if (iread(ImageElement->Description, 32, 1) != 1)
|
|
return IL_FALSE;
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
ILboolean DpxGetImageInfo(DPX_IMAGE_INFO *ImageInfo)
|
|
{
|
|
ILuint i;
|
|
|
|
//if (iread(ImageInfo, sizeof(DPX_IMAGE_INFO), 1) != 1)
|
|
// return IL_FALSE;
|
|
ImageInfo->Orientation = GetBigUShort();
|
|
ImageInfo->NumElements = GetBigUShort();
|
|
ImageInfo->Width = GetBigUInt();
|
|
ImageInfo->Height = GetBigUInt();
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
GetImageElement(&ImageInfo->ImageElement[i]);
|
|
}
|
|
|
|
iseek(52, IL_SEEK_CUR); // Skip padding bytes.
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
ILboolean DpxGetImageOrient(DPX_IMAGE_ORIENT *ImageOrient)
|
|
{
|
|
ImageOrient->XOffset = GetBigUInt();
|
|
ImageOrient->YOffset = GetBigUInt();
|
|
iread(&ImageOrient->XCenter, 4, 1);
|
|
iread(&ImageOrient->YCenter, 4, 1);
|
|
ImageOrient->XOrigSize = GetBigUInt();
|
|
ImageOrient->YOrigSize = GetBigUInt();
|
|
iread(ImageOrient->FileName, 100, 1);
|
|
iread(ImageOrient->CreationTime, 24, 1);
|
|
iread(ImageOrient->InputDev, 32, 1);
|
|
if (iread(ImageOrient->InputSerial, 32, 1) != 1)
|
|
return IL_FALSE;
|
|
ImageOrient->Border[0] = GetBigUShort();
|
|
ImageOrient->Border[1] = GetBigUShort();
|
|
ImageOrient->Border[2] = GetBigUShort();
|
|
ImageOrient->Border[3] = GetBigUShort();
|
|
ImageOrient->PixelAspect[0] = GetBigUInt();
|
|
ImageOrient->PixelAspect[1] = GetBigUInt();
|
|
iseek(28, IL_SEEK_CUR); // Skip reserved bytes.
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
// Internal function used to load the DPX.
|
|
ILboolean iLoadDpxInternal(void)
|
|
{
|
|
DPX_FILE_INFO FileInfo;
|
|
DPX_IMAGE_INFO ImageInfo;
|
|
DPX_IMAGE_ORIENT ImageOrient;
|
|
// BITFILE *File;
|
|
ILuint i, NumElements, CurElem = 0;
|
|
ILushort Val, *ShortData;
|
|
ILubyte Data[8];
|
|
ILenum Format = 0;
|
|
ILubyte NumChans = 0;
|
|
|
|
|
|
if (iCurImage == NULL) {
|
|
ilSetError(IL_ILLEGAL_OPERATION);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
if (!DpxGetFileInfo(&FileInfo))
|
|
return IL_FALSE;
|
|
if (!DpxGetImageInfo(&ImageInfo))
|
|
return IL_FALSE;
|
|
if (!DpxGetImageOrient(&ImageOrient))
|
|
return IL_FALSE;
|
|
|
|
iseek(ImageInfo.ImageElement[CurElem].DataOffset, IL_SEEK_SET);
|
|
|
|
//@TODO: Deal with different origins!
|
|
|
|
switch (ImageInfo.ImageElement[CurElem].Descriptor)
|
|
{
|
|
case 6: // Luminance data
|
|
Format = IL_LUMINANCE;
|
|
NumChans = 1;
|
|
break;
|
|
case 50: // RGB data
|
|
Format = IL_RGB;
|
|
NumChans = 3;
|
|
break;
|
|
case 51: // RGBA data
|
|
Format = IL_RGBA;
|
|
NumChans = 4;
|
|
break;
|
|
default:
|
|
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
// These are all on nice word boundaries.
|
|
switch (ImageInfo.ImageElement[CurElem].BitSize)
|
|
{
|
|
case 8:
|
|
case 16:
|
|
case 32:
|
|
if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, NumChans, Format, IL_UNSIGNED_BYTE, NULL))
|
|
return IL_FALSE;
|
|
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
|
if (iread(iCurImage->Data, iCurImage->SizeOfData, 1) != 1)
|
|
return IL_FALSE;
|
|
goto finish;
|
|
}
|
|
|
|
// The rest of these do not end on word boundaries.
|
|
if (ImageInfo.ImageElement[CurElem].Packing == 1) {
|
|
// Here we have it padded out to a word boundary, so the extra bits are filler.
|
|
switch (ImageInfo.ImageElement[CurElem].BitSize)
|
|
{
|
|
case 10:
|
|
//@TODO: Support other formats!
|
|
/*if (Format != IL_RGB) {
|
|
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
|
return IL_FALSE;
|
|
}*/
|
|
switch (Format)
|
|
{
|
|
case IL_LUMINANCE:
|
|
if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_SHORT, NULL))
|
|
return IL_FALSE;
|
|
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
|
ShortData = (ILushort*)iCurImage->Data;
|
|
NumElements = iCurImage->SizeOfData / 2;
|
|
|
|
for (i = 0; i < NumElements;) {
|
|
iread(Data, 1, 2);
|
|
Val = ((Data[0] << 2) + ((Data[1] & 0xC0) >> 6)) << 6; // Use the first 10 bits of the word-aligned data.
|
|
ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Fill in the lower 6 bits with a copy of the higher bits.
|
|
}
|
|
break;
|
|
|
|
case IL_RGB:
|
|
if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, 3, IL_RGB, IL_UNSIGNED_SHORT, NULL))
|
|
return IL_FALSE;
|
|
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
|
ShortData = (ILushort*)iCurImage->Data;
|
|
NumElements = iCurImage->SizeOfData / 2;
|
|
|
|
for (i = 0; i < NumElements;) {
|
|
iread(Data, 1, 4);
|
|
Val = ((Data[0] << 2) + ((Data[1] & 0xC0) >> 6)) << 6; // Use the first 10 bits of the word-aligned data.
|
|
ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Fill in the lower 6 bits with a copy of the higher bits.
|
|
Val = (((Data[1] & 0x3F) << 4) + ((Data[2] & 0xF0) >> 4)) << 6; // Use the next 10 bits.
|
|
ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Same fill
|
|
Val = (((Data[2] & 0x0F) << 6) + ((Data[3] & 0xFC) >> 2)) << 6; // And finally use the last 10 bits (ignores the last 2 bits).
|
|
ShortData[i++] = Val | ((Val & 0x3F0) >> 4); // Same fill
|
|
}
|
|
break;
|
|
|
|
case IL_RGBA: // Is this even a possibility? There is a ton of wasted space here!
|
|
if (!ilTexImage(ImageInfo.Width, ImageInfo.Height, 1, 4, IL_RGBA, IL_UNSIGNED_SHORT, NULL))
|
|
return IL_FALSE;
|
|
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
|
ShortData = (ILushort*)iCurImage->Data;
|
|
NumElements = iCurImage->SizeOfData / 2;
|
|
|
|
for (i = 0; i < NumElements;) {
|
|
iread(Data, 1, 8);
|
|
Val = (Data[0] << 2) + ((Data[1] & 0xC0) >> 6); // Use the first 10 bits of the word-aligned data.
|
|
ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Fill in the lower 6 bits with a copy of the higher bits.
|
|
Val = ((Data[1] & 0x3F) << 4) + ((Data[2] & 0xF0) >> 4); // Use the next 10 bits.
|
|
ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Same fill
|
|
Val = ((Data[2] & 0x0F) << 6) + ((Data[3] & 0xFC) >> 2); // Use the next 10 bits.
|
|
ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Same fill
|
|
Val = ((Data[3] & 0x03) << 8) + Data[4]; // And finally use the last 10 relevant bits (skips 3 whole bytes worth of padding!).
|
|
ShortData[i++] = (Val << 6) | ((Val & 0x3F0) >> 4); // Last fill
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//case 1:
|
|
//case 12:
|
|
default:
|
|
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
else if (ImageInfo.ImageElement[0].Packing == 0) {
|
|
// Here we have the data packed so that it is never aligned on a word boundary.
|
|
/*File = bfile(iGetFile());
|
|
if (File == NULL)
|
|
return IL_FALSE; //@TODO: Error?
|
|
ShortData = (ILushort*)iCurImage->Data;
|
|
NumElements = iCurImage->SizeOfData / 2;
|
|
for (i = 0; i < NumElements; i++) {
|
|
//bread(&Val, 1, 10, File);
|
|
Val = breadVal(10, File);
|
|
ShortData[i] = (Val << 6) | (Val >> 4);
|
|
}
|
|
bclose(File);*/
|
|
|
|
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
|
return IL_FALSE;
|
|
}
|
|
else {
|
|
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
|
return IL_FALSE; //@TODO: Take care of this in an iCheckDpx* function.
|
|
}
|
|
|
|
finish:
|
|
return ilFixImage();
|
|
}
|
|
|
|
#endif//IL_NO_DPX
|
|
|