I'm a newb, need help with vertices

Need some help correcting this so I get the boundaries in view:

    char const map[] = 
    	"----------"
    	"-        -"
    	"-        -"
    	"-        -"
    	"-        -"
    	"-        -"
    	"-        -"
    	"-        -"
    	"-        -"
    	"----------"
    ;
    
    float points[100][3];
    
    ...
    
    void init_points()
    {
    	memset( points, -1, sizeof(points) );
    	
    	for ( int i = 0, c = 0, p = 0; i < 10; ++i )
    	{
    		for ( int j = 0; j < 10; ++j, ++c )
    		{
    			if ( map[c] == '-' )
    			{
    				points[p][0] =  1.0 / i;
    				points[p][1] =  1.0 / j;
    				points[p][2] =  0;
    				++p;
    			}
    		}
    	}
    }

I managed to correct a few things that the guide I was following didn’t explain properly and now am going with a different method of defining the “map”, gonna use random numbers and boundary checks, for now however trying to do a grid across the viewport but am only getting a quarter of the viewport, some help would be appreciated:

void init_points()
{
	int c = 0, p = 0;
	float row = 1.0 / ROWS, col = 1.0 / COLS;
	float rx = row * (ROWS - 1), ry = col * (COLS - 1);
	
	memset( points, -1, sizeof(points) );
	
	for ( float i = 0.0; i < ROWS; ++i )
	{
		for ( float j = 0; j < COLS; ++j, ++c )
		{
			points[p][0] =  (col * j) - rx;
			points[p][1] =  (row * i) - ry;
			points[p][2] =  0;
			++p;
		}
	}
}

Never mind, figured it out, just multiplied row and col by 2 after using them to calculated the offsets

Thought it best to reuse a thread for this, I created a fresh project to learn opengl with so I don’t mess up my other one that has the experimental math. Tried to get a basic triangle to appear while using VertexArray functions but currently am only getting a black screen, all the important stuff is in this one function:

int draw_opengl()
{
	CRAFTER *program = app.crafters->addr;

	typedef struct _VERTEX
	{
		FVEC3 vPoint;
		FVEC3 vColor;
	} VERTEX;

	typedef VERTEX TRIANGLE[3];

	TRIANGLE user_triangle =
	{
		{
			{  0.0, -0.5,  0.0 },
			{  0.0,  0.0,  1.0 }
		},
		{
			{  0.5,  0.0,  0.0 },
			{  0.0,  1.0,  1.0 },
		},
		{
			{ -0.5,  0.0,  0.0 },
			{  1.0,  1.0,  1.0 }
		}
	};

	TRIANGLE null_triangle =
	{
		{
			{ -1.0, -1.0, -1.0 },
			{  1.0,  1.0,  1.0 }
		},
		{
			{ -1.0, -1.0, -1.0 },
			{  1.0,  1.0,  1.0 }
		},
		{
			{ -1.0, -1.0, -1.0 },
			{  1.0,  1.0,  1.0 }
		}
	};

	struct _VAO
	{
		uint self_id;
		uint buff_id;
		TRIANGLE *buff;
	};

	struct _VAO vao_null, vao_user;

	void init_vao
	(
		struct _VAO *vao
	)
	{
		glExec( NULL, glGenVertexArrays( 1, &(vao->self_id) ) );
		glExec( NULL, glGenBuffers( 1, &(vao->buff_id) ) );

		glExec( NULL, glBindVertexArray( vao->self_id ) );
			glExec( NULL, glBindBuffer( GL_ARRAY_BUFFER, vao->buff_id ) );
			glExec
			(
				NULL
				, glBufferData
				(
					GL_ARRAY_BUFFER
					, sizeof(TRIANGLE)
					, vao->buff
					, GL_STATIC_DRAW
				)
			);
			glVertexAttribDivisor( vao->self_id, sizeof(TRIANGLE) / sizeof(VERTEX) );
			glExec( NULL, glVertexAttribPointer
			(
			   app.vPoint_location,		// attribute 0. No particular reason for 0, but must match the layout in the shader.
			   3,						// size
			   GL_FLOAT,				// type
			   GL_FALSE,				// normalized?
			   sizeof(FVEC3),						// stride
			   (void*)offsetof(VERTEX,vPoint) // array buffer offset
			) );
			glExec( NULL, glVertexAttribPointer
			(
			   app.vColor_location,		// attribute 0. No particular reason for 0, but must match the layout in the shader.
			   3,						// size
			   GL_FLOAT,				// type
			   GL_FALSE,				// normalized?
			   sizeof(FVEC3),						// stride
			   (void*)offsetof(VERTEX,vColor) // array buffer offset
			) );
		glBindVertexArray(0);
	}

	vao_null.buff = &null_triangle;
	vao_user.buff = &user_triangle;

	init_vao( &vao_null );
	init_vao( &vao_user );

	void draw_vao( struct _VAO *vao )
	{
		//glExec( NULL, glEnableVertexAttribArray( vao->self_id ) );
		glExec( NULL, glBindVertexArray( vao->self_id ) );
		glExec( NULL, glVertexAttribPointer
		(
		   app.vPoint_location,		// attribute 0. No particular reason for 0, but must match the layout in the shader.
		   3,						// size
		   GL_FLOAT,				// type
		   GL_FALSE,				// normalized?
		   0,						// stride
		   (void*)offsetof(VERTEX,vPoint) // array buffer offset
		) );
		glExec( NULL, glVertexAttribPointer
		(
		   app.vColor_location,		// attribute 0. No particular reason for 0, but must match the layout in the shader.
		   3,						// size
		   GL_FLOAT,				// type
		   GL_FALSE,				// normalized?
		   0,						// stride
		   (void*)offsetof(VERTEX,vColor) // array buffer offset
		) );
		glExec( NULL, glDrawArrays( GL_TRIANGLES, 0, 3 ) );
		glExec( NULL, glBindVertexArray( vao_null.self_id ) );
		//glExec( NULL, glDisableVertexAttribArray( vao->self_id ) );
	}

	while ( !glfwWindowShouldClose( app.window ) )
	{
		float ratio = (float)(app.span[VEC_X]) / (float)(app.span[VEC_Y]);
		FMAT4X4 m = {0}, p = {0}, mvp = {0};

		app.frame = glfwGetTime();
		app.deltaFrame = app.frame - app.lastFrame;
		app.lastFrame = app.frame;

		/* Make sure GFX card or GPU knows which of it's programs it's using */
		glExec( NULL, glUseProgram( program->id ) );

		/* Clear the screen */
		glExec( NULL, glViewport( 0, 0, app.span[VEC_X], app.span[VEC_Y] ) );
		glExec( NULL, glClearColor( 0, 0, 0, 0 ) );
		glExec( NULL, glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) );

#ifdef USE_MATRIX
		fmat4x4_identify( m );
		fmat4x4_rotate_Z( m, m, app.frame );
		fmat4x4_ortho( p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f );
		fmat4x4_mul( mvp, p, m );

		glExec
		(
			NULL
			, glUniformMatrix4fv
			(
				app.mvp_location
				, 1
				, GL_FALSE
				, (float*)mvp
			)
		);
#endif

		draw_vao( &vao_user );

		/* Hand over to the GFX card or GPU */
		glExec( NULL, glfwSwapBuffers( app.window ) );

		/* Get any new position data before constructing the next frame */
		glExec( NULL, glfwPollEvents() );
	}

	return 0;
}

Someone mind helping me understand where I’m going wrong please?

This shouldn’t be there. Attribute array divisors are only meaningful if you’re using instanced rendering, which you aren’t.

The stride should be sizeof(VERTEX), for both position and colour.

The glVertexAttribPointer calls in draw_vao a) are wrong (have a stride of zero) and b) shouldn’t be there; the point of a VAO is to store this information so that you only need to bind the VAO to set all state related to attribute arrays.

Also: for the sake of legibility, I suggest getting rid of that glExec stuff. If you want to perform error checking of every call, use debug output.

1 Like

Okay, that’s now commented out, thought I needed it to tell the GFX card how many vertices there are

Had not noticed that remenent of the modifications I made while trying to get that triangle to appear were still there, thx.

Okay, deleted now

I thought that was legible enough though? Well since it’s a learning project I’ll leave it in there, thx for the link though, I wandered why the debug output never came when I tried with the callback method, I was missing that glEnable() call.

Still not getting the triangle though, here’s the updated code with the definition of glExec(), I’d like to know how to restrict that to versions of opengl that don’t have the debug callback available.

#ifndef RELEASE
#define glExec( UD, X ) gl_cleanup(); X; glAllOkay( UD, X )
#else
#define glExec( UD, X ) X
#endif

The modified code

	void init_vao
	(
		struct _VAO *vao
	)
	{
		glExec( NULL, glGenVertexArrays( 1, &(vao->self_id) ) );
		glExec( NULL, glGenBuffers( 1, &(vao->buff_id) ) );

		glExec( NULL, glBindVertexArray( vao->self_id ) );
			glExec( NULL, glBindBuffer( GL_ARRAY_BUFFER, vao->buff_id ) );
			glExec
			(
				NULL
				, glBufferData
				(
					GL_ARRAY_BUFFER
					, sizeof(TRIANGLE)
					, vao->buff
					, GL_STATIC_DRAW
				)
			);
			//glVertexAttribDivisor( vao->self_id, sizeof(TRIANGLE) / sizeof(VERTEX) );
			glExec( NULL, glVertexAttribPointer
			(
			   app.vPoint_location,		// attribute 0. No particular reason for 0, but must match the layout in the shader.
			   3,						// size
			   GL_FLOAT,				// type
			   GL_FALSE,				// normalized?
			   sizeof(VERTEX),						// stride
			   (void*)offsetof(VERTEX,vPoint) // array buffer offset
			) );
			glExec( NULL, glVertexAttribPointer
			(
			   app.vColor_location,		// attribute 0. No particular reason for 0, but must match the layout in the shader.
			   3,						// size
			   GL_FLOAT,				// type
			   GL_FALSE,				// normalized?
			   sizeof(VERTEX),						// stride
			   (void*)offsetof(VERTEX,vColor) // array buffer offset
			) );
		glBindVertexArray(0);
	}

	vao_null.buff = &null_triangle;
	vao_user.buff = &user_triangle;

	init_vao( &vao_null );
	init_vao( &vao_user );

	void draw_vao( struct _VAO *vao )
	{
		//glExec( NULL, glEnableVertexAttribArray( vao->self_id ) );
		glExec( NULL, glBindVertexArray( vao->self_id ) );
		glExec( NULL, glDrawArrays( GL_TRIANGLES, 0, 3 ) );
		glExec( NULL, glBindVertexArray( vao_null.self_id ) );
		//glExec( NULL, glDisableVertexAttribArray( vao->self_id ) );
	}

Are you actually enabling the arrays?

Note that the argument to glEnableVertexAttribArray is the attribute location. So you presumably need

glEnableVertexAttribArray(app.vPoint_location);
glEnableVertexAttribArray(app.vColor_location);

This should probably go inside init_vao, executed while the VAO is bound (like other attribute array state, the enable state is stored in the VAO).

1 Like

That did the trick thank you, I’ll leave trying to move the triangle around for another time

Just ported over some code (because I didn’t wanna look up the key codes again) and couldn’t get the triangle to move, I’m guessing there a/some opengl call/s that I still have to make, what kind would they be? Do I just disable then re-enable the vertex attributes?

Edit: Just gave that a try, didn’t work out, for now I just commented the calls out after the failure

Edit 2: Just realised I didn’t post the code

void glfwOnKeyCB
(
	GLFWwindow* window
	, int key
	, int scancode
	, int action
	, int mods
)
{
	float move = 1.0;
	float turn = 0.125;
	float px = 0, py = 0, rx = 0;

	//glExec( NULL, glDisableVertexAttribArray( app.vPoint_location ) );
	//glExec( NULL, glDisableVertexAttribArray( app.vColor_location ) );

	switch ( key )
	{
		case GLFW_KEY_ESCAPE:
			if ( action == GLFW_PRESS )
				glfwSetWindowShouldClose( window, true );
			break;
		case GLFW_KEY_A:
		case GLFW_KEY_W:
		case GLFW_KEY_S:
		case GLFW_KEY_D:
			if ( mods == GLFW_MOD_SHIFT )
				move *= 2;
			else if ( mods == GLFW_MOD_CONTROL )
				move /= 2;
			break;
	}

	move *= app.deltaFrame;
	turn *= app.deltaFrame;

	switch ( key )
	{
		case GLFW_KEY_A: px -= move; break;
		case GLFW_KEY_W: py += move; break;
		case GLFW_KEY_S: py -= move; break;
		case GLFW_KEY_D: px += move; break;
		case GLFW_KEY_LEFT: rx -= turn; break;
		case GLFW_KEY_RIGHT: rx += turn; break;
	}

	user_triangle[0].vPoint[VEC_X] += px;
	user_triangle[1].vPoint[VEC_X] += px;
	user_triangle[2].vPoint[VEC_X] += px;

	user_triangle[0].vPoint[VEC_Y] += py;
	user_triangle[1].vPoint[VEC_Y] += py;
	user_triangle[2].vPoint[VEC_Y] += py;
	//ouser.face = clamp_angle( ouser.face, max_angle );

	//glExec( NULL, glEnableVertexAttribArray( app.vPoint_location ) );
	//glExec( NULL, glEnableVertexAttribArray( app.vColor_location ) );
}

Got an interview 2mw so gonna get some shut eye.

Figured while I wait for a response I’d try implement uniforms (which thanks to the wiki you directed me to has made clear that uniforms are constants, and from compile errors I found out the vertex data is constant too) as structs, that failed somewhere along the line but I still have the triangle, just no movement, (partly because I forgot to update the key callback function to update the objects their using and partly because I’ve obviously got some code wrong somewhere).

Here’s the code I used for the crafter/shader

#version 330

in vec3 vPoint;
in vec3 vColor;

struct object
{
	int rx, ry;
	int cx, cy, cz;
	float x, y, z;
};

uniform object uChar0;
uniform object uView0;

varying vec4 color;

void main()
{
	float x = vPoint.x + uChar0.x;
	float y = vPoint.y + uChar0.y;
	float z = vPoint.z + uChar0.z;
    gl_Position = vec4(x, y, z, 1.0);
    color = vec4(vColor,1.0);
}

Here’s the code I used for updating uniforms

void init_vao
	(
		struct _VAO *vao
	)
	{
		glExec( NULL, glGenVertexArrays( 1, &(vao->self_id) ) );
		glExec( NULL, glGenBuffers( 1, &(vao->buff_id) ) );

		glExec( NULL, glBindVertexArray( vao->self_id ) );
			glExec( NULL, glBindBuffer( GL_ARRAY_BUFFER, vao->buff_id ) );
			glExec
			(
				NULL
				, glBufferData
				(
					GL_ARRAY_BUFFER
					, sizeof(TRIANGLE)
					, vao->buff
					, GL_STATIC_DRAW
				)
			);
			//glVertexAttribDivisor( vao->self_id, sizeof(TRIANGLE) / sizeof(VERTEX) );
			glExec( NULL, glEnableVertexAttribArray( app.vPoint_location ) );
			glExec( NULL, glVertexAttribPointer
			(
			   app.vPoint_location,		// attribute 0. No particular reason for 0, but must match the layout in the shader.
			   3,						// size
			   GL_FLOAT,				// type
			   GL_FALSE,				// normalized?
			   sizeof(VERTEX),						// stride
			   (void*)offsetof(VERTEX,vPoint) // array buffer offset
			) );
			glExec( NULL, glEnableVertexAttribArray( app.vColor_location ) );
			glExec( NULL, glVertexAttribPointer
			(
			   app.vColor_location,		// attribute 0. No particular reason for 0, but must match the layout in the shader.
			   3,						// size
			   GL_FLOAT,				// type
			   GL_FALSE,				// normalized?
			   sizeof(VERTEX),						// stride
			   (void*)offsetof(VERTEX,vColor) // array buffer offset
			) );

		glUniform2i( app.uChar0_location + 0, app.char0.rx, app.char0.ry );
		glUniform3i( app.uChar0_location + 2, app.char0.cx, app.char0.cy, app.char0.cz );
		glUniform3f( app.uChar0_location + 5, app.char0.cx, app.char0.cy, app.char0.cz );

		glUniform2i( app.uView0_location + 0, app.view0.rx, app.view0.ry );
		glUniform3i( app.uView0_location + 2, app.view0.cx, app.view0.cy, app.view0.cz );
		glUniform3f( app.uView0_location + 5, app.view0.cx, app.view0.cy, app.view0.cz );

		glBindVertexArray(0);
	}

	vao_null.buff = &null_triangle;
	vao_user.buff = &user_triangle;

	init_vao( &vao_null );
	init_vao( &vao_user );

	void draw_vao( struct _VAO *vao )
	{
		//glExec( NULL, glEnableVertexAttribArray( vao->self_id ) );
		glExec( NULL, glBindVertexArray( vao->self_id ) );

		glUniform2i( app.uChar0_location + 0, app.char0.rx, app.char0.ry );
		glUniform3i( app.uChar0_location + 2, app.char0.cx, app.char0.cy, app.char0.cz );
		glUniform3f( app.uChar0_location + 5, app.char0.cx, app.char0.cy, app.char0.cz );

		glUniform2i( app.uView0_location + 0, app.view0.rx, app.view0.ry );
		glUniform3i( app.uView0_location + 2, app.view0.cx, app.view0.cy, app.view0.cz );
		glUniform3f( app.uView0_location + 5, app.view0.cx, app.view0.cy, app.view0.cz );

		//glVertexAttrib3fv( vao->self_id, (float*)(&user_triangle) );
		glExec( NULL, glDrawArrays( GL_TRIANGLES, 0, 3 ) );
		glExec( NULL, glBindVertexArray( vao_null.self_id ) );
		//glExec( NULL, glDisableVertexAttribArray( vao->self_id ) );
	}

Edit: Just realised I didn’t post the error:

[OPENGL ERROR 0x824C (33356 - 1)] source 33350, gravity, 37190:
GL_INVALID_OPERATION in glUniform(program not linked)
...
[OPENGL ERROR 0x824C (33356 - 1)] source 33350, gravity, 37190:
GL_INVALID_OPERATION in glUniform3("uChar0.ry"@1 has 1 components, not 3)
[OPENGL ERROR 0x824C (33356 - 1)] source 33350, gravity, 37190:
GL_INVALID_OPERATION in glUniform3("uChar0.cz"@4 has 1 components, not 3)
[OPENGL ERROR 0x824C (33356 - 1)] source 33350, gravity, 37190:
...

Edit 2: Looking through the output turned out there was more than one error, updated the above to reflect all the ones I found

Edit 3: Resolved the uniform problem with this:

	void update_object( uint loc, object *obj )
	{
		glUniform1i( loc + 1, obj->rx );
		glUniform1i( loc + 2, obj->ry );
		glUniform1i( loc + 3, obj->cx );
		glUniform1i( loc + 4, obj->cy );
		glUniform1i( loc + 5, obj->cz );
		glUniform1f( loc + 6, obj->x );
		glUniform1f( loc + 7, obj->y );
		glUniform1f( loc + 8, obj->z );
	}

Haven’t resolved the “program not linked” yet, gotta go to that interview in a few minutes so I’ll try debugging the linkage after I come back, I never expected it to have issues when the crafters compiled fine.

You don’t seem to write the changes of the CPU-side values
user_triangle[0].vPoint
to the GPU-side.
That is, the shader-attribute:
vec3 vPoint;
is not updated. Or what?

You are writing variable
vao->buff
as vertex-positions in your initiation-code

As for the uniforms … I don’t see any calls to
glGetUniformLocation(..) //[a one off initiation]
This is the cpu-side value you call
app.uChar0_location

I’ll make this quick, the uniform locations are grabbed prior to the call to draw_opengl, I’ll just dump that function as I gotta leave now or I’ll be late.

bool init_opengl()
{
	CRAFTER *program;

	app.crafters = load_and_init_crafters
	(
		2,
		GL_VERTEX_SHADER, "builder.glsl",
		GL_FRAGMENT_SHADER, "painter.glsl"
	);

	if ( !(app.crafters) )
		return false;

	program = app.crafters->addr;

	//app.mvp_location = glGetUniformLocation( program->id, "MVP");
	app.uChar0_location = glGetUniformLocation( program->id, "uChar0" );
	app.uView0_location = glGetUniformLocation( program->id, "uView0" );
    app.vPoint_location = glGetAttribLocation( program->id, "vPoint");
    app.vColor_location = glGetAttribLocation( program->id, "vColor");

#ifndef RELEASE
    glEnable( GL_DEBUG_OUTPUT );
#endif

	return true;
}

did you test if
program = app.crafters->addr;
is not == 0
If something is drawn, it should be ok.

Once you’ve got the uniforms right, it could work. By now, you seem to have plenty error-output to guide you.
What about the main loop? Does the consept ring a bell?

Yeah, that load_and_init_crafters allocates that at the start, it also free’s it and returns NULL upon failure, getting a pointer means it viewed the result as a success didn’t check for failure at linkage though, just setting that up now

Edit: Just finished adding that in and nope, there was no issues at that point:

	glExec( NULL, program->id = glCreateProgram() );

	for ( n = 1; n < count; ++n )
	{
		crafter = crafters + n;
		glExec( NULL, glAttachShader( program->id, crafter->id ) );
	}

	glExec( NULL, glLinkProgram( program->id ) );
	glExec
	(
		NULL
		, glGetProgramiv( program->id, GL_LINK_STATUS, &(program->built) )
	);

	if ( !(program->built) )
	{
		debug_program( log, program );
		goto fail;
	}

	va_end( vargs );
	return list;
}

Gonna try moving the glEnable() call above the call to load_and_init_crafters(), maybe opengl wasn’t expecting to debug them and is complaining about a lack of debug symbols by complaining about unlinked program.

Edit 2: Nope, that only added a couple of reports at exit

[OPENGL ERROR 0x824C (33356 - 1)] source 33350, gravity, 37190:
GL_INVALID_OPERATION in glUniform(program not linked)
...
[OPENGL ERROR 0x8251 (33361 - 2)] source 33352, gravity, 33387:
Shader Stats: SGPRS: 8 VGPRS: 28 Code Size: 32 LDS: 0 Scratch: 0 Max Waves: 8 Spilled SGPRs: 0 Spilled VGPRs: 0 PrivMem VGPRs: 0
[OPENGL ERROR 0x8251 (33361 - 2)] source 33352, gravity, 33387:
Shader Stats: SGPRS: 16 VGPRS: 8 Code Size: 112 LDS: 0 Scratch: 0 Max Waves: 8 Spilled SGPRs: 0 Spilled VGPRs: 0 PrivMem VGPRs: 0

You are using

for checking link-status
…
there’s another GL_VALIDATE_STATUS that you seem not to check after doing the link-status. It’s the same setup after calling
glValidateProgram(..)

Just got round to updating the app.char0/app.view0 objects with the expected x/y values (well, not normalised yet but will be later), triangle finally moved so now I can focus on the next task, but before that, how many ways are there to move vertices? Do you have any examples for me to reference? I’d like to set up multiple functions that move the triangle in their own way, from start to finish, I already have boiler plate code for loading glsl files so I can just move the relavant code into those separate functions and load different crafters for the different functions

Done:

[OPENGL ERROR] Program Linkage error:
: '† ­û'
error.c:45: [OPENGL REPORT]
crafters.c:210: Couldn't initiate all crafters, aborting...
n = 3, count = 3
[OPENGL ERROR 0x824C (33356 - 1)] source 33350, gravity 37190:
GL_INVALID_VALUE in glGetShaderiv
[OPENGL ERROR 0]
error.c:45: [OPENGL ERROR] GL_INVALID_VALUE
crafters.c:40: __glewGetShaderiv( crafter->id, 0x8B84, &size )
[OPENGL ERROR 0x824C (33356 - 1)] source 33350, gravity 37190:
GL_INVALID_VALUE in glGetShaderInfoLog(shader)
[OPENGL ERROR 1]
error.c:45: [OPENGL ERROR] GL_INVALID_VALUE
crafters.c:54: __glewGetShaderInfoLog( crafter->id, size, ((void *)0), log )
[OPENGL SHADER ERROR] 24576 bytes:
(null):
Code:
[OPENGL ERROR 0x824C (33356 - 1)] source 33350, gravity 37190:
GL_INVALID_VALUE in glDeleteShader
[OPENGL ERROR 2]
error.c:45: [OPENGL ERROR] GL_INVALID_VALUE
crafters.c:159: __glewDeleteShader( crafter->id )
[OPENGL SHADER ERROR] 32768 bytes:
painter.glsl:
Code:
[OPENGL SHADER ERROR] 40960 bytes:
builder.glsl:
Code:
[OPENGL ERROR 0x824C (33356 - 1)] source 33350, gravity 37190:
GL_INVALID_OPERATION in glGetShaderiv
[OPENGL ERROR 3]
error.c:45: [OPENGL ERROR] GL_INVALID_OPERATION
crafters.c:40: __glewGetShaderiv( crafter->id, 0x8B84, &size )
[OPENGL ERROR 0x824C (33356 - 1)] source 33350, gravity 37190:
GL_INVALID_OPERATION in glGetShaderInfoLog(shader)
[OPENGL ERROR 4]
error.c:45: [OPENGL ERROR] GL_INVALID_OPERATION
crafters.c:54: __glewGetShaderInfoLog( crafter->id, size, ((void *)0), log )
[OPENGL SHADER ERROR] 49152 bytes:
(null):
Code:
[OPENGL ERROR 0x824C (33356 - 1)] source 33350, gravity 37190:
GL_INVALID_OPERATION in glDeleteShader
[OPENGL ERROR 5]
error.c:45: [OPENGL ERROR] GL_INVALID_OPERATION
crafters.c:159: __glewDeleteShader( crafter->id )
[OPENGL ERROR 0x8251 (33361 - 2)] source 33352, gravity 33387:
Shader Stats: SGPRS: 16 VGPRS: 8 Code Size: 112 LDS: 0 Scratch: 0 Max Waves: 8 Spilled SGPRs: 0 Spilled VGPRs: 0 PrivMem VGPRs: 0
[OPENGL ERROR 0x8251 (33361 - 2)] source 33352, gravity 33387:
Shader Stats: SGPRS: 8 VGPRS: 28 Code Size: 32 LDS: 0 Scratch: 0 Max Waves: 8 Spilled SGPRs: 0 Spilled VGPRs: 0 PrivMem VGPRs: 0
Compilation finished successfully.

Haven’t checked the log yet (gonna do that after this post)

Edit: After sorting through the errors I managed to get it down to this much:

[OPENGL CRAFTER ERROR] 16384 bytes:
(null):
Code:
error.c:45: [OPENGL REPORT]
crafters.c:238: Couldn't initiate all crafters, aborting...
n = 3, count = 3
[OPENGL ERROR 0x8251 (33361 - 1)] source 33352, gravity 33387:
Shader Stats: SGPRS: 16 VGPRS: 8 Code Size: 112 LDS: 0 Scratch: 0 Max Waves: 8 Spilled SGPRs: 0 Spilled VGPRs: 0 PrivMem VGPRs: 0
[OPENGL ERROR 0x8251 (33361 - 1)] source 33352, gravity 33387:
Shader Stats: SGPRS: 8 VGPRS: 28 Code Size: 32 LDS: 0 Scratch: 0 Max Waves: 8 Spilled SGPRs: 0 Spilled VGPRs: 0 PrivMem VGPRs: 0

And the bottom of load_and_init_crafters() now looks like this

	glExec( NULL, glLinkProgram( program->id ) );
	glExec
	(
		NULL
		, glGetProgramiv( program->id, GL_LINK_STATUS, &(program->built) )
	);
	glExec( NULL, glValidateProgram( program->id ) );
	glExec
	(
		NULL
		, glGetProgramiv( program->id, GL_VALIDATE_STATUS, &(program->valid) )
	);

	if ( !(program->built) || !(program->valid) )
	{
		debug_crafter( log, program );
		glReport
		(
			NULL
			, 0
			, "Couldn't initiate all crafters, aborting..."
		);

		fprintf( stderr, "n = %u, count = %u\n", n, count );

		while ( n )
		{
			--n;
			term_crafter( crafters + n );
		}

		return del_list( list );
	}

	va_end( vargs );
	return list;
}

Edit 2: Just noticed you mentioned glValidateProgram(), added that in and it brought me back to the original problem of “program not linked”

I cannot read the upper error-report.
I notice that you use glGetShaderInfoLog … I don’t know it.
I use
char infolog[1024]
glGetProgramInfoLog(program,1024,NULL,infolog);
cout << "Validation-log: \n" << infolog << "\n ;
It used to provide errors marked by shader-line-number

you’r missing your appointment …

Yeah, you can ignore that upper one now, that was just down to overlooked code when I added a goto for a quick and dirty cleanup, fixed that now, debug_crafter() now checks against crafter->type to see if it should use shader or program calls, 0 means program, anything else is shader calls. And no, I won’t be late for the appointment, already been, I literally left after saying I needed to leave. Nothing else planned for today besides a zoom meeting so I just need to pay attention to this tab every now and then.

After some googling I finally found a hint that lead me to find I needed to add glExec( NULL, glUseProgram( program->id ) ); in prior to the init_vao() calls in earlier mentioned code.