/** * Compiles a new shader, and creates an opengl_shader_t that will be put into the GL_shader vector * if compilation is successful. * This function is used for main (i.e. model rendering) and particle shaders, post processing shaders use their own infrastructure * * @param flags Combination of SDR_* flags */ void opengl_compile_main_shader(int flags) { char *vert = NULL, *frag = NULL; mprintf(("Compiling new shader:\n")); bool in_error = false; opengl_shader_t new_shader; // choose appropriate files char vert_name[NAME_LENGTH]; char frag_name[NAME_LENGTH]; if (flags & SDR_FLAG_SOFT_QUAD) { strcpy_s( vert_name, "soft-v.sdr"); strcpy_s( frag_name, "soft-f.sdr"); } else { strcpy_s( vert_name, "main-v.sdr"); strcpy_s( frag_name, "main-f.sdr"); } // read vertex shader if ( (vert = opengl_load_shader(vert_name, flags)) == NULL ) { in_error = true; goto Done; } // read fragment shader if ( (frag = opengl_load_shader(frag_name, flags)) == NULL ) { in_error = true; goto Done; } Verify( vert != NULL ); Verify( frag != NULL ); new_shader.program_id = opengl_shader_create(vert, frag); if ( !new_shader.program_id ) { in_error = true; goto Done; } new_shader.flags = flags; opengl_shader_set_current( &new_shader ); mprintf(("Shader features:\n")); //Init all the uniforms if (new_shader.flags & SDR_FLAG_SOFT_QUAD) { for (int j = 0; j < Particle_shader_flag_references; j++) { if (new_shader.flags == GL_Uniform_Reference_Particle[j].flag) { int k; // Equality check needed because the combination of SDR_FLAG_SOFT_QUAD and SDR_FLAG_DISTORTION define something very different // than just SDR_FLAG_SOFT_QUAD alone for (k = 0; k < GL_Uniform_Reference_Particle[j].num_uniforms; k++) { opengl_shader_init_uniform( GL_Uniform_Reference_Particle[j].uniforms[k] ); } for (k = 0; k < GL_Uniform_Reference_Particle[j].num_attributes; k++) { opengl_shader_init_attribute( GL_Uniform_Reference_Particle[j].attributes[k] ); } mprintf((" %s\n", GL_Uniform_Reference_Particle[j].name)); } } } else { for (int j = 0; j < Main_shader_flag_references; j++) { if (new_shader.flags & GL_Uniform_Reference_Main[j].flag) { if (GL_Uniform_Reference_Main[j].num_uniforms > 0) { for (int k = 0; k < GL_Uniform_Reference_Main[j].num_uniforms; k++) { opengl_shader_init_uniform( GL_Uniform_Reference_Main[j].uniforms[k] ); } } if (GL_Uniform_Reference_Main[j].num_attributes > 0) { for (int k = 0; k < GL_Uniform_Reference_Main[j].num_attributes; k++) { opengl_shader_init_attribute( GL_Uniform_Reference_Main[j].attributes[k] ); } } mprintf((" %s\n", GL_Uniform_Reference_Main[j].name)); } } } opengl_shader_set_current(); // add it to our list of embedded shaders GL_shader.push_back( new_shader ); Done: if (vert != NULL) { vm_free(vert); vert = NULL; } if (frag != NULL) { vm_free(frag); frag = NULL; } if (in_error) { // shut off relevant usage things ... bool dealt_with = false; if (flags & SDR_FLAG_HEIGHT_MAP) { mprintf((" Shader in_error! Disabling height maps!\n")); Cmdline_height = 0; dealt_with = true; } if (flags & SDR_FLAG_NORMAL_MAP) { mprintf((" Shader in_error! Disabling normal maps and height maps!\n")); Cmdline_height = 0; Cmdline_normal = 0; dealt_with = true; } if (!dealt_with) { if (flags == 0) { mprintf((" Shader in_error! Disabling GLSL!\n")); Use_GLSL = 0; Cmdline_height = 0; Cmdline_normal = 0; GL_shader.clear(); } else { // We died on a lighting shader, probably due to instruction count. // Drop down to a special var that will use fixed-function rendering // but still allow for post-processing to work mprintf((" Shader in_error! Disabling GLSL model rendering!\n")); Use_GLSL = 1; Cmdline_height = 0; Cmdline_normal = 0; } } } }
/** * Compiles a new shader, and creates an opengl_shader_t that will be put into the GL_shader vector * if compilation is successful. * * @param sdr Identifier defined with the program we wish to compile * @param flags Combination of SDR_* flags */ int opengl_compile_shader(shader_type sdr, uint flags) { int sdr_index = -1; int empty_idx; opengl_shader_t new_shader; Assert(sdr < NUM_SHADER_TYPES); opengl_shader_type_t *sdr_info = &GL_shader_types[sdr]; mprintf(("Compiling new shader:\n")); mprintf((" %s\n", sdr_info->description)); // figure out if the variant requested needs a geometry shader bool use_geo_sdr = false; // do we even have a geometry shader? if ( sdr_info->geo != NULL ) { for (int i = 0; i < GL_num_shader_variants; ++i) { opengl_shader_variant_t *variant = &GL_shader_variants[i]; if (variant->type_id == sdr && flags & variant->flag && variant->use_geometry_sdr) { use_geo_sdr = true; break; } } } auto vertex_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->vert, flags); auto fragment_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->frag, flags); SCP_vector<SCP_string> geom_content; if ( use_geo_sdr ) { if (!Is_Extension_Enabled(OGL_EXT_GEOMETRY_SHADER4)) { return -1; } // read geometry shader geom_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->geo, flags); Current_geo_sdr_params = &sdr_info->geo_sdr_info; } new_shader.program_id = opengl_shader_create(vertex_content, fragment_content, geom_content); if (!new_shader.program_id) { return -1; } new_shader.shader = sdr_info->type_id; new_shader.flags = flags; opengl_shader_set_current(&new_shader); // initialize uniforms and attributes for ( int i = 0; i < sdr_info->num_uniforms; ++i ) { opengl_shader_init_uniform( sdr_info->uniforms[i] ); } for (int i = 0; i < sdr_info->num_attributes; ++i) { opengl_shader_init_attribute(sdr_info->attributes[i]); } // if this shader is POST_PROCESS_MAIN, hack in the user-defined flags if ( sdr_info->type_id == SDR_TYPE_POST_PROCESS_MAIN ) { opengl_post_init_uniforms(flags); } mprintf(("Shader Variant Features:\n")); // initialize all uniforms and attributes that are specific to this variant for ( int i = 0; i < GL_num_shader_variants; ++i ) { opengl_shader_variant_t &variant = GL_shader_variants[i]; if ( sdr_info->type_id == variant.type_id && variant.flag & flags ) { for (int j = 0; j < variant.num_uniforms; ++j) { opengl_shader_init_uniform(variant.uniforms[j]); } for (int j = 0; j < variant.num_attributes; ++j) { opengl_shader_init_attribute(variant.attributes[j]); } mprintf((" %s\n", variant.description)); } } opengl_shader_set_current(); // add it to our list of embedded shaders // see if we have empty shader slots empty_idx = -1; for ( int i = 0; i < (int)GL_shader.size(); ++i ) { if ( GL_shader[i].shader == NUM_SHADER_TYPES ) { empty_idx = i; break; } } // then insert it at an empty slot or at the end if ( empty_idx >= 0 ) { GL_shader[empty_idx] = new_shader; sdr_index = empty_idx; } else { sdr_index = GL_shader.size(); GL_shader.push_back(new_shader); } return sdr_index; }