Ticket #1493: multitexture.diff

File multitexture.diff, 15.0 KB (added by myconid, 12 years ago)

All the above

  • source/graphics/Material.h

     
    2828class CMaterial
    2929{
    3030public:
     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   
    3142    CMaterial();
    3243
    3344    // Whether this material's shaders use alpha blending, in which case
     
    3647    void SetUsesAlphaBlending(bool flag) { m_AlphaBlending = flag; }
    3748    bool UsesAlphaBlending() { return m_AlphaBlending; }
    3849
    39     void SetDiffuseTexture(const CTexturePtr& texture);
    4050    const CTexturePtr& GetDiffuseTexture() const { return m_DiffuseTexture; }
    4151
    4252    void SetShaderEffect(const CStr& effect);
     
    4858    void AddStaticUniform(const char* key, const CVector4D& value);
    4959    const CShaderUniforms& GetStaticUniforms() const { return m_StaticUniforms; }
    5060
     61    void AddSampler(const TextureSampler& texture);
     62    const SamplersVector& GetSamplers() const { return m_Samplers; }
     63
    5164private:
     65   
     66    // This pointer is kept to make it easier for the fixed pipeline to
     67    // access the only texture it's interested in.
    5268    CTexturePtr m_DiffuseTexture;
     69   
     70    SamplersVector m_Samplers;
     71   
    5372    CStrIntern m_ShaderEffect;
    5473    CShaderDefines m_ShaderDefines;
    5574    CShaderUniforms m_StaticUniforms;
  • source/graphics/ObjectEntry.h

     
    3232#include "ps/CStr.h"
    3333#include "ps/Overlay.h"
    3434
     35#include "graphics/ObjectBase.h"
     36
    3537class CObjectEntry
    3638{
    3739public:
     
    4648    // different variations of the actor.
    4749    CObjectBase* m_Base;
    4850
    49     VfsPath m_TextureName;
     51    // samplers list
     52    std::vector<CObjectBase::Samp> m_Samplers;
    5053    // model name
    5154    VfsPath m_ModelName;
    5255    // colour (used when doing alpha-channel colouring, but not doing player-colour)
  • source/graphics/ObjectBase.h

     
    6060        // name of the model file - art/actors/props/sword.xml or whatever
    6161        CStrW m_ModelName;
    6262    };
     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    };
    6371
    6472    struct Decal
    6573    {
     
    7987        CStr m_VariantName; // lowercase name
    8088        int m_Frequency;
    8189        VfsPath m_ModelFilename;
    82         VfsPath m_TextureFilename;
    8390        Decal m_Decal;
    8491        VfsPath m_Particles;
    8592        CStr m_Color;
    8693
    8794        std::vector<Anim> m_Anims;
    8895        std::vector<Prop> m_Props;
     96        std::vector<Samp> m_Samplers;
    8997    };
    9098
    9199    struct Variation
    92100    {
    93         VfsPath texture;
    94101        VfsPath model;
    95102        Decal decal;
    96103        VfsPath particles;
    97104        CStr color;
    98105        std::multimap<CStr, Prop> props;
    99106        std::multimap<CStr, Anim> anims;
     107        std::multimap<CStr, Samp> samplers;
    100108    };
    101109
    102110    CObjectBase(CObjectManager& objectManager);
  • source/graphics/Material.cpp

     
    2727{
    2828}
    2929
    30 void CMaterial::SetDiffuseTexture(const CTexturePtr& texture)
    31 {
    32     m_DiffuseTexture = texture;
    33 }
    34 
    3530void CMaterial::SetShaderEffect(const CStr& effect)
    3631{
    3732    m_ShaderEffect = CStrIntern(effect);
     
    4641{
    4742    m_StaticUniforms.Add(key, value);
    4843}
     44
     45void 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

     
    6262    EL(prop);
    6363    EL(mesh);
    6464    EL(texture);
     65    EL(samplers);
     66    EL(sampler);
    6567    EL(colour);
    6668    EL(decal);
    6769    EL(particles);
     
    149151                    }
    150152                    else if (option_name == el_texture)
    151153                    {
    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);
    153159                    }
     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                    }
    154177                    else if (option_name == el_decal)
    155178                    {
    156179                        XMBAttributeList attrs = option.GetAttributes();
     
    396419
    397420        // Apply its data:
    398421
    399         if (! var.m_TextureFilename.empty())
    400             variation.texture = var.m_TextureFilename;
    401 
    402422        if (! var.m_ModelFilename.empty())
    403423            variation.model = var.m_ModelFilename;
    404424
     
    430450        // and then insert the new ones:
    431451        for (std::vector<CObjectBase::Anim>::iterator it = var.m_Anims.begin(); it != var.m_Anims.end(); ++it)
    432452            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));
    433459    }
    434460
    435461    return variation;
  • source/graphics/ObjectEntry.cpp

     
    6060
    6161    // Copy the chosen data onto this model:
    6262
    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   
    6467    m_ModelName = variation.model;
    6568
    6669    if (! variation.color.empty())
     
    7679
    7780    if (variation.decal.m_SizeX && variation.decal.m_SizeZ)
    7881    {
    79         CTextureProperties textureProps(m_TextureName);
     82        std::multimap<CStr, CObjectBase::Samp>::iterator iter;
     83       
     84        iter = variation.samplers.find("baseTex");
    8085
     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
    8194        // Decals should be transparent, so clamp to the border (default 0,0,0,0)
    8295        textureProps.SetWrap(GL_CLAMP_TO_BORDER);
    8396
     
    121134    model->SetMaterial(g_Renderer.GetMaterialManager().LoadMaterial(m_Base->m_Material));
    122135    model->GetMaterial().AddStaticUniform("objectColor", CVector4D(m_Color.r, m_Color.g, m_Color.b, m_Color.a));
    123136    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    }
    124150
    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 texture
    129     model->GetMaterial().SetDiffuseTexture(texture);
    130 
    131151    // calculate initial object space bounds, based on vertex positions
    132152    model->CalcStaticObjectBounds();
    133153
  • source/renderer/RenderModifiers.h

     
    6363    virtual void BeginPass(const CShaderProgramPtr& shader) = 0;
    6464
    6565    /**
    66      * PrepareTexture: Called before rendering models that use the given
    67      * 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 models
    73      */
    74     virtual void PrepareTexture(const CShaderProgramPtr& shader, CTexture& texture) = 0;
    75 
    76     /**
    7766     * PrepareModel: Called before rendering the given model.
    7867     *
    7968     * Default behaviour does nothing.
     
    133122
    134123    // Implementation
    135124    void BeginPass(const CShaderProgramPtr& shader);
    136     void PrepareTexture(const CShaderProgramPtr& shader, CTexture& texture);
    137125    void PrepareModel(const CShaderProgramPtr& shader, CModel* model);
    138126
    139127private:
    140128    CShaderProgram::Binding m_BindingInstancingTransform;
    141129    CShaderProgram::Binding m_BindingShadingColor;
    142130    CShaderProgram::Binding m_BindingPlayerColor;
    143     CShaderProgram::Binding m_BindingBaseTex;
    144131};
    145132
    146133#endif // INCLUDED_RENDERMODIFIERS
  • source/renderer/ModelRenderer.cpp

     
    2626
    2727#include "graphics/Color.h"
    2828#include "graphics/LightEnv.h"
     29#include "graphics/Material.h"
    2930#include "graphics/Model.h"
    3031#include "graphics/ModelDef.h"
    3132#include "graphics/ShaderManager.h"
     
    467468            else
    468469            {
    469470                // 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.
    470474                std::sort(it->second.begin(), it->second.end(), SMRBatchModel());
    471475
    472476                // Add a tech bucket pointing at this model list
     
    531535        PROFILE3("rendering bucketed submissions");
    532536
    533537        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);
    534552
    535553        while (idxTechStart < techBuckets.size())
    536554        {
     
    555573                modifier->BeginPass(shader);
    556574
    557575                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               
    560584                CModelDef* currentModeldef = NULL;
    561585                CShaderUniforms currentStaticUniforms;
    562                 // (Texture needs to be rebound after binding a new shader, so we
    563                 // can't move currentTex outside of this loop to reduce state changes)
    564586
    565587                for (size_t idx = idxTechStart; idx < idxTechEnd; ++idx)
    566588                {
     
    573595                        if (flags && !(model->GetFlags() & flags))
    574596                            continue;
    575597
    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)
    579604                        {
    580                             currentTex = newTex;
    581                             modifier->PrepareTexture(shader, *currentTex);
     605                            currentTexs.resize(samplersNum, NULL);
     606                            texBindings.resize(samplersNum, CShaderProgram::Binding());
     607                            texBindingNames.resize(samplersNum, CStrIntern());
    582608                        }
     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                            }
    583628
     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
    584638                        // Bind modeldef when it changes
    585639                        CModelDef* newModeldef = model->GetModelDef().get();
    586640                        if (newModeldef != currentModeldef)
  • source/renderer/RenderModifiers.cpp

     
    103103    m_BindingInstancingTransform = shader->GetUniformBinding("instancingTransform");
    104104    m_BindingShadingColor = shader->GetUniformBinding("shadingColor");
    105105    m_BindingPlayerColor = shader->GetUniformBinding("playerColor");
    106     m_BindingBaseTex = shader->GetTextureBinding("baseTex");
    107106}
    108107
    109 void ShaderRenderModifier::PrepareTexture(const CShaderProgramPtr& shader, CTexture& texture)
    110 {
    111     if (m_BindingBaseTex.Active())
    112         shader->BindTexture(m_BindingBaseTex, texture.GetHandle());
    113 }
    114 
    115108void ShaderRenderModifier::PrepareModel(const CShaderProgramPtr& shader, CModel* model)
    116109{
    117110    if (m_BindingInstancingTransform.Active())