0

I am trying to create a program and render a pyramid with texture. I have already added texture functions as well as the texture coordinates. But whenever I run the program, I get a couple of errors saying:

Severity    Code    Description Project File    Line    Suppression State
Error   LNK2019 unresolved external symbol _etc1_get_encoded_data_size referenced in function "void * __cdecl stbi__pkm_load(struct stbi__context *,int *,int *,int *,int)" (?stbi__pkm_load@@YAPAXPAUstbi__context@@PAH11H@Z)  TexturingAPyramid   C:\Users\marce\source\repos\TexturingAPyramid\Source.obj    1   

and

    Severity    Code    Description Project File    Line    Suppression State
Error   LNK2019 unresolved external symbol _etc1_decode_image referenced in function "void * __cdecl stbi__pkm_load(struct stbi__context *,int *,int *,int *,int)" (?stbi__pkm_load@@YAPAXPAUstbi__context@@PAH11H@Z)   TexturingAPyramid   C:\Users\marce\source\repos\TexturingAPyramid\Source.obj    1

I do not know how to interpret these external symbol errors. I thought it meant that I was missing some prototypes or that I was missing some coordinates. But even after making these corrections, I am still having the same problem. Can anyone tell what these mean? Here is my code:

    #include <iostream>         // cout, cerr
#include <cstdlib>          // EXIT_FAILURE
#include <GL/glew.h>        // GLEW library
#include <GLFW/glfw3.h>     // GLFW library
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>        // Image loading Utility functions

// GLM Math Header inclusions
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <SOIL2.h>

using namespace std; // Standard namespace

/*Shader program Macro*/
#ifndef GLSL
#define GLSL(Version, Source) "#version " #Version " core \n" #Source
#endif

// Input Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);

// Declare View Matrix
glm::mat4 viewMatrix;

// Initialize FOV
GLfloat fov = 45.f;

// Define Camera Attributes
glm::vec3 cameraPosition = glm::vec3(0.f, 0.f, 3.f);
glm::vec3 target = glm::vec3(0.f, 0.f, 0.f);
glm::vec3 cameraDirection = glm::normalize(cameraPosition - target);
glm::vec3 worldUp = glm::vec3(0.f, 1.f, 0.f);
glm::vec3 cameraRight = glm::normalize(glm::cross(worldUp, cameraDirection));
glm::vec3 cameraUp = glm::normalize(glm::cross(cameraDirection, cameraRight));
glm::vec3 cameraFront = glm::normalize(glm::vec3(0.f, 0.f, -1.f));

// Declare target prototype
glm::vec3 getTarget();

// Camera transformation prototype
void TransformCamera();

// Boolean for keys and mouse buttons
bool keys[1024], mouseButtons[3];

// Boolean to check camera transformations
bool isPanning = false, isOrbiting = false;

// Radius, Pitch, and Yaw
GLfloat radius = 3.f, rawYaw = 0.f, rawPitch = 0.f, degYaw, degPitch;

GLfloat deltaTime = 0.f, lastFrame = 0.f;
GLfloat lastX = 400, lastY = 300, xChange, yChange;

bool firstMouseMove = true; // Detect inititial mouse movement

void initCamera();

// Unnamed namespace
namespace
{
    const char* const WINDOW_TITLE = "Texturing a Pyramid"; // Macro for window title

    // Variables for window width and height
    int WINDOW_WIDTH = 800;
    int WINDOW_HEIGHT = 600;

    // Stores the GL data relative to a given mesh
    struct GLMesh
    {
        GLuint vao;         // Handle for the vertex array object
        GLuint vbos[2];     // Handles for the vertex buffer objects
        GLuint nIndices;    // Number of indices of the mesh
    };

    // Main GLFW window
    GLFWwindow* gWindow = nullptr;
    // Triangle mesh data
    GLMesh gMesh;
    // Texture id
    GLuint gTextureId;
    // Shader program
    GLuint gProgramId;
}

/* 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 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);


/* Vertex Shader Source Code*/
const GLchar* vertexShaderSource = GLSL(440,
layout(location = 0) in vec3 position; // Vertex data from Vertex Attrib Pointer 0
layout(location = 1) in vec4 color;  // Color data from Vertex Attrib Pointer 1
layout(location = 2) in vec2 textureCoordinate; // Texture data from Vertex Attrib Pointer 2

out vec4 vertexColor; // variable to transfer color data to the fragment shader
out vec2 vertexTextureCoordinate; // variable to transfer texture data to the fragment shader

//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
    vertexColor = color; // references incoming color data
    vertexTextureCoordinate = textureCoordinate; // references incoming texture data
}
);


/* Fragment Shader Source Code*/
const GLchar* fragmentShaderSource = GLSL(440,
    in vec2 vertexTextureCoordinate;

    in vec4 vertexColor; // Variable to hold incoming color data from vertex shader

out vec4 fragmentColor;

uniform sampler2D uTexture;

void main()
{
    fragmentColor = vec4(vertexColor);
    fragmentColor = texture(uTexture, vertexTextureCoordinate); // Sends texture to the GPU for rendering
}
);

// 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;

    // Create the mesh
    UCreateMesh(gMesh); // Calls the function to create the Vertex Buffer Object

    // Create the shader program
    if (!UCreateShaderProgram(vertexShaderSource, fragmentShaderSource, gProgramId))
        return EXIT_FAILURE;

    // Load texture
    const char* texFilename = "brick.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);

    // Set input call back functions
    glfwSetKeyCallback(gWindow, key_callback);
    glfwSetCursorPosCallback(gWindow, cursor_position_callback);
    glfwSetMouseButtonCallback(gWindow, mouse_button_callback);
    glfwSetScrollCallback(gWindow, scroll_callback);


    // render loop
    // -----------
    while (!glfwWindowShouldClose(gWindow))
    {
        // Set delta time
        GLfloat currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;

        // Resize window and graphics simultaneously 
        glfwGetFramebufferSize(gWindow, &WINDOW_WIDTH, &WINDOW_HEIGHT);

        // input
        // -----
        UProcessInput(gWindow);

        // Render this frame
        URender();

        glfwPollEvents();

        // Poll camera transformations
        TransformCamera();
    }

    // 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);

    // 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)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);

    float cameraSpeed = 2.5 * deltaTime;
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        cameraPosition += cameraSpeed * cameraFront;
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        cameraPosition -= cameraSpeed * cameraFront;
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        cameraPosition -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        cameraPosition += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
        cameraPosition -= cameraSpeed * cameraUp;
    if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
        cameraPosition += cameraSpeed * cameraUp;
}


// 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);
}


// Functioned called to render a frame
void URender()
{
    // Enable z-depth
    glEnable(GL_DEPTH_TEST);

    // Wireframe mode
    // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // Clear the frame and z buffers
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // 1. Scales the object by 2
    glm::mat4 scale = glm::scale(glm::vec3(1.0f, 1.0f, 1.0f));
    // 2. Rotates shape by 15 degrees in the x axis
    glm::mat4 rotation = glm::rotate(45.0f, glm::vec3(1.0, 1.0f, 1.0f));
    // 3. Place object at the origin
    glm::mat4 translation = glm::translate(glm::vec3(0.0f, 0.0f, 0.0f));
    // Model matrix: transformations are applied right-to-left order
    glm::mat4 model = translation * rotation * scale;

    // Transforms the camera: move the camera back (z axis)
    glm::mat4 view = glm::lookAt(cameraPosition, getTarget(), worldUp);

    // Creates a perspective projection
    glm::mat4 projection = glm::perspective(fov, (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));

    // 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
    glDrawElements(GL_TRIANGLES, gMesh.nIndices, GL_UNSIGNED_SHORT, NULL); // Draws the triangle

    // 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)
{
    // Position and Color data
    GLfloat verts[] = {
        // Vertex Positions    // Colors (r,g,b,a)      // Texture
        // Top Center Vertex 0      // Red              // UV
         0.0f,  1.0f,  0.0f,   1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f,  
        // Bottom Left Vertex 1     // Green
         -1.0f, -1.0f,  1.0f,  0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,   
        // Bottom Right Vertex 2    // Blue 
         1.0f, -1.0f,  1.0f,   0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f,   
        // Bottom Back Right Vertex 3   // Magenta
         1.0f, -1.0f, -1.0f,   1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f,    
         // Bottom Back Left Vertex 4   // Yellow
         -1.0f, -1.0f, -1.0f,  1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f   

    };

    // Index data to share position data
    GLushort indices[] = {
        // Sides
        0, 1, 2,  // Triangle 1
        0 ,2, 3,  // Triangle 2
        0, 3, 1, // Triangle 3
        0, 3, 4, // Triangle 4
        
        // Base
        1, 2, 3, // Triangle 5
        1, 4, 3 // Triangle 6

    };

    const GLuint floatsPerVertex = 3;
    const GLuint floatsPerColor = 4;
    const GLuint floatsPerUV = 2;

    mesh.nIndices = 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 2 buffers: first one for the vertex data; second one for the indices
    glGenBuffers(2, mesh.vbos);
    glBindBuffer(GL_ARRAY_BUFFER, mesh.vbos[0]); // Activates the buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); // Sends vertex or coordinate data to the GPU

    mesh.nIndices = sizeof(indices) / sizeof(indices[0]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // Strides between vertex coordinates is 6 (x, y, z, r, g, b, a). A tightly packed stride is 0.
    GLint stride = sizeof(float) * (floatsPerVertex + floatsPerColor);// The number of floats before each

    // Create Vertex Attribute Pointers
    glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, floatsPerColor, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float) * floatsPerVertex));
    glEnableVertexAttribArray(1);
}


void UDestroyMesh(GLMesh& mesh)
{
    glDeleteVertexArrays(1, &mesh.vao);
    glDeleteBuffers(2, mesh.vbos);
}

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\n" << 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\n" << 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\n" << infoLog << std::endl;

        return false;
    }

    glUseProgram(programId);    // Uses the shader program

    return true;
}


void UDestroyShaderProgram(GLuint programId)
{
    glDeleteProgram(programId);
}


// Define Input Callback functions
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {

    // Display ASCII Keycode
    //cout << "ASCII: " << key << endl;

    if (action == GLFW_PRESS)
        keys[key] = true;

    else if (action == GLFW_RELEASE)
        keys[key] = false;

}

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {

    /*
    // Display scroll offset
    if (yoffset > 0)
        cout << "Scroll Up: ";
    if (yoffset < 0)
        cout << "Scroll Down: ";

    cout << yoffset << endl;
    */

    // Clamp FOV
    if (fov >= 1.f && fov <= 45.f)
        fov -= yoffset * 0.01f;

    //Default FOV
    if (fov < 1.f)
        fov = 1.f;
    if (fov > 45.f)
        fov = 45.f;
}

void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) {

    // Display mouse x and y coordinates
   // cout << "Mouse X: " << xpos << endl;
   // cout << "Mouse Y: " << ypos << endl;

    if (firstMouseMove) {
        lastX = xpos;
        lastY = ypos;
        firstMouseMove = false;
    }

    // Calculate cursor offset
    xChange = xpos - lastX;
    yChange = lastY - ypos;

    lastX = xpos;
    lastY = ypos;

    // Pan camera
    if (isPanning) {

        if (cameraPosition.z < 0.f)
            cameraFront.z = 1.f;
        else
            cameraFront.z = -1.f;

        GLfloat cameraSpeed = xChange * deltaTime;
        cameraPosition += cameraSpeed * cameraRight;

        cameraSpeed = yChange * deltaTime;
        cameraPosition += cameraSpeed * cameraUp;
    }

    // Orbit camera
    if (isOrbiting) {

        rawYaw += xChange;
        rawPitch += yChange;

        // Convert Yaw and Pitch to degrees
        degYaw = glm::radians(rawYaw);
        // degPitch = glm::radians(rawPitch)
        degPitch = glm::clamp(glm::radians(rawPitch), -glm::pi<float>() / 2.f + .1f, glm::pi<float>() / 2.f - .1f);

        // Azimuth Altitude formula
        cameraPosition.x = target.x + radius * cosf(degPitch) * sin(degYaw);
        cameraPosition.y = target.y + radius * sinf(degPitch);
        cameraPosition.z = target.z + radius * cosf(degPitch) * cosf(degYaw);

    }

}

void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {

    /*
    // Detect mouse button clicks
    if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
        cout << "LMB clicked!" << endl;
    if (button == GLFW_MOUSE_BUTTON_MIDDLE && action == GLFW_PRESS)
        cout << "MMB clicked!" << endl;
    if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
        cout << "RMB clicked!" << endl;
    */

    if (action == GLFW_PRESS)
        mouseButtons[button] = true;
    else if (action == GLFW_RELEASE)
        mouseButtons[button] = false;
}

// Define getTarget function
glm::vec3 getTarget() {

    if (isPanning)
        target = cameraPosition + cameraFront;

    return target;
}

// Define TransformCamera function
void TransformCamera() {
    // Pan camera
    if (keys[GLFW_KEY_LEFT_ALT] && mouseButtons[GLFW_MOUSE_BUTTON_MIDDLE])
        isPanning = true;
    else
        isPanning = false;

    // Orbit camera
    if ((mouseButtons[GLFW_MOUSE_BUTTON_LEFT]))
        isOrbiting = true;
    else
        isOrbiting = false;

    // Reset camera
    if (keys[GLFW_KEY_F])
        initCamera();

}

void initCamera() {
    cameraPosition = glm::vec3(0.f, 0.f, 3.f);
    target = glm::vec3(0.f, 0.f, 0.f);
    cameraDirection = glm::normalize(cameraPosition - target);
    worldUp = glm::vec3(0.f, 1.f, 0.f);
    cameraRight = glm::normalize(glm::cross(worldUp, cameraDirection));
    cameraUp = glm::normalize(glm::cross(cameraDirection, cameraRight));
    cameraFront = glm::normalize(glm::vec3(0.f, 0.f, -1.f));
}
MachoMan
  • 59
  • 6
  • 3
    This message does not mean that the prototypes are missing, it means the the functions themselves are missing. Standard reasons for this frequently asked question: you forgot to write them, you for got to include the source file with them in your build, you didn't include the third party library containing them in your build. – Avi Berger Oct 02 '22 at 02:45

0 Answers0