[ue4] Start anew

This commit is contained in:
badlogic 2016-11-29 14:36:39 +01:00
parent 6fe1e8fa68
commit 27926682d6
43 changed files with 3782 additions and 0 deletions

View File

@ -0,0 +1,5 @@
[EditoronlyBP]
bAllowClassAndBlueprintPinMatching=true
bReplaceBlueprintWithClass=true
bDontLoadBlueprintOutsideEditor=true
bBlueprintIsNotBlueprintType=true

View File

@ -0,0 +1,9 @@
[URL]
[/Script/HardwareTargeting.HardwareTargetingSettings]
TargetedHardwareClass=Desktop
AppliedTargetedHardwareClass=Desktop
DefaultGraphicsPerformance=Maximum
AppliedDefaultGraphicsPerformance=Maximum

View File

@ -0,0 +1,2 @@
[/Script/EngineSettings.GeneralProjectSettings]
ProjectID=A32BDAC45F432EB90DF445842A670D58

Binary file not shown.

Binary file not shown.

View 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

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 KiB

Binary file not shown.

Binary file not shown.

27
spine-ue4/LICENSE Normal file
View 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -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

View File

@ -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.
}

View File

@ -0,0 +1,4 @@
#include "SpineEditorPlugin.h"
#include "SpinePlugin.h"
#include "SpineAtlasImportFactory.h"
#include "SpineSkeletonImportFactory.h"

View File

@ -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

View File

@ -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);
};

View File

@ -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" );
}
};

View File

@ -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;
};

View File

@ -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"
});
}
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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"

View File

@ -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();
}

View File

@ -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

View File

@ -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);
}

View File

@ -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
};

View File

@ -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" );
}
};

View File

@ -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;
};

View File

@ -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
};

View File

@ -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;
};

View File

@ -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;
}
}
}

View 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
View 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

View 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" } );
}
}

View 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
}
}

View 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" );

View File

@ -0,0 +1,6 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "Engine.h"

View File

@ -0,0 +1,8 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "SpineUE4.h"
#include "SpineUE4GameMode.h"

View 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()
};

View 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" } );
}
}

View File

@ -0,0 +1,16 @@
{
"FileVersion": 3,
"EngineAssociation": "4.13",
"Category": "",
"Description": "",
"Modules": [
{
"Name": "SpineUE4",
"Type": "Runtime",
"LoadingPhase": "Default",
"AdditionalDependencies": [
"Engine"
]
}
]
}