mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-20 09:16:01 +08:00
[ue4] Start anew
This commit is contained in:
parent
6fe1e8fa68
commit
27926682d6
5
spine-ue4/Config/DefaultEditor.ini
Normal file
5
spine-ue4/Config/DefaultEditor.ini
Normal file
@ -0,0 +1,5 @@
|
||||
[EditoronlyBP]
|
||||
bAllowClassAndBlueprintPinMatching=true
|
||||
bReplaceBlueprintWithClass=true
|
||||
bDontLoadBlueprintOutsideEditor=true
|
||||
bBlueprintIsNotBlueprintType=true
|
||||
9
spine-ue4/Config/DefaultEngine.ini
Normal file
9
spine-ue4/Config/DefaultEngine.ini
Normal file
@ -0,0 +1,9 @@
|
||||
[URL]
|
||||
|
||||
[/Script/HardwareTargeting.HardwareTargetingSettings]
|
||||
TargetedHardwareClass=Desktop
|
||||
AppliedTargetedHardwareClass=Desktop
|
||||
DefaultGraphicsPerformance=Maximum
|
||||
AppliedDefaultGraphicsPerformance=Maximum
|
||||
|
||||
|
||||
2
spine-ue4/Config/DefaultGame.ini
Normal file
2
spine-ue4/Config/DefaultGame.ini
Normal file
@ -0,0 +1,2 @@
|
||||
[/Script/EngineSettings.GeneralProjectSettings]
|
||||
ProjectID=A32BDAC45F432EB90DF445842A670D58
|
||||
BIN
spine-ue4/Content/Maps/example.umap
Normal file
BIN
spine-ue4/Content/Maps/example.umap
Normal file
Binary file not shown.
BIN
spine-ue4/Content/SpineBoy/Textures/NewPaperSprite.uasset
Normal file
BIN
spine-ue4/Content/SpineBoy/Textures/NewPaperSprite.uasset
Normal file
Binary file not shown.
BIN
spine-ue4/Content/SpineBoy/Textures/spineboy.uasset
Normal file
BIN
spine-ue4/Content/SpineBoy/Textures/spineboy.uasset
Normal file
Binary file not shown.
216
spine-ue4/Content/SpineBoy/spineboy.atlas
Normal file
216
spine-ue4/Content/SpineBoy/spineboy.atlas
Normal file
@ -0,0 +1,216 @@
|
||||
|
||||
spineboy.png
|
||||
size: 1024,1024
|
||||
format: RGBA8888
|
||||
filter: Linear,Linear
|
||||
repeat: none
|
||||
eye_indifferent
|
||||
rotate: true
|
||||
xy: 648, 629
|
||||
size: 93, 89
|
||||
orig: 93, 89
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
eye_surprised
|
||||
rotate: true
|
||||
xy: 233, 179
|
||||
size: 93, 89
|
||||
orig: 93, 89
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front_bracer
|
||||
rotate: false
|
||||
xy: 245, 2
|
||||
size: 58, 80
|
||||
orig: 58, 80
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front_fist_closed
|
||||
rotate: false
|
||||
xy: 168, 45
|
||||
size: 75, 82
|
||||
orig: 75, 82
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front_fist_open
|
||||
rotate: false
|
||||
xy: 844, 646
|
||||
size: 86, 87
|
||||
orig: 86, 87
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front_foot
|
||||
rotate: true
|
||||
xy: 310, 326
|
||||
size: 126, 69
|
||||
orig: 126, 69
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front_foot_bend1
|
||||
rotate: true
|
||||
xy: 951, 894
|
||||
size: 128, 70
|
||||
orig: 128, 70
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front_foot_bend2
|
||||
rotate: false
|
||||
xy: 2, 33
|
||||
size: 108, 93
|
||||
orig: 108, 93
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front_shin
|
||||
rotate: true
|
||||
xy: 739, 735
|
||||
size: 82, 184
|
||||
orig: 82, 184
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front_thigh
|
||||
rotate: false
|
||||
xy: 381, 340
|
||||
size: 48, 112
|
||||
orig: 48, 112
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front_upper_arm
|
||||
rotate: false
|
||||
xy: 112, 29
|
||||
size: 54, 97
|
||||
orig: 54, 97
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
goggles
|
||||
rotate: false
|
||||
xy: 156, 454
|
||||
size: 261, 166
|
||||
orig: 261, 166
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
gun
|
||||
rotate: false
|
||||
xy: 739, 819
|
||||
size: 210, 203
|
||||
orig: 210, 203
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
head
|
||||
rotate: false
|
||||
xy: 466, 724
|
||||
size: 271, 298
|
||||
orig: 271, 298
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
hoverboard_board
|
||||
rotate: true
|
||||
xy: 2, 128
|
||||
size: 492, 152
|
||||
orig: 492, 152
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
hoverboard_thruster
|
||||
rotate: false
|
||||
xy: 602, 558
|
||||
size: 60, 64
|
||||
orig: 60, 64
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
hoverglow_small
|
||||
rotate: true
|
||||
xy: 156, 178
|
||||
size: 274, 75
|
||||
orig: 274, 75
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
mouth_grind
|
||||
rotate: true
|
||||
xy: 951, 799
|
||||
size: 93, 59
|
||||
orig: 93, 59
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
mouth_oooo
|
||||
rotate: true
|
||||
xy: 245, 84
|
||||
size: 93, 59
|
||||
orig: 93, 59
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
mouth_smile
|
||||
rotate: false
|
||||
xy: 925, 738
|
||||
size: 93, 59
|
||||
orig: 93, 59
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle
|
||||
rotate: false
|
||||
xy: 2, 622
|
||||
size: 462, 400
|
||||
orig: 462, 400
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
neck
|
||||
rotate: false
|
||||
xy: 168, 2
|
||||
size: 36, 41
|
||||
orig: 36, 41
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear_bracer
|
||||
rotate: false
|
||||
xy: 932, 664
|
||||
size: 56, 72
|
||||
orig: 56, 72
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear_foot
|
||||
rotate: false
|
||||
xy: 487, 562
|
||||
size: 113, 60
|
||||
orig: 113, 60
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear_foot_bend1
|
||||
rotate: true
|
||||
xy: 419, 503
|
||||
size: 117, 66
|
||||
orig: 117, 66
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear_foot_bend2
|
||||
rotate: false
|
||||
xy: 739, 650
|
||||
size: 103, 83
|
||||
orig: 103, 83
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear_shin
|
||||
rotate: false
|
||||
xy: 233, 274
|
||||
size: 75, 178
|
||||
orig: 75, 178
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear_thigh
|
||||
rotate: true
|
||||
xy: 487, 495
|
||||
size: 65, 104
|
||||
orig: 65, 104
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear_upper_arm
|
||||
rotate: true
|
||||
xy: 156, 129
|
||||
size: 47, 87
|
||||
orig: 47, 87
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
torso
|
||||
rotate: true
|
||||
xy: 466, 624
|
||||
size: 98, 180
|
||||
orig: 98, 180
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
2419
spine-ue4/Content/SpineBoy/spineboy.json
Normal file
2419
spine-ue4/Content/SpineBoy/spineboy.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
spine-ue4/Content/SpineBoy/spineboy.png
Normal file
BIN
spine-ue4/Content/SpineBoy/spineboy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 678 KiB |
BIN
spine-ue4/Content/SpineBoy/spineboy.skel
Normal file
BIN
spine-ue4/Content/SpineBoy/spineboy.skel
Normal file
Binary file not shown.
BIN
spine-ue4/Content/SpineBoy/spineboy.uasset
Normal file
BIN
spine-ue4/Content/SpineBoy/spineboy.uasset
Normal file
Binary file not shown.
27
spine-ue4/LICENSE
Normal file
27
spine-ue4/LICENSE
Normal file
@ -0,0 +1,27 @@
|
||||
Spine Runtimes Software License v2.5
|
||||
|
||||
Copyright (c) 2013-2016, Esoteric Software
|
||||
All rights reserved.
|
||||
|
||||
You are granted a perpetual, non-exclusive, non-sublicensable, and
|
||||
non-transferable license to use, install, execute, and perform the Spine
|
||||
Runtimes software and derivative works solely for personal or internal
|
||||
use. Without the written permission of Esoteric Software (see Section 2 of
|
||||
the Spine Software License Agreement), you may not (a) modify, translate,
|
||||
adapt, or develop new applications using the Spine Runtimes or otherwise
|
||||
create derivative works or improvements of the Spine Runtimes or (b) remove,
|
||||
delete, alter, or obscure any trademarks or any copyright, trademark, patent,
|
||||
or other intellectual property or proprietary rights notices on or in the
|
||||
Software, including any copy thereof. Redistributions in binary or source
|
||||
form must include this license and terms.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
|
||||
USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
BIN
spine-ue4/Plugins/SpinePlugin/Resources/Icon128.png
Normal file
BIN
spine-ue4/Plugins/SpinePlugin/Resources/Icon128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@ -0,0 +1,111 @@
|
||||
#include "SpineEditorPluginPrivatePCH.h"
|
||||
|
||||
#include "SpineAtlasAsset.h"
|
||||
#include "AssetRegistryModule.h"
|
||||
#include "AssetToolsModule.h"
|
||||
#include "PackageTools.h"
|
||||
#include "Developer/DesktopPlatform/Public/IDesktopPlatform.h"
|
||||
#include "Developer/DesktopPlatform/Public/DesktopPlatformModule.h"
|
||||
#include "spine/spine.h"
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define LOCTEXT_NAMESPACE "Spine"
|
||||
|
||||
USpineAtlasAssetFactory::USpineAtlasAssetFactory (const FObjectInitializer& objectInitializer): Super(objectInitializer) {
|
||||
bCreateNew = false;
|
||||
bEditAfterNew = true;
|
||||
bEditorImport = true;
|
||||
SupportedClass = USpineAtlasAsset::StaticClass();
|
||||
|
||||
Formats.Add(TEXT("atlas;Spine atlas file"));
|
||||
}
|
||||
|
||||
FText USpineAtlasAssetFactory::GetToolTip () const {
|
||||
return LOCTEXT("SpineAtlasAssetFactory", "Animations exported from Spine");
|
||||
}
|
||||
|
||||
bool USpineAtlasAssetFactory::FactoryCanImport (const FString& filename) {
|
||||
return true;
|
||||
}
|
||||
|
||||
UObject* USpineAtlasAssetFactory::FactoryCreateFile (UClass * InClass, UObject * InParent, FName InName, EObjectFlags Flags, const FString & Filename, const TCHAR* Parms, FFeedbackContext * Warn, bool& bOutOperationCanceled) {
|
||||
FString rawString;
|
||||
if (!FFileHelper::LoadFileToString(rawString, *Filename)) {
|
||||
return nullptr;
|
||||
}
|
||||
const FString longPackagePath = FPackageName::GetLongPackagePath(InParent->GetOutermost()->GetPathName());
|
||||
FString CurrentSourcePath;
|
||||
FString FilenameNoExtension;
|
||||
FString UnusedExtension;
|
||||
FPaths::Split(UFactory::GetCurrentFilename(), CurrentSourcePath, FilenameNoExtension, UnusedExtension);
|
||||
FString name(InName.ToString());
|
||||
name.Append("-atlas");
|
||||
USpineAtlasAsset* asset = NewObject<USpineAtlasAsset>(InParent, InClass, FName(*name), Flags);
|
||||
asset->SetRawData(rawString);
|
||||
asset->SetAtlasFileName(FName(*Filename));
|
||||
LoadAtlas(asset, CurrentSourcePath, longPackagePath);
|
||||
return asset;
|
||||
}
|
||||
|
||||
bool USpineAtlasAssetFactory::CanReimport(UObject* Obj, TArray<FString>& OutFilenames) {
|
||||
USpineAtlasAsset* asset = Cast<USpineAtlasAsset>(Obj);
|
||||
if (!asset) return false;
|
||||
FString filename = asset->GetAtlasFileName().ToString();
|
||||
if (!filename.IsEmpty())
|
||||
OutFilenames.Add(filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
void USpineAtlasAssetFactory::SetReimportPaths(UObject* Obj, const TArray<FString>& NewReimportPaths) {
|
||||
USpineAtlasAsset* asset = Cast<USpineAtlasAsset>(Obj);
|
||||
if (asset && ensure(NewReimportPaths.Num() == 1))
|
||||
asset->SetAtlasFileName(FName(*NewReimportPaths[0]));
|
||||
}
|
||||
|
||||
EReimportResult::Type USpineAtlasAssetFactory::Reimport(UObject* Obj) {
|
||||
USpineAtlasAsset* asset = Cast<USpineAtlasAsset>(Obj);
|
||||
FString rawString;
|
||||
if (!FFileHelper::LoadFileToString(rawString, *asset->GetAtlasFileName().ToString())) return EReimportResult::Failed;
|
||||
asset->SetRawData(rawString);
|
||||
const FString longPackagePath = FPackageName::GetLongPackagePath(asset->GetOutermost()->GetPathName());
|
||||
FString CurrentSourcePath;
|
||||
FString FilenameNoExtension;
|
||||
FString UnusedExtension;
|
||||
FPaths::Split(UFactory::GetCurrentFilename(), CurrentSourcePath, FilenameNoExtension, UnusedExtension);
|
||||
LoadAtlas(asset, CurrentSourcePath, longPackagePath);
|
||||
if (Obj->GetOuter()) Obj->GetOuter()->MarkPackageDirty();
|
||||
else Obj->MarkPackageDirty();
|
||||
return EReimportResult::Succeeded;
|
||||
}
|
||||
|
||||
UTexture2D* resolveTexture (USpineAtlasAsset* asset, const FString& pageFileName, const FString& targetSubPath) {
|
||||
FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools");
|
||||
|
||||
TArray<FString> fileNames;
|
||||
fileNames.Add(pageFileName);
|
||||
|
||||
//@TODO: Avoid the first compression, since we're going to recompress
|
||||
TArray<UObject*> importedAsset = AssetToolsModule.Get().ImportAssets(fileNames, targetSubPath);
|
||||
UTexture2D* texture = (importedAsset.Num() > 0) ? Cast<UTexture2D>(importedAsset[0]) : nullptr;
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void USpineAtlasAssetFactory::LoadAtlas(USpineAtlasAsset* asset, const FString& currentSourcePath, const FString& longPackagePath) {
|
||||
spAtlas* atlas = asset->GetAtlas(true);
|
||||
asset->atlasPages.Empty();
|
||||
|
||||
const FString targetTexturePath = longPackagePath / TEXT("Textures");
|
||||
|
||||
spAtlasPage* page = atlas->pages;
|
||||
while (page) {
|
||||
const FString sourceTextureFilename = FPaths::Combine(*currentSourcePath, UTF8_TO_TCHAR(page->name));
|
||||
UTexture2D* texture = resolveTexture(asset, sourceTextureFilename, targetTexturePath);
|
||||
page = page->next;
|
||||
asset->atlasPages.Add(texture);
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -0,0 +1,31 @@
|
||||
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "SpineEditorPluginPrivatePCH.h"
|
||||
#include "spine/spine.h"
|
||||
|
||||
|
||||
class FSpineEditorPlugin : public ISpineEditorPlugin
|
||||
{
|
||||
/** IModuleInterface implementation */
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
||||
|
||||
IMPLEMENT_MODULE( FSpineEditorPlugin, ISpineEditorPlugin )
|
||||
|
||||
|
||||
|
||||
void FSpineEditorPlugin::StartupModule()
|
||||
{
|
||||
// This code will execute after your module is loaded into memory (but after global variables are initialized, of course.)
|
||||
}
|
||||
|
||||
|
||||
void FSpineEditorPlugin::ShutdownModule()
|
||||
{
|
||||
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
|
||||
// we call this function before unloading the module.
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
#include "SpineEditorPlugin.h"
|
||||
#include "SpinePlugin.h"
|
||||
#include "SpineAtlasImportFactory.h"
|
||||
#include "SpineSkeletonImportFactory.h"
|
||||
@ -0,0 +1,83 @@
|
||||
#include "SpineEditorPluginPrivatePCH.h"
|
||||
|
||||
#include "SpineSkeletonDataAsset.h"
|
||||
#include "AssetRegistryModule.h"
|
||||
#include "AssetToolsModule.h"
|
||||
#include "PackageTools.h"
|
||||
#include "Developer/DesktopPlatform/Public/IDesktopPlatform.h"
|
||||
#include "Developer/DesktopPlatform/Public/DesktopPlatformModule.h"
|
||||
#include "spine/spine.h"
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define LOCTEXT_NAMESPACE "Spine"
|
||||
|
||||
USpineSkeletonAssetFactory::USpineSkeletonAssetFactory (const FObjectInitializer& objectInitializer): Super(objectInitializer) {
|
||||
bCreateNew = false;
|
||||
bEditAfterNew = true;
|
||||
bEditorImport = true;
|
||||
SupportedClass = USpineSkeletonDataAsset::StaticClass();
|
||||
|
||||
Formats.Add(TEXT("json;Spine skeleton file"));
|
||||
Formats.Add(TEXT("skel;Spine skeleton file"));
|
||||
}
|
||||
|
||||
FText USpineSkeletonAssetFactory::GetToolTip () const {
|
||||
return LOCTEXT("USpineSkeletonAssetFactory", "Animations exported from Spine");
|
||||
}
|
||||
|
||||
bool USpineSkeletonAssetFactory::FactoryCanImport (const FString& filename) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoadAtlas (const FString& filename, const FString& targetPath) {
|
||||
FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools");
|
||||
|
||||
FString skelFile = filename.Replace(TEXT(".skel"), TEXT(".atlas")).Replace(TEXT(".json"), TEXT(".atlas"));
|
||||
if (!FPaths::FileExists(skelFile)) return;
|
||||
|
||||
TArray<FString> fileNames;
|
||||
fileNames.Add(skelFile);
|
||||
TArray<UObject*> importedAssets = AssetToolsModule.Get().ImportAssets(fileNames, targetPath);
|
||||
}
|
||||
|
||||
UObject* USpineSkeletonAssetFactory::FactoryCreateFile (UClass * InClass, UObject * InParent, FName InName, EObjectFlags Flags, const FString & Filename, const TCHAR* Parms, FFeedbackContext * Warn, bool& bOutOperationCanceled) {
|
||||
FString name(InName.ToString());
|
||||
name.Append("-data");
|
||||
USpineSkeletonDataAsset* asset = NewObject<USpineSkeletonDataAsset>(InParent, InClass, FName(*name), Flags);
|
||||
if (!FFileHelper::LoadFileToArray(asset->GetRawData(), *Filename, 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
asset->SetSkeletonDataFileName(FName(*Filename));
|
||||
const FString longPackagePath = FPackageName::GetLongPackagePath(asset->GetOutermost()->GetPathName());
|
||||
LoadAtlas(Filename, longPackagePath);
|
||||
return asset;
|
||||
}
|
||||
|
||||
bool USpineSkeletonAssetFactory::CanReimport(UObject* Obj, TArray<FString>& OutFilenames) {
|
||||
USpineSkeletonDataAsset* asset = Cast<USpineSkeletonDataAsset>(Obj);
|
||||
if (!asset) return false;
|
||||
FString filename = asset->GetSkeletonDataFileName().ToString();
|
||||
if (!filename.IsEmpty())
|
||||
OutFilenames.Add(filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
void USpineSkeletonAssetFactory::SetReimportPaths(UObject* Obj, const TArray<FString>& NewReimportPaths) {
|
||||
USpineSkeletonDataAsset* asset = Cast<USpineSkeletonDataAsset>(Obj);
|
||||
if (asset && ensure(NewReimportPaths.Num() == 1))
|
||||
asset->SetSkeletonDataFileName(FName(*NewReimportPaths[0]));
|
||||
}
|
||||
|
||||
EReimportResult::Type USpineSkeletonAssetFactory::Reimport(UObject* Obj) {
|
||||
USpineSkeletonDataAsset* asset = Cast<USpineSkeletonDataAsset>(Obj);
|
||||
FString rawString;
|
||||
if (!FFileHelper::LoadFileToArray(asset->GetRawData(), *asset->GetSkeletonDataFileName().ToString(), 0)) return EReimportResult::Failed;
|
||||
const FString longPackagePath = FPackageName::GetLongPackagePath(asset->GetOutermost()->GetPathName());
|
||||
LoadAtlas(*asset->GetSkeletonDataFileName().ToString(), longPackagePath);
|
||||
if (Obj->GetOuter()) Obj->GetOuter()->MarkPackageDirty();
|
||||
else Obj->MarkPackageDirty();
|
||||
return EReimportResult::Succeeded;
|
||||
}
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -0,0 +1,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UnrealEd.h"
|
||||
#include "SpineAtlasAsset.h"
|
||||
#include "SpineAtlasImportFactory.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class USpineAtlasAssetFactory : public UFactory, public FReimportHandler
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
|
||||
virtual FText GetToolTip() const override;
|
||||
virtual bool FactoryCanImport(const FString& Filename) override;
|
||||
virtual UObject* FactoryCreateFile (UClass * InClass, UObject * InParent, FName InName, EObjectFlags Flags, const FString & Filename, const TCHAR* Parms, FFeedbackContext * Warn, bool& bOutOperationCanceled) override;
|
||||
|
||||
virtual bool CanReimport(UObject* Obj, TArray<FString>& OutFilenames) override;
|
||||
virtual void SetReimportPaths(UObject* Obj, const TArray<FString>& NewReimportPaths) override;
|
||||
virtual EReimportResult::Type Reimport(UObject* Obj) override;
|
||||
|
||||
void LoadAtlas(USpineAtlasAsset* asset, const FString& currentSourcePath, const FString& longPackagePath);
|
||||
};
|
||||
@ -0,0 +1,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ModuleManager.h"
|
||||
|
||||
class ISpineEditorPlugin : public IModuleInterface {
|
||||
|
||||
public:
|
||||
static inline ISpineEditorPlugin& Get() {
|
||||
return FModuleManager::LoadModuleChecked< ISpineEditorPlugin >( "SpineEditorPlugin" );
|
||||
}
|
||||
|
||||
static inline bool IsAvailable() {
|
||||
return FModuleManager::Get().IsModuleLoaded( "SpineEditorPlugin" );
|
||||
}
|
||||
};
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UnrealEd.h"
|
||||
#include "SpineAtlasAsset.h"
|
||||
#include "SpineSkeletonImportFactory.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class USpineSkeletonAssetFactory : public UFactory, public FReimportHandler
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
|
||||
virtual FText GetToolTip() const override;
|
||||
virtual bool FactoryCanImport(const FString& Filename) override;
|
||||
virtual UObject* FactoryCreateFile (UClass * InClass, UObject * InParent, FName InName, EObjectFlags Flags, const FString & Filename, const TCHAR* Parms, FFeedbackContext * Warn, bool& bOutOperationCanceled) override;
|
||||
|
||||
virtual bool CanReimport(UObject* Obj, TArray<FString>& OutFilenames) override;
|
||||
virtual void SetReimportPaths(UObject* Obj, const TArray<FString>& NewReimportPaths) override;
|
||||
virtual EReimportResult::Type Reimport(UObject* Obj) override;
|
||||
};
|
||||
@ -0,0 +1,32 @@
|
||||
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
namespace UnrealBuildTool.Rules
|
||||
{
|
||||
public class SpineEditorPlugin : ModuleRules
|
||||
{
|
||||
public SpineEditorPlugin(TargetInfo Target)
|
||||
{
|
||||
PublicIncludePaths.AddRange(new string[] { "SpineEditorPlugin/Public" });
|
||||
|
||||
PrivateIncludePaths.AddRange(new string[] { "SpineEditorPlugin/Private" });
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[] {
|
||||
"Core",
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"UnrealEd",
|
||||
"SpinePlugin"
|
||||
});
|
||||
|
||||
PublicIncludePathModuleNames.AddRange(new string[] {
|
||||
"AssetTools",
|
||||
"AssetRegistry"
|
||||
});
|
||||
|
||||
DynamicallyLoadedModuleNames.AddRange(new string[] {
|
||||
"AssetTools",
|
||||
"AssetRegistry"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
#include "SpinePluginPrivatePCH.h"
|
||||
#include "spine/spine.h"
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
|
||||
FString USpineAtlasAsset::GetRawData () const {
|
||||
return rawData;
|
||||
}
|
||||
|
||||
FName USpineAtlasAsset::GetAtlasFileName () const {
|
||||
#if WITH_EDITORONLY_DATA
|
||||
TArray<FString> files;
|
||||
if (importData) importData->ExtractFilenames(files);
|
||||
if (files.Num() > 0) return FName(*files[0]);
|
||||
else return atlasFileName;
|
||||
#else
|
||||
return atlasFileName;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
|
||||
void USpineAtlasAsset::SetRawData (const FString &_rawData) {
|
||||
this->rawData = _rawData;
|
||||
}
|
||||
|
||||
void USpineAtlasAsset::SetAtlasFileName (const FName &_atlasFileName) {
|
||||
importData->UpdateFilenameOnly(_atlasFileName.ToString());
|
||||
TArray<FString> files;
|
||||
importData->ExtractFilenames(files);
|
||||
if (files.Num() > 0) atlasFileName = FName(*files[0]);
|
||||
}
|
||||
|
||||
void USpineAtlasAsset::PostInitProperties () {
|
||||
if (!HasAnyFlags(RF_ClassDefaultObject)) importData = NewObject<UAssetImportData>(this, TEXT("AssetImportData"));
|
||||
Super::PostInitProperties();
|
||||
}
|
||||
|
||||
void USpineAtlasAsset::GetAssetRegistryTags (TArray<FAssetRegistryTag>& OutTags) const {
|
||||
if (importData) {
|
||||
OutTags.Add(FAssetRegistryTag(SourceFileTagName(), importData->GetSourceData().ToJson(), FAssetRegistryTag::TT_Hidden) );
|
||||
}
|
||||
|
||||
Super::GetAssetRegistryTags(OutTags);
|
||||
}
|
||||
|
||||
void USpineAtlasAsset::Serialize (FArchive& Ar) {
|
||||
Super::Serialize(Ar);
|
||||
if (Ar.IsLoading() && Ar.UE4Ver() < VER_UE4_ASSET_IMPORT_DATA_AS_JSON && !importData)
|
||||
importData = NewObject<UAssetImportData>(this, TEXT("AssetImportData"));
|
||||
}
|
||||
|
||||
void USpineAtlasAsset::BeginDestroy () {
|
||||
if (atlas) {
|
||||
spAtlas_dispose(atlas);
|
||||
atlas = nullptr;
|
||||
}
|
||||
Super::BeginDestroy();
|
||||
}
|
||||
|
||||
spAtlas* USpineAtlasAsset::GetAtlas (bool forceReload) {
|
||||
if (!atlas || forceReload) {
|
||||
if (atlas) {
|
||||
spAtlas_dispose(atlas);
|
||||
atlas = nullptr;
|
||||
}
|
||||
std::string t = TCHAR_TO_UTF8(*rawData);
|
||||
atlas = spAtlas_create(t.c_str(), strlen(t.c_str()), "", nullptr);
|
||||
spAtlasPage* page = atlas->pages;
|
||||
int i = 0;
|
||||
while (page) {
|
||||
int num = atlasPages.Num();
|
||||
if (atlasPages.Num() > 0 && atlasPages.Num() > i)
|
||||
page->rendererObject = atlasPages[i++];
|
||||
page = page->next;
|
||||
}
|
||||
}
|
||||
return this->atlas;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,42 @@
|
||||
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "SpinePluginPrivatePCH.h"
|
||||
#include "spine/spine.h"
|
||||
|
||||
|
||||
class FSpinePlugin : public SpinePlugin {
|
||||
/** IModuleInterface implementation */
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
||||
|
||||
IMPLEMENT_MODULE( FSpinePlugin, SpinePlugin )
|
||||
|
||||
|
||||
|
||||
void FSpinePlugin::StartupModule() {
|
||||
// This code will execute after your module is loaded into memory (but after global variables are initialized, of course.)
|
||||
printf("This is a test");
|
||||
}
|
||||
|
||||
|
||||
void FSpinePlugin::ShutdownModule() {
|
||||
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
|
||||
// we call this function before unloading the module.
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void _spAtlasPage_createTexture (spAtlasPage* self, const char* path) {
|
||||
|
||||
}
|
||||
void _spAtlasPage_disposeTexture (spAtlasPage* self) {
|
||||
|
||||
}
|
||||
|
||||
char* _spUtil_readFile (const char* path, int* length) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "SpinePlugin.h"
|
||||
|
||||
// You should place include statements to your module's private header files here. You only need to
|
||||
// add includes for headers that are used in most of your module's source files though.
|
||||
#include "SpineSkeletonDataAsset.h"
|
||||
#include "SpineAtlasAsset.h"
|
||||
#include "SpineSkeletonComponent.h"
|
||||
#include "SpineSkeletonRendererComponent.h"
|
||||
@ -0,0 +1,65 @@
|
||||
// iFll out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "SpinePluginPrivatePCH.h"
|
||||
|
||||
// Sets default values for this component's properties
|
||||
USpineSkeletonComponent::USpineSkeletonComponent()
|
||||
{
|
||||
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
|
||||
// off to improve performance if you don't need them.
|
||||
bWantsBeginPlay = true;
|
||||
PrimaryComponentTick.bCanEverTick = true;
|
||||
bTickInEditor = true;
|
||||
bAutoActivate = true;
|
||||
}
|
||||
|
||||
void USpineSkeletonComponent::BeginPlay() {
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
void USpineSkeletonComponent::TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction ) {
|
||||
Super::TickComponent( DeltaTime, TickType, ThisTickFunction );
|
||||
|
||||
if (lastAtlas != atlas || lastData != skeletonData) {
|
||||
DisposeState();
|
||||
|
||||
if (atlas && skeletonData) {
|
||||
spSkeletonData* data = skeletonData->GetSkeletonData(atlas->GetAtlas(true), true);
|
||||
skeleton = spSkeleton_create(data);
|
||||
stateData = spAnimationStateData_create(data);
|
||||
state = spAnimationState_create(stateData);
|
||||
spAnimationState_setAnimationByName(state, 0, "walk", true);
|
||||
}
|
||||
|
||||
lastAtlas = atlas;
|
||||
lastData = skeletonData;
|
||||
}
|
||||
|
||||
if (state) {
|
||||
spAnimationState_update(state, DeltaTime);
|
||||
spAnimationState_apply(state, skeleton);
|
||||
spSkeleton_updateWorldTransform(skeleton);
|
||||
}
|
||||
}
|
||||
|
||||
void USpineSkeletonComponent::DisposeState() {
|
||||
if (stateData) {
|
||||
spAnimationStateData_dispose(stateData);
|
||||
stateData = nullptr;
|
||||
}
|
||||
|
||||
if (state) {
|
||||
spAnimationState_dispose(state);
|
||||
state = nullptr;
|
||||
}
|
||||
|
||||
if (skeleton) {
|
||||
spSkeleton_dispose(skeleton);
|
||||
skeleton = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void USpineSkeletonComponent::BeginDestroy() {
|
||||
DisposeState();
|
||||
Super::BeginDestroy();
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
#include "SpinePluginPrivatePCH.h"
|
||||
#include "spine/spine.h"
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
|
||||
FName USpineSkeletonDataAsset::GetSkeletonDataFileName () const {
|
||||
#if WITH_EDITORONLY_DATA
|
||||
TArray<FString> files;
|
||||
if (importData) importData->ExtractFilenames(files);
|
||||
if (files.Num() > 0) return FName(*files[0]);
|
||||
else return skeletonDataFileName;
|
||||
#else
|
||||
return skeletonDataFileName;
|
||||
#endif
|
||||
}
|
||||
|
||||
TArray<uint8>& USpineSkeletonDataAsset::GetRawData () {
|
||||
return this->rawData;
|
||||
}
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
|
||||
void USpineSkeletonDataAsset::SetSkeletonDataFileName (const FName &_skeletonDataFileName) {
|
||||
importData->UpdateFilenameOnly(_skeletonDataFileName.ToString());
|
||||
TArray<FString> files;
|
||||
importData->ExtractFilenames(files);
|
||||
if (files.Num() > 0) this->skeletonDataFileName = FName(*files[0]);
|
||||
}
|
||||
|
||||
void USpineSkeletonDataAsset::PostInitProperties () {
|
||||
if (!HasAnyFlags(RF_ClassDefaultObject)) importData = NewObject<UAssetImportData>(this, TEXT("AssetImportData"));
|
||||
Super::PostInitProperties();
|
||||
}
|
||||
|
||||
void USpineSkeletonDataAsset::GetAssetRegistryTags (TArray<FAssetRegistryTag>& OutTags) const {
|
||||
if (importData) {
|
||||
OutTags.Add(FAssetRegistryTag(SourceFileTagName(), importData->GetSourceData().ToJson(), FAssetRegistryTag::TT_Hidden) );
|
||||
}
|
||||
|
||||
Super::GetAssetRegistryTags(OutTags);
|
||||
}
|
||||
|
||||
void USpineSkeletonDataAsset::Serialize (FArchive& Ar) {
|
||||
Super::Serialize(Ar);
|
||||
if (Ar.IsLoading() && Ar.UE4Ver() < VER_UE4_ASSET_IMPORT_DATA_AS_JSON && !importData)
|
||||
importData = NewObject<UAssetImportData>(this, TEXT("AssetImportData"));
|
||||
}
|
||||
|
||||
void USpineSkeletonDataAsset::BeginDestroy () {
|
||||
if (this->skeletonData) {
|
||||
spSkeletonData_dispose(this->skeletonData);
|
||||
this->skeletonData = nullptr;
|
||||
}
|
||||
Super::BeginDestroy();
|
||||
}
|
||||
|
||||
spSkeletonData* USpineSkeletonDataAsset::GetSkeletonData (spAtlas* atlas, bool forceReload) {
|
||||
if (!skeletonData || forceReload) {
|
||||
if (skeletonData) {
|
||||
spSkeletonData_dispose(skeletonData);
|
||||
skeletonData = nullptr;
|
||||
}
|
||||
int dataLen = rawData.Num();
|
||||
if (skeletonDataFileName.GetPlainNameString().Contains(TEXT(".json"))) {
|
||||
spSkeletonJson* json = spSkeletonJson_create(atlas);
|
||||
this->skeletonData = spSkeletonJson_readSkeletonData(json, (const char*)rawData.GetData());
|
||||
spSkeletonJson_dispose(json);
|
||||
} else {
|
||||
spSkeletonBinary* binary = spSkeletonBinary_create(atlas);
|
||||
this->skeletonData = spSkeletonBinary_readSkeletonData(binary, (const unsigned char*)rawData.GetData(), (int)rawData.Num());
|
||||
spSkeletonBinary_dispose(binary);
|
||||
}
|
||||
lastAtlas = atlas;
|
||||
}
|
||||
return this->skeletonData;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,118 @@
|
||||
#include "SpinePluginPrivatePCH.h"
|
||||
#include "Engine.h"
|
||||
#include "spine/spine.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
USpineSkeletonRendererComponent::USpineSkeletonRendererComponent(const FObjectInitializer& ObjectInitializer)
|
||||
{
|
||||
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
|
||||
// off to improve performance if you don't need them.
|
||||
bWantsBeginPlay = true;
|
||||
PrimaryComponentTick.bCanEverTick = true;
|
||||
bTickInEditor = true;
|
||||
bAutoActivate = true;
|
||||
}
|
||||
|
||||
// Called when the game starts
|
||||
void USpineSkeletonRendererComponent::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
// Called every frame
|
||||
void USpineSkeletonRendererComponent::TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction )
|
||||
{
|
||||
Super::TickComponent( DeltaTime, TickType, ThisTickFunction );
|
||||
|
||||
UClass* skeletonClass = USpineSkeletonComponent::StaticClass();
|
||||
AActor* owner = GetOwner();
|
||||
if (owner) {
|
||||
USpineSkeletonComponent* skeleton = Cast<USpineSkeletonComponent>(owner->GetComponentByClass(skeletonClass));
|
||||
if (skeleton && skeleton->skeleton) {
|
||||
spSkeleton_updateWorldTransform(skeleton->skeleton);
|
||||
UpdateMesh(skeleton->skeleton);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void USpineSkeletonRendererComponent::UpdateMesh(spSkeleton* skeleton) {
|
||||
TArray<FVector> vertices;
|
||||
TArray<int32> indices;
|
||||
TArray<FVector2D> uvs;
|
||||
TArray<FColor> colors;
|
||||
|
||||
int worldVerticesLength = 1000;
|
||||
float* worldVertices = (float*)malloc((2 + 2 + 5) * worldVerticesLength);
|
||||
int idx = 0;
|
||||
int meshSection = 0;
|
||||
|
||||
ClearAllMeshSections();
|
||||
|
||||
for (int i = 0; i < skeleton->slotsCount; ++i) {
|
||||
spSlot* slot = skeleton->drawOrder[i];
|
||||
spAttachment* attachment = slot->attachment;
|
||||
if (!attachment) continue;
|
||||
|
||||
if (attachment->type == SP_ATTACHMENT_REGION) {
|
||||
spRegionAttachment* regionAttachment = (spRegionAttachment*)attachment;
|
||||
spRegionAttachment_computeWorldVertices(regionAttachment, slot->bone, worldVertices);
|
||||
|
||||
uint8 r = static_cast<uint8>(skeleton->r * slot->r * 255);
|
||||
uint8 g = static_cast<uint8>(skeleton->g * slot->g * 255);
|
||||
uint8 b = static_cast<uint8>(skeleton->b * slot->b * 255);
|
||||
uint8 a = static_cast<uint8>(skeleton->a * slot->a * 255);
|
||||
|
||||
colors.Add(FColor(r, g, b, a));
|
||||
vertices.Add(FVector(worldVertices[0], 0, worldVertices[1]));
|
||||
uvs.Add(FVector2D(regionAttachment->uvs[0], regionAttachment->uvs[1]));
|
||||
|
||||
colors.Add(FColor(r, g, b, a));
|
||||
vertices.Add(FVector(worldVertices[2], 0, worldVertices[3]));
|
||||
uvs.Add(FVector2D(regionAttachment->uvs[2], regionAttachment->uvs[3]));
|
||||
|
||||
colors.Add(FColor(r, g, b, a));
|
||||
vertices.Add(FVector(worldVertices[4], 0, worldVertices[5]));
|
||||
uvs.Add(FVector2D(regionAttachment->uvs[4], regionAttachment->uvs[5]));
|
||||
|
||||
colors.Add(FColor(r, g, b, a));
|
||||
vertices.Add(FVector(worldVertices[6], 0, worldVertices[7]));
|
||||
uvs.Add(FVector2D(regionAttachment->uvs[6], regionAttachment->uvs[7]));
|
||||
|
||||
indices.Add(idx + 0);
|
||||
indices.Add(idx + 1);
|
||||
indices.Add(idx + 2);
|
||||
indices.Add(idx + 0);
|
||||
indices.Add(idx + 2);
|
||||
indices.Add(idx + 3);
|
||||
idx += 4;
|
||||
}
|
||||
/*else if (attachment->type == ATTACHMENT_MESH) {
|
||||
MeshAttachment* mesh = (MeshAttachment*)attachment;
|
||||
if (mesh->super.worldVerticesLength > SPINE_MESH_VERTEX_COUNT_MAX) continue;
|
||||
texture = (Texture*)((AtlasRegion*)mesh->rendererObject)->page->rendererObject;
|
||||
MeshAttachment_computeWorldVertices(mesh, slot, worldVertices);
|
||||
|
||||
Uint8 r = static_cast<Uint8>(skeleton->r * slot->r * 255);
|
||||
Uint8 g = static_cast<Uint8>(skeleton->g * slot->g * 255);
|
||||
Uint8 b = static_cast<Uint8>(skeleton->b * slot->b * 255);
|
||||
Uint8 a = static_cast<Uint8>(skeleton->a * slot->a * 255);
|
||||
vertex.color.r = r;
|
||||
vertex.color.g = g;
|
||||
vertex.color.b = b;
|
||||
vertex.color.a = a;
|
||||
|
||||
Vector2u size = texture->getSize();
|
||||
for (int i = 0; i < mesh->trianglesCount; ++i) {
|
||||
int index = mesh->triangles[i] << 1;
|
||||
vertex.position.x = worldVertices[index];
|
||||
vertex.position.y = worldVertices[index + 1];
|
||||
vertex.texCoords.x = mesh->uvs[index] * size.x;
|
||||
vertex.texCoords.y = mesh->uvs[index + 1] * size.y;
|
||||
vertexArray->append(vertex);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
CreateMeshSection(0, vertices, indices, TArray<FVector>(), uvs, colors, TArray<FProcMeshTangent>(), false);
|
||||
free(worldVertices);
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine.h"
|
||||
#include "spine/spine.h"
|
||||
#include "SpineAtlasAsset.generated.h"
|
||||
|
||||
UCLASS( ClassGroup=(Spine) )
|
||||
class SPINEPLUGIN_API USpineAtlasAsset : public UObject {
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
spAtlas* GetAtlas (bool forceReload = false);
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Spine)
|
||||
TArray<UTexture2D*> atlasPages;
|
||||
|
||||
FString GetRawData () const;
|
||||
FName GetAtlasFileName () const;
|
||||
|
||||
virtual void BeginDestroy () override;
|
||||
|
||||
protected:
|
||||
spAtlas* atlas = nullptr;
|
||||
|
||||
UPROPERTY()
|
||||
FString rawData;
|
||||
|
||||
UPROPERTY()
|
||||
FName atlasFileName;
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
|
||||
public:
|
||||
void SetRawData (const FString &rawData);
|
||||
void SetAtlasFileName (const FName &atlasFileName);
|
||||
|
||||
protected:
|
||||
UPROPERTY(VisibleAnywhere, Instanced, Category=ImportSettings)
|
||||
class UAssetImportData* importData;
|
||||
|
||||
virtual void PostInitProperties ( ) override;
|
||||
virtual void GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const override;
|
||||
virtual void Serialize (FArchive& Ar) override;
|
||||
#endif
|
||||
};
|
||||
@ -0,0 +1,38 @@
|
||||
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ModuleManager.h"
|
||||
|
||||
|
||||
/**
|
||||
* The public interface to this module. In most cases, this interface is only public to sibling modules
|
||||
* within this plugin.
|
||||
*/
|
||||
class SPINEPLUGIN_API SpinePlugin : public IModuleInterface
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Singleton-like access to this module's interface. This is just for convenience!
|
||||
* Beware of calling this during the shutdown phase, though. Your module might have been unloaded already.
|
||||
*
|
||||
* @return Returns singleton instance, loading the module on demand if needed
|
||||
*/
|
||||
static inline SpinePlugin& Get()
|
||||
{
|
||||
return FModuleManager::LoadModuleChecked< SpinePlugin >( "SpinePlugin" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true.
|
||||
*
|
||||
* @return True if the module is loaded and ready to use
|
||||
*/
|
||||
static inline bool IsAvailable()
|
||||
{
|
||||
return FModuleManager::Get().IsModuleLoaded( "SpinePlugin" );
|
||||
}
|
||||
};
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "SpineSkeletonComponent.generated.h"
|
||||
|
||||
class USpineAtlasAsset;
|
||||
UCLASS( ClassGroup=(Spine), meta=(BlueprintSpawnableComponent) )
|
||||
class SPINEPLUGIN_API USpineSkeletonComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Spine)
|
||||
USpineAtlasAsset* atlas;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Spine)
|
||||
USpineSkeletonDataAsset* skeletonData;
|
||||
|
||||
spAnimationStateData* stateData;
|
||||
spAnimationState* state;
|
||||
spSkeleton* skeleton;
|
||||
|
||||
USpineSkeletonComponent();
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
virtual void TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction ) override;
|
||||
|
||||
virtual void BeginDestroy () override;
|
||||
|
||||
protected:
|
||||
void DisposeState();
|
||||
|
||||
USpineAtlasAsset* lastAtlas = nullptr;
|
||||
USpineSkeletonDataAsset* lastData = nullptr;
|
||||
};
|
||||
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine.h"
|
||||
#include "spine/spine.h"
|
||||
#include "SpineSkeletonDataAsset.generated.h"
|
||||
|
||||
UCLASS( ClassGroup=(Spine) )
|
||||
class SPINEPLUGIN_API USpineSkeletonDataAsset : public UObject {
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
spSkeletonData* GetSkeletonData(spAtlas* atlas, bool forceReload = false);
|
||||
|
||||
FName GetSkeletonDataFileName () const;
|
||||
TArray<uint8>& GetRawData ();
|
||||
|
||||
virtual void BeginDestroy () override;
|
||||
|
||||
protected:
|
||||
UPROPERTY()
|
||||
TArray<uint8> rawData;
|
||||
|
||||
spAtlas* lastAtlas = nullptr;
|
||||
spSkeletonData* skeletonData = nullptr;
|
||||
|
||||
UPROPERTY()
|
||||
FName skeletonDataFileName;
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
public:
|
||||
void SetSkeletonDataFileName (const FName &skeletonDataFileName);
|
||||
|
||||
protected:
|
||||
UPROPERTY(VisibleAnywhere, Instanced, Category=ImportSettings)
|
||||
class UAssetImportData* importData;
|
||||
|
||||
virtual void PostInitProperties ( ) override;
|
||||
virtual void GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const override;
|
||||
virtual void Serialize (FArchive& Ar) override;
|
||||
#endif
|
||||
};
|
||||
@ -0,0 +1,27 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "ProceduralMeshComponent.h"
|
||||
#include "SpineSkeletonComponent.h"
|
||||
#include "SpineSkeletonRendererComponent.generated.h"
|
||||
|
||||
|
||||
UCLASS( ClassGroup=(Spine), meta=(BlueprintSpawnableComponent) )
|
||||
class SPINEPLUGIN_API USpineSkeletonRendererComponent : public UProceduralMeshComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
USpineSkeletonRendererComponent (const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
virtual void BeginPlay () override;
|
||||
|
||||
virtual void TickComponent (float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
|
||||
protected:
|
||||
void UpdateMesh (spSkeleton* skeleton);
|
||||
|
||||
bool updated;
|
||||
};
|
||||
@ -0,0 +1,16 @@
|
||||
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
namespace UnrealBuildTool.Rules
|
||||
{
|
||||
public class SpinePlugin : ModuleRules
|
||||
{
|
||||
public SpinePlugin(TargetInfo Target)
|
||||
{
|
||||
PublicIncludePaths.AddRange(new string[] { "SpinePlugin/Public", "SpinePlugin/Public/spine-c/include" });
|
||||
PrivateIncludePaths.AddRange(new string[] { "SpinePlugin/Private", "SpinePlugin/Public/spine-c/include" });
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "ProceduralMeshComponent" });
|
||||
PrivateDependencyModuleNames.AddRange(new string[] { "RHI", "RenderCore", "ShaderCore" });
|
||||
OptimizeCode = CodeOptimization.Never;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
spine-ue4/Plugins/SpinePlugin/SpinePlugin.uplugin
Normal file
29
spine-ue4/Plugins/SpinePlugin/SpinePlugin.uplugin
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"FileVersion" : 3,
|
||||
"Version" : 1,
|
||||
"VersionName" : "1.0",
|
||||
"FriendlyName" : "Spine Plugin",
|
||||
"Description" : "A plugin to load and render Spine animations in Unreal Engine",
|
||||
"Category" : "2D",
|
||||
"CreatedBy" : "Esoteric Software",
|
||||
"CreatedByURL" : "http://esotericsoftware.com",
|
||||
"DocsURL" : "",
|
||||
"MarketplaceURL" : "",
|
||||
"SupportURL" : "",
|
||||
"EnabledByDefault" : false,
|
||||
"CanContainContent" : false,
|
||||
"IsBetaVersion" : false,
|
||||
"Installed" : false,
|
||||
"Modules" :
|
||||
[
|
||||
{
|
||||
"Name" : "SpinePlugin",
|
||||
"Type" : "Runtime",
|
||||
"LoadingPhase" : "PreDefault"
|
||||
},
|
||||
{
|
||||
"Name" : "SpineEditorPlugin",
|
||||
"Type" : "Editor"
|
||||
}
|
||||
]
|
||||
}
|
||||
29
spine-ue4/README.md
Normal file
29
spine-ue4/README.md
Normal file
@ -0,0 +1,29 @@
|
||||
# spine-ue4
|
||||
The spine-ue4 runtime provides functionality to load, manipulate and render [Spine](http://esotericsoftware.com) skeletal animation data using [Unreal Engine 4](https://www.unrealengine.com/). spine-ue4 is based on [spine-c](https://github.com/EsotericSoftware/spine-runtimes/tree/master/spine-c).
|
||||
|
||||
## Licensing
|
||||
|
||||
This Spine Runtime may only be used for personal or internal use, typically to evaluate Spine before purchasing. If you would like to incorporate a Spine Runtime into your applications, distribute software containing a Spine Runtime, or modify a Spine Runtime, then you will need a valid [Spine license](https://esotericsoftware.com/spine-purchase). Please see the [Spine Runtimes Software License](https://github.com/EsotericSoftware/spine-runtimes/blob/master/LICENSE) for detailed information.
|
||||
|
||||
The Spine Runtimes are developed with the intent to be used with data exported from Spine. By purchasing Spine, `Section 2` of the [Spine Software License](https://esotericsoftware.com/files/license.txt) grants the right to create and distribute derivative works of the Spine Runtimes.
|
||||
|
||||
## Spine version
|
||||
|
||||
spine-ue4 works with data exported from Spine 3.4.02.
|
||||
|
||||
spine-ue4 supports all Spine features.
|
||||
|
||||
## Usage
|
||||
1. Create a new Unreal Engine project. See the [Unreal Engine documentation](https://docs.unrealengine.com/latest/INT/) or have a look at the example in this repository.
|
||||
2. Download the Spine Runtimes source using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip)
|
||||
3. Copy the `Plugins` folder from this directory to your new project's root directory.
|
||||
4. Copy the `spine-c` folder from this repositories root directory to your project's `Plugins/SpinePlugin/Sources/SpinePlugin/Public/` directory.
|
||||
5. Open the Unreal Project in the Unreal Editor
|
||||
|
||||
See the [Spine Runtimes documentation](http://esotericsoftware.com/spine-documentation#runtimesTitle) on how to use the APIs or check out the Spine UE4 example.
|
||||
|
||||
## Example
|
||||
The Spine UE4 example works on all platforms supported by Unreal Engine.
|
||||
|
||||
1. Copy the `spine-c` folder from this repositories root directory to your `Plugins/SpinePlugin/Sources/SpinePlugin/Public/` directory.
|
||||
2. Open the SpineUE4.uproject file with Unreal Editor
|
||||
25
spine-ue4/Source/SpineUE4.Target.cs
Normal file
25
spine-ue4/Source/SpineUE4.Target.cs
Normal file
@ -0,0 +1,25 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
using UnrealBuildTool;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class SpineUE4Target : TargetRules
|
||||
{
|
||||
public SpineUE4Target(TargetInfo Target)
|
||||
{
|
||||
Type = TargetType.Game;
|
||||
}
|
||||
|
||||
//
|
||||
// TargetRules interface.
|
||||
//
|
||||
|
||||
public override void SetupBinaries(
|
||||
TargetInfo Target,
|
||||
ref List<UEBuildBinaryConfiguration> OutBuildBinaryConfigurations,
|
||||
ref List<string> OutExtraModuleNames
|
||||
)
|
||||
{
|
||||
OutExtraModuleNames.AddRange( new string[] { "SpineUE4" } );
|
||||
}
|
||||
}
|
||||
21
spine-ue4/Source/SpineUE4/SpineUE4.Build.cs
Normal file
21
spine-ue4/Source/SpineUE4/SpineUE4.Build.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class SpineUE4 : ModuleRules
|
||||
{
|
||||
public SpineUE4(TargetInfo Target)
|
||||
{
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ProceduralMeshComponent" });
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(new string[] { });
|
||||
|
||||
// Uncomment if you are using Slate UI
|
||||
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
|
||||
|
||||
// Uncomment if you are using online features
|
||||
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
||||
|
||||
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
|
||||
}
|
||||
}
|
||||
5
spine-ue4/Source/SpineUE4/SpineUE4.cpp
Normal file
5
spine-ue4/Source/SpineUE4/SpineUE4.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "SpineUE4.h"
|
||||
|
||||
IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, SpineUE4, "SpineUE4" );
|
||||
6
spine-ue4/Source/SpineUE4/SpineUE4.h
Normal file
6
spine-ue4/Source/SpineUE4/SpineUE4.h
Normal file
@ -0,0 +1,6 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine.h"
|
||||
|
||||
8
spine-ue4/Source/SpineUE4/SpineUE4GameMode.cpp
Normal file
8
spine-ue4/Source/SpineUE4/SpineUE4GameMode.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "SpineUE4.h"
|
||||
#include "SpineUE4GameMode.h"
|
||||
|
||||
|
||||
|
||||
|
||||
19
spine-ue4/Source/SpineUE4/SpineUE4GameMode.h
Normal file
19
spine-ue4/Source/SpineUE4/SpineUE4GameMode.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GameFramework/GameMode.h"
|
||||
#include "SpineUE4GameMode.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class SPINEUE4_API ASpineUE4GameMode : public AGameMode
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
25
spine-ue4/Source/SpineUE4Editor.Target.cs
Normal file
25
spine-ue4/Source/SpineUE4Editor.Target.cs
Normal file
@ -0,0 +1,25 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
using UnrealBuildTool;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class SpineUE4EditorTarget : TargetRules
|
||||
{
|
||||
public SpineUE4EditorTarget(TargetInfo Target)
|
||||
{
|
||||
Type = TargetType.Editor;
|
||||
}
|
||||
|
||||
//
|
||||
// TargetRules interface.
|
||||
//
|
||||
|
||||
public override void SetupBinaries(
|
||||
TargetInfo Target,
|
||||
ref List<UEBuildBinaryConfiguration> OutBuildBinaryConfigurations,
|
||||
ref List<string> OutExtraModuleNames
|
||||
)
|
||||
{
|
||||
OutExtraModuleNames.AddRange( new string[] { "SpineUE4" } );
|
||||
}
|
||||
}
|
||||
16
spine-ue4/SpineUE4.uproject
Normal file
16
spine-ue4/SpineUE4.uproject
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"FileVersion": 3,
|
||||
"EngineAssociation": "4.13",
|
||||
"Category": "",
|
||||
"Description": "",
|
||||
"Modules": [
|
||||
{
|
||||
"Name": "SpineUE4",
|
||||
"Type": "Runtime",
|
||||
"LoadingPhase": "Default",
|
||||
"AdditionalDependencies": [
|
||||
"Engine"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user