Simple Cube not Showing up with simple Example ...

Started by
3 comments, last by tmason 9 years, 5 months ago

Hello,

I am trying to draw a simple cube for a homework assignment for a class but for some reason it isn't showing up.

I am using uniform blocks and modern OpenGL. I am sure I am not doing something correctly.

My complete code is below. The below example depends on GLEW + GLFW + GLM.

Any ideas?

Thank you:


#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>

#ifndef OPENGL_INCLUDES_
#define OPENGL_INCLUDES_

#include "GL\glew.h"

#ifndef GLFW_INCLUDES_
#define GLFW_INCLUDES_

#if defined(_WIN32)
#include <Windows.h>
#define GLFW_EXPOSE_NATIVE_WIN32
#define GLFW_EXPOSE_NATIVE_WGL
#elif defined(__linux__)
#include <X11/X.h>
#include <X11/extensions/Xrandr.h>
#define GLFW_EXPOSE_NATIVE_X11
#define GLFW_EXPOSE_NATIVE_GLX
#endif

#include "GLFW\glfw3.h"
#include "GLFW\glfw3native.h"

#endif

#endif

#ifndef GLM_INCLUDES_
#define GLM_INCLUDES_

#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>

#endif

GLFWwindow* MainWindow;

#ifdef _WIN32

HWND MainWindowWin32Handle;

#endif

GLint WindowWidth = 1024;
GLint WindowHeight = 768;

GLulong SizeDivizor = 1;

GLboolean RiftAvailable = false;
GLboolean UseApplicationWindowFrame = false;

GLuint MainOpenGLShaderProgramID;
GLuint MatricesUniformBlockID;
GLuint MatricesUniformBufferID;

GLuint LightsUniformBlockID;
GLuint LightsUniformBufferID;

GLuint MaterialsUniformBlockID;
GLuint MaterialsUniformBufferID;

glm::mat4 ViewMatrix;
glm::mat4 ViewModelMatrix;
glm::mat4 ProjectionMatrix;
glm::mat4 MVPMatrix;
glm::mat3 NormalMatrix;

class StandardCube;

std::vector<StandardCube> Cubes;

class StandardCube {

private:

	GLfloat* Vertices;
	GLfloat* Normals;
	GLuint* Indices;

	GLuint VAO;

	glm::mat4 ModelMatrix;

public:

	void LoadIntoOpenGL() {

		Vertices = new GLfloat[72]

		{
			1.0f, 1.0f, 1.0f,
				-1.0f, 1.0f, 1.0f,
				-1.0f, -1.0f, 1.0f,
				1.0f, -1.0f, 1.0f,
				-1.0f, -1.0f, -1.0f,
				-1.0f, 1.0f, -1.0f,
				1.0f, 1.0f, -1.0f,
				1.0f, -1.0f, -1.0f,
				1.0f, 1.0f, 1.0f,
				1.0f, 1.0f, -1.0f,
				-1.0f, 1.0f, -1.0f,
				-1.0f, 1.0f, 1.0f,
				-1.0f, -1.0f, -1.0f,
				1.0f, -1.0f, -1.0f,
				1.0f, -1.0f, 1.0f,
				-1.0f, -1.0f, 1.0f,
				1.0f, 1.0f, 1.0f,
				1.0f, -1.0f, 1.0f,
				1.0f, -1.0f, -1.0f,
				1.0f, 1.0f, -1.0f,
				-1.0f, -1.0f, -1.0f,
				-1.0f, -1.0f, 1.0f,
				-1.0f, 1.0f, 1.0f,
				-1.0f, 1.0f, -1.0f
		};

		Normals = new GLfloat[72] {
			0.0f, 0.0f, 1.0f,
				0.0f, 0.0f, 1.0f,
				0.0f, 0.0f, 1.0f,
				0.0f, 0.0f, 1.0f,
				0.0f, 0.0f, -1.0f,
				0.0f, 0.0f, -1.0f,
				0.0f, 0.0f, -1.0f,
				0.0f, 0.0f, -1.0f,
				0.0f, 1.0f, 0.0f,
				0.0f, 1.0f, 0.0f,
				0.0f, 1.0f, 0.0f,
				0.0f, 1.0f, 0.0f,
				0.0f, -1.0f, 0.0f,
				0.0f, -1.0f, 0.0f,
				0.0f, -1.0f, 0.0f,
				0.0f, -1.0f, 0.0f,
				1.0f, 0.0f, 0.0f,
				1.0f, 0.0f, 0.0f,
				1.0f, 0.0f, 0.0f,
				1.0f, 0.0f, 0.0f,
				-1.0f, 0.0f, 0.0f,
				-1.0f, 0.0f, 0.0f,
				-1.0f, 0.0f, 0.0f,
				-1.0f, 0.0f, 0.0f
		};

		Indices = new GLuint[36] {0, 1, 2, 2, 3, 0,
			4, 5, 6, 6, 7, 4,
			8, 9, 10, 10, 11, 8,
			12, 13, 14, 14, 15, 12,
			16, 17, 18, 18, 19, 16,
			20, 21, 22, 22, 23, 20
		};

		glGenVertexArrays(1, &VAO);
		glBindVertexArray(VAO);

		GLuint MeshBufferID;
		glGenBuffers(1, &MeshBufferID);
		glBindBuffer(GL_ARRAY_BUFFER, MeshBufferID);

		GLuint TotalBufferData = (sizeof(GLfloat) * 72) + (sizeof(GLfloat) * 72);

		glBufferData(GL_ARRAY_BUFFER, TotalBufferData, NULL, GL_STATIC_DRAW);

		glBufferSubData(GL_ARRAY_BUFFER, NULL, sizeof(GLfloat) * 72, Vertices);

		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
		glEnableVertexAttribArray(0);

		glBufferSubData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 72, sizeof(GLfloat) * 72, Normals);

		glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(sizeof(GLfloat) * 72));
		glEnableVertexAttribArray(1);

		GLuint IndexBufferID;
		glGenBuffers(1, &IndexBufferID);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * 36, Indices, GL_STATIC_DRAW);

		glBindVertexArray(NULL);

		ModelMatrix = glm::mat4(1.0f);

	}

	void DrawMe() {

		MVPMatrix = ProjectionMatrix * ViewMatrix * ModelMatrix;
		ViewModelMatrix = ViewMatrix * ModelMatrix;
		NormalMatrix = glm::transpose(glm::inverse(glm::mat3(MVPMatrix)));

		glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);

		glBufferSubData(GL_UNIFORM_BUFFER, NULL, sizeof(glm::mat4), glm::value_ptr(MVPMatrix));
		glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(ViewModelMatrix));
		glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4) + sizeof(glm::mat4), sizeof(glm::mat3), glm::value_ptr(NormalMatrix));

		glBindBuffer(GL_UNIFORM_BUFFER, NULL);

		glBindVertexArray(VAO);
		glDrawElementsInstanced(GL_TRIANGLES, 36, GL_UNSIGNED_INT, NULL, 1);
		glBindVertexArray(NULL);

	}

};

static void GLFWKeyCallback(GLFWwindow* p_Window, GLint p_Key, GLint p_Scancode, GLint p_Action, GLint p_Mods) {

	if (p_Key == GLFW_KEY_ESCAPE && p_Action == GLFW_PRESS) {

		glfwSetWindowShouldClose(p_Window, GL_TRUE);
	}

	if (p_Key == GLFW_KEY_O && p_Action == GLFW_PRESS) {

		glClearColor(0.2f, 0.1f, 0.3f, 1.0f);

	}

	if (p_Key == GLFW_KEY_I && p_Action == GLFW_PRESS) {

		glClearColor(1.0f, 0.5f, 0.5f, 1.0f);

	}

}

static void GLFWWindowResizeCallBack(GLFWwindow* p_Window, GLint width, GLint height) {

	//CurrentGLFWApplication->WindowResizeCallBack(p_Window, width, height);

}

static void GLFWMouseMovementCallBack(GLFWwindow* p_Window, GLdouble MouseX, GLdouble MouseY) {

	//CurrentGLFWApplication->MouseMovementCallBack(p_Window, MouseX, MouseY);

}

static void GLFWFramebufferSizeCallback(GLFWwindow* window, GLint width, GLint height)
{

	glViewport(0, 0, width, height);

}

int initializeGLFWGLEW() {

	MainWindow = NULL;

	if (!glfwInit())
	{

		fprintf(stderr, "GLFW failed to initialize.");
		glfwTerminate();
		return EXIT_FAILURE;

	}

	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);

	if (UseApplicationWindowFrame) {

		MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Basic Oculus Rift Example", NULL, NULL);

	}
	else {

		if (!RiftAvailable) {

			MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Basic Oculus Rift Example", NULL, NULL);

		}
		else {

			GLint MonitorCount;
			GLFWmonitor** GLFW_Monitors = glfwGetMonitors(&MonitorCount);
			GLFWmonitor* MonitorToUse;

			switch (MonitorCount)
			{
			case 0:
				printf("No monitors found, exiting.\n");
				return EXIT_FAILURE;
				break;
			case 1:
				printf("Two monitors expected, found only one, using primary...\n");
				MonitorToUse = glfwGetPrimaryMonitor();
				break;
			case 2:
				printf("Two monitors found, using second monitor\n");
				MonitorToUse = GLFW_Monitors[1];
				break;
			default:
				printf("More than two monitors found, using second monitor\n");
				MonitorToUse = GLFW_Monitors[1];
			}

			MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Basic Oculus Rift Example", MonitorToUse, NULL);

		}

	}

	if (!MainWindow)
	{
		fprintf(stderr, "Could not determine OpenGL version; exiting.");
		glfwTerminate();
		return EXIT_FAILURE;
	}

	glfwMakeContextCurrent(MainWindow);

	glewExperimental = GL_TRUE;
	GLenum err = glewInit();

	if (GLEW_OK != err)
	{
		/* Problem: glewInit failed, something is seriously wrong. */
		fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
		return EXIT_FAILURE;

	}



	glfwSetInputMode(MainWindow, GLFW_STICKY_KEYS, GL_TRUE);

	glfwSetKeyCallback(MainWindow, GLFWKeyCallback);
	glfwSetWindowSizeCallback(MainWindow, GLFWWindowResizeCallBack);
	glfwSetCursorPosCallback(MainWindow, GLFWMouseMovementCallBack);
	glfwSetFramebufferSizeCallback(MainWindow, GLFWFramebufferSizeCallback);

	glfwSwapBuffers(MainWindow);

	glfwPollEvents();

	return EXIT_SUCCESS;

}

int prepareOpenGL() {

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glEnable(GL_CULL_FACE);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_MULTISAMPLE);

	return EXIT_SUCCESS;

}

int loadShaders() {

	// Create the shaders
	GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
	GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

	// Compile Vertex Shader
	printf("Compiling Vertext Shader.\n\n");
	char const * VertexSource = "#version 330 \n\n\
										layout(std140) uniform Matrices{\n\
												mat4 m_pvm;\n\
														mat4 m_viewModel;\n\
																mat3 m_normal;\n\
																	};\n\
																		layout(std140) uniform Lights{\n\
																				vec3 l_dir; \n\
																					};\n\
																						in vec4 position;\n\
																							in vec3 normal;\n\
																								\n\
																									\n\
																										out Data{\n\
																												vec3 normal;\n\
																														vec4 eye;\n\
																															} DataOut;\n\
																																\n\
																																	void main() {\n\
																																		\n\
																																				DataOut.normal = normalize(m_normal * normal);\n\
																																						DataOut.eye = -(m_viewModel * position);\n\
																																								\n\
																																										gl_Position = m_pvm * position;\n\
																																											}\n\
																																												\n";

	glShaderSource(VertexShaderID, 1, &VertexSource, NULL);
	glCompileShader(VertexShaderID);

	// Check Vertex Shader

	GLint Result = GL_FALSE;
	int InfoLogLength;

	glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);

	if (InfoLogLength > 0){

		std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
		glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
		std::string ErrorMessage = std::string(&VertexShaderErrorMessage[0]);
		printf("%s\n", &VertexShaderErrorMessage[0]);

	}

	printf("Compiling Fragment Shader.\n\n");
	char const * FragmentSource = "#version 330\n\
								  		layout(std140) uniform Materials{\n\
												vec4 diffuse;\n\
														vec4 ambient;\n\
																vec4 specular;\n\
																		vec4 emissive;\n\
																				float shininess;\n\
																						int texCount;\n\
																							};\
																								\n\
																									layout(std140) uniform Lights{\n\
																											vec3 l_dir; \n\
																												};\
																													\n\
																														in Data{\n\
																																vec3 normal;\n\
																																		vec4 eye;\n\
																																			} DataIn;\n\
																																				\n\
																																					out vec4 colorOut;\
																																						\n\
																																							void main() {\n\
																																								\n\
																																										vec4 spec = vec4(0.0);\n\
																																												\n\
																																														vec3 n = normalize(DataIn.normal);\n\
																																																vec3 e = normalize(vec3(DataIn.eye));\n\
																																																		\n\
																																																				float intensity = max(dot(n, l_dir), 0.0);\n\
																																																						\n\
																																																								if (intensity > 0.0) {\n\
																																																											vec3 h = normalize(l_dir + e);\n\
																																																														\n\
																																																																	float intSpec = max(dot(h, n), 0.0);\n\
																																																																				spec = specular * pow(intSpec, shininess);\n\
																																																																						}\n\
																																																																								\n\
																																																																										colorOut = max(intensity *  diffuse + spec, ambient);\n\
																																																																											}";

	glShaderSource(FragmentShaderID, 1, &FragmentSource, NULL);
	glCompileShader(FragmentShaderID);

	// Check Fragment Shader
	glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	if (InfoLogLength > 0){

		std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
		glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
		std::string ErrorMessage = std::string(&FragmentShaderErrorMessage[0]);
		printf("%s\n", &FragmentShaderErrorMessage[0]);

	}

	// Link the program
	printf("Linking shader program.\n\n");
	GLuint ProgramID = glCreateProgram();
	glAttachShader(ProgramID, VertexShaderID);
	glAttachShader(ProgramID, FragmentShaderID);
	glLinkProgram(ProgramID);

	// Check the program
	glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
	glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	if (InfoLogLength > 0){

		std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
		glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
		std::string ErrorMessage = std::string(&ProgramErrorMessage[0]);
		printf("%s\n", &ProgramErrorMessage[0]);

	}

	glDeleteShader(VertexShaderID);
	glDeleteShader(FragmentShaderID);

	MainOpenGLShaderProgramID = ProgramID;

	return EXIT_SUCCESS;

}

int prepareShaderUniforms() {

	glUseProgram(MainOpenGLShaderProgramID);

	MatricesUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Matrices");
	glUniformBlockBinding(MainOpenGLShaderProgramID, MatricesUniformBlockID, 1);
	glGenBuffers(1, &MatricesUniformBufferID);
	glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);
	glBindBufferBase(GL_UNIFORM_BUFFER, 0, MatricesUniformBufferID);
	GLsizeiptr TotalBufferSize = sizeof(glm::mat4) + sizeof(glm::mat4);
	TotalBufferSize += sizeof(glm::mat3);
	glBufferData(GL_ARRAY_BUFFER, TotalBufferSize, NULL, GL_DYNAMIC_DRAW);
	glBindBuffer(GL_UNIFORM_BUFFER, NULL);

	LightsUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Lights");
	glUniformBlockBinding(MainOpenGLShaderProgramID, LightsUniformBlockID, 2);
	glGenBuffers(1, &LightsUniformBufferID);
	glBindBuffer(GL_UNIFORM_BUFFER, LightsUniformBufferID);
	glBindBufferBase(GL_UNIFORM_BUFFER, 0, LightsUniformBufferID);

	GLfloat LightDirection[3] = { 1.0f, 1.0f, 0.0f };

	glBufferData(GL_UNIFORM_BUFFER, sizeof(LightDirection), &LightDirection, GL_DYNAMIC_DRAW);
	glBindBuffer(GL_UNIFORM_BUFFER, NULL);

	MaterialsUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Materials");
	glUniformBlockBinding(MainOpenGLShaderProgramID, MaterialsUniformBlockID, 3);
	glGenBuffers(1, &MaterialsUniformBufferID);
	glBindBuffer(GL_UNIFORM_BUFFER, MaterialsUniformBufferID);
	glBindBufferBase(GL_UNIFORM_BUFFER, 0, MaterialsUniformBufferID);

	GLfloat Material[18];

	//Diffuse
	Material[0] = 0.5f;
	Material[1] = 0.0f;
	Material[2] = 0.0f;
	Material[3] = 1.0f;

	//Ambient
	Material[4] = 0.2f;
	Material[5] = 0.2f;
	Material[6] = 0.2f;
	Material[7] = 1.0f;

	//Specular
	Material[8] = 0.0f;
	Material[9] = 0.0f;
	Material[10] = 0.0f;
	Material[11] = 1.0f;

	//Emissive
	Material[12] = 0.0f;
	Material[13] = 0.0f;
	Material[14] = 0.0f;
	Material[15] = 1.0f;

	//Shininess
	Material[16] = 2.0f;

	//Texture Count
	Material[17] = 0.0f;

	glBufferData(GL_UNIFORM_BUFFER, sizeof(Material), &Material, GL_DYNAMIC_DRAW);
	glBindBuffer(GL_UNIFORM_BUFFER, NULL);

	return EXIT_SUCCESS;

}

int loadCubes() {

	StandardCube NewCube;

	NewCube.LoadIntoOpenGL();

	Cubes.push_back(NewCube);

	return EXIT_SUCCESS;

}

int prepareMatricies() {

	GLfloat AspectRatio = (GLfloat)(WindowWidth) / (GLfloat)(WindowHeight);

	ProjectionMatrix = glm::perspective(45.0f, AspectRatio, 1.0f, 1000.0f);

	ViewMatrix = glm::lookAt(
		glm::vec3(4.0f, 3.0f, 3.0f),		// camera is at (4,3,3), in world space - Where the camera is inside world.
		glm::vec3(0.0f, 0.0f, 0.0f),		// and looks at the origin - What point the camera is looking at inside world.
		glm::vec3(0.0f, 1.0f, 0.0f)			// head is up(set to 0,1,0) - the direction of up for camera.
		);

	glViewport(0, 0, WindowWidth, WindowHeight);

	return EXIT_SUCCESS;

}

int main(int argc, char** argv) {

	if (initializeGLFWGLEW() == EXIT_FAILURE) {

		exit(EXIT_FAILURE);

	}

	if (prepareOpenGL() == EXIT_FAILURE) {

		exit(EXIT_FAILURE);

	}

	if (loadShaders() == EXIT_FAILURE) {

		exit(EXIT_FAILURE);

	}

	if (prepareShaderUniforms() == EXIT_FAILURE) {

		exit(EXIT_FAILURE);

	}

	if (loadCubes() == EXIT_FAILURE) {

		exit(EXIT_FAILURE);

	}

	if (prepareMatricies() == EXIT_FAILURE) {

		exit(EXIT_FAILURE);

	}

	while (!glfwWindowShouldClose(MainWindow))

	{

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		for (auto & C : Cubes) {

			C.DrawMe();

		}

		glfwSwapBuffers(MainWindow);

		glfwPollEvents();

	}

	exit(EXIT_SUCCESS);

}
Advertisement

glUniformBlockBinding(MainOpenGLShaderProgramID, MatricesUniformBlockID, 1);

glGenBuffers(1, &MatricesUniformBufferID);

glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);

glBindBufferBase(GL_UNIFORM_BUFFER, 0, MatricesUniformBufferID);

glBindBufferBase/Range also bind the generic target, so at least for just filling the buffer, those last two calls are the same.


glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);

//fills the buffer

glBindBuffer(GL_UNIFORM_BUFFER, NULL);

This is where you need to glBindBufferBase to binding point 1 that you've set up for the block. No need to unbind it.

And also stop using NULL when you mean zero.

New C/C++ Build Tool 'Stir' (doesn't just generate Makefiles, it does the build): https://github.com/space222/stir


glUniformBlockBinding(MainOpenGLShaderProgramID, MatricesUniformBlockID, 1);

glGenBuffers(1, &MatricesUniformBufferID);

glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);

glBindBufferBase(GL_UNIFORM_BUFFER, 0, MatricesUniformBufferID);

glBindBufferBase/Range also bind the generic target, so at least for just filling the buffer, those last two calls are the same.


glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);

//fills the buffer

glBindBuffer(GL_UNIFORM_BUFFER, NULL);

This is where you need to glBindBufferBase to binding point 1 that you've set up for the block. No need to unbind it.

And also stop using NULL when you mean zero.

So I make the changes you suggested but no dice.

What I found interesting is that for my light and material uniform blocks I get the index but the uniform block for my MVP matrix I don't get the index.

I also have the updated code at the very bottom of this post.

Any additional ideas?

Here is the relavent vertex and fragment shaders isolated out:

Vertex Shader


#version 330 

		layout(std140) uniform MatrixInformation {
			mat4 m_pvm;
			mat4 m_viewModel;
			mat3 m_normal;
		};

		layout(std140) uniform Lights {
			vec3 l_dir; 
		};
		in vec4 position;
		in vec3 normal;
		
		out Data{
			vec3 normal;
			vec4 eye;
		} DataOut;
		
		void main() {
			
			DataOut.normal = normalize(m_normal * normal);
			DataOut.eye = -(m_viewModel * position);
			
			gl_Position = m_pvm * position;
		}
	


Fragment Shader


#version 330
    	layout(std140) uniform Materials {
			vec4 diffuse;
			vec4 ambient;
			vec4 specular;
			vec4 emissive;
			float shininess;
			int texCount;
		};		
		layout(std140) uniform Lights {
			vec3 l_dir; 
		};		
		in Data{
			vec3 normal;
			vec4 eye;
		} DataIn;
		
		out vec4 colorOut;		
		void main() {
			
			vec4 spec = vec4(0.0);
			
			vec3 n = normalize(DataIn.normal);
			vec3 e = normalize(vec3(DataIn.eye));
			
			float intensity = max(dot(n, l_dir), 0.0);
			
			if (intensity > 0.0) {
				vec3 h = normalize(l_dir + e);
				
				float intSpec = max(dot(h, n), 0.0);
				spec = specular * pow(intSpec, shininess);
			}
		
		colorOut = max(intensity *  diffuse + spec, ambient);
	}

Complete code:


#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>

#ifndef OPENGL_INCLUDES_
#define OPENGL_INCLUDES_

#include "GL\glew.h"

#ifndef GLFW_INCLUDES_
#define GLFW_INCLUDES_

#if defined(_WIN32)
#include <Windows.h>
#define GLFW_EXPOSE_NATIVE_WIN32
#define GLFW_EXPOSE_NATIVE_WGL
#elif defined(__linux__)
#include <X11/X.h>
#include <X11/extensions/Xrandr.h>
#define GLFW_EXPOSE_NATIVE_X11
#define GLFW_EXPOSE_NATIVE_GLX
#endif

#include "GLFW\glfw3.h"
#include "GLFW\glfw3native.h"

#endif

#endif

#ifndef GLM_INCLUDES_
#define GLM_INCLUDES_

#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>

#endif

GLFWwindow* MainWindow;

#ifdef _WIN32

HWND MainWindowWin32Handle;

#endif

GLint WindowWidth = 1024;
GLint WindowHeight = 768;

GLulong SizeDivizor = 1;

GLboolean RiftAvailable = false;
GLboolean UseApplicationWindowFrame = false;

GLuint MainOpenGLShaderProgramID;
GLuint MatricesUniformBlockID;
GLuint MatricesUniformBufferID;

GLuint LightsUniformBlockID;
GLuint LightsUniformBufferID;

GLuint MaterialsUniformBlockID;
GLuint MaterialsUniformBufferID;

glm::mat4 ViewMatrix;
glm::mat4 ViewModelMatrix;
glm::mat4 ProjectionMatrix;
glm::mat4 MVPMatrix;
glm::mat3 NormalMatrix;

class StandardCube;

std::vector<StandardCube> Cubes;

class StandardCube {

private:

	GLfloat* Vertices;
	GLfloat* Normals;
	GLuint* Indices;

	GLuint VAO;

	glm::mat4 ModelMatrix;

public:

	void LoadIntoOpenGL() {

		Vertices = new GLfloat[72]

		{
			1.0f, 1.0f, 1.0f,
			-1.0f, 1.0f, 1.0f,
			-1.0f, -1.0f, 1.0f,
			1.0f, -1.0f, 1.0f,
			-1.0f, -1.0f, -1.0f,
			-1.0f, 1.0f, -1.0f,
			1.0f, 1.0f, -1.0f,
			1.0f, -1.0f, -1.0f,
			1.0f, 1.0f, 1.0f,
			1.0f, 1.0f, -1.0f,
			-1.0f, 1.0f, -1.0f,
			-1.0f, 1.0f, 1.0f,
			-1.0f, -1.0f, -1.0f,
			1.0f, -1.0f, -1.0f,
			1.0f, -1.0f, 1.0f,
			-1.0f, -1.0f, 1.0f,
			1.0f, 1.0f, 1.0f,
			1.0f, -1.0f, 1.0f,
			1.0f, -1.0f, -1.0f,
			1.0f, 1.0f, -1.0f,
			-1.0f, -1.0f, -1.0f,
			-1.0f, -1.0f, 1.0f,
			-1.0f, 1.0f, 1.0f,
			-1.0f, 1.0f, -1.0f
		};

		Normals = new GLfloat[72] {
			0.0f, 0.0f, 1.0f,
			0.0f, 0.0f, 1.0f,
			0.0f, 0.0f, 1.0f,
			0.0f, 0.0f, 1.0f,
			0.0f, 0.0f, -1.0f,
			0.0f, 0.0f, -1.0f,
			0.0f, 0.0f, -1.0f,
			0.0f, 0.0f, -1.0f,
			0.0f, 1.0f, 0.0f,
			0.0f, 1.0f, 0.0f,
			0.0f, 1.0f, 0.0f,
			0.0f, 1.0f, 0.0f,
			0.0f, -1.0f, 0.0f,
			0.0f, -1.0f, 0.0f,
			0.0f, -1.0f, 0.0f,
			0.0f, -1.0f, 0.0f,
			1.0f, 0.0f, 0.0f,
			1.0f, 0.0f, 0.0f,
			1.0f, 0.0f, 0.0f,
			1.0f, 0.0f, 0.0f,
			-1.0f, 0.0f, 0.0f,
			-1.0f, 0.0f, 0.0f,
			-1.0f, 0.0f, 0.0f,
			-1.0f, 0.0f, 0.0f
		};

		Indices = new GLuint[36] {0, 1, 2, 2, 3, 0,
			4, 5, 6, 6, 7, 4,
			8, 9, 10, 10, 11, 8,
			12, 13, 14, 14, 15, 12,
			16, 17, 18, 18, 19, 16,
			20, 21, 22, 22, 23, 20
		};

		glGenVertexArrays(1, &VAO);
		glBindVertexArray(VAO);

		GLuint MeshBufferID;
		glGenBuffers(1, &MeshBufferID);
		glBindBuffer(GL_ARRAY_BUFFER, MeshBufferID);

		GLuint TotalBufferData = (sizeof(GLfloat) * 72) + (sizeof(GLfloat) * 72);

		glBufferData(GL_ARRAY_BUFFER, TotalBufferData, NULL, GL_STATIC_DRAW);

		glBufferSubData(GL_ARRAY_BUFFER, NULL, sizeof(GLfloat) * 72, Vertices);

		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
		glEnableVertexAttribArray(0);

		glBufferSubData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 72, sizeof(GLfloat) * 72, Normals);

		glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(sizeof(GLfloat) * 72));
		glEnableVertexAttribArray(1);

		GLuint IndexBufferID;
		glGenBuffers(1, &IndexBufferID);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * 36, Indices, GL_STATIC_DRAW);

		glBindVertexArray(NULL);

		ModelMatrix = glm::mat4(1.0f);

	}

	void DrawMe() {

		MVPMatrix = ProjectionMatrix * ViewMatrix * ModelMatrix;
		ViewModelMatrix = ViewMatrix * ModelMatrix;
		NormalMatrix = glm::transpose(glm::inverse(glm::mat3(MVPMatrix)));

		glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);

		glBufferSubData(GL_UNIFORM_BUFFER, NULL, sizeof(glm::mat4), glm::value_ptr(MVPMatrix));
		glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(ViewModelMatrix));
		glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4) + sizeof(glm::mat4), sizeof(glm::mat3), glm::value_ptr(NormalMatrix));

		glBindBuffer(GL_UNIFORM_BUFFER, NULL);

		glBindVertexArray(VAO);
		glDrawElementsInstanced(GL_TRIANGLES, 36, GL_UNSIGNED_INT, NULL, 1);
		glBindVertexArray(NULL);

	}

};

static void GLFWKeyCallback(GLFWwindow* p_Window, GLint p_Key, GLint p_Scancode, GLint p_Action, GLint p_Mods) {

	if (p_Key == GLFW_KEY_ESCAPE && p_Action == GLFW_PRESS) {

		glfwSetWindowShouldClose(p_Window, GL_TRUE);
	}

	if (p_Key == GLFW_KEY_O && p_Action == GLFW_PRESS) {

		glClearColor(0.2f, 0.1f, 0.3f, 1.0f);

	}

	if (p_Key == GLFW_KEY_I && p_Action == GLFW_PRESS) {

		glClearColor(1.0f, 0.5f, 0.5f, 1.0f);

	}

}

static void GLFWWindowResizeCallBack(GLFWwindow* p_Window, GLint width, GLint height) {

	//CurrentGLFWApplication->WindowResizeCallBack(p_Window, width, height);

}

static void GLFWMouseMovementCallBack(GLFWwindow* p_Window, GLdouble MouseX, GLdouble MouseY) {

	//CurrentGLFWApplication->MouseMovementCallBack(p_Window, MouseX, MouseY);

}

static void GLFWFramebufferSizeCallback(GLFWwindow* window, GLint width, GLint height)
{

	glViewport(0, 0, width, height);

}

int initializeGLFWGLEW() {

	MainWindow = NULL;

	if (!glfwInit())
	{

		fprintf(stderr, "GLFW failed to initialize.");
		glfwTerminate();
		return EXIT_FAILURE;

	}

	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);

	if (UseApplicationWindowFrame) {

		MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Basic Oculus Rift Example", NULL, NULL);

	}
	else {

		if (!RiftAvailable) {

			MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Basic Oculus Rift Example", NULL, NULL);

		}
		else {

			GLint MonitorCount;
			GLFWmonitor** GLFW_Monitors = glfwGetMonitors(&MonitorCount);
			GLFWmonitor* MonitorToUse;

			switch (MonitorCount)
			{
			case 0:
				printf("No monitors found, exiting.\n");
				return EXIT_FAILURE;
				break;
			case 1:
				printf("Two monitors expected, found only one, using primary...\n");
				MonitorToUse = glfwGetPrimaryMonitor();
				break;
			case 2:
				printf("Two monitors found, using second monitor\n");
				MonitorToUse = GLFW_Monitors[1];
				break;
			default:
				printf("More than two monitors found, using second monitor\n");
				MonitorToUse = GLFW_Monitors[1];
			}

			MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Basic Oculus Rift Example", MonitorToUse, NULL);

		}

	}

	if (!MainWindow)
	{
		fprintf(stderr, "Could not determine OpenGL version; exiting.");
		glfwTerminate();
		return EXIT_FAILURE;
	}

	glfwMakeContextCurrent(MainWindow);

	glewExperimental = GL_TRUE;
	GLenum err = glewInit();

	if (GLEW_OK != err)
	{
		/* Problem: glewInit failed, something is seriously wrong. */
		fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
		return EXIT_FAILURE;

	}

	glfwSetInputMode(MainWindow, GLFW_STICKY_KEYS, GL_TRUE);

	glfwSetKeyCallback(MainWindow, GLFWKeyCallback);
	glfwSetWindowSizeCallback(MainWindow, GLFWWindowResizeCallBack);
	glfwSetCursorPosCallback(MainWindow, GLFWMouseMovementCallBack);
	glfwSetFramebufferSizeCallback(MainWindow, GLFWFramebufferSizeCallback);

	glfwSwapBuffers(MainWindow);

	glfwPollEvents();

	return EXIT_SUCCESS;

}

int prepareOpenGL() {

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glEnable(GL_CULL_FACE);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_MULTISAMPLE);

	return EXIT_SUCCESS;

}

int loadShaders() {

	// Create the shaders
	GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
	GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

	// Compile Vertex Shader
	printf("Compiling Vertext Shader.\n\n");
	char const * VertexSource = "#version 330 \n\n\
		layout(std140) uniform MatrixInformation {\n\
			mat4 m_pvm;\n\
			mat4 m_viewModel;\n\
			mat3 m_normal;\n\
		};\n\
		layout(std140) uniform Lights {\n\
			vec3 l_dir; \n\
		};\n\
		in vec4 position;\n\
		in vec3 normal;\n\
		\n\
		\n\
		out Data{\n\
			vec3 normal;\n\
			vec4 eye;\n\
		} DataOut;\n\
		\n\
		void main() {\n\
			\n\
			DataOut.normal = normalize(m_normal * normal);\n\
			DataOut.eye = -(m_viewModel * position);\n\
			\n\
			gl_Position = m_pvm * position;\n\
		}\n\
	\n";

	glShaderSource(VertexShaderID, 1, &VertexSource, NULL);
	glCompileShader(VertexShaderID);

	// Check Vertex Shader

	GLint Result = GL_FALSE;
	int InfoLogLength;

	glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);

	if (InfoLogLength > 0){

		std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
		glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
		std::string ErrorMessage = std::string(&VertexShaderErrorMessage[0]);
		printf("%s\n", &VertexShaderErrorMessage[0]);

	}

	printf("Compiling Fragment Shader.\n\n");
	char const * FragmentSource = "#version 330\n\
    	layout(std140) uniform Materials {\n\
			vec4 diffuse;\n\
			vec4 ambient;\n\
			vec4 specular;\n\
			vec4 emissive;\n\
			float shininess;\n\
			int texCount;\n\
		};\
		\n\
		layout(std140) uniform Lights {\n\
			vec3 l_dir; \n\
		};\
		\n\
		in Data{\n\
			vec3 normal;\n\
			vec4 eye;\n\
		} DataIn;\n\
		\n\
		out vec4 colorOut;\
		\n\
		void main() {\n\
			\n\
			vec4 spec = vec4(0.0);\n\
			\n\
			vec3 n = normalize(DataIn.normal);\n\
			vec3 e = normalize(vec3(DataIn.eye));\n\
			\n\
			float intensity = max(dot(n, l_dir), 0.0);\n\
			\n\
			if (intensity > 0.0) {\n\
				vec3 h = normalize(l_dir + e);\n\
				\n\
				float intSpec = max(dot(h, n), 0.0);\n\
				spec = specular * pow(intSpec, shininess);\n\
			}\n\
		\n\
		colorOut = max(intensity *  diffuse + spec, ambient);\n\
	}";

	glShaderSource(FragmentShaderID, 1, &FragmentSource, NULL);
	glCompileShader(FragmentShaderID);

	// Check Fragment Shader
	glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	if (InfoLogLength > 0){

		std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
		glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
		std::string ErrorMessage = std::string(&FragmentShaderErrorMessage[0]);
		printf("%s\n", &FragmentShaderErrorMessage[0]);

	}

	// Link the program
	printf("Linking shader program.\n\n");
	GLuint ProgramID = glCreateProgram();
	glAttachShader(ProgramID, VertexShaderID);
	glAttachShader(ProgramID, FragmentShaderID);
	glLinkProgram(ProgramID);

	// Check the program
	glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
	glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	if (InfoLogLength > 0){

		std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
		glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
		std::string ErrorMessage = std::string(&ProgramErrorMessage[0]);
		printf("%s\n", &ProgramErrorMessage[0]);

	}

	glDeleteShader(VertexShaderID);
	glDeleteShader(FragmentShaderID);

	MainOpenGLShaderProgramID = ProgramID;

	return EXIT_SUCCESS;

}

int prepareShaderUniforms() {

	glUseProgram(MainOpenGLShaderProgramID);

	LightsUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Lights");
	glUniformBlockBinding(MainOpenGLShaderProgramID, LightsUniformBlockID, 2);
	glGenBuffers(1, &LightsUniformBufferID);
	glBindBuffer(GL_UNIFORM_BUFFER, LightsUniformBufferID);
	glBindBufferBase(GL_UNIFORM_BUFFER, 2, LightsUniformBufferID);

	GLfloat LightDirection[3] = { 1.0f, 1.0f, 0.0f };

	glBufferData(GL_UNIFORM_BUFFER, sizeof(LightDirection), &LightDirection, GL_DYNAMIC_DRAW);
	glBindBuffer(GL_UNIFORM_BUFFER, NULL);

	MatricesUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "MatrixInformation");
	glUniformBlockBinding(MainOpenGLShaderProgramID, MatricesUniformBlockID, 1);
	glGenBuffers(1, &MatricesUniformBufferID);
	glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);
	glBindBufferBase(GL_UNIFORM_BUFFER, 1, MatricesUniformBufferID);
	GLsizeiptr TotalBufferSize = sizeof(glm::mat4) + sizeof(glm::mat4);
	TotalBufferSize += sizeof(glm::mat3);
	glBufferData(GL_ARRAY_BUFFER, TotalBufferSize, NULL, GL_DYNAMIC_DRAW);
	glBindBuffer(GL_UNIFORM_BUFFER, NULL);

	MaterialsUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Materials");
	glUniformBlockBinding(MainOpenGLShaderProgramID, MaterialsUniformBlockID, 3);
	glGenBuffers(1, &MaterialsUniformBufferID);
	glBindBuffer(GL_UNIFORM_BUFFER, MaterialsUniformBufferID);
	glBindBufferBase(GL_UNIFORM_BUFFER, 3, MaterialsUniformBufferID);

	GLfloat Material[18];

	//Diffuse
	Material[0] = 0.5f;
	Material[1] = 0.0f;
	Material[2] = 0.0f;
	Material[3] = 1.0f;

	//Ambient
	Material[4] = 0.2f;
	Material[5] = 0.2f;
	Material[6] = 0.2f;
	Material[7] = 1.0f;

	//Specular
	Material[8] = 0.0f;
	Material[9] = 0.0f;
	Material[10] = 0.0f;
	Material[11] = 1.0f;

	//Emissive
	Material[12] = 0.0f;
	Material[13] = 0.0f;
	Material[14] = 0.0f;
	Material[15] = 1.0f;

	//Shininess
	Material[16] = 2.0f;

	//Texture Count
	Material[17] = 0.0f;

	glBufferData(GL_UNIFORM_BUFFER, sizeof(Material), &Material, GL_DYNAMIC_DRAW);
	glBindBuffer(GL_UNIFORM_BUFFER, NULL);

	return EXIT_SUCCESS;

}

int loadCubes() {

	StandardCube NewCube;

	NewCube.LoadIntoOpenGL();

	Cubes.push_back(NewCube);

	return EXIT_SUCCESS;

}

int prepareMatricies() {

	GLfloat AspectRatio = (GLfloat)(WindowWidth) / (GLfloat)(WindowHeight);

	ProjectionMatrix = glm::perspective(45.0f, AspectRatio, 1.0f, 1000.0f);

	ViewMatrix = glm::lookAt(
		glm::vec3(4.0f, 3.0f, 3.0f),		// camera is at (4,3,3), in world space - Where the camera is inside world.
		glm::vec3(0.0f, 0.0f, 0.0f),		// and looks at the origin - What point the camera is looking at inside world.
		glm::vec3(0.0f, 1.0f, 0.0f)// head is up(set to 0,1,0) - the direction of up for camera.
		);

	glViewport(0, 0, WindowWidth, WindowHeight);

	return EXIT_SUCCESS;

}

int main(int argc, char** argv) {

	if (initializeGLFWGLEW() == EXIT_FAILURE) {

		exit(EXIT_FAILURE);

	}

	if (prepareOpenGL() == EXIT_FAILURE) {

		exit(EXIT_FAILURE);

	}

	if (loadShaders() == EXIT_FAILURE) {

		exit(EXIT_FAILURE);

	}

	if (prepareShaderUniforms() == EXIT_FAILURE) {

		exit(EXIT_FAILURE);

	}

	if (loadCubes() == EXIT_FAILURE) {

		exit(EXIT_FAILURE);

	}

	if (prepareMatricies() == EXIT_FAILURE) {

		exit(EXIT_FAILURE);

	}

	while (!glfwWindowShouldClose(MainWindow))

	{

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		for (auto & C : Cubes) {

			C.DrawMe();

		}

		glfwSwapBuffers(MainWindow);

		glfwPollEvents();

	}

	exit(EXIT_SUCCESS);

}

The vertex shader input attributes need to be assigned a location, whether with layout or glBindAttribLocation.


MatricesUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "MatrixInformation"); glUniformBlockBinding(MainOpenGLShaderProgramID, MatricesUniformBlockID, 1);

glGenBuffers(1, &MatricesUniformBufferID);

glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);

glBindBufferBase(GL_UNIFORM_BUFFER, 1, MatricesUniformBufferID); GLsizeiptr TotalBufferSize = sizeof(glm::mat4) + sizeof(glm::mat4); TotalBufferSize += sizeof(glm::mat3);
glBufferData(GL_ARRAY_BUFFER, TotalBufferSize, NULL, GL_DYNAMIC_DRAW);

glBindBuffer(GL_UNIFORM_BUFFER, NULL);

There's a typo highlighted, that should be GL_UNIFORM_BUFFER.

Also, I didn't try to get the lighting glsl to work, I just output red from the fragment shader to make sure there was output.

It's a cube!

New C/C++ Build Tool 'Stir' (doesn't just generate Makefiles, it does the build): https://github.com/space222/stir

The vertex shader input attributes need to be assigned a location, whether with layout or glBindAttribLocation.

[...]

There's a typo highlighted, that should be GL_UNIFORM_BUFFER.
Also, I didn't try to get the lighting glsl to work, I just output red from the fragment shader to make sure there was output.
It's a cube!


Indeed; that was the problem! And yes, it was a cube smile.png

This topic is closed to new replies.

Advertisement