Spheres model matrix generation fix

Fix of integer division resulting in some spheres being rendered at same position.
Removed redundant float cast as all operands are being promoted to double anyways.
This commit is contained in:
d3BugErr
2018-04-10 11:23:09 +03:00
committed by GitHub
parent c4c5fea218
commit d702e0c6bf

View File

@@ -1,373 +1,376 @@
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <stb_image.h> #include <stb_image.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <learnopengl/filesystem.h> #include <learnopengl/filesystem.h>
#include <learnopengl/shader.h> #include <learnopengl/shader.h>
#include <learnopengl/camera.h> #include <learnopengl/camera.h>
#include <learnopengl/model.h> #include <learnopengl/model.h>
#include <iostream> #include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height); void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos); void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window); void processInput(GLFWwindow *window);
unsigned int loadTexture(const char *path); unsigned int loadTexture(const char *path);
void renderSphere(); void renderSphere();
// settings // settings
const unsigned int SCR_WIDTH = 1280; const unsigned int SCR_WIDTH = 1280;
const unsigned int SCR_HEIGHT = 720; const unsigned int SCR_HEIGHT = 720;
// camera // camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = 800.0f / 2.0; float lastX = 800.0f / 2.0;
float lastY = 600.0 / 2.0; float lastY = 600.0 / 2.0;
bool firstMouse = true; bool firstMouse = true;
// timing // timing
float deltaTime = 0.0f; float deltaTime = 0.0f;
float lastFrame = 0.0f; float lastFrame = 0.0f;
int main() int main()
{ {
// glfw: initialize and configure // glfw: initialize and configure
// ------------------------------ // ------------------------------
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
#ifdef __APPLE__
// glfw window creation glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
// -------------------- #endif
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
glfwMakeContextCurrent(window); // glfw window creation
if (window == NULL) // --------------------
{ GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
std::cout << "Failed to create GLFW window" << std::endl; glfwMakeContextCurrent(window);
glfwTerminate(); if (window == NULL)
return -1; {
} std::cout << "Failed to create GLFW window" << std::endl;
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glfwTerminate();
glfwSetCursorPosCallback(window, mouse_callback); return -1;
glfwSetScrollCallback(window, scroll_callback); }
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// tell GLFW to capture our mouse glfwSetCursorPosCallback(window, mouse_callback);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetScrollCallback(window, scroll_callback);
// glad: load all OpenGL function pointers // tell GLFW to capture our mouse
// --------------------------------------- glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{ // glad: load all OpenGL function pointers
std::cout << "Failed to initialize GLAD" << std::endl; // ---------------------------------------
return -1; if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
} {
std::cout << "Failed to initialize GLAD" << std::endl;
// configure global opengl state return -1;
// ----------------------------- }
glEnable(GL_DEPTH_TEST);
// configure global opengl state
// build and compile shaders // -----------------------------
// ------------------------- glEnable(GL_DEPTH_TEST);
Shader shader("1.1.pbr.vs", "1.1.pbr.fs");
// build and compile shaders
shader.use(); // -------------------------
shader.setVec3("albedo", 0.5f, 0.0f, 0.0f); Shader shader("1.1.pbr.vs", "1.1.pbr.fs");
shader.setFloat("ao", 1.0f);
shader.use();
// lights shader.setVec3("albedo", 0.5f, 0.0f, 0.0f);
// ------ shader.setFloat("ao", 1.0f);
glm::vec3 lightPositions[] = {
glm::vec3(-10.0f, 10.0f, 10.0f), // lights
glm::vec3( 10.0f, 10.0f, 10.0f), // ------
glm::vec3(-10.0f, -10.0f, 10.0f), glm::vec3 lightPositions[] = {
glm::vec3( 10.0f, -10.0f, 10.0f), glm::vec3(-10.0f, 10.0f, 10.0f),
}; glm::vec3( 10.0f, 10.0f, 10.0f),
glm::vec3 lightColors[] = { glm::vec3(-10.0f, -10.0f, 10.0f),
glm::vec3(300.0f, 300.0f, 300.0f), glm::vec3( 10.0f, -10.0f, 10.0f),
glm::vec3(300.0f, 300.0f, 300.0f), };
glm::vec3(300.0f, 300.0f, 300.0f), glm::vec3 lightColors[] = {
glm::vec3(300.0f, 300.0f, 300.0f) glm::vec3(300.0f, 300.0f, 300.0f),
}; glm::vec3(300.0f, 300.0f, 300.0f),
int nrRows = 7; glm::vec3(300.0f, 300.0f, 300.0f),
int nrColumns = 7; glm::vec3(300.0f, 300.0f, 300.0f)
float spacing = 2.5; };
int nrRows = 7;
// initialize static shader uniforms before rendering int nrColumns = 7;
// -------------------------------------------------- float spacing = 2.5;
glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
shader.use(); // initialize static shader uniforms before rendering
shader.setMat4("projection", projection); // --------------------------------------------------
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
// render loop shader.use();
// ----------- shader.setMat4("projection", projection);
while (!glfwWindowShouldClose(window))
{ // render loop
// per-frame time logic // -----------
// -------------------- while (!glfwWindowShouldClose(window))
float currentFrame = glfwGetTime(); {
deltaTime = currentFrame - lastFrame; // per-frame time logic
lastFrame = currentFrame; // --------------------
float currentFrame = glfwGetTime();
// input deltaTime = currentFrame - lastFrame;
// ----- lastFrame = currentFrame;
processInput(window);
// input
// render // -----
// ------ processInput(window);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // render
// ------
shader.use(); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glm::mat4 view = camera.GetViewMatrix(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.setMat4("view", view);
shader.setVec3("camPos", camera.Position); shader.use();
glm::mat4 view = camera.GetViewMatrix();
// render rows*column number of spheres with varying metallic/roughness values scaled by rows and columns respectively shader.setMat4("view", view);
glm::mat4 model; shader.setVec3("camPos", camera.Position);
for (unsigned int row = 0; row < nrRows; ++row)
{ // render rows*column number of spheres with varying metallic/roughness values scaled by rows and columns respectively
shader.setFloat("metallic", (float)row / (float)nrRows); glm::mat4 model;
for (unsigned int col = 0; col < nrColumns; ++col) for (unsigned int row = 0; row < nrRows; ++row)
{ {
// we clamp the roughness to 0.025 - 1.0 as perfectly smooth surfaces (roughness of 0.0) tend to look a bit off shader.setFloat("metallic", (float)row / (float)nrRows);
// on direct lighting. for (unsigned int col = 0; col < nrColumns; ++col)
shader.setFloat("roughness", glm::clamp((float)col / (float)nrColumns, 0.05f, 1.0f)); {
// we clamp the roughness to 0.025 - 1.0 as perfectly smooth surfaces (roughness of 0.0) tend to look a bit off
model = glm::mat4(); // on direct lighting.
model = glm::translate(model, glm::vec3( shader.setFloat("roughness", glm::clamp((float)col / (float)nrColumns, 0.05f, 1.0f));
(float)(col - (nrColumns / 2)) * spacing,
(float)(row - (nrRows / 2)) * spacing, model = glm::mat4();
0.0f model = glm::translate(model, glm::vec3(
)); (col - (nrColumns / 2.)) * spacing,
shader.setMat4("model", model); (row - (nrRows / 2.)) * spacing,
renderSphere(); 0.0f
} ));
} shader.setMat4("model", model);
renderSphere();
// render light source (simply re-render sphere at light positions) }
// this looks a bit off as we use the same shader, but it'll make their positions obvious and }
// keeps the codeprint small.
for (unsigned int i = 0; i < sizeof(lightPositions) / sizeof(lightPositions[0]); ++i) // render light source (simply re-render sphere at light positions)
{ // this looks a bit off as we use the same shader, but it'll make their positions obvious and
glm::vec3 newPos = lightPositions[i] + glm::vec3(sin(glfwGetTime() * 5.0) * 5.0, 0.0, 0.0); // keeps the codeprint small.
newPos = lightPositions[i]; for (unsigned int i = 0; i < sizeof(lightPositions) / sizeof(lightPositions[0]); ++i)
shader.setVec3("lightPositions[" + std::to_string(i) + "]", newPos); {
shader.setVec3("lightColors[" + std::to_string(i) + "]", lightColors[i]); glm::vec3 newPos = lightPositions[i] + glm::vec3(sin(glfwGetTime() * 5.0) * 5.0, 0.0, 0.0);
newPos = lightPositions[i];
model = glm::mat4(); shader.setVec3("lightPositions[" + std::to_string(i) + "]", newPos);
model = glm::translate(model, newPos); shader.setVec3("lightColors[" + std::to_string(i) + "]", lightColors[i]);
model = glm::scale(model, glm::vec3(0.5f));
shader.setMat4("model", model); model = glm::mat4();
renderSphere(); model = glm::translate(model, newPos);
} model = glm::scale(model, glm::vec3(0.5f));
shader.setMat4("model", model);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) renderSphere();
// ------------------------------------------------------------------------------- }
glfwSwapBuffers(window);
glfwPollEvents(); // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
} // -------------------------------------------------------------------------------
glfwSwapBuffers(window);
// glfw: terminate, clearing all previously allocated GLFW resources. glfwPollEvents();
// ------------------------------------------------------------------ }
glfwTerminate();
return 0; // glfw: terminate, clearing all previously allocated GLFW resources.
} // ------------------------------------------------------------------
glfwTerminate();
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly return 0;
// --------------------------------------------------------------------------------------------------------- }
void processInput(GLFWwindow *window)
{ // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) // ---------------------------------------------------------------------------------------------------------
glfwSetWindowShouldClose(window, true); void processInput(GLFWwindow *window)
{
float cameraSpeed = 2.5 * deltaTime; if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) glfwSetWindowShouldClose(window, true);
camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) float cameraSpeed = 2.5 * deltaTime;
camera.ProcessKeyboard(BACKWARD, deltaTime); if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera.ProcessKeyboard(FORWARD, deltaTime);
camera.ProcessKeyboard(LEFT, deltaTime); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera.ProcessKeyboard(BACKWARD, deltaTime);
camera.ProcessKeyboard(RIGHT, deltaTime); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
} camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
// glfw: whenever the window size changed (by OS or user resize) this callback function executes camera.ProcessKeyboard(RIGHT, deltaTime);
// --------------------------------------------------------------------------------------------- }
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{ // glfw: whenever the window size changed (by OS or user resize) this callback function executes
// make sure the viewport matches the new window dimensions; note that width and // ---------------------------------------------------------------------------------------------
// height will be significantly larger than specified on retina displays. void framebuffer_size_callback(GLFWwindow* window, int width, int height)
glViewport(0, 0, width, height); {
} // make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
// glfw: whenever the mouse moves, this callback is called }
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{ // glfw: whenever the mouse moves, this callback is called
if (firstMouse) // -------------------------------------------------------
{ void mouse_callback(GLFWwindow* window, double xpos, double ypos)
lastX = xpos; {
lastY = ypos; if (firstMouse)
firstMouse = false; {
} lastX = xpos;
lastY = ypos;
float xoffset = xpos - lastX; firstMouse = false;
float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top }
lastX = xpos; float xoffset = xpos - lastX;
lastY = ypos; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
camera.ProcessMouseMovement(xoffset, yoffset); lastX = xpos;
} lastY = ypos;
// glfw: whenever the mouse scroll wheel scrolls, this callback is called camera.ProcessMouseMovement(xoffset, yoffset);
// ---------------------------------------------------------------------- }
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{ // glfw: whenever the mouse scroll wheel scrolls, this callback is called
camera.ProcessMouseScroll(yoffset); // ----------------------------------------------------------------------
} void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
// renders (and builds at first invocation) a sphere camera.ProcessMouseScroll(yoffset);
// ------------------------------------------------- }
unsigned int sphereVAO = 0;
unsigned int indexCount; // renders (and builds at first invocation) a sphere
void renderSphere() // -------------------------------------------------
{ unsigned int sphereVAO = 0;
if (sphereVAO == 0) unsigned int indexCount;
{ void renderSphere()
glGenVertexArrays(1, &sphereVAO); {
if (sphereVAO == 0)
unsigned int vbo, ebo; {
glGenBuffers(1, &vbo); glGenVertexArrays(1, &sphereVAO);
glGenBuffers(1, &ebo);
unsigned int vbo, ebo;
std::vector<glm::vec3> positions; glGenBuffers(1, &vbo);
std::vector<glm::vec2> uv; glGenBuffers(1, &ebo);
std::vector<glm::vec3> normals;
std::vector<unsigned int> indices; std::vector<glm::vec3> positions;
std::vector<glm::vec2> uv;
const unsigned int X_SEGMENTS = 64; std::vector<glm::vec3> normals;
const unsigned int Y_SEGMENTS = 64; std::vector<unsigned int> indices;
const float PI = 3.14159265359;
for (unsigned int y = 0; y <= Y_SEGMENTS; ++y) const unsigned int X_SEGMENTS = 64;
{ const unsigned int Y_SEGMENTS = 64;
for (unsigned int x = 0; x <= X_SEGMENTS; ++x) const float PI = 3.14159265359;
{ for (unsigned int y = 0; y <= Y_SEGMENTS; ++y)
float xSegment = (float)x / (float)X_SEGMENTS; {
float ySegment = (float)y / (float)Y_SEGMENTS; for (unsigned int x = 0; x <= X_SEGMENTS; ++x)
float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI); {
float yPos = std::cos(ySegment * PI); float xSegment = (float)x / (float)X_SEGMENTS;
float zPos = std::sin(xSegment * 2.0f * PI) * std::sin(ySegment * PI); float ySegment = (float)y / (float)Y_SEGMENTS;
float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
positions.push_back(glm::vec3(xPos, yPos, zPos)); float yPos = std::cos(ySegment * PI);
uv.push_back(glm::vec2(xSegment, ySegment)); float zPos = std::sin(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
normals.push_back(glm::vec3(xPos, yPos, zPos));
} positions.push_back(glm::vec3(xPos, yPos, zPos));
} uv.push_back(glm::vec2(xSegment, ySegment));
normals.push_back(glm::vec3(xPos, yPos, zPos));
bool oddRow = false; }
for (int y = 0; y < Y_SEGMENTS; ++y) }
{
if (!oddRow) // even rows: y == 0, y == 2; and so on bool oddRow = false;
{ for (int y = 0; y < Y_SEGMENTS; ++y)
for (int x = 0; x <= X_SEGMENTS; ++x) {
{ if (!oddRow) // even rows: y == 0, y == 2; and so on
indices.push_back(y * (X_SEGMENTS + 1) + x); {
indices.push_back((y + 1) * (X_SEGMENTS + 1) + x); for (int x = 0; x <= X_SEGMENTS; ++x)
} {
} indices.push_back(y * (X_SEGMENTS + 1) + x);
else indices.push_back((y + 1) * (X_SEGMENTS + 1) + x);
{ }
for (int x = X_SEGMENTS; x >= 0; --x) }
{ else
indices.push_back((y + 1) * (X_SEGMENTS + 1) + x); {
indices.push_back(y * (X_SEGMENTS + 1) + x); for (int x = X_SEGMENTS; x >= 0; --x)
} {
} indices.push_back((y + 1) * (X_SEGMENTS + 1) + x);
oddRow = !oddRow; indices.push_back(y * (X_SEGMENTS + 1) + x);
} }
indexCount = indices.size(); }
oddRow = !oddRow;
std::vector<float> data; }
for (int i = 0; i < positions.size(); ++i) indexCount = indices.size();
{
data.push_back(positions[i].x); std::vector<float> data;
data.push_back(positions[i].y); for (int i = 0; i < positions.size(); ++i)
data.push_back(positions[i].z); {
if (uv.size() > 0) data.push_back(positions[i].x);
{ data.push_back(positions[i].y);
data.push_back(uv[i].x); data.push_back(positions[i].z);
data.push_back(uv[i].y); if (uv.size() > 0)
} {
if (normals.size() > 0) data.push_back(uv[i].x);
{ data.push_back(uv[i].y);
data.push_back(normals[i].x); }
data.push_back(normals[i].y); if (normals.size() > 0)
data.push_back(normals[i].z); {
} data.push_back(normals[i].x);
} data.push_back(normals[i].y);
glBindVertexArray(sphereVAO); data.push_back(normals[i].z);
glBindBuffer(GL_ARRAY_BUFFER, vbo); }
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(float), &data[0], GL_STATIC_DRAW); }
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBindVertexArray(sphereVAO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, vbo);
float stride = (3 + 2 + 3) * sizeof(float); glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(float), &data[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1); float stride = (3 + 2 + 3) * sizeof(float);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void*)(3 * sizeof(float))); glEnableVertexAttribArray(0);
glEnableVertexAttribArray(2); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, stride, (void*)(5 * sizeof(float))); glEnableVertexAttribArray(1);
} glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glBindVertexArray(sphereVAO); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, stride, (void*)(5 * sizeof(float)));
glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_INT, 0); }
}
glBindVertexArray(sphereVAO);
// utility function for loading a 2D texture from file glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_INT, 0);
// --------------------------------------------------- }
unsigned int loadTexture(char const * path)
{ // utility function for loading a 2D texture from file
unsigned int textureID; // ---------------------------------------------------
glGenTextures(1, &textureID); unsigned int loadTexture(char const * path)
{
int width, height, nrComponents; unsigned int textureID;
unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0); glGenTextures(1, &textureID);
if (data)
{ int width, height, nrComponents;
GLenum format; unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0);
if (nrComponents == 1) if (data)
format = GL_RED; {
else if (nrComponents == 3) GLenum format;
format = GL_RGB; if (nrComponents == 1)
else if (nrComponents == 4) format = GL_RED;
format = GL_RGBA; else if (nrComponents == 3)
format = GL_RGB;
glBindTexture(GL_TEXTURE_2D, textureID); else if (nrComponents == 4)
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); format = GL_RGBA;
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
stbi_image_free(data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
} glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
else
{ stbi_image_free(data);
std::cout << "Texture failed to load at path: " << path << std::endl; }
stbi_image_free(data); else
} {
std::cout << "Texture failed to load at path: " << path << std::endl;
return textureID; stbi_image_free(data);
} }
return textureID;
}