Advertisement

Minimum of 66 verts?

Started by November 12, 2019 11:15 PM
56 comments, last by Bozemoto 4 years, 10 months ago
57 minutes ago, Net-Ninja said:

Now I'm even more confused, works fine if I comment these lines out

Maybe you are just tired and made incorrect assumption.

Back to what I've said. Most GPU's are designed for 32byte, newer for 64byte, vertex element size. You should always use that size for a single vertex unless you want to be subjected to serious performance hit, or, hidden vertex alignment padding by driver.

Generaly, drivers tend to be tested on standard routines, what yours definitely is not- that is streaming each attribute to it's own buffer.

JohnnyCode: I've created a testbed project and I'm not only providing a vertex buffer, a uniform colour and a uniform modelviewprojection matrix. It's still crashing. So it has nothing to do with having multiple vbos. I'll keep the padding in mind for future iterations of the program.

Think I was mistaken in that removing those lines fixed it, as I've been unable to repro since. 
I'm trying now to create a buffer with 3 hardcoded vertex points in it and it's still crashing.
I think the most likely explanation at this point is that my drivers aren't working properly.
I've had it suggested to me to try and repro on a virtual machine with a software renderer.
I'll do that in the morning.

Video Game Programmer.
5 years in industry.

Advertisement

Maybe you are having a memory leak that manifests on drawelements call, post entire code of your test application.

Here's a shrunk down version of the program, I've tried making it into one document which is why it's a bit messy. Shaders incoming
I'm using SDL2-2.0.7

Spoiler


#include <SDL.h>

#include <stdio.h>
#include <cstring>
#include <fstream>
#include <string>
#include <iostream>
#include <vector>
#include <cmath>
#include <Windows.h>
#include <gl\GL.h>

static constexpr const float PI = 3.1416f; // 3.14159265359

inline constexpr float DegToRad(float degrees)
{
	return degrees * (PI / 180.0f);
}



#include "matrix.h"
#include "Vector.h"

 // --- x86 vs x64 ---

//__cdecl
//__stdcall
#if defined(_WIN32) && !defined(_WIN64)
#define STDCALL __stdcall
#else 
#define STDCALL
#endif

// --- OpenGL defines ---

#define GL_MULTISAMPLE			0x809D

#define GL_FRAGMENT_SHADER		0x8B30
#define GL_VERTEX_SHADER		0x8B31
#define GL_COMPILE_STATUS		0x8B81
#define GL_LINK_STATUS			0x8B82
#define GL_INFO_LOG_LENGTH		0x8B84

#define GL_ARRAY_BUFFER			0x8892
#define GL_ELEMENT_ARRAY_BUFFER 0x8893

#define GL_STATIC_DRAW			0x88E4
#define GL_STATIC_READ			0x88E5
#define GL_STATIC_COPY			0x88E6
#define GL_DYNAMIC_DRAW			0x88E8
#define GL_DYNAMIC_READ			0x88E9
#define GL_DYNAMIC_COPY			0x88EA

#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242

// -----------------------------------------

#define GL_ACTIVE_TEXTURE 0x84E0

#define GL_TEXTURE0 0x84C0
#define GL_TEXTURE1 0x84C1
#define GL_TEXTURE2 0x84C2
#define GL_TEXTURE3 0x84C3

#define GL_CURRENT_PROGRAM 0x8B8D
#define GL_ARRAY_BUFFER_BINDING 0x8894
#define GL_VERTEX_ARRAY_BINDING 0x85B5
#define GL_BLEND_DST_RGB 0x80C8
#define GL_BLEND_SRC_RGB 0x80C9
#define GL_BLEND_DST_ALPHA 0x80CA
#define GL_BLEND_SRC_ALPHA 0x80CB
#define GL_BLEND_EQUATION 0x8009
#define GL_BLEND_EQUATION_RGB GL_BLEND_EQUATION
#define GL_BLEND_EQUATION_ALPHA 0x883D
#define GL_FUNC_ADD 0x8006
#define GL_STREAM_DRAW 0x88E0

#define GL_ACTIVE_UNIFORMS 0x8B86
#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
#define GL_UNIFORM_TYPE 0x8A37

#define GL_SHADER_TYPE                    0x8B4F
#define GL_FLOAT_VEC2                     0x8B50
#define GL_FLOAT_VEC3                     0x8B51
#define GL_FLOAT_VEC4                     0x8B52
#define GL_INT_VEC2                       0x8B53
#define GL_INT_VEC3                       0x8B54
#define GL_INT_VEC4                       0x8B55
#define GL_BOOL                           0x8B56
#define GL_BOOL_VEC2                      0x8B57
#define GL_BOOL_VEC3                      0x8B58
#define GL_BOOL_VEC4                      0x8B59
#define GL_FLOAT_MAT2                     0x8B5A
#define GL_FLOAT_MAT3                     0x8B5B
#define GL_FLOAT_MAT4                     0x8B5C
#define GL_SAMPLER_1D                     0x8B5D
#define GL_SAMPLER_2D                     0x8B5E
#define GL_SAMPLER_3D                     0x8B5F
#define GL_SAMPLER_CUBE                   0x8B60
#define GL_SAMPLER_1D_SHADOW              0x8B61
#define GL_SAMPLER_2D_SHADOW              0x8B62

// --- OpenGL types ---

typedef char GLchar;
typedef size_t GLsizeiptr;

void(STDCALL *glGenVertexArrays)(GLuint, GLuint*) = nullptr;
void(STDCALL *glBindVertexArray)(GLuint) = nullptr;
void(STDCALL *glGenBuffers)(GLuint, GLuint*) = nullptr;

void(STDCALL *glBindBuffer)(GLenum target, GLuint buffer) = nullptr;
void(STDCALL *glBufferData)(GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage) = nullptr;

// Shaders
GLuint(STDCALL *glCreateShader)(GLenum shaderType) = nullptr;
void(STDCALL *glDeleteShader)(GLuint shader) = nullptr;
GLuint(STDCALL *glCreateProgram)() = nullptr;
void(STDCALL *glDeleteProgram)(GLuint program) = nullptr;
void(STDCALL *glShaderSource)(GLuint shader, GLsizei count, const GLchar **string, const GLint *length) = nullptr;
void(STDCALL *glCompileShader)(GLuint shader) = nullptr;
void(STDCALL *glAttachShader)(GLuint program, GLuint shader) = nullptr;
void(STDCALL *glDetachShader)(GLuint program, GLuint shader) = nullptr;
void(STDCALL *glLinkProgram)(GLuint program) = nullptr;
void(STDCALL *glUseProgram)(GLuint program) = nullptr;

void(STDCALL *glGetShaderiv)(GLuint shader, GLenum pname, GLint *params) = nullptr;
void(STDCALL *glGetProgramiv)(GLuint program, GLenum pname, GLint *params) = nullptr;
void(STDCALL *glGetShaderInfoLog)(GLuint shader, GLsizei maxLength, GLsizei *length, GLchar *infoLog) = nullptr;
void(STDCALL *glGetProgramInfoLog)(GLuint program, GLsizei maxLength, GLsizei *length, GLchar *infoLog) = nullptr;
GLint(STDCALL *glGetAttribLocation)(GLuint program, const GLchar *name) = nullptr;

void(STDCALL *glEnableVertexAttribArray)(GLuint index) = nullptr;
void(STDCALL *glDisableVertexAttribArray)(GLuint index) = nullptr;
void(STDCALL *glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer) = nullptr;

GLint(STDCALL *glGetUniformLocation)(GLuint program, const GLchar *name) = nullptr;
void(STDCALL *glUniform4f)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) = nullptr;
void(STDCALL *glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = nullptr;

typedef void (APIENTRY *DEBUGPROC)(GLenum source,
	GLenum type,
	GLuint id,
	GLenum severity,
	GLsizei length,
	const GLchar *message,
	const void *userParam);

void(STDCALL *glDebugMessageCallback)(DEBUGPROC callback, void* userData) = nullptr;

struct Color {
	float r, g, b, a;
	static Color White;
	static Color Black;
	static Color Red;
	static Color Green;
	static Color Blue;
};

Color Color::White = { 1.0f, 1.0f, 1.0f, 1.0f };
Color Color::Black = { 0.0f, 0.0f, 0.0f, 1.0f };
Color Color::Red = { 1.0f, 0.0f, 0.0f, 1.0f };
Color Color::Green = { 0.0f, 1.0f, 0.0f, 1.0f };
Color Color::Blue = { 0.0f, 0.0f, 1.0f, 1.0f };

enum class AlphaMode { SOLID = 0, BLEND, ADDATIVE };

// --- SHADER ---

struct Shader
{
	GLuint gl_shader_program = 0;

	inline ~Shader();

	bool Create(const char* vertex_shader, const char* pixel_shader);
	void Destroy();
	void Use();

	static void ClearActiveShader();
	static bool LoadShader(Shader& shader_out, const char* vert_shader_path, const char* frag_shader_path);
};

static Shader s_defaultShaderSimple;
static GLuint s_current_shader = 0;

// ----------------------------------------------------

Matrix s_view_matrix = Matrix::CreateScale(1.0f);
Matrix s_projection_matrix = Matrix::CreateScale(1.0f);

// --- --- --- --- --- --- --- --- --- --- --- --- ---

struct ScreenResolution
{
	int w, h;
};

static const constexpr ScreenResolution screen_resolution_16_9[] =
{
	{ 1024, 576 }, { 1152, 648 }, { 1280, 720 }, { 1366, 768 },
	{ 1600, 900 }, { 1920, 1080 }, { 2560, 1440 }, { 3840, 2160 }
};

//Screen dimension constants
static const constexpr int SCREEN_W = screen_resolution_16_9[2].w;
static const constexpr int SCREEN_H = screen_resolution_16_9[2].h;

// --- --- --- --- --- --- --- --- --- --- --- --- ---

static SDL_Window* s_sdl_window = nullptr;
static SDL_GLContext s_gl_context;

void InitializeGraphics();

void CheckForErrors();

extern Matrix s_view_matrix;
extern Vector3 s_view_pos;
extern Matrix s_projection_matrix;

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

// ---

struct Mesh
{
	GLuint vao = 0; // Vertex array object
	GLuint vbo = 0; // Vertices

	bool made_buffers = false;
	bool MakeBuffers();

	//struct Vertex { float x, y, z; };
	typedef Vector3 Vertex;
	Vertex* vertices = nullptr;
	size_t num_verts = 0;
};

void CreateTree(Mesh& mesh, float height, float width);
void DrawMeshShaded(Mesh& mesh, Color color, Shader& shader, AlphaMode alpha_mode = AlphaMode::SOLID, Matrix* mat = nullptr);

int main(int argc, char* argv[])
{
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0)
	{
		SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
		return 1;
	}

	// Setup window
	SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);

	//SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	//SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
	//SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);

	//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
	//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);

	SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);

	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
	//SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

	SDL_DisplayMode current;
	SDL_GetCurrentDisplayMode(0, &current);
	s_sdl_window = SDL_CreateWindow("Testbed", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_W, SCREEN_H, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);

	if (s_sdl_window == NULL)
	{
		const char* err = SDL_GetError();
		printf("Could not create window: %s\n", err);
		return 1;
	}

	// Graphics
	s_gl_context = SDL_GL_CreateContext(s_sdl_window);
	SDL_GL_SetSwapInterval(1); // Enable vsync

	// Other
	SDL_GL_MakeCurrent(s_sdl_window, s_gl_context);
	InitializeGraphics();
	Mesh tube_mesh;
	CreateTree(tube_mesh, 1.0, 1.0f);

	// Main loop
	bool running = true;
	while (running)
	{
		SDL_Event current_event;
		while (SDL_PollEvent(&current_event))
		{
			switch (current_event.type)
			{
			case SDL_QUIT:
				running = false;
				break;
			}
		}

		SDL_GL_MakeCurrent(s_sdl_window, s_gl_context);

		glViewport(0, 0, SCREEN_W, SCREEN_H);
		
		glFrontFace(GL_CW);
		glEnable(GL_CULL_FACE);
		glCullFace(GL_BACK);

		glEnable(GL_DEPTH_TEST);

		glClearColor(135.0f / 255.0f, 206.0f / 255.0f, 235.0f / 255.0f, 0.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		// PROJECTION & VIEW
		{
			float aspect = (float)SCREEN_W / SCREEN_H;
			s_projection_matrix = Matrix::CreatePerspective(90.0f, aspect, 0.001f, 500.0f);
			s_view_matrix = Matrix::CreateTranslation({0.0f, 0.0f, 5.0f});
		}

		DrawMeshShaded(tube_mesh, Color::White, s_defaultShaderSimple, AlphaMode::SOLID, nullptr);

		glDisable(GL_DEPTH_TEST);
		SDL_GL_SwapWindow(s_sdl_window);
	}

	s_defaultShaderSimple.Destroy();

	SDL_GL_DeleteContext(s_gl_context);
	SDL_Quit();
	return 0;
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void APIENTRY glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
	std::cout << message << std::endl;
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void CheckForErrors()
{
	GLenum error_code = 0;
	while (error_code = glGetError())
	{
		std::cout << (int)error_code << std::endl;
	}
}

void InitializeGraphics()
{
	(void *&)glGenVertexArrays = SDL_GL_GetProcAddress("glGenVertexArrays");
	(void *&)glBindVertexArray = SDL_GL_GetProcAddress("glBindVertexArray");
	(void *&)glGenBuffers = SDL_GL_GetProcAddress("glGenBuffers");
	(void *&)glBindBuffer = SDL_GL_GetProcAddress("glBindBuffer");
	(void *&)glBufferData = SDL_GL_GetProcAddress("glBufferData");

	// --- Shaders
	(void *&)glCreateShader = SDL_GL_GetProcAddress("glCreateShader");
	(void *&)glDeleteShader = SDL_GL_GetProcAddress("glDeleteShader");
	(void *&)glCreateProgram = SDL_GL_GetProcAddress("glCreateProgram");
	(void *&)glDeleteProgram = SDL_GL_GetProcAddress("glDeleteProgram");
	(void *&)glShaderSource = SDL_GL_GetProcAddress("glShaderSource"); // Set the source text
	(void *&)glCompileShader = SDL_GL_GetProcAddress("glCompileShader"); // Compile it
	(void *&)glAttachShader = SDL_GL_GetProcAddress("glAttachShader");
	(void *&)glDetachShader = SDL_GL_GetProcAddress("glDetachShader");
	(void *&)glLinkProgram = SDL_GL_GetProcAddress("glLinkProgram");
	(void *&)glUseProgram = SDL_GL_GetProcAddress("glUseProgram");

	(void *&)glGetShaderiv = SDL_GL_GetProcAddress("glGetShaderiv");
	(void *&)glGetProgramiv = SDL_GL_GetProcAddress("glGetProgramiv");
	(void *&)glGetShaderInfoLog = SDL_GL_GetProcAddress("glGetShaderInfoLog");
	(void *&)glGetProgramInfoLog = SDL_GL_GetProcAddress("glGetProgramInfoLog");
	(void *&)glGetAttribLocation = SDL_GL_GetProcAddress("glGetAttribLocation");

	(void *&)glVertexAttribPointer = SDL_GL_GetProcAddress("glVertexAttribPointer");
	(void *&)glEnableVertexAttribArray = SDL_GL_GetProcAddress("glEnableVertexAttribArray");
	(void *&)glDisableVertexAttribArray = SDL_GL_GetProcAddress("glDisableVertexAttribArray");

	(void *&)glGetUniformLocation = SDL_GL_GetProcAddress("glGetUniformLocation");
	(void *&)glUniform4f = SDL_GL_GetProcAddress("glUniform4f");
	(void *&)glUniformMatrix4fv = SDL_GL_GetProcAddress("glUniformMatrix4fv");

	(void*&)glDebugMessageCallback = SDL_GL_GetProcAddress("glDebugMessageCallback");

	Shader::LoadShader(s_defaultShaderSimple, "Shaders/default_simple.vert", "Shaders/default_simple.frag");

	glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
	glDebugMessageCallback(glDebugCallback, nullptr);

	glEnable(GL_MULTISAMPLE);
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

static_assert(3 * sizeof(GLfloat) == sizeof(Mesh::Vertex), "Mesh::Vertex must ve 3 * sizeof(GLfloat)");

bool Mesh::MakeBuffers()
{
	if (!made_buffers)
	{
		made_buffers = true;

		glGenVertexArrays(1, &vao);
		CheckForErrors();

		//Create VBO
		if (vertices)
		{
			glGenBuffers(1, &vbo);
			CheckForErrors();
			glBindBuffer(GL_ARRAY_BUFFER, vbo);
			CheckForErrors();
			glBufferData(GL_ARRAY_BUFFER, num_verts * 3 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
			CheckForErrors();
		}

		CheckForErrors();
	}

	return true;
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

inline Shader::~Shader() { Destroy(); }

bool Shader::Create(const char* vertex_shader, const char* pixel_shader)
{
	GLuint vertexshader = 0;
	GLuint fragmentshader = 0;

	vertexshader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexshader, 1, (const GLchar**)&vertex_shader, 0);
	glCompileShader(vertexshader);

	GLint IsCompiled_VS = 0;
	glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &IsCompiled_VS);
	if (IsCompiled_VS == FALSE)
	{
		GLint maxLength = 0;
		glGetShaderiv(vertexshader, GL_INFO_LOG_LENGTH, &maxLength);

		/* The maxLength includes the NULL character */
		char* vertexInfoLog = (char *)malloc(maxLength);
		glGetShaderInfoLog(vertexshader, maxLength, &maxLength, vertexInfoLog);
		printf(vertexInfoLog);
		free(vertexInfoLog);

		return false;
	}

	fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentshader, 1, (const GLchar**)&pixel_shader, 0);
	glCompileShader(fragmentshader);

	GLint IsCompiled_FS = 0;
	glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &IsCompiled_FS);
	if (IsCompiled_FS == FALSE)
	{
		GLint maxLength = 0;
		glGetShaderiv(fragmentshader, GL_INFO_LOG_LENGTH, &maxLength);

		/* The maxLength includes the NULL character */
		char* fragmentInfoLog = (char *)malloc(maxLength);
		glGetShaderInfoLog(fragmentshader, maxLength, &maxLength, fragmentInfoLog);
		printf(fragmentInfoLog);
		free(fragmentInfoLog);

		return false;
	}

	gl_shader_program = glCreateProgram();
	glAttachShader(gl_shader_program, vertexshader);
	glAttachShader(gl_shader_program, fragmentshader);
	glLinkProgram(gl_shader_program);

	glDeleteShader(vertexshader);
	glDeleteShader(fragmentshader);

	GLint IsLinked = 0;

	glGetProgramiv(gl_shader_program, GL_LINK_STATUS, (int *)&IsLinked);
	if (IsLinked == FALSE)
	{
		/* Noticed that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv. */
		GLint maxLength = 0;
		glGetProgramiv(gl_shader_program, GL_INFO_LOG_LENGTH, &maxLength);

		/* The maxLength includes the NULL character */
		char* shaderProgramInfoLog = (char *)malloc(maxLength);
		glGetProgramInfoLog(gl_shader_program, maxLength, &maxLength, shaderProgramInfoLog);
		printf(shaderProgramInfoLog);
		free(shaderProgramInfoLog);
		return false;
	}

	return true;
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void Shader::Destroy()
{
	// Clear Shader
	if (gl_shader_program != 0)
	{
		if (s_current_shader == gl_shader_program)
			Shader::ClearActiveShader();

		glDisableVertexAttribArray(0);
		glDisableVertexAttribArray(1);

		// Detach vert and frag from shader
		//glDetachShader(shaderprogram, vertexshader);
		//glDetachShader(shaderprogram, fragmentshader);

		// Destroy
		glDeleteProgram(gl_shader_program);
		//glDeleteShader(vertexshader);
		//glDeleteShader(fragmentshader);

		gl_shader_program = 0;
		//vertexshader = 0;
		//fragmentshader = 0;
	}
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void Shader::Use()
{
	glUseProgram(gl_shader_program);
	s_current_shader = gl_shader_program;
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void Shader::ClearActiveShader()
{
	s_current_shader = 0;
	glUseProgram(0);
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

bool Shader::LoadShader(Shader& shader_out, const char* vert_shader_path, const char* frag_shader_path)
{
	std::ifstream file_vert(vert_shader_path);
	std::ifstream file_frag(frag_shader_path);

	if (file_vert.is_open() && file_frag.is_open())
	{
		std::string vert;
		{
			file_vert.seekg(0, std::ios::end);
			vert.resize(file_vert.tellg());
			file_vert.seekg(0, std::ios::beg);
			file_vert.read(&vert[0], vert.size());
			file_vert.close();
		}

		std::string frag;
		{
			file_frag.seekg(0, std::ios::end);
			frag.resize(file_frag.tellg());
			file_frag.seekg(0, std::ios::beg);
			file_frag.read(&frag[0], frag.size());
			file_frag.close();
		}

		return shader_out.Create(vert.c_str(), frag.c_str());
	}

	return false;
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void DrawMeshShaded(Mesh& mesh, Color color, Shader& shader, AlphaMode alpha_mode, Matrix* mat)
{
	if (mesh.vbo == 0)
		return;

	//Bind program
	shader.Use();

	//Set vertex data
	glBindVertexArray(mesh.vao);
	CheckForErrors();

	GLint positionLocation = -1;
	positionLocation = glGetAttribLocation(shader.gl_shader_program, "in_Position");
	if (positionLocation != -1)
	{
		if (mesh.vertices)
		{
			glEnableVertexAttribArray(positionLocation);
			glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo);
			glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, NULL);
		}
		else
		{
			glDisableVertexAttribArray(positionLocation);
		}
	}
	CheckForErrors();

	GLint modelViewProjMatLocation = glGetUniformLocation(shader.gl_shader_program, "in_ModelViewProjection");
	if (modelViewProjMatLocation != -1)
	{
		Matrix matrix;
		if (mat)
		{
			matrix = (*mat) * s_view_matrix * s_projection_matrix;
		}
		else
		{
			matrix = s_view_matrix * s_projection_matrix;
		}

		glEnableVertexAttribArray(modelViewProjMatLocation);
		glUniformMatrix4fv(modelViewProjMatLocation, 1, GL_FALSE, (GLfloat*)&matrix);
	}
	CheckForErrors();

	GLint colorLocation = glGetUniformLocation(shader.gl_shader_program, "in_Color");
	if (colorLocation != -1)
	{
		glEnableVertexAttribArray(colorLocation);
		glUniform4f(colorLocation, color.r, color.g, color.b, color.a);
	}
	CheckForErrors();

	glDrawArrays(GL_TRIANGLES, 0, (GLsizei)mesh.num_verts);
	CheckForErrors();

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	CheckForErrors();

	if (colorLocation != -1)
		glDisableVertexAttribArray(colorLocation);

	if (modelViewProjMatLocation != -1)
		glDisableVertexAttribArray(modelViewProjMatLocation);

	//Disable vertex position
	if (positionLocation != -1)
		glDisableVertexAttribArray(positionLocation);

	//Unbind program
	Shader::ClearActiveShader();
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void AppendTube(std::vector<Mesh::Vertex>& verts, Vector3 pos1, Vector3 pos2, float w1, float w2, int segments)
{
	float angle = PI / segments;

	Vector3 normal = (pos2 - pos1).Normal();

	Matrix mtx = Matrix::CreateScale(1.0f);
	if (normal.y != 1.0f)
		mtx = Matrix::CreateLookAt(normal, { 0.0f, 1.0f, 0.0f });

	for (int i = 0; i < segments; ++i)
	{
		float xl = std::cosf(i * angle * 2);
		float xr = std::cosf((i + 1) * angle * 2);
		float zl = std::sinf(i * angle * 2);
		float zr = std::sinf((i + 1) * angle * 2);

		Vector3 ul = mtx.AxisVectorX() * xl + mtx.AxisVectorZ() * zl; ul *= w1; ul += pos1;
		Vector3 ur = mtx.AxisVectorX() * xr + mtx.AxisVectorZ() * zr; ur *= w1; ur += pos1;
		Vector3 ll = mtx.AxisVectorX() * xl + mtx.AxisVectorZ() * zl; ll *= w2; ll += pos2;
		Vector3 lr = mtx.AxisVectorX() * xr + mtx.AxisVectorZ() * zr; lr *= w2; lr += pos2;

		// Triangles
		verts.push_back({ ur.x, ur.y, ur.z });
		verts.push_back({ ul.x, ul.y, ul.z });
		verts.push_back({ lr.x, lr.y, lr.z });

		verts.push_back({ lr.x, lr.y, lr.z });
		verts.push_back({ ul.x, ul.y, ul.z });
		verts.push_back({ ll.x, ll.y, ll.z });
	}
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void CreateTree(Mesh& mesh, float height, float width)
{
	mesh = {};

	std::vector<Mesh::Vertex> vertices;
	AppendTube(vertices, {}, { 0.0f, height, 0.0f }, width, width / 2.0f, 8);

	mesh.num_verts = vertices.size();
	mesh.vertices = new Mesh::Vertex[mesh.num_verts];
	for (int i = 0; i < mesh.num_verts; ++i)
		mesh.vertices[i] = vertices[i];

	mesh.MakeBuffers();
}

 

 

vertex shader
 


#version 330
uniform mat4 in_ModelViewProjection;
uniform vec4 in_Color = vec4(1.0);

// in_Position was bound to attribute index 0 and in_Color was bound to attribute index 1
in vec3 in_Position;

// We output the ex_Color variable to the next shader in the chain
out vec4 ex_Color;

void main(void)
{
    gl_Position = in_ModelViewProjection * vec4(in_Position, 1.0);
    ex_Color = in_Color;
}

fragment shader
 


#version 330
// It was expressed that some drivers required this next line to function properly
precision highp float;

in vec4 ex_Color;

layout (location = 0) out vec4 out_Color;

void main(void)
{
	out_Color = ex_Color;
}

 

Video Game Programmer.
5 years in industry.

Sorry, i don't use sdl and adapting it would take too long since i only know know that it crashes but not where and how.

Things i'd like to comment on, maybe they help:

Why not use a loader like glad or glew ? All these #defines are a jungle and a typo for example in a datatype could spoil the day.

Manual error checking is superfluous when there is a debug context with properly configured debug output callback.

In the vertex shader: "in_Color" is not an attribute but a uniform, which means it is uniform during a draw call. It will not change per vertex and has no attribute location. It can however have a uniform location. Commenting on the comment that seems mislead ...

Binding the attribute in_Position to location 0 is done like this: "layout( location = 0 ) in vec3 in_Position". Thus you don't have to glBindAttributeLocations any more. Using glVertexArrayAttribBinding and glVertexArrayAttribFormat on an attribute is (arguably of cause :-)) shorter and clearer. The array is likewise installed with glCreateVertexArrays and connected to the buffer with glVertexArrayVertexBuffer. Online tutorials are mostly confined to opengl 3 ... ?

High precision attributes are default per spec afaik, there should be no need to state it explicitly. But it probably won't harm ...

In this case, a location qualifier isn't needed for the fragment shader output. There is only the color output to the default framebuffer. Or do you write to an own buffer with specified output format ?

A pixel shader is called fragmenrt shader in opengl ? ?

Hapy debugging, i also have a nut to crack here ...

I've tried glew in the past, it's ok. Found it quite bulky and the idea was to only find the stuff I use. I guess if I wrap it then it won't pollute my global namespace though.

The manual error checking is a remnant from before the debug output. It does however work when you don't have a debug context so I think you might find some use for it.

Yeah, I used to have per vertex color, but I eventually changed it to be more like a tint generally so it became a uniform. The comment is probably just outdated.

There are a few redundancies with the location of the vertex position, I should probably pick one method and stick with it though.

I don't, think that's from the time I dropped some of the predefined shader variables that existed in gl 2.0. That probably needs a tidy.

I've always disliked that name. And it used to be fragment program, shaders were entirely directx lingo. At least as it was described to me back on 2008.

EDIT: tried glew (adding the .c file to the project and including the header) Still the same error, so not a loading issue. Slightly smaller though
 

Spoiler


#include <SDL.h>

#include <stdio.h>
#include <cstring>
#include <fstream>
#include <string>
#include <iostream>
#include <vector>
#include <cmath>
#include <Windows.h>
#include <GL/glew.h>
#include <gl\GL.h>

static constexpr const float PI = 3.1416f; // 3.14159265359

inline constexpr float DegToRad(float degrees)
{
	return degrees * (PI / 180.0f);
}

#include "matrix.h"
#include "Vector.h"

// --- OpenGL types ---
typedef void (APIENTRY *DEBUGPROC)(GLenum source,
	GLenum type,
	GLuint id,
	GLenum severity,
	GLsizei length,
	const GLchar *message,
	const void *userParam);

struct Color {
	float r, g, b, a;
	static Color White;
	static Color Black;
	static Color Red;
	static Color Green;
	static Color Blue;
};

Color Color::White = { 1.0f, 1.0f, 1.0f, 1.0f };
Color Color::Black = { 0.0f, 0.0f, 0.0f, 1.0f };
Color Color::Red = { 1.0f, 0.0f, 0.0f, 1.0f };
Color Color::Green = { 0.0f, 1.0f, 0.0f, 1.0f };
Color Color::Blue = { 0.0f, 0.0f, 1.0f, 1.0f };

enum class AlphaMode { SOLID = 0, BLEND, ADDATIVE };

// --- SHADER ---

struct Shader
{
	GLuint gl_shader_program = 0;

	inline ~Shader();

	bool Create(const char* vertex_shader, const char* pixel_shader);
	void Destroy();
	void Use();

	static void ClearActiveShader();
	static bool LoadShader(Shader& shader_out, const char* vert_shader_path, const char* frag_shader_path);
};

static Shader s_defaultShaderSimple;
static GLuint s_current_shader = 0;

// ----------------------------------------------------

Matrix s_view_matrix = Matrix::CreateScale(1.0f);
Matrix s_projection_matrix = Matrix::CreateScale(1.0f);

// --- --- --- --- --- --- --- --- --- --- --- --- ---

struct ScreenResolution
{
	int w, h;
};

static const constexpr ScreenResolution screen_resolution_16_9[] =
{
	{ 1024, 576 }, { 1152, 648 }, { 1280, 720 }, { 1366, 768 },
	{ 1600, 900 }, { 1920, 1080 }, { 2560, 1440 }, { 3840, 2160 }
};

//Screen dimension constants
static const constexpr int SCREEN_W = screen_resolution_16_9[2].w;
static const constexpr int SCREEN_H = screen_resolution_16_9[2].h;

// --- --- --- --- --- --- --- --- --- --- --- --- ---

static SDL_Window* s_sdl_window = nullptr;
static SDL_GLContext s_gl_context;

void InitializeGraphics();

extern Matrix s_view_matrix;
extern Vector3 s_view_pos;
extern Matrix s_projection_matrix;

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

// ---

struct Mesh
{
	GLuint vao = 0; // Vertex array object
	GLuint vbo = 0; // Vertices

	bool made_buffers = false;
	bool MakeBuffers();

	//struct Vertex { float x, y, z; };
	typedef Vector3 Vertex;
	Vertex* vertices = nullptr;
	size_t num_verts = 0;
};

void CreateTree(Mesh& mesh, float height, float width);
void DrawMeshShaded(Mesh& mesh, Color color, Shader& shader, AlphaMode alpha_mode = AlphaMode::SOLID, Matrix* mat = nullptr);

int main(int argc, char* argv[])
{
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0)
	{
		SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
		return 1;
	}

	// Setup window
	SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);

	//SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	//SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
	//SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);

	//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
	//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);

	//SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);

	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
	//SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

	SDL_DisplayMode current;
	SDL_GetCurrentDisplayMode(0, &current);
	s_sdl_window = SDL_CreateWindow("Testbed", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_W, SCREEN_H, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);

	if (s_sdl_window == NULL)
	{
		const char* err = SDL_GetError();
		printf("Could not create window: %s\n", err);
		return 1;
	}

	// Graphics
	s_gl_context = SDL_GL_CreateContext(s_sdl_window);
	glewInit();
	SDL_GL_SetSwapInterval(1); // Enable vsync

	// Other
	SDL_GL_MakeCurrent(s_sdl_window, s_gl_context);
	InitializeGraphics();
	Mesh tube_mesh;
	CreateTree(tube_mesh, 1.0, 1.0f);

	// Main loop
	bool running = true;
	while (running)
	{
		SDL_Event current_event;
		while (SDL_PollEvent(&current_event))
		{
			switch (current_event.type)
			{
			case SDL_QUIT:
				running = false;
				break;
			}
		}

		SDL_GL_MakeCurrent(s_sdl_window, s_gl_context);

		glViewport(0, 0, SCREEN_W, SCREEN_H);
		
		glFrontFace(GL_CW);
		glEnable(GL_CULL_FACE);
		glCullFace(GL_BACK);

		glEnable(GL_DEPTH_TEST);

		glClearColor(135.0f / 255.0f, 206.0f / 255.0f, 235.0f / 255.0f, 0.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		// PROJECTION & VIEW
		{
			float aspect = (float)SCREEN_W / SCREEN_H;
			s_projection_matrix = Matrix::CreatePerspective(90.0f, aspect, 0.001f, 500.0f);
			s_view_matrix = Matrix::CreateTranslation({0.0f, 0.0f, 5.0f});
		}

		DrawMeshShaded(tube_mesh, Color::White, s_defaultShaderSimple, AlphaMode::SOLID, nullptr);

		glDisable(GL_DEPTH_TEST);
		SDL_GL_SwapWindow(s_sdl_window);
	}

	s_defaultShaderSimple.Destroy();

	SDL_GL_DeleteContext(s_gl_context);
	SDL_Quit();
	return 0;
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void APIENTRY glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
	std::cout << message << std::endl;
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

//void CheckForErrors()
//{
//	GLenum error_code = 0;
//	while (error_code = glGetError())
//	{
//		std::cout << (int)error_code << std::endl;
//	}
//}

void InitializeGraphics()
{
	Shader::LoadShader(s_defaultShaderSimple, "Shaders/default_simple.vert", "Shaders/default_simple.frag");

	glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
	glDebugMessageCallback(glDebugCallback, nullptr);

	glEnable(GL_MULTISAMPLE);
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

static_assert(3 * sizeof(GLfloat) == sizeof(Mesh::Vertex), "Mesh::Vertex must ve 3 * sizeof(GLfloat)");

bool Mesh::MakeBuffers()
{
	if (!made_buffers)
	{
		made_buffers = true;

		glGenVertexArrays(1, &vao);

		//Create VBO
		if (vertices)
		{
			glGenBuffers(1, &vbo);
			glBindBuffer(GL_ARRAY_BUFFER, vbo);
			glBufferData(GL_ARRAY_BUFFER, num_verts * 3 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
		}
	}

	return true;
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

inline Shader::~Shader() { Destroy(); }

bool Shader::Create(const char* vertex_shader, const char* pixel_shader)
{
	GLuint vertexshader = 0;
	GLuint fragmentshader = 0;

	vertexshader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexshader, 1, (const GLchar**)&vertex_shader, 0);
	glCompileShader(vertexshader);

	GLint IsCompiled_VS = 0;
	glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &IsCompiled_VS);
	if (IsCompiled_VS == FALSE)
	{
		GLint maxLength = 0;
		glGetShaderiv(vertexshader, GL_INFO_LOG_LENGTH, &maxLength);

		/* The maxLength includes the NULL character */
		char* vertexInfoLog = (char *)malloc(maxLength);
		glGetShaderInfoLog(vertexshader, maxLength, &maxLength, vertexInfoLog);
		printf(vertexInfoLog);
		free(vertexInfoLog);

		return false;
	}

	fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentshader, 1, (const GLchar**)&pixel_shader, 0);
	glCompileShader(fragmentshader);

	GLint IsCompiled_FS = 0;
	glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &IsCompiled_FS);
	if (IsCompiled_FS == FALSE)
	{
		GLint maxLength = 0;
		glGetShaderiv(fragmentshader, GL_INFO_LOG_LENGTH, &maxLength);

		/* The maxLength includes the NULL character */
		char* fragmentInfoLog = (char *)malloc(maxLength);
		glGetShaderInfoLog(fragmentshader, maxLength, &maxLength, fragmentInfoLog);
		printf(fragmentInfoLog);
		free(fragmentInfoLog);

		return false;
	}

	gl_shader_program = glCreateProgram();
	glAttachShader(gl_shader_program, vertexshader);
	glAttachShader(gl_shader_program, fragmentshader);
	glLinkProgram(gl_shader_program);

	glDeleteShader(vertexshader);
	glDeleteShader(fragmentshader);

	GLint IsLinked = 0;

	glGetProgramiv(gl_shader_program, GL_LINK_STATUS, (int *)&IsLinked);
	if (IsLinked == FALSE)
	{
		/* Noticed that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv. */
		GLint maxLength = 0;
		glGetProgramiv(gl_shader_program, GL_INFO_LOG_LENGTH, &maxLength);

		/* The maxLength includes the NULL character */
		char* shaderProgramInfoLog = (char *)malloc(maxLength);
		glGetProgramInfoLog(gl_shader_program, maxLength, &maxLength, shaderProgramInfoLog);
		printf(shaderProgramInfoLog);
		free(shaderProgramInfoLog);
		return false;
	}

	return true;
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void Shader::Destroy()
{
	// Clear Shader
	if (gl_shader_program != 0)
	{
		if (s_current_shader == gl_shader_program)
			Shader::ClearActiveShader();

		glDisableVertexAttribArray(0);
		glDisableVertexAttribArray(1);

		// Detach vert and frag from shader
		//glDetachShader(shaderprogram, vertexshader);
		//glDetachShader(shaderprogram, fragmentshader);

		// Destroy
		glDeleteProgram(gl_shader_program);
		//glDeleteShader(vertexshader);
		//glDeleteShader(fragmentshader);

		gl_shader_program = 0;
		//vertexshader = 0;
		//fragmentshader = 0;
	}
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void Shader::Use()
{
	glUseProgram(gl_shader_program);
	s_current_shader = gl_shader_program;
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void Shader::ClearActiveShader()
{
	s_current_shader = 0;
	glUseProgram(0);
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

bool Shader::LoadShader(Shader& shader_out, const char* vert_shader_path, const char* frag_shader_path)
{
	std::ifstream file_vert(vert_shader_path);
	std::ifstream file_frag(frag_shader_path);

	if (file_vert.is_open() && file_frag.is_open())
	{
		std::string vert;
		{
			file_vert.seekg(0, std::ios::end);
			vert.resize(file_vert.tellg());
			file_vert.seekg(0, std::ios::beg);
			file_vert.read(&vert[0], vert.size());
			file_vert.close();
		}

		std::string frag;
		{
			file_frag.seekg(0, std::ios::end);
			frag.resize(file_frag.tellg());
			file_frag.seekg(0, std::ios::beg);
			file_frag.read(&frag[0], frag.size());
			file_frag.close();
		}

		return shader_out.Create(vert.c_str(), frag.c_str());
	}

	return false;
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void DrawMeshShaded(Mesh& mesh, Color color, Shader& shader, AlphaMode alpha_mode, Matrix* mat)
{
	if (mesh.vbo == 0)
		return;

	//Bind program
	shader.Use();

	//Set vertex data
	glBindVertexArray(mesh.vao);

	GLint positionLocation = -1;
	positionLocation = glGetAttribLocation(shader.gl_shader_program, "in_Position");
	if (positionLocation != -1)
	{
		if (mesh.vertices)
		{
			glEnableVertexAttribArray(positionLocation);
			glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo);
			glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, NULL);
		}
		else
		{
			glDisableVertexAttribArray(positionLocation);
		}
	}

	GLint modelViewProjMatLocation = glGetUniformLocation(shader.gl_shader_program, "in_ModelViewProjection");
	if (modelViewProjMatLocation != -1)
	{
		Matrix matrix;
		if (mat)
			matrix = (*mat) * s_view_matrix * s_projection_matrix;
		else
			matrix = s_view_matrix * s_projection_matrix;

		glEnableVertexAttribArray(modelViewProjMatLocation);
		glUniformMatrix4fv(modelViewProjMatLocation, 1, GL_FALSE, (GLfloat*)&matrix);
	}

	GLint colorLocation = glGetUniformLocation(shader.gl_shader_program, "in_Color");
	if (colorLocation != -1)
	{
		glEnableVertexAttribArray(colorLocation);
		glUniform4f(colorLocation, color.r, color.g, color.b, color.a);
	}

	glDrawArrays(GL_TRIANGLES, 0, (GLsizei)mesh.num_verts);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	if (colorLocation != -1)
		glDisableVertexAttribArray(colorLocation);

	if (modelViewProjMatLocation != -1)
		glDisableVertexAttribArray(modelViewProjMatLocation);

	//Disable vertex position
	if (positionLocation != -1)
		glDisableVertexAttribArray(positionLocation);

	//Unbind program
	Shader::ClearActiveShader();
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void AppendTube(std::vector<Mesh::Vertex>& verts, Vector3 pos1, Vector3 pos2, float w1, float w2, int segments)
{
	float angle = PI / segments;

	Vector3 normal = (pos2 - pos1).Normal();

	Matrix mtx = Matrix::CreateScale(1.0f);
	if (normal.y != 1.0f)
		mtx = Matrix::CreateLookAt(normal, { 0.0f, 1.0f, 0.0f });

	for (int i = 0; i < segments; ++i)
	{
		float xl = std::cosf(i * angle * 2);
		float xr = std::cosf((i + 1) * angle * 2);
		float zl = std::sinf(i * angle * 2);
		float zr = std::sinf((i + 1) * angle * 2);

		Vector3 ul = mtx.AxisVectorX() * xl + mtx.AxisVectorZ() * zl; ul *= w1; ul += pos1;
		Vector3 ur = mtx.AxisVectorX() * xr + mtx.AxisVectorZ() * zr; ur *= w1; ur += pos1;
		Vector3 ll = mtx.AxisVectorX() * xl + mtx.AxisVectorZ() * zl; ll *= w2; ll += pos2;
		Vector3 lr = mtx.AxisVectorX() * xr + mtx.AxisVectorZ() * zr; lr *= w2; lr += pos2;

		// Triangles
		verts.push_back({ ur.x, ur.y, ur.z });
		verts.push_back({ ul.x, ul.y, ul.z });
		verts.push_back({ lr.x, lr.y, lr.z });

		verts.push_back({ lr.x, lr.y, lr.z });
		verts.push_back({ ul.x, ul.y, ul.z });
		verts.push_back({ ll.x, ll.y, ll.z });
	}
}

// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

void CreateTree(Mesh& mesh, float height, float width)
{
	mesh = {};

	std::vector<Mesh::Vertex> vertices;
	AppendTube(vertices, {}, { 0.0f, height, 0.0f }, width, width / 2.0f, 18);

	mesh.num_verts = vertices.size();
	mesh.vertices = new Mesh::Vertex[mesh.num_verts];
	for (int i = 0; i < mesh.num_verts; ++i)
		mesh.vertices[i] = vertices[i];

	mesh.MakeBuffers();
}

 

 

Video Game Programmer.
5 years in industry.

Advertisement

Sounds like you have to go the same way as we all, debug :-)

Yeah, the pixel/fragment thing ... From photography and all that, a pixel is a physical representation of an image element. A fragment is more, it can have depth and alpha and other information, and several fragments can be combined to make up a pixel of the image on screen. Or, a pixel will have the color of at least one fragment.

Valid until correction :-)

okay...well, I looked at the code. My attention went to Mesh::MakeBuffers(). You generate a vertex array object but never bind it before your vertex buffer object bind and fill. Assuming a +/=3.3 core profile and a required vao.  Other than that, a bit messy. Not easy to look at. 

MarkK: I tried adding that. Same as before. works fine for large meshes but breaking when I pass a smaller number into glDrawArrays. Even if I generate a bigger mesh and push it to the graphics card, and then manually type in 3 as the count it still crashes. It seems like regardless of if everything else works glDrawArrays won't work if the count that's passed is too low. I'm leaning towards a driver issue at this point.

Yeah, it's messy cause I've merged 5 different files into one document, trying to get rid of as much as possible. Tricky to make it read well well when doing that. The second version strips out the function loading and defines so might be a bit better.

My graphics card is a NVIDIA GeForce GTX 660, so quite old.

Video Game Programmer.
5 years in industry.

Hmm, such a driver issue is unlikely. My backup pc has GTX660 too (Linux), runs well. The problem will likely pop up again if left alone.

If you had a minimal version, without much sdl code, just the buffer, array, attribute creation and the loop with the drawcall together with numbers that work and those that crash, that could be run easily elsewhere ...

This topic is closed to new replies.

Advertisement