RenderPrimitive micro-optimizations
This commit is contained in:
parent
47a527ebbf
commit
d5fbd2001b
@ -12,49 +12,78 @@ EnumMap<TextureFiltering> const TextureFilteringNames{
|
||||
{TextureFiltering::Linear, "Linear"}
|
||||
};
|
||||
|
||||
RenderQuad renderTexturedRect(TexturePtr texture, Vec2F minPosition, float textureScale, Vec4B color, float param1) {
|
||||
if (!texture)
|
||||
throw RendererException("renderTexturedRect called with null texture");
|
||||
RenderQuad::RenderQuad(Vec2F posA, Vec2F posB, Vec2F posC, Vec2F posD, Vec4B color, float param1) : texture() {
|
||||
a = { posA, { 0, 0 }, color, param1 };
|
||||
b = { posB, { 0, 0 }, color, param1 };
|
||||
c = { posC, { 0, 0 }, color, param1 };
|
||||
d = { posD, { 0, 0 }, color, param1 };
|
||||
}
|
||||
|
||||
auto textureSize = Vec2F(texture->size());
|
||||
return {
|
||||
move(texture),
|
||||
RenderVertex{minPosition, Vec2F(0, 0), color, param1},
|
||||
RenderVertex{minPosition + Vec2F(textureSize[0], 0) * textureScale, Vec2F(textureSize[0], 0), color, param1},
|
||||
RenderVertex{minPosition + Vec2F(textureSize[0], textureSize[1]) * textureScale, Vec2F(textureSize[0], textureSize[1]), color, param1},
|
||||
RenderVertex{minPosition + Vec2F(0, textureSize[1]) * textureScale, Vec2F(0, textureSize[1]), color, param1}
|
||||
};
|
||||
RenderQuad::RenderQuad(TexturePtr tex, Vec2F minPosition, float textureScale, Vec4B color, float param1) : texture(move(tex)) {
|
||||
Vec2F size = Vec2F(texture->size());
|
||||
a = { minPosition, { 0, 0 }, color, param1};
|
||||
b = { { (minPosition[0] + size[0] * textureScale), minPosition[1] }, { size[0], 0 }, color, param1 };
|
||||
c = { { (minPosition[0] + size[0] * textureScale), (minPosition[1] + size[1] * textureScale) }, size, color, param1 };
|
||||
d = { { minPosition[0], (minPosition[1] + size[1] * textureScale) }, { 0, size[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) {
|
||||
if (!texture)
|
||||
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}
|
||||
};
|
||||
return RenderQuad(move(texture), screenCoords, color, param1);
|
||||
}
|
||||
|
||||
RenderQuad renderFlatRect(RectF const& rect, Vec4B color, float param1) {
|
||||
return {
|
||||
{},
|
||||
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}
|
||||
};
|
||||
return RenderQuad(rect, color, param1);
|
||||
}
|
||||
|
||||
RenderPoly renderFlatPoly(PolyF const& poly, Vec4B color, float param1) {
|
||||
RenderPoly renderPoly;
|
||||
for (auto const& v : poly)
|
||||
renderPoly.vertexes.append({v, {}, color, param1});
|
||||
return renderPoly;
|
||||
return RenderPoly(poly.vertexes(), color, param1);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -50,17 +50,35 @@ struct RenderVertex {
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
List<RenderVertex> vertexes;
|
||||
};
|
||||
@ -100,7 +118,7 @@ public:
|
||||
|
||||
// Transforms the given primitives into a form suitable for the underlying
|
||||
// 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;
|
||||
@ -136,6 +154,7 @@ public:
|
||||
virtual TextureGroupPtr createTextureGroup(TextureGroupSize size = TextureGroupSize::Medium, TextureFiltering filtering = TextureFiltering::Nearest) = 0;
|
||||
virtual RenderBufferPtr createRenderBuffer() = 0;
|
||||
|
||||
virtual List<RenderPrimitive>& immediatePrimitives() = 0;
|
||||
virtual void render(RenderPrimitive primitive) = 0;
|
||||
virtual void renderBuffer(RenderBufferPtr const& renderBuffer, Mat3F const& transformation = Mat3F::identity()) = 0;
|
||||
|
||||
|
@ -366,6 +366,10 @@ RenderBufferPtr OpenGl20Renderer::createRenderBuffer() {
|
||||
return createGlRenderBuffer();
|
||||
}
|
||||
|
||||
List<RenderPrimitive>& OpenGl20Renderer::immediatePrimitives() {
|
||||
return m_immediatePrimitives;
|
||||
}
|
||||
|
||||
void OpenGl20Renderer::render(RenderPrimitive primitive) {
|
||||
m_immediatePrimitives.append(move(primitive));
|
||||
}
|
||||
@ -399,7 +403,8 @@ void OpenGl20Renderer::finishFrame() {
|
||||
flushImmediatePrimitives();
|
||||
// Make sure that the immediate render buffer doesn't needlessly lock texutres
|
||||
// from being compressed.
|
||||
m_immediateRenderBuffer->set({});
|
||||
List<RenderPrimitive> empty;
|
||||
m_immediateRenderBuffer->set(empty);
|
||||
|
||||
filter(m_liveTextureGroups, [](auto const& p) {
|
||||
unsigned const CompressionsPerFrame = 1;
|
||||
@ -569,7 +574,7 @@ OpenGl20Renderer::GlRenderBuffer::~GlRenderBuffer() {
|
||||
glDeleteBuffers(1, &vb.vertexBuffer);
|
||||
}
|
||||
|
||||
void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive> primitives) {
|
||||
void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive>& primitives) {
|
||||
for (auto const& texture : usedTextures) {
|
||||
if (auto gt = as<GlGroupedTexture>(texture.get()))
|
||||
gt->decrementBufferUseCount();
|
||||
@ -637,7 +642,7 @@ void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive> primitives) {
|
||||
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 {
|
||||
v.screenCoordinate,
|
||||
v.textureCoordinate + textureCoordinateOffset,
|
||||
@ -682,6 +687,7 @@ void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive> primitives) {
|
||||
}
|
||||
}
|
||||
|
||||
vertexBuffers.reserve(primitives.size() * 6);
|
||||
finishCurrentBuffer();
|
||||
|
||||
for (auto const& vb : oldVertexBuffers)
|
||||
@ -733,7 +739,8 @@ void OpenGl20Renderer::flushImmediatePrimitives() {
|
||||
if (m_immediatePrimitives.empty())
|
||||
return;
|
||||
|
||||
m_immediateRenderBuffer->set(take(m_immediatePrimitives));
|
||||
m_immediateRenderBuffer->set(m_immediatePrimitives);
|
||||
m_immediatePrimitives.resize(0);
|
||||
renderGlBuffer(*m_immediateRenderBuffer, Mat3F::identity());
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ public:
|
||||
TextureGroupPtr createTextureGroup(TextureGroupSize size, TextureFiltering filtering) override;
|
||||
RenderBufferPtr createRenderBuffer() override;
|
||||
|
||||
List<RenderPrimitive>& immediatePrimitives() override;
|
||||
void render(RenderPrimitive primitive) override;
|
||||
void renderBuffer(RenderBufferPtr const& renderBuffer, Mat3F const& transformation) override;
|
||||
|
||||
@ -128,7 +129,7 @@ private:
|
||||
|
||||
~GlRenderBuffer();
|
||||
|
||||
void set(List<RenderPrimitive> primitives) override;
|
||||
void set(List<RenderPrimitive>& primitives) override;
|
||||
|
||||
RefPtr<GlTexture> whiteTexture;
|
||||
ByteArray accumulationBuffer;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <initializer_list>
|
||||
|
||||
#include "StarAlgorithm.hpp"
|
||||
#include "StarMaybe.hpp"
|
||||
@ -70,6 +71,22 @@ public:
|
||||
template <typename T, typename = ValidateType<T>>
|
||||
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&& x) noexcept(detail::IsNothrowMoveConstructible<FirstType, RestTypes...>::value);
|
||||
|
||||
|
@ -245,15 +245,17 @@ void Cinematic::render() {
|
||||
|
||||
void Cinematic::drawDrawable(Drawable const& drawable, float drawableScale, Vec2F const& drawableTranslation) {
|
||||
auto& guiContext = GuiContext::singleton();
|
||||
auto renderer = guiContext.renderer();
|
||||
auto textureGroup = guiContext.assetTextureGroup();
|
||||
auto& renderer = guiContext.renderer();
|
||||
auto& textureGroup = guiContext.assetTextureGroup();
|
||||
|
||||
auto& primitives = renderer->immediatePrimitives();
|
||||
|
||||
if (drawable.isImage()) {
|
||||
auto const& imagePart = drawable.imagePart();
|
||||
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;
|
||||
|
||||
@ -272,11 +274,12 @@ void Cinematic::drawDrawable(Drawable const& drawable, float drawableScale, Vec2
|
||||
|
||||
Vec4B drawableColor = drawable.color.toRgba();
|
||||
|
||||
renderer->render(RenderQuad{move(texture),
|
||||
RenderVertex{lowerLeft, Vec2F(0, 0), drawableColor, 0.0f},
|
||||
RenderVertex{lowerRight, Vec2F(textureSize[0], 0), drawableColor, 0.0f},
|
||||
RenderVertex{upperRight, Vec2F(textureSize[0], textureSize[1]), drawableColor, 0.0f},
|
||||
RenderVertex{upperLeft, Vec2F(0, textureSize[1]), drawableColor, 0.0f}});
|
||||
primitives.emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
|
||||
lowerLeft, Vec2F{0, 0},
|
||||
lowerRight, Vec2F{size[0], 0},
|
||||
upperRight, Vec2F{size[0], size[1]},
|
||||
upperLeft, Vec2F{0, size[1]},
|
||||
drawableColor, 0.0f);
|
||||
} else {
|
||||
starAssert(drawable.part.empty());
|
||||
}
|
||||
|
@ -384,32 +384,8 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) {
|
||||
} else {
|
||||
m_lightingCalculator.begin(lightRange);
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
if (!m_asyncLighting)
|
||||
lightingTileGather();
|
||||
|
||||
for (auto const& light : renderLightSources) {
|
||||
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;
|
||||
}
|
||||
|
||||
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() {
|
||||
while (true) {
|
||||
if (m_stopLightingThread)
|
||||
@ -1448,6 +1453,9 @@ void WorldClient::lightingMain() {
|
||||
|
||||
if (m_renderData) {
|
||||
int64_t start = Time::monotonicMilliseconds();
|
||||
|
||||
lightingTileGather();
|
||||
|
||||
m_lightingCalculator.calculate(m_renderData->lightMap);
|
||||
m_renderData = nullptr;
|
||||
LogMap::set("render_light_calc", strf("{}ms", Time::monotonicMilliseconds() - start));
|
||||
|
@ -190,6 +190,7 @@ private:
|
||||
bool operator<(DamageNumberKey const& other) const;
|
||||
};
|
||||
|
||||
void lightingTileGather();
|
||||
void lightingMain();
|
||||
|
||||
void initWorld(WorldStartPacket const& packet);
|
||||
|
@ -9,24 +9,25 @@ DrawablePainter::DrawablePainter(RendererPtr renderer, AssetTextureGroupPtr text
|
||||
|
||||
void DrawablePainter::drawDrawable(Drawable const& drawable) {
|
||||
Vec4B color = drawable.color.toRgba();
|
||||
auto& primitives = m_renderer->immediatePrimitives();
|
||||
|
||||
if (auto linePart = drawable.part.ptr<Drawable::LinePart>()) {
|
||||
auto line = linePart->line;
|
||||
line.translate(drawable.position);
|
||||
|
||||
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>()) {
|
||||
auto poly = polyPart->poly;
|
||||
PolyF poly = polyPart->poly;
|
||||
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>()) {
|
||||
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 upperLeft = transformation.transformVec2(Vec2F(imageRect.xMin(), imageRect.yMax()));
|
||||
|
||||
m_renderer->render(RenderQuad{move(texture),
|
||||
{lowerLeft, {0, 0}, color, drawable.fullbright ? 0.0f : 1.0f},
|
||||
{lowerRight, {textureSize[0], 0}, color, drawable.fullbright ? 0.0f : 1.0f},
|
||||
{upperRight, {textureSize[0], textureSize[1]}, color, drawable.fullbright ? 0.0f : 1.0f},
|
||||
{upperLeft, {0, textureSize[1]}, color, drawable.fullbright ? 0.0f : 1.0f}
|
||||
});
|
||||
float param1 = drawable.fullbright ? 0.0f : 1.0f;
|
||||
|
||||
primitives.emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
|
||||
lowerLeft, Vec2F{0, 0},
|
||||
lowerRight, Vec2F{textureSize[0], 0},
|
||||
upperRight, Vec2F{textureSize[0], textureSize[1]},
|
||||
upperLeft, Vec2F{0, textureSize[1]},
|
||||
color, param1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include "StarTime.hpp"
|
||||
#include "StarXXHash.hpp"
|
||||
#include "StarJsonExtra.hpp"
|
||||
#include "StarLogging.hpp"
|
||||
#include "StarMathCommon.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
@ -80,12 +82,14 @@ void EnvironmentPainter::renderStars(float pixelRatio, Vec2F const& screenSize,
|
||||
|
||||
RectF viewRect = RectF::withSize(Vec2F(), viewSize).padded(screenBuffer);
|
||||
|
||||
auto& primitives = m_renderer->immediatePrimitives();
|
||||
|
||||
for (auto& star : stars) {
|
||||
Vec2F screenPos = transform.transformVec2(star.first);
|
||||
if (viewRect.contains(screenPos)) {
|
||||
size_t starFrame = (size_t)(sky.epochTime + star.second.second) % sky.starFrames;
|
||||
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) {
|
||||
Vec2F viewSize = screenSize / pixelRatio;
|
||||
Vec2F viewCenter = viewSize / 2;
|
||||
Vec2F viewMin = sky.starOffset - 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
|
||||
Vec2F velocityOffset = -Vec2F(debrisXVel, debrisYVel) * sky.epochTime;
|
||||
|
||||
float screenBuffer = debrisField.queryFloat("screenBuffer");
|
||||
PolyF field = PolyF(RectF::withSize(viewMin, viewSize).padded(screenBuffer).translated(velocityOffset));
|
||||
JsonArray imageOptions = debrisField.query("list").toArray();
|
||||
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"));
|
||||
JsonArray imageOptions = debrisField.query("list").toArray();
|
||||
|
||||
auto debrisItems = m_debrisGenerators[i]->generate(field,
|
||||
[&](RandomSource& rand) {
|
||||
String debrisImage = rand.randFrom(imageOptions).toString();
|
||||
StringView debrisImage = *rand.randFrom(imageOptions).stringPtr();
|
||||
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);
|
||||
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});
|
||||
@ -166,6 +175,8 @@ void EnvironmentPainter::renderPlanetHorizon(float pixelRatio, Vec2F const& scre
|
||||
float planetPixelRatio = pixelRatio * planetHorizon.scale;
|
||||
Vec2F center = planetHorizon.center * pixelRatio;
|
||||
|
||||
auto& primitives = m_renderer->immediatePrimitives();
|
||||
|
||||
for (auto const& layer : planetHorizon.layers) {
|
||||
TexturePtr leftTexture = m_textureGroup->loadTexture(layer.first);
|
||||
Vec2F leftTextureSize(leftTexture->size());
|
||||
@ -182,17 +193,17 @@ void EnvironmentPainter::renderPlanetHorizon(float pixelRatio, Vec2F const& scre
|
||||
PolyF rightImage = PolyF(rightRect);
|
||||
rightImage.rotate(planetHorizon.rotation, center);
|
||||
|
||||
m_renderer->render(RenderQuad{move(leftTexture),
|
||||
{leftImage[0], Vec2F(0, 0), {255, 255, 255, 255}, 0.0f},
|
||||
{leftImage[1], Vec2F(leftTextureSize[0], 0), {255, 255, 255, 255}, 0.0f},
|
||||
{leftImage[2], Vec2F(leftTextureSize[0], leftTextureSize[1]), {255, 255, 255, 255}, 0.0f},
|
||||
{leftImage[3], Vec2F(0, leftTextureSize[1]), {255, 255, 255, 255}, 0.0f}});
|
||||
primitives.emplace_back(std::in_place_type_t<RenderQuad>(), move(leftTexture),
|
||||
leftImage[0], Vec2F(0, 0),
|
||||
leftImage[1], Vec2F(leftTextureSize[0], 0),
|
||||
leftImage[2], Vec2F(leftTextureSize[0], leftTextureSize[1]),
|
||||
leftImage[3], Vec2F(0, leftTextureSize[1]), Vec4B::filled(255), 0.0f);
|
||||
|
||||
m_renderer->render(RenderQuad{move(rightTexture),
|
||||
{rightImage[0], Vec2F(0, 0), {255, 255, 255, 255}, 0.0f},
|
||||
{rightImage[1], Vec2F(rightTextureSize[0], 0), {255, 255, 255, 255}, 0.0f},
|
||||
{rightImage[2], Vec2F(rightTextureSize[0], rightTextureSize[1]), {255, 255, 255, 255}, 0.0f},
|
||||
{rightImage[3], Vec2F(0, rightTextureSize[1]), {255, 255, 255, 255}, 0.0f}});
|
||||
primitives.emplace_back(std::in_place_type_t<RenderQuad>(), move(rightTexture),
|
||||
rightImage[0], Vec2F(0, 0),
|
||||
rightImage[1], Vec2F(rightTextureSize[0], 0),
|
||||
rightImage[2], Vec2F(rightTextureSize[0], rightTextureSize[1]),
|
||||
rightImage[3], Vec2F(0, rightTextureSize[1]), Vec4B::filled(255), 0.0f);
|
||||
}
|
||||
|
||||
m_renderer->flush();
|
||||
@ -206,15 +217,16 @@ void EnvironmentPainter::renderFrontOrbiters(float pixelRatio, Vec2F const& scre
|
||||
}
|
||||
|
||||
void EnvironmentPainter::renderSky(Vec2F const& screenSize, SkyRenderData const& sky) {
|
||||
m_renderer->render(RenderQuad{{},
|
||||
{Vec2F(0, 0), Vec2F(), sky.bottomRectColor.toRgba(), 0.0f},
|
||||
{Vec2F(screenSize[0], 0), Vec2F(), sky.bottomRectColor.toRgba(), 0.0f},
|
||||
{screenSize, Vec2F(), sky.topRectColor.toRgba(), 0.0f},
|
||||
{Vec2F(0, screenSize[1]), Vec2F(), sky.topRectColor.toRgba(), 0.0f}});
|
||||
auto& primitives = m_renderer->immediatePrimitives();
|
||||
primitives.emplace_back(std::in_place_type_t<RenderQuad>(), TexturePtr(),
|
||||
RenderVertex{Vec2F(0, 0), Vec2F(), sky.bottomRectColor.toRgba(), 0.0f},
|
||||
RenderVertex{Vec2F(screenSize[0], 0), Vec2F(), sky.bottomRectColor.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
|
||||
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();
|
||||
}
|
||||
@ -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
|
||||
|
||||
auto& primitives = m_renderer->immediatePrimitives();
|
||||
|
||||
for (auto& layer : layers) {
|
||||
if (layer.alpha == 0)
|
||||
continue;
|
||||
@ -307,11 +321,11 @@ void EnvironmentPainter::renderParallaxLayers(
|
||||
withDirectives.directives += layer.directives;
|
||||
if (auto texture = m_textureGroup->tryTexture(withDirectives)) {
|
||||
RectF drawRect = RectF::withSize(anchorPoint, subImage.size() * camera.pixelRatio());
|
||||
m_renderer->render(RenderQuad{move(texture),
|
||||
{{drawRect.xMin(), drawRect.yMin()}, {subImage.xMin(), subImage.yMin()}, drawColor, lightMapMultiplier},
|
||||
{{drawRect.xMax(), drawRect.yMin()}, {subImage.xMax(), subImage.yMin()}, drawColor, lightMapMultiplier},
|
||||
{{drawRect.xMax(), drawRect.yMax()}, {subImage.xMax(), subImage.yMax()}, drawColor, lightMapMultiplier},
|
||||
{{drawRect.xMin(), drawRect.yMax()}, {subImage.xMin(), subImage.yMax()}, drawColor, lightMapMultiplier}});
|
||||
primitives.emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
|
||||
RenderVertex{drawRect.min(), subImage.min(), drawColor, lightMapMultiplier},
|
||||
RenderVertex{{drawRect.xMax(), drawRect.yMin()}, {subImage.xMax(), subImage.yMin()}, drawColor, lightMapMultiplier},
|
||||
RenderVertex{drawRect.max(), subImage.max(), 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
|
||||
// Rays show up more on darker backgrounds, so this scales to remove that
|
||||
float sum = std::pow((color[0] + color[1]) * RayColorDependenceScale, RayColorDependenceLevel);
|
||||
m_renderer->render(RenderQuad{{},
|
||||
{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,
|
||||
m_renderer->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), TexturePtr(),
|
||||
RenderVertex{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)) * SunRadius * pixelRatio,
|
||||
{},
|
||||
Vec4B(RayColor,
|
||||
(int)(RayMinUnscaledAlpha + std::abs(m_rayPerlin.get(angle * 896 + time * 30) * RayUnscaledAlphaVariance))
|
||||
* sum
|
||||
* 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,
|
||||
(int)(RayMinUnscaledAlpha + std::abs(m_rayPerlin.get(angle * 626 + time * 30) * RayUnscaledAlphaVariance))
|
||||
* sum
|
||||
* 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) {
|
||||
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) {
|
||||
alpha = sky.dayLevel;
|
||||
@ -398,11 +413,11 @@ void EnvironmentPainter::drawOrbiter(float pixelRatio, Vec2F const& screenSize,
|
||||
RectF renderRect = RectF::withCenter(position, texSize * orbiter.scale * pixelRatio);
|
||||
Vec4B renderColor = Vec4B(255, 255, 255, 255 * alpha);
|
||||
|
||||
m_renderer->render(RenderQuad{move(texture),
|
||||
{renderMatrix.transformVec2(renderRect.min()), Vec2F(0, 0), renderColor, 0.0f},
|
||||
{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},
|
||||
{renderMatrix.transformVec2(Vec2F{renderRect.xMin(), renderRect.yMax()}), Vec2F(0, texSize[1]), renderColor, 0.0f}});
|
||||
m_renderer->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
|
||||
RenderVertex{renderMatrix.transformVec2(renderRect.min()), Vec2F(0, 0), renderColor, 0.0f},
|
||||
RenderVertex{renderMatrix.transformVec2(Vec2F{renderRect.xMax(), renderRect.yMin()}), Vec2F(texSize[0], 0), renderColor, 0.0f},
|
||||
RenderVertex{renderMatrix.transformVec2(renderRect.max()), Vec2F(texSize[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 {
|
||||
|
@ -539,6 +539,7 @@ RectF TextPainter::doRenderLine(StringView text, TextPositioning const& position
|
||||
RectF TextPainter::doRenderGlyph(String::Char c, TextPositioning const& position, bool reallyRender) {
|
||||
if (m_nonRenderedCharacters.find(String(c)) != NPos)
|
||||
return RectF();
|
||||
m_fontTextureGroup.switchFont(m_renderSettings.font);
|
||||
|
||||
int width = glyphWidth(c);
|
||||
// Offset left by width if right anchored.
|
||||
@ -581,8 +582,8 @@ void TextPainter::renderGlyph(String::Char c, Vec2F const& screenPos, unsigned f
|
||||
return;
|
||||
|
||||
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)
|
||||
m_renderer->render(renderTexturedRect(glyphTexture.texture, Vec2F(screenPos) + offset, scale, color, 0.0f));
|
||||
Vec2F offset = glyphTexture.processingOffset * (scale * 0.5f);
|
||||
m_renderer->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), glyphTexture.texture, screenPos + offset, scale, color, 0.0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -55,9 +55,6 @@ void TilePainter::adjustLighting(WorldRenderData& renderData) const {
|
||||
}
|
||||
|
||||
void TilePainter::setup(WorldCamera const& camera, WorldRenderData& renderData) {
|
||||
m_pendingTerrainChunks.clear();
|
||||
m_pendingLiquidChunks.clear();
|
||||
|
||||
auto cameraCenter = camera.centerWorldPosition();
|
||||
if (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.
|
||||
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 y = chunkRange.yMin(); y < chunkRange.yMax(); ++y) {
|
||||
m_pendingTerrainChunks.append(getTerrainChunk(renderData, {x, y}));
|
||||
m_pendingLiquidChunks.append(getLiquidChunk(renderData, {x, y}));
|
||||
size_t index = i++;
|
||||
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) {
|
||||
XXHash64 hasher;
|
||||
XXHash3 hasher;
|
||||
RectI tileRange = RectI::withSize(chunkIndex * RenderChunkSize, Vec2I::filled(RenderChunkSize)).padded(MaterialRenderProfileMaxNeighborDistance);
|
||||
|
||||
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) {
|
||||
XXHash64 hasher;
|
||||
XXHash3 hasher;
|
||||
RectI tileRange = RectI::withSize(chunkIndex * RenderChunkSize, Vec2I::filled(RenderChunkSize)).padded(MaterialRenderProfileMaxNeighborDistance);
|
||||
|
||||
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);
|
||||
RectF textureCoords = piecePair.first->variants.get(materialColorVariant).wrap(variance);
|
||||
RectF worldCoords = RectF::withSize(piecePair.second / TilePixels + Vec2F(pos), textureCoords.size() / TilePixels);
|
||||
quadList.append(RenderQuad{
|
||||
move(texture),
|
||||
RenderVertex{Vec2F(worldCoords.xMin(), worldCoords.yMin()), Vec2F(textureCoords.xMin(), textureCoords.yMin()), color, 1.0f},
|
||||
RenderVertex{Vec2F(worldCoords.xMax(), worldCoords.yMin()), Vec2F(textureCoords.xMax(), textureCoords.yMin()), color, 1.0f},
|
||||
RenderVertex{Vec2F(worldCoords.xMax(), worldCoords.yMax()), Vec2F(textureCoords.xMax(), textureCoords.yMax()), color, 1.0f},
|
||||
RenderVertex{Vec2F(worldCoords.xMin(), worldCoords.yMax()), Vec2F(textureCoords.xMin(), textureCoords.yMax()), color, 1.0f}
|
||||
});
|
||||
quadList.emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
|
||||
worldCoords .min(),
|
||||
textureCoords.min(),
|
||||
Vec2F( worldCoords.xMax(), worldCoords.yMin()),
|
||||
Vec2F(textureCoords.xMax(), textureCoords.yMin()),
|
||||
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);
|
||||
for (auto const& piecePair : pieces) {
|
||||
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);
|
||||
quadList.append(RenderQuad{
|
||||
move(texture),
|
||||
RenderVertex{Vec2F(worldCoords.xMin(), worldCoords.yMin()), Vec2F(textureCoords.xMin(), textureCoords.yMin()), color, 1.0f},
|
||||
RenderVertex{Vec2F(worldCoords.xMax(), worldCoords.yMin()), Vec2F(textureCoords.xMax(), textureCoords.yMin()), color, 1.0f},
|
||||
RenderVertex{Vec2F(worldCoords.xMax(), worldCoords.yMax()), Vec2F(textureCoords.xMax(), textureCoords.yMax()), color, 1.0f},
|
||||
RenderVertex{Vec2F(worldCoords.xMin(), worldCoords.yMax()), Vec2F(textureCoords.xMin(), textureCoords.yMax()), color, 1.0f}
|
||||
});
|
||||
quadList.emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
|
||||
worldCoords.min(), textureCoords.min(),
|
||||
Vec2F(worldCoords.xMax(), worldCoords.yMin()), Vec2F(textureCoords.xMax(), textureCoords.yMin()),
|
||||
worldCoords.max(), textureCoords.max(),
|
||||
Vec2F(worldCoords.xMin(), worldCoords.yMax()), Vec2F(textureCoords.xMin(), textureCoords.yMax()),
|
||||
color, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@ -377,13 +382,12 @@ bool TilePainter::produceTerrainPrimitives(HashMap<QuadZLevel, List<RenderPrimit
|
||||
RectF textureCoords = RectF::withSize(Vec2F(), textureSize);
|
||||
RectF worldCoords = RectF::withSize(crackingImage.second / TilePixels + Vec2F(pos), textureCoords.size() / TilePixels);
|
||||
|
||||
quadList.append(RenderQuad{
|
||||
move(texture),
|
||||
RenderVertex{Vec2F(worldCoords.xMin(), worldCoords.yMin()), Vec2F(textureCoords.xMin(), textureCoords.yMin()), color, 1.0f},
|
||||
RenderVertex{Vec2F(worldCoords.xMax(), worldCoords.yMin()), Vec2F(textureCoords.xMax(), textureCoords.yMin()), color, 1.0f},
|
||||
RenderVertex{Vec2F(worldCoords.xMax(), worldCoords.yMax()), Vec2F(textureCoords.xMax(), textureCoords.yMax()), color, 1.0f},
|
||||
RenderVertex{Vec2F(worldCoords.xMin(), worldCoords.yMax()), Vec2F(textureCoords.xMin(), textureCoords.yMax()), color, 1.0f}
|
||||
});
|
||||
quadList.emplace_back(std::in_place_type_t<RenderQuad>(), move(texture),
|
||||
worldCoords.min(), textureCoords.min(),
|
||||
Vec2F(worldCoords.xMax(), worldCoords.yMin()), Vec2F(textureCoords.xMax(), textureCoords.yMin()),
|
||||
worldCoords.max(), textureCoords.max(),
|
||||
Vec2F(worldCoords.xMin(), worldCoords.yMax()), Vec2F(textureCoords.xMin(), textureCoords.yMax()),
|
||||
color, 1.0f);
|
||||
}
|
||||
|
||||
return occlude;
|
||||
@ -408,13 +412,12 @@ void TilePainter::produceLiquidPrimitives(HashMap<LiquidId, List<RenderPrimitive
|
||||
auto texRect = worldRect.scaled(TilePixels);
|
||||
|
||||
auto const& liquid = m_liquids[tile.liquidId];
|
||||
primitives[tile.liquidId].append(RenderQuad{
|
||||
liquid.texture,
|
||||
RenderVertex{Vec2F(worldRect.xMin(), worldRect.yMin()), Vec2F(texRect.xMin(), texRect.yMin()), liquid.color, 1.0f},
|
||||
RenderVertex{Vec2F(worldRect.xMax(), worldRect.yMin()), Vec2F(texRect.xMax(), texRect.yMin()), liquid.color, 1.0f},
|
||||
RenderVertex{Vec2F(worldRect.xMax(), worldRect.yMax()), Vec2F(texRect.xMax(), texRect.yMax()), liquid.color, 1.0f},
|
||||
RenderVertex{Vec2F(worldRect.xMin(), worldRect.yMax()), Vec2F(texRect.xMin(), texRect.yMax()), liquid.color, 1.0f}
|
||||
});
|
||||
primitives[tile.liquidId].emplace_back(std::in_place_type_t<RenderQuad>(), move(liquid.texture),
|
||||
worldRect.min(), texRect.min(),
|
||||
Vec2F(worldRect.xMax(), worldRect.yMin()), Vec2F(texRect.xMax(), texRect.yMin()),
|
||||
worldRect.max(), texRect.max(),
|
||||
Vec2F(worldRect.xMin(), worldRect.yMax()), Vec2F(texRect.xMin(), texRect.yMax()),
|
||||
liquid.color, 1.0f);
|
||||
}
|
||||
|
||||
bool TilePainter::determineMatchingPieces(MaterialPieceResultList& resultList, bool* occlude, MaterialDatabaseConstPtr const& materialDb, MaterialRenderMatchList const& matchList,
|
||||
|
@ -173,7 +173,10 @@ void WorldPainter::renderParticles(WorldRenderData& renderData, Particle::Layer
|
||||
Vec2F size = Vec2F::filled(particle.size * m_camera.pixelRatio());
|
||||
|
||||
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) {
|
||||
// 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();
|
||||
Vec4B color = particle.color.toRgba();
|
||||
float lightMapMultiplier = particle.fullbright ? 0.0f : 1.0f;
|
||||
m_renderer->render(RenderQuad{{},
|
||||
{position - sideHalf, {}, color, lightMapMultiplier},
|
||||
{position + sideHalf, {}, color, lightMapMultiplier},
|
||||
{position - dir * length + sideHalf, {}, color, lightMapMultiplier},
|
||||
{position - dir * length - sideHalf, {}, color, lightMapMultiplier}
|
||||
});
|
||||
m_renderer->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(),
|
||||
position - sideHalf,
|
||||
position + sideHalf,
|
||||
position - dir * length + sideHalf,
|
||||
position - dir * length - sideHalf,
|
||||
color, lightMapMultiplier);
|
||||
|
||||
} else if (particle.type == Particle::Type::Textured || particle.type == Particle::Type::Animated) {
|
||||
Drawable drawable;
|
||||
|
@ -140,23 +140,24 @@ Vec2U GuiContext::textureSize(AssetPath const& texName) {
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
renderer()->render(RenderQuad{assetTextureGroup()->loadTexture(texName),
|
||||
RenderVertex{Vec2F(screenCoords.xMin(), screenCoords.yMin()), Vec2F(texCoords.xMin(), texCoords.yMin()), color, 0.0f},
|
||||
RenderVertex{Vec2F(screenCoords.xMax(), screenCoords.yMin()), Vec2F(texCoords.xMax(), texCoords.yMin()), color, 0.0f},
|
||||
RenderVertex{Vec2F(screenCoords.xMax(), screenCoords.yMax()), Vec2F(texCoords.xMax(), texCoords.yMax()), color, 0.0f},
|
||||
RenderVertex{Vec2F(screenCoords.xMin(), screenCoords.yMax()), Vec2F(texCoords.xMin(), texCoords.yMax()), color, 0.0f}});
|
||||
renderer()->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), assetTextureGroup()->loadTexture(texName),
|
||||
screenCoords.min(), texCoords.min(),
|
||||
Vec2F(screenCoords.xMax(), screenCoords.yMin()), Vec2F(texCoords.xMax(), texCoords.yMin()),
|
||||
screenCoords.max(), texCoords.max(),
|
||||
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) {
|
||||
@ -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) {
|
||||
Vec2F left = vnorm(Vec2F(end) - Vec2F(begin)).rot90() * lineWidth / 2.0f;
|
||||
renderer()->render(RenderQuad{{},
|
||||
RenderVertex{Vec2F(begin) + left, Vec2F(), color, 0.0f},
|
||||
RenderVertex{Vec2F(begin) - left, Vec2F(), color, 0.0f},
|
||||
RenderVertex{Vec2F(end) - left, Vec2F(), color, 0.0f},
|
||||
RenderVertex{Vec2F(end) + left, Vec2F(), color, 0.0f}});
|
||||
renderer()->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(),
|
||||
begin + left,
|
||||
begin - left,
|
||||
end - left,
|
||||
end + left,
|
||||
color, 0.0f);
|
||||
}
|
||||
|
||||
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) {
|
||||
for (auto poly : triangles) {
|
||||
renderer()->render(RenderTriangle{{},
|
||||
RenderVertex{get<0>(poly), Vec2F(), color, 0.0f},
|
||||
RenderVertex{get<1>(poly), Vec2F(), color, 0.0f},
|
||||
RenderVertex{get<2>(poly), Vec2F(), color, 0.0f}});
|
||||
for (auto& poly : triangles) {
|
||||
renderer()->immediatePrimitives().emplace_back(std::in_place_type_t<RenderTriangle>(),
|
||||
get<0>(poly), get<1>(poly), get<2>(poly), color, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user