[godot] Port of 6a08383

Adds specular map support to spine-godot on the Spine Runtimes 4.2 branch.
This was tested by porting the changes and compiling the spine-godot editor (version 4.3-stable) from source.
This commit is contained in:
Luke Ingram 2025-05-28 23:23:56 -04:00
parent 5b93cafb99
commit b0890856cd
6 changed files with 78 additions and 18 deletions

View File

@ -61,10 +61,12 @@ class GodotSpineTextureLoader : public spine::TextureLoader {
Array *textures; Array *textures;
Array *normal_maps; Array *normal_maps;
Array *specular_maps;
String normal_map_prefix; String normal_map_prefix;
String specular_map_prefix;
public: public:
GodotSpineTextureLoader(Array *_textures, Array *_normal_maps, const String &normal_map_prefix, bool is_importing) : textures(_textures), normal_maps(_normal_maps), normal_map_prefix(normal_map_prefix) { GodotSpineTextureLoader(Array *_textures, Array *_normal_maps, Array *_specular_maps, const String &normal_map_prefix, const String &specular_map_prefix, bool is_importing) : textures(_textures), normal_maps(_normal_maps), specular_maps(_specular_maps), normal_map_prefix(normal_map_prefix), specular_map_prefix(specular_map_prefix) {
} }
static bool fix_path(String &path) { static bool fix_path(String &path) {
@ -156,6 +158,7 @@ public:
auto renderer_object = memnew(SpineRendererObject); auto renderer_object = memnew(SpineRendererObject);
renderer_object->texture = Ref<Texture>(nullptr); renderer_object->texture = Ref<Texture>(nullptr);
renderer_object->normal_map = Ref<Texture>(nullptr); renderer_object->normal_map = Ref<Texture>(nullptr);
renderer_object->specular_map = Ref<Texture>(nullptr);
page.texture = (void *) renderer_object; page.texture = (void *) renderer_object;
return; return;
} }
@ -164,9 +167,12 @@ public:
auto renderer_object = memnew(SpineRendererObject); auto renderer_object = memnew(SpineRendererObject);
renderer_object->texture = texture; renderer_object->texture = texture;
renderer_object->normal_map = Ref<Texture>(nullptr); renderer_object->normal_map = Ref<Texture>(nullptr);
renderer_object->specular_map = Ref<Texture>(nullptr);
String normal_map_path = vformat("%s/%s_%s", fixed_path.get_base_dir(), normal_map_prefix, fixed_path.get_file()); String normal_map_path = vformat("%s/%s_%s", fixed_path.get_base_dir(), normal_map_prefix, fixed_path.get_file());
String specular_map_path = vformat("%s/%s_%s", fixed_path.get_base_dir(), specular_map_prefix, fixed_path.get_file());
is_resource = fix_path(normal_map_path); is_resource = fix_path(normal_map_path);
is_resource = fix_path(specular_map_path);
#if SPINE_GODOT_EXTENSION #if SPINE_GODOT_EXTENSION
if (ResourceLoader::get_singleton()->exists(normal_map_path)) { if (ResourceLoader::get_singleton()->exists(normal_map_path)) {
import_image_resource(normal_map_path); import_image_resource(normal_map_path);
@ -174,6 +180,13 @@ public:
normal_maps->append(normal_map); normal_maps->append(normal_map);
renderer_object->normal_map = normal_map; renderer_object->normal_map = normal_map;
} }
if (ResourceLoader::get_singleton()->exists(specular_map_path)) {
import_image_resource(specular_map_path);
Ref<Texture> specular_map = get_texture_from_image(specular_map_path, is_resource);
specular_maps->append(specular_map);
renderer_object->specular_map = specular_map;
}
#else #else
if (ResourceLoader::exists(normal_map_path)) { if (ResourceLoader::exists(normal_map_path)) {
import_image_resource(normal_map_path); import_image_resource(normal_map_path);
@ -181,12 +194,20 @@ public:
normal_maps->append(normal_map); normal_maps->append(normal_map);
renderer_object->normal_map = normal_map; renderer_object->normal_map = normal_map;
} }
if (ResourceLoader::exists(specular_map_path)) {
import_image_resource(specular_map_path);
Ref<Texture> specular_map = get_texture_from_image(specular_map_path, is_resource);
specular_maps->append(specular_map);
renderer_object->specular_map = specular_map;
}
#endif #endif
#if VERSION_MAJOR > 3 #if VERSION_MAJOR > 3
renderer_object->canvas_texture.instantiate(); renderer_object->canvas_texture.instantiate();
renderer_object->canvas_texture->set_diffuse_texture(renderer_object->texture); renderer_object->canvas_texture->set_diffuse_texture(renderer_object->texture);
renderer_object->canvas_texture->set_normal_texture(renderer_object->normal_map); renderer_object->canvas_texture->set_normal_texture(renderer_object->normal_map);
renderer_object->canvas_texture->set_specular_texture(renderer_object->specular_map);
#endif #endif
page.texture = (void *) renderer_object; page.texture = (void *) renderer_object;
@ -198,6 +219,7 @@ public:
auto renderer_object = (SpineRendererObject *) data; auto renderer_object = (SpineRendererObject *) data;
if (renderer_object->texture.is_valid()) renderer_object->texture.unref(); if (renderer_object->texture.is_valid()) renderer_object->texture.unref();
if (renderer_object->normal_map.is_valid()) renderer_object->normal_map.unref(); if (renderer_object->normal_map.is_valid()) renderer_object->normal_map.unref();
if (renderer_object->specular_map.is_valid()) renderer_object->specular_map.unref();
#if VERSION_MAJOR > 3 #if VERSION_MAJOR > 3
if (renderer_object->canvas_texture.is_valid()) renderer_object->canvas_texture.unref(); if (renderer_object->canvas_texture.is_valid()) renderer_object->canvas_texture.unref();
#endif #endif
@ -210,13 +232,15 @@ void SpineAtlasResource::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_source_path"), &SpineAtlasResource::get_source_path); ClassDB::bind_method(D_METHOD("get_source_path"), &SpineAtlasResource::get_source_path);
ClassDB::bind_method(D_METHOD("get_textures"), &SpineAtlasResource::get_textures); ClassDB::bind_method(D_METHOD("get_textures"), &SpineAtlasResource::get_textures);
ClassDB::bind_method(D_METHOD("get_normal_maps"), &SpineAtlasResource::get_normal_maps); ClassDB::bind_method(D_METHOD("get_normal_maps"), &SpineAtlasResource::get_normal_maps);
ClassDB::bind_method(D_METHOD("get_specular_maps"), &SpineAtlasResource::get_specular_maps);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_path"), "", "get_source_path"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_path"), "", "get_source_path");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures"), "", "get_textures"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures"), "", "get_textures");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "normal_maps"), "", "get_normal_maps"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "normal_maps"), "", "get_normal_maps");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "specular_maps"), "", "get_specular_maps");
} }
SpineAtlasResource::SpineAtlasResource() : atlas(nullptr), texture_loader(nullptr), normal_map_prefix("n") { SpineAtlasResource::SpineAtlasResource() : atlas(nullptr), texture_loader(nullptr), normal_map_prefix("n"), specular_map_prefix("s") {
} }
SpineAtlasResource::~SpineAtlasResource() { SpineAtlasResource::~SpineAtlasResource() {
@ -231,6 +255,7 @@ void SpineAtlasResource::clear() {
texture_loader = nullptr; texture_loader = nullptr;
textures.clear(); textures.clear();
normal_maps.clear(); normal_maps.clear();
specular_maps.clear();
} }
Array SpineAtlasResource::get_textures() { Array SpineAtlasResource::get_textures() {
@ -241,6 +266,10 @@ Array SpineAtlasResource::get_normal_maps() {
return normal_maps; return normal_maps;
} }
Array SpineAtlasResource::get_specular_maps() {
return specular_maps;
}
String SpineAtlasResource::get_source_path() { String SpineAtlasResource::get_source_path() {
return source_path; return source_path;
} }
@ -261,7 +290,7 @@ Error SpineAtlasResource::load_from_atlas_file_internal(const String &path, bool
#endif #endif
clear(); clear();
texture_loader = new GodotSpineTextureLoader(&textures, &normal_maps, normal_map_prefix, is_importing); texture_loader = new GodotSpineTextureLoader(&textures, &normal_maps, &specular_maps, normal_map_prefix, specular_map_prefix, is_importing);
auto atlas_utf8 = atlas_data.utf8(); auto atlas_utf8 = atlas_data.utf8();
atlas = new spine::Atlas(atlas_utf8, atlas_utf8.length(), source_path.get_base_dir().utf8(), texture_loader); atlas = new spine::Atlas(atlas_utf8, atlas_utf8.length(), source_path.get_base_dir().utf8(), texture_loader);
if (atlas) return OK; if (atlas) return OK;
@ -301,9 +330,10 @@ Error SpineAtlasResource::load_from_file(const String &path) {
source_path = content["source_path"]; source_path = content["source_path"];
atlas_data = content["atlas_data"]; atlas_data = content["atlas_data"];
normal_map_prefix = content["normal_texture_prefix"]; normal_map_prefix = content["normal_texture_prefix"];
specular_map_prefix = content["specular_texture_prefix"];
clear(); clear();
texture_loader = new GodotSpineTextureLoader(&textures, &normal_maps, normal_map_prefix, false); texture_loader = new GodotSpineTextureLoader(&textures, &normal_maps, &specular_maps, normal_map_prefix, specular_map_prefix, false);
auto utf8 = atlas_data.utf8(); auto utf8 = atlas_data.utf8();
atlas = new spine::Atlas(utf8.ptr(), utf8.size(), source_path.get_base_dir().utf8(), texture_loader); atlas = new spine::Atlas(utf8.ptr(), utf8.size(), source_path.get_base_dir().utf8(), texture_loader);
if (atlas) return OK; if (atlas) return OK;
@ -334,6 +364,7 @@ Error SpineAtlasResource::save_to_file(const String &path) {
content["source_path"] = source_path; content["source_path"] = source_path;
content["atlas_data"] = atlas_data; content["atlas_data"] = atlas_data;
content["normal_texture_prefix"] = normal_map_prefix; content["normal_texture_prefix"] = normal_map_prefix;
content["specular_texture_prefix"] = specular_map_prefix;
#if VERSION_MAJOR > 3 #if VERSION_MAJOR > 3
JSON *json = memnew(JSON); JSON *json = memnew(JSON);
file->store_string(json->stringify(content)); file->store_string(json->stringify(content));
@ -361,8 +392,10 @@ Error SpineAtlasResource::copy_from(const Ref<Resource> &p_resource) {
this->source_path = spineAtlas->source_path; this->source_path = spineAtlas->source_path;
this->atlas_data = spineAtlas->atlas_data; this->atlas_data = spineAtlas->atlas_data;
this->normal_map_prefix = spineAtlas->normal_map_prefix; this->normal_map_prefix = spineAtlas->normal_map_prefix;
this->specular_map_prefix = spineAtlas->specular_map_prefix;
this->textures = spineAtlas->textures; this->textures = spineAtlas->textures;
this->normal_maps = spineAtlas->normal_maps; this->normal_maps = spineAtlas->normal_maps;
this->specular_maps = spineAtlas->specular_maps;
emit_signal(SNAME("skeleton_file_changed")); emit_signal(SNAME("skeleton_file_changed"));
return OK; return OK;

View File

@ -60,9 +60,11 @@ protected:
String source_path; String source_path;
String atlas_data; String atlas_data;
String normal_map_prefix; String normal_map_prefix;
String specular_map_prefix;
Array textures; Array textures;
Array normal_maps; Array normal_maps;
Array specular_maps;
public: public:
SpineAtlasResource(); SpineAtlasResource();
@ -72,6 +74,8 @@ public:
void set_normal_texture_prefix(const String &prefix) { normal_map_prefix = prefix; } void set_normal_texture_prefix(const String &prefix) { normal_map_prefix = prefix; }
void set_specular_texture_prefix(const String &prefix) { specular_map_prefix = prefix; }
Error load_from_atlas_file(const String &path);// .atlas Error load_from_atlas_file(const String &path);// .atlas
Error load_from_atlas_file_internal(const String &path, bool is_importing);// .atlas Error load_from_atlas_file_internal(const String &path, bool is_importing);// .atlas
@ -92,6 +96,8 @@ public:
Array get_normal_maps(); Array get_normal_maps();
Array get_specular_maps();
void clear_native_data() const { void clear_native_data() const {
this->atlas = nullptr; this->atlas = nullptr;
this->texture_loader = nullptr; this->texture_loader = nullptr;

View File

@ -54,6 +54,7 @@ Error SpineAtlasResourceImportPlugin::import(const String &source_file, const St
#endif #endif
Ref<SpineAtlasResource> atlas(memnew(SpineAtlasResource)); Ref<SpineAtlasResource> atlas(memnew(SpineAtlasResource));
atlas->set_normal_texture_prefix(options["normal_map_prefix"]); atlas->set_normal_texture_prefix(options["normal_map_prefix"]);
atlas->set_specular_texture_prefix(options["specular_map_prefix"]);
atlas->load_from_atlas_file_internal(source_file, true); atlas->load_from_atlas_file_internal(source_file, true);
#if VERSION_MAJOR > 3 #if VERSION_MAJOR > 3
@ -74,12 +75,19 @@ Error SpineAtlasResourceImportPlugin::import(const String &source_file, const St
#ifdef SPINE_GODOT_EXTENSION #ifdef SPINE_GODOT_EXTENSION
TypedArray<Dictionary> SpineAtlasResourceImportPlugin::_get_import_options(const String &p_path, int32_t p_preset_index) const { TypedArray<Dictionary> SpineAtlasResourceImportPlugin::_get_import_options(const String &p_path, int32_t p_preset_index) const {
TypedArray<Dictionary> options; TypedArray<Dictionary> options;
Dictionary dictionary; Dictionary normal_map_dictionary;
dictionary["name"] = "normal_map_prefix"; normal_map_dictionary["name"] = "normal_map_prefix";
dictionary["type"] = Variant::STRING; normal_map_dictionary["type"] = Variant::STRING;
dictionary["hint_string"] = "String"; normal_map_dictionary["hint_string"] = "String";
dictionary["default_value"] = String("n"); normal_map_dictionary["default_value"] = String("n");
options.push_back(dictionary); options.push_back(normal_map_dictionary);
Dictionary specular_map_dictionary;
specular_map_dictionary["name"] = "specular_map_prefix";
specular_map_dictionary["type"] = Variant::STRING;
specular_map_dictionary["hint_string"] = "String";
specular_map_dictionary["default_value"] = String("s");
options.push_back(specular_map_dictionary);
return options; return options;
} }
#else #else
@ -89,12 +97,19 @@ void SpineAtlasResourceImportPlugin::get_import_options(const String &path, List
void SpineAtlasResourceImportPlugin::get_import_options(List<ImportOption> *options, int preset) const { void SpineAtlasResourceImportPlugin::get_import_options(List<ImportOption> *options, int preset) const {
#endif #endif
if (preset == 0) { if (preset == 0) {
ImportOption op; ImportOption normal_map_op;
op.option.name = "normal_map_prefix"; normal_map_op.option.name = "normal_map_prefix";
op.option.type = Variant::STRING; normal_map_op.option.type = Variant::STRING;
op.option.hint_string = "String"; normal_map_op.option.hint_string = "String";
op.default_value = String("n"); normal_map_op.default_value = String("n");
options->push_back(op); options->push_back(normal_map_op);
ImportOption specular_map_op;
specular_map_op.option.name = "specular_map_prefix";
specular_map_op.option.type = Variant::STRING;
specular_map_op.option.hint_string = "String";
specular_map_op.default_value = String("s");
options->push_back(specular_map_op);
} }
} }
#endif #endif

View File

@ -46,6 +46,7 @@
struct SpineRendererObject { struct SpineRendererObject {
Ref<Texture> texture; Ref<Texture> texture;
Ref<Texture> normal_map; Ref<Texture> normal_map;
Ref<Texture> specular_map;
#if VERSION_MAJOR > 3 #if VERSION_MAJOR > 3
Ref<CanvasTexture> canvas_texture; Ref<CanvasTexture> canvas_texture;
#endif #endif

View File

@ -179,6 +179,7 @@ static void add_triangles(SpineMesh2D *mesh_instance,
#else #else
auto texture = renderer_object->texture; auto texture = renderer_object->texture;
auto normal_map = renderer_object->normal_map; auto normal_map = renderer_object->normal_map;
auto specular_map = renderer_object->specular_map;
VisualServer::get_singleton()->canvas_item_add_triangle_array(mesh_instance->get_canvas_item(), VisualServer::get_singleton()->canvas_item_add_triangle_array(mesh_instance->get_canvas_item(),
indices, indices,
vertices, vertices,
@ -188,7 +189,8 @@ static void add_triangles(SpineMesh2D *mesh_instance,
Vector<float>(), Vector<float>(),
texture.is_null() ? RID() : texture->get_rid(), texture.is_null() ? RID() : texture->get_rid(),
-1, -1,
normal_map.is_null() ? RID() : normal_map->get_rid()); normal_map.is_null() ? RID() : normal_map->get_rid(),
specular_map.is_null() ? RID() : specular_map->get_rid());
#endif #endif
#endif #endif
} }
@ -403,7 +405,8 @@ void SpineMesh2D::update_mesh(const Vector<Point2> &vertices,
Transform2D(), Transform2D(),
Color(1, 1, 1, 1), Color(1, 1, 1, 1),
renderer_object->texture.is_null() ? RID() : renderer_object->texture->get_rid(), renderer_object->texture.is_null() ? RID() : renderer_object->texture->get_rid(),
renderer_object->normal_map.is_null() ? RID() : renderer_object->normal_map->get_rid()); renderer_object->normal_map.is_null() ? RID() : renderer_object->normal_map->get_rid(),
renderer_object->specular_map.is_null() ? RID() : renderer_object->specular_map->get_rid());
#endif #endif
} }
#endif #endif

View File

@ -19,6 +19,8 @@
<members> <members>
<member name="normal_maps" type="Array" setter="" getter="get_normal_maps" default="[ ]"> <member name="normal_maps" type="Array" setter="" getter="get_normal_maps" default="[ ]">
</member> </member>
<member name="specular_maps" type="Array" setter="" getter="get_specular_maps" default="[ ]">
</member>
<member name="source_path" type="String" setter="" getter="get_source_path" default="&quot;&quot;"> <member name="source_path" type="String" setter="" getter="get_source_path" default="&quot;&quot;">
</member> </member>
<member name="textures" type="Array" setter="" getter="get_textures" default="[ ]"> <member name="textures" type="Array" setter="" getter="get_textures" default="[ ]">