src/polygoncache.cpp

Sat, 08 Apr 2023 12:55:11 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Sat, 08 Apr 2023 12:55:11 +0300
changeset 343
4a82990affd5
parent 338
719b909a7d2b
child 358
ef90ed0a5720
permissions
-rw-r--r--

Fix BFC formatting not working due to being evaluated after comment format

#include "src/circularprimitive.h"
#include "src/documentmanager.h"
#include "src/invert.h"
#include "src/polygoncache.h"
#include "src/parser.h"

QTextDocument* resolve(const QString& name, const ModelId callingModelId, DocumentManager* documents)
{
	return documents->findDependencyByName(callingModelId, name);
}

static PolygonElement transformed(
	PolygonElement element,
	const glm::mat4& transform)
{
	visitPoints([&transform](glm::vec3& p) {
		p = transform * glm::vec4{p, 1};
	}, element);
	return element;
}

PolygonCache* findPolygonCacheForModel(QTextDocument* model, DocumentManager* context)
{
	std::optional<ModelId> modelId = context->findIdForModel(model);
	if (modelId.has_value()) {
		return context->getPolygonCacheForModel(modelId.value());
	}
	else {
		return nullptr;
	}
}

constexpr bool n_xor(bool a)
{
	return a;
}

template<typename... Args>
constexpr bool n_xor(bool a, Args&&... rest)
{
	return a xor n_xor(rest...);
}

namespace {
struct GetPolygonsContext
{
	bool invertnext = false;
	ModelId modelId;
	class DocumentManager* documents;
};
}

template<typename Fn, typename Fn2>
static void inlineSubfileReference(
	const PolygonCache::vector_type& polygons,
	const Colored<SubfileReference>& ref,
	GetPolygonsContext* context,
	Fn&& add,
	Fn2&& reserve)
{
	const bool needInverting = 0
		^ (glm::determinant(ref.transformation) < 0)
		^ (context->invertnext);
	reserve(polygons.size());
	for (const PolygonElement& cacheElement : polygons) {
		PolygonElement polygon = transformed(cacheElement, ref.transformation);
		if (needInverting) {
			gl::invert(polygon);
		}
		if (polygon.color == MAIN_COLOR) {
			polygon.color = ref.color;
		}
		add(polygon);
	}
}

static QTextDocument* findDependency(const SubfileReference& ref, GetPolygonsContext* context)
{
	return context->documents->findDependencyByName(context->modelId, ref.name);
}

template<typename Fn, typename Fn2>
static void collectPolygons(
	const ParsedLine& element,
	Winding& winding,
	GetPolygonsContext* context,
	Fn&& add,
	Fn2&& reserve)
{
	bool foundinvertnext = false;
	std::visit<void>(overloaded{
		[&](const LineType0& line0) {
			const QString text = line0.value.text.simplified();
			if (text == QStringLiteral("BFC INVERTNEXT")) {
				context->invertnext = true;
				foundinvertnext = true;
			}
			else if (text == QStringLiteral("BFC CERTIFY CW")) {
				winding = Clockwise;
			}
			else if (text == QStringLiteral("BFC CERTIFY CCW")) {
				winding = Anticlockwise;
			}
			else if (text == QStringLiteral("BFC NOCERTIFY")) {
				winding = NoWinding;
			}
		},
		[&](const LineType2& line2) {
			add({line2.value, line2.value.color});
		},
		[&](const LineType3& line3) {
			add({line3.value, line3.value.color});
		},
		[&](const LineType4& line4) {
			add({line4.value, line4.value.color});
		},
		[&](const LineType5& line5) {
			add({line5.value, line5.value.color});
		},
		[&add, context, &reserve](const LineType1& line1) {
			QTextDocument* const dependency = findDependency(line1.value, context);
			if (PolygonCache* cache = (dependency != nullptr)
				? findPolygonCacheForModel(dependency, context->documents)
				: nullptr
			) {
				recacheIfNeeded(cache, dependency, context->documents);
				inlineSubfileReference(cache->polygons, line1.value, context, add, reserve);
			}
		},
	#if 0
		[&add](const Colored<CircularPrimitive>& circ) {
			rasterize(circ, [&](const PlainPolygonElement& polygon, ColorIndex color){
				if (color == MAIN_COLOR) {
					color = circ.color;
				}
				add(PolygonElement{polygon, color});
			});
		},
	#endif
	}, element);
	if (not foundinvertnext) {
		context->invertnext = false;
	}
}

static std::vector<WithId<PolygonElement>> inlinePolygons(
	const QTextDocument* model,
	GetPolygonsContext* context)
{
	Winding winding = NoWinding;
	std::vector<WithId<PolygonElement>> result;
	int i = 0;
	const auto add = [&result, winding, i](const PolygonElement& poly){
		result.push_back({poly, i});
		if (winding == Winding::Clockwise) {
			gl::invert(result.back());
		}
	};
	const auto reserve = [&result](std::size_t incomingsize){
		reserveMore(result, incomingsize);
	};
	for (const QString& line : model->toPlainText().split("\n")) {
		const opt<ParsedLine> parsedline = parse(line);
		if (parsedline.has_value()) {
			collectPolygons(*parsedline, winding, context, add, reserve);
		}
		++i;
	}
	return result;
}

void recacheIfNeeded(PolygonCache *cache, QTextDocument *model, DocumentManager *documents)
{
	if (cache->needRecache)
	{
		cache->polygons.clear();
		const std::optional<ModelId> modelId = documents->findIdForModel(model);
		if (modelId.has_value())
		{
			GetPolygonsContext context{
				.invertnext = false,
				.modelId = *modelId,
				.documents = documents,
			};
			cache->polygons = inlinePolygons(model, &context);
		}
		cache->needRecache = false;
	}
}

mercurial