How to get reference to active shader program in OpenGLDriver?

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
Markuss
Posts: 20
Joined: Tue May 02, 2023 4:48 pm

How to get reference to active shader program in OpenGLDriver?

Post by Markuss »

Im sorry if this is the wrong place to ask Im new to driver programming. Im messing with Minetest and Im trying to attach an int called ConnectionX to each vertex.

Ive got my int set up in my vertex datastructre called ConnectionX and Ive gota attribute in my vertex shader called int vConnectionX;

I want to get the value of ConnectionX into vConnectionX.

But I cant figure out how to send the int to the shader. Im messing around in COpenGLDiver.cpp

Code: Select all


//! draws a vertex primitive list
void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount,
		const void* indexList, u32 primitiveCount,
		E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
{

.
.
.

switch (vType)
	{
		case EVT_STANDARD:
			if (vertices)
			{
				glNormalPointer(GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Normal);
				glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);
				glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);


				IShader* shader = getActiveShader();

				if (shader) {
					GLuint shaderProgram = shader->getProgram();

					GLint vConnectionXLocation = glGetAttribLocation(shaderProgram, "vConnectionX");
					if (vConnectionXLocation != -1) {
						glVertexAttribPointer(vConnectionXLocation, 1, GL_INT, GL_FALSE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].ConnectionX);
						glEnableVertexAttribArray(vConnectionXLocation);
					}
				}
			
			}
This is the code the AI came up with. It seems to think I need a reference to the active shader but it cant seem to figure out how to get it. There is no IShader in Minetests version of Irrlicht there doesnt appear to be getActiveShader either...


There is this code earlier in the driver

Code: Select all

//! Adds a new material renderer to the VideoDriver, using pixel and/or
//! vertex shaders to render geometry.
s32 COpenGLDriver::addShaderMaterial(const c8* vertexShaderProgram,
	const c8* pixelShaderProgram,
	IShaderConstantSetCallBack* callback,
	E_MATERIAL_TYPE baseMaterial, s32 userData)
{
	s32 nr = -1;
	COpenGLShaderMaterialRenderer* r = new COpenGLShaderMaterialRenderer(
		this, nr, vertexShaderProgram, pixelShaderProgram,
		callback, baseMaterial, userData);

	r->drop();
	return nr;
}


That seems to reference the vertex shader program which is what I believe I want, but Im not sure how to get that reference into drawVertexPrimitiveList

Any help or guidance would be much appreciated thank you
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to get reference to active shader program in OpenGLDriver?

Post by CuteAlien »

Not 100% sure I get what you try to do there, but I think you go a bit against the flow there with Irrlicht. Irrlicht really only has 3 vertex types it supports well, S3DVertex, S3DVertex2TCoords and S3DVertexTangents. Just one of those early design decisions which make some things easier and other near impossible.

So that's your per-vertex data. With shaders you are kinda free to abuse those values, no one cares what you do with any of those values. But making other formats is unfortunately pretty hard with Irrlicht. So try to put per vertex data it in one of those. You can use a variable which you don't need otherwise (like Tangent can directly be calculated in shader so there's 3 free floats there).

Rest of information is either send via material or with shader uniforms/constants (same thing). For which you use the shader callback which is called when a shader is needed. See the shader example in Irrlicht examples for those. But that's not per vertex then, but either per material (OnSetMaterial) or per render call (OnSetConstants).

Also Minetest Irrlicht is based on an older Irrlicht version and I think there are a few more options now than it had been back when they created their spin-off. Like custom data in SMaterial got added in Irrlicht and the shader callback didn't have OnCreate yet which gives you access to IMaterialRendererServices earlier (which allows using them in OnSetMaterial). And IMaterialRendererServices didn't have yet startUseProgram/stopUseProgram to set a shader active anywhere. Without those features life for shader-coders is a bit harder.

edit: I'm aware that doesn't answer your question directly. But don't have time to dig deeper into drivers over lunch ;)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Markuss
Posts: 20
Joined: Tue May 02, 2023 4:48 pm

Re: How to get reference to active shader program in OpenGLDriver?

Post by Markuss »

Thanks I decided to heed your warning and pack my int into the normals float. My code appears to work but Im a bit worried that I may get a rounding error or overflow error at some point and not get exactly the int that I tried to pack. Remember I cant use getFloatsFormInt in glsl because Im stuck in GLSL130

Code: Select all

 // pack my int into a float in cpp
for(int i = 0; i < number_of_bits; i++) {
        packedFloat += static_cast<float>(myInt[i]) * (1 << i);
    }
unpack my int from the normal in fragment shader:

Code: Select all

for (int i = 0; i < number_of_bits; i++) {
		float divisor = pow(2.0, i);
		float remainder = mod(vNormal.z, divisor * 2.0);
		int bit = int(floor(remainder / divisor));
		// Here I have the nth bit of my original int and multiply them all together to get my original int
	}
Im trying to pack four 7 bit ints into one float. The IEEE 754 standard for 32-bit floating-point numbers allows for the exact representation of integers up to 2^24 - 1 (approximately 16.7 million 16,777,215).
The maximum value that can be represented by 4 seven-bit integers is 127 + (127 << 7) + (127 << 14) + (127 << 21) = 2,113,929,215.

Maybe if I pack two of my ints into Normal.X and the other two into Normal.Y... just to be safe
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to get reference to active shader program in OpenGLDriver?

Post by CuteAlien »

You don't need normals? I tend to need those (edit: thought I learned recenly how specific optimized voxel engines can work when watching this video: https://www.youtube.com/watch?v=40JzyaOYJeY I guess Irrlicht starts getting more in the way than helping once you go that far).

May I ask what the ConnectionX is about? Maybe I have other ideas then.

edit2: Also why are you stuck with GLSL130? Minetest requirement? Otherwise you can switch the shader version inside the shader, that's not an engine thing.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Markuss
Posts: 20
Joined: Tue May 02, 2023 4:48 pm

Re: How to get reference to active shader program in OpenGLDriver?

Post by Markuss »

I dont think I need normals. I can use Normal.X and Normal.Z to pack my ints but if I try to use normal.Y my mesh turns dark where it shouldnt. Im not sure why or where Normal.Y is being used, the node shader doesn't appear to be using the normals...

I need some bits in each vertex so that I can tilemap the nodes. So for example if I have a grass node next to a dirt node then in the shader I can blend the grass and dirt textures together. Or if I have have a stone tile set I can make all the edges slant downward and appear like the edge of a cliff while stone nodes that are surrounded by other nodes can appear flat.

I can switch to GLSL 330 and have tried but its a big headache for me because I have to rewrite each shader and I would have to calculate some of the matrices myself (apparently in old versions they just give you the matrices) which is going to make upgrading really hard because I have to make many changes at once. Im not sure how Ill be able to tell if my matrix math is off or if some other feature I had to upgrade is not working as expected.
Last edited by Markuss on Mon Apr 22, 2024 4:27 pm, edited 2 times in total.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to get reference to active shader program in OpenGLDriver?

Post by CuteAlien »

OK. To get back to your original question once more. You can get the IMaterialRenderer* from the video-driver via driver->getMaterialRenderer for a given material (SMaterial::MaterialType). It doesn't pass through the opengl stuff, but as you seem to be allowed to modify sources: in your case IMaterialRenderer is really a COpenGLSLMaterialRenderer and Program2 in there is likely the shaderProgram you wanted. And the active material is in COpenGLDriver::Material which you have to hope is set at the point you need it (generally the case before the draw functions). Thought you still need your own draw function for changed vertex types. But I never needed to go that far myself, so can't help you there too much yet.

Also sadly I don't have experience with bit-packing (or unpacking) in shaders. But I agree that you need that data at least for each side, so has to be passed with vertex-data I assume.

Check that video I linked above - that guy goes heavily into packing data - thought more about what it packs in there and less in how to do that with old GLSL :-(
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply