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: [#16132, #16389] The Corkscrew, Twister and Vertical Drop Roller Coasters can now draw inline twists.
|
||||||
- Feature: [#16144] [Plugin] Add ImageManager to API.
|
- Feature: [#16144] [Plugin] Add ImageManager to API.
|
||||||
- Feature: [#16731] [Plugin] New API for fetching and manipulating a staff member's patrol area.
|
- 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: [#3517] Cheats are now saved with the park.
|
||||||
- Improved: [#10150] Ride stations are now properly checked if they’re sheltered.
|
- 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.
|
- Improved: [#10664, #16072] Visibility status can be modified directly in the Tile Inspector's list.
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "../PlatformEnvironment.h"
|
#include "../PlatformEnvironment.h"
|
||||||
#include "../config/Config.h"
|
#include "../config/Config.h"
|
||||||
#include "../core/FileStream.h"
|
#include "../core/FileStream.h"
|
||||||
|
#include "../core/MemoryStream.h"
|
||||||
#include "../core/Path.hpp"
|
#include "../core/Path.hpp"
|
||||||
#include "../platform/Platform.h"
|
#include "../platform/Platform.h"
|
||||||
#include "../sprites.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)
|
static std::optional<PaletteMap> FASTCALL gfx_draw_sprite_get_palette(ImageId imageId)
|
||||||
{
|
{
|
||||||
if (!imageId.HasSecondary())
|
if (!imageId.HasSecondary())
|
||||||
|
|
|
@ -28,7 +28,8 @@ struct ScreenRect;
|
||||||
namespace OpenRCT2
|
namespace OpenRCT2
|
||||||
{
|
{
|
||||||
struct IPlatformEnvironment;
|
struct IPlatformEnvironment;
|
||||||
}
|
struct IStream;
|
||||||
|
} // namespace OpenRCT2
|
||||||
|
|
||||||
namespace OpenRCT2::Drawing
|
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(ImageId imageId);
|
||||||
const rct_g1_element* gfx_get_g1_element(ImageIndex image_id);
|
const rct_g1_element* gfx_get_g1_element(ImageIndex image_id);
|
||||||
void gfx_set_g1_element(ImageIndex imageId, const rct_g1_element* g1);
|
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();
|
bool is_csg_loaded();
|
||||||
void FASTCALL gfx_sprite_to_buffer(rct_drawpixelinfo& dpi, const DrawSpriteArgs& args);
|
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);
|
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);
|
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
|
else
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -219,6 +235,61 @@ std::vector<std::unique_ptr<ImageTable::RequiredImage>> ImageTable::ParseImages(
|
||||||
return result;
|
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(
|
std::vector<std::unique_ptr<ImageTable::RequiredImage>> ImageTable::LoadObjectImages(
|
||||||
IReadObjectContext* context, const std::string& name, const std::vector<int32_t>& range)
|
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);
|
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::vector<int32_t> ParseRange(std::string s);
|
||||||
[[nodiscard]] static std::string FindLegacyObject(const std::string& name);
|
[[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:
|
public:
|
||||||
ImageTable() = default;
|
ImageTable() = default;
|
||||||
|
|
Loading…
Reference in New Issue