I have been thinking of FS again for the first time in a long time, and I have given thought to my once great nemesis, the materials system. I think I may have come up with a way to implement it that will require no (significant) POF format changes, and could yet allow for the level of flexibility that we need. what I have come up with is on a fundamental level very similar to
a suggestion made by The E about a year ago. I had some significant opposition to some of his choices, namely the use of hard coded texture types, lack of fallback mechanisms, and lack of multi-pass material support to name a few, but the basic architecture he suggests has merit. I think I have thought up a way to define the components I think are fundamentally important yet maintain much of the ease of implementation that The E's submission had. the critical impasse between a singular materials table and requiring a material chunk in the POF and the texture replacing one The E described comes down to how do you pass material parameters to the material. the answer is in the fact that texture names are saved as simply a string, a string can have any value, and as such we could have specaly formatted texture names, that rather than loading a set of textures and getting assigned a default material, it could list a material (<-The E's idea) and all of it's parameters (<- my idea).
how this would work in practice, would be in the POF where currently you would have something like
fighter01a
instead you could have something like
metal(fighter01a, fighter01a-glowystuff, 4.0, ship.engine_output)
which would load the metal material, passing the parameters to the material which would load textures and set uniforms based on those parameters
a sample of what a material would look like is as such:
#parameters
$string: diffuse_texture
$string: glow_texture
$number: rate
$variable: attached_to
#end_parameters
;; this defines what inputs this material is expecting,
;; in this case 4 variables named diffuse_texture, glow_texture, rate, and attached_too
;; the first two variables are texture names, the third is a constant,
;; and the final one is the name of a game variable
#textures
$texture:
+name: diffuse
+file: {diffuse_texture}
$texture:
+name: shine
+file: {diffuse_texture}_shine
$texture:
+name: detail
+file: noise
$texture:
+name: glow
+file: {diffuse_texture}_shine
#end_textures
;; this section here defines what textures are used and what handle they are to be referred to by further in the material and within the shaders
;; note that even though only 2 parameters pertain to texture file names
;; this material actually uses 4 one of which is not based on a parameter at all
;; parameters are purpose agnostic and treated as constants throughout the material specification
;; theoretically this could be a place to define dynamic textures (RTT), predefined game textures, or perhaps another material could be referenced
#uniforms
$uniform:
+name: pulse_rate
+value: rate
$uniform:
+name: subsystem
+value: attached_to
#end_uniforms
;; this defines the material specific uniforms name is what they would be referred to in the vertex shader
;; value is what they would be set to
;; this is the part I am least happy with,
;; I think scripting could be brought to great effect here
#render_set
;; this starts a render set, a renderset is simply a set of rendering passes that make up the material
;; there is more than one of them so if the first one fails it has fallback effects that are
;; less resource intensive or at least can run on lower level hardware
$detail: 3 5
;; this marks this material as only being supported when the game's texture detail is 3, 4 or 5 (out of 5)
;; this is optional will default to all levels
$lod: 0 2
;; marks this material as only being applicable when on LOD 0, 1, and 2
;; this is optional will default to all levels
$pass:
;; here we finally have a pass definition
+textures: ( "diffuse" "shine" "detail" )
;;the textures used in this pass
+vertex_shader: really_cool_vertex_shader
+fragment_shader: really_cool_fragment_shader
;; these should be obvious
+alpha_mode: none
;; here we set alpha mode to none, there are a plethora of other possible settings that could be added here but I won't go into them right now
$pass:
;; second pass,
+textures: ( "glow" )
+vertex_shader: another_really_cool_vertex_shader
+fragment_shader: another_really_cool_fragment_shader
+alpha_mode: (add_lighting&fog:subtract) (add_lighting:add) (fog:interp) none
;; this pass will do different things depending on the situation
;; if this is an additional lighting pass and fog is enabled it will use subtractive alpha
;; if it is just an additive lighting pass, it will use additive alpha
;; if it is just fogging, then this pass will draw with the interpalation alpha
;; finaly if none of the other cases catch it will not use any sort of allpha effect
#end_render_set
;;that is the end of the first render set
;; now it's on to the second
#render_set
$pass:
+vertex_shader: less_cool_vertex_shader
+fragment_shader: less_cool_fragment_shader
+alpha_mode: none
$lighting:
+alpha_mode: add
#end_render_set
;; this set would be used if the above render set could not be used for some reason,
;; be it insuffichent hardware support, or detail settings mis matched, or any other such criteria
#render_set
$import: fallback_diffuse({$diffuse_texture})
#end_render_set
;; final render set imports another material
;; an import can happen in any renderset
;; it just so happens that it would be particularly useful for handeling fallbacks
;; if all else fails the default material will be attempted useing the defined textures
;; for diffuse, glow, shine, normal in the order that they are defined in the texture section
;; actualy it might be better if it just errors out so the problem actualy gets fixed
the two parts that still need work are how to handle render conditions (like what lighting pass you are on or if fog is enabled or something else that is slipping my mind) and how to handle the passing of game variables to the shader. Right now the first problem is handled awkwardly and the second really I don't think would work well.