I know this is a common question among beginners of C++ but I have looked at other peoples threads and not found what I was looking for. I understand the unresolved external symbols error usually means missing libraries but these are my classes that it is not accepting. Here is the code and the errors(Sorry it's so messy, I'm in the process of converting it from single file to object orientated):
main.cpp:
#include <iostream>
#include <gl\glew.h>
#include <GL\freeglut.h>
#include <vector>
#include <algorithm>
#include <string>
#include <fStream>
#include <cmath>
#include <array>
#include "ResourceLoader.h"
#include "Shader.h"
#include "Program.h"
#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
void display();
void reshape();
void init();
void InitializeVertexBuffer();
struct glutWindow
{
int width;
int height;
char* title;
float fov;
float zNear;
float zFar;
};
glutWindow win;
GLuint positionBufferObject;
GLuint vao;
Shader vertex("../Shaders/Vertex.vs");
Shader fragment("../Shaders/Fragment.fs");
Program program;
const float vertexPositions[]
{
//102 lines of vertex positions I didn't think were necessary to include...
};
int main(int argc, char** argv)
{
win.width = 800;
win.height = 700;
win.title = "OpenGL";
win.fov = 45;
win.zNear = 1.0f;
win.zFar = 500.0f;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(win.width, win.height);
glutCreateWindow("OpenGL");
glutDisplayFunc(display);
glewInit();
init();
glutMainLoop();
return 0;
}
void init()
{
Shader* shaders[]{&vertex, &fragment};
program.setShaders(shaders);
program.InitializeProgram();
InitializeVertexBuffer();
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnable(GL_CULL_FACE);
glFrontFace(GL_CW);
glCullFace(GL_BACK);
}
void InitializeVertexBuffer()
{
glGenBuffers(1, &positionBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void display()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
program.use();
program.setUniform2f("offset", 0.5f, 0.5f);
size_t colorData = (1, 1, 1, 1);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)colorData);
glDrawArrays(GL_TRIANGLES, 0, 36);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glUseProgram(0);
glutSwapBuffers();
glutPostRedisplay();
}
Program.h:
#ifndef _PROGRAM_H
#define _PROGRAM_H
#include <gl\glew.h>
#include <GL\freeglut.h>
#include <vector>
#include <algorithm>
#include <map>
#include <cstdarg>
#include "Shader.h"
class Program
{
public:
static void CreateProgram(Shader* shaders[]);
void InitializeProgram();
static GLuint getUniformLocation(const GLchar* name);
static void use();
void setShaders(Shader* shaders[]);
void setUniform1f(std::string name, float value);
void setUniform2f(std::string name, float val1, float val2);
static Shader* shaders[3];
private:
static GLuint program;
static std::map<std::string, GLuint> uniforms;
};
#endif
Program.cpp:
#include "Program.h"
void Program::CreateProgram(Shader* shaders[])
{
GLuint program = glCreateProgram();
for (size_t iLoop = 0; iLoop < sizeof(shaders) / sizeof(shaders[0]); iLoop++)
glAttachShader(program, shaders[iLoop]->getShader());
glLinkProgram(program);
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
GLint infoLogLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *strInfoLog = new GLchar[infoLogLength + 1];
glGetProgramInfoLog(program, infoLogLength, NULL, strInfoLog);
fprintf(stderr, "Shader Linker failure: %s\n", strInfoLog);
delete[] strInfoLog;
}
for (size_t iLoop = 0; iLoop < sizeof(shaders) / sizeof(shaders[0]); iLoop++)
glDetachShader(program, shaders[iLoop]->getShader());
Program::program = program;
}
void Program::InitializeProgram()
{
Program::CreateProgram(Program::shaders);
uniforms["offset"] = this->getUniformLocation("offset");
uniforms["frustumScale"] = this->getUniformLocation("frustumScale");
uniforms["zNear"] = this->getUniformLocation("zNear");
uniforms["zFar"] = this->getUniformLocation("zFar");
this->use();
this->setUniform1f("frustumScale", 1.0f);
this->setUniform1f("zNear", 1.0f);
this->setUniform1f("zFar", 1.0f);
glUseProgram(0);
for (int i = 0; i < sizeof(shaders) / sizeof(shaders[0]); i++)
{
glDeleteShader(shaders[i]->getShader());
}
}
void Program::setUniform1f(std::string name, float value)
{
glUniform1f(uniforms[name], value);
}
void Program::setUniform2f(std::string name, float val1, float val2)
{
glUniform2f(uniforms[name], val1, val2);
}
GLuint Program::getUniformLocation(const GLchar* name)
{
return glGetUniformLocation(Program::program, name);
}
void Program::use()
{
glUseProgram(Program::program);
}
void Program::setShaders(Shader* shaders[])
{
for (int i = 0; i < sizeof(shaders) / sizeof(shaders[0]); i++)
{
Program::shaders[i] = shaders[i];
}
}
Shader.h:
#ifndef _SHADER_H
#define _SHADER_H
#include <string>
#include <iostream>
#include <sstream>
#include <gl\glew.h>
#include <GL\freeglut.h>
#include "ResourceLoader.h"
class Shader
{
public:
Shader(const char* filePath);
void loadShader();
void CreateShader(GLenum eShaderType);
std::string getContent();
std::string getFilePath();
GLuint getShader();
private:
const char* filePath;
GLuint shader;
std::string content;
};
#endif
Shader.cpp:
#include "Shader.h"
Shader::Shader(const char* filePath)
{
this->filePath = filePath;
loadShader();
}
void Shader::loadShader()
{
content = ResourceLoader::readFile(this->filePath);
if (content == "")
{
std::cout << "Shader " << filePath << " could not be loaded." << std::endl;
}
}
std::string Shader::getContent()
{
return this->content;
}
std::string Shader::getFilePath()
{
return this->filePath;
}
GLuint Shader::getShader()
{
return this->shader;
}
void Shader::CreateShader(GLenum eShaderType)
{
GLuint shader = glCreateShader(eShaderType);
std::string strFileData = ResourceLoader::readFile(this->filePath);
const char* cstrFileData = strFileData.c_str();
const GLint length = strFileData.length();
glShaderSource(shader, 1, &cstrFileData, &length);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
GLint infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *strInfoLog = new GLchar[infoLogLength + 1];
glGetShaderInfoLog(shader, infoLogLength, NULL, strInfoLog);
const char *strShaderType = NULL;
switch (eShaderType)
{
case GL_VERTEX_SHADER: strShaderType = "vertex"; break;
case GL_GEOMETRY_SHADER: strShaderType = "geometry"; break;
case GL_FRAGMENT_SHADER: strShaderType = "fragment"; break;
}
fprintf(stderr, "Compile failure in %s shader:\n%s\n", strShaderType, strInfoLog);
delete[] strInfoLog;
}
this->shader = shader;
}
ResourceLoader.h:
#ifndef _RESOURCE_LOADER_H
#define _RESOURCE_LOADER_H
#include <string>
#include <fstream>
#include <iostream>
class ResourceLoader
{
public:
static std::string readFile(const char* filePath);
};
#endif
ResourceLoader.cpp:
#include "ResourceLoader.h"
std::string ResourceLoader::readFile(const char *filePath)
{
std::string content;
std::ifstream fileStream(filePath, std::ios::in);
if (!fileStream.is_open())
{
std::cerr << "Could not read file " << filePath << ". File does not exist." << std::endl;
return "";
}
std::string line = "";
while (!fileStream.eof())
{
std::getline(fileStream, line);
content.append(line + "\n");
}
fileStream.close();
return content;
}
Errors:
Error 1 error LNK2001: unresolved external symbol "public: static class Shader * * Program::shaders" (?shaders@Program@@2PAPAVShader@@A) c:\Users\Ben\documents\visual studio 2013\Projects\OpenGL Project\OpenGL Project\Program.obj OpenGL Project
Error 2 error LNK2001: unresolved external symbol "private: static unsigned int Program::program" (?program@Program@@0IA) c:\Users\Ben\documents\visual studio 2013\Projects\OpenGL Project\OpenGL Project\Program.obj OpenGL Project
Error 3 error LNK2001: unresolved external symbol "private: static class std::map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,unsigned int,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,unsigned int> > > Program::uniforms" (?uniforms@Program@@0V?$map@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IU?$less@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@I@std@@@2@@std@@A) c:\Users\Ben\documents\visual studio 2013\Projects\OpenGL Project\OpenGL Project\Program.obj OpenGL Project
Error 4 error LNK1120: 3 unresolved externals c:\users\ben\documents\visual studio 2013\Projects\OpenGL Project\Debug\OpenGL Project.exe 1 1 OpenGL Project
Thanks