Skip to content

Commit c405a85

Browse files
author
Roberto De Ioris
committed
added thumbnail api
1 parent 3facb6e commit c405a85

7 files changed

Lines changed: 238 additions & 3 deletions

File tree

‎Source/UnrealEnginePython/Private/UEPyModule.cpp‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,6 @@ static PyMethodDef ue_PyUObject_methods[] = {
434434

435435
{ "get_super_class", (PyCFunction)py_ue_get_super_class, METH_VARARGS, "" },
436436

437-
438437
{ "get_name", (PyCFunction)py_ue_get_name, METH_VARARGS, "" },
439438
{ "get_display_name", (PyCFunction)py_ue_get_display_name, METH_VARARGS, "" },
440439
{ "get_path_name", (PyCFunction)py_ue_get_path_name, METH_VARARGS, "" },
@@ -454,6 +453,9 @@ static PyMethodDef ue_PyUObject_methods[] = {
454453
{ "pre_edit_change", (PyCFunction)py_ue_pre_edit_change, METH_VARARGS, "" },
455454
{ "modify", (PyCFunction)py_ue_modify, METH_VARARGS, "" },
456455

456+
{ "get_thumbnail", (PyCFunction)py_ue_get_thumbnail, METH_VARARGS, "" },
457+
{ "render_thumbnail", (PyCFunction)py_ue_render_thumbnail, METH_VARARGS, "" },
458+
457459
#if WITH_EDITOR
458460
{ "save_config", (PyCFunction)py_ue_save_config, METH_VARARGS, "" },
459461
{ "get_actor_label", (PyCFunction)py_ue_get_actor_label, METH_VARARGS, "" },
@@ -1803,6 +1805,8 @@ void unreal_engine_init_py_module()
18031805

18041806
ue_python_init_fmorph_target_delta(new_unreal_engine_module);
18051807

1808+
ue_python_init_fobject_thumbnail(new_unreal_engine_module);
1809+
18061810
ue_python_init_fpython_output_device(new_unreal_engine_module);
18071811

18081812
ue_python_init_ftimerhandle(new_unreal_engine_module);

‎Source/UnrealEnginePython/Private/UObject/UEPyObject.cpp‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,64 @@ PyObject *py_ue_get_property(ue_PyUObject *self, PyObject * args)
740740
return ue_py_convert_property(u_property, (uint8 *)self->ue_object);
741741
}
742742

743+
PyObject *py_ue_get_thumbnail(ue_PyUObject *self, PyObject * args)
744+
{
745+
746+
PyObject *py_generate = nullptr;
747+
if (!PyArg_ParseTuple(args, "|O:get_thumbnail", &py_generate))
748+
{
749+
return nullptr;
750+
}
751+
752+
ue_py_check(self);
753+
754+
TArray<FName> names;
755+
names.Add(FName(*self->ue_object->GetFullName()));
756+
757+
FThumbnailMap thumb_map;
758+
759+
FObjectThumbnail *object_thumbnail = nullptr;
760+
761+
if (!ThumbnailTools::ConditionallyLoadThumbnailsForObjects(names, thumb_map))
762+
{
763+
if (py_generate && PyObject_IsTrue(py_generate))
764+
{
765+
object_thumbnail = ThumbnailTools::GenerateThumbnailForObjectToSaveToDisk(self->ue_object);
766+
}
767+
}
768+
else
769+
{
770+
object_thumbnail = &thumb_map[names[0]];
771+
}
772+
773+
if (!object_thumbnail)
774+
{
775+
return PyErr_Format(PyExc_Exception, "unable to retrieve thumbnail");
776+
}
777+
778+
return py_ue_new_fobject_thumbnail(*object_thumbnail);
779+
}
780+
781+
PyObject *py_ue_render_thumbnail(ue_PyUObject *self, PyObject * args)
782+
{
783+
784+
int width = ThumbnailTools::DefaultThumbnailSize;
785+
int height = ThumbnailTools::DefaultThumbnailSize;
786+
PyObject *no_flush = nullptr;
787+
if (!PyArg_ParseTuple(args, "|iiO:render_thumbnail", &width, height, &no_flush))
788+
{
789+
return nullptr;
790+
}
791+
792+
ue_py_check(self);
793+
FObjectThumbnail object_thumbnail;
794+
ThumbnailTools::RenderThumbnail(self->ue_object, width, height,
795+
(no_flush && PyObject_IsTrue(no_flush)) ? ThumbnailTools::EThumbnailTextureFlushMode::NeverFlush : ThumbnailTools::EThumbnailTextureFlushMode::AlwaysFlush,
796+
nullptr, &object_thumbnail);
797+
798+
return py_ue_new_fobject_thumbnail(object_thumbnail);
799+
}
800+
743801
PyObject *py_ue_get_uproperty(ue_PyUObject *self, PyObject * args)
744802
{
745803

‎Source/UnrealEnginePython/Private/UObject/UEPyObject.h‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ PyObject *py_ue_functions(ue_PyUObject *, PyObject *);
5656

5757
PyObject *py_ue_broadcast(ue_PyUObject *, PyObject *);
5858

59-
PyObject *py_ue_post_edit_change( ue_PyUObject *, PyObject * );
59+
PyObject *py_ue_post_edit_change(ue_PyUObject *, PyObject *);
6060
PyObject *py_ue_pre_edit_change(ue_PyUObject *, PyObject *);
6161
PyObject *py_ue_modify(ue_PyUObject *, PyObject *);
6262

@@ -70,4 +70,7 @@ PyObject *py_ue_asset_reimport(ue_PyUObject *, PyObject *);
7070
PyObject *py_ue_get_metadata(ue_PyUObject *, PyObject *);
7171
PyObject *py_ue_set_metadata(ue_PyUObject *, PyObject *);
7272
PyObject *py_ue_has_metadata(ue_PyUObject *, PyObject *);
73-
#endif
73+
#endif
74+
75+
PyObject *py_ue_get_thumbnail(ue_PyUObject *, PyObject *);
76+
PyObject *py_ue_render_thumbnail(ue_PyUObject *, PyObject *);

‎Source/UnrealEnginePython/Private/UnrealEnginePythonPrivatePCH.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "Wrappers/UEPyFPythonOutputDevice.h"
4646
#include "Wrappers/UEPyFSoftSkinVertex.h"
4747
#include "Wrappers/UEPyFMorphTargetDelta.h"
48+
#include "Wrappers/UEPyFObjectThumbnail.h"
4849

4950
#include "UEPyCallable.h"
5051
#include "UEPyUClassesImporter.h"
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#include "UnrealEnginePythonPrivatePCH.h"
2+
3+
4+
static PyObject *py_ue_fobject_thumbnail_get_image_width(ue_PyFObjectThumbnail *self, PyObject * args)
5+
{
6+
return PyLong_FromLong(self->object_thumbnail.GetImageWidth());
7+
}
8+
9+
static PyObject *py_ue_fobject_thumbnail_get_image_height(ue_PyFObjectThumbnail *self, PyObject * args)
10+
{
11+
return PyLong_FromLong(self->object_thumbnail.GetImageHeight());
12+
}
13+
14+
static PyObject *py_ue_fobject_thumbnail_get_compressed_data_size(ue_PyFObjectThumbnail *self, PyObject * args)
15+
{
16+
return PyLong_FromLong(self->object_thumbnail.GetCompressedDataSize());
17+
}
18+
19+
static PyObject *py_ue_fobject_thumbnail_get_uncompressed_image_data(ue_PyFObjectThumbnail *self, PyObject * args)
20+
{
21+
const TArray<uint8> &data = self->object_thumbnail.GetUncompressedImageData();
22+
return PyByteArray_FromStringAndSize((char *)data.GetData(), data.Num());
23+
}
24+
25+
static PyObject *py_ue_fobject_thumbnail_compress_image_data(ue_PyFObjectThumbnail *self, PyObject * args)
26+
{
27+
self->object_thumbnail.CompressImageData();
28+
Py_RETURN_NONE;
29+
}
30+
31+
32+
static PyMethodDef ue_PyFObjectThumbnail_methods[] = {
33+
{ "get_image_width", (PyCFunction)py_ue_fobject_thumbnail_get_image_width, METH_VARARGS, "" },
34+
{ "get_image_height", (PyCFunction)py_ue_fobject_thumbnail_get_image_height, METH_VARARGS, "" },
35+
{ "get_compressed_data_size", (PyCFunction)py_ue_fobject_thumbnail_get_compressed_data_size, METH_VARARGS, "" },
36+
{ "get_uncompressed_image_data", (PyCFunction)py_ue_fobject_thumbnail_get_uncompressed_image_data, METH_VARARGS, "" },
37+
{ "compress_image_data", (PyCFunction)py_ue_fobject_thumbnail_get_uncompressed_image_data, METH_VARARGS, "" },
38+
{ nullptr } /* Sentinel */
39+
};
40+
41+
static PyObject *ue_PyFObjectThumbnail_str(ue_PyFObjectThumbnail *self)
42+
{
43+
return PyUnicode_FromFormat("<unreal_engine.FObjectThumbnail {'width': %d, 'height': %d, 'compressed_data_size': %d}>",
44+
self->object_thumbnail.GetImageWidth(),
45+
self->object_thumbnail.GetImageHeight(),
46+
self->object_thumbnail.GetCompressedDataSize());
47+
}
48+
49+
static PyTypeObject ue_PyFObjectThumbnailType = {
50+
PyVarObject_HEAD_INIT(NULL, 0)
51+
"unreal_engine.FObjectThumbnail", /* tp_name */
52+
sizeof(ue_PyFObjectThumbnail), /* tp_basicsize */
53+
0, /* tp_itemsize */
54+
0, /* tp_dealloc */
55+
0, /* tp_print */
56+
0, /* tp_getattr */
57+
0, /* tp_setattr */
58+
0, /* tp_reserved */
59+
0, /* tp_repr */
60+
0, /* tp_as_number */
61+
0, /* tp_as_sequence */
62+
0, /* tp_as_mapping */
63+
0, /* tp_hash */
64+
0, /* tp_call */
65+
(reprfunc)ue_PyFObjectThumbnail_str, /* tp_str */
66+
0, /* tp_getattro */
67+
0, /* tp_setattro */
68+
0, /* tp_as_buffer */
69+
#if PY_MAJOR_VERSION < 3
70+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
71+
#else
72+
Py_TPFLAGS_DEFAULT, /* tp_flags */
73+
#endif
74+
"Unreal Engine FObjectThumbnail", /* tp_doc */
75+
0, /* tp_traverse */
76+
0, /* tp_clear */
77+
0, /* tp_richcompare */
78+
0, /* tp_weaklistoffset */
79+
0, /* tp_iter */
80+
0, /* tp_iternext */
81+
ue_PyFObjectThumbnail_methods, /* tp_methods */
82+
0,
83+
};
84+
85+
static int py_ue_fobject_thumbnail_init(ue_PyFObjectThumbnail *self, PyObject * args)
86+
{
87+
new(&self->object_thumbnail) FObjectThumbnail();
88+
return 0;
89+
}
90+
91+
void ue_python_init_fobject_thumbnail(PyObject *ue_module)
92+
{
93+
ue_PyFObjectThumbnailType.tp_new = PyType_GenericNew;
94+
ue_PyFObjectThumbnailType.tp_init = (initproc)py_ue_fobject_thumbnail_init;
95+
96+
if (PyType_Ready(&ue_PyFObjectThumbnailType) < 0)
97+
return;
98+
99+
Py_INCREF(&ue_PyFObjectThumbnailType);
100+
PyModule_AddObject(ue_module, "FObjectThumbnail", (PyObject *)&ue_PyFObjectThumbnailType);
101+
}
102+
103+
ue_PyFObjectThumbnail *py_ue_is_fobject_thumbnail(PyObject *obj)
104+
{
105+
if (!PyObject_IsInstance(obj, (PyObject *)&ue_PyFObjectThumbnailType))
106+
return nullptr;
107+
return (ue_PyFObjectThumbnail *)obj;
108+
}
109+
110+
PyObject *py_ue_new_fobject_thumbnail(FObjectThumbnail object_thumnail)
111+
{
112+
ue_PyFObjectThumbnail *ret = (ue_PyFObjectThumbnail *)PyObject_New(ue_PyFObjectThumbnail, &ue_PyFObjectThumbnailType);
113+
new(&ret->object_thumbnail) FObjectThumbnail(object_thumnail);
114+
return (PyObject *)ret;
115+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#pragma once
2+
#include "UnrealEnginePython.h"
3+
4+
#include "Runtime/Core/Public/Misc/ObjectThumbnail.h"
5+
6+
struct ue_PyFObjectThumbnail {
7+
PyObject_HEAD
8+
/* Type-specific fields go here. */
9+
FObjectThumbnail object_thumbnail;
10+
};
11+
12+
void ue_python_init_fobject_thumbnail(PyObject *);
13+
14+
PyObject *py_ue_new_fobject_thumbnail(FObjectThumbnail);
15+
16+
ue_PyFObjectThumbnail *py_ue_is_fobject_thumbnail(PyObject *);

‎examples/thumbnail_viewer.py‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import unreal_engine as ue
2+
from unreal_engine.classes import StaticMesh
3+
from unreal_engine import SWindow, SScrollBox, SVerticalBox, SHorizontalBox, SImage, STextBlock, FARFilter
4+
from unreal_engine.enums import EPixelFormat
5+
6+
_filter = FARFilter()
7+
_filter.class_names = ['StaticMesh']
8+
9+
thumbnails = []
10+
11+
for static_mesh in ue.get_assets_by_filter(_filter):
12+
thumbnails.append((static_mesh.get_full_name(), static_mesh.get_thumbnail()))
13+
14+
15+
window = SWindow(client_size=(1024, 512), title='StaticMeshes thumbnails')
16+
scroll_box = SScrollBox()
17+
18+
vertical = SVerticalBox()
19+
20+
for name, thumbnail in thumbnails:
21+
texture = ue.create_transient_texture(thumbnail.get_image_width(), thumbnail.get_image_height())
22+
texture.texture_set_data(thumbnail.get_uncompressed_image_data())
23+
vertical.add_slot(
24+
SHorizontalBox()
25+
(
26+
SImage().set_texture(texture),
27+
max_width=64
28+
)
29+
(
30+
STextBlock(text=name),
31+
padding=4,
32+
auto_width=True,
33+
),
34+
max_height=64
35+
)
36+
37+
scroll_box.add_slot(vertical)
38+
window.set_content(scroll_box)

0 commit comments

Comments
 (0)