Ticket #1493: multitexture.diff
File multitexture.diff, 15.0 KB (added by , 12 years ago) |
---|
-
source/graphics/Material.h
28 28 class CMaterial 29 29 { 30 30 public: 31 32 struct TextureSampler 33 { 34 TextureSampler(CStr &n, CTexturePtr t) : Name(n), Sampler(t) {} 35 36 CStrIntern Name; 37 CTexturePtr Sampler; 38 }; 39 40 typedef std::vector<TextureSampler> SamplersVector; 41 31 42 CMaterial(); 32 43 33 44 // Whether this material's shaders use alpha blending, in which case … … 36 47 void SetUsesAlphaBlending(bool flag) { m_AlphaBlending = flag; } 37 48 bool UsesAlphaBlending() { return m_AlphaBlending; } 38 49 39 void SetDiffuseTexture(const CTexturePtr& texture);40 50 const CTexturePtr& GetDiffuseTexture() const { return m_DiffuseTexture; } 41 51 42 52 void SetShaderEffect(const CStr& effect); … … 48 58 void AddStaticUniform(const char* key, const CVector4D& value); 49 59 const CShaderUniforms& GetStaticUniforms() const { return m_StaticUniforms; } 50 60 61 void AddSampler(const TextureSampler& texture); 62 const SamplersVector& GetSamplers() const { return m_Samplers; } 63 51 64 private: 65 66 // This pointer is kept to make it easier for the fixed pipeline to 67 // access the only texture it's interested in. 52 68 CTexturePtr m_DiffuseTexture; 69 70 SamplersVector m_Samplers; 71 53 72 CStrIntern m_ShaderEffect; 54 73 CShaderDefines m_ShaderDefines; 55 74 CShaderUniforms m_StaticUniforms; -
source/graphics/ObjectEntry.h
32 32 #include "ps/CStr.h" 33 33 #include "ps/Overlay.h" 34 34 35 #include "graphics/ObjectBase.h" 36 35 37 class CObjectEntry 36 38 { 37 39 public: … … 46 48 // different variations of the actor. 47 49 CObjectBase* m_Base; 48 50 49 VfsPath m_TextureName; 51 // samplers list 52 std::vector<CObjectBase::Samp> m_Samplers; 50 53 // model name 51 54 VfsPath m_ModelName; 52 55 // colour (used when doing alpha-channel colouring, but not doing player-colour) -
source/graphics/ObjectBase.h
60 60 // name of the model file - art/actors/props/sword.xml or whatever 61 61 CStrW m_ModelName; 62 62 }; 63 64 struct Samp 65 { 66 // identifier name of sampler in GLSL shaders 67 CStr m_SamplerName; 68 // path to load from 69 VfsPath m_SamplerFile; 70 }; 63 71 64 72 struct Decal 65 73 { … … 79 87 CStr m_VariantName; // lowercase name 80 88 int m_Frequency; 81 89 VfsPath m_ModelFilename; 82 VfsPath m_TextureFilename;83 90 Decal m_Decal; 84 91 VfsPath m_Particles; 85 92 CStr m_Color; 86 93 87 94 std::vector<Anim> m_Anims; 88 95 std::vector<Prop> m_Props; 96 std::vector<Samp> m_Samplers; 89 97 }; 90 98 91 99 struct Variation 92 100 { 93 VfsPath texture;94 101 VfsPath model; 95 102 Decal decal; 96 103 VfsPath particles; 97 104 CStr color; 98 105 std::multimap<CStr, Prop> props; 99 106 std::multimap<CStr, Anim> anims; 107 std::multimap<CStr, Samp> samplers; 100 108 }; 101 109 102 110 CObjectBase(CObjectManager& objectManager); -
source/graphics/Material.cpp
27 27 { 28 28 } 29 29 30 void CMaterial::SetDiffuseTexture(const CTexturePtr& texture)31 {32 m_DiffuseTexture = texture;33 }34 35 30 void CMaterial::SetShaderEffect(const CStr& effect) 36 31 { 37 32 m_ShaderEffect = CStrIntern(effect); … … 46 41 { 47 42 m_StaticUniforms.Add(key, value); 48 43 } 44 45 void CMaterial::AddSampler(const TextureSampler& texture) 46 { 47 m_Samplers.push_back(texture); 48 if (texture.Name == CStrIntern("baseTex")) 49 m_DiffuseTexture = texture.Sampler; 50 } 51 No newline at end of file -
source/graphics/ObjectBase.cpp
62 62 EL(prop); 63 63 EL(mesh); 64 64 EL(texture); 65 EL(samplers); 66 EL(sampler); 65 67 EL(colour); 66 68 EL(decal); 67 69 EL(particles); … … 149 151 } 150 152 else if (option_name == el_texture) 151 153 { 152 currentVariant->m_TextureFilename = VfsPath("art/textures/skins") / option.GetText().FromUTF8(); 154 // DEPRECATED: This element type is kept for backwards compatibility with existing actor files. It has been superseded by the more generalised "samplers" element below. Maybe this should display a warning. 155 Samp samp; 156 samp.m_SamplerName = "baseTex"; 157 samp.m_SamplerFile = VfsPath("art/textures/skins") / option.GetText().FromUTF8(); 158 currentVariant->m_Samplers.push_back(samp); 153 159 } 160 else if (option_name == el_samplers) 161 { 162 XERO_ITER_EL(option, samplers_element) 163 { 164 ENSURE(samplers_element.GetNodeName() == el_sampler); 165 166 Samp samp; 167 XERO_ITER_ATTR(samplers_element, se) 168 { 169 if (se.Name == at_file) 170 samp.m_SamplerFile = VfsPath("art/textures/skins") / se.Value.FromUTF8(); 171 else if (se.Name == at_name) 172 samp.m_SamplerName = se.Value; 173 } 174 currentVariant->m_Samplers.push_back(samp); 175 } 176 } 154 177 else if (option_name == el_decal) 155 178 { 156 179 XMBAttributeList attrs = option.GetAttributes(); … … 396 419 397 420 // Apply its data: 398 421 399 if (! var.m_TextureFilename.empty())400 variation.texture = var.m_TextureFilename;401 402 422 if (! var.m_ModelFilename.empty()) 403 423 variation.model = var.m_ModelFilename; 404 424 … … 430 450 // and then insert the new ones: 431 451 for (std::vector<CObjectBase::Anim>::iterator it = var.m_Anims.begin(); it != var.m_Anims.end(); ++it) 432 452 variation.anims.insert(make_pair(it->m_AnimName, *it)); 453 454 // Same for samplers, though perhaps not strictly necessary: 455 for (std::vector<CObjectBase::Samp>::iterator it = var.m_Samplers.begin(); it != var.m_Samplers.end(); ++it) 456 variation.samplers.erase(it->m_SamplerName); 457 for (std::vector<CObjectBase::Samp>::iterator it = var.m_Samplers.begin(); it != var.m_Samplers.end(); ++it) 458 variation.samplers.insert(make_pair(it->m_SamplerName, *it)); 433 459 } 434 460 435 461 return variation; -
source/graphics/ObjectEntry.cpp
60 60 61 61 // Copy the chosen data onto this model: 62 62 63 m_TextureName = variation.texture; 63 //m_TextureName = variation.texture; 64 for (std::multimap<CStr, CObjectBase::Samp>::iterator it = variation.samplers.begin(); it != variation.samplers.end(); ++it) 65 m_Samplers.push_back(it->second); 66 64 67 m_ModelName = variation.model; 65 68 66 69 if (! variation.color.empty()) … … 76 79 77 80 if (variation.decal.m_SizeX && variation.decal.m_SizeZ) 78 81 { 79 CTextureProperties textureProps(m_TextureName); 82 std::multimap<CStr, CObjectBase::Samp>::iterator iter; 83 84 iter = variation.samplers.find("baseTex"); 80 85 86 if (iter == variation.samplers.end()) 87 { 88 LOGERROR(L"Actor '%ls' tries to create a decal but has no 'baseTex' sampler entry", m_Base->m_ShortName.c_str()); 89 return false; 90 } 91 92 CTextureProperties textureProps(iter->second.m_SamplerFile); 93 81 94 // Decals should be transparent, so clamp to the border (default 0,0,0,0) 82 95 textureProps.SetWrap(GL_CLAMP_TO_BORDER); 83 96 … … 121 134 model->SetMaterial(g_Renderer.GetMaterialManager().LoadMaterial(m_Base->m_Material)); 122 135 model->GetMaterial().AddStaticUniform("objectColor", CVector4D(m_Color.r, m_Color.g, m_Color.b, m_Color.a)); 123 136 model->InitModel(modeldef); 137 138 std::vector<CObjectBase::Samp>::iterator samp; 139 for (samp = m_Samplers.begin(); samp != m_Samplers.end(); ++samp) 140 { 141 CTextureProperties textureProps(samp->m_SamplerFile); 142 textureProps.SetWrap(GL_CLAMP_TO_EDGE); 143 CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); 144 // if we've loaded this model we're probably going to render it soon, so prefetch its texture. 145 // All textures are prefetched even in the fixed pipeline, including the normal maps etc. 146 // TODO: Should check which renderpath is selected and only preload the necessary textures. 147 texture->Prefetch(); 148 model->GetMaterial().AddSampler(CMaterial::TextureSampler(samp->m_SamplerName, texture)); 149 } 124 150 125 CTextureProperties textureProps(m_TextureName);126 textureProps.SetWrap(GL_CLAMP_TO_EDGE);127 CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);128 texture->Prefetch(); // if we've loaded this model we're probably going to render it soon, so prefetch its texture129 model->GetMaterial().SetDiffuseTexture(texture);130 131 151 // calculate initial object space bounds, based on vertex positions 132 152 model->CalcStaticObjectBounds(); 133 153 -
source/renderer/RenderModifiers.h
63 63 virtual void BeginPass(const CShaderProgramPtr& shader) = 0; 64 64 65 65 /** 66 * PrepareTexture: Called before rendering models that use the given67 * texture.68 *69 * Must be implemented by derived classes.70 *71 * @param pass The current pass number (pass == 0 is the first pass)72 * @param texture The texture used by subsequent models73 */74 virtual void PrepareTexture(const CShaderProgramPtr& shader, CTexture& texture) = 0;75 76 /**77 66 * PrepareModel: Called before rendering the given model. 78 67 * 79 68 * Default behaviour does nothing. … … 133 122 134 123 // Implementation 135 124 void BeginPass(const CShaderProgramPtr& shader); 136 void PrepareTexture(const CShaderProgramPtr& shader, CTexture& texture);137 125 void PrepareModel(const CShaderProgramPtr& shader, CModel* model); 138 126 139 127 private: 140 128 CShaderProgram::Binding m_BindingInstancingTransform; 141 129 CShaderProgram::Binding m_BindingShadingColor; 142 130 CShaderProgram::Binding m_BindingPlayerColor; 143 CShaderProgram::Binding m_BindingBaseTex;144 131 }; 145 132 146 133 #endif // INCLUDED_RENDERMODIFIERS -
source/renderer/ModelRenderer.cpp
26 26 27 27 #include "graphics/Color.h" 28 28 #include "graphics/LightEnv.h" 29 #include "graphics/Material.h" 29 30 #include "graphics/Model.h" 30 31 #include "graphics/ModelDef.h" 31 32 #include "graphics/ShaderManager.h" … … 467 468 else 468 469 { 469 470 // Sort model list by modeldef+texture, for batching 471 // TODO: This only sorts by base texture. While this is an OK approximation 472 // for most cases (as related samplers are usually used together), it would be better 473 // to take all the samplers into account when sorting here. 470 474 std::sort(it->second.begin(), it->second.end(), SMRBatchModel()); 471 475 472 476 // Add a tech bucket pointing at this model list … … 531 535 PROFILE3("rendering bucketed submissions"); 532 536 533 537 size_t idxTechStart = 0; 538 539 // This vector keeps track of texture changes during rendering. It is kept outside the 540 // loops to avoid excessive reallocations. The token allocation of 64 elements 541 // should be plenty, though it is reallocated below (at a cost) if necessary. 542 std::vector<CTexture*> currentTexs; 543 currentTexs.reserve(64); 544 545 // texBindings holds the identifier bindings in the shader, which can no longer be defined 546 // statically in the ShaderRenderModifier class. texBindingNames uses interned strings to 547 // keep track of when bindings need to be reevaluated. 548 std::vector<CShaderProgram::Binding> texBindings; 549 texBindings.reserve(64); 550 std::vector<CStrIntern> texBindingNames; 551 texBindingNames.reserve(64); 534 552 535 553 while (idxTechStart < techBuckets.size()) 536 554 { … … 555 573 modifier->BeginPass(shader); 556 574 557 575 m->vertexRenderer->BeginPass(streamflags); 558 559 CTexture* currentTex = NULL; 576 577 // When the shader technique changes, textures need to be 578 // rebound, so ensure there are no remnants from the last pass. 579 // (the vector size is set to 0, but memory is not freed) 580 currentTexs.clear(); 581 texBindings.clear(); 582 texBindingNames.clear(); 583 560 584 CModelDef* currentModeldef = NULL; 561 585 CShaderUniforms currentStaticUniforms; 562 // (Texture needs to be rebound after binding a new shader, so we563 // can't move currentTex outside of this loop to reduce state changes)564 586 565 587 for (size_t idx = idxTechStart; idx < idxTechEnd; ++idx) 566 588 { … … 573 595 if (flags && !(model->GetFlags() & flags)) 574 596 continue; 575 597 576 // Bind texture when it changes 577 CTexture* newTex = model->GetMaterial().GetDiffuseTexture().get(); 578 if (newTex != currentTex) 598 CMaterial::SamplersVector samplers = model->GetMaterial().GetSamplers(); 599 size_t samplersNum = samplers.size(); 600 601 // make sure the vectors are the right virtual sizes, and also 602 // reallocate if there are more samplers than expected. 603 if (currentTexs.size() != samplersNum) 579 604 { 580 currentTex = newTex; 581 modifier->PrepareTexture(shader, *currentTex); 605 currentTexs.resize(samplersNum, NULL); 606 texBindings.resize(samplersNum, CShaderProgram::Binding()); 607 texBindingNames.resize(samplersNum, CStrIntern()); 582 608 } 609 610 // bind the samplers to the shader 611 for (size_t s = 0; s < samplersNum; ++s) 612 { 613 CMaterial::TextureSampler &samp = samplers[s]; 614 615 CShaderProgram::Binding bind = texBindings[s]; 616 // check that the handles are current 617 // and reevaluate them if necessary 618 if (texBindingNames[s] == samp.Name && bind.Active()) 619 { 620 bind = texBindings[s]; 621 } 622 else 623 { 624 bind = shader->GetTextureBinding(samp.Name.c_str()); 625 texBindings[s] = bind; 626 texBindingNames[s] = samp.Name; 627 } 583 628 629 // same with the actual sampler bindings 630 CTexture* newTex = samp.Sampler.get(); 631 if (bind.Active() && newTex != currentTexs[s]) 632 { 633 shader->BindTexture(bind, samp.Sampler->GetHandle()); 634 currentTexs[s] = newTex; 635 } 636 } 637 584 638 // Bind modeldef when it changes 585 639 CModelDef* newModeldef = model->GetModelDef().get(); 586 640 if (newModeldef != currentModeldef) -
source/renderer/RenderModifiers.cpp
103 103 m_BindingInstancingTransform = shader->GetUniformBinding("instancingTransform"); 104 104 m_BindingShadingColor = shader->GetUniformBinding("shadingColor"); 105 105 m_BindingPlayerColor = shader->GetUniformBinding("playerColor"); 106 m_BindingBaseTex = shader->GetTextureBinding("baseTex");107 106 } 108 107 109 void ShaderRenderModifier::PrepareTexture(const CShaderProgramPtr& shader, CTexture& texture)110 {111 if (m_BindingBaseTex.Active())112 shader->BindTexture(m_BindingBaseTex, texture.GetHandle());113 }114 115 108 void ShaderRenderModifier::PrepareModel(const CShaderProgramPtr& shader, CModel* model) 116 109 { 117 110 if (m_BindingInstancingTransform.Active())