2017-07-16 86 views
1

我希望我的程序能夠繪製出一個簡單的紅色三角形。頂點和片段着色器應該通過我的loadShader()函數從外部文件加載,但由於某種奇怪的原因,我的loadShader()函數正在讀取非ASCII字符,因此着色器編譯錯誤正在生成。爲什麼fgetc()讀取非ASCII字符? (試圖加載GLSL着色器)

嘗試按照here(使用Notepad ++)提供的說明將我的着色器文件轉換爲ASCII格式失敗,因爲結果相同 - 即有關非ASCII字符的着色器編譯器錯誤(請參見屏幕截圖下面)和白色,而不是預期的紅色三角形(由於着色器沒有編譯)。

更多故障排除嘗試:

關鍵碼部分從14到44去 - 我loadShader功能(注我另外上傳我的源代碼,以Pastebin便於行號引用)。 。 由於我的調試輸出(第25行)與Windows資源管理器提供的文件大小具有相同的字節數,因此從第22行開始的「tell file size」部分正常工作,如下面的屏幕截圖所示。 此外,緩衝區(第28行)與第41行的調試輸出中所見的着色器文件大小完全對應(請參見屏幕截圖)。 最後,我的兩個着色器的語法是正確的,因爲我先前對它們進行了硬編碼,結果是所需的紅色三角形渲染。

截圖:

enter image description here

源碼:

// Expected result: Draws a simple red colored triangle to the screen 
// Problem to debug: Why does my loadShader function read non-ASCII characters? 

#include <glad/glad.h> 
#define GLFW_DLL 
#include <GLFW\glfw3.h> 
#include <cstdio> 
#include <iostream> 

// TODO: Debug 
/* Loads shader text files from a given file name (extension required) 
* and returns the shader code as a null terminated string from that file. 
*/ 
const char * loadShader(const char * shaderFileName) { 
    FILE * shaderFile{}; 
    fopen_s(&shaderFile, shaderFileName, "r"); 
    if (!shaderFile) { 
     std::cerr << "ERROR: Cannot open file" << std::endl; 
     return "\0"; 
    } 
    // Tell file size 
    fseek(shaderFile, 0L, SEEK_END); 
    unsigned long shaderFileSize{}; 
    shaderFileSize = ftell(shaderFile); 
    std::cout << "DEBUG: shaderFileSize: " << shaderFileSize << std::endl; // Debug output 
    rewind(shaderFile); 
    // Read from file 
    char * buffer = (char *)malloc(sizeof(char)*(shaderFileSize+1UL)); 
    if (!buffer) { 
     std::cerr << "ERROR: Failed to allocate memory" << std::endl; 
     return "\0"; 
    } 
    int c{}; 
    int i = 0; 
    while ((c = fgetc(shaderFile))!= EOF) { 
     buffer[i++] = c; 
    } 
    // Put '\0' at the end of the buffer (required for OpenGL) 
    buffer[shaderFileSize] = '\0'; 
    std::cout << "DEBUG: buffer: " << buffer << std::endl; // Debug output 
    std::cout << "DEBUG: strlen: " << strlen(buffer) << std::endl; // Debug output 
    fclose(shaderFile); 
    return buffer; 
} // end of loadShader() 

int main() { 
    // Initialize GLFW 
    if (!glfwInit()) { 
     std::cerr << "ERROR: Failed to initialize GLFW3" << std::endl; 
     return -1; 
    } 
    // Create window 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 
    GLFWwindow* window = glfwCreateWindow(640, 480, "OpenGL Game", nullptr, nullptr); 
    if (!window) { 
     std::cerr << "ERROR: Failed to create window with GLFW3" << std::endl; 
     glfwTerminate(); 
     return -1; 
    } 
    glfwMakeContextCurrent(window); 
    // Load all OpenGL function pointers. 
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { 
     std::cerr << "ERROR: Failed to initialize GLAD" << std::endl; 
     return -1; 
    } 
    // Get info from renderer 
    const GLubyte* rendererName = glGetString(GL_RENDERER); 
    const GLubyte* OpenGLVersionSupported = glGetString(GL_VERSION); 
    std::cout << rendererName << std::endl << OpenGLVersionSupported << std::endl; 
    // Enable depth 
    glEnable(GL_DEPTH_TEST); 
    glDepthFunc(GL_LESS); 
    // Define triangle 
    GLfloat points[] = { 0.0f, 0.5f, 0.0f, 
         0.5f, -0.5f, 0.0f, 
         -0.5f, -0.5f, 0.0f }; 
    // Create buffer object 
    GLuint vertexBufferObject = 0; 
    glGenBuffers(1, &vertexBufferObject); 
    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW); 
    // Create vertex attribute object 
    GLuint vertexAttributeObject = 0; 
    glGenVertexArrays(1, &vertexAttributeObject); 
    glBindVertexArray(vertexAttributeObject); 
    glEnableVertexAttribArray(0); 
    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject); 
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); 
    // Load shaders 
    const char * vertexShaderCode = loadShader("VertexShader.glsl"); 
    const char * fragmentShaderCode = loadShader("FragmentShader.glsl"); 
    // Compile shaders 
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); 
    glShaderSource(vertexShader, 1, &vertexShaderCode, nullptr); 
    glCompileShader(vertexShader); 
    // Check vertex shader for compile errors 
    int success = 0; 
    char message[512] = ""; 
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); 
    if (!success) { 
     glGetShaderInfoLog(vertexShader, 512, nullptr, message); 
     std::cerr << "ERROR: Failed to compile vertex shader" << std::endl << message; 
    } 
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 
    glShaderSource(fragmentShader, 1, &fragmentShaderCode, nullptr); 
    glCompileShader(fragmentShader); 
    // Check fragment shader for compile errors 
    success = 0; 
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); 
    if (!success) { 
     glGetShaderInfoLog(fragmentShader, 512, nullptr, message); 
     // TODO: Specify error type in message 
     std::cerr << "ERROR: Failed to compile fragment shader" << std::endl << message; 
    } 
    // Create shader program and link it 
    GLuint shaderProgram = glCreateProgram(); 
    glAttachShader(shaderProgram, vertexShader); 
    glAttachShader(shaderProgram, fragmentShader); 
    glLinkProgram(shaderProgram); 
    // Check for linking errors 
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); 
    if (!success) { 
     glGetShaderInfoLog(shaderProgram, 512, nullptr, message); 
     // TODO: Specify error type in message 
     std::cerr << "ERROR: Failed to link shaders" << std::endl << message; 
    } 
    // Render loop 
    while (!glfwWindowShouldClose(window)) { 
     // Wipe the drawing surface clear 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
     // Use shader program and vertex attribute object 
     glUseProgram(shaderProgram); 
     glBindVertexArray(vertexAttributeObject); 
     // Draw from the currently bound vertex attribute object 
     glDrawArrays(GL_TRIANGLES, 0, 3); 
     glfwPollEvents(); 
     glfwSwapBuffers(window); 
    } 
    // Exit program 
    glfwTerminate(); 
    return 0; 
} // end of main() 
+3

建議:

而是將其替換您的代碼首先檢查着色器文件的字符編碼。如果它不是ASCII文件,你可能已經找到了問題。接下來,通過使用十六進制編輯器檢查非神祕不可打印或非ASCII字符的文件,確保文件不包含任何意外。 – user4581301

+1

你爲什麼使用'fgetc'?你去計算文件長度和一切。爲什麼不使用'fread'並一次讀完所有內容? –

回答

3

0xcd是使用MSVC CRT以填充未初始化的存儲器中的值。會發生什麼情況是您的文件使用\r\n行結尾,但是您在文本模式下打開它,並且CRT將它們轉換爲\n行尾。因此,您讀入的buffer字節數少於ftell返回的大小,因此i的最後一個值小於shaderFileSize,因此在寫入buffer[i]的最後一個值與空終止符之間有一些未初始化的字節。

FILE * shaderFile{}; 
fopen_s(&shaderFile, shaderFileName, "rb"); // <-------- HERE !!!! 
fseek(shaderFile, 0L, SEEK_END); 
unsigned long shaderFileSize = ftell(shaderFile); 
rewind(shaderFile); 
char * buffer = (char *)malloc(shaderFileSize+1); 
fread(buffer, shaderFileSize, 1, shaderFile); 
buffer[shaderFileSize] = '\0';