Ejemplo n.º 1
0
/*
================================================================================================
idRenderProgManager::LoadGLSLShader
================================================================================================
*/
GLuint idRenderProgManager::LoadGLSLShader( GLenum target, const char * name, idList<int> & uniforms ) {

	idStr inFile;
	idStr outFileHLSL;
	idStr outFileGLSL;
	idStr outFileUniforms;
	inFile.Format( "renderprogs\\%s", name );
	inFile.StripFileExtension();
	outFileHLSL.Format( "renderprogs\\glsl\\%s", name );
	outFileHLSL.StripFileExtension();
	outFileGLSL.Format( "renderprogs\\glsl\\%s", name );
	outFileGLSL.StripFileExtension();
	outFileUniforms.Format( "renderprogs\\glsl\\%s", name );
	outFileUniforms.StripFileExtension();
	if ( target == GL_FRAGMENT_SHADER ) {
		inFile += ".pixel";
		outFileHLSL += "_fragment.hlsl";
		outFileGLSL += "_fragment.glsl";
		outFileUniforms += "_fragment.uniforms";
	} else {
		inFile += ".vertex";
		outFileHLSL += "_vertex.hlsl";
		outFileGLSL += "_vertex.glsl";
		outFileUniforms += "_vertex.uniforms";
	}

	// first check whether we already have a valid GLSL file and compare it to the hlsl timestamp;
	ID_TIME_T hlslTimeStamp;
	int hlslFileLength = fileSystem->ReadFile( inFile.c_str(), NULL, &hlslTimeStamp );

	ID_TIME_T glslTimeStamp;
	int glslFileLength = fileSystem->ReadFile( outFileGLSL.c_str(), NULL, &glslTimeStamp );

	// if the glsl file doesn't exist or we have a newer HLSL file we need to recreate the glsl file.
	idStr programGLSL;
	idStr programUniforms;
	if ( ( glslFileLength <= 0 ) || ( hlslTimeStamp > glslTimeStamp ) ) {
		if ( hlslFileLength <= 0 ) {
			// hlsl file doesn't even exist bail out
			return false;
		}

		void * hlslFileBuffer = NULL;
		int len = fileSystem->ReadFile( inFile.c_str(), &hlslFileBuffer );
		if ( len <= 0 ) {
			return false;
		}
		idStr hlslCode( ( const char* ) hlslFileBuffer );
		idStr programHLSL = StripDeadCode( hlslCode, inFile );
		programGLSL = ConvertCG2GLSL( programHLSL, inFile, target == GL_VERTEX_SHADER, programUniforms );

		fileSystem->WriteFile( outFileHLSL, programHLSL.c_str(), programHLSL.Length(), "fs_basepath" );
		fileSystem->WriteFile( outFileGLSL, programGLSL.c_str(), programGLSL.Length(), "fs_basepath" );
		if ( r_useUniformArrays.GetBool() ) {
			fileSystem->WriteFile( outFileUniforms, programUniforms.c_str(), programUniforms.Length(), "fs_basepath" );
		}
	} else {
		// read in the glsl file
		void * fileBufferGLSL = NULL;
		int lengthGLSL = fileSystem->ReadFile( outFileGLSL.c_str(), &fileBufferGLSL );
		if ( lengthGLSL <= 0 ) {
			idLib::Error( "GLSL file %s could not be loaded and may be corrupt", outFileGLSL.c_str() );
		}
		programGLSL = ( const char * ) fileBufferGLSL;
		Mem_Free( fileBufferGLSL );

		if ( r_useUniformArrays.GetBool() ) {
			// read in the uniform file
			void * fileBufferUniforms = NULL;
			int lengthUniforms = fileSystem->ReadFile( outFileUniforms.c_str(), &fileBufferUniforms );
			if ( lengthUniforms <= 0 ) {
				idLib::Error( "uniform file %s could not be loaded and may be corrupt", outFileUniforms.c_str() );
			}
			programUniforms = ( const char* ) fileBufferUniforms;
			Mem_Free( fileBufferUniforms );
		}
	}

	// find the uniforms locations in either the vertex or fragment uniform array
	if ( r_useUniformArrays.GetBool() ) {
		uniforms.Clear();

		idLexer src( programUniforms, programUniforms.Length(), "uniforms" );
		idToken token;
		while ( src.ReadToken( &token ) ) {
			int index = -1;
			for ( int i = 0; i < RENDERPARM_TOTAL && index == -1; i++ ) {
				const char * parmName = GetGLSLParmName( i );
				if ( token == parmName ) {
					index = i;
				}
			}
			for ( int i = 0; i < MAX_GLSL_USER_PARMS && index == -1; i++ ) {
				const char * parmName = GetGLSLParmName( RENDERPARM_USER + i );
				if ( token == parmName ) {
					index = RENDERPARM_USER + i;
				}
			}
			if ( index == -1 ) {
				idLib::Error( "couldn't find uniform %s for %s", token.c_str(), outFileGLSL.c_str() );
			}
			uniforms.Append( index );
		}
	}

	// create and compile the shader
	const GLuint shader = qglCreateShader( target );
	if ( shader ) {
		const char * source[1] = { programGLSL.c_str() };

		qglShaderSource( shader, 1, source, NULL );
		qglCompileShader( shader );

		int infologLength = 0;
		qglGetShaderiv( shader, GL_INFO_LOG_LENGTH, &infologLength );
		if ( infologLength > 1 ) {
			idTempArray<char> infoLog( infologLength );
			int charsWritten = 0;
			qglGetShaderInfoLog( shader, infologLength, &charsWritten, infoLog.Ptr() );

			// catch the strings the ATI and Intel drivers output on success
			if ( strstr( infoLog.Ptr(), "successfully compiled to run on hardware" ) != NULL || 
					strstr( infoLog.Ptr(), "No errors." ) != NULL ) {
				//idLib::Printf( "%s program %s from %s compiled to run on hardware\n", typeName, GetName(), GetFileName() );
			} else if ( r_displayGLSLCompilerMessages.GetBool() ) {
				idLib::Printf( "While compiling %s program %s\n", ( target == GL_FRAGMENT_SHADER ) ? "fragment" : "vertex" , inFile.c_str() );

				const char separator = '\n';
				idList<idStr> lines;
				lines.Clear();
				idStr source( programGLSL );
				lines.Append( source );
				for ( int index = 0, ofs = lines[index].Find( separator ); ofs != -1; index++, ofs = lines[index].Find( separator ) ) {
					lines.Append( lines[index].c_str() + ofs + 1 );
					lines[index].CapLength( ofs );
				}

				idLib::Printf( "-----------------\n" );
				for ( int i = 0; i < lines.Num(); i++ ) {
					idLib::Printf( "%3d: %s\n", i+1, lines[i].c_str() );
				}
				idLib::Printf( "-----------------\n" );

				idLib::Printf( "%s\n", infoLog.Ptr() );
			}
		}

		GLint compiled = GL_FALSE;
		qglGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );
		if ( compiled == GL_FALSE ) {
			qglDeleteShader( shader );
			return INVALID_PROGID;
		}
	}

	return shader;
}
Ejemplo n.º 2
0
/**
 * @brief Reads/Preprocesses/Compiles the specified shader into a program.
 * @param[in] type The type of shader, currently either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
 * @param[in] name The file name of the shader to load from ./base/shaders/ (e.g. "world_fs.glsl").
 * @return A structure used as a handle to the compiled shader (program).
 */
static r_shader_t* R_LoadShader (const GLenum type, const char* name)
{
	r_shader_t* sh;
	char path[MAX_QPATH], *src[1];
	unsigned e, length[1];
	char* srcBuf;
	byte* buf;
	int i;
	size_t bufLength = SHADER_BUF_SIZE;
	size_t initializeLength;

#ifdef DEBUG
	/* Used to contain result of shader compile.*/
	char log[MAX_STRING_CHARS];
#endif

	snprintf(path, sizeof(path), "shaders/%s", name);

	if (FS_LoadFile(path, &buf) == -1) {
		Com_DPrintf(DEBUG_RENDERER, "R_LoadShader: Failed to load ./base/shaders/%s.\n", name);
		return nullptr;
	}

	Com_DPrintf(DEBUG_RENDERER, "R_LoadShader: Loading ./base/shaders/%s.\n", name);

	char* const source = srcBuf = Mem_PoolAllocTypeN(char, bufLength, vid_imagePool);

	initializeLength = R_InitializeShader(type, name, srcBuf, bufLength);
	srcBuf += initializeLength;
	bufLength -= initializeLength;

	R_PreprocessShader(name, (const char*)buf, srcBuf, &bufLength);
	FS_FreeFile(buf);

	src[0] = source;
	length[0] = strlen(source);

	for (i = 0; i < MAX_SHADERS; i++) {
		sh = &r_state.shaders[i];

		if (!sh->id)
			break;
	}

	if (i == MAX_SHADERS) {
		Com_Printf("R_LoadShader: MAX_SHADERS reached.\n");
		Mem_Free(source);
		return nullptr;
	}

	Q_strncpyz(sh->name, name, sizeof(sh->name));

	sh->type = type;

	sh->id = qglCreateShader(sh->type);
	if (!sh->id) {
		Mem_Free(source);
		return nullptr;
	}

	/* upload the shader source */
	qglShaderSource(sh->id, 1, src, length);

	/* compile it and check for errors */
	qglCompileShader(sh->id);

	Mem_Free(source);

	qglGetShaderiv(sh->id, GL_COMPILE_STATUS, &e);
#ifdef DEBUG
	qglGetShaderInfoLog(sh->id, sizeof(log) - 1, nullptr, log);
	Com_Printf("R_LoadShader: %s: %s", sh->name, log);
#endif
	if (!e) {
#ifndef DEBUG
		char log[MAX_STRING_CHARS];
		qglGetShaderInfoLog(sh->id, sizeof(log) - 1, nullptr, log);
		Com_Printf("R_LoadShader: %s: %s", sh->name, log);
#endif

		qglDeleteShader(sh->id);
		OBJZERO(*sh);

		return nullptr;
	}

	return sh;
}
Ejemplo n.º 3
0
/*
 * @brief
 */
static r_shader_t *R_LoadShader(GLenum type, const char *name) {
	r_shader_t *sh;
	char path[MAX_QPATH], *src[1], log[MAX_STRING_CHARS];
	uint32_t e, length[1];
	void *buf;
	int32_t i, len;

	g_snprintf(path, sizeof(path), "shaders/%s", name);

	if ((len = Fs_Load(path, &buf)) == -1) {
		Com_Warn("Failed to load %s\n", name);
		return NULL;
	}

	src[0] = (char *) buf;
	length[0] = len;

	for (i = 0; i < MAX_SHADERS; i++) {
		sh = &r_state.shaders[i];

		if (!sh->id)
			break;
	}

	if (i == MAX_SHADERS) {
		Com_Warn("MAX_SHADERS reached\n");
		Fs_Free(buf);
		return NULL;
	}

	g_strlcpy(sh->name, name, sizeof(sh->name));

	sh->type = type;

	sh->id = qglCreateShader(sh->type);
	if (!sh->id) {
		Fs_Free(buf);
		return NULL;
	}

	// upload the shader source
	qglShaderSource(sh->id, 1, src, length);

	// compile it and check for errors
	qglCompileShader(sh->id);

	qglGetShaderiv(sh->id, GL_COMPILE_STATUS, &e);
	if (!e) {
		qglGetShaderInfoLog(sh->id, sizeof(log) - 1, NULL, log);
		Com_Warn("%s: %s\n", sh->name, log);

		qglDeleteShader(sh->id);
		memset(sh, 0, sizeof(*sh));

		Fs_Free(buf);
		return NULL;
	}

	Fs_Free(buf);
	return sh;
}