TriangleCanvas with Shaders

Here is the source code for TriangleCanvas.h:

#pragma once
#include <memory>
#include "wx/glcanvas.h"

class TriangleCanvas : public wxGLCanvas
{
public:
	TriangleCanvas(wxWindow* parent, wxWindowID id = wxID_ANY,
		const int* attribList = 0, const wxPoint& pos = wxDefaultPosition,
		const wxSize& size = wxDefaultSize, long style = 0L,
		const wxString& name = L"GLCanvas", const wxPalette& palette = wxNullPalette);

	virtual ~TriangleCanvas();
	TriangleCanvas(const TriangleCanvas& tc) = delete;
	TriangleCanvas(TriangleCanvas&& tc) = delete;
	TriangleCanvas& operator=(const TriangleCanvas& tc) = delete;
	TriangleCanvas& operator=(TriangleCanvas&& tc) = delete;

private:
	void InitializeGLEW();
	void SetupGraphics();
	void BuildShaderProgram();
	void BuildVertexShader();
	void BuildFragmentShader();
	void OnPaint(wxPaintEvent& event);

	std::unique_ptr m_context;
	GLuint m_vbo;		// vertex buffer pointer
	GLuint m_vao;		// vertex array pointer
	GLuint m_vertexShader;
	GLuint m_fragmentShader;
	GLuint m_shaderProgram;
};

and TriangleCanvas.cpp:

#include "wx/wxprec.h"
#include <GL/glew.h>
#include "TriangleCanvas.h"

#pragma comment(lib, "glew32.lib")

TriangleCanvas::TriangleCanvas(wxWindow* parent, wxWindowID id, const int* attribList,
	const wxPoint& pos, const wxSize& size, long style, const wxString& name,
	const wxPalette& palette)
	: wxGLCanvas(parent, id, attribList, pos, size, style, name, palette),
	m_vbo(0), m_vao(0)
{
	m_context = std::make_unique(this);
	Bind(wxEVT_PAINT, &TriangleCanvas::OnPaint, this);
	
	SetCurrent(*m_context);
	InitializeGLEW();
	SetupGraphics();
}


TriangleCanvas::~TriangleCanvas()
{
	SetCurrent(*m_context);
	glDeleteProgram(m_shaderProgram);
	glDeleteShader(m_fragmentShader);
	glDeleteShader(m_vertexShader);
	glDeleteVertexArrays(1, &m_vao);
	glDeleteBuffers(1, &m_vbo);
}

void TriangleCanvas::OnPaint(wxPaintEvent& event)
{
	SetCurrent(*m_context);

	// set background to black
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// draw the graphics
	glDrawArrays(GL_TRIANGLES, 0, 3);
	// and display
	glFlush();
	SwapBuffers();
}

void TriangleCanvas::InitializeGLEW()
{
	glewExperimental = true;
	GLenum err = glewInit();
	if (err != GLEW_OK) {
		const GLubyte* msg = glewGetErrorString(err);
		throw std::exception(reinterpret_cast(msg));
	}
}

void TriangleCanvas::SetupGraphics()
{
	// define vertices
	float points[] = {
		0.0f, 0.5f,
		0.5f, -0.5f,
		-0.5f, -0.5f,
	};
	// upload vertex data
	glGenBuffers(1, &m_vbo);
	glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
	// setup vertex array objects
	glGenVertexArrays(1, &m_vao);
	glBindVertexArray(m_vao);
	BuildShaderProgram();
}

void TriangleCanvas::BuildVertexShader()
{
	const GLchar* vertexSource =
		"#version 330 core\n"
		"in vec2 position;"
		"void main()"
		"{"
		"    gl_Position = vec4(position, 0.0, 1.0);"
		"}";
	m_vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(m_vertexShader, 1, &vertexSource, NULL);
	glCompileShader(m_vertexShader);
}

void TriangleCanvas::BuildFragmentShader()
{
	const GLchar* fragmentSource =
		"#version 330 core\n"
		"out vec4 outColor;"
		"void main()"
		"{"
		"	outColor = vec4(1.0, 1.0, 1.0, 1.0);"
		"}";
	m_fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(m_fragmentShader, 1, &fragmentSource, NULL);
	glCompileShader(m_fragmentShader);
}

void TriangleCanvas::BuildShaderProgram()
{
	BuildVertexShader();
	BuildFragmentShader();
	m_shaderProgram = glCreateProgram();
	glAttachShader(m_shaderProgram, m_vertexShader);
	glAttachShader(m_shaderProgram, m_fragmentShader);
	glBindFragDataLocation(m_shaderProgram, 0, "outColor");
	glLinkProgram(m_shaderProgram);
	glUseProgram(m_shaderProgram);

	GLint posAttrib = glGetAttribLocation(m_shaderProgram, "position");
	glEnableVertexAttribArray(posAttrib);
	glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
}
Advertisements