Shader::Shader(const std::string& filename_noExt, bool isGS) { bool flag1{}, flag2{}, flag3{}; GLuint vertexShader = compile(load(filename_noExt + ".vs"), GL_VERTEX_SHADER); GLuint fragmentShader = compile(load(filename_noExt + ".fs"), GL_FRAGMENT_SHADER); GLuint geometryShader{}; if(isGS) { geometryShader = compile(load(filename_noExt + ".gs"), GL_GEOMETRY_SHADER); flag3 = getShaderError(geometryShader, GL_COMPILE_STATUS, "SHADER_ERROR: compilation error -> " + filename_noExt + ".gs"); } flag1 = getShaderError(vertexShader, GL_COMPILE_STATUS, "SHADER_ERROR: compilation error -> " + filename_noExt + ".vs"); flag2 = getShaderError(fragmentShader, GL_COMPILE_STATUS, "SHADER_ERROR: compilation error -> " + filename_noExt + ".fs"); if(flag1 || flag2 || flag3) { glDeleteShader(vertexShader); glDeleteShader(fragmentShader); if(isGS) glDeleteShader(geometryShader); return; } GLuint temp = glCreateProgram(); glAttachShader(temp, vertexShader); glAttachShader(temp, fragmentShader); if(isGS) glAttachShader(temp, geometryShader); glLinkProgram(temp); if(getProgramError(temp, GL_LINK_STATUS, "SHADER_ERROR: could not link program")) { glDeleteProgram(temp); } else { glDetachShader(temp, vertexShader); glDetachShader(temp, fragmentShader); if(isGS) glDetachShader(temp, geometryShader); programID.reset(new GLuint(temp), [](GLuint* programID) { glDeleteProgram(*programID); delete programID; }); } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); if(isGS) glDeleteShader(geometryShader); }
void GPUProgram::reload(const std::string& _code) { std::string code = _code; // If a syntax error occurs while loading the shader we want to break. // However, it makes no sense to break in this loading code when the // error is really in the shader code. To hack this under MSVC we print // out the error as if it were a MSVC error so double clicking will take // us there, then break in this code. To reload the shader we jump back // to the top of the loading routine and try again. bool reloadFromFile = (code == ""); bool ignore = false; LOADSHADER: if (reloadFromFile) { if (fileExists(filename)) { code = readFileAsString(filename); } else { error("Critical Error", std::string("Cannot locate file \"") + filename + "\" to reload it.", true); exit(-1); } } unit = getUnitFromCode(code, extension); glPushAttrib(GL_ALL_ATTRIB_BITS); glEnable(unit); genPrograms(1, &glProgram); bindProgram(unit, glProgram); // Clear the error flag. glGetError(); loadProgram(code); // Check for load errors if ((glGetError() == GL_INVALID_OPERATION) && (! ignore)) { int pos = 0; const unsigned char* msg = NULL; getProgramError(pos, msg); deletePrograms(1, &glProgram); int line = 1; int col = 1; // Find the line and column position. int x = 0; for (x = 0, col = 1; x < pos; ++x, ++col) { if (code[x] == '\n') { ++line; col = 1; } } if (col > 1) { --col; } // Count forward to the end of the line int endCol = col; while ((x < (int)code.size()) && (code[x] != '\n') && (code[x] != '\r')) { ++x; ++endCol; } // Extract the line std::string codeLine = code.substr(pos - col + 1, endCol - col); // Show the line std::string text = format("%s (%d:%d) : %s%s%s", filename.c_str(), line, col, msg, NEWLINE, NEWLINE); text += codeLine + NEWLINE; for (int i = 0; i < col - 1; ++i) { text += " "; } text += "^"; #ifdef G3D_WIN32 { // Print the error message in MSVC format std::string fullFilename = resolveFilename(filename); debugPrintf("%s%s(%d) : GPU Program Error : %s%s%s", NEWLINE, fullFilename.c_str(), line, msg, NEWLINE, NEWLINE); } #endif #ifndef _DEBUG Log::common()->print("\n******************************\n"); Log::common()->print(text); exit(-1); #endif const char* choice[] = {"Debug", "Ignore", "Ignore All", "Exit"}; switch (prompt("Error Loading Program", text.c_str(), choice, 4, true)) { case 0: // Debug { //////////////////////////////////////////////////////////////////////////// // // // PUSH F4 // // // // If your program breaks on this line in debug mode under Windows, // // go to the MSVC Debug window and click on the error message (or // // just press F4 be taken to the error line in your shader. // // // // When you change it and press continue, G3D will try to reload your // // shader (if it came from a file). // // // //////////////////////////////////////////////////////////////////////////// debugBreak(); reloadFromFile = true; goto LOADSHADER; break; } case 1: // Ignore break; case 2: // Ignore all ignore = true; break; case 3: // Exit exit(-1); } } bindingTable.parse(code); glPopAttrib(); }