//-----------------------------------------------------------------------------
//
// ImageLib Sources
// Copyright (C) 2000-2008 by Denton Woods
// Last modified: 06/07/2007
//
// Filename: src-IL/src/il_doom.c
//
// Description: Reads Doom textures and flats
//
//-----------------------------------------------------------------------------


#include "il_internal.h"
#ifndef IL_NO_DOOM
#include "il_manip.h"
#include "il_pal.h"
#include "il_doompal.h"


ILboolean iLoadDoomInternal(void);
ILboolean iLoadDoomFlatInternal(void);


//
// READ A DOOM IMAGE
//

//! Reads a Doom file
ILboolean ilLoadDoom(ILconst_string FileName)
{
	ILHANDLE	DoomFile;
	ILboolean	bDoom = IL_FALSE;

	// Not sure of any kind of specified extension...maybe .lmp?
	/*if (!iCheckExtension(FileName, "")) {
		ilSetError(IL_INVALID_EXTENSION);
		return NULL;
	}*/

	DoomFile = iopenr(FileName);
	if (DoomFile == NULL) {
		ilSetError(IL_COULD_NOT_OPEN_FILE);
		return bDoom;
	}

	bDoom = ilLoadDoomF(DoomFile);
	icloser(DoomFile);

	return bDoom;
}


//! Reads an already-opened Doom file
ILboolean ilLoadDoomF(ILHANDLE File)
{
	ILuint		FirstPos;
	ILboolean	bRet;

	iSetInputFile(File);
	FirstPos = itell();
	bRet = iLoadDoomInternal();
	iseek(FirstPos, IL_SEEK_SET);

	return bRet;
}


//! Reads from a memory "lump" that contains a Doom texture
ILboolean ilLoadDoomL(const ILvoid *Lump, ILuint Size)
{
	iSetInputLump(Lump, Size);
	return iLoadDoomInternal();
}


// From the DTE sources (mostly by Denton Woods with corrections by Randy Heit)
ILboolean iLoadDoomInternal()
{
	ILshort	width, height, graphic_header[2], column_loop, row_loop;
	ILint	column_offset, pointer_position, first_pos;
	ILubyte	post, topdelta, length;
	ILubyte	*NewData;
	ILuint	i;

	if (iCurImage == NULL) {
		ilSetError(IL_ILLEGAL_OPERATION);
		return IL_FALSE;
	}

	first_pos = itell();  // Needed to go back to the offset table
	width = GetLittleShort();
	height = GetLittleShort();
	graphic_header[0] = GetLittleShort();  // Not even used
	graphic_header[1] = GetLittleShort();  // Not even used

	if (!ilTexImage(width, height, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL)) {
		return IL_FALSE;
	}
	iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;

	iCurImage->Pal.Palette = (ILubyte*)ialloc(IL_DOOMPAL_SIZE);
	if (iCurImage->Pal.Palette == NULL) {
		return IL_FALSE;
	}
	iCurImage->Pal.PalSize = IL_DOOMPAL_SIZE;
	iCurImage->Pal.PalType = IL_PAL_RGB24;
	memcpy(iCurImage->Pal.Palette, ilDefaultDoomPal, IL_DOOMPAL_SIZE);

	// 247 is always the transparent colour (usually cyan)
	memset(iCurImage->Data, 247, iCurImage->SizeOfData);

	for (column_loop = 0; column_loop < width; column_loop++) {
		column_offset = GetLittleInt();
		pointer_position = itell();
		iseek(first_pos + column_offset, IL_SEEK_SET);

		while (1) {
			if (iread(&topdelta, 1, 1) != 1)
				return IL_FALSE;
			if (topdelta == 255)
				break;
			if (iread(&length, 1, 1) != 1)
				return IL_FALSE;
			if (iread(&post, 1, 1) != 1)
				return IL_FALSE; // Skip extra byte for scaling

			for (row_loop = 0; row_loop < length; row_loop++) {
				if (iread(&post, 1, 1) != 1)
					return IL_FALSE;
				if (row_loop + topdelta < height)
					iCurImage->Data[(row_loop+topdelta) * width + column_loop] = post;
			}
			iread(&post, 1, 1); // Skip extra scaling byte
		}

		iseek(pointer_position, IL_SEEK_SET);
	}

	// Converts palette entry 247 (cyan) to transparent.
	if (ilGetBoolean(IL_CONV_PAL) == IL_TRUE) {
		NewData = (ILubyte*)ialloc(iCurImage->SizeOfData * 4);
		if (NewData == NULL) {
			return IL_FALSE;
		}

		for (i = 0; i < iCurImage->SizeOfData; i++) {
			NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
			NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
			NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
			NewData[i * 4 + 3] = iCurImage->Data[i] != 247 ? 255 : 0;
		}

		if (!ilTexImage(iCurImage->Width, iCurImage->Height, iCurImage->Depth,
			4, IL_RGBA, iCurImage->Type, NewData)) {
			ifree(NewData);
			return IL_FALSE;
		}
		iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
		ifree(NewData);
	}

	ilFixImage();

	return IL_TRUE;
}


//
// READ A DOOM FLAT
//

//! Reads a Doom flat file
ILboolean ilLoadDoomFlat(ILconst_string FileName)
{
	ILHANDLE	FlatFile;
	ILboolean	bFlat = IL_FALSE;

	// Not sure of any kind of specified extension...maybe .lmp?
	/*if (!iCheckExtension(FileName, "")) {
		ilSetError(IL_INVALID_EXTENSION);
		return NULL;
	}*/

	FlatFile = iopenr(FileName);
	if (FlatFile == NULL) {
		ilSetError(IL_COULD_NOT_OPEN_FILE);
		return bFlat;
	}

	bFlat = ilLoadDoomF(FlatFile);
	icloser(FlatFile);

	return bFlat;
}


//! Reads an already-opened Doom flat file
ILboolean ilLoadDoomFlatF(ILHANDLE File)
{
	ILuint		FirstPos;
	ILboolean	bRet;

	iSetInputFile(File);
	FirstPos = itell();
	bRet = iLoadDoomFlatInternal();
	iseek(FirstPos, IL_SEEK_SET);

	return bRet;
}


//! Reads from a memory "lump" that contains a Doom flat
ILboolean ilLoadDoomFlatL(const ILvoid *Lump, ILuint Size)
{
	iSetInputLump(Lump, Size);
	return iLoadDoomFlatInternal();
}


// Basically just ireads 4096 bytes and copies the palette
ILboolean iLoadDoomFlatInternal()
{
	ILubyte	*NewData;
	ILuint	i;

	if (iCurImage == NULL) {
		ilSetError(IL_ILLEGAL_OPERATION);
		return IL_FALSE;
	}

	if (!ilTexImage(64, 64, 1, 1, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE, NULL)) {
		return IL_FALSE;
	}
	iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;

	iCurImage->Pal.Palette = (ILubyte*)ialloc(IL_DOOMPAL_SIZE);
	if (iCurImage->Pal.Palette == NULL) {
		return IL_FALSE;
	}
	iCurImage->Pal.PalSize = IL_DOOMPAL_SIZE;
	iCurImage->Pal.PalType = IL_PAL_RGB24;
	memcpy(iCurImage->Pal.Palette, ilDefaultDoomPal, IL_DOOMPAL_SIZE);

	if (iread(iCurImage->Data, 1, 4096) != 4096)
		return IL_FALSE;

	if (ilGetBoolean(IL_CONV_PAL) == IL_TRUE) {
		NewData = (ILubyte*)ialloc(iCurImage->SizeOfData * 4);
		if (NewData == NULL) {
			return IL_FALSE;
		}

		for (i = 0; i < iCurImage->SizeOfData; i++) {
			NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
			NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
			NewData[i * 4] = iCurImage->Pal.Palette[iCurImage->Data[i]];
			NewData[i * 4 + 3] = iCurImage->Data[i] != 247 ? 255 : 0;
		}

		if (!ilTexImage(iCurImage->Width, iCurImage->Height, iCurImage->Depth,
			4, IL_RGBA, iCurImage->Type, NewData)) {
			ifree(NewData);
			return IL_FALSE;
		}
		iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
		ifree(NewData);
	}

	ilFixImage();

	return IL_TRUE;
}


#endif
