src/linetypes/propertygenerics.h

Wed, 25 May 2022 20:36:34 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Wed, 25 May 2022 20:36:34 +0300
changeset 199
6988973515d2
parent 186
922662adb72a
permissions
-rw-r--r--

Fix pick() picking from weird places on the screen with high DPI scaling

glReadPixels reads data from the frame buffer, which contains data after
high DPI scaling, so any reads to that need to take this scaling into account

#pragma once
#include "main.h"
#include "colors.h"

class Vec3Editor;
class MatrixEditor;

namespace ldraw
{
	enum CircularPrimitiveType
	{
		Circle,
		Disc
	};
	enum class Property;
	struct PropertyKeyValue;
	template<Property property>
	struct PropertyTraits
	{
		static constexpr bool defined = false;
	};
}

Q_DECLARE_METATYPE(ldraw::CircularPrimitiveType)

/**
 * Different properties
 */
enum class ldraw::Property
{
	Color, // Color of the object
	Text, // Text contained in a comment
	Point0, // First vertex in a polygon or edge line
	Point1, // Second vertex in a polygon or edge line
	Point2, // Third vertex in a polygon
	Point3, // Fourth vertex in a quadrilateral
	Transformation, // 4x4 transformation matrix of a subfile reference
	ReferenceName, // Subfile reference name
	IsInverted, // Whether or not the object has been inverted with BFC INVERTNEXT
	ErrorMessage, // For error lines, why parsing failed
	CircularPrimitiveType, // Type of circular primitive (circle, disc, ...)
	Segments, // Amount of circular segments this primitive covers (numerator)
	Divisions, // Amount of segments in the circle this primitive fits in (8, 16, 48, ...)
};

Q_DECLARE_METATYPE(ldraw::Property)

// Mapping of properties to types
#define LDFORGE_DEFINE_PROPERTY_TYPE(PROPERTY, TYPE) \
	namespace ldraw \
	{ \
		template<> struct PropertyTraits<ldraw::Property::PROPERTY> \
		{ \
			using type = TYPE; \
			static constexpr std::array<char, 256> name{#PROPERTY}; \
			static constexpr bool defined = true; \
		}; \
	}

LDFORGE_DEFINE_PROPERTY_TYPE(Color, ldraw::Color)
LDFORGE_DEFINE_PROPERTY_TYPE(Text, QString)
LDFORGE_DEFINE_PROPERTY_TYPE(Point0, glm::vec3)
LDFORGE_DEFINE_PROPERTY_TYPE(Point1, glm::vec3)
LDFORGE_DEFINE_PROPERTY_TYPE(Point2, glm::vec3)
LDFORGE_DEFINE_PROPERTY_TYPE(Point3, glm::vec3)
LDFORGE_DEFINE_PROPERTY_TYPE(Transformation, glm::mat4)
LDFORGE_DEFINE_PROPERTY_TYPE(ReferenceName, QString)
LDFORGE_DEFINE_PROPERTY_TYPE(IsInverted, bool)
LDFORGE_DEFINE_PROPERTY_TYPE(ErrorMessage, QString)
LDFORGE_DEFINE_PROPERTY_TYPE(CircularPrimitiveType, ldraw::CircularPrimitiveType)
LDFORGE_DEFINE_PROPERTY_TYPE(Segments, int)
LDFORGE_DEFINE_PROPERTY_TYPE(Divisions, int)

#define LDRAW_OBJECT_HANDLE_SET_PROPERTY(PROPERTY, HANDLER) \
	{this->handle<ldraw::Property::PROPERTY>(result, pair, \
		[&](const ldraw::PropertyType<ldraw::Property::PROPERTY>& value) HANDLER);}

// Generics
namespace ldraw
{
	template<ldraw::Property property>
	using PropertyType = typename PropertyTraits<property>::type;

	template<ldraw::Property property>
	inline const char* PROPERTY_NAME = PropertyTraits<property>::name;

	constexpr int MAX_POINTS = 4;

	struct PropertyKeyValue
	{
		Property key;
		QVariant value;
	};

	constexpr Property pointProperty(int n)
	{
		Q_ASSERT(n >= 0 and n < MAX_POINTS);
		return static_cast<Property>(static_cast<int>(Property::Point0) + n);
	}

	struct PropertyTrait
	{
		ldraw::Property property;
		std::array<char, 256> name;
		int type;
	};

	namespace detail
	{
		template<int N>
		constexpr int propertyCountHelper()
		{
			if constexpr (ldraw::PropertyTraits<static_cast<Property>(N)>::defined)
			{
				return propertyCountHelper<N + 1>();
			}
			else
			{
				return N;
			}
		}

		template<int k>
		constexpr PropertyTrait getPropertyTrait()
		{
			constexpr auto property = static_cast<ldraw::Property>(k);
			using trait = ldraw::PropertyTraits<property>;
			return PropertyTrait{
				property,
				trait::name,
				qMetaTypeId<typename trait::type>()
			};
		}

		template<int... Ints>
		auto getPropertyTraits(std::integer_sequence<int, Ints...>)
		{
			return std::array<PropertyTrait, sizeof...(Ints)>{getPropertyTrait<Ints>()...};
		}
	}

	constexpr int NUM_PROPERTIES = detail::propertyCountHelper<0>();
	inline const auto& traits()
	{
		static std::array<PropertyTrait, NUM_PROPERTIES> result =
			detail::getPropertyTraits(std::make_integer_sequence<int, NUM_PROPERTIES>());
		return result;
	}

	inline const auto& traits(ldraw::Property property)
	{
		return traits()[static_cast<int>(property)];
	}

	template<typename T, std::size_t... Ints>
	constexpr auto makeIndexArray(std::index_sequence<Ints...>)
	{
		return std::array{static_cast<T>(Ints)...};
	}

	constexpr auto ALL_PROPERTIES = makeIndexArray<Property>(std::make_index_sequence<NUM_PROPERTIES>{});

	template<typename T>
	bool testPropertyType(ldraw::Property property)
	{
		return qMetaTypeId<T>() == ldraw::traits(property).type;
	}
}

mercurial