#include "RenderPCH.h" #include "GL_Renderer.h" #include "state_to_nvparse_text.h" #include //using namespace std; // register combiners namespace { struct portion_state { GLint portion; GLint input[4]; GLint mapping[4]; GLint compusg[4]; GLint output[3]; GLint opselect[3]; GLint bias; GLint scale; }; bool nvrc1_supported; bool nvrc2_enabled; GLfloat c0[4], c1[4]; bool same_color( const GLfloat * rgba1, const GLfloat * rgba2) { if( rgba1[0] == rgba2[0] && rgba1[1] == rgba2[1] && rgba1[2] == rgba2[2] && rgba1[3] == rgba2[3]) return true; return false; } portion_state get_portion(GLenum combiner, GLenum portion) { GLenum v[4] = { GL_VARIABLE_A_NV, GL_VARIABLE_B_NV, GL_VARIABLE_C_NV, GL_VARIABLE_D_NV }; portion_state p; p.portion = portion; for(int i=0; i < 4; i++) { glGetCombinerInputParameterivNV(combiner, portion, v[i], GL_COMBINER_INPUT_NV, & p.input[i]); glGetCombinerInputParameterivNV(combiner, portion, v[i], GL_COMBINER_MAPPING_NV, & p.mapping[i]); glGetCombinerInputParameterivNV(combiner, portion, v[i], GL_COMBINER_COMPONENT_USAGE_NV, & p.compusg[i]); } glGetCombinerOutputParameterivNV(combiner, portion, GL_COMBINER_AB_OUTPUT_NV, & p.output[0]); glGetCombinerOutputParameterivNV(combiner, portion, GL_COMBINER_CD_OUTPUT_NV, & p.output[1]); glGetCombinerOutputParameterivNV(combiner, portion, GL_COMBINER_SUM_OUTPUT_NV, & p.output[2]); glGetCombinerOutputParameterivNV(combiner, portion, GL_COMBINER_AB_DOT_PRODUCT_NV, & p.opselect[0]); glGetCombinerOutputParameterivNV(combiner, portion, GL_COMBINER_CD_DOT_PRODUCT_NV, & p.opselect[1]); glGetCombinerOutputParameterivNV(combiner, portion, GL_COMBINER_MUX_SUM_NV, & p.opselect[2]); glGetCombinerOutputParameterivNV(combiner, portion, GL_COMBINER_BIAS_NV, & p.bias); glGetCombinerOutputParameterivNV(combiner, portion, GL_COMBINER_SCALE_NV, & p.scale); return p; } string register_name(GLenum reg) { switch (reg) { case GL_CONSTANT_COLOR0_NV: return "const0"; case GL_CONSTANT_COLOR1_NV: return "const1"; case GL_FOG_COLOR: return "fog"; case GL_PRIMARY_COLOR_NV: return "col0"; case GL_SECONDARY_COLOR_NV: return "col1"; case GL_TEXTURE0_ARB: return "tex0"; case GL_TEXTURE1_ARB: return "tex1"; case GL_TEXTURE2_ARB: return "tex2"; case GL_TEXTURE3_ARB: return "tex3"; case GL_SPARE0_NV: return "spare0"; case GL_SPARE1_NV: return "spare1"; case GL_ZERO: return "zero"; case GL_DISCARD_NV: return "discard"; case GL_E_TIMES_F_NV: return "final_product"; case GL_SPARE0_PLUS_SECONDARY_COLOR_NV: return "color_sum"; default: return "unknown_register"; } } void get_mapping(GLenum mapping, string & mapping_prefix, string & mapping_suffix) { switch (mapping) { case GL_SIGNED_IDENTITY_NV: mapping_prefix = ""; mapping_suffix = ""; break; case GL_SIGNED_NEGATE_NV: mapping_prefix = "-"; mapping_suffix = ""; break; case GL_EXPAND_NORMAL_NV: mapping_prefix = "expand("; mapping_suffix = ")"; break; case GL_EXPAND_NEGATE_NV: mapping_prefix = "-expand("; mapping_suffix = ")"; break; case GL_HALF_BIAS_NORMAL_NV: mapping_prefix = "half_bias("; mapping_suffix = ")"; break; case GL_HALF_BIAS_NEGATE_NV: mapping_prefix = "-half_bias("; mapping_suffix = ")"; break; case GL_UNSIGNED_IDENTITY_NV: mapping_prefix = "unsigned("; mapping_suffix = ")"; break; case GL_UNSIGNED_INVERT_NV: mapping_prefix = "unsigned_invert("; mapping_suffix = ")"; break; default: mapping_prefix = "unknown_mapping("; mapping_suffix = ")"; break; } } string operand_string(GLenum reg, GLenum mapping, GLenum compusg, GLenum portion) { string rname = register_name(reg); string cu; if(compusg != portion) { if(compusg == GL_RGB) cu = ".rgb"; if(compusg == GL_ALPHA) cu = ".a"; if(compusg == GL_BLUE) cu = ".b"; } string mapping_prefix, mapping_suffix; get_mapping(mapping, mapping_prefix, mapping_suffix); string op = mapping_prefix + rname + cu + mapping_suffix; return op; } string general_combiner_portion(GLenum combiner, GLenum portion) { portion_state p = get_portion(combiner, portion); string s; // if unused portion return empty string if( p.output[0] == GL_DISCARD_NV && p.output[1] == GL_DISCARD_NV && p.output[2] == GL_DISCARD_NV) return s; if(portion == GL_RGB) s += " rgb {\n"; else s += " alpha {\n"; // do the AB and CD expressions for(int i=0; i < 2; i++) { if(p.output[i] != GL_DISCARD_NV || p.output[2] != GL_DISCARD_NV) { s += " "; s += register_name(p.output[i]); s += " = "; // handle the arg * 1 simplification: if( (p.input[2*i ] == GL_ZERO && p.mapping[2*i ] == GL_UNSIGNED_INVERT_NV) && (p.input[2*i+1] != GL_ZERO) ) { s += operand_string(p.input[2*i+1], p.mapping[2*i+1], p.compusg[2*i+1], portion); } else if( (p.input[2*i+1] == GL_ZERO && p.mapping[2*i+1] == GL_UNSIGNED_INVERT_NV) && (p.input[2*i ] != GL_ZERO) ) { s += operand_string(p.input[2*i], p.mapping[2*i], p.compusg[2*i], portion); } else { s += operand_string(p.input[2*i], p.mapping[2*i], p.compusg[2*i], portion); if(p.opselect[i] == GL_TRUE) s += " . "; else s += " * "; s += operand_string(p.input[2*i+1], p.mapping[2*i+1], p.compusg[2*i+1], portion); } s += ";\n"; } } if(p.output[2] != GL_DISCARD_NV) { s += " "; s += register_name(p.output[2]); s += " = "; if(p.opselect[2] == GL_TRUE) s += "mux();\n"; else s += "sum();\n"; } if(p.bias == GL_NONE && p.scale == GL_SCALE_BY_ONE_HALF_NV) s += " scale_by_one_half();\n"; else if(p.bias == GL_NONE && p.scale == GL_SCALE_BY_TWO_NV) s += " scale_by_one_two();\n"; else if(p.bias == GL_NONE && p.scale == GL_SCALE_BY_FOUR_NV) s += " scale_by_one_four();\n"; else if(p.bias == GL_BIAS_BY_NEGATIVE_ONE_HALF_NV && p.scale == GL_NONE) s += " bias_by_negative_one_half();\n"; else if(p.bias == GL_BIAS_BY_NEGATIVE_ONE_HALF_NV && p.scale == GL_SCALE_BY_TWO_NV) s += " bias_by_negative_one_half_scale_by_two();\n"; s += " }\n"; return s; } string general_combiner(GLenum combiner) { string s; s += general_combiner_portion(combiner, GL_RGB); s += general_combiner_portion(combiner, GL_ALPHA); // if unused combiner return empty string if(s.size() == 0) return ""; string cc; if(nvrc2_enabled) { GLfloat sc0[4], sc1[4]; glGetCombinerStageParameterfvNV(combiner, GL_CONSTANT_COLOR0_NV, sc0); glGetCombinerStageParameterfvNV(combiner, GL_CONSTANT_COLOR1_NV, sc1); if(! same_color(c0, sc0)) { char buf[80]; sprintf(buf, " const0 = (%f, %f, %f, %f);\n", sc0[0], sc0[1], sc0[2], sc0[3]); cc += buf; } if(! same_color(c1, sc1)) { char buf[80]; sprintf(buf, " const1 = (%f, %f, %f, %f);\n", sc1[0], sc1[1], sc1[2], sc1[3]); cc += buf; } } return "{\n" + cc + s + "}\n"; } struct final_combiner_state { GLint input[7]; GLint mapping[7]; GLint compusg[7]; bool clamp_color_sum; }; final_combiner_state get_final_combiner_state() { GLenum v[7] = { GL_VARIABLE_A_NV, GL_VARIABLE_B_NV, GL_VARIABLE_C_NV, GL_VARIABLE_D_NV, GL_VARIABLE_E_NV, GL_VARIABLE_F_NV, GL_VARIABLE_G_NV }; final_combiner_state fc; for(int i=0; i < 7; i++) { glGetFinalCombinerInputParameterivNV(v[i], GL_COMBINER_INPUT_NV, & fc.input[i]); glGetFinalCombinerInputParameterivNV(v[i], GL_COMBINER_MAPPING_NV, & fc.mapping[i]); glGetFinalCombinerInputParameterivNV(v[i], GL_COMBINER_COMPONENT_USAGE_NV, & fc.compusg[i]); } GLboolean clamp_color_sum = GL_FALSE; glGetBooleanv(GL_COLOR_SUM_CLAMP_NV, & clamp_color_sum); fc.clamp_color_sum = (clamp_color_sum == GL_TRUE); return fc; } bool is_zero(const final_combiner_state & fc, int i) { if(fc.input[i] == GL_ZERO && fc.mapping[i] == GL_UNSIGNED_IDENTITY_NV) return true; return false; } string final_operand_string(GLenum reg, GLenum mapping, GLenum compusg, GLenum portion) { string rname = register_name(reg); string cu; if(compusg != portion) { if(compusg == GL_RGB) cu = ".rgb"; if(compusg == GL_ALPHA) cu = ".a"; if(compusg == GL_BLUE) cu = ".b"; } string mapping_prefix, mapping_suffix; if(mapping == GL_UNSIGNED_INVERT_NV) { mapping_prefix = "unsigned_invert("; mapping_suffix = ")"; } string op = mapping_prefix + rname + cu + mapping_suffix; return op; } string final_combiner() { final_combiner_state fc = get_final_combiner_state(); string final_product; if( fc.input[0] == GL_E_TIMES_F_NV || fc.input[1] == GL_E_TIMES_F_NV || fc.input[2] == GL_E_TIMES_F_NV || fc.input[3] == GL_E_TIMES_F_NV ) { final_product += "final_product = "; final_product += final_operand_string(fc.input[4], fc.mapping[4], fc.compusg[4], GL_RGB); final_product += " * "; final_product += final_operand_string(fc.input[5], fc.mapping[5], fc.compusg[5], GL_RGB); final_product += ";\n"; } string clamp_color_sum; if(fc.clamp_color_sum && (fc.input[1] == GL_SPARE0_PLUS_SECONDARY_COLOR_NV || fc.input[2] == GL_SPARE0_PLUS_SECONDARY_COLOR_NV || fc.input[3] == GL_SPARE0_PLUS_SECONDARY_COLOR_NV ) ) clamp_color_sum = "clamp_color_sum();\n"; string out_rgb; if(is_zero(fc, 0) && ! is_zero(fc, 3)) // output == d; { out_rgb = "out.rgb = "; out_rgb += final_operand_string(fc.input[3], fc.mapping[3], fc.compusg[3], GL_RGB); out_rgb += ";\n"; } else if(! is_zero(fc, 0) && ! is_zero(fc, 1) && ! is_zero(fc, 2)) // lerp { out_rgb = "out.rgb = lerp("; out_rgb += final_operand_string(fc.input[0], fc.mapping[0], fc.compusg[0], GL_RGB); out_rgb += ", "; out_rgb += final_operand_string(fc.input[1], fc.mapping[1], fc.compusg[1], GL_RGB); out_rgb += ", "; out_rgb += final_operand_string(fc.input[2], fc.mapping[2], fc.compusg[2], GL_RGB); out_rgb += ")"; if(! is_zero(fc,3)) { out_rgb += " + "; out_rgb += final_operand_string(fc.input[3], fc.mapping[3], fc.compusg[3], GL_RGB); } out_rgb += ";\n"; } else if(! is_zero(fc, 0) && ! is_zero(fc, 1)) // mul or mad { out_rgb = "out.rgb = "; out_rgb += final_operand_string(fc.input[0], fc.mapping[0], fc.compusg[0], GL_RGB); out_rgb += " * "; out_rgb += final_operand_string(fc.input[1], fc.mapping[1], fc.compusg[1], GL_RGB); if(! is_zero(fc,3)) { out_rgb += " + "; out_rgb += final_operand_string(fc.input[3], fc.mapping[3], fc.compusg[3], GL_RGB); } out_rgb += ";\n"; } else if(! is_zero(fc, 0) && is_zero(fc, 1) && ! is_zero(fc,2)) // odd case of mul or mad { // invert the mapping for A since the combiner setup is (1-A)C // but we can only express AB with nvparse if(fc.mapping[0] == GL_UNSIGNED_IDENTITY_NV) fc.mapping[0] = GL_UNSIGNED_INVERT_NV; else fc.mapping[0] = GL_UNSIGNED_IDENTITY_NV; out_rgb = "out.rgb = "; out_rgb += final_operand_string(fc.input[0], fc.mapping[0], fc.compusg[0], GL_RGB); out_rgb += " * "; out_rgb += final_operand_string(fc.input[2], fc.mapping[2], fc.compusg[2], GL_RGB); if(! is_zero(fc,3)) { out_rgb += " + "; out_rgb += final_operand_string(fc.input[3], fc.mapping[3], fc.compusg[3], GL_RGB); } out_rgb += ";\n"; } string out_a; if( ! is_zero(fc, 6) ) { out_a = "out.a = "; out_a += final_operand_string(fc.input[6], fc.mapping[6], fc.compusg[6], GL_ALPHA); out_a += ";\n"; } return final_product + clamp_color_sum + out_rgb + out_a; } } extern "C" char * state_to_rc10 () { nvrc1_supported = false; // required nvrc2_enabled = false; // optional if(SUPPORTS_GL_NV_register_combiners) nvrc1_supported = true; if(SUPPORTS_GL_NV_register_combiners2) { if(glIsEnabled(GL_PER_STAGE_CONSTANTS_NV)) nvrc2_enabled = true; } if(nvrc1_supported == false) return 0; GLenum combiner[8] = {GL_COMBINER0_NV, GL_COMBINER1_NV, GL_COMBINER2_NV, GL_COMBINER3_NV, GL_COMBINER4_NV, GL_COMBINER5_NV, GL_COMBINER6_NV, GL_COMBINER7_NV }; string state; state += "!!RC1.0\n"; glGetFloatv(GL_CONSTANT_COLOR0_NV, c0); glGetFloatv(GL_CONSTANT_COLOR1_NV, c1); char buf[80]; sprintf(buf, "const0 = (%f, %f, %f, %f);\n", c0[0], c0[1], c0[2], c0[3]); state += buf; sprintf(buf, "const1 = (%f, %f, %f, %f);\n", c1[0], c1[1], c1[2], c1[3]); state += buf; GLint num_combiners; glGetIntegerv(GL_NUM_GENERAL_COMBINERS_NV, &num_combiners); for(int i = 0; i < num_combiners; i++) state += general_combiner(combiner[i]); state += final_combiner(); return strdup(state.c_str()); }