Advertisement

Targa Loader, Quick Question

Started by December 14, 2004 02:22 PM
17 comments, last by Zeusbwr 19 years, 11 months ago
The targa loader found at http://steinsoft.net/index.php?site=Programming/Code%20Snippets/Cpp/no8 , has me a bit confused. How exactly do you use it? Can someone just give me a simple example of how to load the tga and create a 2d texture with it? Then bind the one line of code to bind it to a object? (ofcourse its more with polygons, but atm i am talkin prebuilt glut objects.) Thanks! I must have been doin somethin wrong because i get an error anytime i try to implement it. Thanks :)
Rank: OpenGL & Glut "Nub", C++ Freshman.
An example of how to use it is given in the article. Perhaps you could post some of your code along with the specific error you are getting.
Advertisement
Although the example is actually wrong. It should be:
STGA tgaFile;if (loadTGA("data/image.tga", tgaFile)) // no operator&{   //Do things...   // ex. create OpenGL texture using tgaFile->imageData etc.} //tgaFile will clean up itself thanks to destructor

Since the loadTGA function takes its parameter by reference, not by pointer. Looks like this code was originally pure C, retrofitted with a couple of functions (one of which is dangerous and should not be there) and reference calling convention.

Enigma
Sorry, i have been busy with the holiday lol.

Can you give me an example of the "do stuff" section of the code? Inside the if statement for loading the bitmap?


If my light grasp of loading images and creating a texture is correct, you take the image, load it into an array (to do that you need some type of decoder that knows the image format), then start telling opengl what you wish to do with the data you loaded.

However after that it gets very hazy. Can someone give me an example code of what i need to load the texture?

Like the glGenTexture, BindTexture, glTexImage2D, and glTexParameteri's?

Total nub here, please help me out lol, thanks! :)
Rank: OpenGL & Glut "Nub", C++ Freshman.
An example (remember to include the right struct):
http://www.nife.1go.dk/C++/LoadTGAFile.txt
It's not my newest version (because that's implemented into another class, and would therefore be hard to seperate nicely), but it should do the job for now...

For speed:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

Medium quality:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

High quality (2x AF):
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2);

Very high quality (4x AF)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 4);

The higheste count of AF can be achieved by:
int anisotropic;
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic);

And for the GLUT question: frankly I have no idea, since I've never used GLU or GLUT, but I can show you how to with OpenGL functions ;-)
Killers don't end up in jailThey end up on a high-score!
That isn't exactly the best designed class I've seen..
First it should be a class, second, LoadTGA should be a member function of STGA [smile] - but thats just me being picky. Also, the big thing, is that the number of channels in the image is a local variable of LoadTGA.. it should be a class variable.

Btw. to my eye at least, the destroy() method of STGA will likly cause a crash in the destructor so don't use it.

I couldn't resist...
Here is my version: [wink]

STGA.h:
#pragma onceclass STGA{ 	STGA(STGA & tga); // no copying! (memory errors otherwise)public:	STGA();	STGA(char * file);	~STGA();	void destroy();	int width();	int height();	unsigned char * data();	int channels();	bool load(char *filename);	void loadOpenGL();	void bindOpenGL();	void destroyOpenGL();private:	unsigned int openGLid;	int imageWidth;	int imageHeight;	unsigned char imageTypeCode;	unsigned char bitCount;	unsigned char* imageData;	int imageChannels;};


STGA.cpp:
#include "STGA.h"// #include "stdafx.h" // whatever// etcSTGA::STGA(STGA & tga) // no copying! (memory errors otherwise){}STGA::STGA() : imageData(0), imageWidth(0), imageHeight(0), imageTypeCode(0), bitCount(0), imageChannels(0), openGLid(0){}STGA::STGA(char * file) : imageData(0), imageWidth(0), imageHeight(0), imageTypeCode(0), bitCount(0), imageChannels(0), openGLid(0){	load(file);}STGA::~STGA(){	destroy(); }void STGA::destroy(){ 	if (imageData)		delete[] imageData;	imageData=0;	imageWidth=0;	imageHeight=0;	imageTypeCode= 0;	bitCount=0;	imageChannels=0;	destroyOpenGL();}int STGA::width(){	return imageWidth;}int STGA::height(){	return imageHeight;}unsigned char * STGA::data(){	return imageData;}int STGA::channels(){	return imageChannels;}bool STGA::load(char *filename){	FILE *file;	unsigned char		badChar;	short int		badInt;	long		  	imageSize;	int			colorMode;			file = fopen(filename, "rb");			if (!file)		return false;			fread(&badChar, sizeof(unsigned char), 1, file);	fread(&badChar, sizeof(unsigned char), 1, file);			fread(&imageTypeCode, sizeof(unsigned char), 1, file);			//image type either 2 (color) or 3 (greyscale)	if ((imageTypeCode != 2) && (imageTypeCode != 3))	{		fclose(file);		return false;	}			//13 bytes of useless data	fread(&badInt, sizeof(short int), 1, file);	fread(&badInt, sizeof(short int), 1, file);	fread(&badChar, sizeof(unsigned char), 1, file);	fread(&badInt, sizeof(short int), 1, file);	fread(&badInt, sizeof(short int), 1, file);			//image dimensions	fread(&imageWidth, sizeof(short int), 1, file);	fread(&imageHeight, sizeof(short int), 1, file);			//image bit depth	fread(&bitCount, sizeof(unsigned char), 1, file);			//1 byte of garbage data	fread(&badChar, sizeof(unsigned char), 1, file);			//colorMode -> 3 = BGR, 4 = BGRA 	colorMode = bitCount / 8;	imageSize = imageWidth * imageHeight * colorMode;			//allocate memory for image data	imageData = new unsigned char[imageSize];			//read in image data	fread(imageData, sizeof(unsigned char), imageSize, file);			//change BGR to RGB (especially for OpenGL later on)	for (int i = 0; i < imageSize; i += colorMode)	{		//swap blue and red colour value 		imageData ^= imageData[i+2] ^=			imageData ^= imageData[i+2];	}			//close file	fclose(file);	imageChannels=colorMode; 	return true;}STGA::loadOpenGL(){	glGenTextures(1, &openGLid);	glBindTexture(GL_TEXTURE_2D, openGLid);	INSERT YOUR glTexParametrei Calls here to set filtering, etc!!!	unsigned int mode=GL_RGB;	if (channels()==4)		mode=GL_RGBA;	glTexImage2D(GL_TEXTURE_2D,0,channels(),width(),height(),0,mode,GL_UNSIGNED_BYTE,data());	gluBuild2DMipmaps(GL_TEXTURE_2D,channels(),width(),height(),mode,GL_UNSIGNED_BYTE,data());}STGA::bindOpenGL(){	if (openGLid)		glBindTexture(GL_TEXTURE_2D, openGLid);}STGA::destroyOpenGL(){	if (openGLid)		glDeleteTextures(1, &openGLid);	openGLid=0;}



(no guarentee it works, I havn't tested it [smile])

Therefore, the usage would be something like:


STGA tga; // global, or in a class somewhere, ie, sticks around for entire time

....

if (tga.load("data/mytest.tga"))
{
tga.loadOpenGL();
}


then when rendering,

tga.bindOpenGL(); // to bind.

okies? [wink]
All nice and OO :)


hope that compiles. (I've left out the tex param sutff that nife mentioned. put in what you feel is appropriate)


Have fun.
Advertisement
Quote: Original post by RipTorn
That isn't exactly the best designed class I've seen..
First it should be a class, second, LoadTGA should be a member function of STGA [smile] - but thats just me being picky. Also, the big thing, is that the number of channels in the image is a local variable of LoadTGA.. it should be a class variable.

Btw. to my eye at least, the destroy() method of STGA will likly cause a crash in the destructor so don't use it.

I couldn't resist...
Here is my version: [wink]

STGA.h:
*** Source Snippet Removed ***

STGA.cpp:
*** Source Snippet Removed ***


(no guarentee it works, I havn't tested it [smile])

Therefore, the usage would be something like:


STGA tga; // global, or in a class somewhere, ie, sticks around for entire time

....

if (tga.load("data/mytest.tga"))
{
tga.loadOpenGL();
}


then when rendering,

tga.bindOpenGL(); // to bind.

okies? [wink]
All nice and OO :)


hope that compiles. (I've left out the tex param sutff that nife mentioned. put in what you feel is appropriate)


Have fun.


That's one slow tga loader ;)
You have way to many fread's, and instead of swapping the bytes, you could use GL_BGR_EXT and GL_BGRA_EXT with pictures which doesn't require to be read from anymore (ie. no runtime manipulation).
Killers don't end up in jailThey end up on a high-score!
I just copied and pasted the actual loading code form the site he linked.

It's just it's packaged into a class instead. And got rid of a couple of the bugs in it. And added loading into OpenGL.

So that part isn't my code ;)
Thanks guys :), so i havent tested that yet (and my ability to use it). But i'm just curious, do you all just make your own loaders for your applications then?
Rank: OpenGL & Glut "Nub", C++ Freshman.
Well, it's better than it was but there are still some bugs and stylistic issues in that class design. Some of the stylistic points are debatable, I've tried to indicate that where applicable.

Bugs:
  • If copy-construction is illegal then assignment should be too.

  • If copy-construction is illegal then the copy constructor should be declared but not defined. This prevents code that can legally call private member functions (i.e. other members or friends) from successfully linking in the event that they try to use the copy constructor (the same goes for the assignment operator).

  • load may be called multiple times on the same instance. Each such call after the first results in a memory leak.

Stylistic:
  • #pragma once is non-portable. An #ifndef, #define, #endif structure would be better if portability is a concern.

  • const correctness. Many functions are themselves or take parameters that are logically const. This should be reflected in the code.

  • Overly large interface. There are several ways to achieve the same functionality (i.e. STGA instance(filename); vs STGA instance;instance.load(filename);). Prefer to make class interfaces complete but minimal.

  • Resouce Acquisition Is Initialisation (RAII). If you subscribe to this philosophy then STGA(filename); should be the only constructor and should call both load and loadOpenGL. The destructor should then call both destroyOpenGL and destroy. As it is it is far too easy for a client to forget to call destroyOpenGL and thus leak a texture ID. In this instance RAII does require that a valid OpenGL context exists before any STGA instances are created. This may not be acceptable.

  • Prefer std::string to char* for textual types. It's just plain easier that way. And no, char* is not going to be faster in any noticable way. For this code the type used to represent text (provided it's sensible) is never going to be a bottleneck.

  • Testing a pointer for nullness prior to deletion is always redundant. The standard guarantees that deleting a null pointer has no effect.

  • A call to glTexImage2D in addition to gluBuild2DMipmaps is redundant. gluBuild2DMipmaps will build all mipmap levels, including the top level.


Also a note on some of the code that was directly from the original loader: Using xor to swap variables is often a pessimisation, not an optimisation. On the platform I tested it on (Pentium IV) all three compilers I tested produced significantly faster code when using a temporary than when swapping using the xor trick.

Enigma

This topic is closed to new replies.

Advertisement