Example #1
0
	virtual Binding GetTextureBinding(texture_id_t id)
	{
		int index = GetUniformFragmentIndex(CStrIntern(id));
		if (index == -1)
			return Binding();
		else
			return Binding((int)GL_TEXTURE_2D, index);
	}
Example #2
0
	virtual Binding GetUniformBinding(uniform_id_t id)
	{
		std::map<CStrIntern, std::pair<int, GLenum> >::iterator it = m_Uniforms.find(CStrIntern(id));
		if (it == m_Uniforms.end())
			return Binding();
		else
			return Binding(it->second.first, (int)it->second.second);
	}
Example #3
0
	virtual Binding GetTextureBinding(texture_id_t id)
	{
		std::map<CStrIntern, std::pair<GLenum, int> >::iterator it = m_Samplers.find(CStrIntern(id));
		if (it == m_Samplers.end())
			return Binding();
		else
			return Binding((int)it->second.first, it->second.second);
	}
Example #4
0
	virtual void VertexAttribPointer(const char* id, GLint size, GLenum type, GLboolean normalized, GLsizei stride, void* pointer)
	{
		std::map<CStrIntern, int>::iterator it = m_VertexAttribs.find(CStrIntern(id));
		if (it != m_VertexAttribs.end())
		{
			pglVertexAttribPointerARB(it->second, size, type, normalized, stride, pointer);
		}
	}
Example #5
0
	virtual void BindTexture(texture_id_t id, GLuint tex)
	{
		int index = GetUniformFragmentIndex(CStrIntern(id));
		if (index != -1)
		{
			pglActiveTextureARB(GL_TEXTURE0+index);
			glBindTexture(GL_TEXTURE_2D, tex);
		}
	}
Example #6
0
	virtual void BindTexture(texture_id_t id, GLuint tex)
	{
		std::map<CStrIntern, std::pair<GLenum, int> >::iterator it = m_Samplers.find(CStrIntern(id));
		if (it == m_Samplers.end())
			return;

		pglActiveTextureARB(GL_TEXTURE0 + it->second.second);
		glBindTexture(it->second.first, tex);
	}
Example #7
0
	virtual void BindTexture(texture_id_t id, Handle tex)
	{
		int index = GetUniformFragmentIndex(CStrIntern(id));
		if (index != -1)
		{
			GLuint h;
			ogl_tex_get_texture_id(tex, &h);
			pglActiveTextureARB(GL_TEXTURE0+index);
			glBindTexture(GL_TEXTURE_2D, h);
		}
	}
Example #8
0
	virtual void VertexAttribIPointer(const char* id, GLint size, GLenum type, GLsizei stride, void* pointer)
	{
		std::map<CStrIntern, int>::iterator it = m_VertexAttribs.find(CStrIntern(id));
		if (it != m_VertexAttribs.end())
		{
#if CONFIG2_GLES
			debug_warn(L"glVertexAttribIPointer not supported on GLES");
#else
			pglVertexAttribIPointerEXT(it->second, size, type, stride, pointer);
#endif
		}
	}
void CPostprocManager::LoadEffect(CStrW &name)
{
	if (!m_IsInitialised) 
		return;
	
	if (name != L"default")
	{
		CStrW n = L"postproc/" + name;
		m_PostProcTech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern(n.ToUTF8()));
	}
	
	m_PostProcEffect = name;
}
Example #10
0
	virtual void Init(const CParamNode& paramNode)
	{
		m_EditorOnly = paramNode.GetChild("EditorOnly").IsOk();

		// Certain special units always have their selection overlay shown
		m_AlwaysVisible = paramNode.GetChild("Overlay").GetChild("AlwaysVisible").IsOk();
		if (m_AlwaysVisible)
		{
			m_AlphaMin = MIN_ALPHA_ALWAYS_VISIBLE;
			m_Color.a = m_AlphaMin;
		}
		else
			m_AlphaMin = MIN_ALPHA_UNSELECTED;

		const CParamNode& textureNode = paramNode.GetChild("Overlay").GetChild("Texture");
		const CParamNode& outlineNode = paramNode.GetChild("Overlay").GetChild("Outline");

		const char* textureBasePath = "art/textures/selection/";

		// Save some memory by using interned file paths in these descriptors (almost all actors and
		// entities have this component, and many use the same textures).
		if (textureNode.IsOk())
		{
			// textured quad mode (dynamic, for units)
			m_OverlayDescriptor.m_Type = ICmpSelectable::DYNAMIC_QUAD;
			m_OverlayDescriptor.m_QuadTexture = CStrIntern(textureBasePath + textureNode.GetChild("MainTexture").ToUTF8());
			m_OverlayDescriptor.m_QuadTextureMask = CStrIntern(textureBasePath + textureNode.GetChild("MainTextureMask").ToUTF8());
		}
		else if (outlineNode.IsOk())
		{
			// textured outline mode (static, for buildings)
			m_OverlayDescriptor.m_Type = ICmpSelectable::STATIC_OUTLINE;
			m_OverlayDescriptor.m_LineTexture = CStrIntern(textureBasePath + outlineNode.GetChild("LineTexture").ToUTF8());
			m_OverlayDescriptor.m_LineTextureMask = CStrIntern(textureBasePath + outlineNode.GetChild("LineTextureMask").ToUTF8());
			m_OverlayDescriptor.m_LineThickness = outlineNode.GetChild("LineThickness").ToFloat();
		}
	}
Example #11
0
void ParticleRenderer::PrepareForRendering(const CShaderDefines& context)
{
	PROFILE3("prepare particles");

	// Can't load the shader in the constructor because it's called before the
	// renderer initialisation is complete, so load it the first time through here
	if (!m->shader)
	{
		// Only construct the shaders when shaders are supported and enabled; otherwise
		// RenderParticles will never be called so it's safe to leave the shaders as null
		if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
		{
			m->shader = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("particle"), context, CShaderDefines());
			m->shaderSolid = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("particle_solid"), context, CShaderDefines());
		}
	}

	{
		PROFILE("update emitters");
		for (size_t i = 0; i < m->emitters.size(); ++i)
		{
			CParticleEmitter* emitter = m->emitters[i];
			emitter->UpdateArrayData();
		}
	}

	{
		// Sort back-to-front by distance from camera
		PROFILE("sort emitters");
		CMatrix3D worldToCam;
		g_Renderer.GetViewCamera().m_Orientation.GetInverse(worldToCam);
		std::stable_sort(m->emitters.begin(), m->emitters.end(), SortEmitterDistance(worldToCam));
	}

	// TODO: should batch by texture here when possible, maybe
}
Example #12
0
void TerrainRenderer::RenderPriorities()
{
	PROFILE("priorities");

	ENSURE(m->phase == Phase_Render);

	CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_text);
	tech->BeginPass();
	CTextRenderer textRenderer(tech->GetShader());

	textRenderer.Font(CStrIntern("mono-stroke-10"));
	textRenderer.Color(1.0f, 1.0f, 0.0f);

	for (size_t i = 0; i < m->visiblePatches.size(); ++i)
		m->visiblePatches[i]->RenderPriorities(textRenderer);

	textRenderer.Render();
	tech->EndPass();
}
Example #13
0
//Render Manager.
void CConsole::Render()
{
	if (! (m_bVisible || m_bToggle) ) return;

	PROFILE3_GPU("console");

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	CShaderTechniquePtr solidTech = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid);
	solidTech->BeginPass();
	CShaderProgramPtr solidShader = solidTech->GetShader();

	CMatrix3D transform = GetDefaultGuiMatrix();

	// animation: slide in from top of screen
	const float DeltaY = (1.0f - m_fVisibleFrac) * m_fHeight;
	transform.PostTranslate(m_fX, m_fY - DeltaY, 0.0f); // move to window position
	solidShader->Uniform(str_transform, transform);

	DrawWindow(solidShader);

	solidTech->EndPass();

	CShaderTechniquePtr textTech = g_Renderer.GetShaderManager().LoadEffect(str_gui_text);
	textTech->BeginPass();
	CTextRenderer textRenderer(textTech->GetShader());
	textRenderer.Font(CStrIntern(CONSOLE_FONT));
	textRenderer.SetTransform(transform);

	DrawHistory(textRenderer);
	DrawBuffer(textRenderer);

	textRenderer.Render();

	textTech->EndPass();

	glDisable(GL_BLEND);
}
Example #14
0
static void InitPs(bool setup_gui, const CStrW& gui_page, ScriptInterface* srcScriptInterface, JS::HandleValue initData)
{
	{
		// console
		TIMER(L"ps_console");

		g_Console->UpdateScreenSize(g_xres, g_yres);

		// Calculate and store the line spacing
		CFontMetrics font(CStrIntern(CONSOLE_FONT));
		g_Console->m_iFontHeight = font.GetLineSpacing();
		g_Console->m_iFontWidth = font.GetCharacterWidth(L'C');
		g_Console->m_charsPerPage = (size_t)(g_xres / g_Console->m_iFontWidth);
		// Offset by an arbitrary amount, to make it fit more nicely
		g_Console->m_iFontOffset = 7;

		double blinkRate = 0.5;
		CFG_GET_VAL("gui.cursorblinkrate", blinkRate);
		g_Console->SetCursorBlinkRate(blinkRate);
	}

	// hotkeys
	{
		TIMER(L"ps_lang_hotkeys");
		LoadHotkeys();
	}

	if (!setup_gui)
	{
		// We do actually need *some* kind of GUI loaded, so use the
		// (currently empty) Atlas one
		g_GUI->SwitchPage(L"page_atlas.xml", srcScriptInterface, initData);
		return;
	}

	// GUI uses VFS, so this must come after VFS init.
	g_GUI->SwitchPage(gui_page, srcScriptInterface, initData);
}
Example #15
0
void CGUIString::GenerateTextCall(SFeedback &Feedback,
								  CStrIntern DefaultFont,
								  const int &from, const int &to,
								  const bool FirstLine,
								  const IGUIObject *pObject) const
{
	// Reset width and height, because they will be determined with incrementation
	//  or comparisons.
	Feedback.Reset();

	// Check out which text chunk this is within.
	//bool match_found = false;
	std::vector<TextChunk>::const_iterator itTextChunk;
	for (itTextChunk=m_TextChunks.begin(); itTextChunk!=m_TextChunks.end(); ++itTextChunk)
	{
		// Get the area that is overlapped by both the TextChunk and
		//  by the from/to inputted.
		int _from, _to;
		_from = std::max(from, itTextChunk->m_From);
		_to = std::min(to, itTextChunk->m_To);

		// If from is larger than to, than they are not overlapping
		if (_to == _from && itTextChunk->m_From == itTextChunk->m_To)
		{
			// These should never be able to have more than one tag.
			ENSURE(itTextChunk->m_Tags.size()==1);

			// Now do second check
			//  because icons and images are placed on exactly one position
			//  in the words-list, it can be counted twice if placed on an
			//  edge. But there is always only one logical preference that
			//  we want. This check filters the unwanted.

			// it's in the end of one word, and the icon
			//  should really belong to the beginning of the next one
			if (_to == to && to >= 1)
			{
				if (GetRawString()[to-1] == ' ' ||
					GetRawString()[to-1] == '-' ||
					GetRawString()[to-1] == '\n')
					continue;
			}
			// This std::string is just a break
			if (_from == from && from >= 1)
			{
				if (GetRawString()[from] == '\n' &&
					GetRawString()[from-1] != '\n' &&
					GetRawString()[from-1] != ' ' &&
					GetRawString()[from-1] != '-')
					continue;
			}

			// Single tags
			if (itTextChunk->m_Tags[0].m_TagType == CGUIString::TextChunk::Tag::TAG_IMGLEFT)
			{
				// Only add the image if the icon exists.
				if (g_GUI->IconExists(itTextChunk->m_Tags[0].m_TagValue))
				{
					Feedback.m_Images[SFeedback::Left].push_back(itTextChunk->m_Tags[0].m_TagValue);
				}
				else if (pObject)
				{
					LOGERROR(L"Trying to use an [imgleft]-tag with an undefined icon (\"%hs\").", itTextChunk->m_Tags[0].m_TagValue.c_str());
				}
			}
			else
			if (itTextChunk->m_Tags[0].m_TagType == CGUIString::TextChunk::Tag::TAG_IMGRIGHT)
			{
				// Only add the image if the icon exists.
				if (g_GUI->IconExists(itTextChunk->m_Tags[0].m_TagValue))
				{
					Feedback.m_Images[SFeedback::Right].push_back(itTextChunk->m_Tags[0].m_TagValue);
				}
				else if (pObject)
				{
					LOGERROR(L"Trying to use an [imgright]-tag with an undefined icon (\"%hs\").", itTextChunk->m_Tags[0].m_TagValue.c_str());
				}
			}
			else
			if (itTextChunk->m_Tags[0].m_TagType == CGUIString::TextChunk::Tag::TAG_ICON)
			{
				// Only add the image if the icon exists.
				if (g_GUI->IconExists(itTextChunk->m_Tags[0].m_TagValue))
				{
					// We'll need to setup a text-call that will point
					//  to the icon, this is to be able to iterate
					//  through the text-calls without having to
					//  complex the structure virtually for nothing more.
					SGUIText::STextCall TextCall;

					// Also add it to the sprites being rendered.
					SGUIText::SSpriteCall SpriteCall;

					// Get Icon from icon database in g_GUI
					SGUIIcon icon = g_GUI->GetIcon(itTextChunk->m_Tags[0].m_TagValue);

					CSize size = icon.m_Size;

					// append width, and make maximum height the height.
					Feedback.m_Size.cx += size.cx;
					Feedback.m_Size.cy = std::max(Feedback.m_Size.cy, size.cy);

					// These are also needed later
					TextCall.m_Size = size;
					SpriteCall.m_Area = size;

					// Handle additional attributes
					std::vector<TextChunk::Tag::TagAttribute>::const_iterator att_it;
					for(att_it = itTextChunk->m_Tags[0].m_TagAttributes.begin(); att_it != itTextChunk->m_Tags[0].m_TagAttributes.end(); ++att_it)
					{
						TextChunk::Tag::TagAttribute tagAttrib = (TextChunk::Tag::TagAttribute)(*att_it);

						if (tagAttrib.attrib == "displace" && !tagAttrib.value.empty())
						{	//Displace the sprite
							CSize displacement;
							// Parse the value
							if (!GUI<CSize>::ParseString(CStr(tagAttrib.value).FromUTF8(), displacement))
								LOGERROR(L"Error parsing 'displace' value for tag [ICON]");
							else
								SpriteCall.m_Area += displacement;

						}
						else if(tagAttrib.attrib == "tooltip")
						{
							SpriteCall.m_Tooltip = CStr(tagAttrib.value).FromUTF8();
						}
						else if(tagAttrib.attrib == "tooltip_style")
						{
							SpriteCall.m_TooltipStyle = CStr(tagAttrib.value).FromUTF8();
						}
					}

					SpriteCall.m_Sprite = icon.m_SpriteName;
					SpriteCall.m_CellID = icon.m_CellID;

					// Add sprite call
					Feedback.m_SpriteCalls.push_back(SpriteCall);

					// Finalize text call
					TextCall.m_pSpriteCall = &Feedback.m_SpriteCalls.back();

					// Add text call
					Feedback.m_TextCalls.push_back(TextCall);
				}
				else if (pObject)
				{
					LOGERROR(L"Trying to use an [icon]-tag with an undefined icon (\"%hs\").", itTextChunk->m_Tags[0].m_TagValue.c_str());
				}
			}
		}
		else
		if (_to > _from && !Feedback.m_NewLine)
		{
			SGUIText::STextCall TextCall;

			// Set defaults
			TextCall.m_Font = DefaultFont;
			TextCall.m_UseCustomColor = false;

			// Extract substd::string from RawString.
			TextCall.m_String = GetRawString().substr(_from, _to-_from);

			// Go through tags and apply changes.
			std::vector<CGUIString::TextChunk::Tag>::const_iterator it2;
			for (it2 = itTextChunk->m_Tags.begin(); it2 != itTextChunk->m_Tags.end(); ++it2)
			{
				if (it2->m_TagType == CGUIString::TextChunk::Tag::TAG_COLOR)
				{
					// Set custom color
					TextCall.m_UseCustomColor = true;

					// Try parsing the color std::string
					if (!GUI<CColor>::ParseString(CStr(it2->m_TagValue).FromUTF8(), TextCall.m_Color))
					{
						if (pObject)
							LOGERROR(L"Error parsing the value of a [color]-tag in GUI text when reading object \"%hs\".", pObject->GetPresentableName().c_str());
					}
				}
				else
				if (it2->m_TagType == CGUIString::TextChunk::Tag::TAG_FONT)
				{
					// TODO Gee: (2004-08-15) Check if Font exists?
					TextCall.m_Font = CStrIntern(it2->m_TagValue);
				}
			}

			// Calculate the size of the font
			CSize size;
			int cx, cy;
			CFontMetrics font (TextCall.m_Font);
			font.CalculateStringSize(TextCall.m_String.c_str(), cx, cy);
			// For anything other than the first line, the line spacing
			// needs to be considered rather than just the height of the text
			if (! FirstLine)
				cy = font.GetLineSpacing();

			size.cx = (float)cx;
			size.cy = (float)cy;

			// Append width, and make maximum height the height.
			Feedback.m_Size.cx += size.cx;
			Feedback.m_Size.cy = std::max(Feedback.m_Size.cy, size.cy);

			// These are also needed later
			TextCall.m_Size = size;

			if (! TextCall.m_String.empty())
			{
				if (TextCall.m_String[0] == '\n')
				{
					Feedback.m_NewLine = true;
				}
			}

			// Add text-chunk
			Feedback.m_TextCalls.push_back(TextCall);
		}
	}
}
Example #16
0
void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShaderDefines& context, int cullGroup, int flags)
{
	if (m->submissions[cullGroup].empty())
		return;

	CMatrix3D worldToCam;
	g_Renderer.GetViewCamera().m_Orientation.GetInverse(worldToCam);

	/*
	 * Rendering approach:
	 * 
	 * m->submissions contains the list of CModels to render.
	 * 
	 * The data we need to render a model is:
	 *  - CShaderTechnique
	 *  - CTexture
	 *  - CShaderUniforms
	 *  - CModelDef (mesh data)
	 *  - CModel (model instance data)
	 * 
	 * For efficient rendering, we need to batch the draw calls to minimise state changes.
	 * (Uniform and texture changes are assumed to be cheaper than binding new mesh data,
	 * and shader changes are assumed to be most expensive.)
	 * First, group all models that share a technique to render them together.
	 * Within those groups, sub-group by CModelDef.
	 * Within those sub-groups, sub-sub-group by CTexture.
	 * Within those sub-sub-groups, sub-sub-sub-group by CShaderUniforms.
	 * 
	 * Alpha-blended models have to be sorted by distance from camera,
	 * then we can batch as long as the order is preserved.
	 * Non-alpha-blended models can be arbitrarily reordered to maximise batching.
	 * 
	 * For each model, the CShaderTechnique is derived from:
	 *  - The current global 'context' defines
	 *  - The CModel's material's defines
	 *  - The CModel's material's shader effect name
	 * 
	 * There are a smallish number of materials, and a smaller number of techniques.
	 * 
	 * To minimise technique lookups, we first group models by material,
	 * in 'materialBuckets' (a hash table).
	 * 
	 * For each material bucket we then look up the appropriate shader technique.
	 * If the technique requires sort-by-distance, the model is added to the
	 * 'sortByDistItems' list with its computed distance.
	 * Otherwise, the bucket's list of models is sorted by modeldef+texture+uniforms,
	 * then the technique and model list is added to 'techBuckets'.
	 * 
	 * 'techBuckets' is then sorted by technique, to improve batching when multiple
	 * materials map onto the same technique.
	 * 
	 * (Note that this isn't perfect batching: we don't sort across models in
	 * multiple buckets that share a technique. In practice that shouldn't reduce
	 * batching much (we rarely have one mesh used with multiple materials),
	 * and it saves on copying and lets us sort smaller lists.)
	 * 
	 * Extra tech buckets are added for the sorted-by-distance models without reordering.
	 * Finally we render by looping over each tech bucket, then looping over the model
	 * list in each, rebinding the GL state whenever it changes.
	 */

	Allocators::DynamicArena arena(256 * KiB);
	typedef ProxyAllocator<CModel*, Allocators::DynamicArena> ModelListAllocator;
	typedef std::vector<CModel*, ModelListAllocator> ModelList_t;
	typedef boost::unordered_map<SMRMaterialBucketKey, ModelList_t,
		SMRMaterialBucketKeyHash, std::equal_to<SMRMaterialBucketKey>,
		ProxyAllocator<std::pair<const SMRMaterialBucketKey, ModelList_t>, Allocators::DynamicArena>
	> MaterialBuckets_t;
	MaterialBuckets_t materialBuckets((MaterialBuckets_t::allocator_type(arena)));

	{
		PROFILE3("bucketing by material");

		for (size_t i = 0; i < m->submissions[cullGroup].size(); ++i)
		{
			CModel* model = m->submissions[cullGroup][i];

			uint32_t condFlags = 0;

			const CShaderConditionalDefines& condefs = model->GetMaterial().GetConditionalDefines();
			for (size_t j = 0; j < condefs.GetSize(); ++j)
			{
				const CShaderConditionalDefines::CondDefine& item = condefs.GetItem(j);
				int type = item.m_CondType;
				switch (type)
				{
					case DCOND_DISTANCE:
					{
						CVector3D modelpos = model->GetTransform().GetTranslation();
						float dist = worldToCam.Transform(modelpos).Z;
						
						float dmin = item.m_CondArgs[0];
						float dmax = item.m_CondArgs[1];
						
						if ((dmin < 0 || dist >= dmin) && (dmax < 0 || dist < dmax))
							condFlags |= (1 << j);
						
						break;
					}
				}
			}

			CShaderDefines defs = model->GetMaterial().GetShaderDefines(condFlags);
			SMRMaterialBucketKey key(model->GetMaterial().GetShaderEffect(), defs);

			MaterialBuckets_t::iterator it = materialBuckets.find(key);
			if (it == materialBuckets.end())
			{
				std::pair<MaterialBuckets_t::iterator, bool> inserted = materialBuckets.insert(
					std::make_pair(key, ModelList_t(ModelList_t::allocator_type(arena))));
				inserted.first->second.reserve(32);
				inserted.first->second.push_back(model);
			}
			else
			{
				it->second.push_back(model);
			}
		}
	}

	typedef ProxyAllocator<SMRSortByDistItem, Allocators::DynamicArena> SortByDistItemsAllocator;
	std::vector<SMRSortByDistItem, SortByDistItemsAllocator> sortByDistItems((SortByDistItemsAllocator(arena)));

	typedef ProxyAllocator<CShaderTechniquePtr, Allocators::DynamicArena> SortByTechItemsAllocator;
	std::vector<CShaderTechniquePtr, SortByTechItemsAllocator> sortByDistTechs((SortByTechItemsAllocator(arena)));
		// indexed by sortByDistItems[i].techIdx
		// (which stores indexes instead of CShaderTechniquePtr directly
		// to avoid the shared_ptr copy cost when sorting; maybe it'd be better
		// if we just stored raw CShaderTechnique* and assumed the shader manager
		// will keep it alive long enough)

	typedef ProxyAllocator<SMRTechBucket, Allocators::DynamicArena> TechBucketsAllocator;
	std::vector<SMRTechBucket, TechBucketsAllocator> techBuckets((TechBucketsAllocator(arena)));

	{
		PROFILE3("processing material buckets");
		for (MaterialBuckets_t::iterator it = materialBuckets.begin(); it != materialBuckets.end(); ++it)
		{
			CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(it->first.effect, context, it->first.defines);

			// Skip invalid techniques (e.g. from data file errors)
			if (!tech)
				continue;

			if (tech->GetSortByDistance())
			{
				// Add the tech into a vector so we can index it
				// (There might be duplicates in this list, but that doesn't really matter)
				if (sortByDistTechs.empty() || sortByDistTechs.back() != tech)
					sortByDistTechs.push_back(tech);
				size_t techIdx = sortByDistTechs.size()-1;

				// Add each model into sortByDistItems
				for (size_t i = 0; i < it->second.size(); ++i)
				{
					SMRSortByDistItem itemWithDist;
					itemWithDist.techIdx = techIdx;

					CModel* model = it->second[i];
					itemWithDist.model = model;

					CVector3D modelpos = model->GetTransform().GetTranslation();
					itemWithDist.dist = worldToCam.Transform(modelpos).Z;

					sortByDistItems.push_back(itemWithDist);
				}
			}
			else
			{
				// Sort model list by modeldef+texture, for batching
				// TODO: This only sorts by base texture. While this is an OK approximation
				// for most cases (as related samplers are usually used together), it would be better
				// to take all the samplers into account when sorting here.
				std::sort(it->second.begin(), it->second.end(), SMRBatchModel());

				// Add a tech bucket pointing at this model list
				SMRTechBucket techBucket = { tech, &it->second[0], it->second.size() };
				techBuckets.push_back(techBucket);
			}
		}
	}

	{
		PROFILE3("sorting tech buckets");
		// Sort by technique, for better batching
		std::sort(techBuckets.begin(), techBuckets.end(), SMRCompareTechBucket());
	}

	// List of models corresponding to sortByDistItems[i].model
	// (This exists primarily because techBuckets wants a CModel**;
	// we could avoid the cost of copying into this list by adding
	// a stride length into techBuckets and not requiring contiguous CModel*s)
	std::vector<CModel*, ModelListAllocator> sortByDistModels((ModelListAllocator(arena)));

	if (!sortByDistItems.empty())
	{
		{
			PROFILE3("sorting items by dist");
			std::sort(sortByDistItems.begin(), sortByDistItems.end(), SMRCompareSortByDistItem());
		}

		{
			PROFILE3("batching dist-sorted items");

			sortByDistModels.reserve(sortByDistItems.size());

			// Find runs of distance-sorted models that share a technique,
			// and create a new tech bucket for each run

			size_t start = 0; // start of current run
			size_t currentTechIdx = sortByDistItems[start].techIdx;

			for (size_t end = 0; end < sortByDistItems.size(); ++end)
			{
				sortByDistModels.push_back(sortByDistItems[end].model);

				size_t techIdx = sortByDistItems[end].techIdx;
				if (techIdx != currentTechIdx)
				{
					// Start of a new run - push the old run into a new tech bucket
					SMRTechBucket techBucket = { sortByDistTechs[currentTechIdx], &sortByDistModels[start], end-start };
					techBuckets.push_back(techBucket);
					start = end;
					currentTechIdx = techIdx;
				}
			}

			// Add the tech bucket for the final run
			SMRTechBucket techBucket = { sortByDistTechs[currentTechIdx], &sortByDistModels[start], sortByDistItems.size()-start };
			techBuckets.push_back(techBucket);
		}
	}

	{
		PROFILE3("rendering bucketed submissions");

		size_t idxTechStart = 0;
		
		// This vector keeps track of texture changes during rendering. It is kept outside the
		// loops to avoid excessive reallocations. The token allocation of 64 elements 
		// should be plenty, though it is reallocated below (at a cost) if necessary.
		typedef ProxyAllocator<CTexture*, Allocators::DynamicArena> TextureListAllocator;
		std::vector<CTexture*, TextureListAllocator> currentTexs((TextureListAllocator(arena)));
		currentTexs.reserve(64);
		
		// texBindings holds the identifier bindings in the shader, which can no longer be defined 
		// statically in the ShaderRenderModifier class. texBindingNames uses interned strings to
		// keep track of when bindings need to be reevaluated.
		typedef ProxyAllocator<CShaderProgram::Binding, Allocators::DynamicArena> BindingListAllocator;
		std::vector<CShaderProgram::Binding, BindingListAllocator> texBindings((BindingListAllocator(arena)));
		texBindings.reserve(64);

		typedef ProxyAllocator<CStrIntern, Allocators::DynamicArena> BindingNamesListAllocator;
		std::vector<CStrIntern, BindingNamesListAllocator> texBindingNames((BindingNamesListAllocator(arena)));
		texBindingNames.reserve(64);

		while (idxTechStart < techBuckets.size())
		{
			CShaderTechniquePtr currentTech = techBuckets[idxTechStart].tech;

			// Find runs [idxTechStart, idxTechEnd) in techBuckets of the same technique
			size_t idxTechEnd;
			for (idxTechEnd = idxTechStart + 1; idxTechEnd < techBuckets.size(); ++idxTechEnd)
			{
				if (techBuckets[idxTechEnd].tech != currentTech)
					break;
			}

			// For each of the technique's passes, render all the models in this run
			for (int pass = 0; pass < currentTech->GetNumPasses(); ++pass)
			{
				currentTech->BeginPass(pass);

				const CShaderProgramPtr& shader = currentTech->GetShader(pass);
				int streamflags = shader->GetStreamFlags();

				modifier->BeginPass(shader);

				m->vertexRenderer->BeginPass(streamflags);
				
				// When the shader technique changes, textures need to be
				// rebound, so ensure there are no remnants from the last pass.
				// (the vector size is set to 0, but memory is not freed)
				currentTexs.clear();
				texBindings.clear();
				texBindingNames.clear();
				
				CModelDef* currentModeldef = NULL;
				CShaderUniforms currentStaticUniforms;

				for (size_t idx = idxTechStart; idx < idxTechEnd; ++idx)
				{
					CModel** models = techBuckets[idx].models;
					size_t numModels = techBuckets[idx].numModels;
					for (size_t i = 0; i < numModels; ++i)
					{
						CModel* model = models[i];

						if (flags && !(model->GetFlags() & flags))
							continue;

						const CMaterial::SamplersVector& samplers = model->GetMaterial().GetSamplers();
						size_t samplersNum = samplers.size();
						
						// make sure the vectors are the right virtual sizes, and also
						// reallocate if there are more samplers than expected.
						if (currentTexs.size() != samplersNum)
						{
							currentTexs.resize(samplersNum, NULL);
							texBindings.resize(samplersNum, CShaderProgram::Binding());
							texBindingNames.resize(samplersNum, CStrIntern());
							
							// ensure they are definitely empty
							std::fill(texBindings.begin(), texBindings.end(), CShaderProgram::Binding());
							std::fill(currentTexs.begin(), currentTexs.end(), (CTexture*)NULL);
							std::fill(texBindingNames.begin(), texBindingNames.end(), CStrIntern());
						}
						
						// bind the samplers to the shader
						for (size_t s = 0; s < samplersNum; ++s)
						{
							const CMaterial::TextureSampler& samp = samplers[s];
							
							CShaderProgram::Binding bind = texBindings[s];
							// check that the handles are current
							// and reevaluate them if necessary
							if (texBindingNames[s] == samp.Name && bind.Active())
							{
								bind = texBindings[s];
							}
							else
							{
								bind = shader->GetTextureBinding(samp.Name);
								texBindings[s] = bind;
								texBindingNames[s] = samp.Name;
							}

							// same with the actual sampler bindings
							CTexture* newTex = samp.Sampler.get();
							if (bind.Active() && newTex != currentTexs[s])
							{
								shader->BindTexture(bind, samp.Sampler->GetHandle());
								currentTexs[s] = newTex;
							}
						}
						
						// Bind modeldef when it changes
						CModelDef* newModeldef = model->GetModelDef().get();
						if (newModeldef != currentModeldef)
						{
							currentModeldef = newModeldef;
							m->vertexRenderer->PrepareModelDef(shader, streamflags, *currentModeldef);
						}

						// Bind all uniforms when any change
						CShaderUniforms newStaticUniforms = model->GetMaterial().GetStaticUniforms();
						if (newStaticUniforms != currentStaticUniforms)
						{
							currentStaticUniforms = newStaticUniforms;
							currentStaticUniforms.BindUniforms(shader);
						}
						
						const CShaderRenderQueries& renderQueries = model->GetMaterial().GetRenderQueries();
						
						for (size_t q = 0; q < renderQueries.GetSize(); q++)
						{
							CShaderRenderQueries::RenderQuery rq = renderQueries.GetItem(q);
							if (rq.first == RQUERY_TIME)
							{
								CShaderProgram::Binding binding = shader->GetUniformBinding(rq.second);
								if (binding.Active())
								{
									double time = g_Renderer.GetTimeManager().GetGlobalTime();
									shader->Uniform(binding, time, 0,0,0);
								}
							}
							else if (rq.first == RQUERY_WATER_TEX)
							{
								WaterManager* WaterMgr = g_Renderer.GetWaterManager();
								double time = WaterMgr->m_WaterTexTimer;
								double period = 1.6;
								int curTex = (int)(time*60/period) % 60;
								
								if (WaterMgr->m_RenderWater && WaterMgr->WillRenderFancyWater())
									shader->BindTexture(str_waterTex, WaterMgr->m_NormalMap[curTex]);
								else
									shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture());
							}
							else if (rq.first == RQUERY_SKY_CUBE)
							{
								shader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube());
							}
						}

						modifier->PrepareModel(shader, model);

						CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData());
						ENSURE(rdata->GetKey() == m->vertexRenderer.get());

						m->vertexRenderer->RenderModel(shader, streamflags, model, rdata);
					}
				}

				m->vertexRenderer->EndPass(streamflags);

				currentTech->EndPass(pass);
			}

			idxTechStart = idxTechEnd;
		}
	}
}
Example #17
0
void CMiniMap::Draw()
{
	PROFILE3("render minimap");

	// The terrain isn't actually initialized until the map is loaded, which
	// happens when the game is started, so abort until then.
	if(!(GetGUI() && g_Game && g_Game->IsGameStarted()))
		return;

	CSimulation2* sim = g_Game->GetSimulation2();
	CmpPtr<ICmpRangeManager> cmpRangeManager(*sim, SYSTEM_ENTITY);
	ENSURE(cmpRangeManager);

	// Set our globals in case they hadn't been set before
	m_Camera      = g_Game->GetView()->GetCamera();
	m_Terrain     = g_Game->GetWorld()->GetTerrain();
	m_Width  = (u32)(m_CachedActualSize.right - m_CachedActualSize.left);
	m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top);
	m_MapSize = m_Terrain->GetVerticesPerSide();
	m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize);
	m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f);

	if(!m_TerrainTexture || g_GameRestarted)
		CreateTextures();


	// only update 2x / second
	// (note: since units only move a few pixels per second on the minimap,
	// we can get away with infrequent updates; this is slow)
	static double last_time;
	const double cur_time = timer_Time();
	if(cur_time - last_time > 0.5)
	{
		last_time = cur_time;

		if(m_TerrainDirty)
			RebuildTerrainTexture();
	}

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	CMatrix3D matrix = GetDefaultGuiMatrix();
	glLoadMatrixf(&matrix._11);

	// Disable depth updates to prevent apparent z-fighting-related issues
	// with some drivers causing units to get drawn behind the texture
	glDepthMask(0);
	
	CShaderProgramPtr shader;
	CShaderTechniquePtr tech;
	
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
	{
		CShaderDefines defines;
		defines.Add("MINIMAP_BASE", "1");
		tech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("minimap"), g_Renderer.GetSystemShaderDefines(), defines);
		tech->BeginPass();
		shader = tech->GetShader();
	}
	else
	{
		shader = g_Renderer.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines());
		shader->Bind();
	}

	const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom;
	const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top;
	const float z = GetBufferedZ();
	const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize;
	const float angle = GetAngle();

	// Draw the main textured quad
	//g_Renderer.BindTexture(0, m_TerrainTexture);
	
	shader->BindTexture("baseTex", m_TerrainTexture);
	
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	DrawTexture(texCoordMax, angle, x, y, x2, y2, z);


	// Draw territory boundaries
	CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture();
	
	shader->BindTexture("baseTex", territoryTexture.GetTexture());
	
	//territoryTexture.BindTexture(0);
	glEnable(GL_BLEND);
	glMatrixMode(GL_TEXTURE);
	glLoadMatrixf(territoryTexture.GetMinimapTextureMatrix());
	glMatrixMode(GL_MODELVIEW);

	DrawTexture(1.0f, angle, x, y, x2, y2, z);

	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glDisable(GL_BLEND);


	// Draw the LOS quad in black, using alpha values from the LOS texture
	CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture();
	
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
	{
		tech->EndPass();

		CShaderDefines defines;
		defines.Add("MINIMAP_LOS", "1");
		tech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("minimap"), g_Renderer.GetSystemShaderDefines(), defines);
		tech->BeginPass();
		shader = tech->GetShader();
	}
	
	shader->BindTexture("baseTex", losTexture.GetTexture());
	
	//losTexture.BindTexture(0);
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor3f(0.0f, 0.0f, 0.0f);

	glMatrixMode(GL_TEXTURE);
	glLoadMatrixf(losTexture.GetMinimapTextureMatrix());
	glMatrixMode(GL_MODELVIEW);

	DrawTexture(1.0f, angle, x, y, x2, y2, z);

	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);

	glDisable(GL_BLEND);
	
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
	{
		tech->EndPass();

		CShaderDefines defines;
		defines.Add("MINIMAP_POINT", "1");
		tech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("minimap"), g_Renderer.GetSystemShaderDefines(), defines);
		tech->BeginPass();
		shader = tech->GetShader();
	}
	
	// Set up the matrix for drawing points and lines
	glPushMatrix();
	glTranslatef(x, y, z);
	// Rotate around the center of the map
	glTranslatef((x2-x)/2.f, (y2-y)/2.f, 0.f);
	// Scale square maps to fit in circular minimap area
	float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f);
	glScalef(unitScale, unitScale, 1.f);
	glRotatef(angle * 180.f/M_PI, 0.f, 0.f, 1.f);
	glTranslatef(-(x2-x)/2.f, -(y2-y)/2.f, 0.f);

	PROFILE_START("minimap units");

	// Don't enable GL_POINT_SMOOTH because it's far too slow
	// (~70msec/frame on a GF4 rendering a thousand points)
	glPointSize(3.f);

	float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);
	float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);

	CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap);

	std::vector<MinimapUnitVertex> vertexArray;
	vertexArray.reserve(ents.size());

	for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
	{
		MinimapUnitVertex v;
		ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second);
		entity_pos_t posX, posZ;
		if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ))
		{
			ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID());
			if (vis != ICmpRangeManager::VIS_HIDDEN)
			{
				v.a = 255;
				v.x = posX.ToFloat()*sx;
				v.y = -posZ.ToFloat()*sy;
				vertexArray.push_back(v);
			}
		}
	}

	if (!vertexArray.empty())
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_COLOR_ARRAY);
		shader->VertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x);
		shader->ColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r);

		glDrawArrays(GL_POINTS, 0, (GLsizei)vertexArray.size());

		glDisableClientState(GL_COLOR_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);
	}

	PROFILE_END("minimap units");
	
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
	{
		tech->EndPass();

		CShaderDefines defines;
		defines.Add("MINIMAP_LINE", "1");
		tech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("minimap"), g_Renderer.GetSystemShaderDefines(), defines);
		tech->BeginPass();
		shader = tech->GetShader();
	}

	DrawViewRect();

	glPopMatrix();
	
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();
	
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
	{
		tech->EndPass();
	}
	else
	{
		shader->Unbind();
	}

	// Reset everything back to normal
	glPointSize(1.0f);
	glEnable(GL_TEXTURE_2D);
	glDepthMask(1);
}
Example #18
0
void CMaterial::SetShaderEffect(const CStr& effect)
{
	m_ShaderEffect = CStrIntern(effect);
}
Example #19
0
void TerrainRenderer::RenderTerrainShader(const CShaderDefines& context, ShadowMap* shadow, bool filtered)
{
    ENSURE(m->phase == Phase_Render);

    std::vector<CPatchRData*>& visiblePatches = filtered ? m->filteredPatches : m->visiblePatches;
    std::vector<CDecalRData*>& visibleDecals = filtered ? m->filteredDecals : m->visibleDecals;
    if (visiblePatches.empty() && visibleDecals.empty())
        return;

    CShaderManager& shaderManager = g_Renderer.GetShaderManager();

    CShaderTechniquePtr techBase(shaderManager.LoadEffect(CStrIntern("terrain_base"), context, CShaderDefines()));
    CShaderTechniquePtr techBlend(shaderManager.LoadEffect(CStrIntern("terrain_blend"), context, CShaderDefines()));
    CShaderTechniquePtr techDecal(shaderManager.LoadEffect(CStrIntern("terrain_decal"), context, CShaderDefines()));

    // render the solid black sides of the map first
    CShaderTechniquePtr techSolid = g_Renderer.GetShaderManager().LoadEffect("gui_solid");
    techSolid->BeginPass();
    CShaderProgramPtr shaderSolid = techSolid->GetShader();
    shaderSolid->Uniform("transform", g_Renderer.GetViewCamera().GetViewProjection());
    shaderSolid->Uniform("color", 0.0f, 0.0f, 0.0f, 1.0f);

    PROFILE_START("render terrain sides");
    for (size_t i = 0; i < visiblePatches.size(); ++i)
        visiblePatches[i]->RenderSides(shaderSolid);
    PROFILE_END("render terrain sides");

    techSolid->EndPass();

    techBase->BeginPass();
    PrepareShader(techBase->GetShader(), shadow);

    PROFILE_START("render terrain base");
    CPatchRData::RenderBases(visiblePatches, techBase->GetShader(), false);
    PROFILE_END("render terrain base");

    techBase->EndPass();

    // render blends

    techBlend->BeginPass();
    PrepareShader(techBlend->GetShader(), shadow);

    // switch on blending
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // no need to write to the depth buffer a second time
    glDepthMask(0);

    // render blend passes for each patch
    PROFILE_START("render terrain blends");
    CPatchRData::RenderBlends(visiblePatches, techBlend->GetShader(), false);
    PROFILE_END("render terrain blends");

    techBlend->EndPass();

    // Render terrain decals

    techDecal->BeginPass();
    PrepareShader(techDecal->GetShader(), shadow);

    PROFILE_START("render terrain decals");
    for (size_t i = 0; i < visibleDecals.size(); ++i)
        visibleDecals[i]->Render(techDecal->GetShader(), false);
    PROFILE_END("render terrain decals");

    techDecal->EndPass();

    // restore OpenGL state
    g_Renderer.BindTexture(1, 0);
    g_Renderer.BindTexture(2, 0);
    g_Renderer.BindTexture(3, 0);

    glDepthMask(1);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glDisable(GL_BLEND);
}
Example #20
0
void CShaderDefines::Add(const char* name, const char* value)
{
	Set(CStrIntern(name), CStrIntern(value));
}
Example #21
0
CMaterial CMaterialManager::LoadMaterial(const VfsPath& pathname)
{
	if (pathname.empty())
		return CMaterial();

	std::map<VfsPath, CMaterial>::iterator iter = m_Materials.find(pathname);
	if (iter != m_Materials.end())
		return iter->second;

	CXeromyces xeroFile;
	if (xeroFile.Load(g_VFS, pathname, "material") != PSRETURN_OK)
		return CMaterial();

	#define EL(x) int el_##x = xeroFile.GetElementID(#x)
	#define AT(x) int at_##x = xeroFile.GetAttributeID(#x)
	EL(alpha_blending);
	EL(alternative);
	EL(define);
	EL(shader);
	EL(uniform);
	EL(renderquery);
	EL(required_texture);
	EL(conditional_define);
	AT(effect);
	AT(if);
	AT(define);
	AT(quality);
	AT(material);
	AT(name);
	AT(value);
	AT(type);
	AT(min);
	AT(max);
	AT(conf);
	#undef AT
	#undef EL

	CMaterial material;

	XMBElement root = xeroFile.GetRoot();

	CPreprocessorWrapper preprocessor;
	preprocessor.AddDefine("CFG_FORCE_ALPHATEST", g_Renderer.m_Options.m_ForceAlphaTest ? "1" : "0");

	CVector4D vec(qualityLevel,0,0,0);
	material.AddStaticUniform("qualityLevel", vec);

	XERO_ITER_EL(root, node)
	{
		int token = node.GetNodeName();
		XMBAttributeList attrs = node.GetAttributes();
		if (token == el_alternative)
		{
			CStr cond = attrs.GetNamedItem(at_if);
			if (cond.empty() || !preprocessor.TestConditional(cond))
			{
				cond = attrs.GetNamedItem(at_quality);
				if (cond.empty())
					continue;
				else
				{
					if (cond.ToFloat() <= qualityLevel)
						continue;
				}
			}

			material = LoadMaterial(VfsPath("art/materials") / attrs.GetNamedItem(at_material).FromUTF8());
			break;
		}
		else if (token == el_alpha_blending)
		{
			material.SetUsesAlphaBlending(true);
		}
		else if (token == el_shader)
		{
			material.SetShaderEffect(attrs.GetNamedItem(at_effect));
		}
		else if (token == el_define)
		{
			material.AddShaderDefine(CStrIntern(attrs.GetNamedItem(at_name)), CStrIntern(attrs.GetNamedItem(at_value)));
		}
		else if (token == el_conditional_define)
		{
			std::vector<float> args;

			CStr type = attrs.GetNamedItem(at_type).c_str();
			int typeID = -1;

			if (type == CStr("draw_range"))
			{
				typeID = DCOND_DISTANCE;

				float valmin = -1.0f;
				float valmax = -1.0f;

				CStr conf = attrs.GetNamedItem(at_conf);
				if (!conf.empty())
				{
					CFG_GET_VAL("materialmgr." + conf + ".min", valmin);
					CFG_GET_VAL("materialmgr." + conf + ".max", valmax);
				}
				else
				{
					CStr dmin = attrs.GetNamedItem(at_min);
					if (!dmin.empty())
						valmin = attrs.GetNamedItem(at_min).ToFloat();

					CStr dmax = attrs.GetNamedItem(at_max);
					if (!dmax.empty())
						valmax = attrs.GetNamedItem(at_max).ToFloat();
				}

				args.push_back(valmin);
				args.push_back(valmax);

				if (valmin >= 0.0f)
				{
					std::stringstream sstr;
					sstr << valmin;
					material.AddShaderDefine(CStrIntern(conf + "_MIN"), CStrIntern(sstr.str()));
				}

				if (valmax >= 0.0f)
				{
					std::stringstream sstr;
					sstr << valmax;
					material.AddShaderDefine(CStrIntern(conf + "_MAX"), CStrIntern(sstr.str()));
				}
			}

			material.AddConditionalDefine(attrs.GetNamedItem(at_name).c_str(),
						      attrs.GetNamedItem(at_value).c_str(),
						      typeID, args);
		}
		else if (token == el_uniform)
		{
			std::stringstream str(attrs.GetNamedItem(at_value));
			CVector4D vec;
			str >> vec.X >> vec.Y >> vec.Z >> vec.W;
			material.AddStaticUniform(attrs.GetNamedItem(at_name).c_str(), vec);
		}
Example #22
0
bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefines, CShaderProgramPtr& program)
{
    PROFILE2("loading shader");
    PROFILE2_ATTR("name: %s", name);

    if (strncmp(name, "fixed:", 6) == 0)
    {
        program = CShaderProgramPtr(CShaderProgram::ConstructFFP(name+6, baseDefines));
        if (!program)
            return false;
        program->Reload();
        return true;
    }

    VfsPath xmlFilename = L"shaders/" + wstring_from_utf8(name) + L".xml";

    CXeromyces XeroFile;
    PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename);
    if (ret != PSRETURN_OK)
        return false;

#if USE_SHADER_XML_VALIDATION
    {
        TIMER_ACCRUE(tc_ShaderValidation);

        // Serialize the XMB data and pass it to the validator
        XML_Start();
        XML_SetPrettyPrint(false);
        XML_WriteXMB(XeroFile);
        bool ok = m_Validator.ValidateEncoded(wstring_from_utf8(name), XML_GetOutput());
        if (!ok)
            return false;
    }
#endif

    // Define all the elements and attributes used in the XML file
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
    EL(attrib);
    EL(define);
    EL(fragment);
    EL(stream);
    EL(uniform);
    EL(vertex);
    AT(file);
    AT(if);
    AT(loc);
    AT(name);
    AT(semantics);
    AT(type);
    AT(value);
#undef AT
#undef EL

    CPreprocessorWrapper preprocessor;
    preprocessor.AddDefines(baseDefines);

    XMBElement Root = XeroFile.GetRoot();

    bool isGLSL = (Root.GetAttributes().GetNamedItem(at_type) == "glsl");
    VfsPath vertexFile;
    VfsPath fragmentFile;
    CShaderDefines defines = baseDefines;
    std::map<CStrIntern, int> vertexUniforms;
    std::map<CStrIntern, CShaderProgram::frag_index_pair_t> fragmentUniforms;
    std::map<CStrIntern, int> vertexAttribs;
    int streamFlags = 0;

    XERO_ITER_EL(Root, Child)
    {
        if (Child.GetNodeName() == el_define)
        {
            defines.Add(CStrIntern(Child.GetAttributes().GetNamedItem(at_name)), CStrIntern(Child.GetAttributes().GetNamedItem(at_value)));
        }
        else if (Child.GetNodeName() == el_vertex)
        {
            vertexFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8();

            XERO_ITER_EL(Child, Param)
            {
                XMBAttributeList Attrs = Param.GetAttributes();

                CStr cond = Attrs.GetNamedItem(at_if);
                if (!cond.empty() && !preprocessor.TestConditional(cond))
                    continue;

                if (Param.GetNodeName() == el_uniform)
                {
                    vertexUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = Attrs.GetNamedItem(at_loc).ToInt();
                }
                else if (Param.GetNodeName() == el_stream)
                {
                    CStr StreamName = Attrs.GetNamedItem(at_name);
                    if (StreamName == "pos")
                        streamFlags |= STREAM_POS;
                    else if (StreamName == "normal")
                        streamFlags |= STREAM_NORMAL;
                    else if (StreamName == "color")
                        streamFlags |= STREAM_COLOR;
                    else if (StreamName == "uv0")
                        streamFlags |= STREAM_UV0;
                    else if (StreamName == "uv1")
                        streamFlags |= STREAM_UV1;
                    else if (StreamName == "uv2")
                        streamFlags |= STREAM_UV2;
                    else if (StreamName == "uv3")
                        streamFlags |= STREAM_UV3;
                }
                else if (Param.GetNodeName() == el_attrib)
                {
                    int attribLoc = ParseAttribSemantics(Attrs.GetNamedItem(at_semantics));
                    vertexAttribs[CStrIntern(Attrs.GetNamedItem(at_name))] = attribLoc;
                }
            }
        }
Example #23
0
void CMaterial::AddSampler(const TextureSampler& texture)
{
	m_Samplers.push_back(texture);
	if (texture.Name == CStrIntern("baseTex"))
		m_DiffuseTexture = texture.Sampler;
}