2016-05-21 08:41:23 -05:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
/*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
|
|
|
|
2020-04-18 03:39:50 -05:00
|
|
|
#pragma once
|
2016-05-21 08:41:23 -05:00
|
|
|
|
2016-09-15 07:40:26 -05:00
|
|
|
#include <cassert>
|
2020-08-09 16:55:56 -05:00
|
|
|
#include <unordered_map>
|
2016-05-21 08:41:23 -05:00
|
|
|
#include <sstream>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
|
|
#include "Exceptions.hpp"
|
2019-11-13 02:15:07 -06:00
|
|
|
#include <Protocol.hpp>
|
2022-03-29 20:37:57 -05:00
|
|
|
#include <StringVector.hpp>
|
2016-05-21 08:41:23 -05:00
|
|
|
|
2017-09-16 11:27:31 -05:00
|
|
|
#define TILE_WIRE_ID
|
2020-07-12 11:25:49 -05:00
|
|
|
using TileWireId = uint32_t;
|
|
|
|
using TileBinaryHash = uint64_t;
|
2017-06-14 11:28:07 -05:00
|
|
|
|
2023-09-14 07:39:08 -05:00
|
|
|
namespace TileParse
|
|
|
|
{
|
|
|
|
template <typename A> struct Comp
|
|
|
|
{
|
|
|
|
bool operator()(const A& av, const std::string_view arg) { return av.first < arg; }
|
|
|
|
bool operator()(const std::string_view arg, const A& av) { return arg < av.first; }
|
|
|
|
bool operator()(const A& av, const A& bv) { return av.first < bv.first; }
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
template <class T, size_t N> bool checkSorted(T const (&args)[N], int maxEnum)
|
|
|
|
{
|
|
|
|
bool sorted = std::is_sorted(std::begin(args), std::end(args), Comp<T>{});
|
|
|
|
for (int i = 0; i < maxEnum; ++i)
|
|
|
|
{
|
|
|
|
auto range = std::equal_range(std::begin(args), std::end(args), args[i], Comp<T>{});
|
|
|
|
assert(range.first != range.second && // is found
|
|
|
|
std::distance(range.first, range.second) == 1 && // one match
|
|
|
|
std::distance(std::begin(args), range.first) == i); // match is in correct index
|
|
|
|
}
|
|
|
|
return sorted;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
template <class T, size_t N> bool setArg(T (&args)[N], const std::string_view arg, int value)
|
|
|
|
{
|
|
|
|
auto range = std::equal_range(std::begin(args), std::end(args), arg, Comp<T>{});
|
|
|
|
if (range.first == range.second)
|
|
|
|
return false;
|
|
|
|
range.first->second = value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-21 08:41:23 -05:00
|
|
|
/// Tile Descriptor
|
|
|
|
/// Represents a tile's coordinates and dimensions.
|
2020-08-09 16:55:56 -05:00
|
|
|
class TileDesc final
|
2016-05-21 08:41:23 -05:00
|
|
|
{
|
|
|
|
public:
|
2022-08-30 00:27:44 -05:00
|
|
|
TileDesc(int normalizedViewId, int part, int mode, int width, int height, int tilePosX, int tilePosY, int tileWidth,
|
2023-09-07 09:25:37 -05:00
|
|
|
int tileHeight, int ver, int imgSize, int id)
|
2019-10-14 06:12:26 -05:00
|
|
|
: _normalizedViewId(normalizedViewId)
|
|
|
|
, _part(part)
|
2022-08-30 00:27:44 -05:00
|
|
|
, _mode(mode)
|
2019-04-20 13:58:48 -05:00
|
|
|
, _width(width)
|
|
|
|
, _height(height)
|
|
|
|
, _tilePosX(tilePosX)
|
|
|
|
, _tilePosY(tilePosY)
|
|
|
|
, _tileWidth(tileWidth)
|
|
|
|
, _tileHeight(tileHeight)
|
|
|
|
, _ver(ver)
|
|
|
|
, _imgSize(imgSize)
|
|
|
|
, _id(id)
|
|
|
|
, _oldWireId(0)
|
|
|
|
, _wireId(0)
|
2016-05-21 08:41:23 -05:00
|
|
|
{
|
2019-10-14 06:12:26 -05:00
|
|
|
if (_normalizedViewId < 0 ||
|
|
|
|
_part < 0 ||
|
2022-08-29 06:54:36 -05:00
|
|
|
_mode < 0 ||
|
2016-05-21 08:41:23 -05:00
|
|
|
_width <= 0 ||
|
|
|
|
_height <= 0 ||
|
|
|
|
_tilePosX < 0 ||
|
|
|
|
_tilePosY < 0 ||
|
|
|
|
_tileWidth <= 0 ||
|
2016-05-22 10:35:41 -05:00
|
|
|
_tileHeight <= 0 ||
|
|
|
|
_imgSize < 0)
|
2016-05-21 08:41:23 -05:00
|
|
|
{
|
|
|
|
throw BadArgumentException("Invalid tile descriptor.");
|
|
|
|
}
|
|
|
|
}
|
2020-07-12 11:25:49 -05:00
|
|
|
|
2019-10-14 06:12:26 -05:00
|
|
|
int getNormalizedViewId() const { return _normalizedViewId; }
|
|
|
|
void setNormalizedViewId(const int normalizedViewId) { _normalizedViewId = normalizedViewId; }
|
2016-05-21 08:41:23 -05:00
|
|
|
int getPart() const { return _part; }
|
2022-08-29 06:54:36 -05:00
|
|
|
int getEditMode() const { return _mode; }
|
2016-05-21 08:41:23 -05:00
|
|
|
int getWidth() const { return _width; }
|
|
|
|
int getHeight() const { return _height; }
|
|
|
|
int getTilePosX() const { return _tilePosX; }
|
|
|
|
int getTilePosY() const { return _tilePosY; }
|
|
|
|
int getTileWidth() const { return _tileWidth; }
|
|
|
|
int getTileHeight() const { return _tileHeight; }
|
2016-05-22 13:21:05 -05:00
|
|
|
int getVersion() const { return _ver; }
|
|
|
|
void setVersion(const int ver) { _ver = ver; }
|
2016-05-22 10:35:41 -05:00
|
|
|
int getImgSize() const { return _imgSize; }
|
|
|
|
void setImgSize(const int imgSize) { _imgSize = imgSize; }
|
2022-04-27 05:01:03 -05:00
|
|
|
/// if non-zero: a preview.
|
2016-10-04 05:20:41 -05:00
|
|
|
int getId() const { return _id; }
|
2022-03-25 13:32:01 -05:00
|
|
|
void setId(TileWireId id) { _id = id; }
|
2017-06-14 11:28:07 -05:00
|
|
|
void setOldWireId(TileWireId id) { _oldWireId = id; }
|
2022-03-25 13:32:01 -05:00
|
|
|
void forceKeyframe() { setOldWireId(0); }
|
2017-06-14 11:28:07 -05:00
|
|
|
TileWireId getOldWireId() const { return _oldWireId; }
|
|
|
|
void setWireId(TileWireId id) { _wireId = id; }
|
|
|
|
TileWireId getWireId() const { return _wireId; }
|
2016-09-15 07:40:26 -05:00
|
|
|
|
2016-12-18 11:04:18 -06:00
|
|
|
bool operator==(const TileDesc& other) const
|
|
|
|
{
|
|
|
|
return _part == other._part &&
|
|
|
|
_width == other._width &&
|
|
|
|
_height == other._height &&
|
|
|
|
_tilePosX == other._tilePosX &&
|
|
|
|
_tilePosY == other._tilePosY &&
|
|
|
|
_tileWidth == other._tileWidth &&
|
|
|
|
_tileHeight == other._tileHeight &&
|
|
|
|
_id == other._id &&
|
2022-08-30 00:27:44 -05:00
|
|
|
_normalizedViewId == other._normalizedViewId &&
|
|
|
|
_mode == other._mode;
|
2016-12-18 11:04:18 -06:00
|
|
|
}
|
|
|
|
|
2017-01-25 11:21:56 -06:00
|
|
|
static bool rectanglesIntersect(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2)
|
|
|
|
{
|
|
|
|
return x1 + w1 >= x2 &&
|
|
|
|
x1 <= x2 + w2 &&
|
|
|
|
y1 + h1 >= y2 &&
|
|
|
|
y1 <= y2 + h2;
|
|
|
|
}
|
|
|
|
|
2016-09-01 15:15:13 -05:00
|
|
|
bool intersectsWithRect(int x, int y, int w, int h) const
|
|
|
|
{
|
2017-01-25 11:21:56 -06:00
|
|
|
return rectanglesIntersect(getTilePosX(), getTilePosY(), getTileWidth(), getTileHeight(), x, y, w, h);
|
2016-09-01 15:15:13 -05:00
|
|
|
}
|
2016-05-21 08:41:23 -05:00
|
|
|
|
2016-09-15 07:40:26 -05:00
|
|
|
bool intersects(const TileDesc& other) const
|
|
|
|
{
|
|
|
|
return intersectsWithRect(other.getTilePosX(), other.getTilePosY(),
|
|
|
|
other.getTileWidth(), other.getTileHeight());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isAdjacent(const TileDesc& other) const
|
|
|
|
{
|
|
|
|
if (other.getPart() != getPart() ||
|
2022-08-30 00:27:44 -05:00
|
|
|
other.getEditMode() != getEditMode() ||
|
2016-09-15 07:40:26 -05:00
|
|
|
other.getWidth() != getWidth() ||
|
|
|
|
other.getHeight() != getHeight() ||
|
|
|
|
other.getTileWidth() != getTileWidth() ||
|
|
|
|
other.getTileHeight() != getTileHeight())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return intersects(other);
|
|
|
|
}
|
|
|
|
|
2016-09-25 20:30:56 -05:00
|
|
|
bool onSameRow(const TileDesc& other) const
|
|
|
|
{
|
|
|
|
if (other.getPart() != getPart() ||
|
2022-08-30 00:27:44 -05:00
|
|
|
other.getEditMode() != getEditMode() ||
|
2016-09-25 20:30:56 -05:00
|
|
|
other.getWidth() != getWidth() ||
|
|
|
|
other.getHeight() != getHeight() ||
|
|
|
|
other.getTileWidth() != getTileWidth() ||
|
2019-10-14 06:12:26 -05:00
|
|
|
other.getTileHeight() != getTileHeight() ||
|
|
|
|
other.getNormalizedViewId() != getNormalizedViewId())
|
2016-09-25 20:30:56 -05:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-11-28 20:44:09 -06:00
|
|
|
return other.getTilePosY() + other.getTileHeight() >= getTilePosY() &&
|
|
|
|
other.getTilePosY() <= getTilePosY() + getTileHeight();
|
2016-09-25 20:30:56 -05:00
|
|
|
}
|
|
|
|
|
2019-07-25 13:44:50 -05:00
|
|
|
bool canCombine(const TileDesc& other) const
|
|
|
|
{
|
|
|
|
if (!onSameRow(other))
|
|
|
|
return false;
|
2020-07-12 11:25:49 -05:00
|
|
|
|
|
|
|
const int gridX = getTilePosX() / getTileWidth();
|
|
|
|
const int gridXOther = other.getTilePosX() / other.getTileWidth();
|
|
|
|
const int delta = gridX - gridXOther;
|
2019-07-25 13:44:50 -05:00
|
|
|
// a 4k screen - is sixteen 256 pixel wide tiles wide.
|
2020-07-12 11:25:49 -05:00
|
|
|
return (delta >= -16 && delta <= 16);
|
2019-07-25 13:44:50 -05:00
|
|
|
}
|
|
|
|
|
2016-05-21 08:41:23 -05:00
|
|
|
/// Serialize this instance into a string.
|
|
|
|
/// Optionally prepend a prefix.
|
2019-04-20 13:58:48 -05:00
|
|
|
std::string serialize(const std::string& prefix = std::string(),
|
|
|
|
const std::string& suffix = std::string()) const
|
2016-05-21 08:41:23 -05:00
|
|
|
{
|
|
|
|
std::ostringstream oss;
|
|
|
|
oss << prefix
|
2019-10-14 06:12:26 -05:00
|
|
|
<< " nviewid=" << _normalizedViewId
|
2016-05-21 08:41:23 -05:00
|
|
|
<< " part=" << _part
|
|
|
|
<< " width=" << _width
|
|
|
|
<< " height=" << _height
|
|
|
|
<< " tileposx=" << _tilePosX
|
|
|
|
<< " tileposy=" << _tilePosY
|
|
|
|
<< " tilewidth=" << _tileWidth
|
2017-01-04 06:36:13 -06:00
|
|
|
<< " tileheight=" << _tileHeight
|
2017-06-14 11:28:07 -05:00
|
|
|
<< " oldwid=" << _oldWireId
|
|
|
|
<< " wid=" << _wireId;
|
2016-09-19 19:30:35 -05:00
|
|
|
|
2017-01-01 23:30:27 -06:00
|
|
|
// Anything after ver is optional.
|
|
|
|
oss << " ver=" << _ver;
|
|
|
|
|
2016-11-23 20:28:50 -06:00
|
|
|
if (_id >= 0)
|
2016-09-19 19:30:35 -05:00
|
|
|
{
|
2016-11-23 20:28:50 -06:00
|
|
|
oss << " id=" << _id;
|
2016-09-19 19:30:35 -05:00
|
|
|
}
|
|
|
|
|
2016-11-23 20:28:50 -06:00
|
|
|
if (_imgSize > 0)
|
2016-05-21 08:41:23 -05:00
|
|
|
{
|
2016-11-23 20:28:50 -06:00
|
|
|
oss << " imgsize=" << _imgSize;
|
2016-05-21 08:41:23 -05:00
|
|
|
}
|
|
|
|
|
2022-08-30 00:27:44 -05:00
|
|
|
if (_mode)
|
|
|
|
{
|
|
|
|
oss << " mode=" << _mode;
|
|
|
|
}
|
|
|
|
|
2019-04-20 13:58:48 -05:00
|
|
|
oss << suffix;
|
2016-05-21 08:41:23 -05:00
|
|
|
return oss.str();
|
|
|
|
}
|
|
|
|
|
2020-08-07 11:36:56 -05:00
|
|
|
/// short name for a tile for debugging.
|
|
|
|
std::string debugName() const
|
|
|
|
{
|
|
|
|
std::ostringstream oss;
|
2022-08-29 06:54:36 -05:00
|
|
|
oss << '(' << getNormalizedViewId() << ',' << getPart() << ',' << getEditMode() << ',' << getTilePosX() << ',' << getTilePosY() << ')';
|
2020-08-07 11:36:56 -05:00
|
|
|
return oss.str();
|
|
|
|
}
|
|
|
|
|
2016-05-21 08:41:23 -05:00
|
|
|
/// Deserialize a TileDesc from a tokenized string.
|
2020-02-28 03:50:58 -06:00
|
|
|
static TileDesc parse(const StringVector& tokens)
|
2016-05-21 08:41:23 -05:00
|
|
|
{
|
2023-08-24 10:39:24 -05:00
|
|
|
enum argenum { height, id, imgsize, mode, nviewid, part, tileheight, tileposx, tileposy, tilewidth, ver, width, maxEnum };
|
|
|
|
|
|
|
|
struct TileDescParseResults
|
|
|
|
{
|
|
|
|
typedef std::pair<const std::string_view, int> arg_value;
|
|
|
|
|
|
|
|
arg_value args[maxEnum] = {
|
|
|
|
{ STRINGIFY(height), 0 },
|
|
|
|
{ STRINGIFY(id), -1 }, // Optional
|
|
|
|
{ STRINGIFY(imgsize), 0 }, // Optional
|
|
|
|
{ STRINGIFY(mode), 0 }, // Optional
|
|
|
|
{ STRINGIFY(nviewid), 0 },
|
|
|
|
{ STRINGIFY(part), 0 },
|
|
|
|
{ STRINGIFY(tileheight), 0 },
|
|
|
|
{ STRINGIFY(tileposx), 0 },
|
|
|
|
{ STRINGIFY(tileposy), 0 },
|
|
|
|
{ STRINGIFY(tilewidth), 0 },
|
|
|
|
{ STRINGIFY(ver), -1 }, // Optional
|
|
|
|
{ STRINGIFY(width), 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
TileDescParseResults()
|
|
|
|
{
|
2023-09-14 07:39:08 -05:00
|
|
|
static bool isSorted = TileParse::checkSorted(args, maxEnum);
|
2023-08-24 10:39:24 -05:00
|
|
|
assert(isSorted);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool set(const std::string_view arg, int value)
|
|
|
|
{
|
2023-09-14 07:39:08 -05:00
|
|
|
return TileParse::setArg(args, arg, value);
|
2023-08-24 10:39:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int operator[](argenum arg) const
|
|
|
|
{
|
|
|
|
return args[arg].second;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-05-21 09:40:16 -05:00
|
|
|
// We don't expect undocumented fields and
|
2016-05-21 08:41:23 -05:00
|
|
|
// assume all values to be int.
|
2023-08-24 10:39:24 -05:00
|
|
|
TileDescParseResults pairs;
|
2016-05-21 08:41:23 -05:00
|
|
|
|
2017-06-14 11:28:07 -05:00
|
|
|
TileWireId oldWireId = 0;
|
|
|
|
TileWireId wireId = 0;
|
2020-11-15 11:03:45 -06:00
|
|
|
for (std::size_t i = 0; i < tokens.size(); ++i)
|
2016-05-21 08:41:23 -05:00
|
|
|
{
|
2021-04-27 02:52:46 -05:00
|
|
|
if (tokens.getUInt32(i, "oldwid", oldWireId))
|
2017-01-04 06:36:13 -06:00
|
|
|
;
|
2021-04-27 02:52:46 -05:00
|
|
|
else if (tokens.getUInt32(i, "wid", wireId))
|
2017-01-04 06:36:13 -06:00
|
|
|
;
|
|
|
|
else
|
2016-05-21 08:41:23 -05:00
|
|
|
{
|
2023-09-07 09:25:37 -05:00
|
|
|
std::string name;
|
2017-01-04 06:36:13 -06:00
|
|
|
int value = -1;
|
2023-09-07 09:25:37 -05:00
|
|
|
if (tokens.getNameIntegerPair(i, name, value))
|
|
|
|
pairs.set(name, value);
|
2016-05-21 08:41:23 -05:00
|
|
|
}
|
|
|
|
}
|
2016-11-23 20:28:50 -06:00
|
|
|
|
2023-08-24 10:39:24 -05:00
|
|
|
TileDesc result(pairs[nviewid], pairs[part], pairs[mode],
|
|
|
|
pairs[width], pairs[height],
|
|
|
|
pairs[tileposx], pairs[tileposy],
|
|
|
|
pairs[tilewidth], pairs[tileheight],
|
|
|
|
pairs[ver],
|
2023-09-07 09:25:37 -05:00
|
|
|
pairs[imgsize], pairs[id]);
|
2017-06-14 11:28:07 -05:00
|
|
|
result.setOldWireId(oldWireId);
|
|
|
|
result.setWireId(wireId);
|
2017-01-04 06:36:13 -06:00
|
|
|
|
|
|
|
return result;
|
2016-05-21 08:41:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Deserialize a TileDesc from a string format.
|
2016-10-29 20:15:00 -05:00
|
|
|
static TileDesc parse(const std::string& message)
|
2016-05-21 08:41:23 -05:00
|
|
|
{
|
2022-03-29 20:37:57 -05:00
|
|
|
return parse(StringVector::tokenize(message.data(), message.size()));
|
2016-05-21 08:41:23 -05:00
|
|
|
}
|
|
|
|
|
2019-02-13 11:23:37 -06:00
|
|
|
std::string generateID() const
|
|
|
|
{
|
|
|
|
std::ostringstream tileID;
|
2022-08-29 06:54:36 -05:00
|
|
|
tileID << getPart() << ':' << getEditMode() << ':' << getTilePosX() << ':' << getTilePosY()
|
|
|
|
<< ':' << getTileWidth() << ':' << getTileHeight() << ':' << getNormalizedViewId();
|
2019-02-13 11:23:37 -06:00
|
|
|
return tileID.str();
|
|
|
|
}
|
|
|
|
|
2020-08-09 16:55:56 -05:00
|
|
|
private:
|
2019-10-14 06:12:26 -05:00
|
|
|
int _normalizedViewId;
|
2016-05-21 08:41:23 -05:00
|
|
|
int _part;
|
2022-08-30 00:27:44 -05:00
|
|
|
int _mode; //< Used in Impress for EditMode::(Page|MasterPage), 0 = default
|
2016-05-21 08:41:23 -05:00
|
|
|
int _width;
|
|
|
|
int _height;
|
|
|
|
int _tilePosX;
|
|
|
|
int _tilePosY;
|
|
|
|
int _tileWidth;
|
|
|
|
int _tileHeight;
|
2016-10-29 20:15:00 -05:00
|
|
|
int _ver; //< Versioning support.
|
|
|
|
int _imgSize; //< Used for responses.
|
2016-05-21 08:41:23 -05:00
|
|
|
int _id;
|
2017-06-14 11:28:07 -05:00
|
|
|
TileWireId _oldWireId;
|
|
|
|
TileWireId _wireId;
|
2016-05-21 08:41:23 -05:00
|
|
|
};
|
|
|
|
|
2016-08-13 23:01:13 -05:00
|
|
|
/// One or more tile header.
|
|
|
|
/// Used to request the rendering of multiple
|
|
|
|
/// tiles as well as the header of the response.
|
2020-08-09 16:55:56 -05:00
|
|
|
class TileCombined final
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
|
|
|
private:
|
2022-08-30 00:27:44 -05:00
|
|
|
TileCombined(int normalizedViewId, int part, int mode, int width, int height,
|
2016-05-22 10:31:36 -05:00
|
|
|
const std::string& tilePositionsX, const std::string& tilePositionsY,
|
2017-01-01 23:30:27 -06:00
|
|
|
int tileWidth, int tileHeight, const std::string& vers,
|
2019-04-19 16:48:41 -05:00
|
|
|
const std::string& imgSizes,
|
2017-06-14 11:28:07 -05:00
|
|
|
const std::string& oldWireIds,
|
|
|
|
const std::string& wireIds) :
|
2019-10-14 06:12:26 -05:00
|
|
|
_normalizedViewId(normalizedViewId),
|
2016-05-22 10:31:36 -05:00
|
|
|
_part(part),
|
2022-08-30 00:27:44 -05:00
|
|
|
_mode(mode),
|
2016-05-22 10:31:36 -05:00
|
|
|
_width(width),
|
|
|
|
_height(height),
|
|
|
|
_tileWidth(tileWidth),
|
2023-08-15 09:32:53 -05:00
|
|
|
_tileHeight(tileHeight),
|
|
|
|
_isCompiled(true)
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
|
|
|
if (_part < 0 ||
|
2022-08-30 00:27:44 -05:00
|
|
|
_mode < 0 ||
|
2016-05-22 10:31:36 -05:00
|
|
|
_width <= 0 ||
|
|
|
|
_height <= 0 ||
|
|
|
|
_tileWidth <= 0 ||
|
|
|
|
_tileHeight <= 0)
|
|
|
|
{
|
|
|
|
throw BadArgumentException("Invalid tilecombine descriptor.");
|
|
|
|
}
|
|
|
|
|
2022-03-29 20:37:57 -05:00
|
|
|
StringVector positionXtokens(StringVector::tokenize(tilePositionsX, ','));
|
|
|
|
StringVector positionYtokens(StringVector::tokenize(tilePositionsY, ','));
|
|
|
|
StringVector imgSizeTokens(StringVector::tokenize(imgSizes, ','));
|
|
|
|
StringVector verTokens(StringVector::tokenize(vers, ','));
|
|
|
|
StringVector oldWireIdTokens(StringVector::tokenize(oldWireIds, ','));
|
|
|
|
StringVector wireIdTokens(StringVector::tokenize(wireIds, ','));
|
2016-05-22 10:31:36 -05:00
|
|
|
|
2020-11-15 11:03:45 -06:00
|
|
|
const std::size_t numberOfPositions = positionXtokens.size();
|
2016-05-22 10:31:36 -05:00
|
|
|
|
2017-01-04 06:36:13 -06:00
|
|
|
// check that the comma-separated strings have the same number of elements
|
2019-11-13 02:15:07 -06:00
|
|
|
if (numberOfPositions != positionYtokens.size() ||
|
|
|
|
(!imgSizes.empty() && numberOfPositions != imgSizeTokens.size()) ||
|
|
|
|
(!vers.empty() && numberOfPositions != verTokens.size()) ||
|
|
|
|
(!oldWireIds.empty() && numberOfPositions != oldWireIdTokens.size()) ||
|
|
|
|
(!wireIds.empty() && numberOfPositions != wireIdTokens.size()))
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
2017-01-04 06:36:13 -06:00
|
|
|
throw BadArgumentException("Invalid tilecombine descriptor. Unequal number of tiles in parameters.");
|
2016-05-22 10:31:36 -05:00
|
|
|
}
|
|
|
|
|
2020-11-15 11:03:45 -06:00
|
|
|
for (std::size_t i = 0; i < numberOfPositions; ++i)
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
|
|
|
int x = 0;
|
2021-11-18 06:08:14 -06:00
|
|
|
if (!COOLProtocol::stringToInteger(positionXtokens[i], x))
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
2017-01-01 23:30:27 -06:00
|
|
|
throw BadArgumentException("Invalid 'tileposx' in tilecombine descriptor.");
|
2016-05-22 10:31:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int y = 0;
|
2021-11-18 06:08:14 -06:00
|
|
|
if (!COOLProtocol::stringToInteger(positionYtokens[i], y))
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
2017-01-01 23:30:27 -06:00
|
|
|
throw BadArgumentException("Invalid 'tileposy' in tilecombine descriptor.");
|
2016-05-22 10:31:36 -05:00
|
|
|
}
|
|
|
|
|
2017-01-04 06:36:13 -06:00
|
|
|
int imgSize = 0;
|
2021-11-18 06:08:14 -06:00
|
|
|
if (!imgSizeTokens.empty() && !COOLProtocol::stringToInteger(imgSizeTokens[i], imgSize))
|
2016-05-22 10:35:41 -05:00
|
|
|
{
|
2017-01-01 23:30:27 -06:00
|
|
|
throw BadArgumentException("Invalid 'imgsize' in tilecombine descriptor.");
|
|
|
|
}
|
|
|
|
|
|
|
|
int ver = -1;
|
2021-11-18 06:08:14 -06:00
|
|
|
if (!verTokens.empty() && !verTokens[i].empty() && !COOLProtocol::stringToInteger(verTokens[i], ver))
|
2017-01-01 23:30:27 -06:00
|
|
|
{
|
|
|
|
throw BadArgumentException("Invalid 'ver' in tilecombine descriptor.");
|
2016-05-22 10:35:41 -05:00
|
|
|
}
|
|
|
|
|
2017-06-14 11:28:07 -05:00
|
|
|
TileWireId oldWireId = 0;
|
2021-11-18 06:08:14 -06:00
|
|
|
if (!oldWireIdTokens.empty() && !COOLProtocol::stringToUInt32(oldWireIdTokens[i], oldWireId))
|
2017-01-04 06:36:13 -06:00
|
|
|
{
|
|
|
|
throw BadArgumentException("Invalid tilecombine descriptor.");
|
|
|
|
}
|
|
|
|
|
2017-06-14 11:28:07 -05:00
|
|
|
TileWireId wireId = 0;
|
2021-11-18 06:08:14 -06:00
|
|
|
if (!wireIdTokens.empty() && !COOLProtocol::stringToUInt32(wireIdTokens[i], wireId))
|
2017-01-04 06:36:13 -06:00
|
|
|
{
|
|
|
|
throw BadArgumentException("Invalid tilecombine descriptor.");
|
|
|
|
}
|
|
|
|
|
2023-09-07 09:25:37 -05:00
|
|
|
_tiles.emplace_back(_normalizedViewId, _part, _mode, _width, _height, x, y, _tileWidth, _tileHeight, ver, imgSize, -1);
|
2017-06-14 11:28:07 -05:00
|
|
|
_tiles.back().setOldWireId(oldWireId);
|
|
|
|
_tiles.back().setWireId(wireId);
|
2016-05-22 10:31:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2019-10-14 06:12:26 -05:00
|
|
|
int getNormalizedViewId() const { return _normalizedViewId; }
|
2016-05-22 10:31:36 -05:00
|
|
|
int getPart() const { return _part; }
|
2022-08-30 00:27:44 -05:00
|
|
|
int getEditMode() const { return _mode; }
|
2016-05-22 10:31:36 -05:00
|
|
|
int getWidth() const { return _width; }
|
|
|
|
int getHeight() const { return _height; }
|
|
|
|
int getTileWidth() const { return _tileWidth; }
|
|
|
|
int getTileHeight() const { return _tileHeight; }
|
2023-08-15 09:32:53 -05:00
|
|
|
bool getCombined() const { return _isCompiled; }
|
2016-05-22 10:31:36 -05:00
|
|
|
|
|
|
|
const std::vector<TileDesc>& getTiles() const { return _tiles; }
|
|
|
|
std::vector<TileDesc>& getTiles() { return _tiles; }
|
|
|
|
|
2019-10-14 06:12:26 -05:00
|
|
|
void setNormalizedViewId(int nViewId)
|
|
|
|
{
|
|
|
|
for (auto& tile : getTiles())
|
|
|
|
tile.setNormalizedViewId(nViewId);
|
|
|
|
|
|
|
|
_normalizedViewId = nViewId;
|
|
|
|
}
|
|
|
|
|
2022-06-09 07:29:02 -05:00
|
|
|
bool hasDuplicates() const
|
|
|
|
{
|
|
|
|
if (_tiles.size() < 2)
|
|
|
|
return false;
|
|
|
|
for (size_t i = 0; i < _tiles.size() - 1; ++i)
|
|
|
|
{
|
|
|
|
const auto &a = _tiles[i];
|
|
|
|
assert(a.getPart() == _part);
|
2022-08-30 00:27:44 -05:00
|
|
|
assert(a.getEditMode() == _mode);
|
2022-06-09 07:29:02 -05:00
|
|
|
assert(a.getWidth() == _width);
|
|
|
|
assert(a.getHeight() == _height);
|
|
|
|
assert(a.getTileWidth() == _tileWidth);
|
|
|
|
assert(a.getTileHeight() == _tileHeight);
|
|
|
|
for (size_t j = i + 1; j < _tiles.size(); ++j)
|
|
|
|
{
|
|
|
|
const auto &b = _tiles[j];
|
|
|
|
if (a.getTilePosX() == b.getTilePosX() &&
|
|
|
|
a.getTilePosY() == b.getTilePosY())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2019-10-14 06:12:26 -05:00
|
|
|
|
2016-05-22 10:31:36 -05:00
|
|
|
/// Serialize this instance into a string.
|
|
|
|
/// Optionally prepend a prefix.
|
2019-04-20 13:58:48 -05:00
|
|
|
std::string serialize(const std::string& prefix = std::string(),
|
|
|
|
const std::string& suffix = std::string()) const
|
2019-04-19 19:53:12 -05:00
|
|
|
{
|
|
|
|
return serialize(prefix, suffix, _tiles);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string serialize(const std::string& prefix, const std::string &suffix,
|
|
|
|
const std::vector<TileDesc> &tiles) const
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
|
|
|
std::ostringstream oss;
|
|
|
|
oss << prefix
|
2019-10-14 06:12:26 -05:00
|
|
|
<< " nviewid=" << _normalizedViewId
|
2016-05-22 10:31:36 -05:00
|
|
|
<< " part=" << _part
|
|
|
|
<< " width=" << _width
|
|
|
|
<< " height=" << _height
|
|
|
|
<< " tileposx=";
|
2019-04-19 19:53:12 -05:00
|
|
|
for (const auto& tile : tiles)
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
|
|
|
oss << tile.getTilePosX() << ',';
|
|
|
|
}
|
2017-01-04 06:36:13 -06:00
|
|
|
oss.seekp(-1, std::ios_base::cur); // Seek back over last comma, overwritten below.
|
2016-05-22 10:31:36 -05:00
|
|
|
|
|
|
|
oss << " tileposy=";
|
2019-04-19 19:53:12 -05:00
|
|
|
for (const auto& tile : tiles)
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
|
|
|
oss << tile.getTilePosY() << ',';
|
|
|
|
}
|
2017-01-04 06:36:13 -06:00
|
|
|
oss.seekp(-1, std::ios_base::cur); // Ditto.
|
2016-05-22 10:31:36 -05:00
|
|
|
|
2016-05-22 10:35:41 -05:00
|
|
|
oss << " imgsize=";
|
2019-04-19 19:53:12 -05:00
|
|
|
for (const auto& tile : tiles)
|
2016-05-22 10:35:41 -05:00
|
|
|
{
|
2017-01-04 06:36:13 -06:00
|
|
|
oss << tile.getImgSize() << ','; // Ditto.
|
2016-05-22 10:35:41 -05:00
|
|
|
}
|
2017-01-04 06:36:13 -06:00
|
|
|
oss.seekp(-1, std::ios_base::cur);
|
2016-05-22 10:35:41 -05:00
|
|
|
|
2016-05-22 10:31:36 -05:00
|
|
|
oss << " tilewidth=" << _tileWidth
|
|
|
|
<< " tileheight=" << _tileHeight;
|
2016-05-22 13:21:05 -05:00
|
|
|
|
2017-01-01 23:30:27 -06:00
|
|
|
oss << " ver=";
|
2019-04-19 19:53:12 -05:00
|
|
|
for (const auto& tile : tiles)
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
2017-01-01 23:30:27 -06:00
|
|
|
oss << tile.getVersion() << ',';
|
2016-05-22 10:31:36 -05:00
|
|
|
}
|
2017-01-04 06:36:13 -06:00
|
|
|
oss.seekp(-1, std::ios_base::cur); // Ditto.
|
2016-05-22 10:31:36 -05:00
|
|
|
|
2017-06-14 11:28:07 -05:00
|
|
|
oss << " oldwid=";
|
2019-04-19 19:53:12 -05:00
|
|
|
for (const auto& tile : tiles)
|
2017-01-04 06:36:13 -06:00
|
|
|
{
|
2017-06-14 11:28:07 -05:00
|
|
|
oss << tile.getOldWireId() << ',';
|
2017-01-04 06:36:13 -06:00
|
|
|
}
|
|
|
|
oss.seekp(-1, std::ios_base::cur); // Ditto
|
|
|
|
|
2017-06-14 11:28:07 -05:00
|
|
|
oss << " wid=";
|
2019-04-20 13:58:48 -05:00
|
|
|
|
|
|
|
bool comma = false;
|
2019-04-19 19:53:12 -05:00
|
|
|
for (const auto& tile : tiles)
|
2017-01-04 06:36:13 -06:00
|
|
|
{
|
2019-04-20 13:58:48 -05:00
|
|
|
if (comma)
|
|
|
|
oss << ',';
|
|
|
|
|
|
|
|
oss << tile.getWireId();
|
|
|
|
comma = true;
|
2017-01-04 06:36:13 -06:00
|
|
|
}
|
2017-01-01 23:30:27 -06:00
|
|
|
|
2022-08-30 00:27:44 -05:00
|
|
|
if (_mode)
|
|
|
|
oss << " mode=" << _mode;
|
|
|
|
|
2019-04-20 13:58:48 -05:00
|
|
|
oss << suffix;
|
|
|
|
return oss.str();
|
2016-05-22 10:31:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Deserialize a TileDesc from a tokenized string.
|
2020-02-28 03:50:58 -06:00
|
|
|
static TileCombined parse(const StringVector& tokens)
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
2023-09-14 07:39:08 -05:00
|
|
|
enum argenum { height, mode, nviewid, part, tileheight, tilewidth, width, maxEnum };
|
|
|
|
|
|
|
|
struct TileCombinedParseResults
|
|
|
|
{
|
|
|
|
typedef std::pair<const std::string_view, int> arg_value;
|
|
|
|
|
|
|
|
arg_value args[maxEnum] = {
|
|
|
|
{ STRINGIFY(height), 0 },
|
|
|
|
{ STRINGIFY(mode), 0 },
|
|
|
|
{ STRINGIFY(nviewid), 0 },
|
|
|
|
{ STRINGIFY(part), 0 },
|
|
|
|
{ STRINGIFY(tileheight), 0 },
|
|
|
|
{ STRINGIFY(tilewidth), 0 },
|
|
|
|
{ STRINGIFY(width), 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
TileCombinedParseResults()
|
|
|
|
{
|
|
|
|
static bool isSorted = TileParse::checkSorted(args, maxEnum);
|
|
|
|
assert(isSorted);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool set(const std::string_view arg, int value)
|
|
|
|
{
|
|
|
|
return TileParse::setArg(args, arg, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
int operator[](argenum arg) const
|
|
|
|
{
|
|
|
|
return args[arg].second;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-05-22 10:31:36 -05:00
|
|
|
// We don't expect undocumented fields and
|
|
|
|
// assume all values to be int.
|
2023-09-14 07:39:08 -05:00
|
|
|
TileCombinedParseResults pairs;
|
2016-05-22 10:31:36 -05:00
|
|
|
|
|
|
|
std::string tilePositionsX;
|
|
|
|
std::string tilePositionsY;
|
2016-05-22 10:35:41 -05:00
|
|
|
std::string imgSizes;
|
2017-01-01 23:30:27 -06:00
|
|
|
std::string versions;
|
2017-06-14 11:28:07 -05:00
|
|
|
std::string oldwireIds;
|
|
|
|
std::string wireIds;
|
2017-01-19 19:44:39 -06:00
|
|
|
|
|
|
|
for (const auto& token : tokens)
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
std::string value;
|
2021-11-18 06:08:14 -06:00
|
|
|
if (COOLProtocol::parseNameValuePair(tokens.getParam(token), name, value))
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
|
|
|
if (name == "tileposx")
|
|
|
|
{
|
|
|
|
tilePositionsX = value;
|
|
|
|
}
|
|
|
|
else if (name == "tileposy")
|
|
|
|
{
|
|
|
|
tilePositionsY = value;
|
|
|
|
}
|
2016-05-22 10:35:41 -05:00
|
|
|
else if (name == "imgsize")
|
|
|
|
{
|
|
|
|
imgSizes = value;
|
|
|
|
}
|
2017-01-01 23:30:27 -06:00
|
|
|
else if (name == "ver")
|
|
|
|
{
|
|
|
|
versions = value;
|
|
|
|
}
|
2017-06-14 11:28:07 -05:00
|
|
|
else if (name == "oldwid")
|
2017-01-04 06:36:13 -06:00
|
|
|
{
|
2017-06-14 11:28:07 -05:00
|
|
|
oldwireIds = value;
|
2017-01-04 06:36:13 -06:00
|
|
|
}
|
2017-06-14 11:28:07 -05:00
|
|
|
else if (name == "wid")
|
2017-01-04 06:36:13 -06:00
|
|
|
{
|
2017-06-14 11:28:07 -05:00
|
|
|
wireIds = value;
|
2017-01-04 06:36:13 -06:00
|
|
|
}
|
2016-05-22 10:31:36 -05:00
|
|
|
else
|
|
|
|
{
|
|
|
|
int v = 0;
|
2021-11-18 06:08:14 -06:00
|
|
|
if (COOLProtocol::stringToInteger(value, v))
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
2023-09-14 07:39:08 -05:00
|
|
|
pairs.set(name, v);
|
2016-05-22 10:31:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-14 07:39:08 -05:00
|
|
|
return TileCombined(pairs[nviewid], pairs[part], pairs[mode],
|
|
|
|
pairs[width], pairs[height],
|
2016-05-22 10:31:36 -05:00
|
|
|
tilePositionsX, tilePositionsY,
|
2023-09-14 07:39:08 -05:00
|
|
|
pairs[tilewidth], pairs[tileheight],
|
2019-04-19 16:48:41 -05:00
|
|
|
versions, imgSizes, oldwireIds, wireIds);
|
2016-05-22 10:31:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Deserialize a TileDesc from a string format.
|
2016-10-29 20:15:00 -05:00
|
|
|
static TileCombined parse(const std::string& message)
|
2016-05-22 10:31:36 -05:00
|
|
|
{
|
2022-03-29 20:37:57 -05:00
|
|
|
return parse(StringVector::tokenize(message.data(), message.size()));
|
2016-05-22 10:31:36 -05:00
|
|
|
}
|
|
|
|
|
2016-10-29 20:15:00 -05:00
|
|
|
static TileCombined create(const std::vector<TileDesc>& tiles)
|
2016-09-15 07:40:26 -05:00
|
|
|
{
|
|
|
|
assert(!tiles.empty());
|
|
|
|
|
|
|
|
std::ostringstream xs;
|
|
|
|
std::ostringstream ys;
|
2017-01-01 23:30:27 -06:00
|
|
|
std::ostringstream vers;
|
2017-01-04 06:36:13 -06:00
|
|
|
std::ostringstream oldhs;
|
|
|
|
std::ostringstream hs;
|
2016-09-15 07:40:26 -05:00
|
|
|
|
2017-01-01 23:30:27 -06:00
|
|
|
for (const auto& tile : tiles)
|
2016-09-15 07:40:26 -05:00
|
|
|
{
|
|
|
|
xs << tile.getTilePosX() << ',';
|
|
|
|
ys << tile.getTilePosY() << ',';
|
2017-01-01 23:30:27 -06:00
|
|
|
vers << tile.getVersion() << ',';
|
2017-06-14 11:28:07 -05:00
|
|
|
oldhs << tile.getOldWireId() << ',';
|
|
|
|
hs << tile.getWireId() << ',';
|
2016-09-15 07:40:26 -05:00
|
|
|
}
|
|
|
|
|
2017-01-01 23:30:27 -06:00
|
|
|
vers.seekp(-1, std::ios_base::cur); // Remove last comma.
|
2022-08-30 00:27:44 -05:00
|
|
|
return TileCombined(tiles[0].getNormalizedViewId(), tiles[0].getPart(), tiles[0].getEditMode(),
|
|
|
|
tiles[0].getWidth(), tiles[0].getHeight(),
|
2017-01-01 23:30:27 -06:00
|
|
|
xs.str(), ys.str(), tiles[0].getTileWidth(), tiles[0].getTileHeight(),
|
2019-04-19 16:48:41 -05:00
|
|
|
vers.str(), "", oldhs.str(), hs.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// To support legacy / under-used renderTile
|
2020-07-12 11:25:49 -05:00
|
|
|
explicit TileCombined(const TileDesc &desc)
|
2019-04-19 16:48:41 -05:00
|
|
|
{
|
|
|
|
_part = desc.getPart();
|
2022-08-30 00:27:44 -05:00
|
|
|
_mode = desc.getEditMode();
|
2019-04-19 16:48:41 -05:00
|
|
|
_width = desc.getWidth();
|
|
|
|
_height = desc.getHeight();
|
|
|
|
_tileWidth = desc.getTileWidth();
|
|
|
|
_tileHeight = desc.getTileHeight();
|
2019-10-14 06:12:26 -05:00
|
|
|
_normalizedViewId = desc.getNormalizedViewId();
|
2019-04-19 16:48:41 -05:00
|
|
|
_tiles.push_back(desc);
|
2023-08-15 09:32:53 -05:00
|
|
|
_isCompiled = false;
|
2016-09-15 07:40:26 -05:00
|
|
|
}
|
|
|
|
|
2016-05-22 10:31:36 -05:00
|
|
|
private:
|
|
|
|
std::vector<TileDesc> _tiles;
|
2019-10-14 06:12:26 -05:00
|
|
|
int _normalizedViewId;
|
2016-05-22 10:31:36 -05:00
|
|
|
int _part;
|
2022-08-30 00:27:44 -05:00
|
|
|
int _mode;
|
2016-05-22 10:31:36 -05:00
|
|
|
int _width;
|
|
|
|
int _height;
|
|
|
|
int _tileWidth;
|
|
|
|
int _tileHeight;
|
2023-08-15 09:32:53 -05:00
|
|
|
bool _isCompiled;
|
2016-05-22 10:31:36 -05:00
|
|
|
};
|
|
|
|
|
2016-05-21 08:41:23 -05:00
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|