Determine which IMAGE belongs to a shader


(Flippy) #1

Hi,

I am creating an application that will allow you to select the .map or the .bsp file of your map, and it will present you with a list of all the textures you used in your map.
Then, the application can tell you which textures are standard ET textures, and which are custom textures.
This way, it becomes easy to determine which textures you need to supply in your pk3 file and you won’t forget textures!

Now, so far I have managed to extract the textures from the BSP file, but there is one problem:
It does not list the actual ‘image texture files’, but instead it lists the shaders!

So far example, if you happened to use the textures/alpha/bars_m01 shader in your map:

textures/alpha/bars_m01
{
	cull disable
	nomipmaps
	nopicmip
	surfaceparm nomarks
	surfaceparm alphashadow
	surfaceparm metalsteps
	surfaceparm pointlight
	surfaceparm trans
	implicitMask -
}

My application will tell you that you used textures/alpha/bars_m01. However, I have no way of telling if the actual image file (which you would need to supply in your pk3 assuming this was not a standard texture) is either of these:

  • textures/alpha/bars_m01.jpg
  • textures/alpha/bars_m01.tga
    (It is the .tga one, because the .jpg one doesn’t exist, so I guess that is one way to determine which one you need…)

Another example. Suppose you used the textures/battery/ocean_0 shader. My application will tell you again that you need to supply textures/battery/ocean_0. However, this is not even an image! (There is not even a ‘battery’ directory in the textures directory). Instead, if you look at the shader, it uses two other textures:

  • textures/liquids_sd/seawall_specular.tga
  • textures/liquids_sd/sea_bright_na.tga
textures/battery/ocean_0
{
	q3map_baseshader textures/battery/ocean_base
	cull none
	deformVertexes wave 1317 sin 0 2.5 0 0.15
 	deformVertexes wave 317 sin 0 1.5 0 0.30
	
	{
		map textures/liquids_sd/seawall_specular.tga
		blendFunc GL_ONE GL_ONE
		rgbGen vertex
		tcGen environment
		depthWrite
	}
		
	{ 
		map textures/liquids_sd/sea_bright_na.tga
		blendFunc blend
		rgbGen identity
		alphaGen const 0.8
		tcmod scroll 0.005 0.03
	}
	
}

So… My question really is, is there any way to determine easily what image files a certain shader uses, as these are the files you might need to supply in your pk3…

If I can just determine this, my application could even create the textures folder for you!


(aaa3) #2

well, not so easily, but in my imagination, with file operations its possible and almost-easy… (reads line from bsp/map; inputs text between last / and first space [<-first bug here;P]; tries to open the shader in the appropriate folder, and if it founds a shader then it searches it thorough and reads the appr. line the same way; and from here it does the same when it->: if not founds the shader tries to open the jpg in the appr. folder and if if not founds a jpg then its of tga extension and is not a shader.
idk it might needs some search functionality too[?]. and the lots of parses may take a few seconds so u can forget instant list. but i think its perfectly acceptable to have some delay.)


(kamikazee) #3

Couldn’t you reuse GTKRadiant’s (or DarkRadiant’s for that matter) texture browser in some way? That way, you don’t need to write it from scratch.


(Flippy) #4

I had a quick look at the source for the texturebrowser but unfortunately I don’t know very much about C… I tried looking for the part of the code that manages the “Ctrl+A” (show all textures) and then “U” (hide unused textures), which is basically what I need my program to do, but I couldn’t even find that…
I’m programming this in VB.NET which is not very similar so I’m probably going to have to rewrite it completely anyway…

If I can just find an ‘algorithm’ that guarantees me that I find the correct texture that would be enough.

Right now I had something like this in mind to determine the texture image of a selected texture (let’s call it “textures/test/abc”):

  1. Check if a file “textures/test/abc.tga” OR “abc.jpg” exists. If yes --> I’ve got the texture image.
  2. Find every *.shader file that contains the selected texture (already done).
  3. Search through the shader-block (between the first { and last }) for another “textures/…” occurence.

Now my understanding is that each occurence of “textures/…” in the shader-block is indeed a texture that might need to be supplied with the pk3 file… Is that correct??

For example the shader from battery (ocean_0) I posted above would do this:

  1. The file “textures/battery/ocean_0.jpg” or .tga does not exist.
  2. battery.shader file found
  3. Inside battery.shader, the “ocean_0” block is ‘selected’:
textures/battery/ocean_0
{
	q3map_baseshader textures/battery/ocean_base
	cull none
	deformVertexes wave 1317 sin 0 2.5 0 0.15
 	deformVertexes wave 317 sin 0 1.5 0 0.30
	
	{
		map textures/liquids_sd/seawall_specular.tga
		blendFunc GL_ONE GL_ONE
		rgbGen vertex
		tcGen environment
		depthWrite
	}
		
	{ 
		map textures/liquids_sd/sea_bright_na.tga
		blendFunc blend
		rgbGen identity
		alphaGen const 0.8
		tcmod scroll 0.005 0.03
	}
	
}

And a search for “textures/…” yields:

  • textures/battery/ocean_base
  • textures/liquids_sd/seawall_specular.tga
  • textures/liquids_sd/sea_bright_na.tga

The first occurrence does not end in an extension so I could run the same algorithm again for that…
The second and third occurrences are the textures I need.

Now, however I’m not sure if you even need to supply these two textures in your pk3… Are they not compiled into your map maybe? I really haven’t got a clue so I need some more info on this…


(Wezelkrozum) #5

All textures you see in the level when playing it in wolfenstein ET are in your pk3. Else they can’t be displayed and change into an orange/black box.

What you see in this shader (textures/battery/ocean_0) is that only the seawall_specular.tga and sea_bright_na.tga are shown ingame. The ocean_0 texture is only shown in gtkradiant which you won’t see in the game. So you don’t need that texture.

However a shader with the “implicitMask -” command in it will show the texture without setting out a path to the texture itself. Lets say this is the shaderfile:


textures/battery/ocean_0
{
	cull disable
	nomipmaps
	nopicmip
	surfaceparm nomarks
	surfaceparm alphashadow
	surfaceparm metalsteps
	surfaceparm pointlight
	surfaceparm trans
	implicitMask -
}

Here the texture textures/battery/ocean_0 is shown ingame.
But when there are subcommands in the shader ( which are between the “{ }” ) it doesn’t show the texture of the shadername but the texturepath which was set between those “{ }”.

Sorry It’s a bit complex but I can’t tell it easier:)


(Flippy) #6

Alright. My understanding now is this:

  • If there is no shader for a texture name, I can assume it is either ‘texturename.jpg’ or ‘texturename.tga’.

  • If there is a shader and it explicitly contains “ImplicitMask -” then I can also assume it is either ‘texturename.jpg’ or ‘texturename.tga’.

  • If there is a shader and it does NOT contain “ImplicitMask -” then I need to look for a different texture somewhere in that shader (in the ‘subcommands’ between { })

Is that correct?

What about the following shader?

textures/test/abc
{
    surfaceparm metalsteps
}

Is this not a valid shader? It does have a shader, it does not contain “ImplicitMask -” and it has no subcommands. So I will not be able to find a texture for it…
(I realize the texture should be textures/test/abc.jpg or abc.tga, but obviously something is wrong with my reasoning? :stuck_out_tongue: )


(Wezelkrozum) #7

oh shit. I told wrong. Here we go again:
Before I’m going to explain here are 2 type textures to avoid problems:


textures/mapname/texturename     (this is the main-texture)
{
       some commands

       {
                map textures/mapname/texturename           (this is a sub-texture)
                commands for fx's
       }
}

There are 2 types:

  1. A shader without a sub-texture which will show you the main-texture ingame.
  2. A shader with sub-textures which will only show you the sub-textures.

So it’s really simple.
When there are no sub-textures in the shader the maintexture will be displayed and you will only need the main-texture in your pk3file. When there are sub-textures in the shader the maintexture won’t be displayed and you will need only the sub-textures in your pk3file.

(EDITed)


(Flippy) #8

Shouldn’t that be: “when there ARE sub-textures in the shader the main texture will NOT be displayed”?
And when the are NO sub-textures the main texture will be displayed.

Now you say there are NO sub textures, so the main texture must be displayed right?


(Flippy) #9

I think I got most of it worked out now… When I select a ‘multi-stage’ shader I can generate the list of each texture image.

Now one more question:
Is it possible that one shader occurs in multiple shader FILES?

For example,
This in “scripts/shader1.shader”:

textures/test/abc
{ 
   bla
}

And the exact same in “scripts/shader2.shader”:

textures/test/abc
{
   bla
}

Is that possible?


(Flippy) #10

Well, I’ve assumed that it is possible after finding a texture that has this (bunker_sd/girder02 I believe)…

Here’s two new screenshots… I feel this is almost ready for a beta release :slight_smile:

Showing the new ‘Shader Information’ window accessed by clicking the “View Shader Info” button:

Showing the entire list of each used image, accessed by clicking the “View All Images” button:


(Takes about 3 seconds to generate, not bad!)

I still cannot be 100% sure that it actually finds all the textures, but it will still come in handy I think!


(-SSF-Sage) #11

Next thing exclude the qer_editorimage … I see you have common/clip.tga etc.


(Flippy) #12

Yes, true… I can exclude the editorimages pretty easily I think, but the common textures will be a bit harder…

How can I tell when a texture is only used by the editor (other than editorimage textures)? I suppose I could dismiss all the textures in the “common” folder but what if someone is ‘stupid’ enough to put his own textures there…? There must be a better way…


(-SSF-Sage) #13

Well you could exclude every shader with surfaceparm nodraw.


(Flippy) #14

Good idea! And easy to implement too…


(kamikazee) #15

[QUOTE=Flippy;187208]I think I got most of it worked out now… When I select a ‘multi-stage’ shader I can generate the list of each texture image.

Now one more question:
Is it possible that one shader occurs in multiple shader FILES? [/QUOTE]As you noticed yourself, it is.
All pk3 files are taken in consideration and are then sorted on their filename. The last pk3 file in the list wins if there are duplicates.


(ailmanki) #16

how do shader overvwrite each other?

e.g.

a.pk3 - scripts/b.shader
b.pk3 - scripts/a.shader

b.shader and a.shader contain the same shader definiton name…

I suppose et loads first all pk3’s. and then the shaders.
so b.shader would overwrite the same shaders in a.shader? - right?


(Flippy) #17

[QUOTE=ailmanki;187216]how do shader overvwrite each other?

e.g.

a.pk3 - scripts/b.shader
b.pk3 - scripts/a.shader

b.shader and a.shader contain the same shader definiton name…

I suppose et loads first all pk3’s. and then the shaders.
so b.shader would overwrite the same shaders in a.shader? - right?[/QUOTE]

Judging by kamikazee’s post, b.pk3 will be loaded last and thus win, so the shader in a.shader will overwrite the shader in b.shader.


(nUllSkillZ) #18

Very good work.


(kamikazee) #19

[QUOTE=Flippy;187217]Judging by kamikazee’s post, b.pk3 will be loaded last and thus win, so the shader in a.shader will overwrite the shader in b.shader.[/QUOTE]Yes, that is how I understand it to work.

Note that it gets slightly more complex when a.shader and b.shader contain multiple definitions.
Let’s say b.shader contains definitions of textures/me/foo and textures/me/bar. The other file, a.shader, contains textures/me/foo and textures/me/baz.

If you package the shaders as you did before, ET will see textures/me/foo, textures/me/bar and textures/me/baz. The a.shader file will suply the final version of textures/me/foo because it is packaged in b.pk3.

Be welcome to verify this though, because I could have forgotten about some details.