ManageTextures.cpp 9.07 KB
#include "trueeyes.h"
#include "VolumeDataStruct.h"
#include "TextureDataStruct.h"
#include <vector>

//list of volume objects for rendering
vector<VolumeData> VolumeList;

//list of texture objects used for transfer functions
vector<TextureData> TextureList;

void CreateAutoVolume()
{
	int s = 64;
	unsigned char* volume = new unsigned char[s*s*s*3];
	memset(volume, 0, s*s*s*3);

	int x, y, z;
	for(x=0; x<s; x++)
		for(y=0; y<s; y++)
			for(z=0; z<s; z++)
			{
				vector3D<float> v = vector3D<float>(x-s/2, y-s/2, z-s/2);

					volume[z*s*s*3 + y*s*3 + x*3 + 0] = x*(255/s);
					volume[z*s*s*3 + y*s*3 + x*3 + 1] = y*(255/s);
					volume[z*s*s*3 + y*s*3 + x*3 + 2] = z*(255/s);
			}

	if(VolumeList.size() > 0)
	{
		VolumeList[0].Texture.Clean();
		VolumeList.clear();
	}

	//create an OpenGL texture map
	rts_glTextureMap newTexture;
	newTexture.Init(volume, GL_TEXTURE_3D, s, s, s, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, GL_LINEAR);

	//create the volume data structure
	VolumeData newVolume;
	newVolume.Name = "volume";
	newVolume.Texture = newTexture;
	newVolume.FileType = VOLUME_FILE_AUTO;
	newVolume.Dim = vector3D<int>(s, s, s);
	newVolume.ExternalComponents = 3;
	newVolume.ExternalDatatype = GL_UNSIGNED_BYTE;
	newVolume.InternalComponents = 3;
	newVolume.InternalDatatype = GL_UNSIGNED_BYTE;
	
	//add the volume structure to the list of volumes
	VolumeList.push_back(newVolume);
}

//define macros for bit swapping (little endian to big endian in Windows)
#define SWAP_2(x) ( (((x) & 0xff) << 8) | ((unsigned short)(x) >> 8) )
#define SWAP_4(x) ( ((x) << 24) | \
         (((x) << 8) & 0x00ff0000) | \
         (((x) >> 8) & 0x0000ff00) | \
         ((x) >> 24) )
#define FIX_SHORT(x) (*(unsigned short *)&(x) = SWAP_2(*(unsigned short *)&(x)))
#define FIX_INT(x)   (*(unsigned int *)&(x)   = SWAP_4(*(unsigned int *)&(x)))
#define FIX_FLOAT(x) FIX_INT(x)

void FlipBits(void* bits, int bpp, int size)
{
	int i;
	if(bpp == 2)
	{
		unsigned short* short_bits = (unsigned short*)bits;
		for(i=0; i<size; i++)
		{
			FIX_SHORT(short_bits[i]);
		}
	}
	if(bpp == 4)
	{
		unsigned int* int_bits = (unsigned int*)bits;
		for(i=0; i<size; i++)
		{
			FIX_INT(int_bits[i]);
		}
	}
}
int LoadHighComponentRawVolume(VolumeData& newVolume, int minC, int maxC)
{
	//This function loads a single volume with a large number of components as separate textures
	//This is necessary because the maximum number of components in an OpenGL texture is 4 (RGBA)
	//Call this function multiple times, specifying the range in minC and maxC

	//get the volume size and allocate space
	int sx = newVolume.Dim.x;
	int sy = newVolume.Dim.y;
	//the total z dimension is the dimension of each file times the number of files
	int file_z = newVolume.Dim.z;
	int sz = file_z * newVolume.Filenames.size();

	cout<<"Loading high-component volume----------------"<<endl;
	cout<<"Size: "<<sx<<","<<sy<<","<<sz<<endl;

	//set the components to the appropriate value
	int totalC = newVolume.ExternalComponents;
	int components = maxC - minC + 1;
	newVolume.ExternalComponents = components;

	int precision = newVolume.GetByteSize(newVolume.ExternalDatatype);

	cout<<"Allocating "<<sx*sy*sz*components*precision<<" bytes..."<<endl;
	char* bits = (char*)malloc(sx*sy*sz*components*precision);
	if(bits == NULL)
	{
		cout<<"Error allocating main memory."<<endl;
		return 1;
	}

	for(int n=0; n<newVolume.Filenames.size(); n++)
	{
		FILE *f;
		f = fopen(newVolume.Filenames[n].getString().c_str(), "rb");
		//if the file is valid
		if(f)
		{
			//seek past the header
			fseek(f, newVolume.HeaderSize, SEEK_SET);

			//increment to the start of the desired component range
			char* dst = bits;
			dst += precision*minC;
			fseek(f, precision*minC, SEEK_CUR);

			//load each voxel independently
			for(int c=0; c<sx*sy*sz; c++)
			{
				//read the components within the specified range
				fread(dst, sizeof(unsigned char), components*precision, f);
				fseek(f, precision*(totalC - maxC - 1), SEEK_CUR);
			}
		}
		else
			cout<<"error"<<endl;
		fclose(f);
	}

	//create the OpenGL texture map
	rts_glTextureMap newTexture;
	newTexture.Init(bits, GL_TEXTURE_3D, sx, sy, sz, newVolume.getInternalFormat(),
													 newVolume.getExternalFormat(),
													 newVolume.ExternalDatatype);
	free(bits);

	//store it in the volume list
	newVolume.Texture = newTexture;
	VolumeList.push_back(newVolume);

	return 0;
}

int LoadRawVolume(VolumeData& newVolume)
{
	if(newVolume.ExternalComponents > 4)
	{
		LoadHighComponentRawVolume(newVolume, 0, 2);
		LoadHighComponentRawVolume(newVolume, 3, 5);
		return 0;
	}
	//get the volume size and allocate space
	int sx = newVolume.Dim.x;
	int sy = newVolume.Dim.y;
	//the total z dimension is the dimension of each file times the number of files
	int sz = newVolume.Dim.z;
	int file_z;
	if(newVolume.Filenames.size() == 1)
		file_z = sz;
	else if(newVolume.Filenames.size() > 1)
	{
		file_z = 1;
		sz = file_z * newVolume.Filenames.size();
	}
	
	int components = newVolume.ExternalComponents;
	int precision = newVolume.GetByteSize(newVolume.ExternalDatatype);

	cout<<"Loading RAW volume----------------"<<endl;
	cout<<"Size: "<<sx<<","<<sy<<","<<sz<<endl;
	cout<<"Components: "<<components<<endl;
	cout<<"Precision: "<<precision<<" bytes"<<endl;

	cout<<"Allocating "<<sx*sy*sz*components*precision<<" bytes..."<<endl;
	char* bits = (char*)malloc(sx*sy*sz*components*precision);
	if(bits == NULL)
	{
		cout<<"Error allocating main memory."<<endl;
		return 1;
	}

	for(int n=0; n<newVolume.Filenames.size(); n++)
	{
		FILE *f;
		f = fopen(newVolume.Filenames[n].getString().c_str(), "rb");
		if(f)
		{
			fseek(f, newVolume.HeaderSize, SEEK_SET);
			fread(bits + sx*sy*file_z*n*components*precision, sizeof(unsigned char), sx*sy*file_z*components*precision, f);
		}
		else
			cout<<"error"<<endl;
		fclose(f);
	}
	
	if(newVolume.BitType == LOAD_BIG_ENDIAN)
		FlipBits(bits, precision, sx*sy*sz*components);

	//create the OpenGL texture map
	rts_glTextureMap newTexture;
	newTexture.Init(bits, GL_TEXTURE_3D, sx, sy, sz, newVolume.getInternalFormat(),
													 newVolume.getExternalFormat(),
													 newVolume.ExternalDatatype);
	free(bits);
	//store it in the volume list
	newVolume.Dim.z = sz;
	newVolume.Texture = newTexture;
	VolumeList.push_back(newVolume);


	return 0;
}



int LoadImages(VolumeData& newVolume)
{
	//*******currently, this only supports image formats with 8bpp

	//get the number of images
	int sz = newVolume.Filenames.size();

	//load the first image to determine the volume size
	QImage I(newVolume.Filenames[0].getString().c_str());
	int sx = I.width();
	int sy = I.height();
	

	//find the number of color components
	int components = I.depth()/8;

	int precision = 1;

	//allocate memory for the image
	char* bits = (char*)malloc(sx*sy*sz*components*precision);

	cout<<"Image size: "<<I.width()<<","<<I.height()<<endl;
	cout<<"Components: "<<components<<endl;
	cout<<"Precision: "<<precision<<endl;
	//copy each image to the correct place in the array
	for(int i=0; i<sz; i++)
	{
		I = QImage(newVolume.Filenames[i].getString().c_str()).mirrored().rgbSwapped();
		memcpy((unsigned char*)bits + sx*sy*components*precision*i, I.bits(), sx*sy*components*precision);
	}

	//fill the volume data structure
	newVolume.Dim = vector3D<int>(sx, sy, sz);
	newVolume.ExternalComponents = components;
	newVolume.ExternalDatatype = GL_UNSIGNED_BYTE;
	newVolume.InternalComponents = components;
	newVolume.InternalDatatype = GL_UNSIGNED_BYTE;
	//newVolume.Name = newVolume.Filenames[0].getPrefix();

	rts_glTextureMap newTexture;
	/*newTexture.Init(bits, GL_TEXTURE_3D, sx, sy, sz, newVolume.getInternalFormat(),
													 newVolume.getExternalFormat(),
													 newVolume.ExternalDatatype);*/
	newTexture.Init(bits, GL_TEXTURE_3D, sx, sy, sz, newVolume.getInternalFormat(),
													 newVolume.getExternalFormat(),
													 newVolume.ExternalDatatype);
	free(bits);

	newVolume.Texture = newTexture;
	VolumeList.push_back(newVolume);
	

	return 0;
}

int LoadTexture(TextureData& newTexture)
{
	//*******currently, this only supports image formats with 8bpp

	//load the image
	QImage I(newTexture.Filename.getString().c_str());
	//swap because for some reason QImage returns a BGR image as a pointer
	I = I.rgbSwapped();
	int sx = I.width();
	int sy = I.height();
	

	//find the number of color components
	int components = I.depth()/8;

	//allocate memory for the image
	char* bits = (char*)malloc(sx*sy*components);

	cout<<"Image size: "<<I.width()<<","<<I.height()<<endl;
	cout<<"Components: "<<components<<endl;
	//copy the image to a memory array
	memcpy((unsigned char*)bits, I.bits(), sx*sy*components);


	//fill the volume data structure
	newTexture.sX = sx;
	newTexture.sY = sy;
	newTexture.ExternalComponents = components;
	newTexture.InternalComponents = components;
	newTexture.ExternalDatatype = GL_UNSIGNED_BYTE;
	newTexture.InternalDatatype = GL_UNSIGNED_BYTE;
	newTexture.Normalized = true;

	//newVolume.Name = newVolume.Filenames[0].getPrefix();

	rts_glTextureMap texMap;
	texMap.Init(bits, GL_TEXTURE_2D, sx, sy, 0, newTexture.getInternalFormat(),
													 newTexture.getExternalFormat(),
													 newTexture.ExternalDatatype);
	free(bits);

	newTexture.Texture = texMap;
	
	

	return 0;

}