Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assets/opensb/binds/opensb.binds8
-rw-r--r--assets/opensb/sfx/tools/buildradiusgrow.wav (renamed from assets/opensb/sfx/tools/matradiusgrow.wav)bin4494 -> 4494 bytes
-rw-r--r--assets/opensb/sfx/tools/buildradiusshrink.wav (renamed from assets/opensb/sfx/tools/matradiusshrink.wav)bin4494 -> 4494 bytes
-rw-r--r--source/client/StarClientApplication.cpp3
-rw-r--r--source/game/CMakeLists.txt2
-rw-r--r--source/game/StarItemDrop.cpp29
-rw-r--r--source/game/StarItemDrop.hpp1
-rw-r--r--source/game/StarTileDrawer.cpp311
-rw-r--r--source/game/StarTileDrawer.hpp77
-rw-r--r--source/game/StarToolUser.cpp4
-rw-r--r--source/game/interfaces/StarPreviewTileTool.hpp2
-rw-r--r--source/game/items/StarLiquidItem.cpp2
-rw-r--r--source/game/items/StarLiquidItem.hpp2
-rw-r--r--source/game/items/StarMaterialItem.cpp62
-rw-r--r--source/game/items/StarMaterialItem.hpp11
-rw-r--r--source/game/items/StarTools.cpp4
-rw-r--r--source/game/items/StarTools.hpp4
-rw-r--r--source/rendering/StarTilePainter.cpp181
-rw-r--r--source/rendering/StarTilePainter.hpp34
19 files changed, 498 insertions, 239 deletions
diff --git a/assets/opensb/binds/opensb.binds b/assets/opensb/binds/opensb.binds
index 73ba73b..c52385a 100644
--- a/assets/opensb/binds/opensb.binds
+++ b/assets/opensb/binds/opensb.binds
@@ -33,15 +33,15 @@
"group": "building",
"name": "Cycle Material Collision"
},
- "materialRadiusGrow": {
+ "buildingRadiusGrow": {
"default": [],
"group": "building",
- "name": "Grow Material Radius"
+ "name": "Grow Building Radius"
},
- "materialRadiusShrink": {
+ "buildingRadiusShrink": {
"default": [],
"group": "building",
- "name": "Shrink Material Radius"
+ "name": "Shrink Building Radius"
}
}
}
diff --git a/assets/opensb/sfx/tools/matradiusgrow.wav b/assets/opensb/sfx/tools/buildradiusgrow.wav
index 6a27a0e..6a27a0e 100644
--- a/assets/opensb/sfx/tools/matradiusgrow.wav
+++ b/assets/opensb/sfx/tools/buildradiusgrow.wav
Binary files differ
diff --git a/assets/opensb/sfx/tools/matradiusshrink.wav b/assets/opensb/sfx/tools/buildradiusshrink.wav
index 95df1cc..95df1cc 100644
--- a/assets/opensb/sfx/tools/matradiusshrink.wav
+++ b/assets/opensb/sfx/tools/buildradiusshrink.wav
Binary files differ
diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp
index 995325e..19ea9e0 100644
--- a/source/client/StarClientApplication.cpp
+++ b/source/client/StarClientApplication.cpp
@@ -170,9 +170,9 @@ void ClientApplication::applicationInit(ApplicationControllerPtr appController)
AudioFormat audioFormat = appController->enableAudio();
m_mainMixer = make_shared<MainMixer>(audioFormat.sampleRate, audioFormat.channels);
-
m_mainMixer->setVolume(0.5);
+ m_worldPainter = make_shared<WorldPainter>();
m_guiContext = make_shared<GuiContext>(m_mainMixer->mixer(), appController);
m_input = make_shared<Input>();
m_voice = make_shared<Voice>(appController);
@@ -644,7 +644,6 @@ void ClientApplication::changeState(MainAppState newState) {
m_titleScreen->stopMusic();
- m_worldPainter = make_shared<WorldPainter>();
m_mainInterface = make_shared<MainInterface>(m_universeClient, m_worldPainter, m_cinematicOverlay);
m_universeClient->setLuaCallbacks("interface", LuaBindings::makeInterfaceCallbacks(m_mainInterface.get()));
m_universeClient->startLua();
diff --git a/source/game/CMakeLists.txt b/source/game/CMakeLists.txt
index c229000..4886c48 100644
--- a/source/game/CMakeLists.txt
+++ b/source/game/CMakeLists.txt
@@ -144,6 +144,7 @@ SET (star_game_HEADERS
StarTenantDatabase.hpp
StarTerrainDatabase.hpp
StarTileDamage.hpp
+ StarTileDrawer.hpp
StarTileModification.hpp
StarTileSectorArray.hpp
StarTilesetDatabase.hpp
@@ -404,6 +405,7 @@ SET (star_game_SOURCES
StarTenantDatabase.cpp
StarTerrainDatabase.cpp
StarTileDamage.cpp
+ StarTileDrawer.cpp
StarTileModification.cpp
StarTilesetDatabase.cpp
StarToolUser.cpp
diff --git a/source/game/StarItemDrop.cpp b/source/game/StarItemDrop.cpp
index a9dbe0a..c97df6a 100644
--- a/source/game/StarItemDrop.cpp
+++ b/source/game/StarItemDrop.cpp
@@ -8,6 +8,7 @@
#include "StarWorld.hpp"
#include "StarDataStreamExtra.hpp"
#include "StarPlayer.hpp"
+#include "StarMaterialItem.hpp"
namespace Star {
@@ -231,9 +232,10 @@ void ItemDrop::update(float dt, uint64_t) {
m_mode.set(Mode::Dead);
if (m_mode.get() <= Mode::Available && m_ageItemsTimer.elapsedTime() > m_ageItemsEvery) {
- Root::singleton().itemDatabase()->ageItem(m_item, m_ageItemsTimer.elapsedTime());
- m_itemDescriptor.set(m_item->descriptor());
- updateCollisionPoly();
+ if (Root::singleton().itemDatabase()->ageItem(m_item, m_ageItemsTimer.elapsedTime())) {
+ m_itemDescriptor.set(m_item->descriptor());
+ updateCollisionPoly();
+ }
m_ageItemsTimer.setElapsedTime(0.0);
}
} else {
@@ -261,7 +263,7 @@ void ItemDrop::update(float dt, uint64_t) {
}
bool ItemDrop::shouldDestroy() const {
- return m_mode.get() == Mode::Dead;
+ return m_mode.get() == Mode::Dead || m_item->empty();
}
void ItemDrop::render(RenderCallback* renderCallback) {
@@ -294,7 +296,13 @@ void ItemDrop::render(RenderCallback* renderCallback) {
}
if (!m_drawables) {
- m_drawables = m_item->dropDrawables();
+ if (auto mat = as<MaterialItem>(m_item.get())) {
+ m_drawables = mat->generatedPreview(Vec2I(position().floor()));
+ m_overForeground = true;
+ }
+ else
+ m_drawables = m_item->dropDrawables();
+
if (Directives dropDirectives = m_config.getString("directives", "")) {
for (auto& drawable : *m_drawables) {
if (drawable.isImage())
@@ -302,7 +310,7 @@ void ItemDrop::render(RenderCallback* renderCallback) {
}
}
}
- EntityRenderLayer renderLayer = m_mode.get() == Mode::Taken ? RenderLayerForegroundTile : RenderLayerItemDrop;
+ EntityRenderLayer renderLayer = m_mode.get() == Mode::Taken || m_overForeground ? RenderLayerForegroundTile : RenderLayerItemDrop;
Vec2F dropPosition = position();
for (Drawable drawable : *m_drawables) {
drawable.position += dropPosition;
@@ -405,11 +413,16 @@ ItemDrop::ItemDrop() {
m_ageItemsEvery = m_config.getDouble("ageItemsEvery", 10);
m_eternal = false;
+ m_overForeground = false;
}
void ItemDrop::updateCollisionPoly() {
- m_boundBox = Drawable::boundBoxAll(m_item->dropDrawables(), true);
- m_boundBox.rangeSetIfEmpty(RectF{-0.5, -0.5, 0.5, 0.5});
+ if (auto mat = as<MaterialItem>(m_item.get()))
+ m_boundBox = RectF{ -0.5, -0.5, 0.5, 0.5 };
+ else {
+ m_boundBox = Drawable::boundBoxAll(m_item->dropDrawables(), true);
+ m_boundBox.rangeSetIfEmpty(RectF{ -0.5, -0.5, 0.5, 0.5 });
+ }
MovementParameters parameters;
parameters.collisionPoly = PolyF(collisionArea());
m_movementController.applyParameters(parameters);
diff --git a/source/game/StarItemDrop.hpp b/source/game/StarItemDrop.hpp
index a806209..7b76cd7 100644
--- a/source/game/StarItemDrop.hpp
+++ b/source/game/StarItemDrop.hpp
@@ -123,6 +123,7 @@ private:
GameTimer m_intangibleTimer;
EpochTimer m_ageItemsTimer;
+ bool m_overForeground;
Maybe<List<Drawable>> m_drawables;
};
diff --git a/source/game/StarTileDrawer.cpp b/source/game/StarTileDrawer.cpp
new file mode 100644
index 0000000..3ac8e48
--- /dev/null
+++ b/source/game/StarTileDrawer.cpp
@@ -0,0 +1,311 @@
+#include "StarTileDrawer.hpp"
+#include "StarLexicalCast.hpp"
+#include "StarJsonExtra.hpp"
+#include "StarXXHash.hpp"
+#include "StarMaterialDatabase.hpp"
+#include "StarLiquidsDatabase.hpp"
+#include "StarAssets.hpp"
+#include "StarRoot.hpp"
+
+namespace Star {
+
+RenderTile TileDrawer::DefaultRenderTile{
+ NullMaterialId,
+ NoModId,
+ NullMaterialId,
+ NoModId,
+ 0,
+ 0,
+ DefaultMaterialColorVariant,
+ TileDamageType::Protected,
+ 0,
+ 0,
+ 0,
+ DefaultMaterialColorVariant,
+ TileDamageType::Protected,
+ 0,
+ EmptyLiquidId,
+ 0
+};
+
+TileDrawer* TileDrawer::s_singleton;
+
+TileDrawer* TileDrawer::singletonPtr() {
+ return s_singleton;
+}
+
+TileDrawer& TileDrawer::singleton() {
+ if (!s_singleton)
+ throw StarException("TileDrawer::singleton() called with no TileDrawer instance available");
+ else
+ return *s_singleton;
+}
+
+TileDrawer::TileDrawer() {
+ auto assets = Root::singleton().assets();
+
+ m_backgroundLayerColor = jsonToColor(assets->json("/rendering.config:backgroundLayerColor")).toRgba();
+ m_foregroundLayerColor = jsonToColor(assets->json("/rendering.config:foregroundLayerColor")).toRgba();
+ m_liquidDrawLevels = jsonToVec2F(assets->json("/rendering.config:liquidDrawLevels"));
+ s_singleton = this;
+}
+
+TileDrawer::~TileDrawer() {
+ if (s_singleton == this)
+ s_singleton = nullptr;
+}
+
+bool TileDrawer::produceTerrainDrawables(Drawables& drawables,
+ TerrainLayer terrainLayer, Vec2I const& pos, WorldRenderData const& renderData, float scale, Vec2I offset, Maybe<TerrainLayer> variantLayer) {
+ auto& root = Root::singleton();
+ auto assets = Root::singleton().assets();
+ auto materialDatabase = root.materialDatabase();
+
+ RenderTile const& tile = getRenderTile(renderData, pos);
+
+ MaterialId material = EmptyMaterialId;
+ MaterialHue materialHue = 0;
+ MaterialColorVariant materialColorVariant = 0;
+ ModId mod = NoModId;
+ MaterialHue modHue = 0;
+ float damageLevel = 0.0f;
+ TileDamageType damageType = TileDamageType::Protected;
+ Color color;
+
+ bool occlude = false;
+
+ if (terrainLayer == TerrainLayer::Background) {
+ material = tile.background;
+ materialHue = tile.backgroundHueShift;
+ materialColorVariant = tile.backgroundColorVariant;
+ mod = tile.backgroundMod;
+ modHue = tile.backgroundModHueShift;
+ damageLevel = byteToFloat(tile.backgroundDamageLevel);
+ damageType = tile.backgroundDamageType;
+ color = Color::rgba(m_backgroundLayerColor);
+ } else {
+ material = tile.foreground;
+ materialHue = tile.foregroundHueShift;
+ materialColorVariant = tile.foregroundColorVariant;
+ mod = tile.foregroundMod;
+ modHue = tile.foregroundModHueShift;
+ damageLevel = byteToFloat(tile.foregroundDamageLevel);
+ damageType = tile.foregroundDamageType;
+ color = Color::rgba(m_foregroundLayerColor);
+ }
+
+ // render non-block colliding things in the midground
+ bool isBlock = BlockCollisionSet.contains(materialDatabase->materialCollisionKind(material));
+ if ((isBlock && terrainLayer == TerrainLayer::Midground) || (!isBlock && terrainLayer == TerrainLayer::Foreground))
+ return false;
+
+ auto getPieceImage = [](MaterialRenderPieceConstPtr const& piece, Box<float, 2> const& box, MaterialHue hue) -> String {
+ return hue == 0
+ ? strf("{}?crop={};{};{};{}", piece->texture, box.xMin(), box.yMin(), box.xMax(), box.yMax())
+ : strf("{}?crop={};{};{};{}?hueshift={}", piece->texture, box.xMin(), box.yMin(), box.xMax(), box.yMax(), materialHueToDegrees(hue));
+ };
+
+ auto materialRenderProfile = materialDatabase->materialRenderProfile(material);
+
+ auto modRenderProfile = materialDatabase->modRenderProfile(mod);
+
+ if (materialRenderProfile) {
+ occlude = materialRenderProfile->occludesBehind;
+
+ uint32_t variance = staticRandomU32(renderData.geometry.xwrap(pos[0]) + offset[0], pos[1] + offset[1], (int)variantLayer.value(terrainLayer), "main");
+ auto& drawList = drawables[materialZLevel(materialRenderProfile->zLevel, material, materialHue, materialColorVariant)];
+
+ MaterialPieceResultList pieces;
+ determineMatchingPieces(pieces, &occlude, materialDatabase, materialRenderProfile->mainMatchList, renderData, pos,
+ terrainLayer == TerrainLayer::Background ? TileLayer::Background : TileLayer::Foreground, false);
+ for (auto const& piecePair : pieces) {
+ auto& variant = piecePair.first->variants.get(materialColorVariant).wrap(variance);
+ auto image = getPieceImage(piecePair.first, variant, materialHue);
+ drawList.emplace_back(Drawable::makeImage(image, scale, false, piecePair.second * scale + Vec2F(pos), color));
+ }
+ }
+
+ if (modRenderProfile) {
+ auto modColorVariant = modRenderProfile->multiColor ? materialColorVariant : 0;
+ uint32_t variance = staticRandomU32(renderData.geometry.xwrap(pos[0]), pos[1], (int)variantLayer.value(terrainLayer), "mod");
+ auto& drawList = drawables[modZLevel(modRenderProfile->zLevel, mod, modHue, modColorVariant)];
+
+ MaterialPieceResultList pieces;
+ determineMatchingPieces(pieces, &occlude, materialDatabase, modRenderProfile->mainMatchList, renderData, pos,
+ terrainLayer == TerrainLayer::Background ? TileLayer::Background : TileLayer::Foreground, true);
+ for (auto const& piecePair : pieces) {
+ auto& variant = piecePair.first->variants.get(modColorVariant).wrap(variance);
+ auto image = getPieceImage(piecePair.first, variant, modHue);
+ drawList.emplace_back(Drawable::makeImage(image, scale, false, piecePair.second * scale + Vec2F(pos), color));
+ }
+ }
+
+ if (materialRenderProfile && damageLevel > 0 && isBlock) {
+ auto& drawList = drawables[damageZLevel()];
+ auto const& crackingImage = materialRenderProfile->damageImage(damageLevel, damageType);
+
+ drawList.emplace_back(Drawable::makeImage(crackingImage.first, scale, false, crackingImage.second * scale + Vec2F(pos), color));
+ }
+
+ return occlude;
+}
+
+WorldRenderData& TileDrawer::renderData() {
+ return m_tempRenderData;
+}
+
+MutexLocker TileDrawer::lockRenderData() {
+ return MutexLocker(m_tempRenderDataMutex);
+}
+
+RenderTile const& TileDrawer::getRenderTile(WorldRenderData const& renderData, Vec2I const& worldPos) {
+ Vec2I arrayPos = renderData.geometry.diff(worldPos, renderData.tileMinPosition);
+
+ Vec2I size = Vec2I(renderData.tiles.size());
+ if (arrayPos[0] >= 0 && arrayPos[1] >= 0 && arrayPos[0] < size[0] && arrayPos[1] < size[1])
+ return renderData.tiles(Vec2S(arrayPos));
+
+ return DefaultRenderTile;
+}
+
+TileDrawer::QuadZLevel TileDrawer::materialZLevel(uint32_t zLevel, MaterialId material, MaterialHue hue, MaterialColorVariant colorVariant) {
+ QuadZLevel quadZLevel = 0;
+ quadZLevel |= (uint64_t)colorVariant;
+ quadZLevel |= (uint64_t)hue << 8;
+ quadZLevel |= (uint64_t)material << 16;
+ quadZLevel |= (uint64_t)zLevel << 32;
+ return quadZLevel;
+}
+
+TileDrawer::QuadZLevel TileDrawer::modZLevel(uint32_t zLevel, ModId mod, MaterialHue hue, MaterialColorVariant colorVariant) {
+ QuadZLevel quadZLevel = 0;
+ quadZLevel |= (uint64_t)colorVariant;
+ quadZLevel |= (uint64_t)hue << 8;
+ quadZLevel |= (uint64_t)mod << 16;
+ quadZLevel |= (uint64_t)zLevel << 32;
+ quadZLevel |= (uint64_t)1 << 63;
+ return quadZLevel;
+}
+
+TileDrawer::QuadZLevel TileDrawer::damageZLevel() {
+ return (uint64_t)(-1);
+}
+
+bool TileDrawer::determineMatchingPieces(MaterialPieceResultList& resultList, bool* occlude, MaterialDatabaseConstPtr const& materialDb, MaterialRenderMatchList const& matchList,
+ WorldRenderData const& renderData, Vec2I const& basePos, TileLayer layer, bool isMod) {
+ RenderTile const& tile = getRenderTile(renderData, basePos);
+
+ auto matchSetMatches = [&](MaterialRenderMatchConstPtr const& match) -> bool {
+ if (match->requiredLayer && *match->requiredLayer != layer)
+ return false;
+
+ if (match->matchPoints.empty())
+ return true;
+
+ bool matchValid = match->matchJoin == MaterialJoinType::All;
+ for (auto const& matchPoint : match->matchPoints) {
+ auto const& neighborTile = getRenderTile(renderData, basePos + matchPoint.position);
+
+ bool neighborShadowing = false;
+ if (layer == TileLayer::Background) {
+ if (auto profile = materialDb->materialRenderProfile(neighborTile.foreground))
+ neighborShadowing = !profile->foregroundLightTransparent;
+ }
+
+ MaterialHue baseHue = layer == TileLayer::Foreground ? tile.foregroundHueShift : tile.backgroundHueShift;
+ MaterialHue neighborHue = layer == TileLayer::Foreground ? neighborTile.foregroundHueShift : neighborTile.backgroundHueShift;
+ MaterialHue baseModHue = layer == TileLayer::Foreground ? tile.foregroundModHueShift : tile.backgroundModHueShift;
+ MaterialHue neighborModHue = layer == TileLayer::Foreground ? neighborTile.foregroundModHueShift : neighborTile.backgroundModHueShift;
+ MaterialId baseMaterial = layer == TileLayer::Foreground ? tile.foreground : tile.background;
+ MaterialId neighborMaterial = layer == TileLayer::Foreground ? neighborTile.foreground : neighborTile.background;
+ ModId baseMod = layer == TileLayer::Foreground ? tile.foregroundMod : tile.backgroundMod;
+ ModId neighborMod = layer == TileLayer::Foreground ? neighborTile.foregroundMod : neighborTile.backgroundMod;
+
+ bool rulesValid = matchPoint.rule->join == MaterialJoinType::All;
+ for (auto const& ruleEntry : matchPoint.rule->entries) {
+ bool valid = true;
+ if (isMod) {
+ if (ruleEntry.rule.is<MaterialRule::RuleEmpty>()) {
+ valid = neighborMod == NoModId;
+ } else if (ruleEntry.rule.is<MaterialRule::RuleConnects>()) {
+ valid = isConnectableMaterial(neighborMaterial);
+ } else if (ruleEntry.rule.is<MaterialRule::RuleShadows>()) {
+ valid = neighborShadowing;
+ } else if (auto equalsSelf = ruleEntry.rule.ptr<MaterialRule::RuleEqualsSelf>()) {
+ valid = neighborMod == baseMod;
+ if (equalsSelf->matchHue)
+ valid = valid && baseModHue == neighborModHue;
+ } else if (auto equalsId = ruleEntry.rule.ptr<MaterialRule::RuleEqualsId>()) {
+ valid = neighborMod == equalsId->id;
+ } else if (auto propertyEquals = ruleEntry.rule.ptr<MaterialRule::RulePropertyEquals>()) {
+ if (auto profile = materialDb->modRenderProfile(neighborMod))
+ valid = profile->ruleProperties.get(propertyEquals->propertyName, Json()) == propertyEquals->compare;
+ else
+ valid = false;
+ }
+ } else {
+ if (ruleEntry.rule.is<MaterialRule::RuleEmpty>()) {
+ valid = neighborMaterial == EmptyMaterialId;
+ } else if (ruleEntry.rule.is<MaterialRule::RuleConnects>()) {
+ valid = isConnectableMaterial(neighborMaterial);
+ } else if (ruleEntry.rule.is<MaterialRule::RuleShadows>()) {
+ valid = neighborShadowing;
+ } else if (auto equalsSelf = ruleEntry.rule.ptr<MaterialRule::RuleEqualsSelf>()) {
+ valid = neighborMaterial == baseMaterial;
+ if (equalsSelf->matchHue)
+ valid = valid && baseHue == neighborHue;
+ } else if (auto equalsId = ruleEntry.rule.ptr<MaterialRule::RuleEqualsId>()) {
+ valid = neighborMaterial == equalsId->id;
+ } else if (auto propertyEquals = ruleEntry.rule.ptr<MaterialRule::RulePropertyEquals>()) {
+ if (auto profile = materialDb->materialRenderProfile(neighborMaterial))
+ valid = profile->ruleProperties.get(propertyEquals->propertyName) == propertyEquals->compare;
+ else
+ valid = false;
+ }
+ }
+ if (ruleEntry.inverse)
+ valid = !valid;
+
+ if (matchPoint.rule->join == MaterialJoinType::All) {
+ rulesValid = valid && rulesValid;
+ if (!rulesValid)
+ break;
+ } else {
+ rulesValid = valid || rulesValid;
+ }
+ }
+
+ if (match->matchJoin == MaterialJoinType::All) {
+ matchValid = matchValid && rulesValid;
+ if (!matchValid)
+ return matchValid;
+ } else {
+ matchValid = matchValid || rulesValid;
+ }
+ }
+ return matchValid;
+ };
+
+ bool subMatchResult = false;
+ for (auto const& match : matchList) {
+ if (matchSetMatches(match)) {
+ if (match->occlude)
+ *occlude = match->occlude.get();
+
+ subMatchResult = true;
+
+ for (auto const& piecePair : match->resultingPieces)
+ resultList.append({piecePair.first, piecePair.second});
+
+ if (determineMatchingPieces(resultList, occlude, materialDb, match->subMatches, renderData, basePos, layer, isMod) && match->haltOnSubMatch)
+ break;
+
+ if (match->haltOnMatch)
+ break;
+ }
+ }
+
+ return subMatchResult;
+}
+
+} \ No newline at end of file
diff --git a/source/game/StarTileDrawer.hpp b/source/game/StarTileDrawer.hpp
new file mode 100644
index 0000000..907908a
--- /dev/null
+++ b/source/game/StarTileDrawer.hpp
@@ -0,0 +1,77 @@
+#ifndef STAR_TILE_DRAWER_HPP
+#define STAR_TILE_DRAWER_HPP
+
+#include "StarTtlCache.hpp"
+#include "StarWorldRenderData.hpp"
+#include "StarMaterialRenderProfile.hpp"
+#include "StarDrawable.hpp"
+
+namespace Star {
+
+STAR_CLASS(Assets);
+STAR_CLASS(MaterialDatabase);
+STAR_CLASS(TileDrawer);
+
+class TileDrawer {
+public:
+ typedef uint64_t QuadZLevel;
+ typedef HashMap<QuadZLevel, List<Drawable>> Drawables;
+
+ typedef size_t MaterialRenderPieceIndex;
+ typedef List<pair<MaterialRenderPieceConstPtr, Vec2F>> MaterialPieceResultList;
+
+ enum class TerrainLayer { Background, Midground, Foreground };
+
+ static RenderTile DefaultRenderTile;
+
+ static TileDrawer* singletonPtr();
+ static TileDrawer& singleton();
+
+ TileDrawer();
+ ~TileDrawer();
+
+ bool produceTerrainDrawables(Drawables& drawables, TerrainLayer terrainLayer, Vec2I const& pos,
+ WorldRenderData const& renderData, float scale = 1.0f, Vec2I variantOffset = {}, Maybe<TerrainLayer> variantLayer = {});
+
+ WorldRenderData& renderData();
+ MutexLocker lockRenderData();
+
+ template <typename Function>
+ static void forEachRenderTile(WorldRenderData const& renderData, RectI const& worldCoordRange, Function&& function);
+private:
+ friend class TilePainter;
+
+ static TileDrawer* s_singleton;
+
+ static RenderTile const& getRenderTile(WorldRenderData const& renderData, Vec2I const& worldPos);
+
+ static QuadZLevel materialZLevel(uint32_t zLevel, MaterialId material, MaterialHue hue, MaterialColorVariant colorVariant);
+ static QuadZLevel modZLevel(uint32_t zLevel, ModId mod, MaterialHue hue, MaterialColorVariant colorVariant);
+ static QuadZLevel damageZLevel();
+
+ static bool determineMatchingPieces(MaterialPieceResultList& resultList, bool* occlude, MaterialDatabaseConstPtr const& materialDb, MaterialRenderMatchList const& matchList,
+ WorldRenderData const& renderData, Vec2I const& basePos, TileLayer layer, bool isMod);
+
+ Vec4B m_backgroundLayerColor;
+ Vec4B m_foregroundLayerColor;
+ Vec2F m_liquidDrawLevels;
+
+ WorldRenderData m_tempRenderData;
+ Mutex m_tempRenderDataMutex;
+};
+
+template <typename Function>
+void TileDrawer::forEachRenderTile(WorldRenderData const& renderData, RectI const& worldCoordRange, Function&& function) {
+ RectI indexRect = RectI::withSize(renderData.geometry.diff(worldCoordRange.min(), renderData.tileMinPosition), worldCoordRange.size());
+ indexRect.limit(RectI::withSize(Vec2I(0, 0), Vec2I(renderData.tiles.size())));
+
+ if (!indexRect.isEmpty()) {
+ renderData.tiles.forEach(Array2S(indexRect.min()), Array2S(indexRect.size()), [&](Array2S const& index, RenderTile const& tile) {
+ return function(worldCoordRange.min() + (Vec2I(index) - indexRect.min()), tile);
+ });
+ }
+}
+
+}
+
+#endif \ No newline at end of file
diff --git a/source/game/StarToolUser.cpp b/source/game/StarToolUser.cpp
index 7208c6e..dd6f5ff 100644
--- a/source/game/StarToolUser.cpp
+++ b/source/game/StarToolUser.cpp
@@ -536,9 +536,9 @@ void ToolUser::render(RenderCallback* renderCallback, bool inToolRange, bool shi
}
if (auto pri = as<PreviewTileTool>(m_primaryHandItem.get()))
- renderCallback->addTilePreviews(pri->preview(shifting));
+ renderCallback->addTilePreviews(pri->previewTiles(shifting));
else if (auto alt = as<PreviewTileTool>(m_altHandItem.get()))
- renderCallback->addTilePreviews(alt->preview(shifting));
+ renderCallback->addTilePreviews(alt->previewTiles(shifting));
if (auto ren = as<RenderableItem>(m_primaryHandItem.get()))
ren->render(renderCallback, renderLayer);
diff --git a/source/game/interfaces/StarPreviewTileTool.hpp b/source/game/interfaces/StarPreviewTileTool.hpp
index dfc53bf..12a4b2b 100644
--- a/source/game/interfaces/StarPreviewTileTool.hpp
+++ b/source/game/interfaces/StarPreviewTileTool.hpp
@@ -12,7 +12,7 @@ namespace Star {
class PreviewTileTool {
public:
virtual ~PreviewTileTool() {}
- virtual List<PreviewTile> preview(bool shifting) const = 0;
+ virtual List<PreviewTile> previewTiles(bool shifting) const = 0;
};
}
diff --git a/source/game/items/StarLiquidItem.cpp b/source/game/items/StarLiquidItem.cpp
index 08e202f..2e887aa 100644
--- a/source/game/items/StarLiquidItem.cpp
+++ b/source/game/items/StarLiquidItem.cpp
@@ -85,7 +85,7 @@ float LiquidItem::liquidQuantity() const {
return m_quantity;
}
-List<PreviewTile> LiquidItem::preview(bool shifting) const {
+List<PreviewTile> LiquidItem::previewTiles(bool shifting) const {
List<PreviewTile> result;
if (initialized()) {
auto liquid = liquidId();
diff --git a/source/game/items/StarLiquidItem.hpp b/source/game/items/StarLiquidItem.hpp
index 03a73cd..b4c4cfc 100644
--- a/source/game/items/StarLiquidItem.hpp
+++ b/source/game/items/StarLiquidItem.hpp
@@ -28,7 +28,7 @@ public:
LiquidId liquidId() const;
float liquidQuantity() const;
- List<PreviewTile> preview(bool shifting) const override;
+ List<PreviewTile> previewTiles(bool shifting) const override;
bool canPlace(bool shifting) const;
bool canPlaceAtTile(Vec2I pos) const;
diff --git a/source/game/items/StarMaterialItem.cpp b/source/game/items/StarMaterialItem.cpp
index f2f15da..2740eb7 100644
--- a/source/game/items/StarMaterialItem.cpp
+++ b/source/game/items/StarMaterialItem.cpp
@@ -8,6 +8,7 @@
#include "StarWorldClient.hpp"
#include "StarWorldTemplate.hpp"
#include "StarInput.hpp"
+#include "StarTileDrawer.hpp"
namespace Star {
@@ -17,6 +18,7 @@ MaterialItem::MaterialItem(Json const& config, String const& directory, Json con
: Item(config, directory, settings), FireableItem(config), BeamItem(config) {
m_material = config.getInt("materialId");
m_materialHueShift = materialHueFromDegrees(instanceValue("materialHueShift", 0).toFloat());
+ auto materialDatabase = Root::singleton().materialDatabase();
if (materialHueShift() != MaterialHue()) {
auto drawables = iconDrawables();
@@ -36,7 +38,6 @@ MaterialItem::MaterialItem(Json const& config, String const& directory, Json con
m_blockRadius = instanceValue("blockRadius", defaultParameters.getFloat("blockRadius")).toFloat();
m_altBlockRadius = instanceValue("altBlockRadius", defaultParameters.getFloat("altBlockRadius")).toFloat();
- auto materialDatabase = Root::singleton().materialDatabase();
auto multiplace = instanceValue("allowMultiplace", BlockCollisionSet.contains(materialDatabase->materialCollisionKind(m_material)));
if (multiplace.isType(Json::Type::Bool))
m_multiplace = multiplace.toBool();
@@ -96,16 +97,16 @@ void MaterialItem::update(float dt, FireMode fireMode, bool shifting, HashSet<Mo
owner()->addSound("/sfx/tools/cyclematcollision.ogg", 1.0f, Random::randf(0.9f, 1.1f));
}
- if (auto presses = input.bindDown("opensb", "materialRadiusGrow")) {
+ if (auto presses = input.bindDown("opensb", "buildingRadiusGrow")) {
m_blockRadius = min(BlockRadiusLimit, int(m_blockRadius + *presses));
setInstanceValue("blockRadius", m_blockRadius);
- owner()->addSound("/sfx/tools/matradiusgrow.wav", 1.0f, 1.0f + m_blockRadius / BlockRadiusLimit);
+ owner()->addSound("/sfx/tools/buildradiusgrow.wav", 1.0f, 1.0f + m_blockRadius / BlockRadiusLimit);
}
- if (auto presses = input.bindDown("opensb", "materialRadiusShrink")) {
+ if (auto presses = input.bindDown("opensb", "buildingRadiusShrink")) {
m_blockRadius = max(1, int(m_blockRadius - *presses));
setInstanceValue("blockRadius", m_blockRadius);
- owner()->addSound("/sfx/tools/matradiusshrink.wav", 1.0f, 1.0f + m_blockRadius / BlockRadiusLimit);
+ owner()->addSound("/sfx/tools/buildradiusshrink.wav", 1.0f, 1.0f + m_blockRadius / BlockRadiusLimit);
}
}
else {
@@ -148,6 +149,14 @@ void MaterialItem::render(RenderCallback* renderCallback, EntityRenderLayer rend
}
}
+List<Drawable> MaterialItem::preview(PlayerPtr const&) const {
+ return generatedPreview();
+}
+
+List<Drawable> MaterialItem::dropDrawables() const {
+ return generatedPreview();
+}
+
List<Drawable> MaterialItem::nonRotatedDrawables() const {
return beamDrawables(canPlace(m_shifting));
}
@@ -218,6 +227,47 @@ MaterialId MaterialItem::materialId() const {
return m_material;
}
+List<Drawable> const& MaterialItem::generatedPreview(Vec2I position) const {
+ if (!m_generatedPreviewCache) {
+ if (TileDrawer* tileDrawer = TileDrawer::singletonPtr()) {
+ auto locker = tileDrawer->lockRenderData();
+ WorldRenderData& renderData = tileDrawer->renderData();
+ renderData.geometry = WorldGeometry(3, 3);
+ renderData.tiles.resize({ 3, 3 });
+ renderData.tiles.fill(TileDrawer::DefaultRenderTile);
+ renderData.tileMinPosition = { 0, 0 };
+ RenderTile& tile = renderData.tiles.at({ 1, 1 });
+ tile.foreground = m_material;
+ tile.foregroundHueShift = m_materialHueShift;
+ tile.foregroundColorVariant = 0;
+
+ List<Drawable> drawables;
+ TileDrawer::Drawables tileDrawables;
+ bool isBlock = BlockCollisionSet.contains(Root::singleton().materialDatabase()->materialCollisionKind(m_material));
+ TileDrawer::TerrainLayer layer = isBlock ? TileDrawer::TerrainLayer::Foreground : TileDrawer::TerrainLayer::Midground;
+ for (int x = 0; x != 3; ++x) {
+ for (int y = 0; y != 3; ++y)
+ tileDrawer->produceTerrainDrawables(tileDrawables, layer, { x, y }, renderData, 1.0f / TilePixels, position - Vec2I(1, 1));
+ }
+
+ locker.unlock();
+ for (auto& index : tileDrawables.keys())
+ drawables.appendAll(tileDrawables.take(index));
+
+ auto boundBox = Drawable::boundBoxAll(drawables, true);
+ if (!boundBox.isEmpty()) {
+ for (auto& drawable : drawables)
+ drawable.translate(-boundBox.center());
+ }
+
+ m_generatedPreviewCache.emplace(move(drawables));
+ }
+ else
+ m_generatedPreviewCache.emplace(iconDrawables());
+ }
+ return *m_generatedPreviewCache;
+}
+
float MaterialItem::calcRadius(bool shifting) const {
if (!multiplaceEnabled())
return 1;
@@ -270,7 +320,7 @@ TileCollisionOverride& MaterialItem::collisionOverride() {
return m_collisionOverride;
}
-List<PreviewTile> MaterialItem::preview(bool shifting) const {
+List<PreviewTile> MaterialItem::previewTiles(bool shifting) const {
List<PreviewTile> result;
if (initialized()) {
Color lightColor = Color::rgba(owner()->favoriteColor());
diff --git a/source/game/items/StarMaterialItem.hpp b/source/game/items/StarMaterialItem.hpp
index 05f9e08..363d248 100644
--- a/source/game/items/StarMaterialItem.hpp
+++ b/source/game/items/StarMaterialItem.hpp
@@ -7,13 +7,15 @@
#include "StarEntityRendering.hpp"
#include "StarPreviewTileTool.hpp"
#include "StarRenderableItem.hpp"
+#include "StarPreviewableItem.hpp"
#include "StarCollisionBlock.hpp"
namespace Star {
STAR_CLASS(MaterialItem);
+STAR_CLASS(Player);
-class MaterialItem : public Item, public FireableItem, public PreviewTileTool, public RenderableItem, public BeamItem {
+class MaterialItem : public Item, public FireableItem, public PreviewTileTool, public RenderableItem, public PreviewableItem, public BeamItem {
public:
MaterialItem(Json const& config, String const& directory, Json const& settings);
virtual ~MaterialItem() {}
@@ -25,6 +27,8 @@ public:
void update(float dt, FireMode fireMode, bool shifting, HashSet<MoveControlType> const& moves) override;
void render(RenderCallback* renderCallback, EntityRenderLayer renderLayer) override;
+ virtual List<Drawable> preview(PlayerPtr const& viewer = {}) const override;
+ virtual List<Drawable> dropDrawables() const override;
List<Drawable> nonRotatedDrawables() const override;
void fire(FireMode mode, bool shifting, bool edgeTriggered) override;
@@ -40,7 +44,8 @@ public:
float& altBlockRadius();
TileCollisionOverride& collisionOverride();
- List<PreviewTile> preview(bool shifting) const override;
+ List<PreviewTile> previewTiles(bool shifting) const override;
+ List<Drawable> const& generatedPreview(Vec2I position = {}) const;
private:
float calcRadius(bool shifting) const;
List<Vec2I>& tileArea(float radius, Vec2F const& position) const;
@@ -60,6 +65,8 @@ private:
mutable Vec2F m_lastTileAreaOriginCache;
mutable float m_lastTileAreaRadiusCache;
mutable List<Vec2I> m_tileAreasCache;
+
+ mutable Maybe<List<Drawable>> m_generatedPreviewCache;
};
}
diff --git a/source/game/items/StarTools.cpp b/source/game/items/StarTools.cpp
index 602e554..7faaeae 100644
--- a/source/game/items/StarTools.cpp
+++ b/source/game/items/StarTools.cpp
@@ -360,7 +360,7 @@ void BeamMiningTool::setEnd(EndType) {
m_endType = EndType::Object;
}
-List<PreviewTile> BeamMiningTool::preview(bool shifting) const {
+List<PreviewTile> BeamMiningTool::previewTiles(bool shifting) const {
List<PreviewTile> result;
auto ownerp = owner();
auto worldp = world();
@@ -636,7 +636,7 @@ void PaintingBeamTool::update(float dt, FireMode fireMode, bool shifting, HashSe
FireableItem::update(dt, fireMode, shifting, moves);
}
-List<PreviewTile> PaintingBeamTool::preview(bool shifting) const {
+List<PreviewTile> PaintingBeamTool::previewTiles(bool shifting) const {
List<PreviewTile> result;
auto ownerp = owner();
auto worldp = world();
diff --git a/source/game/items/StarTools.hpp b/source/game/items/StarTools.hpp
index fbe79a0..75cdcaf 100644
--- a/source/game/items/StarTools.hpp
+++ b/source/game/items/StarTools.hpp
@@ -150,7 +150,7 @@ public:
List<Drawable> drawables() const override;
virtual void setEnd(EndType type) override;
- virtual List<PreviewTile> preview(bool shifting) const override;
+ virtual List<PreviewTile> previewTiles(bool shifting) const override;
virtual List<Drawable> nonRotatedDrawables() const override;
virtual void fire(FireMode mode, bool shifting, bool edgeTriggered) override;
@@ -219,7 +219,7 @@ public:
void setEnd(EndType type) override;
void update(float dt, FireMode fireMode, bool shifting, HashSet<MoveControlType> const& moves) override;
- List<PreviewTile> preview(bool shifting) const override;
+ List<PreviewTile> previewTiles(bool shifting) const override;
void init(ToolUserEntity* owner, ToolHand hand) override;
List<Drawable> nonRotatedDrawables() const override;
void fire(FireMode mode, bool shifting, bool edgeTriggered) override;
diff --git a/source/rendering/StarTilePainter.cpp b/source/rendering/StarTilePainter.cpp
index 40b3de6..de49910 100644
--- a/source/rendering/StarTilePainter.cpp
+++ b/source/rendering/StarTilePainter.cpp
@@ -6,10 +6,11 @@
#include "StarLiquidsDatabase.hpp"
#include "StarAssets.hpp"
#include "StarRoot.hpp"
+#include "StarTileDrawer.hpp"
namespace Star {
-TilePainter::TilePainter(RendererPtr renderer) {
+TilePainter::TilePainter(RendererPtr renderer) : TileDrawer() {
m_renderer = move(renderer);
m_textureGroup = m_renderer->createTextureGroup(TextureGroupSize::Large);
@@ -24,10 +25,6 @@ TilePainter::TilePainter(RendererPtr renderer) {
m_textureCache.setTimeToLive(assets->json("/rendering.config:textureTimeout").toInt());
- m_backgroundLayerColor = jsonToColor(assets->json("/rendering.config:backgroundLayerColor")).toRgba();
- m_foregroundLayerColor = jsonToColor(assets->json("/rendering.config:foregroundLayerColor")).toRgba();
- m_liquidDrawLevels = jsonToVec2F(assets->json("/rendering.config:liquidDrawLevels"));
-
for (auto const& liquid : root.liquidsDatabase()->allLiquidSettings()) {
m_liquids.set(liquid->id, LiquidInfo{
m_renderer->createTexture(*assets->image(liquid->config.getString("texture")), TextureAddressing::Wrap),
@@ -152,57 +149,6 @@ TilePainter::ChunkHash TilePainter::liquidChunkHash(WorldRenderData& renderData,
return XXH3_64bits(buffer.ptr(), buffer.size());
}
-TilePainter::QuadZLevel TilePainter::materialZLevel(uint32_t zLevel, MaterialId material, MaterialHue hue, MaterialColorVariant colorVariant) {
- QuadZLevel quadZLevel = 0;
- quadZLevel |= (uint64_t)colorVariant;
- quadZLevel |= (uint64_t)hue << 8;
- quadZLevel |= (uint64_t)material << 16;
- quadZLevel |= (uint64_t)zLevel << 32;
- return quadZLevel;
-}
-
-TilePainter::QuadZLevel TilePainter::modZLevel(uint32_t zLevel, ModId mod, MaterialHue hue, MaterialColorVariant colorVariant) {
- QuadZLevel quadZLevel = 0;
- quadZLevel |= (uint64_t)colorVariant;
- quadZLevel |= (uint64_t)hue << 8;
- quadZLevel |= (uint64_t)mod << 16;
- quadZLevel |= (uint64_t)zLevel << 32;
- quadZLevel |= (uint64_t)1 << 63;
- return quadZLevel;
-}
-
-TilePainter::QuadZLevel TilePainter::damageZLevel() {
- return (uint64_t)(-1);
-}
-
-RenderTile const& TilePainter::getRenderTile(WorldRenderData const& renderData, Vec2I const& worldPos) {
- Vec2I arrayPos = renderData.geometry.diff(worldPos, renderData.tileMinPosition);
-
- Vec2I size = Vec2I(renderData.tiles.size());
- if (arrayPos[0] >= 0 && arrayPos[1] >= 0 && arrayPos[0] < size[0] && arrayPos[1] < size[1])
- return renderData.tiles(Vec2S(arrayPos));
-
- static RenderTile defaultRenderTile = {
- NullMaterialId,
- NoModId,
- NullMaterialId,
- NoModId,
- 0,
- 0,
- DefaultMaterialColorVariant,
- TileDamageType::Protected,
- 0,
- 0,
- 0,
- DefaultMaterialColorVariant,
- TileDamageType::Protected,
- 0,
- EmptyLiquidId,
- 0
- };
- return defaultRenderTile;
-}
-
void TilePainter::renderTerrainChunks(WorldCamera const& camera, TerrainLayer terrainLayer) {
Map<QuadZLevel, List<RenderBufferPtr>> zOrderBuffers;
for (auto const& chunk : m_pendingTerrainChunks) {
@@ -285,7 +231,7 @@ bool TilePainter::produceTerrainPrimitives(HashMap<QuadZLevel, List<RenderPrimit
MaterialId material = EmptyMaterialId;
MaterialHue materialHue = 0;
- MaterialHue materialColorVariant = 0;
+ MaterialColorVariant materialColorVariant = 0;
ModId mod = NoModId;
MaterialHue modHue = 0;
float damageLevel = 0.0f;
@@ -316,7 +262,7 @@ bool TilePainter::produceTerrainPrimitives(HashMap<QuadZLevel, List<RenderPrimit
// render non-block colliding things in the midground
bool isBlock = BlockCollisionSet.contains(materialDatabase->materialCollisionKind(material));
- if ((isBlock && terrainLayer == TerrainLayer::Midground) || (!isBlock && terrainLayer == TerrainLayer::Foreground))
+ if (terrainLayer == (isBlock ? TerrainLayer::Midground : TerrainLayer::Foreground))
return false;
auto getPieceTexture = [this, assets](MaterialId material, MaterialRenderPieceConstPtr const& piece, MaterialHue hue, bool mod) {
@@ -423,7 +369,7 @@ void TilePainter::produceLiquidPrimitives(HashMap<LiquidId, List<RenderPrimitive
auto texRect = worldRect.scaled(TilePixels);
auto const& liquid = m_liquids[tile.liquidId];
- primitives[tile.liquidId].emplace_back(std::in_place_type_t<RenderQuad>(), move(liquid.texture),
+ primitives[tile.liquidId].emplace_back(std::in_place_type_t<RenderQuad>(), liquid.texture,
worldRect.min(), texRect.min(),
Vec2F(worldRect.xMax(), worldRect.yMin()), Vec2F(texRect.xMax(), texRect.yMin()),
worldRect.max(), texRect.max(),
@@ -431,123 +377,6 @@ void TilePainter::produceLiquidPrimitives(HashMap<LiquidId, List<RenderPrimitive
liquid.color, 1.0f);
}
-bool TilePainter::determineMatchingPieces(MaterialPieceResultList& resultList, bool* occlude, MaterialDatabaseConstPtr const& materialDb, MaterialRenderMatchList const& matchList,
- WorldRenderData const& renderData, Vec2I const& basePos, TileLayer layer, bool isMod) {
- RenderTile const& tile = getRenderTile(renderData, basePos);
-
- auto matchSetMatches = [&](MaterialRenderMatchConstPtr const& match) -> bool {
- if (match->requiredLayer && *match->requiredLayer != layer)
- return false;
-
- if (match->matchPoints.empty())
- return true;
-
- bool matchValid = match->matchJoin == MaterialJoinType::All;
- for (auto const& matchPoint : match->matchPoints) {
- auto const& neighborTile = getRenderTile(renderData, basePos + matchPoint.position);
-
- bool neighborShadowing = false;
- if (layer == TileLayer::Background) {
- if (auto profile = materialDb->materialRenderProfile(neighborTile.foreground))
- neighborShadowing = !profile->foregroundLightTransparent;
- }
-
- MaterialHue baseHue = layer == TileLayer::Foreground ? tile.foregroundHueShift : tile.backgroundHueShift;
- MaterialHue neighborHue = layer == TileLayer::Foreground ? neighborTile.foregroundHueShift : neighborTile.backgroundHueShift;
- MaterialHue baseModHue = layer == TileLayer::Foreground ? tile.foregroundModHueShift : tile.backgroundModHueShift;
- MaterialHue neighborModHue = layer == TileLayer::Foreground ? neighborTile.foregroundModHueShift : neighborTile.backgroundModHueShift;
- MaterialId baseMaterial = layer == TileLayer::Foreground ? tile.foreground : tile.background;
- MaterialId neighborMaterial = layer == TileLayer::Foreground ? neighborTile.foreground : neighborTile.background;
- ModId baseMod = layer == TileLayer::Foreground ? tile.foregroundMod : tile.backgroundMod;
- ModId neighborMod = layer == TileLayer::Foreground ? neighborTile.foregroundMod : neighborTile.backgroundMod;
-
- bool rulesValid = matchPoint.rule->join == MaterialJoinType::All;
- for (auto const& ruleEntry : matchPoint.rule->entries) {
- bool valid = true;
- if (isMod) {
- if (ruleEntry.rule.is<MaterialRule::RuleEmpty>()) {
- valid = neighborMod == NoModId;
- } else if (ruleEntry.rule.is<MaterialRule::RuleConnects>()) {
- valid = isConnectableMaterial(neighborMaterial);
- } else if (ruleEntry.rule.is<MaterialRule::RuleShadows>()) {
- valid = neighborShadowing;
- } else if (auto equalsSelf = ruleEntry.rule.ptr<MaterialRule::RuleEqualsSelf>()) {
- valid = neighborMod == baseMod;
- if (equalsSelf->matchHue)
- valid = valid && baseModHue == neighborModHue;
- } else if (auto equalsId = ruleEntry.rule.ptr<MaterialRule::RuleEqualsId>()) {
- valid = neighborMod == equalsId->id;
- } else if (auto propertyEquals = ruleEntry.rule.ptr<MaterialRule::RulePropertyEquals>()) {
- if (auto profile = materialDb->modRenderProfile(neighborMod))
- valid = profile->ruleProperties.get(propertyEquals->propertyName, Json()) == propertyEquals->compare;
- else
- valid = false;
- }
- } else {
- if (ruleEntry.rule.is<MaterialRule::RuleEmpty>()) {
- valid = neighborMaterial == EmptyMaterialId;
- } else if (ruleEntry.rule.is<MaterialRule::RuleConnects>()) {
- valid = isConnectableMaterial(neighborMaterial);
- } else if (ruleEntry.rule.is<MaterialRule::RuleShadows>()) {
- valid = neighborShadowing;
- } else if (auto equalsSelf = ruleEntry.rule.ptr<MaterialRule::RuleEqualsSelf>()) {
- valid = neighborMaterial == baseMaterial;
- if (equalsSelf->matchHue)
- valid = valid && baseHue == neighborHue;
- } else if (auto equalsId = ruleEntry.rule.ptr<MaterialRule::RuleEqualsId>()) {
- valid = neighborMaterial == equalsId->id;
- } else if (auto propertyEquals = ruleEntry.rule.ptr<MaterialRule::RulePropertyEquals>()) {
- if (auto profile = materialDb->materialRenderProfile(neighborMaterial))
- valid = profile->ruleProperties.get(propertyEquals->propertyName) == propertyEquals->compare;
- else
- valid = false;
- }
- }
- if (ruleEntry.inverse)
- valid = !valid;
-
- if (matchPoint.rule->join == MaterialJoinType::All) {
- rulesValid = valid && rulesValid;
- if (!rulesValid)
- break;
- } else {
- rulesValid = valid || rulesValid;
- }
- }
-
- if (match->matchJoin == MaterialJoinType::All) {
- matchValid = matchValid && rulesValid;
- if (!matchValid)
- return matchValid;
- } else {
- matchValid = matchValid || rulesValid;
- }
- }
- return matchValid;
- };
-
- bool subMatchResult = false;
- for (auto const& match : matchList) {
- if (matchSetMatches(match)) {
- if (match->occlude)
- *occlude = match->occlude.get();
-
- subMatchResult = true;
-
- for (auto const& piecePair : match->resultingPieces)
- resultList.append({piecePair.first, piecePair.second});
-
- if (determineMatchingPieces(resultList, occlude, materialDb, match->subMatches, renderData, basePos, layer, isMod) && match->haltOnSubMatch)
- break;
-
- if (match->haltOnMatch)
- break;
- }
- }
-
- return subMatchResult;
-}
-
float TilePainter::liquidDrawLevel(float liquidLevel) const {
return clamp((liquidLevel - m_liquidDrawLevels[0]) / (m_liquidDrawLevels[1] - m_liquidDrawLevels[0]), 0.0f, 1.0f);
}
diff --git a/source/rendering/StarTilePainter.hpp b/source/rendering/StarTilePainter.hpp
index 9e21850..3126a16 100644
--- a/source/rendering/StarTilePainter.hpp
+++ b/source/rendering/StarTilePainter.hpp
@@ -6,6 +6,7 @@
#include "StarMaterialRenderProfile.hpp"
#include "StarRenderer.hpp"
#include "StarWorldCamera.hpp"
+#include "StarTileDrawer.hpp"
namespace Star {
@@ -13,7 +14,7 @@ STAR_CLASS(Assets);
STAR_CLASS(MaterialDatabase);
STAR_CLASS(TilePainter);
-class TilePainter {
+class TilePainter : public TileDrawer {
public:
// The rendered tiles are split and cached in chunks of RenderChunkSize x
// RenderChunkSize. This means that, around the border, there may be as many
@@ -62,13 +63,10 @@ private:
typedef HashMap<TerrainLayer, HashMap<QuadZLevel, RenderBufferPtr>> TerrainChunk;
typedef HashMap<LiquidId, RenderBufferPtr> LiquidChunk;
- typedef size_t MaterialRenderPieceIndex;
typedef tuple<MaterialId, MaterialRenderPieceIndex, MaterialHue, bool> MaterialPieceTextureKey;
typedef String AssetTextureKey;
typedef Variant<MaterialPieceTextureKey, AssetTextureKey> TextureKey;
- typedef List<pair<MaterialRenderPieceConstPtr, Vec2F>> MaterialPieceResultList;
-
struct TextureKeyHash {
size_t operator()(TextureKey const& key) const;
};
@@ -80,15 +78,6 @@ private:
static ChunkHash terrainChunkHash(WorldRenderData& renderData, Vec2I chunkIndex);
static ChunkHash liquidChunkHash(WorldRenderData& renderData, Vec2I chunkIndex);
- static QuadZLevel materialZLevel(uint32_t zLevel, MaterialId material, MaterialHue hue, MaterialColorVariant colorVariant);
- static QuadZLevel modZLevel(uint32_t zLevel, ModId mod, MaterialHue hue, MaterialColorVariant colorVariant);
- static QuadZLevel damageZLevel();
-
- static RenderTile const& getRenderTile(WorldRenderData const& renderData, Vec2I const& worldPos);
-
- template <typename Function>
- static void forEachRenderTile(WorldRenderData const& renderData, RectI const& worldCoordRange, Function&& function);
-
void renderTerrainChunks(WorldCamera const& camera, TerrainLayer terrainLayer);
shared_ptr<TerrainChunk const> getTerrainChunk(WorldRenderData& renderData, Vec2I chunkIndex);
@@ -98,17 +87,10 @@ private:
TerrainLayer terrainLayer, Vec2I const& pos, WorldRenderData const& renderData);
void produceLiquidPrimitives(HashMap<LiquidId, List<RenderPrimitive>>& primitives, Vec2I const& pos, WorldRenderData const& renderData);
- bool determineMatchingPieces(MaterialPieceResultList& resultList, bool* occlude, MaterialDatabaseConstPtr const& materialDb, MaterialRenderMatchList const& matchList,
- WorldRenderData const& renderData, Vec2I const& basePos, TileLayer layer, bool isMod);
-
float liquidDrawLevel(float liquidLevel) const;
List<LiquidInfo> m_liquids;
- Vec4B m_backgroundLayerColor;
- Vec4B m_foregroundLayerColor;
- Vec2F m_liquidDrawLevels;
-
RendererPtr m_renderer;
TextureGroupPtr m_textureGroup;
@@ -123,18 +105,6 @@ private:
Vec2F m_cameraPan;
};
-template <typename Function>
-void TilePainter::forEachRenderTile(WorldRenderData const& renderData, RectI const& worldCoordRange, Function&& function) {
- RectI indexRect = RectI::withSize(renderData.geometry.diff(worldCoordRange.min(), renderData.tileMinPosition), worldCoordRange.size());
- indexRect.limit(RectI::withSize(Vec2I(0, 0), Vec2I(renderData.tiles.size())));
-
- if (!indexRect.isEmpty()) {
- renderData.tiles.forEach(Array2S(indexRect.min()), Array2S(indexRect.size()), [&](Array2S const& index, RenderTile const& tile) {
- return function(worldCoordRange.min() + (Vec2I(index) - indexRect.min()), tile);
- });
- }
-}
-
}
#endif