mirror of https://github.com/OpenRCT2/OpenRCT2.git
Parkobj loads rct_gx (#16806)
* allow loading of lgx rct_gx packed images within parkobjs * add changelog entry * allow loading of lgx without range
This commit is contained in:
parent
c84da5512c
commit
a3700c832a
|
@ -16,6 +16,7 @@
|
|||
- Feature: [#16132, #16389] The Corkscrew, Twister and Vertical Drop Roller Coasters can now draw inline twists.
|
||||
- Feature: [#16144] [Plugin] Add ImageManager to API.
|
||||
- Feature: [#16731] [Plugin] New API for fetching and manipulating a staff member's patrol area.
|
||||
- Feature: [#16806] Parkobj can load sprites from RCT image archives.
|
||||
- Improved: [#3517] Cheats are now saved with the park.
|
||||
- Improved: [#10150] Ride stations are now properly checked if they’re sheltered.
|
||||
- Improved: [#10664, #16072] Visibility status can be modified directly in the Tile Inspector's list.
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "../PlatformEnvironment.h"
|
||||
#include "../config/Config.h"
|
||||
#include "../core/FileStream.h"
|
||||
#include "../core/MemoryStream.h"
|
||||
#include "../core/Path.hpp"
|
||||
#include "../platform/Platform.h"
|
||||
#include "../sprites.h"
|
||||
|
@ -361,6 +362,31 @@ bool gfx_load_csg()
|
|||
}
|
||||
}
|
||||
|
||||
std::optional<rct_gx> GfxLoadGx(const std::vector<uint8_t>& buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
OpenRCT2::MemoryStream istream(buffer.data(), buffer.size());
|
||||
rct_gx gx;
|
||||
|
||||
gx.header = istream.ReadValue<rct_g1_header>();
|
||||
|
||||
// Read element headers
|
||||
gx.elements.resize(gx.header.num_entries);
|
||||
read_and_convert_gxdat(&istream, gx.header.num_entries, false, gx.elements.data());
|
||||
|
||||
// Read element data
|
||||
gx.data = istream.ReadArray<uint8_t>(gx.header.total_size);
|
||||
|
||||
return std::make_optional(std::move(gx));
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
log_verbose("Unable to load rct_gx graphics");
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static std::optional<PaletteMap> FASTCALL gfx_draw_sprite_get_palette(ImageId imageId)
|
||||
{
|
||||
if (!imageId.HasSecondary())
|
||||
|
|
|
@ -28,7 +28,8 @@ struct ScreenRect;
|
|||
namespace OpenRCT2
|
||||
{
|
||||
struct IPlatformEnvironment;
|
||||
}
|
||||
struct IStream;
|
||||
} // namespace OpenRCT2
|
||||
|
||||
namespace OpenRCT2::Drawing
|
||||
{
|
||||
|
@ -525,6 +526,7 @@ void gfx_unload_csg();
|
|||
const rct_g1_element* gfx_get_g1_element(ImageId imageId);
|
||||
const rct_g1_element* gfx_get_g1_element(ImageIndex image_id);
|
||||
void gfx_set_g1_element(ImageIndex imageId, const rct_g1_element* g1);
|
||||
std::optional<rct_gx> GfxLoadGx(const std::vector<uint8_t>& buffer);
|
||||
bool is_csg_loaded();
|
||||
void FASTCALL gfx_sprite_to_buffer(rct_drawpixelinfo& dpi, const DrawSpriteArgs& args);
|
||||
void FASTCALL gfx_bmp_sprite_to_buffer(rct_drawpixelinfo& dpi, const DrawSpriteArgs& args);
|
||||
|
|
|
@ -137,6 +137,22 @@ std::vector<std::unique_ptr<ImageTable::RequiredImage>> ImageTable::ParseImages(
|
|||
result = LoadObjectImages(context, name, range);
|
||||
}
|
||||
}
|
||||
else if (String::StartsWith(s, "$LGX:"))
|
||||
{
|
||||
auto name = s.substr(5);
|
||||
auto rangeStart = name.find('[');
|
||||
if (rangeStart != std::string::npos)
|
||||
{
|
||||
auto rangeString = name.substr(rangeStart);
|
||||
auto range = ParseRange(name.substr(rangeStart));
|
||||
name = name.substr(0, rangeStart);
|
||||
result = LoadImageArchiveImages(context, name, range);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = LoadImageArchiveImages(context, name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
|
@ -219,6 +235,61 @@ std::vector<std::unique_ptr<ImageTable::RequiredImage>> ImageTable::ParseImages(
|
|||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<ImageTable::RequiredImage>> ImageTable::LoadImageArchiveImages(
|
||||
IReadObjectContext* context, const std::string& path, const std::vector<int32_t>& range)
|
||||
{
|
||||
std::vector<std::unique_ptr<RequiredImage>> result;
|
||||
auto gxRaw = context->GetData(path);
|
||||
std::optional<rct_gx> gxData = GfxLoadGx(gxRaw);
|
||||
if (gxData.has_value())
|
||||
{
|
||||
// Fix entry data offsets
|
||||
for (uint32_t i = 0; i < gxData->header.num_entries; i++)
|
||||
{
|
||||
gxData->elements[i].offset += reinterpret_cast<uintptr_t>(gxData->data.get());
|
||||
}
|
||||
|
||||
if (range.size() > 0)
|
||||
{
|
||||
size_t placeHoldersAdded = 0;
|
||||
for (auto i : range)
|
||||
{
|
||||
if (i >= 0 && (i < static_cast<int32_t>(gxData->header.num_entries)))
|
||||
{
|
||||
result.push_back(std::make_unique<RequiredImage>(gxData->elements[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back(std::make_unique<RequiredImage>());
|
||||
placeHoldersAdded++;
|
||||
}
|
||||
}
|
||||
|
||||
// Log place holder information
|
||||
if (placeHoldersAdded > 0)
|
||||
{
|
||||
std::string msg = "Adding " + std::to_string(placeHoldersAdded) + " placeholders";
|
||||
context->LogWarning(ObjectError::InvalidProperty, msg.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < static_cast<int32_t>(gxData->header.num_entries); i++)
|
||||
result.push_back(std::make_unique<RequiredImage>(gxData->elements[i]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto msg = String::StdFormat("Unable to load rct_gx '%s'", path.c_str());
|
||||
context->LogWarning(ObjectError::BadImageTable, msg.c_str());
|
||||
for (size_t i = 0; i < range.size(); i++)
|
||||
{
|
||||
result.push_back(std::make_unique<RequiredImage>());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<ImageTable::RequiredImage>> ImageTable::LoadObjectImages(
|
||||
IReadObjectContext* context, const std::string& name, const std::vector<int32_t>& range)
|
||||
{
|
||||
|
|
|
@ -45,6 +45,8 @@ private:
|
|||
IReadObjectContext* context, const std::string& name, const std::vector<int32_t>& range);
|
||||
[[nodiscard]] static std::vector<int32_t> ParseRange(std::string s);
|
||||
[[nodiscard]] static std::string FindLegacyObject(const std::string& name);
|
||||
[[nodiscard]] static std::vector<std::unique_ptr<ImageTable::RequiredImage>> LoadImageArchiveImages(
|
||||
IReadObjectContext* context, const std::string& path, const std::vector<int32_t>& range = {});
|
||||
|
||||
public:
|
||||
ImageTable() = default;
|
||||
|
|
Loading…
Reference in New Issue