Shaders manager & co

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Shaders manager & co

Post by radubolovan »

Hello again :)
I've made some structures and classes for managing shaders.
I have no where to upload a demo so here is the code in the next posts.

Enjoy :)
Last edited by radubolovan on Sat May 31, 2008 10:52 am, edited 1 time in total.
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Post by radubolovan »

dswshader.h

Code: Select all

/***************************************************************************
 *   Copyright (C) 2007-2008 by Radu Dumitru Bolovan                       *
 *   radubolovan@darkstarlinux.ro                                          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

/**
	@author Radu Dumitru Bolovan <radubolovan@darkstarlinux.ro>
 */

#ifndef __DSWHEELS_SHADER_H__
#define __DSWHEELS_SHADER_H__

#include "irrlicht.h"
using namespace irr;

typedef enum _eShaderParamType
{
	SH_PARAM_TYPE_VERTEX = 0,
	SH_PARAM_TYPE_PIXEL
}eShaderParamType;

typedef enum _eTexParamType
{
	SH_TEX_TYPE_DIFFUSE = 0,
	SH_TEX_TYPE_BUMP,
	SH_TEX_TYPE_SPECULAR
}eTexParamType;

typedef struct _tShaderParam
{
	inline _tShaderParam()
	{
		m_type = SH_PARAM_TYPE_VERTEX;
		strcpy( m_name, "" );
		m_nVanCount = 0;
		m_values = NULL;
	}

	_tShaderParam( char const* name, float const* values, int nValCount, eShaderParamType type );
	~_tShaderParam();

	eShaderParamType	m_type;
	char				m_name[256];
	float*				m_values;
	int					m_nVanCount;
}tShaderParam;

class DSWShaderCallBack : public video::IShaderConstantSetCallBack
{
public:
	inline DSWShaderCallBack() : video::IShaderConstantSetCallBack(){}
	~DSWShaderCallBack()
	{
		uint nIndex;
		for( nIndex = 0; nIndex < m_params.size(); nIndex++ )
		{
			tShaderParam* param = m_params[ nIndex ];
			delete param;
		}
	}

	inline void addShaderParam( char const* name, float const* values, int nValCount, const eShaderParamType& type )
	{
		uint nIndex;
		for( nIndex = 0; nIndex < m_params.size(); nIndex++ )
		{
			if( strcmp( m_params[nIndex]->m_name, name ) == 0 )
				return;
		}
		tShaderParam* param = new tShaderParam( name, values, nValCount, type );
		m_params.push_back( param );
	}

	inline void setParamValues( char const* name, float const* values, int nValCount )
	{
		uint nIndex;
		for( nIndex = 0; nIndex < m_params.size(); nIndex++ )
		{
			if( strcmp( m_params[nIndex]->m_name, name ) == 0 )
			{
				if( m_params[nIndex]->m_nVanCount < nValCount )
					return;
				memcpy( m_params[nIndex]->m_values, values, nValCount * sizeof(float) );
				return;
			}
		}
	}

	inline void OnSetConstants( video::IMaterialRendererServices* s, s32 userData )
	{
		uint nIndex;
		for( nIndex = 0; nIndex < m_params.size(); nIndex++ )
		{
			if( m_params[nIndex]->m_type, SH_PARAM_TYPE_VERTEX )
				s->setVertexShaderConstant( m_params[nIndex]->m_name, m_params[nIndex]->m_values, m_params[nIndex]->m_nVanCount );
			else
				s->setPixelShaderConstant( m_params[nIndex]->m_name, m_params[nIndex]->m_values, m_params[nIndex]->m_nVanCount );
		}
	}

protected:
	core::array<tShaderParam*> m_params;
};

class ShaderManager;

class Shader
{
public:
	inline Shader()
	{
		m_shCallback = NULL;
		strcpy( m_name, "" );
		m_nId = -1;
		m_manager = NULL;
	}
	Shader( char const* name, ShaderManager* man );
	~Shader();

	int load( c8* vsFileName, c8* psFileName, E_MATERIAL_TYPE matType );

	inline int id(){ return m_nId; }

	inline void addParam( char const* name, float const* values, int nValCount, const eShaderParamType& type )
	{
		m_shCallback->addShaderParam( name, values, nValCount, type );
	}

	inline void setParamValues( char const* name, float const* values, int nValCount )
	{
		m_shCallback->setParamValues( name, values, nValCount );
	}

	friend class ShaderManager;

protected:
	DSWShaderCallBack*		m_shCallback;
	char					m_name[256];
	int						m_nId;

	ShaderManager*			m_manager;
};

class ShaderManager
{
public:
	ShaderManager();
	~ShaderManager();

	void init( char const* szAppDir );

	s32 loadShader( char const* shaderName, c8* vsFileName, c8* psFileName, E_MATERIAL_TYPE matType );

	s32 getShader( char const* shaderName );

	Shader* shader( char const* shaderName ) const;

	friend class Shader;

protected:
	char					m_szAppDir[DSW_MAX_PATH];

	E_VERTEX_SHADER_TYPE	m_vsType;
	E_PIXEL_SHADER_TYPE		m_psType;

	core::array<Shader*> m_shaders;

   video::IVideoDriver*        m_driver
};

extern DSWheels::ShaderManager* g_pShaderManager;

#endif //__DSWHEELS_SHADER_H__
Last edited by radubolovan on Mon Jun 02, 2008 8:00 pm, edited 2 times in total.
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Post by radubolovan »

dswshader.cpp

Code: Select all

/***************************************************************************
 *   Copyright (C) 2007-2008 by Radu Dumitru Bolovan                       *
 *   radubolovan@darkstarlinux.ro                                          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

/**
	@author Radu Dumitru Bolovan <radubolovan@darkstarlinux.ro>
 */

#include "dswshader.h"

_tShaderParam::_tShaderParam( char const* name, float const* values, int nValCount, eShaderParamType type )
{
	m_type = type;
	strcpy( m_name, name );
	m_nVanCount = nValCount;
	m_values = (float*)malloc( nValCount * sizeof(float) );
	memcpy( m_values, values, nValCount * sizeof(float) );
}

_tShaderParam::~_tShaderParam()
{
	if( m_nVanCount > 0 )
	{
		free( m_values );
	}
}

DSWheels::ShaderManager* g_pShaderManager = NULL;

/************************************************************************************/
Shader::Shader( char const* name, ShaderManager* man )
{
	m_shCallback = new DSWShaderCallBack();
	strcpy( m_name, name );
	m_nId = -1;
	m_manager = man;
}

Shader::~Shader()
{
	delete m_shCallback;
}

int Shader::load( c8* vsFileName, c8* psFileName, E_MATERIAL_TYPE matType )
{
	m_nId = m_manager->m_driver->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles( vsFileName, "main", m_manager->m_vsType, psFileName, "main", m_manager->m_psType, m_shCallback, matType );
	return m_nId;
}
/************************************************************************************/


/************************************************************************************/
ShaderManager::ShaderManager()
{
	strcpy( m_szAppDir, "" );

   m_driver = NULL;
	m_vsType = EVST_VS_1_1;
	m_psType = EPST_PS_1_1;
}

ShaderManager::~ShaderManager()
{
	uint nIndex;
	for( nIndex = 0; nIndex < m_shaders.size(); nIndex++ )
	{
		delete m_shaders[nIndex];
	}
}

void ShaderManager::init( char const* szAppDir, video::IVideoDriver* driver )
{
	strcpy( m_szAppDir, szAppDir );

	video::E_DRIVER_TYPE dType = driver->getDriverType();
	if( ( dType == video::EDT_DIRECT3D9 ) || ( dType == video::EDT_DIRECT3D8 ) )
	{
		if( driver->queryFeature( video::EVDF_VERTEX_SHADER_3_0 ) )
			m_vsType = video::EVST_VS_3_0;
		else if( driver->queryFeature( video::EVDF_VERTEX_SHADER_2_0 ) )
			m_vsType = video::EVST_VS_2_0;
		else if( driver->queryFeature( video::EVDF_VERTEX_SHADER_1_1 ) )
			m_vsType = video::EVST_VS_1_1;
	
		if( driver->queryFeature( video::EVDF_VERTEX_SHADER_3_0 ) )
			m_psType = video::EPST_PS_3_0;
		else if( driver->queryFeature( video::EVDF_PIXEL_SHADER_2_0 ) )
			m_psType = video::EPST_PS_2_0;
		else if( driver->queryFeature( video::EVDF_PIXEL_SHADER_1_4 ) )
			m_psType = video::EPST_PS_1_4;
		else if( driver->queryFeature( video::EVDF_PIXEL_SHADER_1_3 ) )
			m_psType = video::EPST_PS_1_3;
		else if( driver->queryFeature( video::EVDF_PIXEL_SHADER_1_2 ) )
			m_psType = video::EPST_PS_1_2;
		else if( driver->queryFeature( video::EVDF_VERTEX_SHADER_1_1 ) )
			m_psType = video::EPST_PS_1_1;
	}
	else if( dType == video::EDT_OPENGL )
	{
		m_vsType = EVST_VS_3_0;
		m_psType = EPST_PS_3_0;
	}

   m_driver = driver;
}

s32 ShaderManager::loadShader( char const* shaderName, c8* vsFileName, c8* psFileName, E_MATERIAL_TYPE matType )
{
	uint nIndex;
	for( nIndex = 0; nIndex < m_shaders.size(); nIndex++ )
	{
		if( strcmp( m_shaders[nIndex]->m_name, shaderName ) == 0 )
		{
			return m_shaders[nIndex]->id();
		}
	}
	Shader* sh = new Shader( shaderName, this );
	int nRet = sh->load( vsFileName, psFileName, matType );
	if( nRet > -1 )
		m_shaders.push_back( sh );
	return nRet;
}

s32 ShaderManager::getShader( char const* shaderName )
{
	uint nIndex;
	for( nIndex = 0; nIndex < m_shaders.size(); nIndex++ )
	{
		if( strcmp( m_shaders[nIndex]->m_name, shaderName ) == 0 )
		{
			return m_shaders[nIndex]->id();
		}
	}
	return -1;
}

Shader* ShaderManager::shader( char const* shaderName ) const
{
	uint nIndex;
	for( nIndex = 0; nIndex < m_shaders.size(); nIndex++ )
	{
		Shader* sh = m_shaders[nIndex];
		if( strcmp( sh->m_name, shaderName ) == 0 )
		{
			return sh;
		}
	}
	return NULL;
}
/************************************************************************************/
Last edited by radubolovan on Mon Jun 02, 2008 7:59 pm, edited 1 time in total.
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Post by radubolovan »

Usage
Initialisations

Code: Select all

g_pShaderManager = new ShaderManager();
	g_pShaderManager->init( "data_directory", driver );
destroying

Code: Select all

delete g_pShaderManager;
Using

Code: Select all

int nShader = g_pShaderManager->loadShader( "my_shader", "path_to_vertex_shader_inside_data_directory", "path_to_fragment_shader_inside_data_directory", video::EMT_SOLID );
You can change EMT_SOLID with any material type.
Adding to vertex shader parameter(s)

Code: Select all

float fVValue = 1.0f;
	g_pShaderManager->shader( "my_shader" )->addParam( "a_Vparameter", &fPValue, 1, SH_PARAM_TYPE_VERTEX );
Adding to fragment shader parameter(s)

Code: Select all

float fPValue = 1.0f;
	g_pShaderManager->shader( "my_shader" )->addParam( "a_Pparameter", &fPValue, 1, SH_PARAM_TYPE_PIXEL );
changing parameters values - you cand do this per frame before smgr->drawAll()

Code: Select all

float fNewValue = 5.0f;
	g_pShaderManager->shader( "my_shader" )->setParamValues( "a_Vparameter", &fNewValue, 1 );
Last edited by radubolovan on Mon Jun 02, 2008 8:01 pm, edited 1 time in total.
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Instead of setting the default to PS 1.1, and VS 1.1, what I like to do is query the maximum supported shader model using driver->queryFeature() and use that instead, it's a good idea to compile for the highest supported shader model even on shaders that fall well below the instruction limit for example PS 3.0, because compiling at a higher model produces much more efficient code and less instructions since the compiler can utilize newly added optimization features.

Cheers
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Post by radubolovan »

BlindSide wrote:Instead of setting the default to PS 1.1, and VS 1.1, what I like to do is query the maximum supported shader model using driver->queryFeature() and use that instead, it's a good idea to compile for the highest supported shader model even on shaders that fall well below the instruction limit for example PS 3.0, because compiling at a higher model produces much more efficient code and less instructions since the compiler can utilize newly added optimization features.

Cheers
You're absolutly right :) ... see modifications above
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

hi radubolovan,

i'm impressed with the posted code above. good job.

i guess the bar is now raised higher, and i'm hoping to see more interesting code posted that build on top of it.

what i'd like to see are presets, shaders that are basically generic and can be applied to a material on-the-fly. then only then i can tweak the parameters and see these changes real-time.
Image
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Post by radubolovan »

Hello dlangdev ... I intend to do that (a shader editor), but before ... I want to add some kind of templates ... Something like writting in a file or more many functions as applyLights() for example, then in other file write "include_file.tsh" (sht = shader template) and simply applyLights() ... it's not difficult, but I have to right some code and right now I don't have the time :( ... but soon :D
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

hi radubolovan,

once again, i'd like to express my gratitude to the effort you made, not only that, you posted a real working code here as well.

at the moment, i'm using the code you posted above as a way of getting into a simple hypershader design. no lights are going to be added in this design, though. it's mostly about shaders and its relation to a material.

when implemented, i should be able to have a simple shader objects built onto a simple shader editor.

of course, bump mapping and displacement maps will be there as well.
Image
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Post by radubolovan »

dlangdev wrote:... no lights are going to be added in this design, though. it's mostly about shaders and its relation to a material.....
You can export any variables to shader ... any lights variables or ... anything...
example:

Code: Select all

scene::ILightSceneNode* l1 = smgr->addLightSceneNode( ... );
video::SLight ld = l1->getLightData ();

float lightVector[4];
lightVector[0] = ld.AmbientColor.getRed();
lightVector[1] = ld.AmbientColor.getGreen();
lightVector[2] = ld.AmbientColor.getBlue();
lightVector[3] = ld.AmbientColor.getAlpha();
then

Code: Select all

g_pShaderManager->shader( "my_shader" )->addParam( "light_color", &lightVector[0], 4, SH_PARAM_TYPE_PIXEL );
Then in the fragment shader:

Code: Select all

uniform float light_color[4];
and use it as well ...
And you cand export enything you want :)
[EDIT]
but ... here is an example of shader which is using light with no export (but texture):
vertex shader:

Code: Select all

varying vec4 a_color;
void main()
{
	vec3 normal = normalize( gl_NormalMatrix * gl_Normal );
	vec3 position = vec3( gl_ModelViewMatrix * gl_Vertex );
	vec3 lightVector = normalize( gl_LightSource[0].position.xyz - position );
	vec4 diffuse = gl_FrontLightProduct[0].diffuse * max( 0.0, dot( normal,lightVector ) );
	a_color = gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + diffuse;
	
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
	
	gl_TexCoord[0] = gl_MultiTexCoord0;
}
fragment shader:

Code: Select all

varying vec4 a_color;
uniform sampler2D myTexture;
void main()
{
   vec4 col = texture2D( myTexture, vec2( gl_TexCoord[0] ) );
   gl_FragColor = col * a_color;
}
I think I was copying this shaders from irrlicht forums ... anyway it's working ;)
Post Reply