Question
I managed to wrap the texture on my pyramid but 2 sides don't show bricks but seem stretched to stripes. I can not find the
I managed to wrap the texture on my pyramid but 2 sides don't show bricks but seem stretched to stripes. I can not find the error in my code. Please help! Also I set a key light and a fill light from different angles but don't see much difference. Can you see it? I think the texture should be brown brick but the light makes everything just green. How can I change the texture is still brown but the light green? #include
// GLM Math Header inclusions #include
#include
using namespace std; // Standard namespace
/*Shader program Macro*/ #ifndef GLSL #define GLSL(Version, Source) "#version " #Version " core " #Source #endif
// Unnamed namespace namespace { const char* const WINDOW_TITLE = "Textured pyramid with light"; // Macro for window title
// Variables for window width and height const int WINDOW_WIDTH = 800; const int WINDOW_HEIGHT = 600;
// Stores the GL data relative to a given mesh struct GLMesh { GLuint vao; // Handle for the vertex array object GLuint vbo; // Handle for the vertex buffer object GLuint nVertices; // Number of indices of the mesh };
// Main GLFW window GLFWwindow* gWindow = nullptr; // Triangle mesh data GLMesh gMesh;
// Texture GLuint gTextureId; glm::vec2 gUVScale(5.0f, 5.0f); GLint gTexWrapMode = GL_REPEAT;
// Shader program GLuint gProgramId; GLuint gLampProgramId;
// camera Camera gCamera(glm::vec3(1.0f, 1.0f, 3.0f)); float gLastX = WINDOW_WIDTH / 2.0f; float gLastY = WINDOW_HEIGHT / 2.0f; bool gFirstMouse = true;
// timing float gDeltaTime = 0.0f; // time between current frame and last frame float gLastFrame = 0.0f;
// Subject position and scale glm::vec3 gPyramidPosition(0.0f, 0.0f, 0.0f); glm::vec3 gPyramidScale(2.0f);
// Pyramid and light color //m::vec3 gObjectColor(0.6f, 0.5f, 0.75f); glm::vec3 gObjectColor(1.f, 0.2f, 0.0f); glm::vec3 gLightColor(0.0f, 1.0f, 0.0f);
// Key Light position and scale glm::vec3 gLightPosition(1.5f, 7.5f, 4.0f); //adjusts the key light glm::vec3 gLightScale(0.3f); }
/* User-defined Function prototypes to: * initialize the program, set the window size, * redraw graphics on the window when resized, * and render graphics on the screen */ bool UInitialize(int, char*[], GLFWwindow** window); void UResizeWindow(GLFWwindow* window, int width, int height); void UProcessInput(GLFWwindow* window); void UMousePositionCallback(GLFWwindow* window, double xpos, double ypos); void UMouseScrollCallback(GLFWwindow* window, double xoffset, double yoffset); void UMouseButtonCallback(GLFWwindow* window, int button, int action, int mods); void UCreateMesh(GLMesh &mesh); void UDestroyMesh(GLMesh &mesh); bool UCreateTexture(const char* filename, GLuint &textureId); void UDestroyTexture(GLuint textureId); void URender(); bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint &programId); void UDestroyShaderProgram(GLuint programId);
/* Pyramid Vertex Shader Source Code*/ const GLchar * pyramidVertexShaderSource = GLSL(440, layout (location = 0) in vec3 position; layout(location = 1) in vec3 normal; // VAP position 1 for normals layout (location = 2) in vec2 textureCoordinate;
out vec3 vertexNormal; // For outgoing normals to fragment shader out vec3 vertexFragmentPos; // For outgoing color / pixels to fragment shader out vec2 vertexTextureCoordinate;
//Global variables for the transform matrices uniform mat4 model; uniform mat4 view; uniform mat4 projection;
void main() { gl_Position = projection * view * model * vec4(position, 1.0f); // transforms vertices to clip coordinates
vertexFragmentPos = vec3(model * vec4(position, 1.0f)); // Gets fragment / pixel position in world space only (exclude view and projection)
vertexNormal = mat3(transpose(inverse(model))) * normal; // get normal vectors in world space only and exclude normal translation properties
vertexTextureCoordinate = textureCoordinate; } );
/* Pyramid Fragment Shader Source Code*/ const GLchar * pyramidFragmentShaderSource = GLSL(440,
in vec3 vertexNormal; // For incoming normals in vec3 vertexFragmentPos; // For incoming fragment position in vec2 vertexTextureCoordinate;
out vec4 fragmentColor;
// Uniform / Global variables for object color, key light color, key light position, and camera/view position uniform vec3 objectColor; uniform vec3 lightColor; uniform vec3 lightPos; uniform vec3 viewPosition; uniform sampler2D uTexture; uniform vec2 uvScale;
void main() { // Adjust the strengths for key and fill lights float keyLightStrength = 1.0; // 100% float fillLightStrength = 0.1; // 10%
// Ambient lighting float ambientStrength = 3.0f; vec3 ambient = ambientStrength * lightColor;
// Diffuse lighting (key light) vec3 norm = normalize(vertexNormal); vec3 lightDir = normalize(lightPos - vertexFragmentPos); float diff = max(dot(norm, lightDir), 0.0); vec3 diffuse = keyLightStrength * diff * lightColor;
// Fill light contribution (reduce contrast) vec3 fillLightPos = vec3(4.0, 2.0, 0.0); // Adjust the position of the fill light vec3 fillLightDir = normalize(fillLightPos - vertexFragmentPos); vec3 fillDiffuse = fillLightStrength * max(dot(norm, fillLightDir), 0.0) * lightColor;
// Specular lighting float specularStrength = 0.5; vec3 viewDir = normalize(viewPosition - vertexFragmentPos); vec3 reflectDir = reflect(-lightDir, norm); float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0); vec3 specular = specularStrength * spec * lightColor;
// Combine key and fill light contributions vec3 result = (ambient + diffuse + specular) * objectColor.rgb + fillDiffuse;
fragmentColor = texture(uTexture, vertexTextureCoordinate * uvScale) * vec4(result, 1.0); } );
// Images are loaded with Y axis going down, but OpenGL's Y axis goes up, so let's flip it void flipImageVertically(unsigned char *image, int width, int height, int channels) { for (int j = 0; j < height / 2; ++j) { int index1 = j * width * channels; int index2 = (height - 1 - j) * width * channels;
for (int i = width * channels; i > 0; --i) { unsigned char tmp = image[index1]; image[index1] = image[index2]; image[index2] = tmp; ++index1; ++index2; } } }
int main(int argc, char* argv[]) { if (!UInitialize(argc, argv, &gWindow)) return EXIT_FAILURE;
//build the mesh UCreateMesh(gMesh); // Calls the function to create the Vertex Buffer Object
// build the shader program if (!UCreateShaderProgram(pyramidVertexShaderSource, pyramidFragmentShaderSource, gProgramId)) return EXIT_FAILURE;
// Load texture const char * texFilename = "../../resources/textures/wall.jpg"; if (!UCreateTexture(texFilename, gTextureId)) { cout << "Failed to load texture " << texFilename << endl; return EXIT_FAILURE; } // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) glUseProgram(gProgramId); // We set the texture as texture unit 0 glUniform1i(glGetUniformLocation(gProgramId, "uTexture"), 0);
// Sets the background color of the window to black (it will be implicitely used by glClear) glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// render loop // ----------- while (!glfwWindowShouldClose(gWindow)) { // per-frame timing // -------------------- float currentFrame = glfwGetTime(); gDeltaTime = currentFrame - gLastFrame; gLastFrame = currentFrame;
// input // ----- UProcessInput(gWindow);
// Render this frame URender();
glfwPollEvents(); }
// Release mesh data UDestroyMesh(gMesh);
// Release texture UDestroyTexture(gTextureId);
// Release shader program UDestroyShaderProgram(gProgramId);
exit(EXIT_SUCCESS); // Terminates the program successfully }
// Initialize GLFW, GLEW, and create a window bool UInitialize(int argc, char* argv[], GLFWwindow** window) { // GLFW: initialize and configure // ------------------------------ glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif
// GLFW: window creation // --------------------- *window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE, NULL, NULL); if (*window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return false; } glfwMakeContextCurrent(*window); glfwSetFramebufferSizeCallback(*window, UResizeWindow); glfwSetCursorPosCallback(*window, UMousePositionCallback); glfwSetScrollCallback(*window, UMouseScrollCallback); glfwSetMouseButtonCallback(*window, UMouseButtonCallback);
// tell GLFW to capture our mouse glfwSetInputMode(*window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// GLEW: initialize // ---------------- // Note: if using GLEW version 1.13 or earlier glewExperimental = GL_TRUE; GLenum GlewInitResult = glewInit();
if (GLEW_OK != GlewInitResult) { std::cerr << glewGetErrorString(GlewInitResult) << std::endl; return false; }
// Displays GPU OpenGL version cout << "INFO: OpenGL Version: " << glGetString(GL_VERSION) << endl;
return true; }
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly void UProcessInput(GLFWwindow* window) { static const float cameraSpeed = 2.5f;
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) gCamera.ProcessKeyboard(FORWARD, gDeltaTime); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) gCamera.ProcessKeyboard(BACKWARD, gDeltaTime); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) gCamera.ProcessKeyboard(LEFT, gDeltaTime); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) gCamera.ProcessKeyboard(RIGHT, gDeltaTime);
if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS && gTexWrapMode != GL_REPEAT) { glBindTexture(GL_TEXTURE_2D, gTextureId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glBindTexture(GL_TEXTURE_2D, 0);
gTexWrapMode = GL_REPEAT;
cout << "Current Texture Wrapping Mode: REPEAT" << endl; } else if (glfwGetKey(window, GLFW_KEY_2) == GLFW_PRESS && gTexWrapMode != GL_MIRRORED_REPEAT) { glBindTexture(GL_TEXTURE_2D, gTextureId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); glBindTexture(GL_TEXTURE_2D, 0);
gTexWrapMode = GL_MIRRORED_REPEAT;
cout << "Current Texture Wrapping Mode: MIRRORED REPEAT" << endl; } else if (glfwGetKey(window, GLFW_KEY_3) == GLFW_PRESS && gTexWrapMode != GL_CLAMP_TO_EDGE) { glBindTexture(GL_TEXTURE_2D, gTextureId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_2D, 0);
gTexWrapMode = GL_CLAMP_TO_EDGE;
cout << "Current Texture Wrapping Mode: CLAMP TO EDGE" << endl; } else if (glfwGetKey(window, GLFW_KEY_4) == GLFW_PRESS && gTexWrapMode != GL_CLAMP_TO_BORDER) { float color[] = {1.0f, 0.0f, 1.0f, 1.0f}; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
glBindTexture(GL_TEXTURE_2D, gTextureId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glBindTexture(GL_TEXTURE_2D, 0);
gTexWrapMode = GL_CLAMP_TO_BORDER;
cout << "Current Texture Wrapping Mode: CLAMP TO BORDER" << endl; }
if (glfwGetKey(window, GLFW_KEY_RIGHT_BRACKET) == GLFW_PRESS) { gUVScale += 0.1f; cout << "Current scale (" << gUVScale[0] << ", " << gUVScale[1] << ")" << endl; } else if (glfwGetKey(window, GLFW_KEY_LEFT_BRACKET) == GLFW_PRESS) { gUVScale -= 0.1f; cout << "Current scale (" << gUVScale[0] << ", " << gUVScale[1] << ")" << endl; } }
// glfw: whenever the window size changed (by OS or user resize) this callback function executes void UResizeWindow(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); }
// glfw: whenever the mouse moves, this callback is called // ------------------------------------------------------- void UMousePositionCallback(GLFWwindow* window, double xpos, double ypos) { if (gFirstMouse) { gLastX = xpos; gLastY = ypos; gFirstMouse = false; }
float xoffset = xpos - gLastX; float yoffset = gLastY - ypos; // reversed since y-coordinates go from bottom to top
gLastX = xpos; gLastY = ypos;
gCamera.ProcessMouseMovement(xoffset, yoffset); }
// glfw: whenever the mouse scroll wheel scrolls, this callback is called // ---------------------------------------------------------------------- void UMouseScrollCallback(GLFWwindow* window, double xoffset, double yoffset) { gCamera.ProcessMouseScroll(yoffset); }
// glfw: handle mouse button events // -------------------------------- void UMouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { switch (button) { case GLFW_MOUSE_BUTTON_LEFT: { if (action == GLFW_PRESS) cout << "Left mouse button pressed" << endl; else cout << "Left mouse button released" << endl; } break;
case GLFW_MOUSE_BUTTON_MIDDLE: { if (action == GLFW_PRESS) cout << "Middle mouse button pressed" << endl; else cout << "Middle mouse button released" << endl; } break;
case GLFW_MOUSE_BUTTON_RIGHT: { if (action == GLFW_PRESS) cout << "Right mouse button pressed" << endl; else cout << "Right mouse button released" << endl; } break;
default: cout << "Unhandled mouse button event" << endl; break; } }
// Functioned called to render a frame void URender() { // Enable z-depth glEnable(GL_DEPTH_TEST); // Clear the frame and z buffers glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float scaler = 1.0f; glm::mat4 scale = glm::scale(glm::vec3(scaler)); glm::mat4 rotation = glm::rotate(glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)); // Rotate by 45 degrees in the x-axis glm::vec3 location = glm::vec3(0.0f, 0.0f, 0.0f); glm::mat4 translation = glm::translate(location); glm::mat4 model = translation * rotation * scale;
// camera/view transformation glm::mat4 view = gCamera.GetViewMatrix();
// Creates a perspective projection glm::mat4 projection = glm::perspective(glm::radians(gCamera.Zoom), (GLfloat)WINDOW_WIDTH / (GLfloat)WINDOW_HEIGHT, 0.1f, 100.0f);
// Set the shader to be used glUseProgram(gProgramId);
// Retrieves and passes transform matrices to the Shader program GLint modelLoc = glGetUniformLocation(gProgramId, "model"); GLint viewLoc = glGetUniformLocation(gProgramId, "view"); GLint projLoc = glGetUniformLocation(gProgramId, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
// Set lighting uniforms GLint objectColorLoc = glGetUniformLocation(gProgramId, "objectColor"); GLint lightColorLoc = glGetUniformLocation(gProgramId, "lightColor"); GLint lightPosLoc = glGetUniformLocation(gProgramId, "lightPos"); GLint viewPosLoc = glGetUniformLocation(gProgramId, "viewPosition");
glUniform3fv(objectColorLoc, 1, glm::value_ptr(gObjectColor)); glUniform3fv(lightColorLoc, 1, glm::value_ptr(gLightColor)); glUniform3fv(lightPosLoc, 1, glm::value_ptr(gLightPosition)); glUniform3fv(viewPosLoc, 1, glm::value_ptr(gCamera.Position));
GLint UVScaleLoc = glGetUniformLocation(gProgramId, "uvScale"); glUniform2fv(UVScaleLoc, 1, glm::value_ptr(gUVScale));
// Activate the VBOs contained within the mesh's VAO glBindVertexArray(gMesh.vao);
// bind textures on corresponding texture units glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, gTextureId);
// Draws the triangles glDrawArrays(GL_TRIANGLES, 0, gMesh.nVertices);
// Deactivate the Vertex Array Object glBindVertexArray(0);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) glfwSwapBuffers(gWindow); // Flips the the back buffer with the front buffer every frame. }
// Implements the UCreateMesh function void UCreateMesh(GLMesh &mesh) { GLfloat verts[] = { // Positions // Texture Coordinates 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, // Front Vertex 0 -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, // Left Bottom Vertex 1 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Left Top Vertex 2
0.0f, 0.0f, 2.0f, 0.0f, 0.0f, // Front Vertex 0 -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, // Left Bottom Vertex 1 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // Right Bottom Vertex 3
0.0f, 0.0f, 2.0f, 0.0f, 0.0f, // Front Vertex 0 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // Right Bottom Vertex 3 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // Right Top Vertex 4
0.0f, 0.0f, 2.0f, 0.0f, 0.0f, // Front Vertex 0 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Left Top Vertex 2 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // Right Top Vertex 4
1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // Right Top Vertex 4 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Left Top Vertex 2 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // Right Bottom Vertex 3 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // Right Bottom Vertex 3 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Left Top Vertex 2 -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, // Left Bottom Vertex 1 };
// Calculate normals std::vector
glm::vec3 normal = glm::normalize(glm::cross(v2 - v1, v3 - v1));
normals.push_back(normal); normals.push_back(normal); normals.push_back(normal); }
const GLuint floatsPerVertex = 3; const GLuint floatsPerUV = 2;
mesh.nVertices = sizeof(verts) / (sizeof(verts[0]) * (floatsPerVertex + floatsPerUV));
glGenVertexArrays(1, &mesh.vao); glBindVertexArray(mesh.vao);
glGenBuffers(1, &mesh.vbo); glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
GLint stride = sizeof(float) * (floatsPerVertex + floatsPerUV);
glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0); glEnableVertexAttribArray(0);
glVertexAttribPointer(2, floatsPerUV, GL_FLOAT, GL_FALSE, stride, (void*)(sizeof(float) * floatsPerVertex)); glEnableVertexAttribArray(2);
// Generate and bind a normal buffer GLuint normalBuffer; glGenBuffers(1, &normalBuffer); glBindBuffer(GL_ARRAY_BUFFER, normalBuffer); glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW);
// Set up the normal attribute glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (void*)0); glEnableVertexAttribArray(1);
// Vertex Data /*GLfloat verts[] = { //Positions //Texture Coordinates 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, // Front Vertex 0 -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, // Left Bottom Vertex 1 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Left Top Vertex 2
0.0f, 0.0f, 2.0f, 0.0f, 0.0f, // Front Vertex 0 -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, // Left Bottom Vertex 1 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // Right Bottom Vertex 3
0.0f, 0.0f, 2.0f, 0.0f, 0.0f, // Front Vertex 0 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // Right Bottom Vertex 3 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // Right Top Vertex 4
0.0f, 0.0f, 2.0f, 0.0f, 0.0f, // Front Vertex 0 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Left Top Vertex 2 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // Right Top Vertex 4
1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // Right Top Vertex 4 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Left Top Vertex 2 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // Right Bottom Vertex 3 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // Right Bottom Vertex 3 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Left Top Vertex 2 -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, // Left Bottom Vertex 1 };
const GLuint floatsPerVertex = 3; const GLuint floatsPerUV = 2;
mesh.nVertices = sizeof(verts) / (sizeof(verts[0]) * (floatsPerVertex + floatsPerUV));
glGenVertexArrays(1, &mesh.vao); // we can also generate multiple VAOs or buffers at the same time glBindVertexArray(mesh.vao);
// Create VBO glGenBuffers(1, &mesh.vbo); glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo); // Activates the buffer glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); // Sends vertex or coordinate data to the GPU
// Strides between vertex coordinates GLint stride = sizeof(float) * (floatsPerVertex + floatsPerUV);
// Create Vertex Attribute Pointers glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0); glEnableVertexAttribArray(0);
glVertexAttribPointer(2, floatsPerUV, GL_FLOAT, GL_FALSE, stride, (void*)(sizeof(float) * floatsPerVertex)); glEnableVertexAttribArray(2);*/ }
void UDestroyMesh(GLMesh &mesh) { glDeleteVertexArrays(1, &mesh.vao); glDeleteBuffers(1, &mesh.vbo); }
/*Generate and load the texture*/ bool UCreateTexture(const char* filename, GLuint &textureId) { int width, height, channels; unsigned char *image = stbi_load(filename, &width, &height, &channels, 0); if (image) { flipImageVertically(image, width, height, channels);
glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId);
// set the texture wrapping parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // set texture filtering parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (channels == 3) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); else if (channels == 4) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); else { cout << "Not implemented to handle image with " << channels << " channels" << endl; return false; }
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(image); glBindTexture(GL_TEXTURE_2D, 0); // Unbind the texture
return true; }
// Error loading the image return false; }
void UDestroyTexture(GLuint textureId) { glGenTextures(1, &textureId); }
// Implements the UCreateShaders function bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint &programId) { // Compilation and linkage error reporting int success = 0; char infoLog[512];
// Create a Shader program object. programId = glCreateProgram();
// Create the vertex and fragment shader objects GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER); GLuint fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
// Retrive the shader source glShaderSource(vertexShaderId, 1, &vtxShaderSource, NULL); glShaderSource(fragmentShaderId, 1, &fragShaderSource, NULL);
// Compile the vertex shader, and print compilation errors (if any) glCompileShader(vertexShaderId); // compile the vertex shader // check for shader compile errors glGetShaderiv(vertexShaderId, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vertexShaderId, 512, NULL, infoLog); std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED " << infoLog << std::endl;
return false; }
glCompileShader(fragmentShaderId); // compile the fragment shader // check for shader compile errors glGetShaderiv(fragmentShaderId, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragmentShaderId, sizeof(infoLog), NULL, infoLog); std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED " << infoLog << std::endl;
return false; }
// Attached compiled shaders to the shader program glAttachShader(programId, vertexShaderId); glAttachShader(programId, fragmentShaderId);
glLinkProgram(programId); // links the shader program // check for linking errors glGetProgramiv(programId, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(programId, sizeof(infoLog), NULL, infoLog); std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED " << infoLog << std::endl;
return false; }
glUseProgram(programId); // Uses the shader program
return true; }
void UDestroyShaderProgram(GLuint programId) { glDeleteProgram(programId); }
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started