Skip to content

Commit 64b6c7c

Browse files
author
Roberto De Ioris
committed
improved texture api
1 parent dabe808 commit 64b6c7c

File tree

5 files changed

+119
-20
lines changed

5 files changed

+119
-20
lines changed

Source/UnrealEnginePython/Private/UEPyAudio.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,18 @@ PyObject *py_ue_queue_audio(ue_PyUObject *self, PyObject * args) {
1212
}
1313

1414
USoundWaveProcedural *sound_wave_procedural = ue_py_check_type<USoundWaveProcedural>(self);
15-
if (!sound_wave_procedural)
15+
if (!sound_wave_procedural) {
16+
// Clean up
17+
PyBuffer_Release(&sound_buffer);
1618
return PyErr_Format(PyExc_Exception, "UObject is not a USoundWaveProcedural.");
17-
19+
}
1820
// Convert the buffer
1921
uint8 *buffer = (uint8 *)sound_buffer.buf;
20-
if (buffer == nullptr)
22+
if (buffer == nullptr) {
23+
// Clean up
24+
PyBuffer_Release(&sound_buffer);
2125
return PyErr_Format(PyExc_Exception, "Invalid sound buffer.");
26+
}
2227

2328
// Add the audio to the Sound Wave's audio buffer
2429
sound_wave_procedural->QueueAudio(buffer, sound_buffer.len);

Source/UnrealEnginePython/Private/UEPyModule.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ static PyMethodDef unreal_engine_methods[] = {
145145

146146
{ "get_content_dir", py_unreal_engine_get_content_dir, METH_VARARGS, "" },
147147
{ "convert_relative_path_to_full", py_unreal_engine_convert_relative_path_to_full, METH_VARARGS, "" },
148+
149+
{ "compress_image_array", py_unreal_engine_compress_image_array, METH_VARARGS, "" },
150+
{ "create_checkerboard_texture", py_unreal_engine_create_checkerboard_texture, METH_VARARGS, "" },
151+
148152
#if WITH_EDITOR
149153

150154
// slate
@@ -571,6 +575,8 @@ static PyMethodDef ue_PyUObject_methods[] = {
571575
// Texture
572576
{ "texture_get_data", (PyCFunction)py_ue_texture_get_data, METH_VARARGS, "" },
573577
{ "texture_set_data", (PyCFunction)py_ue_texture_set_data, METH_VARARGS, "" },
578+
{ "texture_get_width", (PyCFunction)py_ue_texture_get_width, METH_VARARGS, "" },
579+
{ "texture_get_height", (PyCFunction)py_ue_texture_get_height, METH_VARARGS, "" },
574580

575581
// Sequencer
576582
{ "sequencer_master_tracks", (PyCFunction)py_ue_sequencer_master_tracks, METH_VARARGS, "" },

Source/UnrealEnginePython/Private/UEPyObject.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,13 @@ PyObject *py_ue_save_package(ue_PyUObject * self, PyObject * args) {
871871
if (!name) {
872872
return PyErr_Format(PyExc_Exception, "the object has no associated package, please specify a name");
873873
}
874+
if (!has_package) {
875+
// unmark transient object
876+
if (u_object->HasAnyFlags(RF_Transient)) {
877+
u_object->ClearFlags(RF_Transient);
878+
u_object->SetFlags(RF_Public | RF_Standalone);
879+
}
880+
}
874881
package = (UPackage *)StaticFindObject(nullptr, ANY_PACKAGE, UTF8_TO_TCHAR(name), true);
875882
// create a new package if it does not exist
876883
if (!package) {
@@ -889,6 +896,9 @@ PyObject *py_ue_save_package(ue_PyUObject * self, PyObject * args) {
889896
}
890897
else {
891898
// move to object into the new package
899+
if (!self->ue_object->Rename(*(self->ue_object->GetName()), package, REN_Test)) {
900+
return PyErr_Format(PyExc_Exception, "unable to set object outer to package");
901+
}
892902
if (!self->ue_object->Rename(*(self->ue_object->GetName()), package)) {
893903
return PyErr_Format(PyExc_Exception, "unable to set object outer to package");
894904
}
Lines changed: 89 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
#include "UnrealEnginePythonPrivatePCH.h"
22

3+
#include "Runtime/Engine/Public/ImageUtils.h"
4+
#include "Runtime/Engine/Classes/Engine/Texture.h"
5+
6+
PyObject *py_ue_texture_get_width(ue_PyUObject *self, PyObject * args) {
7+
8+
ue_py_check(self);
9+
10+
UTexture2D *texture = ue_py_check_type<UTexture2D>(self);
11+
if (!texture)
12+
return PyErr_Format(PyExc_Exception, "object is not a Texture");
13+
14+
return PyLong_FromLong(texture->GetSizeX());
15+
}
16+
17+
PyObject *py_ue_texture_get_height(ue_PyUObject *self, PyObject * args) {
18+
19+
ue_py_check(self);
20+
21+
UTexture2D *texture = ue_py_check_type<UTexture2D>(self);
22+
if (!texture)
23+
return PyErr_Format(PyExc_Exception, "object is not a Texture");
24+
25+
return PyLong_FromLong(texture->GetSizeY());
26+
}
327

428
PyObject *py_ue_texture_get_data(ue_PyUObject *self, PyObject * args) {
529

@@ -11,11 +35,10 @@ PyObject *py_ue_texture_get_data(ue_PyUObject *self, PyObject * args) {
1135
return NULL;
1236
}
1337

14-
if (!self->ue_object->IsA<UTexture2D>())
38+
UTexture2D *tex = ue_py_check_type<UTexture2D>(self);
39+
if (!tex)
1540
return PyErr_Format(PyExc_Exception, "object is not a Texture2D");
1641

17-
UTexture2D *tex = (UTexture2D *)self->ue_object;
18-
1942
if (mipmap >= tex->GetNumMips())
2043
return PyErr_Format(PyExc_Exception, "invalid mipmap id");
2144

@@ -29,44 +52,94 @@ PyObject *py_ue_texture_set_data(ue_PyUObject *self, PyObject * args) {
2952

3053
ue_py_check(self);
3154

32-
PyObject *byte_array;
55+
Py_buffer py_buf;
3356
int mipmap = 0;
3457

35-
if (!PyArg_ParseTuple(args, "O|i:texture_get_data", &byte_array, &mipmap)) {
58+
if (!PyArg_ParseTuple(args, "z*|i:texture_set_data", &py_buf, &mipmap)) {
3659
return NULL;
3760
}
3861

39-
if (!self->ue_object->IsA<UTexture2D>())
62+
UTexture2D *tex = ue_py_check_type<UTexture2D>(self);
63+
if (!tex)
4064
return PyErr_Format(PyExc_Exception, "object is not a Texture2D");
4165

42-
UTexture2D *tex = (UTexture2D *)self->ue_object;
4366

44-
if (!PyByteArray_Check(byte_array))
45-
return PyErr_Format(PyExc_Exception, "argument is not a bytearray");
67+
if (!py_buf.buf)
68+
return PyErr_Format(PyExc_Exception, "invalid data");
4669

4770
if (mipmap >= tex->GetNumMips())
4871
return PyErr_Format(PyExc_Exception, "invalid mipmap id");
4972

5073
char *blob = (char*)tex->PlatformData->Mips[mipmap].BulkData.Lock(LOCK_READ_WRITE);
5174
int32 len = tex->PlatformData->Mips[mipmap].BulkData.GetBulkDataSize();
52-
Py_ssize_t byte_array_size = PyByteArray_Size(byte_array);
75+
int32 wanted_len = py_buf.len;
5376
// avoid making mess
54-
if (byte_array_size > len)
55-
byte_array_size = len;
56-
char *byte_array_blob = PyByteArray_AsString(byte_array);
57-
FMemory::Memcpy(blob, byte_array_blob, byte_array_size);
77+
if (wanted_len > len) {
78+
UE_LOG(LogPython, Warning, TEXT("truncating buffer to %d bytes"), len);
79+
wanted_len = len;
80+
}
81+
FMemory::Memcpy(blob, py_buf.buf, wanted_len);
5882
tex->PlatformData->Mips[mipmap].BulkData.Unlock();
5983

6084
tex->MarkPackageDirty();
6185
#if WITH_EDITOR
6286
tex->PostEditChange();
6387
#endif
6488

65-
// ensure compatibility between 4.12 and 4.14
66-
//tex->UpdateResourceW();
89+
tex->UpdateResource();
6790

6891
Py_INCREF(Py_None);
6992
return Py_None;
7093
}
7194

95+
PyObject *py_unreal_engine_compress_image_array(PyObject * self, PyObject * args) {
96+
int width;
97+
int height;
98+
Py_buffer py_buf;
99+
if (!PyArg_ParseTuple(args, "iiz*:compress_image_array", &width, &height, &py_buf)) {
100+
return NULL;
101+
}
102+
103+
if (py_buf.buf == nullptr || py_buf.len <= 0) {
104+
PyBuffer_Release(&py_buf);
105+
return PyErr_Format(PyExc_Exception, "invalid image data");
106+
}
107+
108+
TArray<FColor> colors;
109+
uint8 *buf = (uint8 *)py_buf.buf;
110+
for (int32 i = 0; i < py_buf.len; i += 4) {
111+
colors.Add(FColor(buf[i], buf[1 + 1], buf[i + 2], buf[i + 3]));
112+
}
113+
114+
TArray<uint8> output;
115+
116+
FImageUtils::CompressImageArray(width, height, colors, output);
117+
118+
return PyBytes_FromStringAndSize((char *)output.GetData(), output.Num());
119+
}
120+
121+
PyObject *py_unreal_engine_create_checkerboard_texture(PyObject * self, PyObject * args) {
122+
PyObject *py_color_one;
123+
PyObject *py_color_two;
124+
int checker_size;
125+
if (!PyArg_ParseTuple(args, "OOi:create_checkboard_texture", &py_color_one, &py_color_two, &checker_size)) {
126+
return NULL;
127+
}
128+
129+
ue_PyFColor *color_one = py_ue_is_fcolor(py_color_one);
130+
if (!color_one)
131+
return PyErr_Format(PyExc_Exception, "argument is not a FColor");
132+
133+
ue_PyFColor *color_two = py_ue_is_fcolor(py_color_two);
134+
if (!color_two)
135+
return PyErr_Format(PyExc_Exception, "argument is not a FColor");
136+
137+
UTexture2D *texture = FImageUtils::CreateCheckerboardTexture(color_one->color, color_two->color, checker_size);
138+
139+
ue_PyUObject *ret = ue_get_python_wrapper(texture);
140+
if (!ret)
141+
return PyErr_Format(PyExc_Exception, "uobject is in invalid state");
142+
Py_INCREF(ret);
143+
return (PyObject *)ret;
144+
}
72145

Source/UnrealEnginePython/Private/UEPyTexture.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@
55
#include "UnrealEnginePython.h"
66

77
PyObject *py_ue_texture_get_data(ue_PyUObject *, PyObject *);
8-
PyObject *py_ue_texture_set_data(ue_PyUObject *, PyObject *);
8+
PyObject *py_ue_texture_set_data(ue_PyUObject *, PyObject *);
9+
PyObject *py_ue_texture_get_width(ue_PyUObject *, PyObject *);
10+
PyObject *py_ue_texture_get_height(ue_PyUObject *, PyObject *);
11+
12+
PyObject *py_unreal_engine_compress_image_array(PyObject *, PyObject *);
13+
PyObject *py_unreal_engine_create_checkerboard_texture(PyObject *, PyObject *);

0 commit comments

Comments
 (0)