mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-22 15:23:01 +01:00
Create command to export images from .DAT file
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
- Feature: [#11231] Change shortcut window list order to be more intuitive, and split it into logical sections.
|
- Feature: [#11231] Change shortcut window list order to be more intuitive, and split it into logical sections.
|
||||||
- Feature: [#11306] Path additions are now kept when replacing the path.
|
- Feature: [#11306] Path additions are now kept when replacing the path.
|
||||||
- Feature: [#11320] Support for custom JavaScript plugins.
|
- Feature: [#11320] Support for custom JavaScript plugins.
|
||||||
|
- Feature: [#11788] Command to extract images from a .DAT file.
|
||||||
- Change: [#11209] Warn when user is running OpenRCT2 through Wine.
|
- Change: [#11209] Warn when user is running OpenRCT2 through Wine.
|
||||||
- Change: [#11358] Switch copy and paste button positions in tile inspector.
|
- Change: [#11358] Switch copy and paste button positions in tile inspector.
|
||||||
- Change: [#11449] Remove complete circuit requirement from Air Powered Vertical Coaster (for RCT1 parity).
|
- Change: [#11449] Remove complete circuit requirement from Air Powered Vertical Coaster (for RCT1 parity).
|
||||||
|
|||||||
@@ -11,12 +11,18 @@
|
|||||||
|
|
||||||
#include "CmdlineSprite.h"
|
#include "CmdlineSprite.h"
|
||||||
|
|
||||||
|
#include "Context.h"
|
||||||
#include "OpenRCT2.h"
|
#include "OpenRCT2.h"
|
||||||
#include "core/Imaging.h"
|
#include "core/Imaging.h"
|
||||||
#include "drawing/Drawing.h"
|
#include "drawing/Drawing.h"
|
||||||
#include "drawing/ImageImporter.h"
|
#include "drawing/ImageImporter.h"
|
||||||
|
#include "object/ObjectLimits.h"
|
||||||
|
#include "object/ObjectManager.h"
|
||||||
|
#include "object/ObjectRepository.h"
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "util/Util.h"
|
#include "util/Util.h"
|
||||||
|
#include "world/Entrance.h"
|
||||||
|
#include "world/Scenery.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -196,14 +202,12 @@ static void sprite_file_close()
|
|||||||
SafeFree(spriteFileData);
|
SafeFree(spriteFileData);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sprite_file_export(int32_t spriteIndex, const char* outPath)
|
static bool sprite_file_export(rct_g1_element* spriteHeader, const char* outPath)
|
||||||
{
|
{
|
||||||
rct_g1_element* spriteHeader;
|
|
||||||
rct_drawpixelinfo dpi;
|
rct_drawpixelinfo dpi;
|
||||||
uint8_t* pixels;
|
uint8_t* pixels;
|
||||||
int32_t pixelBufferSize;
|
int32_t pixelBufferSize;
|
||||||
|
|
||||||
spriteHeader = &spriteFileEntries[spriteIndex];
|
|
||||||
pixelBufferSize = spriteHeader->width * spriteHeader->height;
|
pixelBufferSize = spriteHeader->width * spriteHeader->height;
|
||||||
std::unique_ptr<uint8_t[]> pixelBuffer(new uint8_t[pixelBufferSize]);
|
std::unique_ptr<uint8_t[]> pixelBuffer(new uint8_t[pixelBufferSize]);
|
||||||
pixels = pixelBuffer.get();
|
pixels = pixelBuffer.get();
|
||||||
@@ -371,7 +375,8 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sprite_file_export(spriteIndex, outputPath))
|
rct_g1_element* spriteHeader = &spriteFileEntries[spriteIndex];
|
||||||
|
if (!sprite_file_export(spriteHeader, outputPath))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Could not export\n");
|
fprintf(stderr, "Could not export\n");
|
||||||
sprite_file_close();
|
sprite_file_close();
|
||||||
@@ -431,7 +436,8 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||||||
printf("\r%d / %d, %d%%", spriteIndex, maxIndex, spriteIndex / maxIndex);
|
printf("\r%d / %d, %d%%", spriteIndex, maxIndex, spriteIndex / maxIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sprite_file_export(spriteIndex, outputPath))
|
rct_g1_element* spriteHeader = &spriteFileEntries[spriteIndex];
|
||||||
|
if (!sprite_file_export(spriteHeader, outputPath))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Could not export\n");
|
fprintf(stderr, "Could not export\n");
|
||||||
sprite_file_close();
|
sprite_file_close();
|
||||||
@@ -452,6 +458,155 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||||||
sprite_file_close();
|
sprite_file_close();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
else if (_strcmpi(argv[0], "exportalldat") == 0)
|
||||||
|
{
|
||||||
|
if (argc < 3)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "usage: sprite exportall <spritefile> <output directory>\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char datName[DAT_NAME_LENGTH + 1] = { 0 };
|
||||||
|
std::fill_n(datName, DAT_NAME_LENGTH, ' ');
|
||||||
|
int32_t i = 0;
|
||||||
|
for (const char* ch = argv[1]; *ch != '\0' && i < DAT_NAME_LENGTH; ch++)
|
||||||
|
{
|
||||||
|
datName[i++] = *ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto context = OpenRCT2::CreateContext();
|
||||||
|
context->Initialise();
|
||||||
|
|
||||||
|
const ObjectRepositoryItem* ori = object_repository_find_object_by_name(datName);
|
||||||
|
if (ori == nullptr)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Could not find the object.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rct_object_entry* entry = &ori->ObjectEntry;
|
||||||
|
void* loadedObject = object_manager_load_object(entry);
|
||||||
|
if (loadedObject == nullptr)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unable to load object.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
auto entryIndex = object_manager_get_loaded_object_entry_index(loadedObject);
|
||||||
|
uint8_t objectType = entry->GetType();
|
||||||
|
|
||||||
|
auto& objManager = context->GetObjectManager();
|
||||||
|
auto metaObject = objManager.GetLoadedObject(objectType, entryIndex);
|
||||||
|
|
||||||
|
char outputPath[MAX_PATH];
|
||||||
|
safe_strcpy(outputPath, argv[2], MAX_PATH);
|
||||||
|
path_end_with_separator(outputPath, MAX_PATH);
|
||||||
|
|
||||||
|
if (!platform_ensure_directory_exists(outputPath))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unable to create directory.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t maxIndex = static_cast<int32_t>(metaObject->GetNumImages());
|
||||||
|
int32_t imagesOffset = 0;
|
||||||
|
switch (objectType)
|
||||||
|
{
|
||||||
|
case OBJECT_TYPE_RIDE:
|
||||||
|
{
|
||||||
|
auto rideEntry = get_ride_entry(entryIndex);
|
||||||
|
imagesOffset = rideEntry->images_offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OBJECT_TYPE_SMALL_SCENERY:
|
||||||
|
case OBJECT_TYPE_LARGE_SCENERY:
|
||||||
|
case OBJECT_TYPE_WALLS:
|
||||||
|
case OBJECT_TYPE_BANNERS:
|
||||||
|
case OBJECT_TYPE_PATH_BITS:
|
||||||
|
{
|
||||||
|
auto obj = objManager.GetLoadedObject(objectType, entryIndex);
|
||||||
|
if (obj != nullptr)
|
||||||
|
{
|
||||||
|
auto sceneryEntry = static_cast<rct_scenery_entry*>(obj->GetLegacyData());
|
||||||
|
imagesOffset = sceneryEntry->image;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OBJECT_TYPE_PATHS:
|
||||||
|
{
|
||||||
|
auto pathEntry = get_path_surface_entry(entryIndex);
|
||||||
|
imagesOffset = pathEntry->image;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OBJECT_TYPE_SCENERY_GROUP:
|
||||||
|
{
|
||||||
|
auto sceneryGroupEntry = get_scenery_group_entry(entryIndex);
|
||||||
|
imagesOffset = sceneryGroupEntry->image;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OBJECT_TYPE_PARK_ENTRANCE:
|
||||||
|
{
|
||||||
|
auto obj = objManager.GetLoadedObject(objectType, entryIndex);
|
||||||
|
if (obj != nullptr)
|
||||||
|
{
|
||||||
|
auto entranceEnty = static_cast<rct_entrance_type*>(obj->GetLegacyData());
|
||||||
|
imagesOffset = entranceEnty->image_id;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Cannot extract images from this type of object.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t numDigits = std::max(1, static_cast<int32_t>(std::floor(std::log(maxIndex))));
|
||||||
|
size_t pathLen = strlen(outputPath);
|
||||||
|
|
||||||
|
if (pathLen >= static_cast<size_t>(MAX_PATH - numDigits - 5))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Path too long.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t x = 0; x < numDigits; x++)
|
||||||
|
{
|
||||||
|
outputPath[pathLen + x] = '0';
|
||||||
|
}
|
||||||
|
safe_strcpy(outputPath + pathLen + numDigits, ".png", MAX_PATH - pathLen - numDigits);
|
||||||
|
|
||||||
|
for (int32_t spriteIndex = 0; spriteIndex < maxIndex; spriteIndex++)
|
||||||
|
{
|
||||||
|
const rct_g1_element* g1 = gfx_get_g1_element(spriteIndex + imagesOffset);
|
||||||
|
if (g1 == nullptr)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Could not load image metadata\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sprite_file_export(const_cast<rct_g1_element*>(g1), outputPath))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Could not export\n");
|
||||||
|
sprite_file_close();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "{ \"path\": \"%s\", \"x\": %d, \"y\": %d },\n", outputPath, g1->x_offset, g1->y_offset);
|
||||||
|
|
||||||
|
// Add to the index at the end of the file name
|
||||||
|
char* counter = outputPath + pathLen + numDigits - 1;
|
||||||
|
(*counter)++;
|
||||||
|
while (*counter > '9')
|
||||||
|
{
|
||||||
|
*counter = '0';
|
||||||
|
counter--;
|
||||||
|
(*counter)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
metaObject->Unload();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
else if (_strcmpi(argv[0], "create") == 0)
|
else if (_strcmpi(argv[0], "create") == 0)
|
||||||
{
|
{
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ const CommandLineCommand CommandLine::SpriteCommands[]
|
|||||||
DefineCommand("details", "<spritefile> [idx]", SpriteOptions, HandleSprite),
|
DefineCommand("details", "<spritefile> [idx]", SpriteOptions, HandleSprite),
|
||||||
DefineCommand("export", "<spritefile> <idx> <output>", SpriteOptions, HandleSprite),
|
DefineCommand("export", "<spritefile> <idx> <output>", SpriteOptions, HandleSprite),
|
||||||
DefineCommand("exportall", "<spritefile> <output directory>", SpriteOptions, HandleSprite),
|
DefineCommand("exportall", "<spritefile> <output directory>", SpriteOptions, HandleSprite),
|
||||||
|
DefineCommand("exportalldat", "<datname> <output directory>", SpriteOptions, HandleSprite),
|
||||||
|
|
||||||
CommandTableEnd
|
CommandTableEnd
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|||||||
@@ -252,6 +252,11 @@ public:
|
|||||||
rct_object_entry GetScgWallsHeader();
|
rct_object_entry GetScgWallsHeader();
|
||||||
rct_object_entry GetScgPathXHeader();
|
rct_object_entry GetScgPathXHeader();
|
||||||
rct_object_entry CreateHeader(const char name[9], uint32_t flags, uint32_t checksum);
|
rct_object_entry CreateHeader(const char name[9], uint32_t flags, uint32_t checksum);
|
||||||
|
|
||||||
|
uint32_t GetNumImages() const
|
||||||
|
{
|
||||||
|
return GetImageTable().GetCount();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
#ifdef __WARN_SUGGEST_FINAL_TYPES__
|
#ifdef __WARN_SUGGEST_FINAL_TYPES__
|
||||||
# pragma GCC diagnostic pop
|
# pragma GCC diagnostic pop
|
||||||
|
|||||||
Reference in New Issue
Block a user