blob: b597f8b827e9f277d594e0c92f3ff651904f67a8 [file] [log] [blame]
#include "utils/serializing_factory.hpp"
#include "rive/decoders/bitmap_decoder.hpp"
#include "rive/core/binary_reader.hpp"
#include <cstring>
#include <stdlib.h>
#include <filesystem>
#include <inttypes.h>
#include <unordered_map>
using namespace rive;
// Threshold for floating point tests.
static const float epsilon = 0.001f;
enum class SerializeOp : unsigned char
{
makeRenderBuffer = 0,
makeLinearGradient = 1,
makeRadialGradient = 2,
makeRenderPath = 3,
makeRenderPaint = 5,
decodeImage = 6,
save = 7,
restore = 8,
transform = 9,
drawPath = 10,
clipPath = 11,
drawImage = 12,
drawImageMesh = 13,
// RenderBuffer
setVertexBufferData = 14,
setIndexBufferData = 15,
// RenderPath
addRawPath = 16,
rewind = 17,
fillRule = 18,
// RenderPaint
style = 20,
color = 21,
thickness = 22,
join = 23,
cap = 24,
feather = 25,
blendMode = 26,
shader = 27,
frame = 28,
frameSize = 29,
};
static const char* opToName(SerializeOp op)
{
switch (op)
{
case SerializeOp::makeRenderBuffer:
return "makeRenderBuffer";
case SerializeOp::makeLinearGradient:
return "makeLinearGradient";
case SerializeOp::makeRadialGradient:
return "makeRadialGradient";
case SerializeOp::makeRenderPath:
return "makeRenderPath";
case SerializeOp::makeRenderPaint:
return "makeRenderPaint";
case SerializeOp::decodeImage:
return "decodeImage";
case SerializeOp::save:
return "save";
case SerializeOp::restore:
return "restore";
case SerializeOp::transform:
return "transform";
case SerializeOp::drawPath:
return "drawPath";
case SerializeOp::clipPath:
return "clipPath";
case SerializeOp::drawImage:
return "drawImage";
case SerializeOp::drawImageMesh:
return "drawImageMesh";
// RenderBuffer
case SerializeOp::setVertexBufferData:
return "setVertexBufferData";
case SerializeOp::setIndexBufferData:
return "setIndexBufferData";
// RenderPath
case SerializeOp::addRawPath:
return "addRawPath";
case SerializeOp::rewind:
return "rewind";
case SerializeOp::fillRule:
return "fillRule";
// RenderPaint
case SerializeOp::style:
return "style";
case SerializeOp::color:
return "color";
case SerializeOp::thickness:
return "thickness";
case SerializeOp::join:
return "join";
case SerializeOp::cap:
return "cap";
case SerializeOp::feather:
return "feather";
case SerializeOp::blendMode:
return "blendMode";
case SerializeOp::shader:
return "shader";
case SerializeOp::frame:
return "frame";
case SerializeOp::frameSize:
return "frameSize";
}
return "???";
}
class SerializingRenderImage : public RenderImage
{
public:
SerializingRenderImage(uint64_t id, uint32_t width, uint32_t height) :
m_id(id)
{
m_Width = width;
m_Height = height;
}
uint64_t id() const { return m_id; }
private:
uint64_t m_id;
};
static void serializeRawPath(BinaryWriter* writer, const RawPath& path)
{
auto verbs = path.verbs();
auto points = path.points();
writer->writeVarUint((uint64_t)verbs.size());
for (auto verb : verbs)
{
writer->writeVarUint((uint64_t)verb);
}
writer->writeVarUint((uint64_t)points.size());
for (auto point : points)
{
writer->writeFloat(point.x);
writer->writeFloat(point.y);
}
}
class SerializingRenderShader : public RenderShader
{
public:
SerializingRenderShader(uint64_t id) : m_id(id) {}
uint64_t id() const { return m_id; }
private:
uint64_t m_id;
};
class SerializingRenderPaint : public RenderPaint
{
public:
SerializingRenderPaint(BinaryWriter* writer, uint64_t id) :
m_id(id), m_writer(writer)
{
m_writer->writeVarUint((uint32_t)SerializeOp::makeRenderPaint);
m_writer->writeVarUint(m_id);
}
void color(unsigned int value) override
{
if (m_color == value)
{
return;
}
m_color = value;
m_writer->writeVarUint((uint32_t)SerializeOp::color);
m_writer->writeVarUint(m_id);
m_writer->writeVarUint(m_color);
}
void style(RenderPaintStyle value) override
{
if (m_stroked == (value == RenderPaintStyle::stroke))
{
return;
}
m_stroked = value == RenderPaintStyle::stroke;
m_writer->writeVarUint((uint32_t)SerializeOp::style);
m_writer->writeVarUint(m_id);
m_writer->writeVarUint((uint32_t)(m_stroked ? 0 : 1));
}
void thickness(float value) override
{
if (m_thickness == value)
{
return;
}
m_thickness = value;
m_writer->writeVarUint((uint32_t)SerializeOp::thickness);
m_writer->writeVarUint(m_id);
m_writer->writeFloat(m_thickness);
}
void join(StrokeJoin value) override
{
if (m_join == value)
{
return;
}
m_join = value;
m_writer->writeVarUint((uint32_t)SerializeOp::join);
m_writer->writeVarUint(m_id);
m_writer->writeVarUint((uint32_t)m_join);
}
void cap(StrokeCap value) override
{
if (m_cap == value)
{
return;
}
m_cap = value;
m_writer->writeVarUint((uint32_t)SerializeOp::cap);
m_writer->writeVarUint(m_id);
m_writer->writeVarUint((uint32_t)m_cap);
}
void blendMode(BlendMode value) override
{
if (m_blendMode == value)
{
return;
}
m_blendMode = value;
m_writer->writeVarUint((uint32_t)SerializeOp::blendMode);
m_writer->writeVarUint(m_id);
m_writer->writeVarUint((uint32_t)m_blendMode);
}
void shader(rcp<RenderShader> shader) override
{
if (m_shader == shader)
{
return;
}
m_shader = shader;
m_writer->writeVarUint((uint32_t)SerializeOp::shader);
m_writer->writeVarUint(m_id);
m_writer->writeVarUint(
shader == nullptr
? 0
: static_cast<SerializingRenderShader*>(shader.get())->id());
}
void invalidateStroke() override {}
void feather(float value) override
{
if (m_feather == value)
{
return;
}
m_feather = value;
m_writer->writeVarUint((uint32_t)SerializeOp::feather);
m_writer->writeVarUint(m_id);
m_writer->writeFloat(m_feather);
}
uint64_t id() const { return m_id; }
private:
uint64_t m_id;
BinaryWriter* m_writer;
rcp<RenderShader> m_shader;
unsigned int m_color = 0xFF000000;
float m_thickness = 1;
StrokeJoin m_join = StrokeJoin::miter;
StrokeCap m_cap = StrokeCap::butt;
float m_feather = 0;
BlendMode m_blendMode = BlendMode::srcOver;
bool m_stroked = false;
};
class SerializingRenderPath : public RenderPath
{
public:
void rewind() override
{
m_writer->writeVarUint((uint32_t)SerializeOp::rewind);
m_writer->writeVarUint(m_id);
}
void fillRule(FillRule value) override
{
if (m_fillRule == value)
{
return;
}
m_fillRule = value;
m_writer->writeVarUint((uint32_t)SerializeOp::fillRule);
m_writer->writeVarUint(m_id);
m_writer->writeVarUint((uint64_t)value);
}
void addPath(CommandPath* path, const Mat2D& transform) override
{
RIVE_UNREACHABLE();
}
void addRenderPath(RenderPath* path, const Mat2D& transform) override
{
RIVE_UNREACHABLE();
}
void moveTo(float x, float y) override { RIVE_UNREACHABLE(); }
void lineTo(float x, float y) override { RIVE_UNREACHABLE(); }
void cubicTo(float ox, float oy, float ix, float iy, float x, float y)
override
{
RIVE_UNREACHABLE();
}
void close() override { RIVE_UNREACHABLE(); }
void addRawPath(const RawPath& path) override
{
m_rawPath.addPath(path, nullptr);
m_writer->writeVarUint((uint32_t)SerializeOp::addRawPath);
m_writer->writeVarUint(m_id);
serializeRawPath(m_writer, path);
}
SerializingRenderPath(BinaryWriter* writer, uint64_t id) :
m_id(id), m_writer(writer)
{
m_writer->writeVarUint((uint32_t)SerializeOp::makeRenderPath);
m_writer->writeVarUint(m_id);
}
SerializingRenderPath(BinaryWriter* writer,
uint64_t id,
const RawPath& path,
FillRule fillRule) :
m_id(id), m_fillRule(fillRule), m_rawPath(path), m_writer(writer)
{
m_writer->writeVarUint((uint32_t)SerializeOp::makeRenderPath);
m_writer->writeVarUint(m_id);
this->fillRule(fillRule);
addRawPath(path);
}
uint64_t id() const { return m_id; }
private:
uint64_t m_id;
FillRule m_fillRule = FillRule::nonZero;
RawPath m_rawPath;
BinaryWriter* m_writer;
};
class SerializingRenderBuffer : public RenderBuffer
{
public:
SerializingRenderBuffer(BinaryWriter* writer,
uint64_t id,
RenderBufferType type,
RenderBufferFlags flags,
size_t sizeInBytes) :
RenderBuffer(type, flags, sizeInBytes),
m_writer(writer),
m_bytes(sizeInBytes),
m_id(id)
{
m_writer->writeVarUint((uint32_t)SerializeOp::makeRenderBuffer);
m_writer->writeVarUint(m_id);
m_writer->writeVarUint((uint64_t)sizeInBytes);
m_writer->writeVarUint((uint32_t)type);
m_writer->writeVarUint((uint32_t)flags);
}
uint64_t id() const { return m_id; }
void* onMap() override { return m_bytes.data(); }
void onUnmap() override
{
switch (type())
{
case RenderBufferType::index:
m_writer->writeVarUint(
(uint32_t)SerializeOp::setIndexBufferData);
break;
case RenderBufferType::vertex:
m_writer->writeVarUint(
(uint32_t)SerializeOp::setVertexBufferData);
break;
default:
RIVE_UNREACHABLE();
}
m_writer->writeVarUint(m_id);
switch (type())
{
case RenderBufferType::vertex:
{
auto count = m_bytes.size() / sizeof(float);
auto floatBuffer = reinterpret_cast<float*>(m_bytes.data());
for (size_t i = 0; i < count; i++)
{
m_writer->writeFloat(floatBuffer[i]);
}
break;
}
case RenderBufferType::index:
{
auto count = m_bytes.size() / sizeof(uint16_t);
auto shortBuffer = reinterpret_cast<uint16_t*>(m_bytes.data());
for (size_t i = 0; i < count; i++)
{
m_writer->writeVarUint((uint32_t)shortBuffer[i]);
}
break;
}
}
}
private:
BinaryWriter* m_writer;
std::vector<uint8_t> m_bytes;
uint64_t m_id;
};
rcp<RenderBuffer> SerializingFactory::makeRenderBuffer(RenderBufferType type,
RenderBufferFlags flags,
size_t size)
{
return make_rcp<SerializingRenderBuffer>(&m_writer,
m_renderBufferId++,
type,
flags,
size);
}
rcp<RenderShader> SerializingFactory::makeLinearGradient(
float sx,
float sy,
float ex,
float ey,
const ColorInt colors[], // [count]
const float stops[], // [count]
size_t count)
{
auto id = m_renderShaderId++;
m_writer.writeVarUint((uint32_t)SerializeOp::makeLinearGradient);
m_writer.writeVarUint(id);
m_writer.writeVarUint((uint64_t)count);
for (auto i = 0; i < count; i++)
{
m_writer.writeVarUint(colors[i]);
m_writer.writeFloat(stops[i]);
}
m_writer.writeFloat(sx);
m_writer.writeFloat(sy);
m_writer.writeFloat(ex);
m_writer.writeFloat(ey);
return make_rcp<SerializingRenderShader>(id);
}
rcp<RenderShader> SerializingFactory::makeRadialGradient(
float cx,
float cy,
float radius,
const ColorInt colors[], // [count]
const float stops[], // [count]
size_t count)
{
auto id = m_renderShaderId++;
m_writer.writeVarUint((uint32_t)SerializeOp::makeRadialGradient);
m_writer.writeVarUint(id);
m_writer.writeVarUint((uint64_t)count);
for (auto i = 0; i < count; i++)
{
m_writer.writeVarUint(colors[i]);
m_writer.writeFloat(stops[i]);
}
m_writer.writeFloat(cx);
m_writer.writeFloat(cy);
m_writer.writeFloat(radius);
return make_rcp<SerializingRenderShader>(id);
}
rcp<RenderPath> SerializingFactory::makeRenderPath(RawPath& rawPath,
FillRule fillRule)
{
return make_rcp<SerializingRenderPath>(&m_writer,
m_renderPathId++,
rawPath,
fillRule);
}
rcp<RenderPath> SerializingFactory::makeEmptyRenderPath()
{
return make_rcp<SerializingRenderPath>(&m_writer, m_renderPathId++);
}
rcp<RenderPaint> SerializingFactory::makeRenderPaint()
{
return make_rcp<SerializingRenderPaint>(&m_writer, m_renderPaintId++);
}
rcp<RenderImage> SerializingFactory::decodeImage(Span<const uint8_t> data)
{
auto id = m_renderImageId++;
m_writer.writeVarUint((uint32_t)SerializeOp::decodeImage);
m_writer.writeVarUint(id);
m_writer.writeVarUint((uint64_t)data.size());
m_writer.write(data.data(), data.size());
auto bitmap = Bitmap::decode(data.data(), data.size());
if (!bitmap)
{
return nullptr;
}
return make_rcp<SerializingRenderImage>(id,
bitmap->width(),
bitmap->height());
}
class SerializingRenderer : public Renderer
{
public:
SerializingRenderer(BinaryWriter* writer) : m_writer(writer) {}
void save() override
{
m_writer->writeVarUint((uint32_t)SerializeOp::save);
}
void restore() override
{
m_writer->writeVarUint((uint32_t)SerializeOp::restore);
}
void transform(const Mat2D& mat) override
{
m_writer->writeVarUint((uint32_t)SerializeOp::transform);
for (int i = 0; i < 6; i++)
{
m_writer->writeFloat(mat[i]);
}
}
void drawPath(RenderPath* path, RenderPaint* paint) override
{
m_writer->writeVarUint((uint32_t)SerializeOp::drawPath);
m_writer->writeVarUint(static_cast<SerializingRenderPath*>(path)->id());
m_writer->writeVarUint(
static_cast<SerializingRenderPaint*>(paint)->id());
}
void clipPath(RenderPath* path) override
{
m_writer->writeVarUint((uint32_t)SerializeOp::clipPath);
m_writer->writeVarUint(static_cast<SerializingRenderPath*>(path)->id());
}
virtual void drawImage(const RenderImage* image,
ImageSampler samplerOptions,
BlendMode blendMode,
float opacity) override
{
m_writer->writeVarUint((uint32_t)SerializeOp::drawImage);
m_writer->writeVarUint(
static_cast<const SerializingRenderImage*>(image)->id());
m_writer->writeVarUint((uint32_t)blendMode);
m_writer->writeFloat(opacity);
}
virtual void drawImageMesh(const RenderImage* image,
ImageSampler samplerOptions,
rcp<RenderBuffer> positions,
rcp<RenderBuffer> uvs,
rcp<RenderBuffer> indices,
uint32_t vertexCount,
uint32_t indexCount,
BlendMode blendMode,
float opacity) override
{
m_writer->writeVarUint((uint32_t)SerializeOp::drawImageMesh);
m_writer->writeVarUint(
static_cast<const SerializingRenderImage*>(image)->id());
m_writer->writeVarUint((uint32_t)blendMode);
m_writer->writeFloat(opacity);
m_writer->writeVarUint(
static_cast<SerializingRenderBuffer*>(positions.get())->id());
m_writer->writeVarUint(
static_cast<SerializingRenderBuffer*>(uvs.get())->id());
m_writer->writeVarUint(
static_cast<SerializingRenderBuffer*>(indices.get())->id());
}
private:
BinaryWriter* m_writer;
};
SerializingFactory::SerializingFactory() : m_writer(&m_buffer)
{
m_writer.write((const uint8_t*)"SRIV", 4);
m_writer.writeVarUint((uint32_t)1);
}
std::unique_ptr<Renderer> SerializingFactory::makeRenderer()
{
return rivestd::make_unique<SerializingRenderer>(&m_writer);
}
void SerializingFactory::addFrame()
{
m_writer.writeVarUint((uint32_t)SerializeOp::frame);
}
void SerializingFactory::frameSize(uint32_t width, uint32_t height)
{
m_writer.writeVarUint((uint32_t)SerializeOp::frameSize);
m_writer.writeVarUint(width);
m_writer.writeVarUint(height);
}
void SerializingFactory::save(const char* filename)
{
FILE* fp = fopen(filename, "wb");
fwrite(m_buffer.data(), 1, m_buffer.size(), fp);
fclose(fp);
}
void SerializingFactory::saveTarnished(const char* filename)
{
auto path = std::string("silvers/tarnished/");
if (!std::filesystem::exists(path))
{
if (!std::filesystem::create_directories(path))
{
fprintf(stderr, "failed to create directory %s\n", path.c_str());
}
}
auto fullFileName = path + std::string(filename) + std::string(".sriv");
save(fullFileName.c_str());
}
static bool varUintMatches(uint64_t op,
std::string name,
BinaryReader& readerA,
BinaryReader& readerB,
uint64_t* value = nullptr)
{
auto valueA = readerA.readVarUint64();
auto valueB = readerB.readVarUint64();
if (valueA != valueB)
{
fprintf(stderr,
"%s for %s doesn't match %" PRIu64 " != %" PRIu64 "\n",
name.c_str(),
opToName((SerializeOp)op),
valueA,
valueB);
return false;
}
if (value != nullptr)
{
*value = valueA;
}
return true;
}
static bool bytesMatches(uint64_t op,
std::string name,
uint64_t size,
BinaryReader& readerA,
BinaryReader& readerB)
{
for (int i = 0; i < size; i++)
{
auto valueA = readerA.readByte();
auto valueB = readerB.readByte();
if (valueA != valueB)
{
fprintf(stderr,
"%s [%i] for %s doesn't match %hhu != %hhu\n",
name.c_str(),
i,
opToName((SerializeOp)op),
valueA,
valueB);
return false;
}
}
return true;
}
static bool floatMatches(uint64_t op,
std::string name,
BinaryReader& readerA,
BinaryReader& readerB,
float* value = nullptr)
{
auto valueA = readerA.readFloat32();
auto valueB = readerB.readFloat32();
if (std::abs(valueA - valueB) > epsilon)
{
fprintf(stderr,
"%s for %s doesn't match %f != %f\n",
name.c_str(),
opToName((SerializeOp)op),
valueA,
valueB);
return false;
}
if (value != nullptr)
{
*value = valueA;
}
return true;
}
static bool shortMatches(uint64_t op,
std::string name,
BinaryReader& readerA,
BinaryReader& readerB,
uint16_t* value = nullptr)
{
auto valueA = readerA.readUint16();
auto valueB = readerB.readUint16();
if (valueA != valueB)
{
fprintf(stderr,
"%s for %s doesn't match %i != %i\n",
name.c_str(),
opToName((SerializeOp)op),
valueA,
valueB);
return false;
}
if (value != nullptr)
{
*value = valueA;
}
return true;
}
static bool vec2DMatches(uint64_t op,
std::string name,
BinaryReader& readerA,
BinaryReader& readerB,
Vec2D* value = nullptr)
{
auto ax = readerA.readFloat32();
auto ay = readerA.readFloat32();
auto bx = readerB.readFloat32();
auto by = readerB.readFloat32();
// if (ax != bx || ay != by)
if (rive::Vec2D::distance(Vec2D(ax, ay), Vec2D(bx, by)) > epsilon)
{
fprintf(stderr,
"%s for %s doesn't match (%f, %f) != (%f, %f)\n",
name.c_str(),
opToName((SerializeOp)op),
ax,
ay,
bx,
by);
return false;
}
if (value != nullptr)
{
*value = Vec2D(ax, ay);
}
return true;
}
static bool gradientMatches(uint64_t op,
std::string name,
BinaryReader& readerA,
BinaryReader& readerB,
Vec2D* value = nullptr)
{
if (!varUintMatches(op,
std::string("make_") + name + std::string("_id"),
readerA,
readerB))
{
return false;
}
uint64_t count = 0;
if (!varUintMatches(op,
std::string("make_") + name + std::string("_count"),
readerA,
readerB,
&count))
{
return false;
}
for (size_t i = 0; i < count; i++)
{
std::string colorName = std::string("make_") + name +
std::string("_color_") + std::to_string(i);
if (!varUintMatches(op, colorName, readerA, readerB))
{
return false;
}
std::string stopName = std::string("make_") + name +
std::string("_stop_") + std::to_string(i);
if (!floatMatches(op, stopName, readerA, readerB))
{
return false;
}
}
return true;
}
bool advancedMatch(std::vector<uint8_t>& fileA, std::vector<uint8_t>& fileB)
{
BinaryReader readerA(fileA);
BinaryReader readerB(fileB);
if (readerA.readByte() != 'S' || readerA.readByte() != 'R' ||
readerA.readByte() != 'I' || readerA.readByte() != 'V')
{
fprintf(stderr, "advancedMatch: invalid header A\n");
return false;
}
if (readerB.readByte() != 'S' || readerB.readByte() != 'R' ||
readerB.readByte() != 'I' || readerB.readByte() != 'V')
{
fprintf(stderr, "advancedMatch: invalid header B\n");
return false;
}
if (readerA.readVarUint64() != 1 || readerB.readVarUint64() != 1)
{
fprintf(stderr, "advancedMatch: invalid version\n");
return false;
}
std::unordered_map<uint64_t, uint64_t> renderBufferSizes;
while (!readerA.reachedEnd())
{
if (readerB.reachedEnd())
{
fprintf(stderr, "generated file is shorter.\n");
return false;
}
auto opA = readerA.readVarUint64();
auto opB = readerB.readVarUint64();
if (opA != opB)
{
fprintf(stderr,
"expected %s but got %s\n",
opToName((SerializeOp)opA),
opToName((SerializeOp)opB));
}
switch ((SerializeOp)opA)
{
case SerializeOp::makeRenderBuffer:
{
uint64_t id = 0;
uint64_t size = 0;
if (!varUintMatches(opA,
"make_renderbuffer_id",
readerA,
readerB,
&id))
{
return false;
}
if (!varUintMatches(opA,
"make_renderbuffer_size",
readerA,
readerB,
&size))
{
return false;
}
if (!varUintMatches(opA,
"make_renderbuffer_flags",
readerA,
readerB))
{
return false;
}
renderBufferSizes[id] = size;
break;
}
case SerializeOp::makeLinearGradient:
if (!gradientMatches(opA, "lineargradient", readerA, readerB))
{
return false;
}
if (!vec2DMatches(opA,
"make_lineargradient_start",
readerA,
readerB))
{
return false;
}
if (!vec2DMatches(opA,
"make_lineargradient_end",
readerA,
readerB))
{
return false;
}
break;
case SerializeOp::makeRadialGradient:
if (!gradientMatches(opA, "lineargradient", readerA, readerB))
{
return false;
}
if (!vec2DMatches(opA,
"make_lineargradient_center",
readerA,
readerB))
{
return false;
}
if (!floatMatches(opA,
"make_lineargradient_radius",
readerA,
readerB))
{
return false;
}
break;
case SerializeOp::makeRenderPath:
if (!varUintMatches(opA,
"make_renderpath_id",
readerA,
readerB))
{
return false;
}
break;
case SerializeOp::makeRenderPaint:
if (!varUintMatches(opA,
"make_renderpaint_id",
readerA,
readerB))
{
return false;
}
break;
case SerializeOp::decodeImage:
{
if (!varUintMatches(opA, "decodeimage_id", readerA, readerB))
{
return false;
}
uint64_t size = 0;
if (!varUintMatches(opA,
"decodeimage_size",
readerA,
readerB,
&size))
{
return false;
}
if (!bytesMatches(opA,
"decodeimage_bytes",
size,
readerA,
readerB))
{
return false;
}
break;
}
case SerializeOp::save:
break;
case SerializeOp::restore:
break;
case SerializeOp::transform:
for (int i = 0; i < 6; i++)
{
if (!floatMatches(opA,
std::string("transform[") +
std::to_string(i) + std::string("]"),
readerA,
readerB))
{
return false;
}
}
break;
case SerializeOp::drawPath:
if (!varUintMatches(opA, "drawpath_id", readerA, readerB))
{
return false;
}
if (!varUintMatches(opA, "drawpath_paint_id", readerA, readerB))
{
return false;
}
break;
case SerializeOp::clipPath:
if (!varUintMatches(opA, "clippath_id", readerA, readerB))
{
return false;
}
break;
case SerializeOp::drawImage:
if (!varUintMatches(opA, "drawimage_id", readerA, readerB))
{
return false;
}
if (!varUintMatches(opA,
"drawimage_blendmode",
readerA,
readerB))
{
return false;
}
if (!floatMatches(opA, "drawimage_opacity", readerA, readerB))
{
return false;
}
break;
case SerializeOp::drawImageMesh:
if (!varUintMatches(opA, "drawimagemesh_id", readerA, readerB))
{
return false;
}
if (!varUintMatches(opA,
"drawimagemesh_blendmode",
readerA,
readerB))
{
return false;
}
if (!floatMatches(opA,
"drawimagemesh_opacity",
readerA,
readerB))
{
return false;
}
if (!varUintMatches(opA,
"drawimagemesh_vertex_id",
readerA,
readerB))
{
return false;
}
if (!varUintMatches(opA,
"drawimagemesh_uv_id",
readerA,
readerB))
{
return false;
}
if (!varUintMatches(opA,
"drawimagemesh_index_id",
readerA,
readerB))
{
return false;
}
break;
case SerializeOp::setVertexBufferData:
{
uint64_t id = 0;
if (!varUintMatches(opA,
"setvertexbufferdata_id",
readerA,
readerB,
&id))
{
return false;
}
if (renderBufferSizes.find(id) == renderBufferSizes.end())
{
fprintf(stderr,
"could not find render buffer with id: %" PRIu64
"\n",
id);
return false;
}
uint64_t size = renderBufferSizes[id];
uint64_t floatCount = size / sizeof(float);
for (int i = 0; i < floatCount; i++)
{
if (!floatMatches(opA,
std::string("setvertexbufferdata_[") +
std::to_string(i) + std::string("]"),
readerA,
readerB))
{
return false;
}
}
break;
}
case SerializeOp::setIndexBufferData:
{
uint64_t id = 0;
if (!varUintMatches(opA,
"setindexbufferdata_id",
readerA,
readerB,
&id))
{
return false;
}
if (renderBufferSizes.find(id) == renderBufferSizes.end())
{
fprintf(stderr,
"could not find render buffer with id: %" PRIu64
"\n",
id);
return false;
}
uint64_t size = renderBufferSizes[id];
uint64_t shortCount = size / sizeof(uint16_t);
for (int i = 0; i < shortCount; i++)
{
if (!shortMatches(opA,
std::string("setindexbufferdata_[") +
std::to_string(i) + std::string("]"),
readerA,
readerB))
{
return false;
}
}
break;
}
// RenderPath
case SerializeOp::addRawPath:
{
uint64_t verbCount = 0;
uint64_t pointCount = 0;
if (!varUintMatches(opA, "addrawpath_id", readerA, readerB))
{
return false;
}
if (!varUintMatches(opA,
"addrawpath_verb_count",
readerA,
readerB,
&verbCount))
{
return false;
}
for (int i = 0; i < verbCount; i++)
{
if (!varUintMatches(opA,
std::string("addrawpath_verb[") +
std::to_string(i) +
std::string("]"),
readerA,
readerB))
{
return false;
}
}
if (!varUintMatches(opA,
"addrawpath_point_count",
readerA,
readerB,
&pointCount))
{
return false;
}
for (int i = 0; i < pointCount; i++)
{
if (!vec2DMatches(opA,
std::string("addrawpath_point[") +
std::to_string(i) + std::string("]"),
readerA,
readerB))
{
return false;
}
}
}
break;
case SerializeOp::rewind:
if (!varUintMatches(opA, "rewind_path_id", readerA, readerB))
{
return false;
}
break;
case SerializeOp::fillRule:
if (!varUintMatches(opA, "fillrule_path_id", readerA, readerB))
{
return false;
}
if (!varUintMatches(opA, "fillrule_value", readerA, readerB))
{
return false;
}
break;
// RenderPaint
case SerializeOp::style:
if (!varUintMatches(opA, "style_paint_id", readerA, readerB))
{
return false;
}
if (!varUintMatches(opA, "style_value", readerA, readerB))
{
return false;
}
break;
case SerializeOp::color:
if (!varUintMatches(opA, "color_paint_id", readerA, readerB))
{
return false;
}
if (!varUintMatches(opA, "color_value", readerA, readerB))
{
return false;
}
break;
case SerializeOp::thickness:
if (!varUintMatches(opA,
"thickness_paint_id",
readerA,
readerB))
{
return false;
}
if (!floatMatches(opA, "thickness_value", readerA, readerB))
{
return false;
}
break;
case SerializeOp::join:
if (!varUintMatches(opA, "join_paint_id", readerA, readerB))
{
return false;
}
if (!varUintMatches(opA, "join_value", readerA, readerB))
{
return false;
}
break;
case SerializeOp::cap:
if (!varUintMatches(opA, "cap_paint_id", readerA, readerB))
{
return false;
}
if (!varUintMatches(opA, "cap_value", readerA, readerB))
{
return false;
}
break;
case SerializeOp::feather:
if (!varUintMatches(opA, "feather_paint_id", readerA, readerB))
{
return false;
}
if (!floatMatches(opA, "feather_value", readerA, readerB))
{
return false;
}
break;
case SerializeOp::blendMode:
if (!varUintMatches(opA,
"blendmode_paint_id",
readerA,
readerB))
{
return false;
}
if (!varUintMatches(opA, "blendmode_value", readerA, readerB))
{
return false;
}
break;
case SerializeOp::shader:
if (!varUintMatches(opA,
"setgradient_paint_id",
readerA,
readerB))
{
return false;
}
if (!varUintMatches(opA, "setgradient_value", readerA, readerB))
{
return false;
}
break;
case SerializeOp::frame:
break;
case SerializeOp::frameSize:
if (!varUintMatches(opA, "framesize_width", readerA, readerB))
{
return false;
}
if (!varUintMatches(opA, "framesize_height", readerA, readerB))
{
return false;
}
}
}
if (!readerB.reachedEnd())
{
fprintf(stderr, "generated file is longer, otherwise matches.\n");
return false;
}
// for (size_t i = 0; i < length; i++)
// {
// if (fileA[i] != fileB[i])
// {
// fprintf(stderr,
// "SerializingFactory::matches - %s buffer did not match "
// "generated one.\n",
// filename);
// return false;
// }
// }
return true;
}
bool SerializingFactory::matches(const char* filename)
{
auto fullFileName =
std::string("silvers/") + std::string(filename) + std::string(".sriv");
const char* rebaseline = getenv("REBASELINE_SILVERS");
if (rebaseline != nullptr)
{
save(fullFileName.c_str());
return true;
}
FILE* fp = fopen(fullFileName.c_str(), "rb");
if (fp == nullptr)
{
fprintf(stderr,
"SerializingFactory::matches - %s is missing\n",
fullFileName.c_str());
return false;
}
fseek(fp, 0, SEEK_END);
const size_t length = ftell(fp);
if (m_buffer.size() != length)
{
fprintf(stderr,
"SerializingFactory::matches - %s size differs from generated "
"one %zu != %zu.\n",
filename,
m_buffer.size(),
length);
fclose(fp);
saveTarnished(filename);
return false;
}
fseek(fp, 0, SEEK_SET);
std::vector<uint8_t> existing(length);
if (fread(existing.data(), 1, length, fp) != length)
{
fprintf(stderr,
"SerializingFactory::matches - %s could not be read.\n",
filename);
return false;
}
fclose(fp);
if (!advancedMatch(existing, m_buffer))
{
saveTarnished(filename);
return false;
}
return true;
}