RenderPrimitive micro-optimizations

This commit is contained in:
Kae 2023-06-30 04:34:10 +10:00
parent 47a527ebbf
commit d5fbd2001b
14 changed files with 307 additions and 197 deletions

View File

@ -12,49 +12,78 @@ EnumMap<TextureFiltering> const TextureFilteringNames{
{TextureFiltering::Linear, "Linear"} {TextureFiltering::Linear, "Linear"}
}; };
RenderQuad renderTexturedRect(TexturePtr texture, Vec2F minPosition, float textureScale, Vec4B color, float param1) { RenderQuad::RenderQuad(Vec2F posA, Vec2F posB, Vec2F posC, Vec2F posD, Vec4B color, float param1) : texture() {
if (!texture) a = { posA, { 0, 0 }, color, param1 };
throw RendererException("renderTexturedRect called with null texture"); b = { posB, { 0, 0 }, color, param1 };
c = { posC, { 0, 0 }, color, param1 };
d = { posD, { 0, 0 }, color, param1 };
}
auto textureSize = Vec2F(texture->size()); RenderQuad::RenderQuad(TexturePtr tex, Vec2F minPosition, float textureScale, Vec4B color, float param1) : texture(move(tex)) {
return { Vec2F size = Vec2F(texture->size());
move(texture), a = { minPosition, { 0, 0 }, color, param1};
RenderVertex{minPosition, Vec2F(0, 0), color, param1}, b = { { (minPosition[0] + size[0] * textureScale), minPosition[1] }, { size[0], 0 }, color, param1 };
RenderVertex{minPosition + Vec2F(textureSize[0], 0) * textureScale, Vec2F(textureSize[0], 0), color, param1}, c = { { (minPosition[0] + size[0] * textureScale), (minPosition[1] + size[1] * textureScale) }, size, color, param1 };
RenderVertex{minPosition + Vec2F(textureSize[0], textureSize[1]) * textureScale, Vec2F(textureSize[0], textureSize[1]), color, param1}, d = { { minPosition[0], (minPosition[1] + size[1] * textureScale) }, { 0, size[1] }, color, param1 };
RenderVertex{minPosition + Vec2F(0, textureSize[1]) * textureScale, Vec2F(0, textureSize[1]), color, param1} }
};
RenderQuad::RenderQuad(TexturePtr tex, RectF const& screenCoords, Vec4B color, float param1) : texture(move(tex)) {
Vec2F size = Vec2F(texture->size());
a = { screenCoords.min(), { 0, 0 }, color, param1 };
b = { { screenCoords.xMax(), screenCoords.yMin(), }, { size[0], 0.f }, color, param1 };
c = { screenCoords.max(), size, color, param1};
d = { { screenCoords.xMin(), screenCoords.yMax(), }, { 0.f, size[1] }, color, param1 };
}
RenderQuad::RenderQuad(TexturePtr tex, Vec2F posA, Vec2F uvA, Vec2F posB, Vec2F uvB, Vec2F posC, Vec2F uvC, Vec2F posD, Vec2F uvD, Vec4B color, float param1) : texture(move(tex)) {
a = { posA, uvA, color, param1 };
b = { posB, uvB, color, param1 };
c = { posC, uvC, color, param1 };
d = { posD, uvD, color, param1 };
}
RenderQuad::RenderQuad(TexturePtr tex, RenderVertex vA, RenderVertex vB, RenderVertex vC, RenderVertex vD)
: texture(move(tex)), a(move(vA)), b(move(vB)), c(move(vC)), d(move(vD)) {}
RenderQuad::RenderQuad(RectF const& rect, Vec4B color, float param1)
: a{ rect.min(), {}, color, param1 }
, b{ { rect.xMax(), rect.yMin()}, {}, color, param1 }
, c{ rect.max(), {}, color, param1 }
, d{ { rect.xMin() ,rect.yMax() }, {}, color, param1 } {};
RenderPoly::RenderPoly(List<Vec2F> const& verts, Vec4B color, float param1) {
vertexes.reserve(verts.size());
for (Vec2F const& v : verts)
vertexes.append({ v, { 0, 0 }, color, param1 });
}
RenderTriangle::RenderTriangle(Vec2F posA, Vec2F posB, Vec2F posC, Vec4B color, float param1) : texture() {
a = { posA, { 0, 0 }, color, param1 };
b = { posB, { 0, 0 }, color, param1 };
c = { posC, { 0, 0 }, color, param1 };
}
RenderTriangle::RenderTriangle(TexturePtr tex, Vec2F posA, Vec2F uvA, Vec2F posB, Vec2F uvB, Vec2F posC, Vec2F uvC, Vec4B color, float param1) : texture(move(tex)) {
a = { posA, uvA, color, param1 };
b = { posB, uvB, color, param1 };
c = { posC, uvC, color, param1 };
}
RenderQuad renderTexturedRect(TexturePtr texture, Vec2F minPosition, float textureScale, Vec4B color, float param1) {
return RenderQuad(move(texture), minPosition, textureScale, color, param1);
} }
RenderQuad renderTexturedRect(TexturePtr texture, RectF const& screenCoords, Vec4B color, float param1) { RenderQuad renderTexturedRect(TexturePtr texture, RectF const& screenCoords, Vec4B color, float param1) {
if (!texture) return RenderQuad(move(texture), screenCoords, color, param1);
throw RendererException("renderTexturedRect called with null texture");
auto textureSize = Vec2F(texture->size());
return {
move(texture),
RenderVertex{{screenCoords.xMin(), screenCoords.yMin()}, Vec2F(0, 0), color, param1},
RenderVertex{{screenCoords.xMax(), screenCoords.yMin()}, Vec2F(textureSize[0], 0), color, param1},
RenderVertex{{screenCoords.xMax(), screenCoords.yMax()}, Vec2F(textureSize[0], textureSize[1]), color, param1},
RenderVertex{{screenCoords.xMin(), screenCoords.yMax()}, Vec2F(0, textureSize[1]), color, param1}
};
} }
RenderQuad renderFlatRect(RectF const& rect, Vec4B color, float param1) { RenderQuad renderFlatRect(RectF const& rect, Vec4B color, float param1) {
return { return RenderQuad(rect, color, param1);
{},
RenderVertex{{rect.xMin(), rect.yMin()}, {}, color, param1},
RenderVertex{{rect.xMax(), rect.yMin()}, {}, color, param1},
RenderVertex{{rect.xMax(), rect.yMax()}, {}, color, param1},
RenderVertex{{rect.xMin(), rect.yMax()}, {}, color, param1}
};
} }
RenderPoly renderFlatPoly(PolyF const& poly, Vec4B color, float param1) { RenderPoly renderFlatPoly(PolyF const& poly, Vec4B color, float param1) {
RenderPoly renderPoly; return RenderPoly(poly.vertexes(), color, param1);
for (auto const& v : poly)
renderPoly.vertexes.append({v, {}, color, param1});
return renderPoly;
} }
} }

View File

@ -50,17 +50,35 @@ struct RenderVertex {
float param1; float param1;
}; };
struct RenderTriangle { class RenderTriangle {
public:
RenderTriangle() = default;
RenderTriangle(Vec2F posA, Vec2F posB, Vec2F posC, Vec4B color = Vec4B::filled(255), float param1 = 0.0f);
RenderTriangle(TexturePtr tex, Vec2F posA, Vec2F uvA, Vec2F posB, Vec2F uvB, Vec2F posC, Vec2F uvC, Vec4B color = Vec4B::filled(255), float param1 = 0.0f);
TexturePtr texture; TexturePtr texture;
RenderVertex a, b, c; RenderVertex a, b, c;
}; };
struct RenderQuad { class RenderQuad {
public:
RenderQuad() = default;
RenderQuad(Vec2F posA, Vec2F posB, Vec2F posC, Vec2F posD, Vec4B color = Vec4B::filled(255), float param1 = 0.0f);
RenderQuad(TexturePtr tex, Vec2F minScreen, float textureScale = 1.0f, Vec4B color = Vec4B::filled(255), float param1 = 0.0f);
RenderQuad(TexturePtr tex, RectF const& screenCoords, Vec4B color = Vec4B::filled(255), float param1 = 0.0f);
RenderQuad(TexturePtr tex, Vec2F posA, Vec2F uvA, Vec2F posB, Vec2F uvB, Vec2F posC, Vec2F uvC, Vec2F posD, Vec2F uvD, Vec4B color = Vec4B::filled(255), float param1 = 0.0f);
RenderQuad(TexturePtr tex, RenderVertex vA, RenderVertex vB, RenderVertex vC, RenderVertex vD);
RenderQuad(RectF const& rect, Vec4B color = Vec4B::filled(255), float param1 = 0.0f);
TexturePtr texture; TexturePtr texture;
RenderVertex a, b, c, d; RenderVertex a, b, c, d;
}; };
struct RenderPoly { class RenderPoly {
public:
RenderPoly() = default;
RenderPoly(List<Vec2F> const& verts, Vec4B color, float param1 = 0.0f);
TexturePtr texture; TexturePtr texture;
List<RenderVertex> vertexes; List<RenderVertex> vertexes;
}; };
@ -100,7 +118,7 @@ public:
// Transforms the given primitives into a form suitable for the underlying // Transforms the given primitives into a form suitable for the underlying
// graphics system and stores it for fast replaying. // graphics system and stores it for fast replaying.
virtual void set(List<RenderPrimitive> primitives) = 0; virtual void set(List<RenderPrimitive>& primitives) = 0;
}; };
typedef Variant<bool, int, float, Vec2F, Vec3F, Vec4F> RenderEffectParameter; typedef Variant<bool, int, float, Vec2F, Vec3F, Vec4F> RenderEffectParameter;
@ -136,6 +154,7 @@ public:
virtual TextureGroupPtr createTextureGroup(TextureGroupSize size = TextureGroupSize::Medium, TextureFiltering filtering = TextureFiltering::Nearest) = 0; virtual TextureGroupPtr createTextureGroup(TextureGroupSize size = TextureGroupSize::Medium, TextureFiltering filtering = TextureFiltering::Nearest) = 0;
virtual RenderBufferPtr createRenderBuffer() = 0; virtual RenderBufferPtr createRenderBuffer() = 0;
virtual List<RenderPrimitive>& immediatePrimitives() = 0;
virtual void render(RenderPrimitive primitive) = 0; virtual void render(RenderPrimitive primitive) = 0;
virtual void renderBuffer(RenderBufferPtr const& renderBuffer, Mat3F const& transformation = Mat3F::identity()) = 0; virtual void renderBuffer(RenderBufferPtr const& renderBuffer, Mat3F const& transformation = Mat3F::identity()) = 0;

View File

@ -366,6 +366,10 @@ RenderBufferPtr OpenGl20Renderer::createRenderBuffer() {
return createGlRenderBuffer(); return createGlRenderBuffer();
} }
List<RenderPrimitive>& OpenGl20Renderer::immediatePrimitives() {
return m_immediatePrimitives;
}
void OpenGl20Renderer::render(RenderPrimitive primitive) { void OpenGl20Renderer::render(RenderPrimitive primitive) {
m_immediatePrimitives.append(move(primitive)); m_immediatePrimitives.append(move(primitive));
} }
@ -399,7 +403,8 @@ void OpenGl20Renderer::finishFrame() {
flushImmediatePrimitives(); flushImmediatePrimitives();
// Make sure that the immediate render buffer doesn't needlessly lock texutres // Make sure that the immediate render buffer doesn't needlessly lock texutres
// from being compressed. // from being compressed.
m_immediateRenderBuffer->set({}); List<RenderPrimitive> empty;
m_immediateRenderBuffer->set(empty);
filter(m_liveTextureGroups, [](auto const& p) { filter(m_liveTextureGroups, [](auto const& p) {
unsigned const CompressionsPerFrame = 1; unsigned const CompressionsPerFrame = 1;
@ -569,7 +574,7 @@ OpenGl20Renderer::GlRenderBuffer::~GlRenderBuffer() {
glDeleteBuffers(1, &vb.vertexBuffer); glDeleteBuffers(1, &vb.vertexBuffer);
} }
void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive> primitives) { void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive>& primitives) {
for (auto const& texture : usedTextures) { for (auto const& texture : usedTextures) {
if (auto gt = as<GlGroupedTexture>(texture.get())) if (auto gt = as<GlGroupedTexture>(texture.get()))
gt->decrementBufferUseCount(); gt->decrementBufferUseCount();
@ -637,7 +642,7 @@ void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive> primitives) {
return {float(textureIndex), Vec2F(glTexture->glTextureCoordinateOffset())}; return {float(textureIndex), Vec2F(glTexture->glTextureCoordinateOffset())};
}; };
auto appendBufferVertex = [&](RenderVertex v, float textureIndex, Vec2F textureCoordinateOffset) { auto appendBufferVertex = [&](RenderVertex const& v, float textureIndex, Vec2F textureCoordinateOffset) {
GlRenderVertex glv { GlRenderVertex glv {
v.screenCoordinate, v.screenCoordinate,
v.textureCoordinate + textureCoordinateOffset, v.textureCoordinate + textureCoordinateOffset,
@ -682,6 +687,7 @@ void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive> primitives) {
} }
} }
vertexBuffers.reserve(primitives.size() * 6);
finishCurrentBuffer(); finishCurrentBuffer();
for (auto const& vb : oldVertexBuffers) for (auto const& vb : oldVertexBuffers)
@ -733,7 +739,8 @@ void OpenGl20Renderer::flushImmediatePrimitives() {
if (m_immediatePrimitives.empty()) if (m_immediatePrimitives.empty())
return; return;
m_immediateRenderBuffer->set(take(m_immediatePrimitives)); m_immediateRenderBuffer->set(m_immediatePrimitives);
m_immediatePrimitives.resize(0);
renderGlBuffer(*m_immediateRenderBuffer, Mat3F::identity()); renderGlBuffer(*m_immediateRenderBuffer, Mat3F::identity());
} }

View File

@ -32,6 +32,7 @@ public:
TextureGroupPtr createTextureGroup(TextureGroupSize size, TextureFiltering filtering) override; TextureGroupPtr createTextureGroup(TextureGroupSize size, TextureFiltering filtering) override;
RenderBufferPtr createRenderBuffer() override; RenderBufferPtr createRenderBuffer() override;
List<RenderPrimitive>& immediatePrimitives() override;
void render(RenderPrimitive primitive) override; void render(RenderPrimitive primitive) override;
void renderBuffer(RenderBufferPtr const& renderBuffer, Mat3F const& transformation) override; void renderBuffer(RenderBufferPtr const& renderBuffer, Mat3F const& transformation) override;
@ -128,7 +129,7 @@ private:
~GlRenderBuffer(); ~GlRenderBuffer();
void set(List<RenderPrimitive> primitives) override; void set(List<RenderPrimitive>& primitives) override;
RefPtr<GlTexture> whiteTexture; RefPtr<GlTexture> whiteTexture;
ByteArray accumulationBuffer; ByteArray accumulationBuffer;

View File

@ -3,6 +3,7 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <initializer_list>
#include "StarAlgorithm.hpp" #include "StarAlgorithm.hpp"
#include "StarMaybe.hpp" #include "StarMaybe.hpp"
@ -70,6 +71,22 @@ public:
template <typename T, typename = ValidateType<T>> template <typename T, typename = ValidateType<T>>
Variant(T&& x); Variant(T&& x);
template <typename T, typename = ValidateType<T>, typename... Args,
typename std::enable_if< std::is_constructible<T, Args...>::value, int >::type = 0
>
Variant(std::in_place_type_t<T>, Args&&... args) {
new (&m_buffer) T(forward<Args>(args)...);
m_typeIndex = TypeIndex<T>::value;
}
template <typename T, typename U, typename = ValidateType<T>, typename... Args,
typename std::enable_if< std::is_constructible<T, std::initializer_list<U>&, Args...>::value, int >::type = 0
>
Variant(std::in_place_type_t<T>, std::initializer_list<U> il, Args&&... args) {
new (&m_buffer) T(il, forward<Args>(args)...);
m_typeIndex = TypeIndex<T>::value;
}
Variant(Variant const& x); Variant(Variant const& x);
Variant(Variant&& x) noexcept(detail::IsNothrowMoveConstructible<FirstType, RestTypes...>::value); Variant(Variant&& x) noexcept(detail::IsNothrowMoveConstructible<FirstType, RestTypes...>::value);

View File

@ -245,15 +245,17 @@ void Cinematic::render() {
void Cinematic::drawDrawable(Drawable const& drawable, float drawableScale, Vec2F const& drawableTranslation) { void Cinematic::drawDrawable(Drawable const& drawable, float drawableScale, Vec2F const& drawableTranslation) {
auto& guiContext = GuiContext::singleton(); auto& guiContext = GuiContext::singleton();
auto renderer = guiContext.renderer(); auto& renderer = guiContext.renderer();
auto textureGroup = guiContext.assetTextureGroup(); auto& textureGroup = guiContext.assetTextureGroup();
auto& primitives = renderer->immediatePrimitives();
if (drawable.isImage()) { if (drawable.isImage()) {
auto const& imagePart = drawable.imagePart(); auto const& imagePart = drawable.imagePart();
auto texture = textureGroup->loadTexture(imagePart.image); auto texture = textureGroup->loadTexture(imagePart.image);
auto textureSize = Vec2F(texture->size()); auto size = Vec2F(texture->size());
RectF imageRect(Vec2F(), textureSize); RectF imageRect(Vec2F(), size);
Vec2F screenTranslation = drawable.position * drawableScale + drawableTranslation; Vec2F screenTranslation = drawable.position * drawableScale + drawableTranslation;
@ -272,11 +274,12 @@ void Cinematic::drawDrawable(Drawable const& drawable, float drawableScale, Vec2
Vec4B drawableColor = drawable.color.toRgba(); Vec4B drawableColor = drawable.color.toRgba();
renderer->render(RenderQuad{move(texture), primitives.emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
RenderVertex{lowerLeft, Vec2F(0, 0), drawableColor, 0.0f}, lowerLeft, Vec2F{0, 0},
RenderVertex{lowerRight, Vec2F(textureSize[0], 0), drawableColor, 0.0f}, lowerRight, Vec2F{size[0], 0},
RenderVertex{upperRight, Vec2F(textureSize[0], textureSize[1]), drawableColor, 0.0f}, upperRight, Vec2F{size[0], size[1]},
RenderVertex{upperLeft, Vec2F(0, textureSize[1]), drawableColor, 0.0f}}); upperLeft, Vec2F{0, size[1]},
drawableColor, 0.0f);
} else { } else {
starAssert(drawable.part.empty()); starAssert(drawable.part.empty());
} }

View File

@ -384,32 +384,8 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) {
} else { } else {
m_lightingCalculator.begin(lightRange); m_lightingCalculator.begin(lightRange);
Vec3F environmentLight = m_sky->environmentLight().toRgbF(); if (!m_asyncLighting)
float undergroundLevel = m_worldTemplate->undergroundLevel(); lightingTileGather();
auto liquidsDatabase = Root::singleton().liquidsDatabase();
auto materialDatabase = Root::singleton().materialDatabase();
// Each column in tileEvalColumns is guaranteed to be no larger than the sector size.
m_tileArray->tileEvalColumns(m_lightingCalculator.calculationRegion(), [&](Vec2I const& pos, ClientTile const* column, size_t ySize) {
size_t baseIndex = m_lightingCalculator.baseIndexFor(pos);
for (size_t y = 0; y < ySize; ++y) {
auto& tile = column[y];
Vec3F light;
if (tile.foreground != EmptyMaterialId || tile.foregroundMod != NoModId)
light += materialDatabase->radiantLight(tile.foreground, tile.foregroundMod);
if (tile.liquid.liquid != EmptyLiquidId && tile.liquid.level != 0.0f)
light += liquidsDatabase->radiantLight(tile.liquid);
if (tile.foregroundLightTransparent) {
if (tile.background != EmptyMaterialId || tile.backgroundMod != NoModId)
light += materialDatabase->radiantLight(tile.background, tile.backgroundMod);
if (tile.backgroundLightTransparent && pos[1] + y > undergroundLevel)
light += environmentLight;
}
m_lightingCalculator.setCellIndex(baseIndex + y, move(light), !tile.foregroundLightTransparent);
}
});
for (auto const& light : renderLightSources) { for (auto const& light : renderLightSources) {
Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), light.position); Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), light.position);
@ -1439,6 +1415,35 @@ RpcPromise<InteractAction> WorldClient::interact(InteractRequest const& request)
return pair.first; return pair.first;
} }
void WorldClient::lightingTileGather() {
Vec3F environmentLight = m_sky->environmentLight().toRgbF();
float undergroundLevel = m_worldTemplate->undergroundLevel();
auto liquidsDatabase = Root::singleton().liquidsDatabase();
auto materialDatabase = Root::singleton().materialDatabase();
// Each column in tileEvalColumns is guaranteed to be no larger than the sector size.
m_tileArray->tileEvalColumns(m_lightingCalculator.calculationRegion(), [&](Vec2I const& pos, ClientTile const* column, size_t ySize) {
size_t baseIndex = m_lightingCalculator.baseIndexFor(pos);
for (size_t y = 0; y < ySize; ++y) {
auto& tile = column[y];
Vec3F light;
if (tile.foreground != EmptyMaterialId || tile.foregroundMod != NoModId)
light += materialDatabase->radiantLight(tile.foreground, tile.foregroundMod);
if (tile.liquid.liquid != EmptyLiquidId && tile.liquid.level != 0.0f)
light += liquidsDatabase->radiantLight(tile.liquid);
if (tile.foregroundLightTransparent) {
if (tile.background != EmptyMaterialId || tile.backgroundMod != NoModId)
light += materialDatabase->radiantLight(tile.background, tile.backgroundMod);
if (tile.backgroundLightTransparent && pos[1] + y > undergroundLevel)
light += environmentLight;
}
m_lightingCalculator.setCellIndex(baseIndex + y, move(light), !tile.foregroundLightTransparent);
}
});
}
void WorldClient::lightingMain() { void WorldClient::lightingMain() {
while (true) { while (true) {
if (m_stopLightingThread) if (m_stopLightingThread)
@ -1448,6 +1453,9 @@ void WorldClient::lightingMain() {
if (m_renderData) { if (m_renderData) {
int64_t start = Time::monotonicMilliseconds(); int64_t start = Time::monotonicMilliseconds();
lightingTileGather();
m_lightingCalculator.calculate(m_renderData->lightMap); m_lightingCalculator.calculate(m_renderData->lightMap);
m_renderData = nullptr; m_renderData = nullptr;
LogMap::set("render_light_calc", strf("{}ms", Time::monotonicMilliseconds() - start)); LogMap::set("render_light_calc", strf("{}ms", Time::monotonicMilliseconds() - start));

View File

@ -190,6 +190,7 @@ private:
bool operator<(DamageNumberKey const& other) const; bool operator<(DamageNumberKey const& other) const;
}; };
void lightingTileGather();
void lightingMain(); void lightingMain();
void initWorld(WorldStartPacket const& packet); void initWorld(WorldStartPacket const& packet);

View File

@ -9,24 +9,25 @@ DrawablePainter::DrawablePainter(RendererPtr renderer, AssetTextureGroupPtr text
void DrawablePainter::drawDrawable(Drawable const& drawable) { void DrawablePainter::drawDrawable(Drawable const& drawable) {
Vec4B color = drawable.color.toRgba(); Vec4B color = drawable.color.toRgba();
auto& primitives = m_renderer->immediatePrimitives();
if (auto linePart = drawable.part.ptr<Drawable::LinePart>()) { if (auto linePart = drawable.part.ptr<Drawable::LinePart>()) {
auto line = linePart->line; auto line = linePart->line;
line.translate(drawable.position); line.translate(drawable.position);
Vec2F left = Vec2F(vnorm(line.diff())).rot90() * linePart->width / 2.0f; Vec2F left = Vec2F(vnorm(line.diff())).rot90() * linePart->width / 2.0f;
m_renderer->render(RenderQuad{{},
RenderVertex{Vec2F(line.min()) + left, Vec2F(), color, drawable.fullbright ? 0.0f : 1.0f},
RenderVertex{Vec2F(line.min()) - left, Vec2F(), color, drawable.fullbright ? 0.0f : 1.0f},
RenderVertex{Vec2F(line.max()) - left, Vec2F(), color, drawable.fullbright ? 0.0f : 1.0f},
RenderVertex{Vec2F(line.max()) + left, Vec2F(), color, drawable.fullbright ? 0.0f : 1.0f}
});
float fullbright = drawable.fullbright ? 0.0f : 1.0f;
primitives.emplace_back(std::in_place_type_t<RenderQuad>(),
line.min() + left,
line.min() - left,
line.max() - left,
line.max() + left,
color, fullbright);
} else if (auto polyPart = drawable.part.ptr<Drawable::PolyPart>()) { } else if (auto polyPart = drawable.part.ptr<Drawable::PolyPart>()) {
auto poly = polyPart->poly; PolyF poly = polyPart->poly;
poly.translate(drawable.position); poly.translate(drawable.position);
m_renderer->render(renderFlatPoly(poly, color, 0.0f)); primitives.emplace_back(std::in_place_type_t<RenderPoly>(), poly.vertexes(), color, 0.0f);
} else if (auto imagePart = drawable.part.ptr<Drawable::ImagePart>()) { } else if (auto imagePart = drawable.part.ptr<Drawable::ImagePart>()) {
TexturePtr texture = m_textureGroup->loadTexture(imagePart->image); TexturePtr texture = m_textureGroup->loadTexture(imagePart->image);
@ -41,12 +42,14 @@ void DrawablePainter::drawDrawable(Drawable const& drawable) {
Vec2F upperRight = transformation.transformVec2(Vec2F(imageRect.xMax(), imageRect.yMax())); Vec2F upperRight = transformation.transformVec2(Vec2F(imageRect.xMax(), imageRect.yMax()));
Vec2F upperLeft = transformation.transformVec2(Vec2F(imageRect.xMin(), imageRect.yMax())); Vec2F upperLeft = transformation.transformVec2(Vec2F(imageRect.xMin(), imageRect.yMax()));
m_renderer->render(RenderQuad{move(texture), float param1 = drawable.fullbright ? 0.0f : 1.0f;
{lowerLeft, {0, 0}, color, drawable.fullbright ? 0.0f : 1.0f},
{lowerRight, {textureSize[0], 0}, color, drawable.fullbright ? 0.0f : 1.0f}, primitives.emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
{upperRight, {textureSize[0], textureSize[1]}, color, drawable.fullbright ? 0.0f : 1.0f}, lowerLeft, Vec2F{0, 0},
{upperLeft, {0, textureSize[1]}, color, drawable.fullbright ? 0.0f : 1.0f} lowerRight, Vec2F{textureSize[0], 0},
}); upperRight, Vec2F{textureSize[0], textureSize[1]},
upperLeft, Vec2F{0, textureSize[1]},
color, param1);
} }
} }

View File

@ -3,6 +3,8 @@
#include "StarTime.hpp" #include "StarTime.hpp"
#include "StarXXHash.hpp" #include "StarXXHash.hpp"
#include "StarJsonExtra.hpp" #include "StarJsonExtra.hpp"
#include "StarLogging.hpp"
#include "StarMathCommon.hpp"
namespace Star { namespace Star {
@ -80,12 +82,14 @@ void EnvironmentPainter::renderStars(float pixelRatio, Vec2F const& screenSize,
RectF viewRect = RectF::withSize(Vec2F(), viewSize).padded(screenBuffer); RectF viewRect = RectF::withSize(Vec2F(), viewSize).padded(screenBuffer);
auto& primitives = m_renderer->immediatePrimitives();
for (auto& star : stars) { for (auto& star : stars) {
Vec2F screenPos = transform.transformVec2(star.first); Vec2F screenPos = transform.transformVec2(star.first);
if (viewRect.contains(screenPos)) { if (viewRect.contains(screenPos)) {
size_t starFrame = (size_t)(sky.epochTime + star.second.second) % sky.starFrames; size_t starFrame = (size_t)(sky.epochTime + star.second.second) % sky.starFrames;
auto const& texture = m_starTextures[star.second.first * sky.starFrames + starFrame]; auto const& texture = m_starTextures[star.second.first * sky.starFrames + starFrame];
m_renderer->render(renderTexturedRect(texture, screenPos * pixelRatio - Vec2F(texture->size()) / 2, 1.0, color, 0.0f)); primitives.emplace_back(std::in_place_type_t<RenderQuad>(), texture, screenPos * pixelRatio - Vec2F(texture->size()) / 2, 1.0, color, 0.0f);
} }
} }
@ -99,7 +103,6 @@ void EnvironmentPainter::renderDebrisFields(float pixelRatio, Vec2F const& scree
if (sky.type == SkyType::Orbital || sky.type == SkyType::Warp) { if (sky.type == SkyType::Orbital || sky.type == SkyType::Warp) {
Vec2F viewSize = screenSize / pixelRatio; Vec2F viewSize = screenSize / pixelRatio;
Vec2F viewCenter = viewSize / 2; Vec2F viewCenter = viewSize / 2;
Vec2F viewMin = sky.starOffset - viewCenter;
Mat3F rotMatrix = Mat3F::rotation(sky.starRotation, viewCenter); Mat3F rotMatrix = Mat3F::rotation(sky.starRotation, viewCenter);
@ -114,23 +117,29 @@ void EnvironmentPainter::renderDebrisFields(float pixelRatio, Vec2F const& scree
// Translate the entire field to make the debris seem as though they are moving // Translate the entire field to make the debris seem as though they are moving
Vec2F velocityOffset = -Vec2F(debrisXVel, debrisYVel) * sky.epochTime; Vec2F velocityOffset = -Vec2F(debrisXVel, debrisYVel) * sky.epochTime;
float screenBuffer = debrisField.queryFloat("screenBuffer"); JsonArray imageOptions = debrisField.query("list").toArray();
PolyF field = PolyF(RectF::withSize(viewMin, viewSize).padded(screenBuffer).translated(velocityOffset)); Vec2U biggest = Vec2U();
for (Json const& json : imageOptions) {
TexturePtr texture = m_textureGroup->loadTexture(*json.stringPtr());
biggest = biggest.piecewiseMax(texture->size());
}
float screenBuffer = ceil((float)biggest.max() * (float)Constants::sqrt2) * 2.0f;
PolyF field = PolyF(RectF::withSize(sky.starOffset, viewSize).padded(screenBuffer).translated(velocityOffset));
Vec2F debrisAngularVelocityRange = jsonToVec2F(debrisField.query("angularVelocityRange")); Vec2F debrisAngularVelocityRange = jsonToVec2F(debrisField.query("angularVelocityRange"));
JsonArray imageOptions = debrisField.query("list").toArray();
auto debrisItems = m_debrisGenerators[i]->generate(field, auto debrisItems = m_debrisGenerators[i]->generate(field,
[&](RandomSource& rand) { [&](RandomSource& rand) {
String debrisImage = rand.randFrom(imageOptions).toString(); StringView debrisImage = *rand.randFrom(imageOptions).stringPtr();
float debrisAngularVelocity = rand.randf(debrisAngularVelocityRange[0], debrisAngularVelocityRange[1]); float debrisAngularVelocity = rand.randf(debrisAngularVelocityRange[0], debrisAngularVelocityRange[1]);
return pair<String, float>(debrisImage, debrisAngularVelocity); return pair<StringView, float>(debrisImage, debrisAngularVelocity);
}); });
Vec2F debrisPositionOffset = -(sky.starOffset + velocityOffset + viewCenter); Vec2F debrisPositionOffset = -(sky.starOffset + velocityOffset);
for (auto debrisItem : debrisItems) { for (auto& debrisItem : debrisItems) {
Vec2F debrisPosition = rotMatrix.transformVec2(debrisItem.first + debrisPositionOffset); Vec2F debrisPosition = rotMatrix.transformVec2(debrisItem.first + debrisPositionOffset);
float debrisAngle = fmod(Constants::deg2rad * debrisItem.second.second * sky.epochTime, Constants::pi * 2) + sky.starRotation; float debrisAngle = fmod(Constants::deg2rad * debrisItem.second.second * sky.epochTime, Constants::pi * 2) + sky.starRotation;
drawOrbiter(pixelRatio, screenSize, sky, {SkyOrbiterType::SpaceDebris, 1.0f, debrisAngle, debrisItem.second.first, debrisPosition}); drawOrbiter(pixelRatio, screenSize, sky, {SkyOrbiterType::SpaceDebris, 1.0f, debrisAngle, debrisItem.second.first, debrisPosition});
@ -166,6 +175,8 @@ void EnvironmentPainter::renderPlanetHorizon(float pixelRatio, Vec2F const& scre
float planetPixelRatio = pixelRatio * planetHorizon.scale; float planetPixelRatio = pixelRatio * planetHorizon.scale;
Vec2F center = planetHorizon.center * pixelRatio; Vec2F center = planetHorizon.center * pixelRatio;
auto& primitives = m_renderer->immediatePrimitives();
for (auto const& layer : planetHorizon.layers) { for (auto const& layer : planetHorizon.layers) {
TexturePtr leftTexture = m_textureGroup->loadTexture(layer.first); TexturePtr leftTexture = m_textureGroup->loadTexture(layer.first);
Vec2F leftTextureSize(leftTexture->size()); Vec2F leftTextureSize(leftTexture->size());
@ -182,17 +193,17 @@ void EnvironmentPainter::renderPlanetHorizon(float pixelRatio, Vec2F const& scre
PolyF rightImage = PolyF(rightRect); PolyF rightImage = PolyF(rightRect);
rightImage.rotate(planetHorizon.rotation, center); rightImage.rotate(planetHorizon.rotation, center);
m_renderer->render(RenderQuad{move(leftTexture), primitives.emplace_back(std::in_place_type_t<RenderQuad>(), move(leftTexture),
{leftImage[0], Vec2F(0, 0), {255, 255, 255, 255}, 0.0f}, leftImage[0], Vec2F(0, 0),
{leftImage[1], Vec2F(leftTextureSize[0], 0), {255, 255, 255, 255}, 0.0f}, leftImage[1], Vec2F(leftTextureSize[0], 0),
{leftImage[2], Vec2F(leftTextureSize[0], leftTextureSize[1]), {255, 255, 255, 255}, 0.0f}, leftImage[2], Vec2F(leftTextureSize[0], leftTextureSize[1]),
{leftImage[3], Vec2F(0, leftTextureSize[1]), {255, 255, 255, 255}, 0.0f}}); leftImage[3], Vec2F(0, leftTextureSize[1]), Vec4B::filled(255), 0.0f);
m_renderer->render(RenderQuad{move(rightTexture), primitives.emplace_back(std::in_place_type_t<RenderQuad>(), move(rightTexture),
{rightImage[0], Vec2F(0, 0), {255, 255, 255, 255}, 0.0f}, rightImage[0], Vec2F(0, 0),
{rightImage[1], Vec2F(rightTextureSize[0], 0), {255, 255, 255, 255}, 0.0f}, rightImage[1], Vec2F(rightTextureSize[0], 0),
{rightImage[2], Vec2F(rightTextureSize[0], rightTextureSize[1]), {255, 255, 255, 255}, 0.0f}, rightImage[2], Vec2F(rightTextureSize[0], rightTextureSize[1]),
{rightImage[3], Vec2F(0, rightTextureSize[1]), {255, 255, 255, 255}, 0.0f}}); rightImage[3], Vec2F(0, rightTextureSize[1]), Vec4B::filled(255), 0.0f);
} }
m_renderer->flush(); m_renderer->flush();
@ -206,15 +217,16 @@ void EnvironmentPainter::renderFrontOrbiters(float pixelRatio, Vec2F const& scre
} }
void EnvironmentPainter::renderSky(Vec2F const& screenSize, SkyRenderData const& sky) { void EnvironmentPainter::renderSky(Vec2F const& screenSize, SkyRenderData const& sky) {
m_renderer->render(RenderQuad{{}, auto& primitives = m_renderer->immediatePrimitives();
{Vec2F(0, 0), Vec2F(), sky.bottomRectColor.toRgba(), 0.0f}, primitives.emplace_back(std::in_place_type_t<RenderQuad>(), TexturePtr(),
{Vec2F(screenSize[0], 0), Vec2F(), sky.bottomRectColor.toRgba(), 0.0f}, RenderVertex{Vec2F(0, 0), Vec2F(), sky.bottomRectColor.toRgba(), 0.0f},
{screenSize, Vec2F(), sky.topRectColor.toRgba(), 0.0f}, RenderVertex{Vec2F(screenSize[0], 0), Vec2F(), sky.bottomRectColor.toRgba(), 0.0f},
{Vec2F(0, screenSize[1]), Vec2F(), sky.topRectColor.toRgba(), 0.0f}}); RenderVertex{screenSize, Vec2F(), sky.topRectColor.toRgba(), 0.0f},
RenderVertex{Vec2F(0, screenSize[1]), Vec2F(), sky.topRectColor.toRgba(), 0.0f});
// Flash overlay for Interstellar travel // Flash overlay for Interstellar travel
Vec4B flashColor = sky.flashColor.toRgba(); Vec4B flashColor = sky.flashColor.toRgba();
m_renderer->render(renderFlatRect(RectF(Vec2F(), screenSize), flashColor, 0.0f)); primitives.emplace_back(std::in_place_type_t<RenderQuad>(), RectF(Vec2F(), screenSize), flashColor, 0.0f);
m_renderer->flush(); m_renderer->flush();
} }
@ -224,6 +236,8 @@ void EnvironmentPainter::renderParallaxLayers(
// Note: the "parallax space" referenced below is a grid where the scale of each cell is the size of the parallax image // Note: the "parallax space" referenced below is a grid where the scale of each cell is the size of the parallax image
auto& primitives = m_renderer->immediatePrimitives();
for (auto& layer : layers) { for (auto& layer : layers) {
if (layer.alpha == 0) if (layer.alpha == 0)
continue; continue;
@ -307,11 +321,11 @@ void EnvironmentPainter::renderParallaxLayers(
withDirectives.directives += layer.directives; withDirectives.directives += layer.directives;
if (auto texture = m_textureGroup->tryTexture(withDirectives)) { if (auto texture = m_textureGroup->tryTexture(withDirectives)) {
RectF drawRect = RectF::withSize(anchorPoint, subImage.size() * camera.pixelRatio()); RectF drawRect = RectF::withSize(anchorPoint, subImage.size() * camera.pixelRatio());
m_renderer->render(RenderQuad{move(texture), primitives.emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
{{drawRect.xMin(), drawRect.yMin()}, {subImage.xMin(), subImage.yMin()}, drawColor, lightMapMultiplier}, RenderVertex{drawRect.min(), subImage.min(), drawColor, lightMapMultiplier},
{{drawRect.xMax(), drawRect.yMin()}, {subImage.xMax(), subImage.yMin()}, drawColor, lightMapMultiplier}, RenderVertex{{drawRect.xMax(), drawRect.yMin()}, {subImage.xMax(), subImage.yMin()}, drawColor, lightMapMultiplier},
{{drawRect.xMax(), drawRect.yMax()}, {subImage.xMax(), subImage.yMax()}, drawColor, lightMapMultiplier}, RenderVertex{drawRect.max(), subImage.max(), drawColor, lightMapMultiplier},
{{drawRect.xMin(), drawRect.yMax()}, {subImage.xMin(), subImage.yMax()}, drawColor, lightMapMultiplier}}); RenderVertex{{drawRect.xMin(), drawRect.yMax()}, {subImage.xMin(), subImage.yMax()}, drawColor, lightMapMultiplier});
} }
} }
} }
@ -365,26 +379,27 @@ void EnvironmentPainter::drawRay(float pixelRatio,
// Sum is used to vary the ray intensity based on sky color // Sum is used to vary the ray intensity based on sky color
// Rays show up more on darker backgrounds, so this scales to remove that // Rays show up more on darker backgrounds, so this scales to remove that
float sum = std::pow((color[0] + color[1]) * RayColorDependenceScale, RayColorDependenceLevel); float sum = std::pow((color[0] + color[1]) * RayColorDependenceScale, RayColorDependenceLevel);
m_renderer->render(RenderQuad{{}, m_renderer->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), TexturePtr(),
{start + Vec2F(std::cos(angle + width), std::sin(angle + width)) * length, {}, Vec4B(RayColor, 0), 0.0f}, RenderVertex{start + Vec2F(std::cos(angle + width), std::sin(angle + width)) * length, {}, Vec4B(RayColor, 0), 0.0f},
{start + Vec2F(std::cos(angle + width), std::sin(angle + width)) * SunRadius * pixelRatio, RenderVertex{start + Vec2F(std::cos(angle + width), std::sin(angle + width)) * SunRadius * pixelRatio,
{}, {},
Vec4B(RayColor, Vec4B(RayColor,
(int)(RayMinUnscaledAlpha + std::abs(m_rayPerlin.get(angle * 896 + time * 30) * RayUnscaledAlphaVariance)) (int)(RayMinUnscaledAlpha + std::abs(m_rayPerlin.get(angle * 896 + time * 30) * RayUnscaledAlphaVariance))
* sum * sum
* alpha), 0.0f}, * alpha), 0.0f},
{start + Vec2F(std::cos(angle), std::sin(angle)) * SunRadius * pixelRatio, RenderVertex{start + Vec2F(std::cos(angle), std::sin(angle)) * SunRadius * pixelRatio,
{}, {},
Vec4B(RayColor, Vec4B(RayColor,
(int)(RayMinUnscaledAlpha + std::abs(m_rayPerlin.get(angle * 626 + time * 30) * RayUnscaledAlphaVariance)) (int)(RayMinUnscaledAlpha + std::abs(m_rayPerlin.get(angle * 626 + time * 30) * RayUnscaledAlphaVariance))
* sum * sum
* alpha), 0.0f}, * alpha), 0.0f},
{start + Vec2F(std::cos(angle), std::sin(angle)) * length, {}, Vec4B(RayColor, 0), 0.0f}}); RenderVertex{start + Vec2F(std::cos(angle), std::sin(angle)) * length, {}, Vec4B(RayColor, 0), 0.0f});
} }
void EnvironmentPainter::drawOrbiter(float pixelRatio, Vec2F const& screenSize, SkyRenderData const& sky, SkyOrbiter const& orbiter) { void EnvironmentPainter::drawOrbiter(float pixelRatio, Vec2F const& screenSize, SkyRenderData const& sky, SkyOrbiter const& orbiter) {
float alpha = 1.0f; float alpha = 1.0f;
Vec2F position = orbiter.position * pixelRatio; Vec2F screenCenter = screenSize / 2;
Vec2F position = screenCenter + (orbiter.position - screenCenter) * pixelRatio;
if (orbiter.type == SkyOrbiterType::Sun) { if (orbiter.type == SkyOrbiterType::Sun) {
alpha = sky.dayLevel; alpha = sky.dayLevel;
@ -398,11 +413,11 @@ void EnvironmentPainter::drawOrbiter(float pixelRatio, Vec2F const& screenSize,
RectF renderRect = RectF::withCenter(position, texSize * orbiter.scale * pixelRatio); RectF renderRect = RectF::withCenter(position, texSize * orbiter.scale * pixelRatio);
Vec4B renderColor = Vec4B(255, 255, 255, 255 * alpha); Vec4B renderColor = Vec4B(255, 255, 255, 255 * alpha);
m_renderer->render(RenderQuad{move(texture), m_renderer->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
{renderMatrix.transformVec2(renderRect.min()), Vec2F(0, 0), renderColor, 0.0f}, RenderVertex{renderMatrix.transformVec2(renderRect.min()), Vec2F(0, 0), renderColor, 0.0f},
{renderMatrix.transformVec2(Vec2F{renderRect.xMax(), renderRect.yMin()}), Vec2F(texSize[0], 0), renderColor, 0.0f}, RenderVertex{renderMatrix.transformVec2(Vec2F{renderRect.xMax(), renderRect.yMin()}), Vec2F(texSize[0], 0), renderColor, 0.0f},
{renderMatrix.transformVec2(renderRect.max()), Vec2F(texSize[0], texSize[1]), renderColor, 0.0f}, RenderVertex{renderMatrix.transformVec2(renderRect.max()), Vec2F(texSize[0], texSize[1]), renderColor, 0.0f},
{renderMatrix.transformVec2(Vec2F{renderRect.xMin(), renderRect.yMax()}), Vec2F(0, texSize[1]), renderColor, 0.0f}}); RenderVertex{renderMatrix.transformVec2(Vec2F{renderRect.xMin(), renderRect.yMax()}), Vec2F(0, texSize[1]), renderColor, 0.0f});
} }
uint64_t EnvironmentPainter::starsHash(SkyRenderData const& sky, Vec2F const& viewSize) const { uint64_t EnvironmentPainter::starsHash(SkyRenderData const& sky, Vec2F const& viewSize) const {

View File

@ -539,6 +539,7 @@ RectF TextPainter::doRenderLine(StringView text, TextPositioning const& position
RectF TextPainter::doRenderGlyph(String::Char c, TextPositioning const& position, bool reallyRender) { RectF TextPainter::doRenderGlyph(String::Char c, TextPositioning const& position, bool reallyRender) {
if (m_nonRenderedCharacters.find(String(c)) != NPos) if (m_nonRenderedCharacters.find(String(c)) != NPos)
return RectF(); return RectF();
m_fontTextureGroup.switchFont(m_renderSettings.font);
int width = glyphWidth(c); int width = glyphWidth(c);
// Offset left by width if right anchored. // Offset left by width if right anchored.
@ -581,8 +582,8 @@ void TextPainter::renderGlyph(String::Char c, Vec2F const& screenPos, unsigned f
return; return;
const FontTextureGroup::GlyphTexture& glyphTexture = m_fontTextureGroup.glyphTexture(c, fontSize, processingDirectives); const FontTextureGroup::GlyphTexture& glyphTexture = m_fontTextureGroup.glyphTexture(c, fontSize, processingDirectives);
Vec2F offset = glyphTexture.processingOffset * (scale * 0.5f); //Kae: Re-center the glyph if the image scale was changed by the directives (it is positioned from the bottom left) Vec2F offset = glyphTexture.processingOffset * (scale * 0.5f);
m_renderer->render(renderTexturedRect(glyphTexture.texture, Vec2F(screenPos) + offset, scale, color, 0.0f)); m_renderer->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), glyphTexture.texture, screenPos + offset, scale, color, 0.0f);
} }
} }

View File

@ -55,9 +55,6 @@ void TilePainter::adjustLighting(WorldRenderData& renderData) const {
} }
void TilePainter::setup(WorldCamera const& camera, WorldRenderData& renderData) { void TilePainter::setup(WorldCamera const& camera, WorldRenderData& renderData) {
m_pendingTerrainChunks.clear();
m_pendingLiquidChunks.clear();
auto cameraCenter = camera.centerWorldPosition(); auto cameraCenter = camera.centerWorldPosition();
if (m_lastCameraCenter) if (m_lastCameraCenter)
m_cameraPan = renderData.geometry.diff(cameraCenter, *m_lastCameraCenter); m_cameraPan = renderData.geometry.diff(cameraCenter, *m_lastCameraCenter);
@ -66,10 +63,16 @@ void TilePainter::setup(WorldCamera const& camera, WorldRenderData& renderData)
//Kae: Padded by one to fix culling issues with certain tile pieces at chunk borders, such as grass. //Kae: Padded by one to fix culling issues with certain tile pieces at chunk borders, such as grass.
RectI chunkRange = RectI::integral(RectF(camera.worldTileRect().padded(1)).scaled(1.0f / RenderChunkSize)); RectI chunkRange = RectI::integral(RectF(camera.worldTileRect().padded(1)).scaled(1.0f / RenderChunkSize));
size_t chunks = chunkRange.volume();
m_pendingTerrainChunks.resize(chunks);
m_pendingLiquidChunks.resize(chunks);
size_t i = 0;
for (int x = chunkRange.xMin(); x < chunkRange.xMax(); ++x) { for (int x = chunkRange.xMin(); x < chunkRange.xMax(); ++x) {
for (int y = chunkRange.yMin(); y < chunkRange.yMax(); ++y) { for (int y = chunkRange.yMin(); y < chunkRange.yMax(); ++y) {
m_pendingTerrainChunks.append(getTerrainChunk(renderData, {x, y})); size_t index = i++;
m_pendingLiquidChunks.append(getLiquidChunk(renderData, {x, y})); m_pendingTerrainChunks[index] = getTerrainChunk(renderData, {x, y});
m_pendingLiquidChunks [index] = getLiquidChunk(renderData, {x, y});
} }
} }
} }
@ -117,7 +120,7 @@ size_t TilePainter::TextureKeyHash::operator()(TextureKey const& key) const {
} }
TilePainter::ChunkHash TilePainter::terrainChunkHash(WorldRenderData& renderData, Vec2I chunkIndex) { TilePainter::ChunkHash TilePainter::terrainChunkHash(WorldRenderData& renderData, Vec2I chunkIndex) {
XXHash64 hasher; XXHash3 hasher;
RectI tileRange = RectI::withSize(chunkIndex * RenderChunkSize, Vec2I::filled(RenderChunkSize)).padded(MaterialRenderProfileMaxNeighborDistance); RectI tileRange = RectI::withSize(chunkIndex * RenderChunkSize, Vec2I::filled(RenderChunkSize)).padded(MaterialRenderProfileMaxNeighborDistance);
forEachRenderTile(renderData, tileRange, [&](Vec2I const&, RenderTile const& renderTile) { forEachRenderTile(renderData, tileRange, [&](Vec2I const&, RenderTile const& renderTile) {
@ -128,7 +131,7 @@ TilePainter::ChunkHash TilePainter::terrainChunkHash(WorldRenderData& renderData
} }
TilePainter::ChunkHash TilePainter::liquidChunkHash(WorldRenderData& renderData, Vec2I chunkIndex) { TilePainter::ChunkHash TilePainter::liquidChunkHash(WorldRenderData& renderData, Vec2I chunkIndex) {
XXHash64 hasher; XXHash3 hasher;
RectI tileRange = RectI::withSize(chunkIndex * RenderChunkSize, Vec2I::filled(RenderChunkSize)).padded(MaterialRenderProfileMaxNeighborDistance); RectI tileRange = RectI::withSize(chunkIndex * RenderChunkSize, Vec2I::filled(RenderChunkSize)).padded(MaterialRenderProfileMaxNeighborDistance);
forEachRenderTile(renderData, tileRange, [&](Vec2I const&, RenderTile const& renderTile) { forEachRenderTile(renderData, tileRange, [&](Vec2I const&, RenderTile const& renderTile) {
@ -334,13 +337,16 @@ bool TilePainter::produceTerrainPrimitives(HashMap<QuadZLevel, List<RenderPrimit
TexturePtr texture = getPieceTexture(material, piecePair.first, materialHue, false); TexturePtr texture = getPieceTexture(material, piecePair.first, materialHue, false);
RectF textureCoords = piecePair.first->variants.get(materialColorVariant).wrap(variance); RectF textureCoords = piecePair.first->variants.get(materialColorVariant).wrap(variance);
RectF worldCoords = RectF::withSize(piecePair.second / TilePixels + Vec2F(pos), textureCoords.size() / TilePixels); RectF worldCoords = RectF::withSize(piecePair.second / TilePixels + Vec2F(pos), textureCoords.size() / TilePixels);
quadList.append(RenderQuad{ quadList.emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
move(texture), worldCoords .min(),
RenderVertex{Vec2F(worldCoords.xMin(), worldCoords.yMin()), Vec2F(textureCoords.xMin(), textureCoords.yMin()), color, 1.0f}, textureCoords.min(),
RenderVertex{Vec2F(worldCoords.xMax(), worldCoords.yMin()), Vec2F(textureCoords.xMax(), textureCoords.yMin()), color, 1.0f}, Vec2F( worldCoords.xMax(), worldCoords.yMin()),
RenderVertex{Vec2F(worldCoords.xMax(), worldCoords.yMax()), Vec2F(textureCoords.xMax(), textureCoords.yMax()), color, 1.0f}, Vec2F(textureCoords.xMax(), textureCoords.yMin()),
RenderVertex{Vec2F(worldCoords.xMin(), worldCoords.yMax()), Vec2F(textureCoords.xMin(), textureCoords.yMax()), color, 1.0f} worldCoords .max(),
}); textureCoords.max(),
Vec2F( worldCoords.xMin(), worldCoords.yMax()),
Vec2F(textureCoords.xMin(), textureCoords.yMax()),
color, 1.0f);
} }
} }
@ -354,15 +360,14 @@ bool TilePainter::produceTerrainPrimitives(HashMap<QuadZLevel, List<RenderPrimit
terrainLayer == TerrainLayer::Background ? TileLayer::Background : TileLayer::Foreground, true); terrainLayer == TerrainLayer::Background ? TileLayer::Background : TileLayer::Foreground, true);
for (auto const& piecePair : pieces) { for (auto const& piecePair : pieces) {
auto texture = getPieceTexture(mod, piecePair.first, modHue, true); auto texture = getPieceTexture(mod, piecePair.first, modHue, true);
auto textureCoords = piecePair.first->variants.get(modColorVariant).wrap(variance); auto& textureCoords = piecePair.first->variants.get(modColorVariant).wrap(variance);
RectF worldCoords = RectF::withSize(piecePair.second / TilePixels + Vec2F(pos), textureCoords.size() / TilePixels); RectF worldCoords = RectF::withSize(piecePair.second / TilePixels + Vec2F(pos), textureCoords.size() / TilePixels);
quadList.append(RenderQuad{ quadList.emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
move(texture), worldCoords.min(), textureCoords.min(),
RenderVertex{Vec2F(worldCoords.xMin(), worldCoords.yMin()), Vec2F(textureCoords.xMin(), textureCoords.yMin()), color, 1.0f}, Vec2F(worldCoords.xMax(), worldCoords.yMin()), Vec2F(textureCoords.xMax(), textureCoords.yMin()),
RenderVertex{Vec2F(worldCoords.xMax(), worldCoords.yMin()), Vec2F(textureCoords.xMax(), textureCoords.yMin()), color, 1.0f}, worldCoords.max(), textureCoords.max(),
RenderVertex{Vec2F(worldCoords.xMax(), worldCoords.yMax()), Vec2F(textureCoords.xMax(), textureCoords.yMax()), color, 1.0f}, Vec2F(worldCoords.xMin(), worldCoords.yMax()), Vec2F(textureCoords.xMin(), textureCoords.yMax()),
RenderVertex{Vec2F(worldCoords.xMin(), worldCoords.yMax()), Vec2F(textureCoords.xMin(), textureCoords.yMax()), color, 1.0f} color, 1.0f);
});
} }
} }
@ -377,13 +382,12 @@ bool TilePainter::produceTerrainPrimitives(HashMap<QuadZLevel, List<RenderPrimit
RectF textureCoords = RectF::withSize(Vec2F(), textureSize); RectF textureCoords = RectF::withSize(Vec2F(), textureSize);
RectF worldCoords = RectF::withSize(crackingImage.second / TilePixels + Vec2F(pos), textureCoords.size() / TilePixels); RectF worldCoords = RectF::withSize(crackingImage.second / TilePixels + Vec2F(pos), textureCoords.size() / TilePixels);
quadList.append(RenderQuad{ quadList.emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
move(texture), worldCoords.min(), textureCoords.min(),
RenderVertex{Vec2F(worldCoords.xMin(), worldCoords.yMin()), Vec2F(textureCoords.xMin(), textureCoords.yMin()), color, 1.0f}, Vec2F(worldCoords.xMax(), worldCoords.yMin()), Vec2F(textureCoords.xMax(), textureCoords.yMin()),
RenderVertex{Vec2F(worldCoords.xMax(), worldCoords.yMin()), Vec2F(textureCoords.xMax(), textureCoords.yMin()), color, 1.0f}, worldCoords.max(), textureCoords.max(),
RenderVertex{Vec2F(worldCoords.xMax(), worldCoords.yMax()), Vec2F(textureCoords.xMax(), textureCoords.yMax()), color, 1.0f}, Vec2F(worldCoords.xMin(), worldCoords.yMax()), Vec2F(textureCoords.xMin(), textureCoords.yMax()),
RenderVertex{Vec2F(worldCoords.xMin(), worldCoords.yMax()), Vec2F(textureCoords.xMin(), textureCoords.yMax()), color, 1.0f} color, 1.0f);
});
} }
return occlude; return occlude;
@ -408,13 +412,12 @@ void TilePainter::produceLiquidPrimitives(HashMap<LiquidId, List<RenderPrimitive
auto texRect = worldRect.scaled(TilePixels); auto texRect = worldRect.scaled(TilePixels);
auto const& liquid = m_liquids[tile.liquidId]; auto const& liquid = m_liquids[tile.liquidId];
primitives[tile.liquidId].append(RenderQuad{ primitives[tile.liquidId].emplace_back(std::in_place_type_t<RenderQuad>(), move(liquid.texture),
liquid.texture, worldRect.min(), texRect.min(),
RenderVertex{Vec2F(worldRect.xMin(), worldRect.yMin()), Vec2F(texRect.xMin(), texRect.yMin()), liquid.color, 1.0f}, Vec2F(worldRect.xMax(), worldRect.yMin()), Vec2F(texRect.xMax(), texRect.yMin()),
RenderVertex{Vec2F(worldRect.xMax(), worldRect.yMin()), Vec2F(texRect.xMax(), texRect.yMin()), liquid.color, 1.0f}, worldRect.max(), texRect.max(),
RenderVertex{Vec2F(worldRect.xMax(), worldRect.yMax()), Vec2F(texRect.xMax(), texRect.yMax()), liquid.color, 1.0f}, Vec2F(worldRect.xMin(), worldRect.yMax()), Vec2F(texRect.xMin(), texRect.yMax()),
RenderVertex{Vec2F(worldRect.xMin(), worldRect.yMax()), Vec2F(texRect.xMin(), texRect.yMax()), liquid.color, 1.0f} liquid.color, 1.0f);
});
} }
bool TilePainter::determineMatchingPieces(MaterialPieceResultList& resultList, bool* occlude, MaterialDatabaseConstPtr const& materialDb, MaterialRenderMatchList const& matchList, bool TilePainter::determineMatchingPieces(MaterialPieceResultList& resultList, bool* occlude, MaterialDatabaseConstPtr const& materialDb, MaterialRenderMatchList const& matchList,

View File

@ -173,7 +173,10 @@ void WorldPainter::renderParticles(WorldRenderData& renderData, Particle::Layer
Vec2F size = Vec2F::filled(particle.size * m_camera.pixelRatio()); Vec2F size = Vec2F::filled(particle.size * m_camera.pixelRatio());
if (particle.type == Particle::Type::Ember) { if (particle.type == Particle::Type::Ember) {
m_renderer->render(renderFlatRect(RectF(position - size / 2, position + size / 2), particle.color.toRgba(), particle.fullbright ? 0.0f : 1.0f)); m_renderer->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(),
RectF(position - size / 2, position + size / 2),
particle.color.toRgba(),
particle.fullbright ? 0.0f : 1.0f);
} else if (particle.type == Particle::Type::Streak) { } else if (particle.type == Particle::Type::Streak) {
// Draw a rotated quad streaking in the direction the particle is coming from. // Draw a rotated quad streaking in the direction the particle is coming from.
@ -183,12 +186,12 @@ void WorldPainter::renderParticles(WorldRenderData& renderData, Particle::Layer
float length = particle.length * m_camera.pixelRatio(); float length = particle.length * m_camera.pixelRatio();
Vec4B color = particle.color.toRgba(); Vec4B color = particle.color.toRgba();
float lightMapMultiplier = particle.fullbright ? 0.0f : 1.0f; float lightMapMultiplier = particle.fullbright ? 0.0f : 1.0f;
m_renderer->render(RenderQuad{{}, m_renderer->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(),
{position - sideHalf, {}, color, lightMapMultiplier}, position - sideHalf,
{position + sideHalf, {}, color, lightMapMultiplier}, position + sideHalf,
{position - dir * length + sideHalf, {}, color, lightMapMultiplier}, position - dir * length + sideHalf,
{position - dir * length - sideHalf, {}, color, lightMapMultiplier} position - dir * length - sideHalf,
}); color, lightMapMultiplier);
} else if (particle.type == Particle::Type::Textured || particle.type == Particle::Type::Animated) { } else if (particle.type == Particle::Type::Textured || particle.type == Particle::Type::Animated) {
Drawable drawable; Drawable drawable;

View File

@ -140,23 +140,24 @@ Vec2U GuiContext::textureSize(AssetPath const& texName) {
} }
void GuiContext::drawQuad(RectF const& screenCoords, Vec4B const& color) { void GuiContext::drawQuad(RectF const& screenCoords, Vec4B const& color) {
renderer()->render(renderFlatRect(screenCoords, color, 0.0f)); renderer()->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), screenCoords, color, 0.0f);
} }
void GuiContext::drawQuad(AssetPath const& texName, RectF const& screenCoords, Vec4B const& color) { void GuiContext::drawQuad(AssetPath const& texName, RectF const& screenCoords, Vec4B const& color) {
renderer()->render(renderTexturedRect(assetTextureGroup()->loadTexture(texName), screenCoords, color, 0.0f)); renderer()->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), assetTextureGroup()->loadTexture(texName), screenCoords, color, 0.0f);
} }
void GuiContext::drawQuad(AssetPath const& texName, Vec2F const& screenPos, int pixelRatio, Vec4B const& color) { void GuiContext::drawQuad(AssetPath const& texName, Vec2F const& screenPos, int pixelRatio, Vec4B const& color) {
renderer()->render(renderTexturedRect(assetTextureGroup()->loadTexture(texName), screenPos, pixelRatio, color, 0.0f)); renderer()->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), assetTextureGroup()->loadTexture(texName), screenPos, pixelRatio, color, 0.0f);
} }
void GuiContext::drawQuad(AssetPath const& texName, RectF const& texCoords, RectF const& screenCoords, Vec4B const& color) { void GuiContext::drawQuad(AssetPath const& texName, RectF const& texCoords, RectF const& screenCoords, Vec4B const& color) {
renderer()->render(RenderQuad{assetTextureGroup()->loadTexture(texName), renderer()->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), assetTextureGroup()->loadTexture(texName),
RenderVertex{Vec2F(screenCoords.xMin(), screenCoords.yMin()), Vec2F(texCoords.xMin(), texCoords.yMin()), color, 0.0f}, screenCoords.min(), texCoords.min(),
RenderVertex{Vec2F(screenCoords.xMax(), screenCoords.yMin()), Vec2F(texCoords.xMax(), texCoords.yMin()), color, 0.0f}, Vec2F(screenCoords.xMax(), screenCoords.yMin()), Vec2F(texCoords.xMax(), texCoords.yMin()),
RenderVertex{Vec2F(screenCoords.xMax(), screenCoords.yMax()), Vec2F(texCoords.xMax(), texCoords.yMax()), color, 0.0f}, screenCoords.max(), texCoords.max(),
RenderVertex{Vec2F(screenCoords.xMin(), screenCoords.yMax()), Vec2F(texCoords.xMin(), texCoords.yMax()), color, 0.0f}}); Vec2F(screenCoords.xMin(), screenCoords.yMax()), Vec2F(texCoords.xMin(), texCoords.yMax()),
color, 0.0f);
} }
void GuiContext::drawDrawable(Drawable drawable, Vec2F const& screenPos, int pixelRatio, Vec4B const& color) { void GuiContext::drawDrawable(Drawable drawable, Vec2F const& screenPos, int pixelRatio, Vec4B const& color) {
@ -171,11 +172,12 @@ void GuiContext::drawDrawable(Drawable drawable, Vec2F const& screenPos, int pix
void GuiContext::drawLine(Vec2F const& begin, Vec2F const end, Vec4B const& color, float lineWidth) { void GuiContext::drawLine(Vec2F const& begin, Vec2F const end, Vec4B const& color, float lineWidth) {
Vec2F left = vnorm(Vec2F(end) - Vec2F(begin)).rot90() * lineWidth / 2.0f; Vec2F left = vnorm(Vec2F(end) - Vec2F(begin)).rot90() * lineWidth / 2.0f;
renderer()->render(RenderQuad{{}, renderer()->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(),
RenderVertex{Vec2F(begin) + left, Vec2F(), color, 0.0f}, begin + left,
RenderVertex{Vec2F(begin) - left, Vec2F(), color, 0.0f}, begin - left,
RenderVertex{Vec2F(end) - left, Vec2F(), color, 0.0f}, end - left,
RenderVertex{Vec2F(end) + left, Vec2F(), color, 0.0f}}); end + left,
color, 0.0f);
} }
void GuiContext::drawPolyLines(PolyF const& poly, Vec4B const& color, float lineWidth) { void GuiContext::drawPolyLines(PolyF const& poly, Vec4B const& color, float lineWidth) {
@ -184,11 +186,9 @@ void GuiContext::drawPolyLines(PolyF const& poly, Vec4B const& color, float line
} }
void GuiContext::drawTriangles(List<tuple<Vec2F, Vec2F, Vec2F>> const& triangles, Vec4B const& color) { void GuiContext::drawTriangles(List<tuple<Vec2F, Vec2F, Vec2F>> const& triangles, Vec4B const& color) {
for (auto poly : triangles) { for (auto& poly : triangles) {
renderer()->render(RenderTriangle{{}, renderer()->immediatePrimitives().emplace_back(std::in_place_type_t<RenderTriangle>(),
RenderVertex{get<0>(poly), Vec2F(), color, 0.0f}, get<0>(poly), get<1>(poly), get<2>(poly), color, 0.0f);
RenderVertex{get<1>(poly), Vec2F(), color, 0.0f},
RenderVertex{get<2>(poly), Vec2F(), color, 0.0f}});
} }
} }