Плохо содержится в строке, за исключением случаев, когда я храню ее в классе C ++ - PullRequest
0 голосов
/ 11 июля 2019

Я тренируюсь в программировании openGL и хочу создать свои собственные классы, чтобы облегчить мне жизнь.Однако в моем классе Shader я столкнулся с проблемой.

Мой класс Shader состоит из одной строки C ++ (имя шейдера) и двух других строк C (которые содержат код фрагмента ивершинные шейдеры).

Затем, во время инициализации, я читаю свои файлы, чтобы записать каждый символ в мою строку C.На данный момент эти две переменные заполнены правильно, но если я попытаюсь прочитать их с помощью моего getVertex() метода, он вообще не покажет мне, что в нем должно быть.

Код шейдеров фрагментов и вершин должениметь запас в const GLchar * из-за glShaderSource(), который используется для загрузки шейдеров.Вот прототип этой функции: void glShaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length);.

Я уже пытался использовать базовый const char * как const GLchar *, но он четный.

Я также пытался снабдить шейдерамикод в строки C ++ и преобразовать их в строку C в основном, но это ничего не меняет.

Вот мой код с отладочной печатью:

-main.cpp

#include "head.h"

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);

int main(){

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);    //For MacOS


    /*Window initialization*/
    GLFWwindow* window = glfwCreateWindow(800, 600, "Hello Window!", NULL, NULL);
    if (window == NULL){
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);


    /*GLAD initialization*/
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }


    /*Initialize shaders*/
    Shader myShaders("Hello");

    std::cout << "Main Print\n" << myShaders.getVertex() << std::endl;

    /*Triangle Vertices*/
    /*float vertices[] = {
    -0.5f, -0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
     0.0f,  0.5f, 0.0f
    };*/


    /*Rectangle Vertices*/
    float vertices[] = {
     0.5f,  0.5f, 0.0f,  // top right
     0.5f, -0.5f, 0.0f,  // bottom right
    -0.5f, -0.5f, 0.0f,  // bottom left
    -0.5f,  0.5f, 0.0f   // top left 
    };
    unsigned int indices[] = {
        0, 1, 3,   // first triangle
        1, 2, 3    // second triangle
    };

    unsigned int VBO;
    glGenBuffers(1, &VBO);

    /*Define the type of the VBO*/
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    /*Copy vertices into the GL_ARRAY_BUFFER object (VBO)*/
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);


    /*Creating a VS object*/
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);

    /*Link the VS code to the VS object*/
    glShaderSource(vertexShader, 1, &myShaders.getVertex(), NULL);
    glCompileShader(vertexShader);

    /*Testing the VS compilation*/
    int  success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);

    if (!success){
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    /*As the VS, same for FS*/
    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &myShaders.getFragment(), NULL);
    glCompileShader(fragmentShader);
    if (!success) {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }


    /*Creating the program Shader*/
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();

    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    /*Testing PS compilation*/
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::COMPILATION_FAILED\n" << infoLog << std::endl;
    }


    /*Deleting shaders already used*/
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    /*Activating our shader*/
    glUseProgram(shaderProgram);


    /*How to interprets data*/
    /*(layout (location = 0),vec3,type of the vec,for [-1.0;1.0],stride worked with 0 too, offset to begin*/
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);


    /*Creating Vertex Array Object*/
    unsigned int VAO;
    glGenVertexArrays(1, &VAO);

    // 1. Lier le Vertex Array Object (VAO)
    glBindVertexArray(VAO);
    // 2. Copier les sommets dans un tampon pour qu’OpenGL les utilise
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 3. Initialiser les pointeurs d’attributs de sommets
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);


    /*Creating an EBO for tell the order of vertices to being draw*/
    unsigned int EBO;    
    glGenBuffers(1, &EBO);

    /*GL_ELEMENT_ARRAY_BUFFER for EBO*/
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


    /*Setting the view*/
    glViewport(0, 0, 800, 600);


    /*To get a thread style*/
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);


    /*Render Loop*/
    while (!glfwWindowShouldClose(window)){
        glClearColor(0.5f, 0.3f, 0.6f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        processInput(window);

        glUseProgram(shaderProgram);
        //glBindVertexArray(VAO);
        /*(Kind of primitive to use, begin of vertices tab, end of vertices tab)*/
        //glDrawArrays(GL_TRIANGLES, 0, 3);


        /*6 for length of EBO*/
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glfwPollEvents();
        glfwSwapBuffers(window);
    }


    glfwTerminate();


    return 0;
}


/*Resize*/
void framebuffer_size_callback(GLFWwindow* window, int width, int height){
    glViewport(0, 0, width, height);
}


/*Handle inputs*/
void processInput(GLFWwindow* window){
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

-shader.hpp:

#pragma once

class Shader {

public:
    Shader(std::string const& name) : name_(name){
        std::string tmp;
        std::ifstream stream("./shaders/" + name_ + ".fs");
        if(stream) {
            while (stream.good()) {
                tmp += stream.get();
            }
        }
        fragment_ = tmp.c_str();

        stream.close();

        tmp = "";

        stream.open("./shaders/" + name_ + ".vs");
        if(stream) {
            while (stream.good()) {
                tmp += stream.get();
            }
        }
        vertex_ = tmp.c_str();

        stream.close();
        std::cout << "Shader Initialization Print\n" << vertex_ << "\n\n";
    }

    void initialize(){
        if (name_.size() > 0) {
            std::string tmp;
            std::ifstream stream("./shaders/" + name_ + ".fs");
            if (stream) {
                while (stream.good()) {
                    tmp += stream.get();
                }
            }
            fragment_ = tmp.c_str();
            stream.close();

            tmp = "";

            stream.open("./shaders/" + name_ + ".vs");
            if (stream) {
                while (stream.good()) {
                    tmp += stream.get();
                }
            }
            vertex_ = tmp.c_str();
            stream.close();
        }
    }

    void setName(std::string const& name) {
        name_ = name;
    }

    std::string getName() {
        return name_;
    }

    void setFragment(std::string const& fragment) {
        fragment_ = fragment.c_str();
    }

    const GLchar* & getFragment() {
        return fragment_;
    }

    void setVertex(std::string const& vertex) {
        vertex_ = vertex.c_str();
    }

    const GLchar* & getVertex() {
        std::cout << "getVertex() Print\n" << vertex_ << "\n\n";
        return vertex_;
    }

private:
    std::string name_;
    const GLchar * vertex_;
    const GLchar * fragment_;
};

-head.h:

#pragma once

#include <iostream>
#include <fstream>
#include <string>

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include "shader.hpp"

-Trace исполнения

Shader Initialization Print
#version 330 core

layout (location = 0) in vec3 aPos;
void main()
{
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
} 

getVertex() Print
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦  

Main Print
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦  
getVertex() Print
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦  

ERROR::SHADER::VERTEX::COMPILATION_FAILED
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"

ERROR::SHADER::FRAGMENT::COMPILATION_FAILED
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"

ERROR::SHADER::PROGRAM::COMPILATION_FAILED
Vertex info
-----------
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
(0) : error C2003: incompatible options for link

Fragment info
-------------
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
(0) : error C2003: incompatible options for link

Собственно, я ожидаючтобы получить то, что печатают инициализацию шейдера везде, я вызываю свои getVertex() / getFragment() методы.

Ответы [ 2 ]

0 голосов
/ 12 июля 2019

Прежде всего, возникает проблема, когда вы читаете файл, который необходимо оценить stream.good() после того, как символ прочитан, но перед тем, как символ добавляется в строку. Обратите внимание, что .get устанавливает eofbit, когда не удается прочитать символ, но не когда читается th kast charater:

std::string tmp;
std::ifstream stream("./shaders/" + name_ + ".fs");

while (true) {
    char c = stream.get();
    if (!stream)
        break;
    tmp += c;
}

В любом случае, я рекомендую использовать std::istreambuf_iterator:

std::ifstream stream("./shaders/" + name_ + ".fs");
std::string tmp = std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());

getVertex и getFragment. Должен возвращать ссылку на указатель на символы кода шейдера (const GLchar*&). Таким образом, вы должны хранить код шейдера в атрибуте. Я рекомендую использовать код в std::string. Далее вам необходим атрибут типа const GLchar*, который содержит указатель на код и может быть возвращен по ссылке:

class Shader {
public:

   // ...

   void setVertex(std::string const& vertex) {
        vertex_ = vertex;
        vs_ptr_ = vertex_.c_str();
    }

    const GLchar*& getVertex() {
        return vs_ptr_;
    }

private:

    // ...

    std::string vertex_;
    const GLchar *vs_ptr_;
};

Весь класс выглядит так:

class Shader {

public:
    Shader(std::string const& name) 
        : name_(name){
        initialize();
    }

    void initialize(){
        if (name_.empty())
            return;

        std::ifstream stream("./shaders/" + name_ + ".fs");
        std::string tmp = std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>()); 
        stream.close();
        setFragment(tmp);

        stream.open("./shaders/" + name_ + ".vs");
        tmp = std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
        stream.close();
        setVertex(tmp);
    }

    void setName(std::string const& name) {
        name_ = name;
    }

    std::string getName() {
        return name_;
    }

    void setFragment(std::string const& fragment) {
        fragment_ = fragment;
        fs_ptr_ = fragment_.c_str();
    }

    const GLchar*& getFragment() {
        return fs_ptr_;
    }

    void setVertex(std::string const& vertex) {
        vertex_ = vertex;
        vs_ptr_ = vertex_.c_str();
    }

    const GLchar*& getVertex() {
        return vs_ptr_;
    }

private:
    std::string name_;
    std::string vertex_;
    std::string fragment_;
    const GLchar *vs_ptr_;
    const GLchar *fs_ptr_;
};
0 голосов
/ 12 июля 2019

Вот один из способов справиться с этим. Он использует string, а также сохраняет результат c_str() в этой строке. Дело в том, что сохраняя указатель и строку, на которой он основан, вы убедитесь, что указатель остается действительным до тех пор, пока строка действительна.

class Shader
{
public:
    void setVertex(std::string const& vertex) {
        vertex_ = vertex;
        vertexPtr_ = vertex_.c_str(); // this must be vertex_ not vertex, otherwise we have exactly the same problem as before
    }

    const GLchar* & getVertex() {
        std::cout << "getVertex() Print\n" << vertex_ << "\n\n";
        return vertexPtr_;
    }

private:
    string vertex_;
    const GLchar* vertexPtr_;
};

Это непроверенный код.

C ++ не является языком, в котором данные остаются действительными, пока они доступны (в отличие, например, от Java). Вы не можете программировать на C ++ без понимания времени жизни создаваемых вами объектов. Ваша программа правильно указала типы, но не смогла понять, что указатель был недействительным к тому времени, когда вы его использовали. Эта версия хранит строку и указатель на нее вместе , так что оба имеют одинаковое время жизни.

...