Jump to content

  • Log In with Google      Sign In   
  • Create Account

Shaders won't work when I use Wrapper Classes but give no errors?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
3 replies to this topic

#1 Sean_Seanston   Members   -  Reputation: 371

Like
0Likes
Like

Posted 19 March 2014 - 07:22 PM

Ok, I apologize that this is a very general question that necessitates a lot of code (only some of which is really relevant to the problem though, I at least assume) but I've been wracking my brain and haven't come any closer to figuring this one out and have no idea what's happening.

 

The situation is:

 

1. I've been roughly following a series of OpenGL tutorials, and in this particular part he creates 2 wrapper classes to more easily use shaders and shader programs: http://www.mbsoftworks.sk/index.php?page=tutorials&series=1&tutorial=6

2. Originally, I just ignored the wrappers temporarily and made the first 4 tutorials work just using a more basic method.

3. After getting tutorial 4 working (displaying a series of 3D pyramids), I decided to alter my code to incorporate 2 wrapper classes that are based on the classes he uses in the tutorial. As far as I can see, my classes appear to function identically to his.

4. My old method works fine, but when I replace the relevant code with its wrapper-using equivalent... I get no errors and yet all I see is a black screen.

 

I've looked through the functions of the wrapper classes and used OutputDebugString() etc. to confirm that variables are being set correctly, and as far as I can tell... shaders seem to be being loaded correctly, and the program seems to be adding shaders, linking and being set to be used correctly. e.g. I printed out the strings that were meant to contain the shader code and they both looked fine.

If I open the tutorial code in VS, I can run that fine and so far I haven't been able to notice any difference that seems relevant to the shader classes.

 

One thing though, is that I'm using GLFW and the tutorial is just using the Windows API. Can't imagine that would matter, but then I don't know.

 

Here's the main section of code. I've included labels inside square brackets [] to help identify and make sense of the 2 relevant groups of code. The code from the working version without the wrappers is commented out and marked as such, the code relevant to the wrapper implementation is marked similarly. You can presumably ignore everything else. I've checked the shader loading function in my Shader class and it appears to function identically to the global load/buildShader() functions in the working non-wrapper version.

Also, the main loop has some irrelevant code relating to interpolation and framerate that currently does very little/nothing.

 

Looking at the code, is there any reason that jumps out as being a possible cause of this kind of behaviour? It seems I've just directly replaced the old code with its wrapper counterpart, but nothing is displayed.

#include "main.h"

//[NON-WORKING WRAPPER CODE:
ShaderProgram program;
Shader vShader;
Shader fShader;
//NON-WORKING WRAPPER CODE]

//[WORKING CODE WITHOUT WRAPPERS:
/*
GLuint buildShader( GLenum eShaderType, const std::string &shaderText )
{
    GLuint shader = glCreateShader( eShaderType );
    const char *strFileData = shaderText.c_str();
    glShaderSource( shader, 1, &strFileData, NULL );

    glCompileShader(shader);

    GLint status;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (status == GL_FALSE)
    {
        //With ARB_debug_output, we already get the info log on compile failure.
        if(!glext_ARB_debug_output)
        {
            GLint infoLogLength;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);

            GLchar *strInfoLog = new GLchar[infoLogLength + 1];
            glGetShaderInfoLog(shader, infoLogLength, NULL, strInfoLog);

            const char *strShaderType = NULL;
            switch(eShaderType)
            {
                case GL_VERTEX_SHADER: strShaderType = "vertex"; break;
                case GL_GEOMETRY_SHADER: strShaderType = "geometry"; break;
                case GL_FRAGMENT_SHADER: strShaderType = "fragment"; break;
            }

            fprintf(stderr, "Compile failure in %s shader:\n%s\n", strShaderType, strInfoLog);
            delete[] strInfoLog;
        }

        throw std::runtime_error("Compile failure in shader.");
    }

    return shader;
}

GLuint loadShader( GLenum eShaderType, std::string sFile )
{
    GLuint shaderID = 0;
    std::string shaderString;

    //Open file
    std::ifstream sourceFile( sFile.c_str() );

    //If file is valid
    if( sourceFile )
    {
        //Assign file contents to string
        shaderString.assign( ( std::istreambuf_iterator<char>( sourceFile ) ), ( std::istreambuf_iterator<char>() ) );

        //Build shader using string of file contents
        shaderID = buildShader( eShaderType, shaderString );
    }
    else
    {
        printf( "Unable to open file %s\n", sFile.c_str() );
    }

    //Return shader
    return shaderID;
}
*/
//WORKING CODE WITHOUT WRAPPERS]

void init()
{
	//One VBO for vertices positions, one for colors
	GLuint vbo[2];

	//One VAO for pyramid
	GLuint vao;

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

	float fPyramid[36]; // Pyramid data - 4 triangles of 3 vertices of 3 floats
	float fPyramidColor[36]; // Same for color

	// Setup pyramid

	// Front face
	fPyramid[0] = 0.0f; fPyramid[1] = 5.0f; fPyramid[2] = 0.0f;
	fPyramid[3] = -3.0f; fPyramid[4] = 0.0f; fPyramid[5] = 3.0f;
	fPyramid[6] = 3.0f; fPyramid[7] = 0.0f; fPyramid[8] = 3.0f;

	// Back face
	fPyramid[9] = 0.0f; fPyramid[10] = 5.0f; fPyramid[11] = 0.0f;
	fPyramid[12] = 3.0f; fPyramid[13] = 0.0f; fPyramid[14] = -3.0f;
	fPyramid[15] = -3.0f; fPyramid[16] = 0.0f; fPyramid[17] = -3.0f;

	// Left face
	fPyramid[18] = 0.0f; fPyramid[19] = 5.0f; fPyramid[20] = 0.0f;
	fPyramid[21] = -3.0f; fPyramid[22] = 0.0f; fPyramid[23] = -3.0f;
	fPyramid[24] = -3.0f; fPyramid[25] = 0.0f; fPyramid[26] = 3.0f;

	// Right face
	fPyramid[27] = 0.0f; fPyramid[28] = 5.0f; fPyramid[29] = 0.0f;
	fPyramid[30] = 3.0f; fPyramid[31] = 0.0f; fPyramid[32] = 3.0f;
	fPyramid[33] = 3.0f; fPyramid[34] = 0.0f; fPyramid[35] = -3.0f;

	// Setup pyramid color
	for( int i = 0; i < 4; i++ )
	{
		fPyramidColor[i*9] = 1.0f; fPyramidColor[i*9+1] = 0.0f; fPyramidColor[i*9+2] = 0.0f;
		if(i < 2)
		{
			fPyramidColor[i*9+1] = 0.0f; fPyramidColor[i*9+4] = 1.0f; fPyramidColor[i*9+5] = 0.0f;
			fPyramidColor[i*9+2] = 0.0f; fPyramidColor[i*9+7] = 0.0f; fPyramidColor[i*9+8] = 1.0f;
		}
		else
		{
			fPyramidColor[i*9+2] = 0.0f; fPyramidColor[i*9+7] = 1.0f; fPyramidColor[i*9+8] = 0.0f;
			fPyramidColor[i*9+1] = 0.0f; fPyramidColor[i*9+4] = 0.0f; fPyramidColor[i*9+5] = 1.0f;
		}
	}

	glGenBuffers( 2, vbo );

	glBindBuffer( GL_ARRAY_BUFFER, vbo[0] );
	glBufferData( GL_ARRAY_BUFFER, 36*sizeof(float), fPyramid, GL_STATIC_DRAW );

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

	glBindBuffer( GL_ARRAY_BUFFER, vbo[1] );
	glBufferData( GL_ARRAY_BUFFER, 36*sizeof(float), fPyramidColor, GL_STATIC_DRAW );
	glEnableVertexAttribArray( 1 );
	glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 0, 0 );

	glBindBuffer( GL_ARRAY_BUFFER, 0 );

//[NON-WORKING WRAPPER CODE:
	vShader.loadShader( GL_VERTEX_SHADER, "shader.vert" );
	fShader.loadShader( GL_FRAGMENT_SHADER, "shader.frag" );

	program.createProgram();
	program.addShader( &vShader );
	program.addShader( &fShader );

	program.linkProgram();
	program.useProgram();
//NON-WORKING WRAPPER CODE]

//[WORKING CODE WITHOUT WRAPPERS:
/*	GLuint vertShader = loadShader( GL_VERTEX_SHADER, "shader.vert" );
	GLuint fragShader = loadShader( GL_FRAGMENT_SHADER, "shader.frag" );

	GLuint program;

	program = glCreateProgram();
	glAttachShader( program, vertShader );
	glAttachShader( program, fragShader );
	glLinkProgram( program );

	GLint status;
	glGetProgramiv ( program, GL_LINK_STATUS, &status );
	if ( status == GL_FALSE )
	{
		if( !glext_ARB_debug_output )
		{
			GLint infoLogLength;
			glGetProgramiv( program, GL_INFO_LOG_LENGTH, &infoLogLength );

			GLchar *strInfoLog = new GLchar[ infoLogLength + 1 ];
			glGetProgramInfoLog( program, infoLogLength, NULL, strInfoLog );
			fprintf( stderr, "Linker failure: %s\n", strInfoLog );
			delete[] strInfoLog;
		}

		throw std::runtime_error( "Shader could not be linked." );
	}

	//Set shader program
	glUseProgram( program );
//WORKING CODE WITHOUT WRAPPERS]

	glEnable( GL_DEPTH_TEST );
	glClearDepth( 1.0 );

	//Get locations for projection and modelView matrices
//[WORKING CODE WITHOUT WRAPPERS:
//	Engine::instance()->modelViewLoc = glGetUniformLocation( program, "modelViewMatrix" );
//	Engine::instance()->projLoc = glGetUniformLocation( program, "projectionMatrix" );
//WORKING CODE WITHOUT WRAPPERS]

//[NON-WORKING WRAPPER CODE:
	Engine::instance()->modelViewLoc = glGetUniformLocation( program.getProgramID(), "modelViewMatrix" );
	Engine::instance()->projLoc = glGetUniformLocation( program.getProgramID(), "projectionMatrix" );
//NON-WORKING WRAPPER CODE]

	Engine::instance()->setProjMatrix( FOV, ASPECT_RATIO, NEAR_CLIP, FAR_CLIP );

	//Create projection matrix uniform
	glUniformMatrix4fv( Engine::instance()->projLoc, 1, GL_FALSE, glm::value_ptr( Engine::instance()->getProjMatrix() ) );
}

void display()
{
	static float fRotationAngle = 0.0f;
	const float PIover180 = 3.1415f/180.0f;

	//Set clear color and clear color buffer
	glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	//Create ModelView matrix
	glm::mat4 modelView = glm::lookAt( glm::vec3( 0, 15, 20 ), glm::vec3( 0.0f, 0.0f, 0.0f ), glm::vec3( 0.0f, 1.0f, 0.0f ) );
	//LOOKAT: ( CAMERA POS, CAMERA TARGET, UP VECTOR )

		//Draw vertex data
		//Apply rotation of modelView matrix around Y axis and store in mCurrent
		glm::mat4 current = glm::rotate( modelView, fRotationAngle, glm::vec3( 0.0f, 1.0f, 0.0f ) );
		glUniformMatrix4fv( Engine::instance()->modelViewLoc, 1, GL_FALSE, glm::value_ptr( current ) );
		glDrawArrays( GL_TRIANGLES, 0, 12 );

		 // One on the left
		current = glm::translate( modelView, glm::vec3( -20.0f, 10.0f*float( sin( fRotationAngle * PIover180 ) ), 0.0f ) );
		glUniformMatrix4fv( Engine::instance()->modelViewLoc, 1, GL_FALSE, glm::value_ptr( current ) );
		glDrawArrays( GL_TRIANGLES, 0, 12 ); 

		// One on the right
		current = glm::translate( modelView, glm::vec3( 20.0f, -10.0f*float( sin( fRotationAngle * PIover180 ) ), 0.0f ) );
		glUniformMatrix4fv( Engine::instance()->modelViewLoc, 1, GL_FALSE, glm::value_ptr( current ) );
		glDrawArrays( GL_TRIANGLES, 0, 12 ); 

		//And one translating and rotating on top
		current = glm::translate( modelView, glm::vec3( 20.0f*float(sin( fRotationAngle*PIover180 ) ), 10.0f, 0.0f ) );
		current = glm::rotate( current, fRotationAngle, glm::vec3( 1.0f, 0.0f, 0.0f ) );
		glUniformMatrix4fv( Engine::instance()->modelViewLoc, 1, GL_FALSE, glm::value_ptr( current ) );
		glDrawArrays(GL_TRIANGLES, 0, 12); 

		float fScaleValue = 1.5f+float(sin(fRotationAngle*PIover180))*0.5f;
		current = glm::translate(modelView, glm::vec3(0.0f, -10.0f, 0.0f));
		current = glm::scale(current, glm::vec3(fScaleValue, fScaleValue, fScaleValue));
		current = glm::rotate(current, fRotationAngle, glm::vec3(1.0f, 0.0f, 0.0f));
		current = glm::rotate(current, fRotationAngle, glm::vec3(0.0f, 1.0f, 0.0f));
		current = glm::rotate(current, fRotationAngle, glm::vec3(0.0f, 0.0f, 1.0f));
		glUniformMatrix4fv( Engine::instance()->modelViewLoc, 1, GL_FALSE, glm::value_ptr( current ) );
		glDrawArrays(GL_TRIANGLES, 0, 12); 

	//Increment rotation angle
	fRotationAngle += 0.05f;
	fRotationAngle > 360.0f ? fRotationAngle = 0.0f : fRotationAngle = fRotationAngle;

	//Swap front and back buffers
	glfwSwapBuffers();
}

void cleanUp()
{
	glDisableVertexAttribArray( 0 );
	glDisableVertexAttribArray( 1 );

	glUseProgram( 0 );
}

//Called whenever the window is resized. The new window size is given, in pixels.
//This is an opportunity to call glViewport or glScissor to keep up with the change in size.
void reshape( int w, int h )
{
	glViewport( 0, 0, ( GLsizei ) w, ( GLsizei ) h );
	Engine::instance()->setProjMatrix( FOV, ( float ) w /( float ) h, NEAR_CLIP, FAR_CLIP );

	//Create projection matrix uniform
	glUniformMatrix4fv( Engine::instance()->projLoc, 1, GL_FALSE, glm::value_ptr( Engine::instance()->getProjMatrix() ) );
}

void APIENTRY DebugFunc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
						const GLchar* message, const GLvoid* userParam)
{
	std::string srcName;
	switch(source)
	{
	case GL_DEBUG_SOURCE_API_ARB: srcName = "API"; break;
	case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: srcName = "Window System"; break;
	case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: srcName = "Shader Compiler"; break;
	case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: srcName = "Third Party"; break;
	case GL_DEBUG_SOURCE_APPLICATION_ARB: srcName = "Application"; break;
	case GL_DEBUG_SOURCE_OTHER_ARB: srcName = "Other"; break;
	}

	std::string errorType;
	switch(type)
	{
	case GL_DEBUG_TYPE_ERROR_ARB: errorType = "Error"; break;
	case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: errorType = "Deprecated Functionality"; break;
	case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: errorType = "Undefined Behavior"; break;
	case GL_DEBUG_TYPE_PORTABILITY_ARB: errorType = "Portability"; break;
	case GL_DEBUG_TYPE_PERFORMANCE_ARB: errorType = "Performance"; break;
	case GL_DEBUG_TYPE_OTHER_ARB: errorType = "Other"; break;
	}

	std::string typeSeverity;
	switch(severity)
	{
	case GL_DEBUG_SEVERITY_HIGH_ARB: typeSeverity = "High"; break;
	case GL_DEBUG_SEVERITY_MEDIUM_ARB: typeSeverity = "Medium"; break;
	case GL_DEBUG_SEVERITY_LOW_ARB: typeSeverity = "Low"; break;
	}

	printf("%s from %s,\t%s priority\nMessage: %s\n",
		errorType.c_str(), srcName.c_str(), typeSeverity.c_str(), message);
}

int main()
{
	if( !glfwInit() )
	{
		return -1;
	}

	glfwOpenWindowHint( GLFW_OPENGL_VERSION_MAJOR, 3 );
	glfwOpenWindowHint( GLFW_OPENGL_VERSION_MINOR, 3 );
	glfwOpenWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
#ifdef DEBUG
	glfwOpenWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE );
#endif

	//Create window
	if( !glfwOpenWindow( 1000, 500, 8, 8, 8, 8, 24, 8, GLFW_WINDOW ) )
	{
		glfwTerminate();
		return -1;
	}

	//Load OpenGL functions
	if( !glload::LoadFunctions() )
	{
		glfwTerminate();
		return -1;
	}

	//Set window title
	glfwSetWindowTitle( "GLFW Demo" );

	if( glext_ARB_debug_output )
	{
		glEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB );
		glDebugMessageCallbackARB( DebugFunc, ( void* )15 );
	}

	//Initialize scene
	init();

	glfwSetWindowSizeCallback( reshape );

	//Variables for framerate management
	DWORD next_game_tick = GetTickCount();
	int loops = 0;
	float interpolation;

	//Main loop
	while( Engine::instance()->isRunning() )
	{
		float time = ( float )GetTickCount();
		loops = 0;

		//Handle events
		if( glfwGetKey( GLFW_KEY_ESC ) || !glfwGetWindowParam( GLFW_OPENED ) )
		{
			break;
		}

		while( GetTickCount() > next_game_tick && loops < Engine::MAX_FRAMESKIP )
		{		
			//Do event handling and updating of current active state
			Engine::instance()->handleEvents();
			Engine::instance()->update();

			next_game_tick += Engine::SKIP_TICKS;
			loops++;
		}

		//Calculate interpolation value
		interpolation = float( GetTickCount() + Engine::SKIP_TICKS - next_game_tick ) / float( Engine::SKIP_TICKS );

		//Render
		display();
	}

	cleanUp();

	glfwTerminate();
	
	return 0;
}
 


Sponsor:

#2 Sean_Seanston   Members   -  Reputation: 371

Like
0Likes
Like

Posted 20 March 2014 - 06:49 AM

Any guesses at all to what might possibly lead to something like this? One of the thoughts I had was something going out of scope or similar... i.e. maybe things were being set up ok in theory but wound up empty or full of junk when they were needed. That's why I moved the Shader and ShaderProgram object declarations out of the init() function where the non-wrapper equivalents are, but had no success with that either obviously. I also would have imagined these kind of scenarios would result in at least some form of error.

 

Here are the shader classes anyway, though I THINK they seem to wrap the very same functionality that works without the wrappers:

//Class to wrap a shader
class Shader
{
public:
	Shader();

	bool loadShader( GLenum eShaderType, std::string sFile );
	void deleteShader();

	GLuint getShaderID();

	bool isLoaded();

private:
	GLuint shaderID;
	GLenum shaderType;
	bool loaded;
};

//Class to wrap a shader program
class ShaderProgram
{
public:
	ShaderProgram();

	void createProgram();
	void deleteProgram();

	bool addShader( Shader* shader );
	bool linkProgram();

	void useProgram();

	GLuint getProgramID();

private:
	GLuint programID;
	bool linked;
};
Shader::Shader() : loaded ( false )
{
}

bool Shader::loadShader( GLenum eShaderType, std::string sFile )
{
	GLuint shaderID = 0;
	std::string shaderString;

	//Open file
	std::ifstream sourceFile( sFile.c_str() );

	//If file is valid
	if( sourceFile )
	{
		//Assign file contents to string
		shaderString.assign( ( std::istreambuf_iterator<char>( sourceFile ) ), ( std::istreambuf_iterator<char>() ) );

		//Build shader using string of file contents
		shaderID = glCreateShader( eShaderType );

		const char *strFileData = shaderString.c_str();

		glShaderSource( shaderID, 1, &strFileData, NULL );

		glCompileShader( shaderID );

		GLint status;
		glGetShaderiv( shaderID, GL_COMPILE_STATUS, &status );
		if ( status == GL_FALSE )
		{
			//With ARB_debug_output, we already get the info log on compile failure.
			if( !glext_ARB_debug_output )
			{
				GLint infoLogLength;
				glGetShaderiv( shaderID, GL_INFO_LOG_LENGTH, &infoLogLength );

				GLchar *strInfoLog = new GLchar[infoLogLength + 1];
				glGetShaderInfoLog( shaderID, infoLogLength, NULL, strInfoLog );

				const char *strShaderType = NULL;
				switch( eShaderType )
				{
					case GL_VERTEX_SHADER: strShaderType = "vertex"; break;
					case GL_GEOMETRY_SHADER: strShaderType = "geometry"; break;
					case GL_FRAGMENT_SHADER: strShaderType = "fragment"; break;
				}

				fprintf( stderr, "Compile failure in %s shader:\n%s\n", strShaderType, strInfoLog );
				delete[] strInfoLog;
			}

			throw std::runtime_error( "Compile failure in shader." );
			return false;
		}
	}
	else
	{
		printf( "Unable to open file %s\n", sFile.c_str() );

		return false;
	}

	shaderType = eShaderType;
	loaded = true;
	return true;
}

void Shader::deleteShader()
{
	if( !isLoaded() )
	{
		return;
	}

	loaded = false;
	glDeleteShader( shaderID );
}

GLuint Shader::getShaderID()
{
	return shaderID;
}

bool Shader::isLoaded()
{
	return loaded;
}

ShaderProgram::ShaderProgram() : linked( false )
{
}

void ShaderProgram::createProgram()
{
	programID = glCreateProgram();
}

void ShaderProgram::deleteProgram()
{
	if ( !linked )
	{
		return;
	}

	linked = false;
	glDeleteProgram( programID );
}

bool ShaderProgram::addShader( Shader* shader )
{
	if( !shader->isLoaded() )
	{
		return false;
	}

	glAttachShader( programID, shader->getShaderID() );

	return true;
}

bool ShaderProgram::linkProgram()
{
	glLinkProgram( programID );

	int status;
	glGetProgramiv( programID, GL_LINK_STATUS, &status );

	linked = ( status == GL_TRUE );
	return linked;
}

void ShaderProgram::useProgram()
{
	if( linked )
	{
		glUseProgram( programID );
	}
}

GLuint ShaderProgram::getProgramID()
{
	return programID;
}



#3 Sean_Seanston   Members   -  Reputation: 371

Like
0Likes
Like

Posted 20 March 2014 - 07:11 PM

Ok, I'm closing in on the problem but haven't quite found it yet.

 

The ShaderProgram class would appear to be working correctly and the problem must lie within the Shader class.

 

If I use the old shaders, i.e.

GLuint vertShader = loadShader( GL_VERTEX_SHADER, "shader.vert" );
GLuint fragShader = loadShader( GL_FRAGMENT_SHADER, "shader.frag" );

In conjunction with the ShaderProgram class, by attaching them using the old method:

glAttachShader( program.getProgramID(), vertShader );
glAttachShader( program.getProgramID(), fragShader );

Everything then works fine.

 

Hence, there must be something wrong with the Shader class... possibly in the loading of the shaders, though I could swear the shaders appear to be loading correctly since the GL_COMPILE_STATUS isn't returning false and the full correct text of the shaders seems to be getting loaded.

 

Going to keep looking, but maybe someone else can spot something with this new information...



#4 Sean_Seanston   Members   -  Reputation: 371

Like
3Likes
Like

Posted 20 March 2014 - 08:50 PM

Ok, problem solved. Turned out it was a really dumb mistake on my part.

 

The problem was the first line of the loadShader() function:

GLuint shaderID = 0;

This was fine for the previous global version of the loadShader() function because it was used as the return value, but when I adapted that for the Shader class, I should've gotten rid of that line because it was completely unnecessary and because it was declaring a variable with the same name and type as the intended one within Shader, it was harder for me to notice what was going wrong. Ugh.

 

Solved now anyway.






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS