Add support for k_time / osg_FrameTime inputs, and change the Shader Generator not to require a separate texcoord set for every texture in an effort to cut down on register overuse.

This commit is contained in:
rdb 2014-02-10 11:32:06 +00:00
parent 89749133ff
commit 4da840805f
6 changed files with 271 additions and 215 deletions

View File

@ -996,6 +996,16 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4 &
0.0); 0.0);
return &t; return &t;
} }
case Shader::SMO_frame_time: {
PN_stdfloat time = ClockObject::get_global_clock()->get_frame_time();
t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, time, time, time, time);
return &t;
}
case Shader::SMO_frame_delta: {
PN_stdfloat dt = ClockObject::get_global_clock()->get_dt();
t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dt, dt, dt, dt);
return &t;
}
case Shader::SMO_texpad_x: { case Shader::SMO_texpad_x: {
Texture *tex = _target_shader->get_shader_input_texture(name); Texture *tex = _target_shader->get_shader_input_texture(name);
nassertr(tex != 0, &LMatrix4::zeros_mat()); nassertr(tex != 0, &LMatrix4::zeros_mat());

View File

@ -71,14 +71,13 @@ TypeHandle CLP(ShaderContext)::_type_handle;
bool CLP(ShaderContext):: bool CLP(ShaderContext)::
parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, Shader *objShader) { parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, Shader *objShader) {
Shader::ShaderArgInfo p; Shader::ShaderArgInfo p;
p._id = arg_id; p._id = arg_id;
string basename(arg_id._name); string basename(arg_id._name);
// Split it at the underscores. // Split it at the underscores.
vector_string pieces; vector_string pieces;
tokenize(basename, pieces, "_"); tokenize(basename, pieces, "_");
if (pieces[0] == "mstrans") { if (pieces[0] == "mstrans") {
pieces[0] = "trans"; pieces[0] = "trans";
pieces.push_back("to"); pieces.push_back("to");
@ -119,9 +118,9 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, Shader *objSha
pieces.push_back("to"); pieces.push_back("to");
pieces.push_back("clip"); pieces.push_back("clip");
} }
if ((pieces[0] == "mat")||(pieces[0] == "inv")|| if ((pieces[0] == "mat") || (pieces[0] == "inv") ||
(pieces[0] == "tps")||(pieces[0] == "itp")) { (pieces[0] == "tps") || (pieces[0] == "itp")) {
if (!objShader->cp_errchk_parameter_words(p, 2)) { if (!objShader->cp_errchk_parameter_words(p, 2)) {
return false; return false;
} }
@ -138,33 +137,33 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, Shader *objSha
objShader->cp_report_error(p,"unrecognized matrix name"); objShader->cp_report_error(p,"unrecognized matrix name");
return false; return false;
} }
if (trans=="mat") { if (trans == "mat") {
pieces[0] = "trans"; pieces[0] = "trans";
} else if (trans=="inv") { } else if (trans == "inv") {
string t = pieces[1]; string t = pieces[1];
pieces[1] = pieces[3]; pieces[1] = pieces[3];
pieces[3] = t; pieces[3] = t;
} else if (trans=="tps") { } else if (trans == "tps") {
pieces[0] = "tpose"; pieces[0] = "tpose";
} else if (trans=="itp") { } else if (trans == "itp") {
string t = pieces[1]; string t = pieces[1];
pieces[1] = pieces[3]; pieces[1] = pieces[3];
pieces[3] = t; pieces[3] = t;
pieces[0] = "tpose"; pieces[0] = "tpose";
} }
} }
// Implement the transform-matrix generator. // Implement the transform-matrix generator.
if ((pieces[0]=="trans")|| if ((pieces[0] == "trans") ||
(pieces[0]=="tpose")|| (pieces[0] == "tpose") ||
(pieces[0]=="row0")|| (pieces[0] == "row0") ||
(pieces[0]=="row1")|| (pieces[0] == "row1") ||
(pieces[0]=="row2")|| (pieces[0] == "row2") ||
(pieces[0]=="row3")|| (pieces[0] == "row3") ||
(pieces[0]=="col0")|| (pieces[0] == "col0") ||
(pieces[0]=="col1")|| (pieces[0] == "col1") ||
(pieces[0]=="col2")|| (pieces[0] == "col2") ||
(pieces[0]=="col3")) { (pieces[0] == "col3")) {
Shader::ShaderMatSpec bind; Shader::ShaderMatSpec bind;
bind._id = arg_id; bind._id = arg_id;
@ -174,27 +173,26 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, Shader *objSha
pieces.push_back(""); pieces.push_back("");
// Decide whether this is a matrix or vector. // Decide whether this is a matrix or vector.
if (pieces[0]=="trans") bind._piece = Shader::SMP_whole; if (pieces[0] == "trans") bind._piece = Shader::SMP_whole;
else if (pieces[0]=="tpose") bind._piece = Shader::SMP_transpose; else if (pieces[0] == "tpose") bind._piece = Shader::SMP_transpose;
else if (pieces[0]=="row0") bind._piece = Shader::SMP_row0; else if (pieces[0] == "row0") bind._piece = Shader::SMP_row0;
else if (pieces[0]=="row1") bind._piece = Shader::SMP_row1; else if (pieces[0] == "row1") bind._piece = Shader::SMP_row1;
else if (pieces[0]=="row2") bind._piece = Shader::SMP_row2; else if (pieces[0] == "row2") bind._piece = Shader::SMP_row2;
else if (pieces[0]=="row3") bind._piece = Shader::SMP_row3; else if (pieces[0] == "row3") bind._piece = Shader::SMP_row3;
else if (pieces[0]=="col0") bind._piece = Shader::SMP_col0; else if (pieces[0] == "col0") bind._piece = Shader::SMP_col0;
else if (pieces[0]=="col1") bind._piece = Shader::SMP_col1; else if (pieces[0] == "col1") bind._piece = Shader::SMP_col1;
else if (pieces[0]=="col2") bind._piece = Shader::SMP_col2; else if (pieces[0] == "col2") bind._piece = Shader::SMP_col2;
else if (pieces[0]=="col3") bind._piece = Shader::SMP_col3; else if (pieces[0] == "col3") bind._piece = Shader::SMP_col3;
if (!objShader->cp_parse_coord_sys(p, pieces, next, bind, true)) { if (!objShader->cp_parse_coord_sys(p, pieces, next, bind, true)) {
return false; return false;
} }
if (!objShader->cp_parse_delimiter(p, pieces, next)) { if (!objShader->cp_parse_delimiter(p, pieces, next)) {
return false; return false;
} }
if (!objShader->cp_parse_coord_sys(p, pieces, next, bind, false)) { if (!objShader->cp_parse_coord_sys(p, pieces, next, bind, false)) {
return false; return false;
} }
if (!objShader->cp_parse_eol(p, pieces, next)) { if (!objShader->cp_parse_eol(p, pieces, next)) {
return false; return false;
} }
@ -338,7 +336,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
} }
bind._arg[0] = NULL; bind._arg[0] = NULL;
bind._arg[1] = NULL; bind._arg[1] = NULL;
if (matrix_name == "ModelViewProjectionMatrix") { if (matrix_name == "ModelViewProjectionMatrix") {
bind._func = Shader::SMF_compose; bind._func = Shader::SMF_compose;
if (inverse) { if (inverse) {
@ -418,15 +416,14 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
// them as well, to increase compatibility. // them as well, to increase compatibility.
// Other inputs we may support in the future: // Other inputs we may support in the future:
// int osg_FrameNumber // int osg_FrameNumber
// float osg_FrameTime
// float osg_DeltaFrameTime Shader::ShaderMatSpec bind;
bind._id = arg_id;
bind._arg[0] = NULL;
bind._arg[1] = NULL;
if (param_name == "osg_ViewMatrix") { if (param_name == "osg_ViewMatrix") {
Shader::ShaderMatSpec bind;
bind._id = arg_id;
bind._piece = Shader::SMP_whole; bind._piece = Shader::SMP_whole;
bind._arg[0] = NULL;
bind._arg[1] = NULL;
bind._func = Shader::SMF_first; bind._func = Shader::SMF_first;
bind._part[0] = Shader::SMO_world_to_view; bind._part[0] = Shader::SMO_world_to_view;
bind._part[1] = Shader::SMO_identity; bind._part[1] = Shader::SMO_identity;
@ -436,11 +433,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
continue; continue;
} else if (param_name == "osg_InverseViewMatrix") { } else if (param_name == "osg_InverseViewMatrix") {
Shader::ShaderMatSpec bind;
bind._id = arg_id;
bind._piece = Shader::SMP_whole; bind._piece = Shader::SMP_whole;
bind._arg[0] = NULL;
bind._arg[1] = NULL;
bind._func = Shader::SMF_first; bind._func = Shader::SMF_first;
bind._part[0] = Shader::SMO_view_to_world; bind._part[0] = Shader::SMO_view_to_world;
bind._part[1] = Shader::SMO_identity; bind._part[1] = Shader::SMO_identity;
@ -448,6 +441,26 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
bind._dep[1] = Shader::SSD_NONE; bind._dep[1] = Shader::SSD_NONE;
s->_mat_spec.push_back(bind); s->_mat_spec.push_back(bind);
continue; continue;
} else if (param_name == "osg_FrameTime") {
bind._piece = Shader::SMP_row3x1;
bind._func = Shader::SMF_first;
bind._part[0] = Shader::SMO_frame_time;
bind._part[1] = Shader::SMO_identity;
bind._dep[0] = Shader::SSD_general;
bind._dep[1] = Shader::SSD_NONE;
s->_mat_spec.push_back(bind);
continue;
} else if (param_name == "osg_DeltaFrameTime") {
bind._piece = Shader::SMP_row3x1;
bind._func = Shader::SMF_first;
bind._part[0] = Shader::SMO_frame_delta;
bind._part[1] = Shader::SMO_identity;
bind._dep[0] = Shader::SSD_general;
bind._dep[1] = Shader::SSD_NONE;
s->_mat_spec.push_back(bind);
continue;
} }
} }
@ -455,7 +468,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
if (parse_and_set_short_hand_shader_vars(arg_id, s)) { if (parse_and_set_short_hand_shader_vars(arg_id, s)) {
continue; continue;
} }
if (param_size == 1) { if (param_size == 1) {
switch (param_type) { switch (param_type) {
#ifndef OPENGLES #ifndef OPENGLES
@ -706,7 +719,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
} }
} }
} }
gsg->report_my_gl_errors(); gsg->report_my_gl_errors();
} }
@ -1162,12 +1175,13 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg,
} }
} }
#endif #endif
InternalName *name = _shader->_var_spec[i]._name; InternalName *name = _shader->_var_spec[i]._name;
int texslot = _shader->_var_spec[i]._append_uv; int texslot = _shader->_var_spec[i]._append_uv;
if (texslot >= 0 && texslot < gsg->_state_texture->get_num_on_stages()) { if (texslot >= 0 && texslot < gsg->_state_texture->get_num_on_stages()) {
TextureStage *stage = gsg->_state_texture->get_on_stage(texslot); TextureStage *stage = gsg->_state_texture->get_on_stage(texslot);
InternalName *texname = stage->get_texcoord_name(); InternalName *texname = stage->get_texcoord_name();
if (name == InternalName::get_texcoord()) { if (name == InternalName::get_texcoord()) {
name = texname; name = texname;
} else if (texname != InternalName::get_texcoord()) { } else if (texname != InternalName::get_texcoord()) {

View File

@ -414,23 +414,23 @@ cp_dependency(ShaderMatInput inp) {
(inp == SMO_view_to_model)) { (inp == SMO_view_to_model)) {
dep |= SSD_transform; dep |= SSD_transform;
} }
if ((inp == SMO_texpad_x)|| if ((inp == SMO_texpad_x) ||
(inp == SMO_texpix_x)|| (inp == SMO_texpix_x) ||
(inp == SMO_alight_x)|| (inp == SMO_alight_x) ||
(inp == SMO_dlight_x)|| (inp == SMO_dlight_x) ||
(inp == SMO_plight_x)|| (inp == SMO_plight_x) ||
(inp == SMO_slight_x)|| (inp == SMO_slight_x) ||
(inp == SMO_satten_x)|| (inp == SMO_satten_x) ||
(inp == SMO_mat_constant_x)|| (inp == SMO_mat_constant_x) ||
(inp == SMO_vec_constant_x)|| (inp == SMO_vec_constant_x) ||
(inp == SMO_clipplane_x)|| (inp == SMO_clipplane_x) ||
(inp == SMO_view_x_to_view)|| (inp == SMO_view_x_to_view) ||
(inp == SMO_view_to_view_x)|| (inp == SMO_view_to_view_x) ||
(inp == SMO_apiview_x_to_view)|| (inp == SMO_apiview_x_to_view) ||
(inp == SMO_view_to_apiview_x)|| (inp == SMO_view_to_apiview_x) ||
(inp == SMO_clip_x_to_view)|| (inp == SMO_clip_x_to_view) ||
(inp == SMO_view_to_clip_x)|| (inp == SMO_view_to_clip_x) ||
(inp == SMO_apiclip_x_to_view)|| (inp == SMO_apiclip_x_to_view) ||
(inp == SMO_view_to_apiclip_x)) { (inp == SMO_view_to_apiclip_x)) {
dep |= SSD_shaderinputs; dep |= SSD_shaderinputs;
} }
@ -588,36 +588,45 @@ compile_parameter(const ShaderArgId &arg_id,
} }
ShaderVarSpec bind; ShaderVarSpec bind;
bind._id = arg_id; bind._id = arg_id;
bind._append_uv = -1;
if (pieces.size() == 2) { if (pieces.size() == 2) {
if (pieces[1]=="position") { if (pieces[1] == "position") {
bind._name = InternalName::get_vertex(); bind._name = InternalName::get_vertex();
bind._append_uv = -1; bind._append_uv = -1;
_var_spec.push_back(bind); _var_spec.push_back(bind);
return true; return true;
} }
if (pieces[1].substr(0,8)=="texcoord") { if (pieces[1].substr(0, 8) == "texcoord") {
bind._name = InternalName::get_texcoord(); bind._name = InternalName::get_texcoord();
bind._append_uv = atoi(pieces[1].c_str()+8); if (pieces[1].size() > 8) {
bind._append_uv = atoi(pieces[1].c_str() + 8);
}
_var_spec.push_back(bind); _var_spec.push_back(bind);
return true; return true;
} }
if (pieces[1].substr(0,7)=="tangent") { if (pieces[1].substr(0, 7) == "tangent") {
bind._name = InternalName::get_tangent(); bind._name = InternalName::get_tangent();
bind._append_uv = atoi(pieces[1].c_str()+7); if (pieces[1].size() > 7) {
bind._append_uv = atoi(pieces[1].c_str() + 7);
}
_var_spec.push_back(bind); _var_spec.push_back(bind);
return true; return true;
} }
if (pieces[1].substr(0,8)=="binormal") { if (pieces[1].substr(0, 8) == "binormal") {
bind._name = InternalName::get_binormal(); bind._name = InternalName::get_binormal();
bind._append_uv = atoi(pieces[1].c_str()+8); if (pieces[1].size() > 8) {
bind._append_uv = atoi(pieces[1].c_str() + 8);
}
_var_spec.push_back(bind); _var_spec.push_back(bind);
return true; return true;
} }
} }
bind._name = InternalName::get_root(); bind._name = InternalName::get_root();
bind._append_uv = -1; for (int i = 1; i < pieces.size(); ++i) {
for (int i=1; i<(int)(pieces.size()-0); i++)
bind._name = bind._name->append(pieces[i]); bind._name = bind._name->append(pieces[i]);
}
_var_spec.push_back(bind); _var_spec.push_back(bind);
return true; return true;
} }
@ -1008,7 +1017,7 @@ compile_parameter(const ShaderArgId &arg_id,
// Keywords to access unusual parameters. // Keywords to access unusual parameters.
if (pieces[0] == "sys") { if (pieces[0] == "sys") {
if ((!cp_errchk_parameter_words(p,2)) || if ((!cp_errchk_parameter_words(p, 2)) ||
(!cp_errchk_parameter_in(p)) || (!cp_errchk_parameter_in(p)) ||
(!cp_errchk_parameter_uniform(p))) { (!cp_errchk_parameter_uniform(p))) {
return false; return false;
@ -1025,14 +1034,24 @@ compile_parameter(const ShaderArgId &arg_id,
} }
bind._part[0] = SMO_pixel_size; bind._part[0] = SMO_pixel_size;
bind._arg[0] = NULL; bind._arg[0] = NULL;
} else if (pieces[1] == "windowsize") { } else if (pieces[1] == "windowsize") {
if (!cp_errchk_parameter_float(p, 2, 2)) { if (!cp_errchk_parameter_float(p, 2, 2)) {
return false; return false;
} }
bind._part[0] = SMO_window_size; bind._part[0] = SMO_window_size;
bind._arg[0] = NULL; bind._arg[0] = NULL;
} else if (pieces[1] == "time") {
if (!cp_errchk_parameter_float(p, 1, 1)) {
return false;
}
bind._piece = SMP_row3x1;
bind._part[0] = SMO_frame_time;
bind._arg[0] = NULL;
} else { } else {
cp_report_error(p,"unknown system parameter"); cp_report_error(p, "unknown system parameter");
return false; return false;
} }

View File

@ -30,7 +30,7 @@
#include "pta_LVecBase2.h" #include "pta_LVecBase2.h"
#ifdef HAVE_CG #ifdef HAVE_CG
// I don't want to include the Cg header file into panda as a // I don't want to include the Cg header file into panda as a
// whole. Instead, I'll just excerpt some opaque declarations. // whole. Instead, I'll just excerpt some opaque declarations.
typedef struct _CGcontext *CGcontext; typedef struct _CGcontext *CGcontext;
typedef struct _CGprogram *CGprogram; typedef struct _CGprogram *CGprogram;
@ -40,8 +40,8 @@ typedef struct _CGparameter *CGparameter;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : Shader // Class : Shader
// Summary: The Shader class is meant to select the Shader Language, // Summary: The Shader class is meant to select the Shader Language,
// select the available profile, compile the shader, and // select the available profile, compile the shader, and
// finally compile and store the shader parameters // finally compile and store the shader parameters
// in the appropriate structure. // in the appropriate structure.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount { class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount {
@ -115,11 +115,11 @@ public:
SMO_pixel_size, SMO_pixel_size,
SMO_texpad_x, SMO_texpad_x,
SMO_texpix_x, SMO_texpix_x,
SMO_attr_material, SMO_attr_material,
SMO_attr_color, SMO_attr_color,
SMO_attr_colorscale, SMO_attr_colorscale,
SMO_alight_x, SMO_alight_x,
SMO_dlight_x, SMO_dlight_x,
SMO_plight_x, SMO_plight_x,
@ -128,7 +128,7 @@ public:
SMO_texmat_x, SMO_texmat_x,
SMO_plane_x, SMO_plane_x,
SMO_clipplane_x, SMO_clipplane_x,
SMO_mat_constant_x, SMO_mat_constant_x,
SMO_vec_constant_x, SMO_vec_constant_x,
@ -146,7 +146,7 @@ public:
SMO_apiclip_to_view, SMO_apiclip_to_view,
SMO_view_to_apiclip, SMO_view_to_apiclip,
SMO_view_x_to_view, SMO_view_x_to_view,
SMO_view_to_view_x, SMO_view_to_view_x,
@ -161,11 +161,15 @@ public:
SMO_attr_fog, SMO_attr_fog,
SMO_attr_fogcolor, SMO_attr_fogcolor,
SMO_frame_number,
SMO_frame_time,
SMO_frame_delta,
SMO_INVALID SMO_INVALID
}; };
enum ShaderArgClass { enum ShaderArgClass {
SAC_scalar, SAC_scalar,
SAC_vector, SAC_vector,
SAC_matrix, SAC_matrix,
@ -173,28 +177,28 @@ public:
SAC_array, SAC_array,
SAC_unknown, SAC_unknown,
}; };
enum ShaderArgType { enum ShaderArgType {
SAT_scalar, SAT_scalar,
SAT_vec1, SAT_vec1,
SAT_vec2, SAT_vec2,
SAT_vec3, SAT_vec3,
SAT_vec4, SAT_vec4,
SAT_mat1x1, SAT_mat1x1,
SAT_mat1x2, SAT_mat1x2,
SAT_mat1x3, SAT_mat1x3,
SAT_mat1x4, SAT_mat1x4,
SAT_mat2x1, SAT_mat2x1,
SAT_mat2x2, SAT_mat2x2,
SAT_mat2x3, SAT_mat2x3,
SAT_mat2x4, SAT_mat2x4,
SAT_mat3x1, SAT_mat3x1,
SAT_mat3x2, SAT_mat3x2,
SAT_mat3x3, SAT_mat3x3,
SAT_mat3x4, SAT_mat3x4,
SAT_mat4x1, SAT_mat4x1,
SAT_mat4x2, SAT_mat4x2,
SAT_mat4x3, SAT_mat4x3,
SAT_mat4x4, SAT_mat4x4,
SAT_sampler1d, SAT_sampler1d,
SAT_sampler2d, SAT_sampler2d,
@ -230,20 +234,20 @@ public:
}; };
enum ShaderStateDep { enum ShaderStateDep {
SSD_NONE = 0, SSD_NONE = 0x000,
SSD_general = 1, SSD_general = 0x001,
SSD_transform = 2, SSD_transform = 0x002,
SSD_color = 4, SSD_color = 0x004,
SSD_colorscale = 8, SSD_colorscale = 0x008,
SSD_material = 16, SSD_material = 0x010,
SSD_shaderinputs = 32, SSD_shaderinputs = 0x020,
SSD_fog = 64, SSD_fog = 0x040,
}; };
enum ShaderBug { enum ShaderBug {
SBUG_ati_draw_buffers, SBUG_ati_draw_buffers,
}; };
enum ShaderMatFunc { enum ShaderMatFunc {
SMF_compose, SMF_compose,
SMF_transform_dlight, SMF_transform_dlight,
@ -251,36 +255,36 @@ public:
SMF_transform_slight, SMF_transform_slight,
SMF_first, SMF_first,
}; };
struct ShaderArgId { struct ShaderArgId {
string _name; string _name;
ShaderType _type; ShaderType _type;
int _seqno; int _seqno;
}; };
struct ShaderArgInfo { struct ShaderArgInfo {
ShaderArgId _id; ShaderArgId _id;
ShaderArgClass _class; ShaderArgClass _class;
ShaderArgClass _subclass; ShaderArgClass _subclass;
ShaderArgType _type; ShaderArgType _type;
ShaderArgDir _direction; ShaderArgDir _direction;
bool _varying; bool _varying;
NotifyCategory *_cat; NotifyCategory *_cat;
}; };
enum ShaderPtrType { enum ShaderPtrType {
SPT_float, SPT_float,
SPT_double, SPT_double,
SPT_unknown SPT_unknown
}; };
// Container structure for data of parameters ShaderPtrSpec. // Container structure for data of parameters ShaderPtrSpec.
struct ShaderPtrData { struct ShaderPtrData {
private: private:
PT(ReferenceCount) _pta; PT(ReferenceCount) _pta;
public: public:
void *_ptr; void *_ptr;
ShaderPtrType _type; ShaderPtrType _type;
bool _updated; bool _updated;
int _size; //number of elements vec3[4]=12 int _size; //number of elements vec3[4]=12
@ -339,8 +343,8 @@ public:
PT(InternalName) _name; PT(InternalName) _name;
int _append_uv; int _append_uv;
}; };
struct ShaderPtrSpec { struct ShaderPtrSpec {
ShaderArgId _id; ShaderArgId _id;
int _dim[3]; //n_elements,rows,cols int _dim[3]; //n_elements,rows,cols
int _dep[2]; int _dep[2];
@ -376,8 +380,8 @@ public:
public: public:
INLINE ShaderFile() {}; INLINE ShaderFile() {};
INLINE ShaderFile(const string &shared); INLINE ShaderFile(const string &shared);
INLINE ShaderFile(const string &vertex, INLINE ShaderFile(const string &vertex,
const string &fragment, const string &fragment,
const string &geometry, const string &geometry,
const string &tess_control, const string &tess_control,
const string &tess_evaluation); const string &tess_evaluation);
@ -404,18 +408,18 @@ public:
void parse_upto(string &result, string pattern, bool include); void parse_upto(string &result, string pattern, bool include);
void parse_rest(string &result); void parse_rest(string &result);
bool parse_eof(); bool parse_eof();
void cp_report_error(ShaderArgInfo &arg, const string &msg); void cp_report_error(ShaderArgInfo &arg, const string &msg);
bool cp_errchk_parameter_words(ShaderArgInfo &arg, int len); bool cp_errchk_parameter_words(ShaderArgInfo &arg, int len);
bool cp_errchk_parameter_in(ShaderArgInfo &arg); bool cp_errchk_parameter_in(ShaderArgInfo &arg);
bool cp_errchk_parameter_ptr(ShaderArgInfo &p); bool cp_errchk_parameter_ptr(ShaderArgInfo &p);
bool cp_errchk_parameter_varying(ShaderArgInfo &arg); bool cp_errchk_parameter_varying(ShaderArgInfo &arg);
bool cp_errchk_parameter_uniform(ShaderArgInfo &arg); bool cp_errchk_parameter_uniform(ShaderArgInfo &arg);
bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi); bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi);
bool cp_errchk_parameter_sampler(ShaderArgInfo &arg); bool cp_errchk_parameter_sampler(ShaderArgInfo &arg);
bool cp_parse_eol(ShaderArgInfo &arg, bool cp_parse_eol(ShaderArgInfo &arg,
vector_string &pieces, int &next); vector_string &pieces, int &next);
bool cp_parse_delimiter(ShaderArgInfo &arg, bool cp_parse_delimiter(ShaderArgInfo &arg,
vector_string &pieces, int &next); vector_string &pieces, int &next);
string cp_parse_non_delimiter(vector_string &pieces, int &next); string cp_parse_non_delimiter(vector_string &pieces, int &next);
bool cp_parse_coord_sys(ShaderArgInfo &arg, bool cp_parse_coord_sys(ShaderArgInfo &arg,
@ -425,12 +429,12 @@ public:
void cp_optimize_mat_spec(ShaderMatSpec &spec); void cp_optimize_mat_spec(ShaderMatSpec &spec);
#ifdef HAVE_CG #ifdef HAVE_CG
void cg_recurse_parameters(CGparameter parameter, void cg_recurse_parameters(CGparameter parameter,
const ShaderType &type, const ShaderType &type,
bool &success); bool &success);
#endif #endif
bool compile_parameter(const ShaderArgId &arg_id, bool compile_parameter(const ShaderArgId &arg_id,
const ShaderArgClass &arg_class, const ShaderArgClass &arg_class,
const ShaderArgClass &arg_subclass, const ShaderArgClass &arg_subclass,
const ShaderArgType &arg_type, const ShaderArgType &arg_type,
@ -443,7 +447,7 @@ public:
#ifdef HAVE_CG #ifdef HAVE_CG
private: private:
ShaderArgClass cg_parameter_class(CGparameter p); ShaderArgClass cg_parameter_class(CGparameter p);
ShaderArgType cg_parameter_type(CGparameter p); ShaderArgType cg_parameter_type(CGparameter p);
ShaderArgDir cg_parameter_dir(CGparameter p); ShaderArgDir cg_parameter_dir(CGparameter p);
@ -455,7 +459,7 @@ private:
bool cg_compile_shader(const ShaderCaps &caps); bool cg_compile_shader(const ShaderCaps &caps);
void cg_release_resources(); void cg_release_resources();
void cg_report_errors(); void cg_report_errors();
// Determines the appropriate cg profile settings and stores them in the active shader caps // Determines the appropriate cg profile settings and stores them in the active shader caps
// based on any profile settings stored in the shader's header // based on any profile settings stored in the shader's header
void cg_get_profile_from_header(ShaderCaps &caps); void cg_get_profile_from_header(ShaderCaps &caps);
@ -477,24 +481,24 @@ public:
bool cg_compile_for(const ShaderCaps &caps, CGcontext &ctx, bool cg_compile_for(const ShaderCaps &caps, CGcontext &ctx,
CGprogram &vprogram, CGprogram &fprogram, CGprogram &vprogram, CGprogram &fprogram,
CGprogram &gprogram, pvector<CGparameter> &map); CGprogram &gprogram, pvector<CGparameter> &map);
#endif #endif
public: public:
pvector <ShaderPtrSpec> _ptr_spec; pvector <ShaderPtrSpec> _ptr_spec;
epvector <ShaderMatSpec> _mat_spec; epvector <ShaderMatSpec> _mat_spec;
pvector <ShaderTexSpec> _tex_spec; pvector <ShaderTexSpec> _tex_spec;
pvector <ShaderVarSpec> _var_spec; pvector <ShaderVarSpec> _var_spec;
bool _error_flag; bool _error_flag;
CPT(ShaderFile) _text; CPT(ShaderFile) _text;
protected: protected:
CPT(ShaderFile) _filename; CPT(ShaderFile) _filename;
int _parse; int _parse;
bool _loaded; bool _loaded;
ShaderLanguage _language; ShaderLanguage _language;
static ShaderCaps _default_caps; static ShaderCaps _default_caps;
static ShaderUtilization _shader_utilization; static ShaderUtilization _shader_utilization;
static int _shaders_generated; static int _shaders_generated;
@ -510,7 +514,7 @@ protected:
typedef pmap <PreparedGraphicsObjects *, ShaderContext *> Contexts; typedef pmap <PreparedGraphicsObjects *, ShaderContext *> Contexts;
Contexts _contexts; Contexts _contexts;
private: private:
void clear_prepared(PreparedGraphicsObjects *prepared_objects); void clear_prepared(PreparedGraphicsObjects *prepared_objects);
Shader(); Shader();

View File

@ -622,15 +622,13 @@ synthesize_shader(const RenderState *rs) {
// These variables will hold the results of register allocation. // These variables will hold the results of register allocation.
char *ntangent_vreg = 0; char *tangent_freg = 0;
char *ntangent_freg = 0; char *binormal_freg = 0;
char *nbinormal_vreg = 0; string tangent_input;
char *nbinormal_freg = 0; string binormal_input;
char *htangent_vreg = 0; pmap<const InternalName *, char *> texcoord_fregs;
char *hbinormal_vreg = 0; pvector<char *> dlightcoord_fregs;
pvector<char *> texcoord_freg; pvector<char *> slightcoord_fregs;
pvector<char *> dlightcoord_freg;
pvector<char *> slightcoord_freg;
char *world_position_freg = 0; char *world_position_freg = 0;
char *world_normal_freg = 0; char *world_normal_freg = 0;
char *eye_position_freg = 0; char *eye_position_freg = 0;
@ -659,11 +657,39 @@ synthesize_shader(const RenderState *rs) {
for (int i = 0; i < _num_textures; ++i) { for (int i = 0; i < _num_textures; ++i) {
TextureStage *stage = texture->get_on_stage(i); TextureStage *stage = texture->get_on_stage(i);
if (!tex_gen->has_stage(stage)) { if (!tex_gen->has_stage(stage)) {
texcoord_freg.push_back(alloc_freg()); const InternalName *texcoord_name = stage->get_texcoord_name();
text << "\t in float4 vtx_texcoord" << i << " : " << alloc_vreg() << ",\n";
text << "\t out float4 l_texcoord" << i << " : " << texcoord_freg[i] << ",\n"; if (texcoord_fregs.count(texcoord_name) == 0) {
} else { char *freg = alloc_freg();
texcoord_freg.push_back(NULL); string tcname = texcoord_name->join("_");
texcoord_fregs[texcoord_name] = freg;
text << "\t in float4 vtx_" << tcname << " : " << alloc_vreg() << ",\n";
text << "\t out float4 l_" << tcname << " : " << freg << ",\n";
}
}
if ((_map_index_normal == i && _lighting && _auto_normal_on) || _map_index_height == i) {
const InternalName *texcoord_name = stage->get_texcoord_name();
PT(InternalName) tangent_name = InternalName::get_tangent();
PT(InternalName) binormal_name = InternalName::get_binormal();
if (texcoord_name != InternalName::get_texcoord()) {
tangent_name = tangent_name->append(texcoord_name->get_basename());
binormal_name = binormal_name->append(texcoord_name->get_basename());
}
tangent_input = tangent_name->join("_");
binormal_input = binormal_name->join("_");
text << "\t in float4 vtx_" << tangent_input << " : " << alloc_vreg() << ",\n";
text << "\t in float4 vtx_" << binormal_input << " : " << alloc_vreg() << ",\n";
if (_map_index_normal == i && _lighting && _auto_normal_on) {
tangent_freg = alloc_freg();
binormal_freg = alloc_freg();
text << "\t out float4 l_tangent : " << tangent_freg << ",\n";
text << "\t out float4 l_binormal : " << binormal_freg << ",\n";
}
} }
} }
if (_vertex_colors) { if (_vertex_colors) {
@ -695,49 +721,27 @@ synthesize_shader(const RenderState *rs) {
text << "\t in float4 vtx_normal : NORMAL,\n"; text << "\t in float4 vtx_normal : NORMAL,\n";
} }
if (_map_index_height >= 0) { if (_map_index_height >= 0) {
htangent_vreg = alloc_vreg();
hbinormal_vreg = alloc_vreg();
if (_map_index_normal == _map_index_height) {
ntangent_vreg = htangent_vreg;
nbinormal_vreg = hbinormal_vreg;
}
text << "\t in float4 vtx_tangent" << _map_index_height << " : " << htangent_vreg << ",\n";
text << "\t in float4 vtx_binormal" << _map_index_height << " : " << hbinormal_vreg << ",\n";
text << "\t uniform float4 mspos_view,\n"; text << "\t uniform float4 mspos_view,\n";
text << "\t out float3 l_eyevec,\n"; text << "\t out float3 l_eyevec,\n";
} }
if (_lighting) { if (_lighting) {
if (_map_index_normal >= 0 && _auto_normal_on) {
// If we had a height map and it used the same stage, that means we already have those inputs.
if (_map_index_normal != _map_index_height) {
ntangent_vreg = alloc_vreg();
nbinormal_vreg = alloc_vreg();
// NB. If we used TANGENT and BINORMAL, Cg would have them overlap with TEXCOORD6-7.
text << "\t in float4 vtx_tangent" << _map_index_normal << " : " << ntangent_vreg << ",\n";
text << "\t in float4 vtx_binormal" << _map_index_normal << " : " << nbinormal_vreg << ",\n";
}
ntangent_freg = alloc_freg();
nbinormal_freg = alloc_freg();
text << "\t out float4 l_tangent : " << ntangent_freg << ",\n";
text << "\t out float4 l_binormal : " << nbinormal_freg << ",\n";
}
if (_shadows && _auto_shadow_on) { if (_shadows && _auto_shadow_on) {
for (int i=0; i < (int)_dlights.size(); i++) { for (int i=0; i < (int)_dlights.size(); i++) {
if (_dlights[i]->_shadow_caster) { if (_dlights[i]->_shadow_caster) {
dlightcoord_freg.push_back(alloc_freg()); dlightcoord_fregs.push_back(alloc_freg());
text << "\t uniform float4x4 trans_model_to_clip_of_dlight" << i << ",\n"; text << "\t uniform float4x4 trans_model_to_clip_of_dlight" << i << ",\n";
text << "\t out float4 l_dlightcoord" << i << " : " << dlightcoord_freg[i] << ",\n"; text << "\t out float4 l_dlightcoord" << i << " : " << dlightcoord_fregs[i] << ",\n";
} else { } else {
dlightcoord_freg.push_back(NULL); dlightcoord_fregs.push_back(NULL);
} }
} }
for (int i=0; i < (int)_slights.size(); i++) { for (int i=0; i < (int)_slights.size(); i++) {
if (_slights[i]->_shadow_caster) { if (_slights[i]->_shadow_caster) {
slightcoord_freg.push_back(alloc_freg()); slightcoord_fregs.push_back(alloc_freg());
text << "\t uniform float4x4 trans_model_to_clip_of_slight" << i << ",\n"; text << "\t uniform float4x4 trans_model_to_clip_of_slight" << i << ",\n";
text << "\t out float4 l_slightcoord" << i << " : " << slightcoord_freg[i] << ",\n"; text << "\t out float4 l_slightcoord" << i << " : " << slightcoord_fregs[i] << ",\n";
} else { } else {
slightcoord_freg.push_back(NULL); slightcoord_fregs.push_back(NULL);
} }
} }
} }
@ -768,18 +772,19 @@ synthesize_shader(const RenderState *rs) {
text << "\t l_eye_normal.xyz = mul((float3x3)tpose_view_to_model, vtx_normal.xyz);\n"; text << "\t l_eye_normal.xyz = mul((float3x3)tpose_view_to_model, vtx_normal.xyz);\n";
text << "\t l_eye_normal.w = 0;\n"; text << "\t l_eye_normal.w = 0;\n";
} }
for (int i = 0; i < _num_textures; ++i) { pmap<const InternalName *, char *>::const_iterator it;
if (!tex_gen->has_stage(texture->get_on_stage(i))) { for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
text << "\t l_texcoord" << i << " = vtx_texcoord" << i << ";\n"; // Pass through all texcoord inputs as-is.
} string tcname = it->first->join("_");
text << "\t l_" << tcname << " = vtx_" << tcname << ";\n";
} }
if (_vertex_colors) { if (_vertex_colors) {
text << "\t l_color = vtx_color;\n"; text << "\t l_color = vtx_color;\n";
} }
if (_lighting && (_map_index_normal >= 0 && _auto_normal_on)) { if (_lighting && (_map_index_normal >= 0 && _auto_normal_on)) {
text << "\t l_tangent.xyz = mul((float3x3)tpose_view_to_model, vtx_tangent" << _map_index_normal << ".xyz);\n"; text << "\t l_tangent.xyz = mul((float3x3)tpose_view_to_model, vtx_" << tangent_input << ".xyz);\n";
text << "\t l_tangent.w = 0;\n"; text << "\t l_tangent.w = 0;\n";
text << "\t l_binormal.xyz = mul((float3x3)tpose_view_to_model, -vtx_binormal" << _map_index_normal << ".xyz);\n"; text << "\t l_binormal.xyz = mul((float3x3)tpose_view_to_model, -vtx_" << binormal_input << ".xyz);\n";
text << "\t l_binormal.w = 0;\n"; text << "\t l_binormal.w = 0;\n";
} }
if (_shadows && _auto_shadow_on) { if (_shadows && _auto_shadow_on) {
@ -824,22 +829,22 @@ synthesize_shader(const RenderState *rs) {
if (_need_eye_normal) { if (_need_eye_normal) {
text << "\t in float4 l_eye_normal : " << eye_normal_freg << ",\n"; text << "\t in float4 l_eye_normal : " << eye_normal_freg << ",\n";
} }
for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
text << "\t in float4 l_" << it->first->join("_") << " : " << it->second << ",\n";
}
const TexMatrixAttrib *tex_matrix = DCAST(TexMatrixAttrib, rs->get_attrib_def(TexMatrixAttrib::get_class_slot())); const TexMatrixAttrib *tex_matrix = DCAST(TexMatrixAttrib, rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
for (int i=0; i<_num_textures; i++) { for (int i=0; i<_num_textures; i++) {
TextureStage *stage = texture->get_on_stage(i); TextureStage *stage = texture->get_on_stage(i);
Texture *tex = texture->get_on_texture(stage); Texture *tex = texture->get_on_texture(stage);
nassertr(tex != NULL, NULL); nassertr(tex != NULL, NULL);
text << "\t uniform sampler" << texture_type_as_string(tex->get_texture_type()) << " tex_" << i << ",\n"; text << "\t uniform sampler" << texture_type_as_string(tex->get_texture_type()) << " tex_" << i << ",\n";
if (!tex_gen->has_stage(stage)) {
text << "\t in float4 l_texcoord" << i << " : " << texcoord_freg[i] << ",\n";
}
if (tex_matrix->has_stage(stage)) { if (tex_matrix->has_stage(stage)) {
text << "\t uniform float4x4 texmat_" << i << ",\n"; text << "\t uniform float4x4 texmat_" << i << ",\n";
} }
} }
if (_lighting && (_map_index_normal >= 0 && _auto_normal_on)) { if (_lighting && (_map_index_normal >= 0 && _auto_normal_on)) {
text << "\t in float3 l_tangent : " << ntangent_freg << ",\n"; text << "\t in float3 l_tangent : " << tangent_freg << ",\n";
text << "\t in float3 l_binormal : " << nbinormal_freg << ",\n"; text << "\t in float3 l_binormal : " << binormal_freg << ",\n";
} }
if (_lighting) { if (_lighting) {
for (int i=0; i < (int)_alights.size(); i++) { for (int i=0; i < (int)_alights.size(); i++) {
@ -853,7 +858,7 @@ synthesize_shader(const RenderState *rs) {
} else { } else {
text << "\t uniform sampler2D k_dlighttex" << i << ",\n"; text << "\t uniform sampler2D k_dlighttex" << i << ",\n";
} }
text << "\t in float4 l_dlightcoord" << i << " : " << dlightcoord_freg[i] << ",\n"; text << "\t in float4 l_dlightcoord" << i << " : " << dlightcoord_fregs[i] << ",\n";
} }
} }
for (int i=0; i < (int)_plights.size(); i++) { for (int i=0; i < (int)_plights.size(); i++) {
@ -868,7 +873,7 @@ synthesize_shader(const RenderState *rs) {
} else { } else {
text << "\t uniform sampler2D k_slighttex" << i << ",\n"; text << "\t uniform sampler2D k_slighttex" << i << ",\n";
} }
text << "\t in float4 l_slightcoord" << i << " : " << slightcoord_freg[i] << ",\n"; text << "\t in float4 l_slightcoord" << i << " : " << slightcoord_fregs[i] << ",\n";
} }
} }
if (_need_material_props) { if (_need_material_props) {
@ -916,26 +921,30 @@ synthesize_shader(const RenderState *rs) {
if (tex_gen != NULL && tex_gen->has_stage(stage)) { if (tex_gen != NULL && tex_gen->has_stage(stage)) {
switch (tex_gen->get_mode(stage)) { switch (tex_gen->get_mode(stage)) {
case TexGenAttrib::M_world_position: case TexGenAttrib::M_world_position:
text << "\t float4 l_texcoord" << i << " = l_world_position;\n"; text << "\t float4 texcoord" << i << " = l_world_position;\n";
break; break;
case TexGenAttrib::M_world_normal: case TexGenAttrib::M_world_normal:
text << "\t float4 l_texcoord" << i << " = l_world_normal;\n"; text << "\t float4 texcoord" << i << " = l_world_normal;\n";
break; break;
case TexGenAttrib::M_eye_position: case TexGenAttrib::M_eye_position:
text << "\t float4 l_texcoord" << i << " = l_eye_position;\n"; text << "\t float4 texcoord" << i << " = l_eye_position;\n";
break; break;
case TexGenAttrib::M_eye_normal: case TexGenAttrib::M_eye_normal:
text << "\t float4 l_texcoord" << i << " = l_eye_normal;\n"; text << "\t float4 texcoord" << i << " = l_eye_normal;\n";
text << "\t l_texcoord" << i << ".w = 1.0f;\n"; text << "\t texcoord" << i << ".w = 1.0f;\n";
break; break;
default: default:
pgraph_cat.error() << "Unsupported TexGenAttrib mode\n"; pgraph_cat.error() << "Unsupported TexGenAttrib mode\n";
text << "\t float4 l_texcoord" << i << " = float4(0, 0, 0, 0);\n"; text << "\t float4 texcoord" << i << " = float4(0, 0, 0, 0);\n";
} }
} else {
// Cg seems to be able to optimize this temporary away when appropriate.
const InternalName *texcoord_name = stage->get_texcoord_name();
text << "\t float4 texcoord" << i << " = l_" << texcoord_name->join("_") << ";\n";
} }
if (tex_matrix != NULL && tex_matrix->has_stage(stage)) { if (tex_matrix != NULL && tex_matrix->has_stage(stage)) {
text << "\t l_texcoord" << i << " = mul(texmat_" << i << ", l_texcoord" << i << ");\n"; text << "\t texcoord" << i << " = mul(texmat_" << i << ", texcoord" << i << ");\n";
text << "\t l_texcoord" << i << ".xyz /= l_texcoord" << i << ".w;\n"; text << "\t texcoord" << i << ".xyz /= texcoord" << i << ".w;\n";
} }
} }
text << "\t // Fetch all textures.\n"; text << "\t // Fetch all textures.\n";
@ -943,7 +952,7 @@ synthesize_shader(const RenderState *rs) {
Texture *tex = texture->get_on_texture(texture->get_on_stage(_map_index_height)); Texture *tex = texture->get_on_texture(texture->get_on_stage(_map_index_height));
nassertr(tex != NULL, NULL); nassertr(tex != NULL, NULL);
text << "\t float4 tex" << _map_index_height << " = tex" << texture_type_as_string(tex->get_texture_type()); text << "\t float4 tex" << _map_index_height << " = tex" << texture_type_as_string(tex->get_texture_type());
text << "(tex_" << _map_index_height << ", l_texcoord" << _map_index_height << "."; text << "(tex_" << _map_index_height << ", texcoord" << _map_index_height << ".";
switch (tex->get_texture_type()) { switch (tex->get_texture_type()) {
case Texture::TT_cube_map: case Texture::TT_cube_map:
case Texture::TT_3d_texture: case Texture::TT_3d_texture:
@ -983,21 +992,21 @@ synthesize_shader(const RenderState *rs) {
nassertr(tex != NULL, NULL); nassertr(tex != NULL, NULL);
// Parallax mapping pushes the texture coordinates of the other textures away from the camera. // Parallax mapping pushes the texture coordinates of the other textures away from the camera.
if (_map_index_height >= 0 && parallax_mapping_samples > 0) { if (_map_index_height >= 0 && parallax_mapping_samples > 0) {
text << "\t l_texcoord" << i << ".xyz -= parallax_offset;\n"; text << "\t texcoord" << i << ".xyz -= parallax_offset;\n";
} }
text << "\t float4 tex" << i << " = tex" << texture_type_as_string(tex->get_texture_type()); text << "\t float4 tex" << i << " = tex" << texture_type_as_string(tex->get_texture_type());
text << "(tex_" << i << ", l_texcoord" << i << "."; text << "(tex_" << i << ", texcoord" << i << ".";
switch(tex->get_texture_type()) { switch(tex->get_texture_type()) {
case Texture::TT_cube_map: case Texture::TT_cube_map:
case Texture::TT_3d_texture: case Texture::TT_3d_texture:
case Texture::TT_2d_texture_array: case Texture::TT_2d_texture_array:
text << "xyz"; text << "xyz";
break; break;
case Texture::TT_2d_texture: case Texture::TT_2d_texture:
text << "xy"; text << "xy";
break; break;
case Texture::TT_1d_texture: case Texture::TT_1d_texture:
text << "x"; text << "x";
break; break;
default: default:
break; break;
@ -1240,7 +1249,7 @@ synthesize_shader(const RenderState *rs) {
} else if (_flat_colors) { } else if (_flat_colors) {
text << "\t result = attr_color;\n"; text << "\t result = attr_color;\n";
} else { } else {
text << "\t result = float4(1,1,1,1);\n"; text << "\t result = float4(1, 1, 1, 1);\n";
} }
} }

View File

@ -86,8 +86,8 @@ protected:
int _vtregs_used; int _vtregs_used;
int _ftregs_used; int _ftregs_used;
void reset_register_allocator(); void reset_register_allocator();
INLINE char *alloc_vreg(); char *alloc_vreg();
INLINE char *alloc_freg(); char *alloc_freg();
// RenderState analysis information. Created by analyze_renderstate: // RenderState analysis information. Created by analyze_renderstate: