Array member by index

Tried your suggestion (made me notice I forgot to edit the type after a copy-paste), did not resolve the black screen issue, I even made sure to check the floats expected by the reported indices, there’s no issue I see with them so in theory I should have 2 static triangles on screen (which I don’t). Despite trying with both GL_ARRAY_BUFFER & GL_ELEMENTS_ARRAY_BUFFER (which from what I’ve read seems contextually correct since only the 1st buffer is holding floats, the rest are buffers holding indices referring to those floats), I cannot seem to get either triangle to show up, I’m assuming I handled the indices wrong, problem is OpenGL is not complaining of misusage so I can’t think of a potential cause.

How would you normally use index buffers given the above scenario I’ve show myself to be trying to use?

At this stage I’d go one further and say get rid of your entire abstraction layer because you’re only confusing yourself.

Where you’re at is that you don’t yet understand how OpenGL works, you’re building (or trying to build) an abstraction layer around it, you’re making a mess, and you’re making it very difficult for people to help you because they’ve first got to try unpick that mess.

I’m not even sure what it is you’re trying to do any more, but you seem to have gone down some kind of rabbit hole with buffer objects and confusion about their intended use, and that seems to have led you to trying to use a single GL_ARRAY_BUFFER with multiple GL_ELEMENT_ARRAY_BUFFERs. If you had proper error checking in, that would be caught, so the glX thing you’re doing - whatever on earth that is - is at least not helping you in this regard.

So clean up the mess first, and just use simple, direct procedural GL calls. At least that way people stand a chance of being able to understand your code.

1 Like

I’m not confusing myself, I’m using a single float array to hold every combination of vec4, vec3 & vec2, the index buffers hold the index of 1st found instance of the desired vectors, those indices are supposed to tell the gpu/card where in the 1st array to copy from into the desired attribute, that concept is clear in my head, it’s just the understanding how to do it that’s the problem, I just about get how to pass the buffers into the gpu/card but I don’t understand how to tell it to use them the way I intend them to be used, all the abstraction on CPU side I can understand perfectly because I understand how to pass the data around and ensure that it is used correctly, but when it comes to passing data to the card/gpu & telling it how to use it, that is where I get stumped, the current floats that are in the vertex buffer are fixed, I know exactly where the triangles should appear and roughly what colours they should be, the whole abstraction layer for them is so that after I finally can get their indices used correctly I can then experiment with meshes which will use those layers of abstraction, when I can get meshes to work correctly I then will go to the next layer, models & scenes (which I will treat as mostly the same thing), then onto maps (which will hold scenes which hold models), before I ever learnt that BotW used a grid system I had a similar thought in mind, that’s the point I’m aiming for and to do that I have to understand how to pass the data and tell the card/gpu how I want to use it, that’s what this code is for, the abstraction calls hold no OpenGL calls, they merely meddle with the data before it is passed along and used by this call, the trigon (I chose that name instead of triangle because I keep mistyping the ia as ai, trigon I don’t) calls at the top of the refresh function are where I overwrite the entire index buffer with new indices, the crafter/shader (btw you can’t speak for the entire human race, there may be others who like the name better and use it in their code, as long as everyone knows what I’m referring to then it doesn’t matter if I call them crafters) is not going to care what model & mesh it’s working with besides what the uniforms (which I can now use properly knowing they’re the same across every crafter/shader instance) I will later be adding tell them, so to summerise all I’m trying to tell the card/gpu at this point is load 1 vertex buffer and load SPOT_COUNT index buffers and use those index buffers to load from the vertex buffer and fill the appropriate attributes in the vertex crafter/shader calls

Don’t think I got round to posting what glX is

#ifdef _DEBUG
#define glX( UD, CALL ) \
	{ \
		glClearErrors(); \
		CALL; \
		glHadNoErrors( UD, __FILE__, __LINE__, #CALL ); \
	}
#else
#define glX( UD, CALL ) CALL
#endif

And the definitions:

void glClearErrors()
{
	while ( glGetError() );
}
bool glHadNoErrors
(
	void *ud,
	char const * const file,
	uint line,
	char const * const call
)
{
	int fault = glGetError();

	if ( fault )
	{
		print___x( errout, file, line, glReportToString(fault) );
		fprintf( errout, " %s\n", call );
		return false;
	}

	return true;
}
void GLAPIENTRY glDebugMsgCB
(
	GLenum source
	, GLenum report
	, GLuint id
	, GLenum weight
	, GLsizei length
	, const GLchar *msg
	, const void *ud
)
{
	fprintf
	(
		stderr
		, "%s (%u) source %s, weight, %s:\n\n%s\n"
		, glReportToString( report )
		, id
		, glSourceToString( source )
		, glWeightToString( weight )
		, msg
	);
}

Finally got somewhere, not what I expected but it still progress, only the draw calls have changed so I’ll post just the refresh function:

void glfwRefreshCB( GLFWwindow *window )
{
	BUFF *SpotIndexBuffers = core.SpotIndexBuffers;
	LIST *Trigons = &(core.Trigons);
	TRIGON *trigons = get_list_addr(Trigons);

	for ( uint trigon = 0; trigon < get_list_used(Trigons); ++trigon )
	{
		if ( list_is_taken( Trigons, trigon, -1 ) )
			continue;
		add_trigon_to_index_buffers( &core, trigons + trigon );
	}

	// Clear the screen
	glX( NULL, glUseProgram( core.Proc->ID ));
	glX( NULL, glClearColor( 0, 0, 0, 0 ));
	glX( NULL, glClear( GL_COLOR_BUFFER_BIT ));

	glX( NULL, glBindVertexArray( core.FloatsArrayID ) );

	glX( NULL, glInvalidateBufferData( core.FloatsBufferID ));
	glX( NULL, glBindBuffer( GL_ARRAY_BUFFER, core.FloatsBufferID ) );
	glX( NULL, glBufferData
	(
		GL_ARRAY_BUFFER,
		core.Floats.size,
		core.Floats.addr,
		GL_STATIC_DRAW
	) );
	glX( NULL, glVertexArrayElementBuffer( core.FloatsArrayID, core.FloatsBufferID ));

	for ( uint attr = 0; attr < SPOT_COUNT; ++attr )
	{
		BUFF *Indices = SpotIndexBuffers + attr;
		uint values;
		uint bufferId = core.SpotIDs[attr];
		uint location = core.SpotAttribLocations[attr];

		if ( attr != SPOT_PLACE && attr != SPOT_COLOR )
			continue;

		glX( NULL, glEnableVertexAttribArray( location ));

		if ( attr == SPOT_COLOR )
			values = 4;
		else if ( attr == SPOT_COORD )
			values = 2;
		else
			values = 3;

		glX( NULL, glBindBuffer( GL_ARRAY_BUFFER, core.FloatsBufferID ) );
#if 0
		glX( NULL, glVertexAttribFormat
		(
			location,
			values,
			GL_FLOAT,
			GL_FALSE,
			0
		));
#else
		glX( NULL, glVertexAttribPointer
		(
			location,
			values,
			GL_FLOAT,
			GL_FALSE,
			values * sizeof(float),
			NULL
		));
#endif
		glX( NULL, glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, bufferId ) );
		glX( NULL, glBufferData
		(
			GL_ELEMENT_ARRAY_BUFFER,
			SpotIndexBuffers->used * sizeof(uint),
			Indices->addr,
			GL_DYNAMIC_DRAW
		));
		//glX( NULL, glVertexAttribBinding( core.FloatsBufferID, 0 ));
	}

	glX( NULL, glBindVertexArray( core.FloatsArrayID ) );
	//glX( NULL, glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL ) );
	glX( NULL, glDrawArrays( GL_TRIANGLES, 6, GL_FLOAT ) );
	for ( uint attr = 0; attr < SPOT_COUNT; ++attr )
	{
		if ( attr != SPOT_PLACE && attr != SPOT_COLOR )
			continue;

		glX( NULL, glDisableVertexAttribArray( core.SpotAttribLocations[attr] ));
	}
	glfwSwapBuffers(window);
	set_index_buffers_count( &core, 0 );
}

I’ve been looking at this thread trying to get anything on screen

Just made a screen shot, gonna crop it a bit then post it along with the vertices I gave, in the mean time tell me if you see any improper gl related calls

And the vertices:

/* Add triangles */
trigon1 = add_trigon( &core );
trigon2 = add_trigon( &core );
Trigons = &(core.Trigons);
trigons = get_list_addr(Trigons);
Trigon1 = trigons + trigon1;
Trigon2 = trigons + trigon2;
Trigons->Buff.used = 2;

/* Add default vertex information */
if
(
	find_trio( &core, Trio.raw ) == (uint)-1
	|| find_quad( &core, Quad.raw ) == (uint)-1
)
{
	print___x( errout, __FILE__, __LINE__, "[FATAL ERROR]" );
	fprintf( errout, "%s\n", "Couldn't add default floats" );
	empty_core( &core );
	return EXIT_FAILURE;
}

Quad.w =  1.0;
/* Add our triangles, we don't check for success here because the memory
 * has already been allocated above */
Trio.x =  0.25;
Trio.y =  0.25;
Quad.z =  1.0;
Quad.y =  0.75;
Trigon1->a[SPOT_PLACE] = find_trio( &core, Trio.raw );
Trigon1->a[SPOT_COLOR] = find_quad( &core, Quad.raw );

Trio.x = -0.25;
Trio.y =  0.25;
Quad.z =  1.0;
Quad.y =  0.5;
Trigon1->b[SPOT_PLACE] = find_trio( &core, Trio.raw );
Trigon1->b[SPOT_COLOR] = find_quad( &core, Quad.raw );

Trio.x =  0.0;
Trio.y =  0.5;
Quad.z =  1.0;
Quad.y =  0.25;
Trigon1->c[SPOT_PLACE] = find_trio( &core, Trio.raw );
Trigon1->c[SPOT_COLOR] = find_quad( &core, Quad.raw );

Trio.x =  0.25;
Trio.y = -0.25;
Quad.z =  0.75;
Quad.y =  1.0;
Trigon2->a[SPOT_PLACE] = find_trio( &core, Trio.raw );
Trigon2->a[SPOT_COLOR] = find_quad( &core, Quad.raw );

Trio.x = -0.25;
Trio.y = -0.25;
Quad.z =  0.5;
Quad.y =  1.0;
Trigon2->b[SPOT_PLACE] = find_trio( &core, Trio.raw );
Trigon2->b[SPOT_COLOR] = find_quad( &core, Quad.raw );

Trio.x =  0.0;
Trio.y = -0.5;
Quad.z =  0.25;
Quad.y =  1.0;
Trigon2->c[SPOT_PLACE] = find_trio( &core, Trio.raw );
Trigon2->c[SPOT_COLOR] = find_quad( &core, Quad.raw );

Edit: I was expecting the 2 triangles to point up and down with a gap between, I chose different colors so I could differentiate them once I start trying to move them independently of each other

Edit 2: Did a print out of the values (had an #if 0 statement beneath the above code

main.c:187: Trigon1
.a = Coord { 0.000000, 0.000000 }
.a = Color { 0.000000, 0.750000, 1.000000, 1.000000 }
.a = Place { 0.250000, 0.250000, 0.000000 }
.a = Normal { 0.000000, 0.000000, 0.000000 }
.a = Tangent { 0.000000, 0.000000, 0.000000 }
.a = BiNormal { 0.000000, 0.000000, 0.000000 }
.b = Coord { 0.000000, 0.000000 }
.b = Color { 0.000000, 0.500000, 1.000000, 1.000000 }
.b = Place { -0.250000, 0.250000, 0.000000 }
.b = Normal { 0.000000, 0.000000, 0.000000 }
.b = Tangent { 0.000000, 0.000000, 0.000000 }
.b = BiNormal { 0.000000, 0.000000, 0.000000 }
.c = Coord { 0.000000, 0.000000 }
.c = Color { 0.000000, 0.250000, 1.000000, 1.000000 }
.c = Place { 0.000000, 0.500000, 0.000000 }
.c = Normal { 0.000000, 0.000000, 0.000000 }
.c = Tangent { 0.000000, 0.000000, 0.000000 }
.c = BiNormal { 0.000000, 0.000000, 0.000000 }
main.c:189: Trigon2
.a = Coord { 0.000000, 0.000000 }
.a = Color { 0.000000, 1.000000, 0.750000, 1.000000 }
.a = Place { 0.250000, -0.250000, 0.000000 }
.a = Normal { 0.000000, 0.000000, 0.000000 }
.a = Tangent { 0.000000, 0.000000, 0.000000 }
.a = BiNormal { 0.000000, 0.000000, 0.000000 }
.b = Coord { 0.000000, 0.000000 }
.b = Color { 0.000000, 1.000000, 0.500000, 1.000000 }
.b = Place { -0.250000, -0.250000, 0.000000 }
.b = Normal { 0.000000, 0.000000, 0.000000 }
.b = Tangent { 0.000000, 0.000000, 0.000000 }
.b = BiNormal { 0.000000, 0.000000, 0.000000 }
.c = Coord { 0.000000, 0.000000 }
.c = Color { 0.000000, 1.000000, 0.250000, 1.000000 }
.c = Place { 0.000000, -0.500000, 0.000000 }
.c = Normal { 0.000000, 0.000000, 0.000000 }
.c = Tangent { 0.000000, 0.000000, 0.000000 }
.c = BiNormal { 0.000000, 0.000000, 0.000000 }

Managed to track down a clue, seems the indices I’m giving don’t appear to match up with what the card/gpu maps those indices to, I’m assuming I’ve made a mistake in the tracking or adding down of said indices. Here’s the code from the only file directly handling those indices, maybe someone here will see what I’ve yet to see:

#include "core.h"


uint have_quads( CORE *Core ) { return Core->Floats.have / 4; }
uint have_trios( CORE *Core ) { return Core->Floats.have / 3; }
uint have_pairs( CORE *Core ) { return Core->Floats.have / 2; }

uint used_quads( CORE *Core )
{
	BUFF *Floats = &(Core->Floats);
	return (Floats->used / 4) + !!(Floats->used % 4);
}

uint used_trios( CORE *Core )
{
	BUFF *Floats = &(Core->Floats);
	return (Floats->used / 3) + !!(Floats->used % 3);
}

uint used_pairs( CORE *Core )
{
	BUFF *Floats = &(Core->Floats);
	return (Floats->used / 2) + !!(Floats->used % 2);
}

uint floats_need( uint want ) { return ((want / 12) + !!(want % 12)) * 12; }
BUFF * more_floats( CORE *Core, uint want )
{
	return buff_inc_only
	(
		&(Core->Alloc),
		&(Core->Floats),
		float,
		floats_need(want)
	);
}

BUFF * more_vec4( CORE *Core, uint want )
{
	return more_floats( Core, want * 4 );
}

BUFF * more_vec3( CORE *Core, uint want )
{
	return more_floats( Core, want * 3 );
}

BUFF * more_vec2( CORE *Core, uint want )
{
	return more_floats( Core, want * 2 );
}

uint next_quad( CORE *Core )
{
	BUFF *Floats = &(Core->Floats);
	uint quad = used_quads( Core );
	uint need = floats_need( quad );

	if ( Floats->have > need )
	{
		Floats->used = need;
		return quad;
	}

	Floats = more_vec4( Core, quad + 1000 );

	if ( !Floats )
		return -1;

	Floats->used = need;
	return quad;
}

uint find_quad( CORE *Core, vec4 Quad )
{
	BUFF *Floats = &(Core->Floats);
	uint used = used_quads( Core ), vec;
	vec4 *vecs = Floats->addr;

	for ( vec = 0; vec < used; ++vec )
	{
		if ( memcmp( vecs + vec, Quad, sizeof(vec4) ) == 0 )
			return vec;
	}

	if ( Floats->have < floats_need( vec ) || next_quad( Core ) == (uint)-1 )
	{
		print___x( errout, __FILE__, __LINE__, "[WARNING]" );
		fprintf( errout, "%s\n", "Not enough quads avaialable" );
		return -1;
	}

	vecs = Floats->addr;
	memcpy( vecs + used, Quad, sizeof(vec4) );
	Floats->used = (used+1) * 4;
	return used;
}

uint next_trio( CORE *Core )
{
	BUFF *Floats = &(Core->Floats);
	uint trio = used_trios( Core );
	uint need = floats_need( trio );

	if ( Floats->have > need )
	{
		Floats->used = need;
		return trio;
	}

	Floats = more_vec3( Core, trio + 1000 );

	if ( !Floats )
	{
		print___x( errout, __FILE__, __LINE__, "[WARNING]" );
		fprintf( errout, "%s\n", "Not enough memory available" );
		return -1;
	}

	Floats->used = need;
	return trio;
}

uint find_trio( CORE *Core, vec3 Trio )
{
	BUFF *Floats = &(Core->Floats);
	uint used = used_trios( Core ), vec;
	vec3 *vecs = Floats->addr;

	for ( vec = 0; vec < used; ++vec )
	{
		if ( memcmp( vecs + vec, Trio, sizeof(vec3) ) == 0 )
			return vec;
	}

	if ( Floats->have < floats_need( vec ) || next_trio( Core ) == (uint)-1 )
	{
		print___x( errout, __FILE__, __LINE__, "[WARNING]" );
		fprintf( errout, "%s\n", "Not enough trios avaialable" );
		return -1;
	}

	vecs = Floats->addr;
	memcpy( vecs + used, Trio, sizeof(vec3) );
	Floats->used = (used+1) * 3;
	return used;
}

uint next_pair( CORE *Core )
{
	BUFF *Floats = &(Core->Floats);
	uint pair = used_pairs( Core );
	uint need = floats_need( pair );

	if ( Floats->have > need )
	{
		Floats->used = need;
		return pair;
	}

	Floats = more_vec2( Core, pair + 1000 );

	if ( !Floats )
		return -1;

	Floats->used = need;
	return pair;
}

uint find_pair( CORE *Core, vec2 Pair )
{
	BUFF *Floats = &(Core->Floats);
	uint used = used_pairs( Core ), vec;
	vec2 *vecs = Floats->addr;

	for ( vec = 0; vec < used; ++vec )
	{
		if ( memcmp( vecs + vec, Pair, sizeof(vec2) ) == 0 )
			return vec;
	}

	if ( Floats->have < floats_need( used ) || next_pair( Core ) == (uint)-1 )
		return -1;

	vecs = Floats->addr;
	memcpy( vecs + used, Pair, sizeof(vec2) );
	Floats->used = (used+1) * 2;
	return used;
}

I found that clue after re-ordering the adding of those floats to the main array and getting a different output

Edit: Start from the find_*() functions because that’s what’s called to add the floats to the buffer

Turned the TRIGON object into a union and simplified the construction process, also simplified the implementation of find_*(), I’ll post hose in a minute, first the simplified construction:

/* Add triangles */
int add_trigons( CORE *Core )
{
	LIST *Trigons;
	TRIGON *trigons, *Trigon1, *Trigon2;
	uint trigon1, trigon2;

	vec4s Quad = {{0.0}}, quads[3] =
	{
		{{ 0.0, 0.25, 1.0, 1.0 }},
		{{ 0.0, 0.5,  1.0, 1.0 }},
		{{ 0.0, 0.75, 1.0, 1.0 }}
	};
	vec3s Trio = {{0.0}}, trios[3] =
	{
		{{ -0.25, 0.25, 0.0 }},
		{{  0.25, 0.25, 0.0 }},
		{{  0.0,  0.5,  0.0 }}
	};

	trigon1 = add_trigon( &core );
	trigon2 = add_trigon( &core );
	Trigons = &(core.Trigons);
	trigons = get_list_addr(Trigons);
	Trigon1 = trigons + trigon1;
	Trigon2 = trigons + trigon2;
	Trigons->Buff.used = 2;

	/* Add default vertex information */
	if ( find_quad( &core, Quad.raw ) == (uint)-1 )
	{
		print___x( errout, __FILE__, __LINE__, "[FATAL ERROR]" );
		fprintf( errout, "%s\n", "Couldn't add default floats" );
		empty_core( &core );
		return EXIT_FAILURE;
	}

	for ( uint v = 0; v < 3; ++v )
	{
		Quad = quads[v];
		Trio = trios[v];

		Trigon1->raw[v][SPOT_COLOR] = find_quad( &core, Quad.raw );
		Trigon1->raw[v][SPOT_PLACE] = find_trio( &core, Trio.raw );

		Quad.y = quads[v].z;
		Quad.z = quads[v].y;
		Trio.y = -(Trio.y);

		Trigon2->raw[v][SPOT_COLOR] = find_quad( &core, Quad.raw );
		Trigon2->raw[v][SPOT_PLACE] = find_trio( &core, Trio.raw );
	}

#if 1
	print___trigon( errout, __FILE__, __LINE__, "Trigon1", &core, Trigon1 );
	fputc( '\n', errout );
	print___trigon( errout, __FILE__, __LINE__, "Trigon2", &core, Trigon2 );
#endif
	return 0;
}

Now for the find_*() implementations:

uint find_quad( CORE *Core, vec4 Quad )
{
	BUFF *Floats = &(Core->Floats);
	uint used = used_quads( Core ), have = have_quads( Core ), quad;
	vec4 *quads = Floats->addr;

	for ( quad = 0; quad < used; ++quad )
	{
		if ( memcmp( quads + quad, Quad, sizeof(vec4) ) == 0 )
			return quad;
	}

	if ( used >= have && !more_floats( Core, (used + 1000) * 4 ) )
	{
		print___x( errout, __FILE__, __LINE__, "[WARNING]" );
		fprintf( errout, "%s\n", "Not enough quads avaialable" );
		return -1;
	}

	quads = Floats->addr;
	memcpy( quads + used, Quad, sizeof(vec4) );
	Floats->used = (used+1) * 4;
	return used;
}

uint find_trio( CORE *Core, vec3 Trio )
{
	BUFF *Floats = &(Core->Floats);
	uint used = used_trios( Core ), have = have_trios( Core ), trio;
	vec3 *trios = Floats->addr;

	for ( trio = 0; trio < used; ++trio )
	{
		if ( memcmp( trios + trio, Trio, sizeof(vec3) ) == 0 )
			return trio;
	}

	if ( used >= have && !more_floats( Core, (used + 1000) * 3 ) )
	{
		print___x( errout, __FILE__, __LINE__, "[WARNING]" );
		fprintf( errout, "%s\n", "Not enough trios avaialable" );
		return -1;
	}

	trios = Floats->addr;
	memcpy( trios + used, Trio, sizeof(vec3) );
	Floats->used = (used+1) * 3;
	return used;
}

uint find_pair( CORE *Core, vec2 Pair )
{
	BUFF *Floats = &(Core->Floats);
	uint used = used_pairs( Core ), have = have_pairs( Core ), pair;
	vec2 *pairs = Floats->addr;

	for ( pair = 0; pair < used; ++pair )
	{
		if ( memcmp( pairs + pair, Pair, sizeof(vec2) ) == 0 )
			return pair;
	}

	if ( used >= have && !more_floats( Core, (used + 1000) * 2 ) )
	{
		print___x( errout, __FILE__, __LINE__, "[WARNING]" );
		fprintf( errout, "%s\n", "Not enough pairs avaialable" );
		return -1;
	}

	pairs = Floats->addr;
	memcpy( pairs + used, Pair, sizeof(vec2) );
	Floats->used = (used+1) * 4;
	return used;
}

Still not getting the expected result of 2 triangles facing opposite directions with a gap between, really appreciate any help I get here.

Changed the implementation of used_*() as well:

uint used_quads( CORE *Core )
{
	BUFF *Floats = &(Core->Floats);
	uint used = Floats->used;
	uint quads = used / 4;
	while ( (quads * 4) < used ) ++quads;
	return quads;
}

uint used_trios( CORE *Core )
{
	BUFF *Floats = &(Core->Floats);
	uint used = Floats->used;
	uint trios = used / 3;
	while ( (trios * 3) < used ) ++trios;
	return trios;
}

uint used_pairs( CORE *Core )
{
	BUFF *Floats = &(Core->Floats);
	uint used = Floats->used;
	uint pairs = used / 2;
	while ( (pairs * 2) < used ) ++pairs;
	return pairs;
}

Still not getting the expected output though

Finally noticed that I used glDrawArrays instead of glDrawElements, changing that resolved the orientation of the 1st triangle but there’s no sign of the 2nd triangle that has the inverted y axis

Finally found he cause of my missing triangle, I used ‘index’ instead of ‘i’ when reading the byte at the end of this function (which I’ve already corrected before making this post.

int list_is_taken( struct _LIST *List, uint index, int take )
{
	BUFF *Took = &(List->Took);
	unsigned char *took = Took->addr, b;
	uint i = index / CHAR_BIT;

	if ( Took->have <= i )
	{
		print___x( errout, __FILE__, __LINE__, "index" );
		fprintf( errout, "%s\n", "was out of range" );
		return -1;
	}

	b = !!take;
	b <<= (index % CHAR_BIT);

	if ( take >= 0 )
		took[i] |= b;

	return !!(took[i] & b);
}

Releasing however that the method I’m using is inefficient for storing indices, gonna re-think that before I move onto texture’s, in the meantime what material would people suggest I read for textures (assuming the code I’m converting from tinyrenderer’s textures is not enough for me to get it right)?

Just in case anyone has some suggestions, this is the current structure set I plan to use:

typedef struct _STRIP
{
	uint Draw;
	uint ShapesID;
	LIST Shapes;
} STRIP;

typedef struct _MODEL
{
	vec3s Place;
	BUFF Floats;
	BUFF Strips;
} MODEL;

typedef struct _FIELD
{
	BUFF BufferIDs;
	BUFF Models;
} FIELD;

typedef struct _SCENE
{
	BUFF FieldIDs;
	BUFF Fields;
} SCENE;

The SCENE object will represent entire “maps”, like for example in FFXV there’s the main continent that would serve as a map and nearby islands that would serve as scenes as well, furthermore the scenes position will always be relative to another scene (I’ll work out the implementation for this detail later), this would eliminate the infinity issue on a global scale, I’m considering having sub scene support for the case that a scene is still large enough to cause an infinity issue.

The FIELD object would be individual cells within these scenes, they would provide a normalised environment for models (which would solve the infinity issue on a local scale), these fields will hold indices for nearby fields, the positions will be calculated at load time, these positions will likewise fall into a normalised environment, just with a ±1 to the x,y &/or z axis.

In other words every object should only see a normalised environment from it’s direct parent and not care about how where it is in other ancestors. The first model in a field is reserved for the the field model, the last model or group of models are reserved for active models (like the player, NPCs & enemies), all between is for “static” objects, ie, they don’t move from their position, even if they’re a breakable, instead their strips just move relative to their model’s position, this also make’s it easy to produce re-spawnable objects because you just have to go far enough that it would be unloaded before going back to have them re-loaded.

Again if anyone has suggestions feel free to mention them

By the lack of responses I guessing peops either had no suggestions or just didn’t care, I’m betting the later,that’s fine, at least I tried getting input.

Anyways, for anyone that still struggling to use index buffers I’m now uploading my code to gitlab.com/awsdert/glengine, the main function to look at is glfwRefreshCB(), I’m not going to claim it’s a good example, but it should get you on the right track, just be warned, this project is not intended for other people to use, it’s only meant for my experiments so expect the code to be a mess to some extent.

In the process of trying to fix some errors I realised I was still understanding the vertex array id wrong, it just happened to work because I was only linking to one cache of floats (gave up trying to keep them all in one buffer for time being), if my understanding is finally correct then each vertex array is only supposed to hold 1 buffer of floats and as many index buffers as one pleases (within memory limits obviously), this kind of information would be helpful in the guides but not a single one mentions that, as if they expect people to figure that out without any help (despite the fact they’re consulting a guide in the 1st place).

Anyways I’ve currently switched to a paired cache buffer & index buffer system but opengl is now throwing errors at me when I mainly just moved code to a more appropriate place for this system. Here’s the code block that’s throwing errors:

			for ( uint strip = 0; strip < Strips->used; ++strip )
			{
				STRIP *Strip = strips + strip;
				BUFF *traits = Strip->Traits;
				uint used = traits->used;

				for ( uint trait = 0; trait < TRAIT_COUNT; ++trait )
				{
					BUFF *Trait = traits + trait;
					BUFF *Cache = Caches + Traits->UseCache[trait];
					uint values = Traits->PerTrait[trait];
					uint TraitID = Traits->TraitIDs[trait];
					uint CacheID = Traits->CacheIDs[trait];
					uint IndexID = Traits->IndexIDs[trait];
					uint location = Core->TraitLoc[trait];

					if ( trait != TRAIT_PLACE && trait != TRAIT_COLOR )
						continue;

					glX( NULL, glEnableVertexAttribArray( location ));

#ifdef _DEBUG
					fprintf
					(
						errout,
						"model = %u, trait = %u, Cache->size = %zu\n",
						model,
						trait,
						Cache->size
					);
#endif

					glX( NULL, glBindVertexArray( TraitID ) );
					//glX( NULL, glInvalidateBufferData( CacheID ) );
					glX( NULL, glBindBuffer( GL_ARRAY_BUFFER, CacheID ) );
					glX( NULL, glBufferData
					(
						GL_ARRAY_BUFFER,
						Cache->size,
						Cache->addr,
						GL_DYNAMIC_DRAW
					) );
					glX( NULL, glVertexAttribPointer
					(
						location,
						values,
						GL_FLOAT,
						GL_FALSE,
						0,
						NULL
					));
					glX( NULL, glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, IndexID ) );
					glX( NULL, glBufferData
					(
						GL_ELEMENT_ARRAY_BUFFER,
						used * sizeof(uint),
						Trait->addr,
						GL_DYNAMIC_DRAW
					));
				}

				glX( NULL, glDrawElements( Strip->DrawAs, used, GL_UNSIGNED_INT, NULL ));
			}

And here’s the errors (duplicates were cropped out before posting):

model = 0, trait = 1, Cache->size = 4096
main.c:576: GL_INVALID_OPERATION  glBufferData ( GL_ARRAY_BUFFER, Cache->size, Cache->addr, GL_DYNAMIC_DRAW )
main.c:585: GL_INVALID_OPERATION  glVertexAttribPointer ( location, values, GL_FLOAT, GL_FALSE, 0, NULL )
main.c:593: GL_INVALID_OPERATION  glBufferData ( GL_ELEMENT_ARRAY_BUFFER, used * sizeof(uint), Trait->addr, GL_DYNAMIC_DRAW )
model = 0, trait = 2, Cache->size = 4096
main.c:576: GL_INVALID_OPERATION  glBufferData ( GL_ARRAY_BUFFER, Cache->size, Cache->addr, GL_DYNAMIC_DRAW )
main.c:585: GL_INVALID_OPERATION  glVertexAttribPointer ( location, values, GL_FLOAT, GL_FALSE, 0, NULL )
main.c:593: GL_INVALID_OPERATION  glBufferData ( GL_ELEMENT_ARRAY_BUFFER, used * sizeof(uint), Trait->addr, GL_DYNAMIC_DRAW )
main.c:596: GL_INVALID_OPERATION  glDrawElements( Strip->DrawAs, used, GL_UNSIGNED_INT, NULL )
model = 1, trait = 1, Cache->size = 4096
main.c:576: GL_INVALID_OPERATION  glBufferData ( GL_ARRAY_BUFFER, Cache->size, Cache->addr, GL_DYNAMIC_DRAW )
main.c:585: GL_INVALID_OPERATION  glVertexAttribPointer ( location, values, GL_FLOAT, GL_FALSE, 0, NULL )
main.c:593: GL_INVALID_OPERATION  glBufferData ( GL_ELEMENT_ARRAY_BUFFER, used * sizeof(uint), Trait->addr, GL_DYNAMIC_DRAW )
model = 1, trait = 2, Cache->size = 4096
main.c:576: GL_INVALID_OPERATION  glBufferData ( GL_ARRAY_BUFFER, Cache->size, Cache->addr, GL_DYNAMIC_DRAW )
main.c:585: GL_INVALID_OPERATION  glVertexAttribPointer ( location, values, GL_FLOAT, GL_FALSE, 0, NULL )
main.c:593: GL_INVALID_OPERATION  glBufferData ( GL_ELEMENT_ARRAY_BUFFER, used * sizeof(uint), Trait->addr, GL_DYNAMIC_DRAW )
main.c:596: GL_INVALID_OPERATION  glDrawElements( Strip->DrawAs, used, GL_UNSIGNED_INT, NULL )
model = 2, trait = 1, Cache->size = 4096
main.c:576: GL_INVALID_OPERATION  glBufferData ( GL_ARRAY_BUFFER, Cache->size, Cache->addr, GL_DYNAMIC_DRAW )
main.c:585: GL_INVALID_OPERATION  glVertexAttribPointer ( location, values, GL_FLOAT, GL_FALSE, 0, NULL )
main.c:593: GL_INVALID_OPERATION  glBufferData ( GL_ELEMENT_ARRAY_BUFFER, used * sizeof(uint), Trait->addr, GL_DYNAMIC_DRAW )
model = 2, trait = 2, Cache->size = 4096
main.c:576: GL_INVALID_OPERATION  glBufferData ( GL_ARRAY_BUFFER, Cache->size, Cache->addr, GL_DYNAMIC_DRAW )
main.c:585: GL_INVALID_OPERATION  glVertexAttribPointer ( location, values, GL_FLOAT, GL_FALSE, 0, NULL )
main.c:593: GL_INVALID_OPERATION  glBufferData ( GL_ELEMENT_ARRAY_BUFFER, used * sizeof(uint), Trait->addr, GL_DYNAMIC_DRAW )
main.c:596: GL_INVALID_OPERATION  glDrawElements( Strip->DrawAs, used, GL_UNSIGNED_INT, NULL )

Any ideas to what I should be looking for? Or even better what I should change?

Never mind, turned out I gave Traits the wrong pointer so it was giving the wrong IDs (which had all been initialised to 0 in the process of initializing buffer data from their relative BUFF object via their MODEL object)

This is completely wrong.

You’ve either got your terminology badly mixed-up, or what you’re doing is just accidentally working.

accidentally then because when I tried do a paired system I just got a black screen, the moment I went back to one “vertex array object” and just bound all the buffers to that one the triangles I was expecting appeared, didn’t get round to texture mapping though, for the first one I plan to just use a buffer generated by rand_r, the 2nd one I plan to try using SAIL to load an image and layer it over, I’m trying to go with a different triangle for each format so that I can trace the difference in handling every time I look back on this project

Help please, finally finished following the guide for a simple 2D texture while substituting a randomised array of vec4s (in RGBA order) but when I tried to run it the triangle that should’ve been textured appeared to have no texture, here’s what I have:

Draw Code:

			glUniform1ui( Core->CoveredLoc, !!(Strip->Covered) );

			if ( Strip->Covered )
			{
				COVER *Cover = covers + Strip->Covered;
				glBindTexture( Cover->UsedAs, Cover->ID );
			}

Initialisation Code:

typedef int (*rand_r_cb)( uint *seed );

typedef struct _RAND
{
	uint seed;
	rand_r_cb rand_r;
} RAND;

typedef union RGBA_RAND
{
	RAND raw[4];
	struct
	{
		RAND r;
		RAND g;
		RAND b;
		RAND a;
	};
} RGBA_RAND;

void generate_raw_cover( COVER *Cover, RGBA_RAND *gen )
{
	double max = UINT_MAX;
	uint have = Cover->Buffer.size / sizeof(vec4);
	vec4s *vecs = Cover->Buffer.addr;
	for ( uint v = 0; v < have; ++v )
	{
		double r = gen->r.rand_r( &(gen->r.seed) );
		double g = gen->g.rand_r( &(gen->g.seed) );
		double b = gen->b.rand_r( &(gen->b.seed) );
		double a = gen->a.rand_r( &(gen->a.seed) );
		vec4s * vec = vecs + v;

		vec->raw[0] = r / max;
		vec->raw[1] = g / max;
		vec->raw[2] = b / max;
		vec->raw[3] = a / max;
	}
}
...
	Covers = buff_inc_only( &(Core->Alloc), &(Core->Covers), COVER, 64 );

	if ( !Covers )
	{
		print___x( errout, __FILE__, __LINE__, "[FATAL ERROR]" );
		fprintf( errout, "%s\n", "Couldn't allocate cover objects" );
		empty_core( Core );
		return -1;
	}

	covers = Covers->addr;
	cover = 1;
	Cover = covers + cover;

	for ( uint r = 0; r < 4; ++r )
	{
		rgba_rand.raw[r].seed = time(NULL);
		rgba_rand.raw[r].rand_r = rand_r;
	}

	glGenTextures( 1, &(Cover->ID) );
	Cover->Formed = true;
	Cover->Bounds.x = 256;
	Cover->Bounds.y = 256;
	if
	(
		!buff_inc_only
		(
			&(Core->Alloc),
			&(Cover->Buffer),
			vec4,
			Cover->Bounds.x * Cover->Bounds.y
		)
	)
	{
		print___x( errout, __FILE__, __LINE__, "[FATAL ERROR]" );
		fprintf( errout, "%s\n", "Couldn't allocate cover buffer" );
		empty_core( Core );
		return -1;
	}
	generate_raw_cover( Cover, &rgba_rand );
	Cover->UsedAs = GL_TEXTURE_2D;
	glBindTexture( Cover->UsedAs, Cover->ID );
	glTexImage2D
	(
		Cover->UsedAs,
		0,
		GL_RGBA,
		Cover->Bounds.x,
		Cover->Bounds.y,
		0,
		GL_RGBA,
		GL_FLOAT,
		Cover->Buffer.addr
	);
	glGenerateMipmap(Cover->UsedAs);

Never mind, I overlooked a piece of code from the guide, adding that in fixed the issue