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

summaryrefslogtreecommitdiff
path: root/source/game/StarDrawable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/game/StarDrawable.cpp')
-rw-r--r--source/game/StarDrawable.cpp273
1 files changed, 273 insertions, 0 deletions
diff --git a/source/game/StarDrawable.cpp b/source/game/StarDrawable.cpp
new file mode 100644
index 0000000..5fd5071
--- /dev/null
+++ b/source/game/StarDrawable.cpp
@@ -0,0 +1,273 @@
+#include "StarDrawable.hpp"
+#include "StarColor.hpp"
+#include "StarJsonExtra.hpp"
+#include "StarDataStreamExtra.hpp"
+#include "StarAssets.hpp"
+#include "StarImageMetadataDatabase.hpp"
+#include "StarGameTypes.hpp"
+#include "StarRoot.hpp"
+
+namespace Star {
+
+void Drawable::ImagePart::addDirectives(String const& directives, bool keepImageCenterPosition) {
+ if (directives.empty())
+ return;
+
+ if (keepImageCenterPosition) {
+ auto imageMetadata = Root::singleton().imageMetadataDatabase();
+ Vec2F imageSize = Vec2F(imageMetadata->imageSize(image));
+ image = AssetPath::addDirectives(image, {directives});
+ Vec2F newImageSize = Vec2F(imageMetadata->imageSize(image));
+
+ // If we are trying to maintain the image center, PRE translate the image by
+ // the change in size / 2
+ transformation *= Mat3F::translation((imageSize - newImageSize) / 2);
+ } else {
+ image = AssetPath::addDirectives(image, {directives});
+ }
+}
+
+void Drawable::ImagePart::removeDirectives(bool keepImageCenterPosition) {
+ if (keepImageCenterPosition) {
+ auto imageMetadata = Root::singleton().imageMetadataDatabase();
+ Vec2F imageSize = Vec2F(imageMetadata->imageSize(image));
+ image = AssetPath::removeDirectives(image);
+ Vec2F newImageSize = Vec2F(imageMetadata->imageSize(image));
+
+ // If we are trying to maintain the image center, PRE translate the image by
+ // the change in size / 2
+ transformation *= Mat3F::translation((imageSize - newImageSize) / 2);
+ } else {
+ image = AssetPath::removeDirectives(image);
+ }
+}
+
+Drawable Drawable::makeLine(Line2F const& line, float lineWidth, Color const& color, Vec2F const& position) {
+ Drawable drawable;
+ drawable.part = LinePart{move(line), lineWidth};
+ drawable.color = color;
+ drawable.position = position;
+
+ return drawable;
+}
+
+Drawable Drawable::makePoly(PolyF poly, Color const& color, Vec2F const& position) {
+ Drawable drawable;
+ drawable.part = PolyPart{move(poly)};
+ drawable.color = color;
+ drawable.position = position;
+
+ return drawable;
+}
+
+Drawable Drawable::makeImage(String image, float pixelSize, bool centered, Vec2F const& position, Color const& color) {
+ Drawable drawable;
+ Mat3F transformation = Mat3F::identity();
+ if (centered) {
+ auto imageMetadata = Root::singleton().imageMetadataDatabase();
+ Vec2F imageSize = Vec2F(imageMetadata->imageSize(image));
+ transformation.translate(-imageSize / 2);
+ }
+
+ transformation.scale(pixelSize);
+
+ drawable.part = ImagePart{move(image), move(transformation)};
+ drawable.position = position;
+ drawable.color = color;
+
+ return drawable;
+}
+
+Drawable::Drawable()
+ : color(Color::White), fullbright(false) {}
+
+Drawable::Drawable(Json const& json) {
+ if (auto line = json.opt("line")) {
+ part = LinePart{jsonToLine2F(*line), json.getFloat("width")};
+ } else if (auto poly = json.opt("poly")) {
+ part = PolyPart{jsonToPolyF(*poly)};
+ } else if (auto image = json.opt("image")) {
+ auto imageString = image->toString();
+ Mat3F transformation = Mat3F::identity();
+ if (auto transformationConfig = json.opt("transformation")) {
+ transformation = jsonToMat3F(*transformationConfig);
+ } else {
+ if (json.getBool("centered", true)) {
+ auto imageMetadata = Root::singleton().imageMetadataDatabase();
+ Vec2F imageSize = Vec2F(imageMetadata->imageSize(imageString));
+ transformation.translate(-imageSize / 2);
+ }
+ if (auto rotation = json.optFloat("rotation"))
+ transformation.rotate(*rotation);
+ if (json.getBool("mirrored", false))
+ transformation.scale(Vec2F(-1, 1));
+ if (auto scale = json.optFloat("scale"))
+ transformation.scale(*scale);
+ }
+
+ part = ImagePart{move(imageString), move(transformation)};
+ }
+ position = json.opt("position").apply(jsonToVec2F).value();
+ color = json.opt("color").apply(jsonToColor).value(Color::White);
+ fullbright = json.getBool("fullbright", false);
+}
+
+Json Drawable::toJson() const {
+ JsonObject json;
+ if (auto line = part.ptr<LinePart>()) {
+ json.set("line", jsonFromLine2F(line->line));
+ json.set("width", line->width);
+ } else if (auto poly = part.ptr<PolyPart>()) {
+ json.set("poly", jsonFromPolyF(poly->poly));
+ } else if (auto image = part.ptr<ImagePart>()) {
+ json.set("image", image->image);
+ json.set("transformation", jsonFromMat3F(image->transformation));
+ }
+
+ json.set("position", jsonFromVec2F(position));
+ json.set("color", jsonFromColor(color));
+ json.set("fullbright", fullbright);
+
+ return move(json);
+}
+
+void Drawable::translate(Vec2F const& translation) {
+ position += translation;
+}
+
+void Drawable::rotate(float rotation, Vec2F const& rotationCenter) {
+ if (auto line = part.ptr<LinePart>())
+ line->line.rotate(rotation);
+ else if (auto poly = part.ptr<PolyPart>())
+ poly->poly.rotate(rotation);
+ else if (auto image = part.ptr<ImagePart>())
+ image->transformation.rotate(rotation);
+
+ position = (position - rotationCenter).rotate(rotation) + rotationCenter;
+}
+
+void Drawable::scale(float scaling, Vec2F const& scaleCenter) {
+ scale(Vec2F::filled(scaling), scaleCenter);
+}
+
+void Drawable::scale(Vec2F const& scaling, Vec2F const& scaleCenter) {
+ if (auto line = part.ptr<LinePart>())
+ line->line.scale(scaling);
+ else if (auto poly = part.ptr<PolyPart>())
+ poly->poly.scale(scaling);
+ else if (auto image = part.ptr<ImagePart>())
+ image->transformation.scale(scaling);
+
+ position = (position - scaleCenter).piecewiseMultiply(scaling) + scaleCenter;
+}
+
+void Drawable::transform(Mat3F const& transformation) {
+ Vec2F localTranslation = transformation.transformVec2(Vec2F());
+ Mat3F localTransform = Mat3F::translation(-localTranslation) * transformation;
+
+ if (auto line = part.ptr<LinePart>())
+ line->line.transform(localTransform);
+ else if (auto poly = part.ptr<PolyPart>())
+ poly->poly.transform(localTransform);
+ else if (auto image = part.ptr<ImagePart>())
+ image->transformation = localTransform * image->transformation;
+
+ position = transformation.transformVec2(position);
+}
+
+void Drawable::rebase(Vec2F const& newBase) {
+ if (auto line = part.ptr<LinePart>())
+ line->line.translate(position - newBase);
+ else if (auto poly = part.ptr<PolyPart>())
+ poly->poly.translate(position - newBase);
+ else if (auto image = part.ptr<ImagePart>())
+ image->transformation.translate(position - newBase);
+
+ position = newBase;
+}
+
+RectF Drawable::boundBox(bool cropImages) const {
+ RectF boundBox = RectF::null();
+ if (auto line = part.ptr<LinePart>()) {
+ boundBox.combine(line->line.min());
+ boundBox.combine(line->line.max());
+
+ } else if (auto poly = part.ptr<PolyPart>()) {
+ boundBox.combine(poly->poly.boundBox());
+
+ } else if (auto image = part.ptr<ImagePart>()) {
+ auto imageMetadata = Root::singleton().imageMetadataDatabase();
+ RectF imageRegion = RectF::null();
+ if (cropImages) {
+ RectU nonEmptyRegion = imageMetadata->nonEmptyRegion(image->image);
+ if (!nonEmptyRegion.isNull())
+ imageRegion = RectF(nonEmptyRegion);
+ } else {
+ imageRegion = RectF::withSize(Vec2F(), Vec2F(imageMetadata->imageSize(image->image)));
+ }
+
+ if (!imageRegion.isNull()) {
+ boundBox.combine(image->transformation.transformVec2(Vec2F(imageRegion.xMin(), imageRegion.yMin())));
+ boundBox.combine(image->transformation.transformVec2(Vec2F(imageRegion.xMax(), imageRegion.yMin())));
+ boundBox.combine(image->transformation.transformVec2(Vec2F(imageRegion.xMin(), imageRegion.yMax())));
+ boundBox.combine(image->transformation.transformVec2(Vec2F(imageRegion.xMax(), imageRegion.yMax())));
+ }
+ }
+
+ if (!boundBox.isNull())
+ boundBox.translate(position);
+
+ return boundBox;
+}
+
+DataStream& operator>>(DataStream& ds, Drawable::LinePart& line) {
+ ds >> line.line;
+ ds >> line.width;
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, Drawable::LinePart const& line) {
+ ds << line.line;
+ ds << line.width;
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, Drawable::PolyPart& poly) {
+ ds >> poly.poly;
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, Drawable::PolyPart const& poly) {
+ ds << poly.poly;
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, Drawable::ImagePart& image) {
+ ds >> image.image;
+ ds >> image.transformation;
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, Drawable::ImagePart const& image) {
+ ds << image.image;
+ ds << image.transformation;
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, Drawable& drawable) {
+ ds >> drawable.part;
+ ds >> drawable.position;
+ ds >> drawable.color;
+ ds >> drawable.fullbright;
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, Drawable const& drawable) {
+ ds << drawable.part;
+ ds << drawable.position;
+ ds << drawable.color;
+ ds << drawable.fullbright;
+ return ds;
+}
+
+}