1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "2D/BsSprite.h"
4#include "Material/BsMaterial.h"
5#include "Image/BsTexture.h"
6#include "Mesh/BsMesh.h"
7#include "Material/BsShader.h"
8#include "Renderer/BsRendererUtility.h"
9#include "Material/BsGpuParamsSet.h"
10#include "CoreThread/BsCoreThread.h"
11
12namespace bs
13{
14 SpriteMaterial::SpriteMaterial(UINT32 id, const HMaterial& material, const ShaderVariation& variation,
15 bool allowBatching)
16 :mId(id), mAllowBatching(allowBatching), mMaterialStored(false), mParamBufferIdx(-1)
17 {
18 mMaterial = material->getCore();
19
20 FIND_TECHNIQUE_DESC findTechniqueDesc;
21 findTechniqueDesc.variation = &variation;
22
23 mTechnique = mMaterial->findTechnique(findTechniqueDesc);
24 mMaterialStored.store(true, std::memory_order_release);
25
26 gCoreThread().queueCommand(std::bind(&SpriteMaterial::initialize, this));
27 }
28
29 SpriteMaterial::~SpriteMaterial()
30 {
31 gCoreThread().queueCommand(std::bind(&SpriteMaterial::destroy, mMaterial, mParams));
32 }
33
34 void SpriteMaterial::initialize()
35 {
36 // Make sure that mMaterial assignment completes on the previous thread before continuing
37 const bool materialStored = mMaterialStored.load(std::memory_order_acquire);
38 assert(materialStored == true);
39
40 const SPtr<ct::Pass>& pass = mMaterial->getPass(0, mTechnique);
41
42 if(pass)
43 pass->compile();
44
45 mParams = mMaterial->createParamsSet(mTechnique);
46
47 SPtr<ct::Shader> shader = mMaterial->getShader();
48 if(shader->hasTextureParam("gMainTexture"))
49 {
50 mTextureParam = mMaterial->getParamTexture("gMainTexture");
51 mSamplerParam = mMaterial->getParamSamplerState("gMainTexSamp");
52 }
53
54 mParamBufferIdx = mParams->getParamBlockBufferIndex("GUIParams");
55
56 if(mParamBufferIdx == (UINT32)-1)
57 LOGERR("Sprite material shader missing \"GUIParams\" block.");
58 }
59
60 void SpriteMaterial::destroy(const SPtr<ct::Material>& material, const SPtr<ct::GpuParamsSet>& params)
61 {
62 // Do nothing, we just need to make sure the material pointer's last reference is lost while on the core thread
63 }
64
65 UINT64 SpriteMaterial::getMergeHash(const SpriteMaterialInfo& info) const
66 {
67 UINT64 textureId = 0;
68 if (info.texture.isLoaded())
69 textureId = info.texture->getInternalID();
70
71 size_t hash = 0;
72 bs_hash_combine(hash, info.groupId);
73 bs_hash_combine(hash, getId());
74 bs_hash_combine(hash, textureId);
75 bs_hash_combine(hash, info.tint);
76
77 return (UINT64)hash;
78 }
79
80 void SpriteMaterial::render(const SPtr<ct::MeshBase>& mesh, const SubMesh& subMesh, const SPtr<ct::Texture>& texture,
81 const SPtr<ct::SamplerState>& sampler, const SPtr<ct::GpuParamBlockBuffer>& paramBuffer,
82 const SPtr<SpriteMaterialExtraInfo>& additionalData) const
83 {
84 SPtr<ct::Texture> spriteTexture;
85 if (texture != nullptr)
86 spriteTexture = texture;
87 else
88 spriteTexture = ct::Texture::WHITE;
89
90 mTextureParam.set(spriteTexture);
91 mSamplerParam.set(sampler);
92
93 if(mParamBufferIdx != (UINT32)-1)
94 mParams->setParamBlockBuffer(mParamBufferIdx, paramBuffer, true);
95
96 mMaterial->updateParamsSet(mParams);
97
98 ct::gRendererUtility().setPass(mMaterial, 0, mTechnique);
99 ct::gRendererUtility().setPassParams(mParams);
100 ct::gRendererUtility().draw(mesh, subMesh);
101 }
102}