Added several new shader-parameter keywords, esp for lights and materials

This commit is contained in:
Josh Yelon 2008-01-25 03:30:56 +00:00
parent 151d8c2814
commit aee0c904ca
3 changed files with 445 additions and 93 deletions

View File

@ -40,6 +40,10 @@
#include "graphicsOutput.h"
#include "texturePool.h"
#include "geomMunger.h"
#include "ambientLight.h"
#include "directionalLight.h"
#include "pointLight.h"
#include "spotLight.h"
#include <algorithm>
#include <limits.h>
@ -825,6 +829,7 @@ fetch_specified_value(Shader::ShaderMatSpec &spec, bool altered) {
const LMatrix4f *val2;
static LMatrix4f t1;
static LMatrix4f t2;
LVecBase3f v;
switch(spec._func) {
case Shader::SMF_compose:
@ -846,6 +851,38 @@ fetch_specified_value(Shader::ShaderMatSpec &spec, bool altered) {
val1 = fetch_specified_part(spec._part[0], spec._arg[0], t1);
acc.multiply(*val1, spec._cache);
return &acc;
case Shader::SMF_transform_dlight:
if (altered) {
spec._cache = *fetch_specified_part(spec._part[0], spec._arg[0], t1);
}
val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2);
acc = spec._cache;
v = val2->xform_vec(spec._cache.get_row3(2));
v.normalize();
acc.set_row(2, v);
v = val2->xform_vec(spec._cache.get_row3(3));
v.normalize();
acc.set_row(3, v);
return &acc;
case Shader::SMF_transform_plight:
if (altered) {
spec._cache = *fetch_specified_part(spec._part[0], spec._arg[0], t1);
}
val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2);
acc = spec._cache;
acc.set_row(2, val2->xform_point(spec._cache.get_row3(2)));
return &acc;
case Shader::SMF_transform_slight:
if (altered) {
spec._cache = *fetch_specified_part(spec._part[0], spec._arg[0], t1);
}
val2 = fetch_specified_part(spec._part[1], spec._arg[1], t2);
acc = spec._cache;
acc.set_row(2, val2->xform_point(spec._cache.get_row3(2)));
v = val2->xform_vec(spec._cache.get_row3(3));
v.normalize();
acc.set_row(3, v);
return &acc;
case Shader::SMF_first:
return fetch_specified_part(spec._part[0], spec._arg[0], t1);
default:
@ -885,6 +922,101 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4f
0.0);
return &t;
}
case Shader::SMO_attr_material: {
// Material matrix contains AMBIENT, DIFFUSE, EMISSION, SPECULAR+SHININESS
if (_target._material->is_off()) {
t = LMatrix4f(1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0);
return &t;
}
Material *m = _target._material->get_material();
LVecBase4f const &amb = m->get_ambient();
LVecBase4f const &dif = m->get_diffuse();
LVecBase4f const &emm = m->get_emission();
LVecBase4f spc = m->get_specular();
spc[3] = m->get_shininess();
t = LMatrix4f(amb[0],amb[1],amb[2],amb[3],
dif[0],dif[1],dif[2],dif[3],
emm[0],emm[1],emm[2],emm[3],
spc[0],spc[1],spc[2],spc[3]);
return &t;
}
case Shader::SMO_attr_color: {
if (_target._color->get_color_type() != ColorAttrib::T_flat) {
return &LMatrix4f::ones_mat();
}
LVecBase4f c = _target._color->get_color();
t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]);
return &t;
}
case Shader::SMO_alight_x: {
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
nassertr(!np.is_empty(), &LMatrix4f::zeros_mat());
AmbientLight *lt;
DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat());
Colorf const &c = lt->get_color();
t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]);
return &t;
}
case Shader::SMO_satten_x: {
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
nassertr(!np.is_empty(), &LMatrix4f::ones_mat());
Spotlight *lt;
DCAST_INTO_R(lt, np.node(), &LMatrix4f::ones_mat());
LVecBase3f const &a = lt->get_attenuation();
float x = lt->get_exponent();
t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,a[0],a[1],a[2],x);
return &t;
}
case Shader::SMO_dlight_x: {
// The dlight matrix contains COLOR, SPECULAR, DIRECTION, PSEUDOHALFANGLE
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
nassertr(!np.is_empty(), &LMatrix4f::zeros_mat());
DirectionalLight *lt;
DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat());
Colorf const &c = lt->get_color();
Colorf const &s = lt->get_specular_color();
t = np.get_net_transform()->get_mat() *
get_scene()->get_world_transform()->get_mat();
LVecBase3f d = -(t.xform_vec(lt->get_direction()));
d.normalize();
LVecBase3f h = d + LVecBase3f(0,-1,0);
h.normalize();
t = LMatrix4f(c[0],c[1],c[2],c[3],s[0],s[1],s[2],c[3],d[0],d[1],d[2],0,h[0],h[1],h[2],0);
return &t;
}
case Shader::SMO_plight_x: {
// The plight matrix contains COLOR, SPECULAR, POINT, ATTENUATION
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
nassertr(!np.is_empty(), &LMatrix4f::ones_mat());
PointLight *lt;
DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat());
Colorf const &c = lt->get_color();
Colorf const &s = lt->get_specular_color();
t = np.get_net_transform()->get_mat() *
get_scene()->get_world_transform()->get_mat();
LVecBase3f p = (t.xform_point(lt->get_point()));
LVecBase3f a = lt->get_attenuation();
t = LMatrix4f(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,a[0],a[1],a[2],0);
return &t;
}
case Shader::SMO_slight_x: {
// The slight matrix contains COLOR, SPECULAR, POINT, DIRECTION
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
nassertr(!np.is_empty(), &LMatrix4f::zeros_mat());
Spotlight *lt;
DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat());
Lens *lens = lt->get_lens();
nassertr(lens != (Lens *)NULL, &LMatrix4f::zeros_mat());
Colorf const &c = lt->get_color();
Colorf const &s = lt->get_specular_color();
float cutoff = cos(deg_2_rad(lens->get_hfov() * 0.5f));
t = np.get_net_transform()->get_mat() *
get_scene()->get_world_transform()->get_mat();
LVecBase3f p = t.xform_point(lens->get_nodal_point());
LVecBase3f d = -(t.xform_vec(lens->get_view_vector()));
t = LMatrix4f(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,d[0],d[1],d[2],cutoff);
return &t;
}
case Shader::SMO_mat_constant_x: {
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
nassertr(!np.is_empty(), &LMatrix4f::ident_mat());

View File

@ -20,6 +20,8 @@
#include "shader.h"
#include "preparedGraphicsObjects.h"
#include "virtualFileSystem.h"
#include <iostream>
#include <fstream>
#ifdef HAVE_CG
#include "Cg/cg.h"
@ -31,6 +33,7 @@ TypeHandle Shader::_type_handle;
Shader::LoadTable Shader::_load_table;
Shader::MakeTable Shader::_make_table;
Shader::ShaderCaps Shader::_default_caps;
int Shader::_shaders_generated;
ShaderUtilization Shader::_shader_utilization = SUT_UNSPECIFIED;
////////////////////////////////////////////////////////////////////
@ -188,29 +191,136 @@ cp_errchk_parameter_sampler(ShaderArgInfo &p)
}
////////////////////////////////////////////////////////////////////
// Function: Shader::cp_parse_trans_clause
// Function: Shader::cp_parse_eol
// Access: Public
// Description: Parses a single clause of a "trans" parameter.
// Description: Make sure the next thing on the word list is EOL
////////////////////////////////////////////////////////////////////
bool Shader::
cp_parse_trans_clause(ShaderArgInfo &p, ShaderMatSpec &spec,
int part, const vector_string &pieces,
int &next, ShaderMatInput ofop, ShaderMatInput op) {
if (pieces[next+1]=="of") {
if (pieces[next+2]=="") {
cp_report_error(p, "'of' should be followed by a name");
return false;
}
spec._part[part] = ofop;
spec._arg[part] = InternalName::make(pieces[next+2]);
next += 3;
return true;
} else {
spec._part[part] = op;
spec._arg[part] = NULL;
next += 1;
return true;
cp_parse_eol(ShaderArgInfo &p, vector_string &words, int &next) {
if (words[next] != "") {
cp_report_error(p, "Too many words in parameter");
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::cp_parse_delimiter
// Access: Public
// Description: Pop a delimiter ('to' or 'rel') from the word list.
////////////////////////////////////////////////////////////////////
bool Shader::
cp_parse_delimiter(ShaderArgInfo &p, vector_string &words, int &next) {
if ((words[next] != "to")&&(words[next] != "rel")) {
cp_report_error(p, "Keyword 'to' or 'rel' expected");
return false;
}
next += 1;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::cp_parse_non_delimiter
// Access: Public
// Description: Pop a non-delimiter word from the word list.
// Delimiters are 'to' and 'rel.'
////////////////////////////////////////////////////////////////////
string Shader::
cp_parse_non_delimiter(vector_string &words, int &next) {
const string &nword = words[next];
if ((nword == "")||(nword == "to")||(nword == "rel")) {
return "";
}
next += 1;
return nword;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::cp_parse_coord_sys
// Access: Public
// Description: Convert a single-word coordinate system name into
// a PART/ARG of a ShaderMatSpec.
////////////////////////////////////////////////////////////////////
bool Shader::
cp_parse_coord_sys(ShaderArgInfo &p,
vector_string &pieces, int &next,
ShaderMatSpec &bind, bool fromflag) {
string word1 = cp_parse_non_delimiter(pieces, next);
string word2 = cp_parse_non_delimiter(pieces, next);
ShaderMatInput from_single;
ShaderMatInput from_double;
ShaderMatInput to_single;
ShaderMatInput to_double;
if (word1 == "") {
cp_report_error(p, "Could not parse coordinate system name");
return false;
} else if (word1 == "world") {
from_single = SMO_world_to_view;
from_double = SMO_INVALID;
to_single = SMO_view_to_world;
to_double = SMO_INVALID;
} else if (word1 == "model") {
from_single = SMO_model_to_view;
from_double = SMO_view_x_to_view;
to_single = SMO_view_to_model;
to_double = SMO_view_to_view_x;
} else if (word1 == "clip") {
from_single = SMO_clip_to_view;
from_double = SMO_clip_x_to_view;
to_single = SMO_view_to_clip;
to_double = SMO_view_to_clip_x;
} else if (word1 == "view") {
from_single = SMO_identity;
from_double = SMO_view_x_to_view;
to_single = SMO_identity;
to_double = SMO_view_to_view_x;
} else if (word1 == "apiview") {
from_single = SMO_apiview_to_view;
from_double = SMO_apiview_x_to_view;
to_single = SMO_view_to_apiview;
to_double = SMO_view_to_apiview_x;
} else if (word1 == "apiclip") {
from_single = SMO_apiclip_to_view;
from_double = SMO_apiclip_x_to_view;
to_single = SMO_view_to_apiclip;
to_double = SMO_view_to_apiclip_x;
} else {
from_single = SMO_view_x_to_view;
from_double = SMO_view_x_to_view;
to_single = SMO_view_to_view_x;
to_double = SMO_view_to_view_x;
word2 = word1;
}
if (fromflag) {
if (word2 == "") {
bind._part[0] = from_single;
bind._arg[0] = NULL;
} else {
if (from_double == SMO_INVALID) {
cp_report_error(p, "Could not parse coordinate system name");
return false;
}
bind._part[0] = from_double;
bind._arg[0] = InternalName::make(word2);
}
} else {
if (word2 == "") {
bind._part[1] = to_single;
bind._arg[1] = NULL;
} else {
if (to_double == SMO_INVALID) {
cp_report_error(p, "Could not parse coordinate system name");
return false;
}
bind._part[1] = to_double;
bind._arg[1] = InternalName::make(word2);
}
}
return true;
}
////////////////////////////////////////////////////////////////////
@ -468,76 +578,16 @@ compile_parameter(const ShaderArgId &arg_id,
if (!cp_errchk_parameter_float(p, 4, 4)) return false;
}
// Parse the first half of the clause.
bool ok = true;
if ((pieces[next]=="")||(pieces[next]=="of")||(pieces[next]=="to")){
cp_report_error(p, "argument missing");
return false;
} else if (pieces[next] == "world") {
bind._part[0] = SMO_world_to_view;
bind._arg[0] = NULL;
next += 1;
} else if (pieces[next] == "model") {
ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_view_x_to_view, SMO_model_to_view);
} else if (pieces[next] == "clip") {
ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_clip_x_to_view, SMO_clip_to_view);
} else if (pieces[next] == "view") {
ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_view_x_to_view, SMO_identity);
} else if (pieces[next] == "apiview") {
ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_apiview_x_to_view, SMO_apiview_to_view);
} else if (pieces[next] == "apiclip") {
ok &= cp_parse_trans_clause(p, bind, 0, pieces, next, SMO_apiclip_x_to_view, SMO_apiclip_to_view);
} else {
bind._part[0] = SMO_view_x_to_view;
bind._arg[0] = InternalName::make(pieces[next]);
next += 1;
}
// Check for errors in the first clause.
if (!ok) {
if (!cp_parse_coord_sys(p, pieces, next, bind, true)) {
return false;
}
// Check for syntactic well-formed-ness.
if (pieces[next] != "to") {
cp_report_error(p, "keyword 'to' expected");
return false;
} else {
next += 1;
}
// Parse the second half of the clause.
if ((pieces[next]=="")||(pieces[next]=="of")||(pieces[next]=="to")){
cp_report_error(p, "argument missing");
return false;
} else if (pieces[next] == "world") {
bind._part[1] = SMO_view_to_world;
bind._arg[1] = NULL;
next += 1;
} else if (pieces[next] == "model") {
ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_view_x, SMO_view_to_model);
} else if (pieces[next] == "clip") {
ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_clip_x, SMO_view_to_clip);
} else if (pieces[next] == "view") {
ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_view_x, SMO_identity);
} else if (pieces[next] == "apiview") {
ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_apiview_x, SMO_view_to_apiview);
} else if (pieces[next] == "apiclip") {
ok &= cp_parse_trans_clause(p, bind, 1, pieces, next, SMO_view_to_apiclip_x, SMO_view_to_apiclip);
} else {
bind._part[1] = SMO_view_to_view_x;
bind._arg[1] = InternalName::make(pieces[next]);
next += 1;
}
// Check for errors in the second clause.
if (!ok) {
if (!cp_parse_delimiter(p, pieces, next)) {
return false;
}
// Check for syntactic well-formed-ness.
if (pieces[next] != "") {
cp_report_error(p, "end of line expected");
if (!cp_parse_coord_sys(p, pieces, next, bind, false)) {
return false;
}
if (!cp_parse_eol(p, pieces, next)) {
return false;
}
@ -546,6 +596,145 @@ compile_parameter(const ShaderArgId &arg_id,
return true;
}
// Special parameter: attr_material or attr_color
if (pieces[0] == "attr") {
if ((!cp_errchk_parameter_words(p,2)) ||
(!cp_errchk_parameter_in(p)) ||
(!cp_errchk_parameter_uniform(p))) {
return false;
}
ShaderMatSpec bind;
if (pieces[1] == "material") {
if (!cp_errchk_parameter_float(p,16,16)) {
return false;
}
bind._id = arg_id;
bind._piece = SMP_transpose;
bind._func = SMF_first;
bind._part[0] = SMO_attr_material;
bind._arg[0] = NULL;
bind._part[1] = SMO_identity;
bind._arg[1] = NULL;
} else if (pieces[1] == "color") {
if (!cp_errchk_parameter_float(p,3,4)) {
return false;
}
bind._id = arg_id;
bind._piece = SMP_row3;
bind._func = SMF_first;
bind._part[0] = SMO_attr_color;
bind._arg[0] = NULL;
bind._part[1] = SMO_identity;
bind._arg[1] = NULL;
} else {
cp_report_error(p,"Unknown attr parameter.");
return false;
}
cp_optimize_mat_spec(bind);
_mat_spec.push_back(bind);
return true;
}
if (pieces[0] == "color") {
if ((!cp_errchk_parameter_words(p,1)) ||
(!cp_errchk_parameter_in(p)) ||
(!cp_errchk_parameter_uniform(p))) {
return false;
}
ShaderMatSpec bind;
cp_optimize_mat_spec(bind);
_mat_spec.push_back(bind);
return true;
}
// Keywords to access light properties.
if (pieces[0] == "alight") {
if ((!cp_errchk_parameter_words(p,2))||
(!cp_errchk_parameter_in(p)) ||
(!cp_errchk_parameter_uniform(p))||
(!cp_errchk_parameter_float(p,3,4))) {
return false;
}
ShaderMatSpec bind;
bind._id = arg_id;
bind._piece = SMP_row3;
bind._func = SMF_first;
bind._part[0] = SMO_alight_x;
bind._arg[0] = InternalName::make(pieces[1]);
bind._part[1] = SMO_identity;
bind._arg[1] = NULL;
cp_optimize_mat_spec(bind);
_mat_spec.push_back(bind);
return true;
}
if (pieces[0] == "satten") {
if ((!cp_errchk_parameter_words(p,2))||
(!cp_errchk_parameter_in(p)) ||
(!cp_errchk_parameter_uniform(p))||
(!cp_errchk_parameter_float(p,4,4))) {
return false;
}
ShaderMatSpec bind;
bind._id = arg_id;
bind._piece = SMP_row3;
bind._func = SMF_first;
bind._part[0] = SMO_satten_x;
bind._arg[0] = InternalName::make(pieces[1]);
bind._part[1] = SMO_identity;
bind._arg[1] = NULL;
cp_optimize_mat_spec(bind);
_mat_spec.push_back(bind);
return true;
}
if ((pieces[0]=="dlight")||(pieces[0]=="plight")||(pieces[0]=="slight")) {
if ((!cp_errchk_parameter_in(p)) ||
(!cp_errchk_parameter_uniform(p))||
(!cp_errchk_parameter_float(p,16,16))) {
return false;
}
ShaderMatSpec bind;
bind._id = arg_id;
bind._piece = SMP_transpose;
int next = 1;
pieces.push_back("");
if (pieces[next] == "") {
cp_report_error(p, "Light name expected");
return false;
}
if (pieces[0] == "dlight") {
bind._func = SMF_transform_dlight;
bind._part[0] = SMO_dlight_x;
} else if (pieces[0] == "plight") {
bind._func = SMF_transform_plight;
bind._part[0] = SMO_plight_x;
} else if (pieces[0] == "slight") {
bind._func = SMF_transform_slight;
bind._part[0] = SMO_slight_x;
}
bind._arg[0] = InternalName::make(pieces[next]);
next += 1;
if (!cp_parse_delimiter(p, pieces, next)) {
return false;
}
if (!cp_parse_coord_sys(p, pieces, next, bind, false)) {
return false;
}
if (!cp_parse_eol(p, pieces, next)) {
return false;
}
cp_optimize_mat_spec(bind);
_mat_spec.push_back(bind);
return true;
}
// Keywords to access unusual parameters.
if (pieces[0] == "sys") {
@ -1253,6 +1442,17 @@ make(const string &body) {
}
PT(Shader) result = new Shader("created-shader", body);
_make_table[body] = result;
if (dump_generated_shaders) {
ostringstream fns;
int index = _shaders_generated ++;
fns << "genshader" << index;
string fn = fns.str();
gobj_cat.warning() << "Dumping shader: " << fn << "\n";
ofstream s;
s.open(fn.c_str());
s << body;
s.close();
}
return result;
}

View File

@ -72,6 +72,15 @@ public:
SMO_pixel_size,
SMO_card_center,
SMO_attr_material,
SMO_attr_color,
SMO_alight_x,
SMO_dlight_x,
SMO_plight_x,
SMO_slight_x,
SMO_satten_x,
SMO_mat_constant_x,
SMO_vec_constant_x,
@ -101,6 +110,12 @@ public:
SMO_apiclip_x_to_view,
SMO_view_to_apiclip_x,
SMO_light_vector,
SMO_light_color,
SMO_light_spec,
SMO_INVALID
};
enum ShaderArgType {
@ -139,11 +154,14 @@ public:
enum ShaderBug {
SBUG_ati_draw_buffers,
};
enum ShaderMatFunc {
SMF_compose,
SMF_compose_cache_first,
SMF_compose_cache_second,
SMF_transform_dlight,
SMF_transform_plight,
SMF_transform_slight,
SMF_first,
};
@ -215,13 +233,14 @@ public:
bool cp_errchk_parameter_uniform(ShaderArgInfo &arg);
bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi);
bool cp_errchk_parameter_sampler(ShaderArgInfo &arg);
bool cp_parse_trans_clause(ShaderArgInfo &arg,
ShaderMatSpec &spec,
int part,
const vector_string &pieces,
int &next,
ShaderMatInput ofop,
ShaderMatInput op);
bool cp_parse_eol(ShaderArgInfo &arg,
vector_string &pieces, int &next);
bool cp_parse_delimiter(ShaderArgInfo &arg,
vector_string &pieces, int &next);
string cp_parse_non_delimiter(vector_string &pieces, int &next);
bool cp_parse_coord_sys(ShaderArgInfo &arg,
vector_string &pieces, int &next,
ShaderMatSpec &spec, bool fromflag);
void cp_optimize_mat_spec(ShaderMatSpec &spec);
bool compile_parameter(const ShaderArgId &arg_id,
@ -273,6 +292,7 @@ public:
static ShaderCaps _default_caps;
static ShaderUtilization _shader_utilization;
static int _shaders_generated;
typedef pmap < Filename , Shader * > LoadTable;
typedef pmap < string , Shader * > MakeTable;