I am learning a little bit of opengl and i run into condition where i needed to use templates the file which has class declaration and defination is :
#pragma once
#include <vector>
#include <glad/glad.h>
template<class T>
class Vertexbuffer
{
private:
unsigned m_bufferID;
std::vector<T> m_data;
unsigned m_capacity;
unsigned m_count;
mutable bool gpu_del;
void setup(const T* vertices, const unsigned count);
public:
const std::vector<T>& getdata() { return m_data; }
Vertexbuffer() :m_bufferID(0), m_capacity(0), m_count(0), gpu_del(true) {}
Vertexbuffer(const T* vertices, const unsigned count, bool g_del = true);
Vertexbuffer(const float* data, unsigned size);
Vertexbuffer(const Vertexbuffer& in);
~Vertexbuffer();
void Bind() const;
void Unbind() const;
void AddData(const T* vertices,const unsigned count);
const unsigned getID() const { return m_bufferID; }
};
template<class T>
Vertexbuffer<T>::Vertexbuffer(const T* vertices, const unsigned count, bool g_del) :gpu_del(g_del)
{
setup(vertices, count);
}
template<class T>
Vertexbuffer<T>::Vertexbuffer(const float* data, unsigned size) : gpu_del(true), m_capacity(size), m_count(size)
{
GLcall(glGenBuffers(1, &m_bufferID));
GLcall(glBindBuffer(GL_ARRAY_BUFFER, m_bufferID));
GLcall(glBufferData(GL_ARRAY_BUFFER, size * sizeof(float), data, GL_DYNAMIC_DRAW));
}
template<class T>
Vertexbuffer<T>::~Vertexbuffer()
{
if (gpu_del) {
//std::cout << "vbo freed\n";
GLcall(glDeleteBuffers(1, &m_bufferID));
}
}
template<class T>
void Vertexbuffer<T>::setup(const T* vertices, const unsigned count)
{
if (vertices == nullptr) {
m_capacity = count;
m_count = 0;
if (count == 0)
return;
}
else {
m_capacity = count;
m_count = count;
m_data.reserve(m_count);
for (uint i = 0; i < m_count; i++) {
m_data.push_back(vertices[i]);
}
}
GLcall(glGenBuffers(1, &m_bufferID));
GLcall(glBindBuffer(GL_ARRAY_BUFFER, m_bufferID));
GLcall(glBufferData(GL_ARRAY_BUFFER, sizeof(T) * count, vertices, GL_DYNAMIC_DRAW));
GLcall(glBindBuffer(GL_ARRAY_BUFFER, 0));
}
template<class T>
void Vertexbuffer<T>::Bind() const
{
GLcall(glBindBuffer(GL_ARRAY_BUFFER, m_bufferID));
}
template<class T>
void Vertexbuffer<T>::Unbind() const
{
GLcall(glBindBuffer(GL_ARRAY_BUFFER, 0));
}
template<class T>
void Vertexbuffer<T>::AddData(const T* vertices, const unsigned count)
{
if ((m_bufferID == 0) || (m_count == 0)) {
setup(vertices, count);
}
else
{
m_data.resize(m_count + count);
m_capacity = m_data.capacity();
unsigned a = 0;
for (uint i = 0; i < count; i++) {
a = i + m_count;
m_data[a] = vertices[i];
}
GLcall(glBindBuffer(GL_ARRAY_BUFFER, m_bufferID));
GLcall(void* pointer = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY));
#ifdef _MSC_VER
void* tempdata = _malloca(m_count * sizeof(T));
memcpy_s(tempdata, m_count * sizeof(T), pointer, m_count * sizeof(T));
#else
void* tempdata = malloc(m_count * sizeof(T));
memcpy(tempdata, pointer, m_count * sizeof(T));
#endif
GLcall(glDeleteBuffers(1, &m_bufferID));
GLcall(glGenBuffers(1, &m_bufferID));
GLcall(glBindBuffer(GL_ARRAY_BUFFER, m_bufferID));
GLcall(glBufferData(GL_ARRAY_BUFFER, (m_count + count) * sizeof(T), nullptr, GL_DYNAMIC_DRAW));
GLcall(glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(T), tempdata));
GLcall(glBufferSubData(GL_ARRAY_BUFFER, m_count * sizeof(T), sizeof(T) * count, vertices));
GLcall(glBindBuffer(GL_ARRAY_BUFFER, 0));
m_count = m_data.size();
}
}
template<class T>
Vertexbuffer<T>::Vertexbuffer(const Vertexbuffer& in)
: m_bufferID(in.m_bufferID), m_capacity(in.m_capacity), m_count(in.m_count), gpu_del(true)
{
m_data = in.m_data;
in.gpu_del = false;
}
this is a file which works fine as it has all definition at the bottom, but when I try to copy all definition to separate cpp file and as I learnt in this site:
I just wrote
template class Vertexbuffer<int>;
at the end of the .cpp file and it didnot work.
But if we write the program mentioned in the page then it works!
What am I missing here?
Any helps or ideas are warmly welcomed..
EDIT1
I created the .cpp file by cutting all the definitions of all member functions to vertexbuffer.cpp and just left
template<class T>
class Vertexbuffer
{
...
}
declaration like this in veretxbuffer.h file
now i get a linking error like
1>Renderer.obj : error LNK2001: unresolved external symbol "public: __cdecl Vertexbuffer<struct Vertex>::Vertexbuffer<struct Vertex>(struct Vertex const *,unsigned int,bool)" (??0?$Vertexbuffer@UVertex@@@@QEAA@PEBUVertex@@I_N@Z)
at each and every file where this class is used to make object.
But when i keep all the code like all the member unction defination in .h file it works as expected.
template class Vertexbuffer<int>;
was added at the bottom of .cpp file just to avoid linking error as said in the site above.
EDIT2
It worked when I explicitly instantiated the class with template argument being all the classes and data types which I was using in the whole project at the end of the .cpp file like
template class Vertexbuffer<Vertex>;
template class Vertexbuffer<float>;
which means I can only use the template with these template arguments and even defining these in respective file where i intend to use these instantiations did not work. Any workaround that so that i can instantiate the Vertexbuffer class with any class as template argument without changing the .cpp file?