mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 09:46:02 +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