1 #include "DrawSprite.h"
10 #include "bgfxUtils.h"
12 static bool screenSpaceIsTopDown =
true;
17 struct PosColorTexcoordVertex
27 .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
28 .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8,
true)
29 .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
33 static bgfx::VertexDecl ms_decl;
38 bgfx::VertexDecl PosColorTexcoordVertex::ms_decl;
50 constexpr uint32_t abgrBlack = 0xFF000000;
51 constexpr uint32_t abgrWhite = 0xFFFFFFFF;
52 constexpr uint32_t abgrRed = 0x000000FF;
53 constexpr uint32_t abgrGreen = 0x0000FF00;
54 constexpr uint32_t abgrBlue = 0xFFFF0000;
56 static const uint16_t s_quadTriList[] = {
61 static const uint16_t s_quadTriStrip[] = {
68 bgfx::TextureHandle spriteTexture = BGFX_INVALID_HANDLE;
69 bgfx::VertexBufferHandle vertexBuffer = BGFX_INVALID_HANDLE;
74 bgfx::IndexBufferHandle m_quadIndexBuf = BGFX_INVALID_HANDLE;
75 bgfx::ProgramHandle m_program = BGFX_INVALID_HANDLE;
76 bgfx::UniformHandle m_texColor = BGFX_INVALID_HANDLE;
77 bgfx::UniformHandle m_palColor = BGFX_INVALID_HANDLE;
78 bgfx::TextureHandle m_paletteColor = BGFX_INVALID_HANDLE;
82 static bgfx::VertexBufferHandle
85 const bgfx::Memory* quadMemory = bgfx::alloc(4 *
sizeof(PosColorTexcoordVertex));
89 PosColorTexcoordVertex* quadPtr = (PosColorTexcoordVertex*)(
void*)quadMemory->data;
92 const float lastColumn = float(frame.width);
93 const float lastRow = float(frame.height);
95 const float fOffsetX = float(frame.offsetX);
96 const float fOffsetY = float(frame.offsetY);
97 const float lastColumnOffset = fOffsetX + lastColumn;
98 const float lastRowOffset = fOffsetY + lastRow;
99 const bool topDown =
true;
100 if (topDown == screenSpaceIsTopDown) {
101 quadPtr[0] = {{fOffsetX, fOffsetY, 0.f}, abgrBlack, 0.f, 0.f};
102 quadPtr[1] = {{fOffsetX, lastRowOffset, 0.f}, abgrGreen, 0.f, lastRow};
103 quadPtr[2] = {{lastColumnOffset, fOffsetY, 0.f}, abgrRed, lastColumn, 0.f};
104 quadPtr[3] = {{lastColumnOffset, lastRowOffset, 0.f}, abgrWhite, lastColumn, lastRow};
108 quadPtr[0] = {{fOffsetX, lastRowOffset, 0.f}, abgrGreen, 0.f, 0.f};
109 quadPtr[1] = {{fOffsetX, fOffsetY, 0.f}, abgrBlack, 0.f, lastRow};
110 quadPtr[2] = {{lastColumnOffset, lastRowOffset, 0.f}, abgrWhite, lastColumn, 0.f};
111 quadPtr[3] = {{lastColumnOffset, fOffsetY, 0.f}, abgrRed, lastColumn, lastRow};
115 return bgfx::createVertexBuffer(quadMemory, PosColorTexcoordVertex::ms_decl);
120 bgfx::TextureHandle spriteTexture = BGFX_INVALID_HANDLE;
121 uint32_t flagsSprite = BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT;
122 spriteTexture = bgfx::createTexture2D(
123 frame.width, frame.height,
false, 1, bgfx::TextureFormat::R8U, flagsSprite,
124 bgfx::copy(frame.data, uint32_t(frame.width) * uint32_t(frame.height)));
125 if (bgfx::isValid(spriteTexture)) bgfx::setName(spriteTexture,
"SpriteTexture");
126 return spriteTexture;
132 renderData.spriteTexture = createTextureFromSprite(frame);
133 renderData.vertexBuffer = createVertexBufferFromSpriteFrame(frame);
138 bgfx::destroy(frameRenderData.vertexBuffer);
139 bgfx::destroy(frameRenderData.spriteTexture);
142 void SpriteRenderer::SpriteRenderData::addSpriteFrame(
const Frame& frame)
144 framesData.push_back(createFrameRenderData(frame));
146 SpriteRenderer::SpriteRenderData::~SpriteRenderData()
149 destroy(frameRenderData);
154 data = std::make_unique<SpriteRendererData>();
156 BX_UNUSED(s_quadTriList, s_quadTriStrip);
157 BX_UNUSED(abgrBlack, abgrWhite, abgrRed, abgrGreen, abgrBlue);
159 PosColorTexcoordVertex::init();
162 data->m_quadIndexBuf = bgfx::createIndexBuffer(
164 bgfx::makeRef(s_quadTriStrip,
sizeof(s_quadTriStrip)));
167 data->m_texColor = bgfx::createUniform(
"s_texColor", bgfx::UniformType::Int1);
168 data->m_palColor = bgfx::createUniform(
"s_palColor", bgfx::UniformType::Int1);
173 data->m_program = loadProgram(
"vs_sprite",
"fs_sprite");
174 data->m_timeOffset = bx::getHPCounter();
177 int SpriteRenderer::shutdown()
179 spritesToRender.clear();
183 bgfx::destroy(data->m_paletteColor);
184 bgfx::destroy(data->m_palColor);
185 bgfx::destroy(data->m_texColor);
186 bgfx::destroy(data->m_program);
187 bgfx::destroy(data->m_quadIndexBuf);
195 if (bgfx::isValid(data->m_paletteColor)) bgfx::destroy(data->m_paletteColor);
198 static_assert(
sizeof(Palette::Color24Bits) == 3,
"");
199 auto paletteRGB888 = bgfx::alloc(
sizeof(Palette::Color24Bits) * Palette::colorCount);
200 for (
size_t i = 0; i < Palette::colorCount; i++)
205 data->m_paletteColor =
206 bgfx::createTexture2D(Palette::colorCount, 1,
false, 1, bgfx::TextureFormat::RGB8,
207 BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT, paletteRGB888);
208 bgfx::setName(data->m_paletteColor,
"SpritePalette");
211 SpriteRenderer::SpriteRenderDataHandle SpriteRenderer::createSpriteRenderData()
213 spritesData.push_back(std::make_shared<SpriteRenderData>());
214 return spritesData.back();
217 void SpriteRenderer::destroySpriteRenderData(SpriteRenderDataHandle renderDataHandle)
219 SpriteRenderData* renderDataPtr = renderDataHandle.lock().get();
220 assert(renderDataPtr !=
nullptr);
221 for (
auto& ptr : spritesData)
223 if (ptr.get() == renderDataPtr) {
224 assert(ptr.unique());
231 void SpriteRenderer::recycleSpritesData()
236 if (spritesData.size() > 20) {
237 spritesData.erase(std::remove_if(spritesData.begin(), spritesData.end(),
238 [](
const std::shared_ptr<SpriteRenderData>& ptr) {
239 return ptr ==
nullptr || ptr.unique();
245 void SpriteRenderer::pushDrawRequest(SpriteRenderDataHandle spriteHandle,
246 const DrawRequest& drawRequest)
248 auto spritePtr = spriteHandle.lock();
249 assert(spritePtr !=
nullptr);
250 spritesToRender.emplace_back(std::make_pair(std::move(spritePtr), drawRequest));
256 bgfx::setVertexBuffer(0, renderData.vertexBuffer);
257 bgfx::setIndexBuffer(data->m_quadIndexBuf);
260 bgfx::setTexture(0, data->m_texColor, renderData.spriteTexture);
261 bgfx::setTexture(1, data->m_palColor, data->m_paletteColor);
265 bgfx::setState(0 | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_CULL_CW
266 | BGFX_STATE_PT_TRISTRIP);
269 bgfx::submit(0, data->m_program);
272 bool SpriteRenderer::draw(
int screenWidth,
int screenHeight)
274 float at[3] = {0.f, 0.f, 0.f};
275 float eye[3] = {0.f, 0.f, -35.0f};
279 bx::mtxLookAtRh(view, eye, at);
282 if (screenSpaceIsTopDown) {
299 bx::mtxOrtho(proj, 0.f,
float(screenWidth),
float(screenHeight), 0.f, -1000.f, 1000.f, 0.f,
300 bgfx::getCaps()->homogeneousDepth);
317 bx::mtxOrtho(proj, 0.f,
float(screenWidth), 0.f,
float(screenHeight), 1000.f, -1000.f, 0.f,
318 bgfx::getCaps()->homogeneousDepth);
321 bgfx::setViewTransform(0,
nullptr, proj);
324 bgfx::setViewRect(0, 0, 0, uint16_t(screenWidth), uint16_t(screenHeight));
331 static size_t i = size_t(-1);
332 for (
const auto& spriteData : spritesToRender)
335 i %= (spriteData.first->framesData.size() * 10);
336 const DrawRequest& drawRequest = spriteData.second;
337 const FrameRenderData& renderData = spriteData.first->framesData[drawRequest.frame];
338 const float scale = drawRequest.scale;
342 bx::mtxIdentity(mtx);
343 bx::mtxScale(mtx, scale);
345 const auto& translation = drawRequest.translation;
346 mtx[12] = translation.x;
347 mtx[13] = translation.y;
350 bgfx::setTransform(&mtx);
352 drawFrame(renderData);
355 spritesToRender.clear();
356 recycleSpritesData();
360 SpriteRenderer::SpriteRenderer() {}
361 SpriteRenderer::~SpriteRenderer() {}
Helper to load a Diablo 2 palette (.pal/.dat format)