|
@@ -32,106 +32,154 @@
|
|
|
namespace Rocket {
|
|
namespace Rocket {
|
|
|
namespace Core {
|
|
namespace Core {
|
|
|
|
|
|
|
|
-DecoratorTiledInstancer::~DecoratorTiledInstancer()
|
|
|
|
|
|
|
+DecoratorTiledInstancer::DecoratorTiledInstancer(size_t num_tiles)
|
|
|
{
|
|
{
|
|
|
|
|
+ tile_property_ids.reserve(num_tiles);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Adds the property declarations for a tile.
|
|
// Adds the property declarations for a tile.
|
|
|
void DecoratorTiledInstancer::RegisterTileProperty(const String& name, bool register_repeat_modes)
|
|
void DecoratorTiledInstancer::RegisterTileProperty(const String& name, bool register_repeat_modes)
|
|
|
{
|
|
{
|
|
|
- TilePropertyIds tile = {};
|
|
|
|
|
|
|
+ TilePropertyIds ids = {};
|
|
|
|
|
|
|
|
- tile.src = RegisterProperty(CreateString(32, "%s-src", name.c_str()), "").AddParser("string").GetId();
|
|
|
|
|
- tile.s_begin = RegisterProperty(CreateString(32, "%s-s-begin", name.c_str()), "0").AddParser("length").GetId();
|
|
|
|
|
- tile.s_end = RegisterProperty(CreateString(32, "%s-s-end", name.c_str()), "1").AddParser("length").GetId();
|
|
|
|
|
- tile.t_begin = RegisterProperty(CreateString(32, "%s-t-begin", name.c_str()), "0").AddParser("length").GetId();
|
|
|
|
|
- tile.t_end = RegisterProperty(CreateString(32, "%s-t-end", name.c_str()), "1").AddParser("length").GetId();
|
|
|
|
|
- RegisterShorthand(CreateString(32, "%s-s", name.c_str()), CreateString(64, "%s-s-begin, %s-s-end", name.c_str(), name.c_str()), ShorthandType::FallThrough);
|
|
|
|
|
- RegisterShorthand(CreateString(32, "%s-t", name.c_str()), CreateString(64, "%s-t-begin, %s-t-end", name.c_str(), name.c_str()), ShorthandType::FallThrough);
|
|
|
|
|
|
|
+ ids.src = RegisterProperty(CreateString(32, "%s-src", name.c_str()), "").AddParser("string").GetId();
|
|
|
|
|
+ ids.x = RegisterProperty(CreateString(32, "%s-x", name.c_str()), "0px").AddParser("number_length_percent").GetId();
|
|
|
|
|
+ ids.y = RegisterProperty(CreateString(32, "%s-y", name.c_str()), "0px").AddParser("number_length_percent").GetId();
|
|
|
|
|
+ ids.width = RegisterProperty(CreateString(32, "%s-width", name.c_str()), "0px").AddParser("number_length_percent").GetId();
|
|
|
|
|
+ ids.height = RegisterProperty(CreateString(32, "%s-height", name.c_str()), "0px").AddParser("number_length_percent").GetId();
|
|
|
|
|
+ RegisterShorthand(CreateString(32, "%s-pos", name.c_str()), CreateString(64, "%s-x, %s-y", name.c_str(), name.c_str()), ShorthandType::FallThrough);
|
|
|
|
|
+ RegisterShorthand(CreateString(32, "%s-size", name.c_str()), CreateString(64, "%s-width, %s-height", name.c_str(), name.c_str()), ShorthandType::FallThrough);
|
|
|
|
|
|
|
|
if (register_repeat_modes)
|
|
if (register_repeat_modes)
|
|
|
{
|
|
{
|
|
|
- tile.repeat = RegisterProperty(CreateString(32, "%s-repeat", name.c_str()), "stretch")
|
|
|
|
|
|
|
+ ids.repeat = RegisterProperty(CreateString(32, "%s-repeat", name.c_str()), "stretch")
|
|
|
.AddParser("keyword", "stretch, clamp-stretch, clamp-truncate, repeat-stretch, repeat-truncate")
|
|
.AddParser("keyword", "stretch, clamp-stretch, clamp-truncate, repeat-stretch, repeat-truncate")
|
|
|
.GetId();
|
|
.GetId();
|
|
|
- RegisterShorthand(name, CreateString(256, "%s-src, %s-repeat, %s-s-begin, %s-t-begin, %s-s-end, %s-t-end", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()), ShorthandType::FallThrough);
|
|
|
|
|
|
|
+ RegisterShorthand(name, CreateString(256, "%s-src, %s-repeat, %s-x, %s-y, %s-width, %s-height", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()), ShorthandType::FallThrough);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
- RegisterShorthand(name, CreateString(256, "%s-src, %s-s-begin, %s-t-begin, %s-s-end, %s-t-end", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()), ShorthandType::FallThrough);
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ ids.repeat = PropertyId::Invalid;
|
|
|
|
|
+ RegisterShorthand(name, CreateString(256, "%s-src, %s-x, %s-y, %s-width, %s-height", name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()), ShorthandType::FallThrough);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // @performance: Reserve number of tiles on construction
|
|
|
|
|
- tile_property_ids.push_back(tile);
|
|
|
|
|
|
|
+ tile_property_ids.push_back(ids);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Retrieves all the properties for a tile from the property dictionary.
|
|
|
|
|
-void DecoratorTiledInstancer::GetTileProperties(size_t tile_index, DecoratorTiled::Tile& tile, String& texture_name, String& rcss_path, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface)
|
|
|
|
|
|
|
+
|
|
|
|
|
+// Loads a single texture coordinate value from the properties.
|
|
|
|
|
+static void LoadTexCoord(const Property& property, float& tex_coord, bool& tex_coord_absolute)
|
|
|
{
|
|
{
|
|
|
- ROCKET_ASSERT(tile_index < tile_property_ids.size());
|
|
|
|
|
-
|
|
|
|
|
- const TilePropertyIds& ids = tile_property_ids[tile_index];
|
|
|
|
|
-
|
|
|
|
|
- const Property* texture_property = properties.GetProperty(ids.src);
|
|
|
|
|
- texture_name = texture_property->Get< String >();
|
|
|
|
|
- rcss_path = texture_property->source;
|
|
|
|
|
-
|
|
|
|
|
- // Declaring the name 'auto' is the same as an empty string. This gives an easy way to skip certain
|
|
|
|
|
- // tiles in a shorthand since we can't always declare an empty string.
|
|
|
|
|
- static const String none_texture_name = "auto";
|
|
|
|
|
- if (texture_name == none_texture_name)
|
|
|
|
|
- texture_name.clear();
|
|
|
|
|
-
|
|
|
|
|
- // @performance / @todo: We want some way to determine sprite or image instead of always doing the lookup as a sprite name.
|
|
|
|
|
- // @performance: We already have the texture loaded in the spritesheet, very unnecessary to return as name and then convert to texture again.
|
|
|
|
|
- if (const Sprite * sprite = interface.GetSprite(texture_name))
|
|
|
|
|
|
|
+ tex_coord = property.value.Get< float >();
|
|
|
|
|
+ if (property.unit == Property::PX)
|
|
|
{
|
|
{
|
|
|
- texture_name = sprite->sprite_sheet->image_source;
|
|
|
|
|
- rcss_path = sprite->sprite_sheet->definition_source;
|
|
|
|
|
-
|
|
|
|
|
- tile.texcoords[0].x = sprite->rectangle.x;
|
|
|
|
|
- tile.texcoords[0].y = sprite->rectangle.y;
|
|
|
|
|
- tile.texcoords[1].x = sprite->rectangle.x + sprite->rectangle.width;
|
|
|
|
|
- tile.texcoords[1].y = sprite->rectangle.y + sprite->rectangle.height;
|
|
|
|
|
-
|
|
|
|
|
- tile.texcoords_absolute[0][0] = true;
|
|
|
|
|
- tile.texcoords_absolute[0][1] = true;
|
|
|
|
|
- tile.texcoords_absolute[1][0] = true;
|
|
|
|
|
- tile.texcoords_absolute[1][1] = true;
|
|
|
|
|
|
|
+ tex_coord_absolute = true;
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- LoadTexCoord(properties, ids.s_begin, tile.texcoords[0].x, tile.texcoords_absolute[0][0]);
|
|
|
|
|
- LoadTexCoord(properties, ids.t_begin, tile.texcoords[0].y, tile.texcoords_absolute[0][1]);
|
|
|
|
|
- LoadTexCoord(properties, ids.s_end, tile.texcoords[1].x, tile.texcoords_absolute[1][0]);
|
|
|
|
|
- LoadTexCoord(properties, ids.t_end, tile.texcoords[1].y, tile.texcoords_absolute[1][1]);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(ids.repeat != PropertyId::Invalid)
|
|
|
|
|
- {
|
|
|
|
|
- const Property* repeat_property = properties.GetProperty(ids.repeat);
|
|
|
|
|
- ROCKET_ASSERT(repeat_property);
|
|
|
|
|
- tile.repeat_mode = (DecoratorTiled::TileRepeatMode) repeat_property->value.Get< int >();
|
|
|
|
|
|
|
+ tex_coord_absolute = false;
|
|
|
|
|
+ if (property.unit == Property::PERCENT)
|
|
|
|
|
+ tex_coord *= 0.01f;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Loads a single texture coordinate value from the properties.
|
|
|
|
|
-void DecoratorTiledInstancer::LoadTexCoord(const PropertyDictionary& properties, PropertyId id, float& tex_coord, bool& tex_coord_absolute)
|
|
|
|
|
|
|
+
|
|
|
|
|
+// Retrieves all the properties for a tile from the property dictionary.
|
|
|
|
|
+bool DecoratorTiledInstancer::GetTileProperties(DecoratorTiled::Tile* tiles, Texture* textures, size_t num_tiles_and_textures, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) const
|
|
|
{
|
|
{
|
|
|
- const Property* property = properties.GetProperty(id);
|
|
|
|
|
|
|
+ ROCKET_ASSERT(num_tiles_and_textures == tile_property_ids.size());
|
|
|
|
|
|
|
|
- // May fail if we forgot to set default values before instancing the tile
|
|
|
|
|
- ROCKET_ASSERT(property);
|
|
|
|
|
|
|
+ String previous_texture_name;
|
|
|
|
|
+ Texture previous_texture;
|
|
|
|
|
|
|
|
- tex_coord = property->value.Get< float >();
|
|
|
|
|
- if (property->unit == Property::PX)
|
|
|
|
|
- {
|
|
|
|
|
- tex_coord_absolute = true;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
|
|
+ for(size_t i = 0; i < num_tiles_and_textures; i++)
|
|
|
{
|
|
{
|
|
|
- tex_coord_absolute = false;
|
|
|
|
|
- if (property->unit == Property::PERCENT)
|
|
|
|
|
- tex_coord *= 0.01f;
|
|
|
|
|
|
|
+ const TilePropertyIds& ids = tile_property_ids[i];
|
|
|
|
|
+
|
|
|
|
|
+ const Property* src_property = properties.GetProperty(ids.src);
|
|
|
|
|
+ const String texture_name = src_property->Get< String >();
|
|
|
|
|
+
|
|
|
|
|
+ if (texture_name == "window-tl")
|
|
|
|
|
+ {
|
|
|
|
|
+ int i = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Skip the tile if it has no source name.
|
|
|
|
|
+ // Declaring the name 'auto' is the same as an empty string. This gives an easy way to skip certain
|
|
|
|
|
+ // tiles in a shorthand since we can't always declare an empty string.
|
|
|
|
|
+ static const String auto_str = "auto";
|
|
|
|
|
+ if (texture_name.empty() || texture_name == auto_str)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ // A tile is always either a sprite or a texture with position and dimensions specified.
|
|
|
|
|
+ bool src_is_sprite = false;
|
|
|
|
|
+
|
|
|
|
|
+ // We are required to set default values before instancing the tile, thus, all properties should always be dereferencable.
|
|
|
|
|
+ // If the debugger captures a zero-dereference, check that all properties for every tile is set and default values are set just before instancing.
|
|
|
|
|
+ const Property& width_property = *properties.GetProperty(ids.width);
|
|
|
|
|
+ float width = width_property.Get<float>();
|
|
|
|
|
+ if (width == 0.0f)
|
|
|
|
|
+ {
|
|
|
|
|
+ // A sprite always has its own dimensions, thus, we let zero width/height define that it is a sprite.
|
|
|
|
|
+ src_is_sprite = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ DecoratorTiled::Tile& tile = tiles[i];
|
|
|
|
|
+ Texture& texture = textures[i];
|
|
|
|
|
+
|
|
|
|
|
+ if (src_is_sprite)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (const Sprite * sprite = interface.GetSprite(texture_name))
|
|
|
|
|
+ {
|
|
|
|
|
+ tile.position.x = sprite->rectangle.x;
|
|
|
|
|
+ tile.position.y = sprite->rectangle.y;
|
|
|
|
|
+ tile.size.x = sprite->rectangle.width;
|
|
|
|
|
+ tile.size.y = sprite->rectangle.height;
|
|
|
|
|
+
|
|
|
|
|
+ tile.position_absolute[0] = tile.position_absolute[1] = true;
|
|
|
|
|
+ tile.size_absolute[0] = tile.size_absolute[1] = true;
|
|
|
|
|
+
|
|
|
|
|
+ texture = sprite->sprite_sheet->texture;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ Log::Message(Log::LT_WARNING, "The sprite '%s' given in decorator could not be found, declared at %s:%d", texture_name.c_str(), src_property->source.c_str(), src_property->source_line_number);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ LoadTexCoord(*properties.GetProperty(ids.x), tile.position.x, tile.position_absolute[0]);
|
|
|
|
|
+ LoadTexCoord(*properties.GetProperty(ids.y), tile.position.y, tile.position_absolute[1]);
|
|
|
|
|
+ LoadTexCoord(width_property, tile.size.x, tile.size_absolute[0]);
|
|
|
|
|
+ LoadTexCoord(*properties.GetProperty(ids.height), tile.size.y, tile.size_absolute[1]);
|
|
|
|
|
+
|
|
|
|
|
+ // Since the common use case is to specify the same texture for all tiles, we
|
|
|
|
|
+ // check the previous texture first before fetching from the global database.
|
|
|
|
|
+ if (texture_name == previous_texture_name)
|
|
|
|
|
+ {
|
|
|
|
|
+ texture = previous_texture;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (texture.Load(texture_name, src_property->source))
|
|
|
|
|
+ {
|
|
|
|
|
+ previous_texture_name = texture_name;
|
|
|
|
|
+ previous_texture = texture;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ Log::Message(Log::LT_WARNING, "Could not load texture '%s' given in decorator at %s:%d", texture_name.c_str(), src_property->source.c_str(), src_property->source_line_number);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(ids.repeat != PropertyId::Invalid)
|
|
|
|
|
+ {
|
|
|
|
|
+ const Property& repeat_property = *properties.GetProperty(ids.repeat);
|
|
|
|
|
+ tile.repeat_mode = (DecoratorTiled::TileRepeatMode)repeat_property.value.Get< int >();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|