[SOLVED][FTE]Retrieve entity shader in CSQC

Discuss CSQC related programming.
Post Reply
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

[SOLVED][FTE]Retrieve entity shader in CSQC

Post by toneddu2000 »

Does anyone know if it's possible to retrieve an entity shader ingame so it can be stored in a var and then re-applied via .forceshader()?
Because I took a look at fte csqc defs and it talks about

Code: Select all

void(entity e, string skinfilename, optional string skindata) setcustomskin = #376; /* Part of FTE_QC_CUSTOMSKINS
		Sets an entity's skin overrides to a new skin object. Releases the entities old skin (refcounted). */

float(string skinfilename, optional string skindata) loadcustomskin = #377; /*
		Creates a new skin object and returns it. These are custom per-entity surface->shader lookups. The skinfilename/data should be in .skin format:
		surfacename,shadername - makes the named surface use the named shader (legacy format for compat with q3)
		replace "surfacename" "shadername" - non-legacy equivalent.
		qwskin "foo" - use an unmodified quakeworld player skin (including crop+repalette rules)
		q1lower 0xff0000 - specify an override for the entity's lower colour, in this case to red
		q1upper 0x0000ff - specify an override for the entity's lower colour, in this case to blue
		compose "surfacename" "shader" "imagename@x,y:w,h$s,t,s2,t2?r,g,b,a" - compose a skin texture from multiple images.
		  The texture is determined to be sufficient to hold the first named image, additional images can be named as extra tokens on the same line.
		  Use a + at the end of the line to continue reading image tokens from the next line also, the named shader must use 'map $diffuse' to read the composed texture (compatible with the defaultskin shader). Must be matched with a releasecustomskin call later, and is pointless without applycustomskin. */

void(entity e, float skinobj) applycustomskin = #378; /*
		Updates the entity's custom skin (refcounted). */

void(float skinobj) releasecustomskin = #379; /*
		Lets the engine know that the skin will no longer be needed. Thanks to refcounting any ents with the skin already applied will retain their skin until later changed. It is valid to destroy a skin just after applying it to an ent in the same function that it was created in, as the skin will only be destroyed once its refcount rops to 0. */
But I couldn't find on the net any info about creating a .skin file

Thanks a bunch for any help!
Last edited by toneddu2000 on Sat Nov 16, 2019 12:41 pm, edited 1 time in total.
Meadow Fun!! - my first commercial game, made with FTEQW game engine
Shpuld
Posts: 106
Joined: Sat Feb 13, 2010 1:48 pm

Re: [FTE]Retrieve entity shader in CSQC

Post by Shpuld »

Considering that it's possible for an entity to be using multiple shaders, this sounds like a difficult thing to achieve. I'd approach the problem by maybe having custom fields where you can manually set the "default" shader for that entity, or just have default shaders for different types of entities stored in constants or something, might not be applicable for your case though.

What I would like to see would be being able to remove forced shader without having to actually know the originals, the engine should already know it.


EDIT: Actually that seems to work, if you do self.forceshader = 0; it seems to use the original shader again
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: [FTE]Retrieve entity shader in CSQC

Post by toneddu2000 »

self.forceshader = 0; works like a charm, even on multi material entitities! incredible, it was so simple!

thanks a lot Shpuld, you saved me LOTS of head-walls interaction! :mrgreen:
Meadow Fun!! - my first commercial game, made with FTEQW game engine
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: [SOLVED][FTE]Retrieve entity shader in CSQC

Post by Spike »

pseudo code:

Code: Select all

if (ent.skin >= r_globalskin_first && ent.skin < r_globalskin_first+r_globalskin_count)
    material = findmaterialname_formatted("gfx/skin%d.lmp", ent.skin);
else
    material = ent.model.surface[SURFACEID].material[bound(0, ent.skin, ent.model.maxskins-1)];
if (ent.customskin && ent.customskin.surface[SURFACEID])
    material = ent.customskin.surface[SURFACEID].newmaterial;

shader = material.shader;
if (ent.forceshader)
    shader = ent.forceshader;
shader = shader.remappedshader;
if (rtlightmode)
    shader = shader.altmode[rtlightmode];
fte's concept of a material is a bit weird - they're kinda bolted on to the side of the shader parsing, but where a shader may be forced/remapped/specialised, the material's textures are not so easily changed. This allows rtlights to use the same shader and yet still use the correct textures for each surface.
this also means that you can use the same forced shader to affect multiple models while handling their diffuse texture somewhat generically, or whatever.

custom skins are not necessarily tied to any single specific model, but rather a single skin can be used on multiple different models, affecting only each named surface. surfaces not named will be unaffected. whether this is useful to you or not I've no idea. note that there is a small cost that scales with the number of surfaces named in the skin so don't go too crazy with it.
skin objects can also control geomsets (ie only one set of surfaces within each grouping will be shown). careful handling can allow you to support rpg-style hairstyle+items+etc customisations in a moderately generic way (geomsets controlling the hairstyle type, with materials changing its colour etc).

And yeah, if you want to undo setting the forceshader field then you can just reset it to its default value, ie ent.forceshader=0;
This is also true for custom skins - applycustomskin(ent, 0); which is basically the same thing, just with refcounting and the actual field hidden from view (for some reason).
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: [SOLVED][FTE]Retrieve entity shader in CSQC

Post by toneddu2000 »

thanks Spike for the explanation, but still I don't understand how skin format is structured, could you please post a .skin example? And which name should I use? I saw that SteelStorm (2011, Darkplaces engine) uses the format foo.dpm_0.skin. Steel Storm used dpm model format, but it's the same. Is it right the nomenclature?

Thanks
Meadow Fun!! - my first commercial game, made with FTEQW game engine
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: [SOLVED][FTE]Retrieve entity shader in CSQC

Post by Spike »

you pasted it yourself, loadcustomskin's documentation specifies the accepted .skin file lines (ie: replace "surfacename" "replacementmaterial" one line per surface you want to override).
Also, use those optional args (and give an empy skinfilename) to avoid using actual files, generate that data at runtime if you want.

the foo.iqm_0.skin etc files are automatically parsed by the model loader (in both fte and dp) by just concatenating it onto the end of the model's name, and thus are limited to just replacements. Its probably worth noting that many model formats(md3/iqm/dpm) don't support numbered skins (like those used for progs/armor.mdl) but this gives you a way to define them without any extra code.
Steelstorm is a viable example I suppose, Xonotic also has a number of similar overrides.
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: [SOLVED][FTE]Retrieve entity shader in CSQC

Post by toneddu2000 »

Yeah, thanks Spike I only tried the foo.iqm_0.skin replacement, probably that's why it didn't work. I'll try to use custom skin and see if it works, I'll try also optional args to create skins on the fly
Thanks both for you help!
Meadow Fun!! - my first commercial game, made with FTEQW game engine
Post Reply