Author Topic: Gimp plt plugin (Python version)  (Read 2705 times)

Legacy_Asymmetric

  • Sr. Member
  • ****
  • Posts: 289
  • Karma: +0/-0
Gimp plt plugin (Python version)
« on: December 05, 2015, 09:52:17 pm »


               

I wrote a plt plugin for gimp recently (I needed one that was working under Linux and wanted to test plt import for neverblender) and I have kind of a trivial question.


 


As you know plt uses greyscale and I want the plugin to convert it by itself if the image is still in RGB mode instead of an error message. Again this is kind of a technical and trivial question, but: What is your preferred way to convert from RGB to greyscale ?


  • Lightness:   (max(R, G, B )+ min(R, G, B ) / 2,  i.e. average the most and least prominent colours

  • Average:     (R + G + B ) / 3

  • Luminosity:  0.21 R + 0.72 G + 0.07 B . Matches Human perception

If you use the Colors->Desaturate menu you can choose between the three. If you simply go to Image -> Mode->Grayscale it will use Luminsosity. So my choice would be Luminosity.


This would be non-destructive of course, it won't touch the original image.


 


EDIT: Pesky smiley's popping up everywhere and destroying my formulas.


               
               

               
            

Legacy_OldTimeRadio

  • Hero Member
  • *****
  • Posts: 2307
  • Karma: +0/-0
Gimp plt plugin (Python version)
« Reply #1 on: December 06, 2015, 05:17:08 pm »


               

You can probably get an idea what technique Bioware used by grabbing one of the NPC face textures, converting it to grayscale via the various methods and then comparing that to the player analog PLT grayscale.  Unfortuantely, this might not yield the best result, just the one that matches official content the closest.  You may find out that Bioware punted and used something like Lightness or Average, instead.


 


BigfootNZ's thread "BigfootNZ's NWN spruce up" in the NWN Omnibus talks a little about the differences between PLT grayscale images from the original release compared to HotU.  His screenshot links still work, BTW.


 


A few years ago, I converted over some nude body (neck down) textures from another game to PLT and I'm 99% sure I used Luminosity to get them into B&W.  However, I had to spend quite a while brightness and contrast matching (i.e. tweaking sliders in GIMP) with an official content head PLT grayscale in an adjacent window in order to get it close enough to work.


 


I hope that helps.


 


By the way, can you direct me to where I can find more information about the header of a PLT?  I've found decent header information for the MDL and DDS but nothing on the PLT so far.  There's an obscure file called a ".4pc" which isn't actually used in NWN but which the executable searches for.  It is described as a "Custom 16-bit RGBA texture format", which I interpreted to probably mean a 2 or possibly 4-layer PLT, the latter possible containing layers of less than 8-bits...or something.  This is what I'm trying to reproduce to see if it does anything but I have no idea how to make sample files to experiment with.



               
               

               
            

Legacy_Asymmetric

  • Sr. Member
  • ****
  • Posts: 289
  • Karma: +0/-0
Gimp plt plugin (Python version)
« Reply #2 on: December 06, 2015, 09:00:59 pm »


               

Ah yes that's a good idea, thanks. I'll check the face textures.


 


As for the plt header. I kinda figured it out with a hex editor and a lot of files. It's a 24 byte header.



// First 8 bytes are always:
50 4C 54 20 56 31 20 20
P  L  T     V  1

// Next 8 bytes seem to be kinda random, at least the first byte is. The other 7 are always 00.
// Can't make sense of it and doesn't seem to matter. In custom content it's always:
0A 00 00 00 00 00 00 00
// In standard bioware plt there is some variation in the first byte, but it never goes higher than 0A, which would
// be 10 = the number of layers in a plt. I suspect it has something to do with the number of layers,
// but it's not used I think.
 
// Next 4 bytes is width (little endian)
80 00 00 00

// Next 4 bytes is height
40 00 00 00

// The rest are (values, layer) tuples
AA 00 BB 01 ...

// Which would be:
// (AA = value, 00 = layer), (BB = value, 01 = layer)
// values are 0-255 grayscale
// layer id are 0-9 in the following order:
// ['Skin', 'Hair', 'Metal1', 'Metal2', 'Cloth1', 'Cloth2', 'Leather1', 'Leather2', 'Tattoo1', 'Tattoo2']
// I haven't actually tested what happens if I try to use layer 10

While we're at it: I tried to figure out the bioware dds header, but had limited luck. As far as I can tell it has a 16 byte header: Width, Height, "Type" (Alpha or Non-alpha/Compression type), Data Size and some random 4 bytes. However it's only random for images with an alpha channel. For images without alpha it's always 00 00 80 3F. I wonder what it does. It's not needed for importing, but maybe for exporting ?


I thought of writing a gimp plugin, which can load and save bioware dds files in addition to standard ones.  Could you point me to some information ?



               
               

               
            

Legacy_OldTimeRadio

  • Hero Member
  • *****
  • Posts: 2307
  • Karma: +0/-0
Gimp plt plugin (Python version)
« Reply #3 on: December 06, 2015, 09:42:45 pm »


               

Much thanks!  That at least gives me a roadmap to work with.  

 

As far as the DDS header goes, the following from John Bible (BW programmer) in the Omnibus tread entitled "The dds format":



Sorry, apparently the readme read slightly wrong on this topic --- it wasn't meant to be something you needed to hack  '<img'>  (though that's always fun).

I just scanned through the ImageWriteS3TC function, and it heads the file with

width (int)

height (int)

bits per pixel (int)

compressed_size (int) (of the first mipmap level)

alphamean (float)

Obviously, these values are packed (well, okay, maybe not obviously [/icon_wink.gif] ) Also, sizes of values are as for c\c++ in Visual C++ 6.

Following these are the compressed mipmaps largest to smallest (compressed with dx1 and dx5 if you're using the nomenclature in directx, where bpp determines which the dds is when decompressing).

That should be enough.



 


Muddled with this just a little bit.  The 00 00 80 3F comes out to 1.0, which would make sense that this would be the alpha mean for a texture with no alpha channel.  Why, exactly, they store the alpha mean has been a curiosity to me though it might play some role in feeding the texture to OpenGL without having to do an on-the-fly test.  Not sure, though.  Just playing around briefly a week or so ago, I changed that 00 00 80 3F (1.0) to 00 00 00 3F (.5) thanks to this site but didn't notice any difference.  This could have purely been shoddy testing on my part.


 


To be taken with a huge grain of salt: Anecdotally, trolling the Omnibus seemed to indicate that there might be some other things stored or that could possibly be stored in the texture's header but that the Bioware DDS header, much like the binary model header, is sort of flexible in what it contains, depending.  Most of this investigation took place a few weeks ago, in a haze of looking for comparisons and contrasts between the NWN Bioware DDS files and KotOR's TPC, among other things.  Unfortunately, I may have my wires crossed and that anecdotal bit could be about TPC's instead.  I should pointedly note that this whole paragraph is more related to uncovering undiscovered functionality than anything that would be needed for a community utility.



               
               

               
            

Legacy_Asymmetric

  • Sr. Member
  • ****
  • Posts: 289
  • Karma: +0/-0
Gimp plt plugin (Python version)
« Reply #4 on: January 17, 2016, 01:20:18 pm »


               

Alrighty. I've released a new version of the plt plugin. It uses gimp layer names to decide which plt layer a gimp layer corresponds to. It's a bit faster too, as now I don't have to find the layer index myself.


There is a new option "Plt: Create Layers" under "Tools". It will create the 10 necessary layers, so you don't have to do it manually: 'skin', 'hair', 'metal1', 'metal2', 'cloth1', 'cloth2', 'leather1', 'leather2', 'tattoo1', 'tattoo2'.