textures2quake: Takes high res textures --> Quake/Half-Li

Discuss anything not covered by any of the other categories.
Sajt
Posts: 1215
Joined: Sat Oct 16, 2004 3:39 am

Post by Sajt »

A nearest-neighbour reduction using luminosity weighting (wow... a lot of big words makes that sound more than what it is: extremely simple) produces a much more palatable image:

Image

But I'm sure that that fancier algorithm must be good for something. I wonder what sort of image it would do well on.
F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Works well enough for my purposes. Most textures that would be used in a Quake map aren't really "millions of colors" type textures.

I used what was available in FreeImage.

Quake palette conversion of Nexuiz:

Image

Maybe fun to work on the fixed palette conversions for future versions :D

/Btw ... I can't tell if you are being sarcastic, but if so I'd like to point out that your palette indexes in your sample are wrong.

Image
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Sajt
Posts: 1215
Joined: Sat Oct 16, 2004 3:39 am

Post by Sajt »

I'm not really sure what I could have been sarcastic about. I would like to see an example of what sort of situations this special algorithm is designed for.

As for the palette, my program exported a PCX and I used PSP to convert it to a PNG so I could upload it. Paint Shop Pro rearranges the palette (or "optimizes" it?) when it saves a PNG. They still are the same Quake colours, though, just in a different order. (It's not like anyone in their right mind would use PNG for game textures, anyway.)

Looks like PSP has an option to disable that palette "optimization". I'll use that next time...
F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Sajt wrote:I'm not really sure what I could have been sarcastic about. I would like to see an example of what sort of situations this special algorithm is designed for.
Could be a speed thing ...
My general research activities are in visual/multimedia computing and communications. I have published numerous algorithms for computer graphics and image processing (image coding in particular), some of which are being used by practitioners, such as a fast optimal color quantizer, and a Context-based Adaptive Lossless Image Codec (CALIC) which was developed jointly with Nasir Memon as a candidate algorithm for the new JPEG lossless standard.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Teiman
Posts: 311
Joined: Sun Jun 03, 2007 9:39 am

Post by Teiman »

Sajt wrote:... (It's not like anyone in their right mind would use PNG for game textures, anyway.)...
Oooops... hehehe.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Teiman wrote:
Sajt wrote:... (It's not like anyone in their right mind would use PNG for game textures, anyway.)...
Oooops... hehehe.
It is a shame that TGA can't be used on the internet like PNG can. It is also a shame that TGA cannot easily be browsed with the thumbnail view in Windows.

Back when I was a fan of PNG textures in the past, that was what I liked about them: make them once, display them anywhere.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
c0burn
Posts: 208
Joined: Fri Nov 05, 2004 12:48 pm
Location: Liverpool, England
Contact:

Post by c0burn »

I use FastStone MaxView as my image viewer, and when installed the shell extension shows TGA thumbnails, which is nice.
Teiman
Posts: 311
Joined: Sun Jun 03, 2007 9:39 am

Post by Teiman »

I was trying to avoid it, but here goes:

Why? Why is a bad idea to use PNG?

Is not like JPG, it don't destroy the quality of the image. and it supports a alpha channel, two styles (1 bit alfa and 8 bits alfa )...

Why is not that good? do it randomize the palette in 8 bits mode or something?
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Post by Spike »

Tei:
png and zip use the same compression algorithm, but applied differently.
In png, its applied on a per-plane basis. In zip+tga its applied over the entire byte stream.
Compressing a tga in a zip means that you compress each pixel individually while png compresses each pixel 3/4 times. Repeating patterns and windows and stuff mean that tga has a smaller chance for repetition, but when there is some, there are a third less references in the window.

Basically the outcome is that you can block-decompress+decode a tga faster than you can decode+combine the multiple planes of a png.
And its a bit smaller too.

.rar+.tga or .tar.gz+.tga gives solid archives, which allows the reuse of compression windows over multiple similar files.

If the engine supports zips/pk3s, use tgas.
If the engine doesn't support zips/pk3s, you get even better compression from tgas inside a pak anyway, and the extra size weighed against the lack of compression doesn't hinder load times, but it does mean faster download speeds. However it does use more disk space. Disk space is rarely a concern nowadays.

pngs are nice and all... but... mneh.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Teiman wrote:I was trying to avoid it, but here goes:

Why? Why is a bad idea to use PNG?
Another reason: TGA loading in the engine can just use the engine code. If you have some non-traditional platform, supporting TGA loading is as easy as any other platform. You don't need .dll files to load a TGA.

Case in point, FitzQuake and Enhanced GL/WinQuake support external TGA textures but need no external dlls.

Code: Select all

/*
=========================================================

TARGA LOADING

=========================================================
*/

#pragma pack(1)
typedef struct _TargaHeader {
	unsigned char 	id_length, colormap_type, image_type;
	unsigned short	colormap_index, colormap_length;
	unsigned char	colormap_size;
	unsigned short	x_origin, y_origin, width, height;
	unsigned char	pixel_size, attributes;
} TargaHeader;
#pragma pack()

/*
=============
LoadTGA
=============
*/
static byte *LoadTGA (char *name, int *width, int *height, qboolean alphablend)
{
	TargaHeader *targa_header;
	FILE	    *f;
	int	    columns, rows, numPixels;
	byte	    *pixbuf, *buf;
	byte	    *targa_rgba;
	int	    row, realrow, column;
	qboolean    upside_down, alpha, blend;
	char	    filename[MAX_OSPATH];

	sprintf (filename, "%s.tga", name);
	COM_FOpenFile (filename, &f);

	if (!f)
		return NULL;

	if (com_filesize < sizeof(TargaHeader))
		Sys_Error ("LoadTGA: can't read header in %s", filename);

	targa_header = malloc (com_filesize);

	if (!targa_header)
		Sys_Error ("LoadTGA1: error allocating %d bytes for %s", com_filesize, filename);

	if (fread (targa_header, 1, com_filesize, f) != com_filesize)
		Sys_Error ("LoadTGA: error reading %s", filename);

	fclose (f);

	targa_header->width = SwapShort (&targa_header->width);
	targa_header->height = SwapShort (&targa_header->height);

	if (targa_header->image_type!=2
		&& targa_header->image_type!=10)
		Sys_Error ("LoadTGA: %s: only type 2 and 10 targa RGB images supported, not %d", filename, targa_header->image_type);

	if (targa_header->colormap_type !=0
		|| (targa_header->pixel_size!=32 && targa_header->pixel_size!=24))
		Sys_Error ("LoadTGA: %s: only 24 and 32 bit images supported (no colormaps, type=%d, bpp=%d)", filename, targa_header->colormap_type, targa_header->pixel_size);

	columns = targa_header->width;
	rows = targa_header->height;
	numPixels = columns * rows;
	upside_down = !(targa_header->attributes & 0x20); // true => picture is stored bottom to top

	targa_rgba = malloc (numPixels*4);

	if (!targa_rgba)
		Sys_Error ("LoadTGA2: error allocating %d bytes for %s", numPixels*4, filename);

	blend = alphablend && gl_alphablend.value;
	alpha = targa_header->pixel_size == 32;

	buf = (byte *)(targa_header + 1);

	if (targa_header->id_length != 0)
		buf += targa_header->id_length; // skip TARGA image comment

	if (targa_header->image_type==2) {  // Uncompressed, RGB images
		for(row=rows-1; row>=0; row--) {
			realrow = upside_down ? row : rows - 1 - row;
			pixbuf = targa_rgba + realrow*columns*4;

			ChkBounds ("LoadTGA1", buf - (byte *)targa_header + columns * targa_header->pixel_size / 8, com_filesize, filename);
			ChkBounds ("LoadTGA2", pixbuf - targa_rgba + columns * 4, numPixels * 4, filename);

			for(column=0; column<columns; column++) {
				unsigned char red,green,blue,alphabyte;
				blue = *buf++;
				green = *buf++;
				red = *buf++;
				*pixbuf++ = red;
				*pixbuf++ = green;
				*pixbuf++ = blue;
				*pixbuf++ = alpha ? *buf++ : (blend ? (red + green + blue) / 3 : 255); // Better way?;
			}
		}
	}
	else if (targa_header->image_type==10) {   // Runlength encoded RGB images
		unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
		for(row=rows-1; row>=0; row--) {
			realrow = upside_down ? row : rows - 1 - row;
			pixbuf = targa_rgba + realrow*columns*4;
			for(column=0; column<columns; ) {
				packetHeader = *buf++;
				packetSize = 1 + (packetHeader & 0x7f);

				ChkBounds ("LoadTGA3", pixbuf - targa_rgba + packetSize * 4, numPixels * 4, filename);

				if (packetHeader & 0x80) {        // run-length packet
					ChkBounds ("LoadTGA4", buf - (byte *)targa_header + targa_header->pixel_size / 8, com_filesize, filename);
					blue = *buf++;
					green = *buf++;
					red = *buf++;
					alphabyte = alpha ? *buf++ : (blend ? (red + green + blue) / 3 : 255); // Better way?;

					for(j=0;j<packetSize;j++) {
						*pixbuf++ = red;
						*pixbuf++ = green;
						*pixbuf++ = blue;
						*pixbuf++ = alphabyte;
						column++;
						if (column==columns) { // run spans across rows
							column=0;
							if (row>0)
								row--;
							else
								goto breakOut;
							realrow = upside_down ? row : rows - 1 - row;
							pixbuf = targa_rgba + realrow*columns*4;
						}
					}
				}
				else {                            // non run-length packet
					ChkBounds ("LoadTGA5", buf - (byte *)targa_header + packetSize * targa_header->pixel_size / 8, com_filesize, filename);
					for(j=0;j<packetSize;j++) {
						blue = *buf++;
						green = *buf++;
						red = *buf++;
						*pixbuf++ = red;
						*pixbuf++ = green;
						*pixbuf++ = blue;
						*pixbuf++ = alpha ? *buf++ : (blend ? (red + green + blue) / 3 : 255); // Better way?;
						column++;
						if (column==columns) { // pixel packet run spans across rows
							column=0;
							if (row>0)
								row--;
							else
								goto breakOut;
							realrow = upside_down ? row : rows - 1 - row;
							pixbuf = targa_rgba + realrow*columns*4;
						}
					}
				}
			}
			breakOut:;
		}
	}

	*width = targa_header->width;
	*height = targa_header->height;

	free (targa_header);

	return targa_rgba;
}
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Sajt
Posts: 1215
Joined: Sat Oct 16, 2004 3:39 am

Post by Sajt »

Also, the LibPNG loader is notoriously slow.

Of course, much better than either PNG or zipped TGA is the mysterious "dmip" format... but that's another story.
F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe.
Teiman
Posts: 311
Joined: Sun Jun 03, 2007 9:39 am

Post by Teiman »

Uh.. ok, thanks guys ( Sajt, Baker, Spike).

Now.. I remember the libpng library as a memory-hungry and unstable one.

The tga in a zip thing is very interesting.
ceriux
Posts: 2230
Joined: Sat Sep 06, 2008 3:30 pm
Location: Indiana, USA

Post by ceriux »

made a news post about it on my moddb group

http://www.moddb.com/groups/quakedb/new ... rsion-tool
negke
Posts: 150
Joined: Wed Apr 16, 2008 5:53 pm
Contact:

Post by negke »

Good job.
Especially the 50% reduction will make batch conversion much more convenient in many cases.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Some things that this could do better ...

Take the #water #lava textures and for the Quake portion of the process, turn them into *water and *lava, etc.

Apparently a 16 pixels is the minimum Quake texture dimension, not 8. Reference: http://www.celephais.net/stuff/texturefaq.htm

And apparently liquids and clip should be 64x64 for software renderers.

And sky textures 256x128. Although since Quake 3 and no other game uses Quake sky textures, such a conversion enforcement is a little "unneeded".
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Post Reply