/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ #include "globalincs/pstypes.h" #include "globalincs/def_files.h" #include "graphics/2d.h" #include "lighting/lighting.h" #include "graphics/grinternal.h" #include "graphics/gropengl.h" #include "graphics/gropenglextension.h" #include "graphics/gropengltexture.h" #include "graphics/gropengllight.h" #include "graphics/gropengltnl.h" #include "graphics/gropengldraw.h" #include "graphics/gropenglshader.h" #include "math/vecmat.h" #include "render/3d.h" #include "cmdline/cmdline.h" SCP_vector GL_shader; static char *GLshader_info_log = NULL; static const int GLshader_info_log_size = 8192; #define MAX_SHADER_UNIFORMS 15 struct opengl_shader_file_t { char *vert; char *frag; int flags; int num_uniforms; char *uniforms[MAX_SHADER_UNIFORMS]; }; static opengl_shader_file_t GL_shader_file[] = { { "null-v.sdr", "null-f.sdr", (0), 0, { NULL }, }, { "b-v.sdr", "b-f.sdr", (SDR_FLAG_DIFFUSE_MAP), 1, { "sBasemap" } }, { "b-v.sdr", "bg-f.sdr", (SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP), 2, { "sBasemap", "sGlowmap" } }, { "l-v.sdr", "lb-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP), 2, { "sBasemap", "n_lights" } }, { "l-v.sdr", "lbg-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP), 3, { "sBasemap", "sGlowmap", "n_lights" } }, { "l-v.sdr", "lbgs-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP), 4, { "sBasemap", "sGlowmap", "sSpecmap", "n_lights" } }, { "l-v.sdr", "lbs-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_SPEC_MAP), 3, { "sBasemap", "sSpecmap", "n_lights" } }, { "le-v.sdr", "lbgse-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_ENV_MAP), 7, { "sBasemap", "sGlowmap", "sSpecmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "le-v.sdr", "lbse-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_ENV_MAP), 6, { "sBasemap", "sSpecmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "ln-v.sdr", "lbgn-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP| SDR_FLAG_NORMAL_MAP), 4, { "sBasemap", "sGlowmap", "sNormalmap", "n_lights" } }, { "ln-v.sdr", "lbgsn-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP), 5, { "sBasemap", "sGlowmap", "sSpecmap", "sNormalmap", "n_lights" } }, { "ln-v.sdr", "lbn-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_NORMAL_MAP), 3, { "sBasemap", "sNormalmap", "n_lights" } }, { "ln-v.sdr", "lbsn-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP), 4, { "sBasemap", "sSpecmap", "sNormalmap", "n_lights" } }, { "ln-v.sdr", "lbgnh-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP| SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP), 5, { "sBasemap", "sGlowmap", "sNormalmap", "sHeightmap", "n_lights" } }, { "ln-v.sdr", "lbgsnh-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP), 6, { "sBasemap", "sGlowmap", "sSpecmap", "sNormalmap", "sHeightmap", "n_lights" } }, { "ln-v.sdr", "lbnh-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP), 4, { "sBasemap", "sNormalmap", "sHeightmap", "n_lights" } }, { "ln-v.sdr", "lbsnh-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP), 5, { "sBasemap", "sSpecmap", "sNormalmap", "sHeightmap", "n_lights" } }, { "lne-v.sdr", "lbgsne-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_ENV_MAP), 8, { "sBasemap", "sGlowmap", "sSpecmap", "sNormalmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "lne-v.sdr", "lbsne-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_ENV_MAP), 7, { "sBasemap", "sSpecmap", "sNormalmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "lne-v.sdr", "lbgsnhe-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP | SDR_FLAG_ENV_MAP), 9, { "sBasemap", "sGlowmap", "sSpecmap", "sNormalmap", "sHeightmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "lne-v.sdr", "lbsnhe-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP | SDR_FLAG_ENV_MAP), 8, { "sBasemap", "sSpecmap", "sNormalmap", "sHeightmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "lf-v.sdr", "lfb-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP), 2, { "sBasemap", "n_lights" } }, { "lf-v.sdr", "lfbg-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP), 3, { "sBasemap", "sGlowmap", "n_lights" } }, { "lf-v.sdr", "lfbgs-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP), 4, { "sBasemap", "sGlowmap", "sSpecmap", "n_lights" } }, { "lf-v.sdr", "lfbs-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_SPEC_MAP), 3, { "sBasemap", "sSpecmap", "n_lights" } }, { "lfe-v.sdr", "lfbgse-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_ENV_MAP), 7, { "sBasemap", "sGlowmap", "sSpecmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "lfe-v.sdr", "lfbse-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_ENV_MAP), 6, { "sBasemap", "sSpecmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "lfn-v.sdr", "lfbgn-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP| SDR_FLAG_NORMAL_MAP), 4, { "sBasemap", "sGlowmap", "sNormalmap", "n_lights" } }, { "lfn-v.sdr", "lfbgsn-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP), 5, { "sBasemap", "sGlowmap", "sSpecmap", "sNormalmap", "n_lights" } }, { "lfn-v.sdr", "lfbn-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_NORMAL_MAP), 3, { "sBasemap", "sNormalmap", "n_lights" } }, { "lfn-v.sdr", "lfbsn-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP), 4, { "sBasemap", "sSpecmap", "sNormalmap", "n_lights" } }, { "lfn-v.sdr", "lfbgnh-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP| SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP), 5, { "sBasemap", "sGlowmap", "sNormalmap", "sHeightmap", "n_lights" } }, { "lfn-v.sdr", "lfbgsnh-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP), 6, { "sBasemap", "sGlowmap", "sSpecmap", "sNormalmap", "sHeightmap", "n_lights" } }, { "lfn-v.sdr", "lfbnh-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP), 4, { "sBasemap", "sNormalmap", "sHeightmap", "n_lights" } }, { "lfn-v.sdr", "lfbsnh-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP), 5, { "sBasemap", "sSpecmap", "sNormalmap", "sHeightmap", "n_lights" } }, { "lfne-v.sdr", "lfbgsne-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_ENV_MAP), 8, { "sBasemap", "sGlowmap", "sSpecmap", "sNormalmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "lfne-v.sdr", "lfbsne-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_ENV_MAP), 7, { "sBasemap", "sSpecmap", "sNormalmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "lfne-v.sdr", "lfbgsnhe-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP | SDR_FLAG_ENV_MAP), 9, { "sBasemap", "sGlowmap", "sSpecmap", "sNormalmap", "sHeightmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "lfne-v.sdr", "lfbsnhe-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_FOG | SDR_FLAG_DIFFUSE_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP | SDR_FLAG_ENV_MAP), 8, { "sBasemap", "sSpecmap", "sNormalmap", "sHeightmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "l-v.sdr", "null-f.sdr", (SDR_FLAG_LIGHT), 0, { NULL } }, { "l-v.sdr", "lg-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_GLOW_MAP), 2, { "sGlowmap", "n_lights" } }, { "l-v.sdr", "lgs-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP), 3, { "sGlowmap", "sSpecmap", "n_lights" } }, { "l-v.sdr", "ls-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_SPEC_MAP), 2, { "sSpecmap", "n_lights" } }, { "le-v.sdr", "lgse-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_ENV_MAP), 6, { "sGlowmap", "sSpecmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "le-v.sdr", "lse-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_SPEC_MAP | SDR_FLAG_ENV_MAP), 5, { "sSpecmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "ln-v.sdr", "lgn-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_GLOW_MAP | SDR_FLAG_NORMAL_MAP), 3, { "sGlowmap", "sNormalmap", "n_lights" } }, { "ln-v.sdr", "lgsn-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP), 4, { "sGlowmap", "sSpecmap", "sNormalmap", "n_lights" } }, { "ln-v.sdr", "ln-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_NORMAL_MAP), 2, { "sNormalmap", "n_lights" } }, { "ln-v.sdr", "lsn-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP), 3, { "sSpecmap", "sNormalmap", "n_lights" } }, { "ln-v.sdr", "lgnh-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_GLOW_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP), 4, { "sGlowmap", "sNormalmap", "sHeightmap", "n_lights" } }, { "ln-v.sdr", "lgsnh-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP), 5, { "sGlowmap", "sSpecmap", "sNormalmap", "sHeightmap", "n_lights" } }, { "ln-v.sdr", "lnh-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP), 3, { "sNormalmap", "sHeightmap", "n_lights" } }, { "ln-v.sdr", "lsnh-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP), 4, { "sSpecmap", "sNormalmap", "sHeightmap", "n_lights" } }, { "lne-v.sdr", "lgsne-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_ENV_MAP), 7, { "sGlowmap", "sSpecmap", "sNormalmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "lne-v.sdr", "lsne-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_ENV_MAP), 6, { "sSpecmap", "sNormalmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "lne-v.sdr", "lgsnhe-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_GLOW_MAP | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP | SDR_FLAG_ENV_MAP), 8, { "sGlowmap", "sSpecmap", "sNormalmap", "sHeightmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } }, { "lne-v.sdr", "lsnhe-f.sdr", (SDR_FLAG_LIGHT | SDR_FLAG_SPEC_MAP | SDR_FLAG_NORMAL_MAP | SDR_FLAG_HEIGHT_MAP | SDR_FLAG_ENV_MAP), 7, { "sSpecmap", "sNormalmap", "sHeightmap", "sEnvmap", "envMatrix", "alpha_spec", "n_lights" } } }; static const int Num_shader_files = sizeof(GL_shader_file) / sizeof(opengl_shader_file_t); opengl_shader_t *Current_shader = NULL; void opengl_shader_check_info_log(GLhandleARB shader_object); void opengl_shader_set_current(opengl_shader_t *shader_obj) { Current_shader = shader_obj; if (Current_shader != NULL) { vglUseProgramObjectARB(Current_shader->program_id); #ifndef NDEBUG if ( opengl_check_for_errors("shader_set_current()") ) { vglValidateProgramARB(Current_shader->program_id); GLint obj_status = 0; vglGetObjectParameterivARB(Current_shader->program_id, GL_OBJECT_VALIDATE_STATUS_ARB, &obj_status); if ( !obj_status ) { opengl_shader_check_info_log(Current_shader->program_id); mprintf(("VALIDATE INFO-LOG:\n")); if (strlen(GLshader_info_log) > 5) { mprintf(("%s\n", GLshader_info_log)); } else { mprintf(("\n")); } } } #endif } else { vglUseProgramObjectARB(0); } } int opengl_shader_get_index(int flags) { uint idx; for (idx = 0; idx < GL_shader.size(); idx++) { if (GL_shader[idx].flags == flags) { return idx; } } return -1; } void opengl_shader_shutdown() { uint i; if ( !Use_GLSL ) { return; } for (i = 0; i < GL_shader.size(); i++) { if (GL_shader[i].program_id) { vglDeleteObjectARB(GL_shader[i].program_id); GL_shader[i].program_id = 0; } GL_shader[i].uniforms.clear(); } GL_shader.clear(); if (GLshader_info_log != NULL) { vm_free(GLshader_info_log); GLshader_info_log = NULL; } } char *opengl_load_shader(char *filename, int flags, bool main_shdr) { std::string sflags; if (main_shdr) { if (flags & SDR_FLAG_DIFFUSE_MAP) sflags += "#define FLAG_DIFFUSE_MAP\n"; if (flags & SDR_FLAG_ENV_MAP) sflags += "#define FLAG_ENV_MAP\n"; if (flags & SDR_FLAG_FOG) sflags += "#define FLAG_FOG\n"; if (flags & SDR_FLAG_GLOW_MAP) sflags += "#define FLAG_GLOW_MAP\n"; if (flags & SDR_FLAG_HEIGHT_MAP) sflags += "#define FLAG_HEIGHT_MAP\n"; if (flags & SDR_FLAG_LIGHT) sflags += "#define FLAG_LIGHT\n"; if (flags & SDR_FLAG_NORMAL_MAP) sflags += "#define FLAG_NORMAL_MAP\n"; if (flags & SDR_FLAG_SPEC_MAP) sflags += "#define FLAG_SPEC_MAP\n"; } const char *shader_flags = sflags.c_str(); int flags_len = strlen(shader_flags); CFILE *cf_shader = cfopen(filename, "rt", CFILE_NORMAL, CF_TYPE_EFFECTS); if (cf_shader != NULL) { int len = cfilelength(cf_shader); char *shader = (char*) vm_malloc(len + flags_len + 1); strcpy(shader, shader_flags); memset(shader + flags_len, 0, len + 1); cfread(shader + flags_len, len + 1, 1, cf_shader); cfclose(cf_shader); return shader; } else return NULL; } void opengl_shader_init() { char *vert = NULL, *frag = NULL; int i, idx; if ( !Use_GLSL ) { return; } // check if main shaders exist bool main_vert = cf_exists_full("main-v.sdr", CF_TYPE_EFFECTS) != 0; bool main_frag = cf_exists_full("main-f.sdr", CF_TYPE_EFFECTS) != 0; GL_shader.reserve(Num_shader_files); for (idx = 0; idx < Num_shader_files; idx++) { bool in_error = false; opengl_shader_t new_shader; opengl_shader_file_t *shader_file = &GL_shader_file[idx]; if ( !Cmdline_glow && (shader_file->flags & SDR_FLAG_GLOW_MAP) ) { continue; } if ( !Cmdline_spec && (shader_file->flags & SDR_FLAG_SPEC_MAP) ) { continue; } if ( !Cmdline_env && (shader_file->flags & SDR_FLAG_ENV_MAP) ) { continue; } if ( !Cmdline_normal && (shader_file->flags & SDR_FLAG_NORMAL_MAP) ) { continue; } if ( !Cmdline_height && (shader_file->flags & SDR_FLAG_HEIGHT_MAP) ) { continue; } // choose appropriate files char *vert_name; if (main_vert) vert_name = "main-v.sdr"; else vert_name = shader_file->vert; char *frag_name; if (main_frag) frag_name = "main-f.sdr"; else frag_name = shader_file->frag; mprintf((" Compiling shader -> %s (%s) / %s (%s) ... \n", vert_name, shader_file->vert, frag_name, shader_file->frag)); // read vertex shader if ((vert = opengl_load_shader(vert_name, shader_file->flags, main_vert)) == NULL) { in_error = true; goto Done; } // read fragment shader if ((frag = opengl_load_shader(frag_name, shader_file->flags, main_frag)) == 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 = shader_file->flags; opengl_shader_set_current( &new_shader ); new_shader.uniforms.reserve(shader_file->num_uniforms); for (i = 0; i < shader_file->num_uniforms; i++) { opengl_shader_init_uniform( shader_file->uniforms[i] ); } 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 ... if (shader_file->flags & SDR_FLAG_HEIGHT_MAP) { mprintf((" Shader in_error! Disabling height maps!\n")); Cmdline_height = 0; } if (shader_file->flags & SDR_FLAG_NORMAL_MAP) { mprintf((" Shader in_error! Disabling normal maps and height maps!\n")); Cmdline_height = 0; Cmdline_normal = 0; } if (idx == 0) { mprintf((" Shader in_error! Disabling GLSL!\n")); Use_GLSL = 0; Cmdline_height = 0; Cmdline_normal = 0; GL_shader.clear(); break;; } } } mprintf(("\n")); } void opengl_shader_check_info_log(GLhandleARB shader_object) { if (GLshader_info_log == NULL) { GLshader_info_log = (char *) vm_malloc(GLshader_info_log_size); } memset(GLshader_info_log, 0, GLshader_info_log_size); vglGetInfoLogARB(shader_object, GLshader_info_log_size-1, 0, GLshader_info_log); } GLhandleARB opengl_shader_compile_object(const GLcharARB *shader_source, GLenum shader_type) { GLhandleARB shader_object = 0; GLint status = 0; shader_object = vglCreateShaderObjectARB(shader_type); vglShaderSourceARB(shader_object, 1, &shader_source, NULL); vglCompileShaderARB(shader_object); // check if the compile was successful vglGetObjectParameterivARB(shader_object, GL_OBJECT_COMPILE_STATUS_ARB, &status); opengl_shader_check_info_log(shader_object); // we failed, bail out now... if (status == 0) { // basic error check mprintf(("%s shader failed to compile:\n%s\n", (shader_type == GL_VERTEX_SHADER_ARB) ? "Vertex" : "Fragment", GLshader_info_log)); // this really shouldn't exist, but just in case if (shader_object) { vglDeleteObjectARB(shader_object); } return 0; } // we succeeded, maybe output warnings too if (strlen(GLshader_info_log) > 5) { nprintf(("SHADER-DEBUG", "%s shader compiled with warnings:\n%s\n", (shader_type == GL_VERTEX_SHADER_ARB) ? "Vertex" : "Fragment", GLshader_info_log)); } return shader_object; } GLhandleARB opengl_shader_link_object(GLhandleARB vertex_object, GLhandleARB fragment_object) { GLhandleARB shader_object = 0; GLint status = 0; shader_object = vglCreateProgramObjectARB(); if (vertex_object) { vglAttachObjectARB(shader_object, vertex_object); } if (fragment_object) { vglAttachObjectARB(shader_object, fragment_object); } vglLinkProgramARB(shader_object); // check if the link was successful vglGetObjectParameterivARB(shader_object, GL_OBJECT_LINK_STATUS_ARB, &status); opengl_shader_check_info_log(shader_object); // we failed, bail out now... if (status == 0) { mprintf(("Shader failed to link:\n%s\n", GLshader_info_log)); if (shader_object) { vglDeleteObjectARB(shader_object); } return 0; } // we succeeded, maybe output warnings too if (strlen(GLshader_info_log) > 5) { nprintf(("SHADER-DEBUG", "Shader linked with warnings:\n%s\n", GLshader_info_log)); } return shader_object; } /*GLhandleARB opengl_shader_create(const char *vs, const char *fs) { GLhandleARB vs_o = 0; GLhandleARB fs_o = 0; GLhandleARB program = 0; if (vs) { vs_o = opengl_shader_compile_object( (const GLcharARB*)vs, GL_VERTEX_SHADER_ARB ); if ( !vs_o ) { mprintf(("ERROR! Unable to create vertex shader!\n")); goto Done; } } if (fs) { fs_o = opengl_shader_compile_object( (const GLcharARB*)fs, GL_FRAGMENT_SHADER_ARB ); if ( !fs_o ) { mprintf(("ERROR! Unable to create fragment shader!\n")); goto Done; } } program = opengl_shader_link_object(vs_o, fs_o); if ( !program ) { mprintf(("ERROR! Unable to create shader program!\n")); } Done: if (vs_o) { vglDeleteObjectARB(vs_o); } if (fs_o) { vglDeleteObjectARB(fs_o); } return program; }*/ GLhandleARB opengl_shader_create(const char *vs, const char *fs) { GLhandleARB vs_o = 0; GLhandleARB fs_o = 0; GLhandleARB program = 0; if (vs) { vs_o = opengl_shader_compile_object( (const GLcharARB*)vs, GL_VERTEX_SHADER_ARB ); if ( !vs_o ) { mprintf(("ERROR! Unable to create vertex shader!\n")); goto Done; } } if (fs) { fs_o = opengl_shader_compile_object( (const GLcharARB*)fs, GL_FRAGMENT_SHADER_ARB ); if ( !fs_o ) { mprintf(("ERROR! Unable to create fragment shader!\n")); goto Done; } } program = opengl_shader_link_object(vs_o, fs_o); if ( !program ) { mprintf(("ERROR! Unable to create shader program!\n")); } Done: if (vs_o) { vglDeleteObjectARB(vs_o); } if (fs_o) { vglDeleteObjectARB(fs_o); } return program; } void opengl_shader_init_uniform(char *uniform_text) { opengl_shader_uniform_t new_uniform; if ( (Current_shader == NULL) || (uniform_text == NULL) ) { Int3(); return; } new_uniform.text_id = uniform_text; new_uniform.location = vglGetUniformLocationARB(Current_shader->program_id, uniform_text); if (new_uniform.location < 0) { mprintf(("WARNING: Unable to get shader uniform location for \"%s\"!\n", uniform_text)); return; } Current_shader->uniforms.push_back( new_uniform ); } GLint opengl_shader_get_uniform(char *uniform_text) { if ( (Current_shader == NULL) || (uniform_text == NULL) ) { Int3(); return -1; } SCP_vector::iterator uniform; for (uniform = Current_shader->uniforms.begin(); uniform != Current_shader->uniforms.end(); ++uniform) { if ( !uniform->text_id.compare(uniform_text) ) { return uniform->location; } } return -1; }