This commit is contained in:
Yamo4490 2025-09-05 13:48:58 +09:00
parent 5a91df8bd7
commit e6891471db
132 changed files with 4788 additions and 298 deletions

8
Assets/External/Hap Player.meta vendored Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5e5431614cff2064cbe2bac3589f5fab
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4a8e49c85c7ee7a478c2a40f7cca9061
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: aaf22bd5628ec0b48846a14ad7d42515
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,156 @@
using UnityEngine;
using UnityEditor;
namespace Klak.Hap
{
[CanEditMultipleObjects]
[CustomEditor(typeof(HapPlayer))]
sealed class HapPlayerEditor : Editor
{
SerializedProperty _filePath;
SerializedProperty _pathMode;
SerializedProperty _time;
SerializedProperty _speed;
SerializedProperty _loop;
SerializedProperty _targetTexture;
SerializedProperty _flipHorizontal;
SerializedProperty _flipVertical;
static class Labels
{
public static readonly GUIContent Property = new GUIContent("Property");
public static readonly GUIContent Select = new GUIContent("Select");
}
string _sourceInfo;
void ShowSourceInfo(HapPlayer player)
{
if (!player.enabled || !player.gameObject.activeInHierarchy) return;
if (!player.isValid)
{
EditorGUILayout.HelpBox(
"Failed to open file. " +
"Please specify a valid HAP-encoded .mov file.",
MessageType.Warning
);
return;
}
if (_sourceInfo == null)
_sourceInfo = string.Format(
"Codec: {0}\n" +
"Frame dimensions: {1} x {2}\n" +
"Stream duration: {3:0.00}\n" +
"Frame rate: {4:0.00}",
player.codecType,
player.frameWidth, player.frameHeight,
player.streamDuration,
player.frameCount / player.streamDuration
);
EditorGUILayout.HelpBox(_sourceInfo, MessageType.None);
}
void OnEnable()
{
_filePath = serializedObject.FindProperty("_filePath");
_pathMode = serializedObject.FindProperty("_pathMode");
_time = serializedObject.FindProperty("_time");
_speed = serializedObject.FindProperty("_speed");
_loop = serializedObject.FindProperty("_loop");
_targetTexture = serializedObject.FindProperty("_targetTexture");
_flipHorizontal = serializedObject.FindProperty("_flipHorizontal");
_flipVertical = serializedObject.FindProperty("_flipVertical");
}
public override void OnInspectorGUI()
{
var reload = false;
serializedObject.Update();
// Source infomation
if (!_filePath.hasMultipleDifferentValues &&
!_pathMode.hasMultipleDifferentValues &&
!string.IsNullOrEmpty(_filePath.stringValue))
{
ShowSourceInfo((HapPlayer)target);
}
// Source file (드래그 앤 드롭 + 파일 브라우저)
EditorGUILayout.BeginHorizontal();
EditorGUI.BeginChangeCheck();
EditorGUILayout.DelayedTextField(_filePath);
if (GUILayout.Button("파일 선택", GUILayout.Width(80)))
{
string path = EditorUtility.OpenFilePanel("HAP MOV 파일 선택", Application.dataPath, "mov");
if (!string.IsNullOrEmpty(path))
{
string streamingPath = Application.streamingAssetsPath;
if (path.StartsWith(streamingPath))
path = path.Substring(streamingPath.Length + 1);
_filePath.stringValue = path;
}
}
EditorGUILayout.EndHorizontal();
if (EditorGUI.EndChangeCheck()) reload = true;
// 드래그 앤 드롭 지원
Rect dropRect = GUILayoutUtility.GetLastRect();
if (Event.current.type == EventType.DragUpdated || Event.current.type == EventType.DragPerform)
{
if (dropRect.Contains(Event.current.mousePosition))
{
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
if (Event.current.type == EventType.DragPerform)
{
DragAndDrop.AcceptDrag();
foreach (var dragged in DragAndDrop.paths)
{
if (dragged.ToLower().EndsWith(".mov"))
{
string path = dragged;
string streamingPath = Application.streamingAssetsPath;
if (path.StartsWith(streamingPath))
path = path.Substring(streamingPath.Length + 1);
_filePath.stringValue = path;
GUI.FocusControl(null);
reload = true;
break;
}
}
Event.current.Use();
}
}
}
// Playback control
EditorGUILayout.PropertyField(_time);
EditorGUILayout.PropertyField(_speed);
EditorGUILayout.PropertyField(_loop);
// Flip options
EditorGUILayout.Space();
EditorGUILayout.LabelField("Flip Options", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_flipHorizontal, new GUIContent("Flip Horizontal"));
EditorGUILayout.PropertyField(_flipVertical, new GUIContent("Flip Vertical"));
// Target texture
EditorGUILayout.PropertyField(_targetTexture);
serializedObject.ApplyModifiedProperties();
if (reload)
{
foreach (HapPlayer hp in targets)
{
hp.SendMessage("OnDestroy");
hp.SendMessage("LateUpdate");
}
_sourceInfo = null;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a374e606a0d24345b93bc348a6fbf54
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,16 @@
{
"name": "Klak.Hap.Editor",
"references": [
"Klak.Hap"
],
"optionalUnityReferences": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 26694ad9b328c7148a8fb73421baa7fe
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,87 @@
using UnityEngine;
using UnityEditor;
using System;
using System.Collections.Generic;
namespace Klak.Hap
{
static class MaterialPropertySelector
{
#region Public method
// Material property drop-down list
public static void DropdownList(
SerializedProperty rendererProperty,
SerializedProperty materialProperty
)
{
// Try retrieving the target shader.
var shader = RetrieveTargetShader(rendererProperty);
// Abandon the current value if it failed to get a shader.
if (shader == null)
{
materialProperty.stringValue = "";
return;
}
// Cache property names found in the target shader.
CachePropertyNames(shader);
// Abandon the current value if there is no property candidate.
if (_propertyNames.Length == 0)
{
materialProperty.stringValue = "";
return;
}
// Show the dropdown list.
var index = Array.IndexOf(_propertyNames, materialProperty.stringValue);
var newIndex = EditorGUILayout.Popup("Property", index, _propertyNames);
// Update the serialized property if the selection was changed.
if (index != newIndex) materialProperty.stringValue = _propertyNames[newIndex];
}
#endregion
#region Private members
static string[] _propertyNames; // Property name list
static Shader _cachedShader; // Shader used to cache the name list
// Retrieve a shader from a given renderer.
static Shader RetrieveTargetShader(SerializedProperty rendererProperty)
{
var renderer = rendererProperty.objectReferenceValue as Renderer;
if (renderer == null) return null;
var material = renderer.sharedMaterial;
if (material == null) return null;
return material.shader;
}
// Cache property names provided within a specified shader.
static void CachePropertyNames(Shader shader)
{
// Exit early when the shader is same to the cached one.
if (shader == _cachedShader) return;
var temp = new List<string>();
var count = ShaderUtil.GetPropertyCount(shader);
for (var i = 0; i < count; i++)
{
var propType = ShaderUtil.GetPropertyType(shader, i);
if (propType == ShaderUtil.ShaderPropertyType.TexEnv)
temp.Add(ShaderUtil.GetPropertyName(shader, i));
}
_propertyNames = temp.ToArray();
_cachedShader = shader;
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fe3e2d486287f2f40936cd00c558818d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,215 @@
License summary:
KlakHAP - MIT license
HAP codec - FreeBSD license
Snappy - BSD 3-clause license
MP4 demuxer - CC0 (public domain)
-------------------------------------------------------------------------------
KlakHAP
https://github.com/keijiro/KlakHap
-------------------------------------------------------------------------------
Copyright (c) 2019 Unity Technologies
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-------------------------------------------------------------------------------
HAP
https://github.com/Vidvox/hap
-------------------------------------------------------------------------------
Copyright (c) 2012-2013, Tom Butterworth and Vidvox LLC. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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.
-------------------------------------------------------------------------------
Snappy
https://github.com/google/snappy
-------------------------------------------------------------------------------
Copyright 2011, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"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 THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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.
-------------------------------------------------------------------------------
Minimalistic MP4 muxer & demuxer
https://github.com/aspt/mp4
-------------------------------------------------------------------------------
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: cafc978caabfcd84e8dc32d52b4f2b79
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dd3bd64373abe6d4bac999a0b5b69bcd
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 47a9aaa064c67514da9f5ff173be35fb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: 467f13044a0a9364795fef0b526e5eed
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
platformData:
- first:
'': Any
second:
enabled: 0
settings:
Exclude Editor: 0
Exclude Linux: 1
Exclude Linux64: 0
Exclude LinuxUniversal: 0
Exclude OSXUniversal: 1
Exclude Win: 0
Exclude Win64: 0
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: x86_64
DefaultValueInitialized: true
OS: Linux
- first:
Facebook: Win
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Facebook: Win64
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Linux
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Linux64
second:
enabled: 1
settings:
CPU: x86_64
- first:
Standalone: LinuxUniversal
second:
enabled: 1
settings:
CPU: x86_64
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win
second:
enabled: 1
settings:
CPU: AnyCPU
- first:
Standalone: Win64
second:
enabled: 1
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 93e3b14ab64306d4a85ce4feb6c9b2fd
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,73 @@
fileFormatVersion: 2
guid: 849058cd649269543a8d95c4703cf3d9
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Editor: 0
Exclude Linux64: 1
Exclude OSXUniversal: 0
Exclude Win: 1
Exclude Win64: 1
Exclude iOS: 1
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: OSX
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 1
settings:
CPU: AnyCPU
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: x86
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: x86_64
- first:
iPhone: iOS
second:
enabled: 0
settings:
AddToEmbeddedBinaries: false
CPU: AnyCPU
CompileFlags:
FrameworkDependencies:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: afcc650d93eee184aa34e7d62096bf27
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: e794ded0c0aa5a4449367e5b2b2d96ed
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
platformData:
- first:
'': Any
second:
enabled: 0
settings:
Exclude Editor: 0
Exclude Linux: 0
Exclude Linux64: 0
Exclude LinuxUniversal: 0
Exclude OSXUniversal: 0
Exclude Win: 1
Exclude Win64: 0
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: x86_64
DefaultValueInitialized: true
OS: Windows
- first:
Facebook: Win
second:
enabled: 0
settings:
CPU: None
- first:
Facebook: Win64
second:
enabled: 0
settings:
CPU: AnyCPU
- first:
Standalone: Linux
second:
enabled: 1
settings:
CPU: x86
- first:
Standalone: Linux64
second:
enabled: 1
settings:
CPU: x86_64
- first:
Standalone: LinuxUniversal
second:
enabled: 1
settings:
CPU: AnyCPU
- first:
Standalone: OSXUniversal
second:
enabled: 1
settings:
CPU: AnyCPU
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 1
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/External/Hap Player/jp.keijiro.klak.hap@9a47acf6295e/README.md (Stored with Git LFS) vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 76ac0e324de156547a580e86fdd8ea2f
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2b78bdcad9737cf48a8f9b23254b7f84
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,57 @@
Shader "Klak/HAP"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
CGINCLUDE
#include "UnityCG.cginc"
struct Attributes
{
float4 position : POSITION;
float2 texcoord : TEXCOORD;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 position : SV_Position;
float2 texcoord : TEXCOORD;
};
sampler2D _MainTex;
float4 _MainTex_ST;
Varyings Vertex(Attributes input)
{
UNITY_SETUP_INSTANCE_ID(input);
Varyings output;
output.position = UnityObjectToClipPos(input.position);
output.texcoord = TRANSFORM_TEX(input.texcoord, _MainTex);
output.texcoord.y = 1 - output.texcoord.y;
return output;
}
fixed4 Fragment(Varyings input) : SV_Target
{
return tex2D(_MainTex, input.texcoord);
}
ENDCG
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma vertex Vertex
#pragma fragment Fragment
#pragma multi_compile_instancing
ENDCG
}
}
}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 49f216cf9a0966d4493e7ba1af11c3d6
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,59 @@
Shader "Klak/HAP Alpha"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
CGINCLUDE
#include "UnityCG.cginc"
struct Attributes
{
float4 position : POSITION;
float2 texcoord : TEXCOORD;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 position : SV_Position;
float2 texcoord : TEXCOORD;
};
sampler2D _MainTex;
float4 _MainTex_ST;
Varyings Vertex(Attributes input)
{
UNITY_SETUP_INSTANCE_ID(input);
Varyings output;
output.position = UnityObjectToClipPos(input.position);
output.texcoord = TRANSFORM_TEX(input.texcoord, _MainTex);
output.texcoord.y = 1 - output.texcoord.y;
return output;
}
fixed4 Fragment(Varyings input) : SV_Target
{
return tex2D(_MainTex, input.texcoord);
}
ENDCG
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex Vertex
#pragma fragment Fragment
#pragma multi_compile_instancing
ENDCG
}
}
}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 90b82a87346a5254286d43f76863782c
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,72 @@
Shader "Klak/HAP Q"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
CGINCLUDE
#include "UnityCG.cginc"
struct Attributes
{
float4 position : POSITION;
float2 texcoord : TEXCOORD;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 position : SV_Position;
float2 texcoord : TEXCOORD;
};
sampler2D _MainTex;
float4 _MainTex_ST;
half3 CoCgSY2RGB(half4 i)
{
#if !defined(UNITY_COLORSPACE_GAMMA)
i.xyz = LinearToGammaSpace(i.xyz);
#endif
i.xy -= half2(0.50196078431373, 0.50196078431373);
half s = 1 / ((i.z * (255.0 / 8)) + 1);
half3 rgb = half3(i.x - i.y, i.y, -i.x - i.y) * s + i.w;
#if !defined(UNITY_COLORSPACE_GAMMA)
rgb = GammaToLinearSpace(rgb);
#endif
return rgb;
}
Varyings Vertex(Attributes input)
{
UNITY_SETUP_INSTANCE_ID(input);
Varyings output;
output.position = UnityObjectToClipPos(input.position);
output.texcoord = TRANSFORM_TEX(input.texcoord, _MainTex);
output.texcoord.y = 1 - output.texcoord.y;
return output;
}
fixed4 Fragment(Varyings input) : SV_Target
{
return fixed4(CoCgSY2RGB(tex2D(_MainTex, input.texcoord)), 1);
}
ENDCG
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma multi_compile _ UNITY_COLORSPACE_GAMMA
#pragma vertex Vertex
#pragma fragment Fragment
#pragma multi_compile_instancing
ENDCG
}
}
}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 807e261a8905cde469501ab123338e05
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3a1ee959e394fc54bb43e56fdae7a146
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,4 @@
namespace Klak.Hap
{
public enum CodecType { Unsupported, Hap, HapQ, HapAlpha }
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec81190dde6b4d24fb7fdb8f562fccbe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,45 @@
Shader "Hidden/FlipBlit"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_FlipX ("Flip X", Float) = 0
_FlipY ("Flip Y", Float) = 0
}
SubShader
{
Pass
{
ZTest Always Cull Off ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
float _FlipX;
float _FlipY;
struct appdata_t { float4 vertex : POSITION; float2 uv : TEXCOORD0; };
struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; };
v2f vert (appdata_t v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float2 uv = i.uv;
if (_FlipX > 0.5) uv.x = 1.0 - uv.x;
if (_FlipY > 0.5) uv.y = 1.0 - uv.y;
return tex2D(_MainTex, uv);
}
ENDCG
}
}
}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 83fc09b934829ee489c1947480fcc03e
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,339 @@
using UnityEngine;
using UnityEngine.Playables;
#if KLAKHAP_HAS_TIMELINE
using UnityEngine.Timeline;
#endif
namespace Klak.Hap
{
[ExecuteInEditMode, AddComponentMenu("Klak/HAP/HAP Player")]
#if KLAKHAP_HAS_TIMELINE
public sealed class HapPlayer : MonoBehaviour , ITimeControl, IPropertyPreview
#else
public sealed class HapPlayer : MonoBehaviour
#endif
{
#region Editable attributes
public enum PathMode { StreamingAssets, LocalFileSystem }
[SerializeField] PathMode _pathMode = PathMode.StreamingAssets;
[SerializeField] string _filePath = "";
[SerializeField] float _time = 0;
[SerializeField, Range(-10, 10)] float _speed = 1;
[SerializeField] bool _loop = true;
[SerializeField] RenderTexture _targetTexture = null;
[SerializeField] string _targetMaterialProperty = "_MainTex";
[SerializeField] bool _flipHorizontal = false;
[SerializeField] bool _flipVertical = true;
#endregion
#region Public properties
public float time {
get { return _time; }
set { _time = value; }
}
public float speed {
get { return _speed; }
set { _speed = value; }
}
public bool loop {
get { return _loop; }
set { _loop = value; }
}
public RenderTexture targetTexture {
get { return _targetTexture; }
set { _targetTexture = value; }
}
public string targetMaterialProperty {
get { return _targetMaterialProperty; }
set { _targetMaterialProperty = value; }
}
public bool flipHorizontal {
get { return _flipHorizontal; }
set { _flipHorizontal = value; }
}
public bool flipVertical {
get { return _flipVertical; }
set { _flipVertical = value; }
}
#endregion
#region Read-only properties
public bool isValid { get { return _demuxer != null; } }
public int frameWidth { get { return _demuxer?.Width ?? 0; } }
public int frameHeight { get { return _demuxer?.Height ?? 0; } }
public int frameCount { get { return _demuxer?.FrameCount ?? 0; } }
public double streamDuration { get { return _demuxer?.Duration ?? 0; } }
public CodecType codecType { get {
return Utility.DetermineCodecType(_demuxer?.VideoType ?? 0);
} }
public string resolvedFilePath { get {
if (_pathMode == PathMode.StreamingAssets)
return System.IO.Path.Combine(Application.streamingAssetsPath, _filePath);
else
return _filePath;
} }
public Texture2D texture { get { return _texture; } }
#endregion
#region Public methods
public void Open(string filePath, PathMode pathMode = PathMode.StreamingAssets)
{
if (_demuxer != null)
{
Debug.LogError("Stream has already been opened.");
return;
}
_filePath = filePath;
_pathMode = pathMode;
OpenInternal();
}
public void UpdateNow()
=> LateUpdate();
#endregion
#region Private members
Demuxer _demuxer;
StreamReader _stream;
Decoder _decoder;
Texture2D _texture;
TextureUpdater _updater;
float _storedTime;
float _storedSpeed;
// Flip-related variables
Material _flipMaterial;
void OpenInternal()
{
// Demuxer instantiation
_demuxer = new Demuxer(resolvedFilePath);
if (!_demuxer.IsValid)
{
if (Application.isPlaying)
{
Debug.LogError("Failed to open stream (" + resolvedFilePath + ").");
enabled = false;
}
_demuxer.Dispose();
_demuxer = null;
return;
}
_stream = new StreamReader(_demuxer, _time, _speed / 60);
(_storedTime, _storedSpeed) = (_time, _speed);
_decoder = new Decoder(
_stream, _demuxer.Width, _demuxer.Height, _demuxer.VideoType
);
_texture = new Texture2D(
_demuxer.Width, _demuxer.Height,
Utility.DetermineTextureFormat(_demuxer.VideoType), false
);
_texture.wrapMode = TextureWrapMode.Clamp;
_texture.hideFlags = HideFlags.DontSave;
_updater = new TextureUpdater(_texture, _decoder);
}
void UpdateTargetTexture()
{
if (_targetTexture == null || _texture == null || _demuxer == null) return;
if (this == null || !enabled) return;
if (_flipMaterial == null)
{
_flipMaterial = new Material(Shader.Find("Hidden/FlipBlit"));
_flipMaterial.hideFlags = HideFlags.DontSave;
}
_flipMaterial.SetFloat("_FlipX", _flipHorizontal ? 1f : 0f);
_flipMaterial.SetFloat("_FlipY", _flipVertical ? 1f : 0f);
try
{
Graphics.Blit(_texture, _targetTexture, _flipMaterial);
}
catch (System.NullReferenceException)
{
return;
}
}
#endregion
#region ITimeControl implementation
bool _externalTime;
public void OnControlTimeStart()
{
_externalTime = true;
// In the external time mode, we can't know the actual playback
// speed but sure that it's positive (Control Track doesn't support
// reverse playback), so we assume that the speed is 1.0.
// Cons: Resync could happen every frame for high speed play back.
_speed = 1;
}
public void OnControlTimeStop()
{
_externalTime = false;
}
public void SetTime(double time)
{
_time = (float)time;
_speed = 1;
}
#endregion
#region IPropertyPreview implementation
#if KLAKHAP_HAS_TIMELINE
public void GatherProperties(PlayableDirector director, IPropertyCollector driver)
{
driver.AddFromName<HapPlayer>(gameObject, "_time");
}
#endif
#endregion
#region MonoBehaviour implementation
void OnDestroy()
{
if (_updater != null)
{
_updater.Dispose();
_updater = null;
}
if (_decoder != null)
{
_decoder.Dispose();
_decoder = null;
}
if (_stream != null)
{
_stream.Dispose();
_stream = null;
}
if (_demuxer != null)
{
_demuxer.Dispose();
_demuxer = null;
}
Utility.Destroy(_texture);
Utility.Destroy(_flipMaterial);
}
#if UNITY_EDITOR
void OnValidate()
{
// 더 이상 필요 없음: 렌더러 관련 클리어 코드 제거
}
#endif
int _lastUpdateFrameCount = -1;
void LateUpdate()
{
if (!enabled || this == null) return;
if (Time.frameCount == _lastUpdateFrameCount) return;
_lastUpdateFrameCount = Time.frameCount;
if (_demuxer == null && !string.IsNullOrEmpty(_filePath))
OpenInternal();
if (_demuxer == null) return;
var duration = (float)_demuxer.Duration;
var dt = duration / _demuxer.FrameCount;
var resync = _time < _storedTime || _time > _storedTime + dt;
if (_speed != _storedSpeed)
{
resync = true;
_storedSpeed = _speed;
}
var t = _loop ? _time : Mathf.Clamp(_time, 0, duration - 1e-4f);
var bgdec = !resync && Application.isPlaying;
if (resync && _stream != null) _stream.Restart(t, _speed / 60);
if (_decoder != null && _updater != null)
{
if (TextureUpdater.AsyncSupport)
{
if (bgdec) _decoder.UpdateAsync(t); else _decoder.UpdateSync(t);
_updater.RequestAsyncUpdate();
}
#if !HAP_NO_DELAY
else if (bgdec)
{
_updater.UpdateNow();
_decoder.UpdateAsync(t);
}
#endif
else
{
_decoder.UpdateSync(t);
_updater.UpdateNow();
}
}
if (Application.isPlaying && !_externalTime)
_time += Time.deltaTime * _speed;
_storedTime = _time;
// 렌더 텍스처만 업데이트
if (this != null && enabled)
{
try
{
if (_targetTexture != null)
UpdateTargetTexture();
}
catch (System.NullReferenceException ex)
{
Debug.LogWarning($"HapPlayer: Null reference in external object updates - {ex.Message}");
}
catch (System.Exception ex)
{
Debug.LogWarning($"HapPlayer: Unexpected error in external object updates - {ex.Message}");
}
}
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b8ea76979ef31fb42882178890076b16
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9826f2ed5102c594db39cb240eb1a004
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,146 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace Klak.Hap
{
internal sealed class Decoder : IDisposable
{
#region Initialization/finalization
public Decoder(StreamReader stream, int width, int height, int videoType)
{
_stream = stream;
// Plugin initialization
_plugin = KlakHap_CreateDecoder(width, height, videoType);
_id = ++_instantiationCount;
KlakHap_AssignDecoder(_id, _plugin);
// By default, start from the first frame.
_time = 0;
// Decoder thread startup
_resume.req = new AutoResetEvent(true);
_resume.ack = new AutoResetEvent(false);
_thread = new Thread(DecoderThread);
_thread.Start();
}
public void Dispose()
{
if (_thread != null)
{
_terminate = true;
_resume.req.Set();
_thread.Join();
_thread = null;
}
if (_plugin != IntPtr.Zero)
{
KlakHap_AssignDecoder(_id, IntPtr.Zero);
KlakHap_DestroyDecoder(_plugin);
_plugin = IntPtr.Zero;
}
}
#endregion
#region Public members
public uint CallbackID { get { return _id; } }
public int BufferSize { get {
return KlakHap_GetDecoderBufferSize(_plugin);
} }
public void UpdateSync(float time)
{
_time = time;
var buffer = _stream.Advance(_time);
if (buffer != null)
KlakHap_DecodeFrame(_plugin, buffer.PluginPointer);
}
public void UpdateAsync(float time)
{
_time = time;
_resume.req.Set();
_resume.ack.WaitOne();
}
public IntPtr LockBuffer()
{
return KlakHap_LockDecoderBuffer(_plugin);
}
public void UnlockBuffer()
{
KlakHap_UnlockDecoderBuffer(_plugin);
}
#endregion
#region Private members
static uint _instantiationCount;
IntPtr _plugin;
uint _id;
Thread _thread;
(AutoResetEvent req, AutoResetEvent ack) _resume;
bool _terminate;
StreamReader _stream;
float _time;
#endregion
#region Thread function
void DecoderThread()
{
while (true)
{
_resume.req.WaitOne();
_resume.ack.Set();
if (_terminate) break;
var buffer = _stream.Advance(_time);
if (buffer == null) continue;
KlakHap_DecodeFrame(_plugin, buffer.PluginPointer);
}
}
#endregion
#region Native plugin entry points
[DllImport("KlakHap")]
internal static extern IntPtr KlakHap_CreateDecoder(int width, int height, int typeID);
[DllImport("KlakHap")]
internal static extern void KlakHap_DestroyDecoder(IntPtr decoder);
[DllImport("KlakHap")]
internal static extern void KlakHap_AssignDecoder(uint id, IntPtr decoder);
[DllImport("KlakHap")]
internal static extern void KlakHap_DecodeFrame(IntPtr decoder, IntPtr input);
[DllImport("KlakHap")]
internal static extern IntPtr KlakHap_LockDecoderBuffer(IntPtr decoder);
[DllImport("KlakHap")]
internal static extern void KlakHap_UnlockDecoderBuffer(IntPtr decoder);
[DllImport("KlakHap")]
internal static extern int KlakHap_GetDecoderBufferSize(IntPtr decoder);
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb63cbce06802f644820b09291d8dfb0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,103 @@
using System;
using System.Runtime.InteropServices;
namespace Klak.Hap
{
internal sealed class Demuxer : IDisposable
{
#region Public properties
public bool IsValid { get { return _plugin != IntPtr.Zero; } }
public int Width { get { return _width; } }
public int Height { get { return _height; } }
public int VideoType { get { return _videoType; } }
public double Duration { get { return _duration; } }
public int FrameCount { get { return _frameCount; } }
#endregion
#region Initialization/finalization
public Demuxer(string filePath)
{
_plugin = KlakHap_OpenDemuxer(filePath);
if (KlakHap_DemuxerIsValid(_plugin) == 0)
{
// Instantiation failed; Close and stop.
KlakHap_CloseDemuxer(_plugin);
_plugin = IntPtr.Zero;
return;
}
// Video properties
_width = KlakHap_GetVideoWidth(_plugin);
_height = KlakHap_GetVideoHeight(_plugin);
_videoType = KlakHap_AnalyzeVideoType(_plugin);
_duration = KlakHap_GetDuration(_plugin);
_frameCount = KlakHap_CountFrames(_plugin);
}
public void Dispose()
{
if (_plugin != IntPtr.Zero)
{
KlakHap_CloseDemuxer(_plugin);
_plugin = IntPtr.Zero;
}
}
#endregion
#region Public methods
public void ReadFrame(ReadBuffer buffer, int index, float time)
{
KlakHap_ReadFrame(_plugin, index, buffer.PluginPointer);
buffer.Index = index;
buffer.Time = time;
}
#endregion
#region Private members
IntPtr _plugin;
int _width, _height, _videoType;
double _duration;
int _frameCount;
#endregion
#region Native plugin entry points
[DllImport("KlakHap")]
internal static extern IntPtr KlakHap_OpenDemuxer(string filepath);
[DllImport("KlakHap")]
internal static extern void KlakHap_CloseDemuxer(IntPtr demuxer);
[DllImport("KlakHap")]
internal static extern int KlakHap_DemuxerIsValid(IntPtr demuxer);
[DllImport("KlakHap")]
internal static extern int KlakHap_CountFrames(IntPtr demuxer);
[DllImport("KlakHap")]
internal static extern double KlakHap_GetDuration(IntPtr demuxer);
[DllImport("KlakHap")]
internal static extern int KlakHap_GetVideoWidth(IntPtr demuxer);
[DllImport("KlakHap")]
internal static extern int KlakHap_GetVideoHeight(IntPtr demuxer);
[DllImport("KlakHap")]
internal static extern int KlakHap_AnalyzeVideoType(IntPtr demuxer);
[DllImport("KlakHap")]
internal static extern void KlakHap_ReadFrame(IntPtr demuxer, int frameNumber, IntPtr buffer);
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 01e2f3e55fcbb10448e3b4976da8097d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,48 @@
using System;
using System.Runtime.InteropServices;
namespace Klak.Hap
{
internal sealed class ReadBuffer : IDisposable
{
#region Initialization/finalization
public IntPtr PluginPointer { get { return _plugin; } }
public int Index { get; set; }
public float Time { get; set; }
#endregion
#region Initialization/finalization
public ReadBuffer()
{
_plugin = KlakHap_CreateReadBuffer();
Index = Int32.MaxValue;
Time = Single.MaxValue;
}
public void Dispose()
{
KlakHap_DestroyReadBuffer(_plugin);
}
#endregion
#region Private members
IntPtr _plugin;
#endregion
#region Native plugin entry points
[DllImport("KlakHap")]
internal static extern IntPtr KlakHap_CreateReadBuffer();
[DllImport("KlakHap")]
internal static extern void KlakHap_DestroyReadBuffer(IntPtr buffer);
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4489c695e7711e44bbe985cac12755c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,266 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
namespace Klak.Hap
{
internal sealed class StreamReader : IDisposable
{
#region Public methods
public StreamReader(Demuxer demuxer, float time, float delta)
{
_demuxer = demuxer;
_leadQueue = new Queue<ReadBuffer>();
_freeBuffers = new List<ReadBuffer>();
// Initial buffer entry allocation
_freeBuffers.Add(new ReadBuffer());
_freeBuffers.Add(new ReadBuffer());
_freeBuffers.Add(new ReadBuffer());
_freeBuffers.Add(new ReadBuffer());
// Initial playback settings
_restart = (time, SafeDelta(delta));
// Reader thread startup
_updateEvent = new AutoResetEvent(true);
_readEvent = new AutoResetEvent(false);
_thread = new Thread(ReaderThread);
_thread.Start();
}
public void Dispose()
{
if (_thread != null)
{
_terminate = true;
_updateEvent.Set();
_thread.Join();
_thread = null;
}
if (_updateEvent != null)
{
_updateEvent.Dispose();
_updateEvent = null;
}
if (_readEvent != null)
{
_readEvent.Dispose();
_readEvent = null;
}
if (_current != null)
{
_current.Dispose();
_current = null;
}
if (_leadQueue != null)
{
foreach (var rb in _leadQueue) rb.Dispose();
_leadQueue.Clear();
_leadQueue = null;
}
if (_freeBuffers != null)
{
foreach (var rb in _freeBuffers) rb.Dispose();
_freeBuffers.Clear();
_freeBuffers = null;
}
}
public void Restart(float time, float delta)
{
// Restart request
lock (_restartLock) _restart = (time, SafeDelta(delta));
// Wait for reset/read on the reader thread.
_readEvent.Reset();
while (_restart != null)
{
_updateEvent.Set();
_readEvent.WaitOne();
}
}
public ReadBuffer Advance(float time)
{
// Add an epsilon-ish value to avoid rounding error.
time += 1e-6f;
var changed = false;
// There is no slow path in this function, so we prefer holding
// the queue lock for the entire function block rather than
// acquiring/releasing it for each operation.
lock (_queueLock)
{
// Scan the lead queue.
while (_leadQueue.Count > 0)
{
var peek = _leadQueue.Peek();
if (_current != null)
{
if (_current.Time <= peek.Time)
{
// Forward playback case:
// Break if it hasn't reached the next frame.
if (time < peek.Time) break;
}
else
{
// Reverse playback case:
// Break if it's still on the current frame.
if (_current.Time < time) break;
}
// Free the current frame before replacing it.
_freeBuffers.Add(_current);
}
_current = _leadQueue.Dequeue();
changed = true;
}
}
// Poke the reader thread.
_updateEvent.Set();
// Only returns a buffer object when the frame was changed.
return changed ? _current : null;
}
#endregion
#region Private members
// Assigned demuxer
Demuxer _demuxer;
// Thread and synchronization objects
Thread _thread;
AutoResetEvent _updateEvent;
AutoResetEvent _readEvent;
bool _terminate;
// Read buffer objects
ReadBuffer _current;
Queue<ReadBuffer> _leadQueue;
List<ReadBuffer> _freeBuffers;
readonly object _queueLock = new object();
// Restart request
(float, float)? _restart;
readonly object _restartLock = new object();
// Used to avoid too small delta time values.
float SafeDelta(float delta)
{
var min = (float)(_demuxer.Duration / _demuxer.FrameCount);
return Math.Max(Math.Abs(delta), min) * (delta < 0 ? -1 : 1);
}
#endregion
#region Thread function
void ReaderThread()
{
// Initial time settings from the restart request tuple
var (time, delta) = _restart.Value;
_restart = null;
// Stream attributes
var totalTime = _demuxer.Duration;
var totalFrames = _demuxer.FrameCount;
while (true)
{
// Synchronization with the parent thread
_updateEvent.WaitOne();
if (_terminate) break;
// Check if there is a restart request.
lock (_restartLock) if (_restart != null)
{
// Flush out the current contents of the lead queue.
lock (_queueLock) while (_leadQueue.Count > 0)
_freeBuffers.Add(_leadQueue.Dequeue());
// Apply the restart request.
(time, delta) = _restart.Value;
_restart = null;
}
// Time -> Frame count
// Rounding strategy: We don't prefer Math.Round because it can
// show a frame before the playhead reaches it (especially when
// using slow-mo). On the other hand, Math.Floor causes frame
// skipping due to rounding errors. To avoid these problems,
// we use the "adding a very-very small fractional frame"
// approach. 1/1000 might be safe and enough for all the cases.
var frameCount = (int)(time * totalFrames / totalTime + 1e-3f);
// Frame count -> Frame snapped time
var snappedTime = (float)(frameCount * totalTime / totalFrames);
// Frame count -> Wrapped frame number
var frameNumber = frameCount % totalFrames;
if (frameNumber < 0) frameNumber += totalFrames;
lock (_queueLock)
{
// Do nothing if there is no free buffer; It indicates that
// the lead queue is fully filled.
if (_freeBuffers.Count == 0) continue;
ReadBuffer buffer = null;
// Look for a free buffer that has the same frame number.
foreach (var temp in _freeBuffers)
{
if (temp.Index == frameNumber)
{
buffer = temp;
break;
}
}
if (buffer != null)
{
// Reuse the found buffer; Although we can use it
// without reading frame data, the time field should
// be updated to handle wrapping-around hits.
_freeBuffers.Remove(buffer);
buffer.Time = snappedTime;
}
else
{
// Allocate a buffer from the free buffer list.
buffer = _freeBuffers[_freeBuffers.Count - 1];
_freeBuffers.RemoveAt(_freeBuffers.Count - 1);
// Frame data read
_demuxer.ReadFrame(buffer, frameNumber, snappedTime);
}
// Push the buffer to the lead queue.
_leadQueue.Enqueue(buffer);
}
_readEvent.Set();
time += delta;
}
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a5b51807ae8c7e749b98a930666f136b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,77 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Rendering;
namespace Klak.Hap
{
internal sealed class TextureUpdater : IDisposable
{
#region Public properties
public static bool AsyncSupport { get {
return SystemInfo.graphicsDeviceType == GraphicsDeviceType.Direct3D11;
} }
#endregion
#region Public methods
public TextureUpdater(Texture2D texture, Decoder decoder)
{
_texture = texture;
_decoder = decoder;
if (AsyncSupport)
{
_command = new CommandBuffer();
_command.name = "Klak HAP";
_command.IssuePluginCustomTextureUpdateV2(
KlakHap_GetTextureUpdateCallback(),
texture, decoder.CallbackID
);
}
}
public void Dispose()
{
if (_command != null)
{
_command.Dispose();
_command = null;
}
}
public void UpdateNow()
{
_texture.LoadRawTextureData(
_decoder.LockBuffer(),
_decoder.BufferSize
);
_texture.Apply();
_decoder.UnlockBuffer();
}
public void RequestAsyncUpdate()
{
if (_command != null) Graphics.ExecuteCommandBuffer(_command);
}
#endregion
#region Private fields
Texture2D _texture;
Decoder _decoder;
CommandBuffer _command;
#endregion
#region Native plugin entry points
[DllImport("KlakHap")]
internal static extern IntPtr KlakHap_GetTextureUpdateCallback();
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 430fee5c2bdcf0c4492d6b8d742439f8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,48 @@
using UnityEngine;
namespace Klak.Hap
{
internal static class Utility
{
public static void Destroy(Object o)
{
if (o == null) return;
if (Application.isPlaying)
Object.Destroy(o);
else
Object.DestroyImmediate(o);
}
public static CodecType DetermineCodecType(int videoType)
{
switch (videoType & 0xf)
{
case 0xb: return CodecType.Hap;
case 0xe: return CodecType.HapAlpha;
case 0xf: return CodecType.HapQ;
}
return CodecType.Unsupported;
}
public static TextureFormat DetermineTextureFormat(int videoType)
{
switch (videoType & 0xf)
{
case 0xb: return TextureFormat.DXT1;
case 0xe: return TextureFormat.DXT5;
case 0xf: return TextureFormat.DXT5;
case 0xc: return TextureFormat.BC7;
case 0x1: return TextureFormat.BC4;
}
return TextureFormat.DXT1;
}
public static Shader DetermineBlitShader(int videoType)
{
if ((videoType & 0xf) == 0xf)
return Shader.Find("Klak/HAP Q");
else
return Shader.Find("Klak/HAP");
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f6abcc4e09417604ca245a0c5a5a1f0c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,21 @@
{
"name": "Klak.Hap",
"references": [
"GUID:f06555f75b070af458a003d92f9efb00"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.unity.timeline",
"expression": "1.0.0",
"define": "KLAKHAP_HAS_TIMELINE"
}
],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d30a992d73d108f4eaaafff3ed9490e3
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/External/Hap Player/jp.keijiro.klak.hap@9a47acf6295e/package.json (Stored with Git LFS) vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 52bab5075038b8c46ac3f7bb51b068b2
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 49e2cc8b12f20664080fc8178c8a8098
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: b8d6350aa7a54634d93678cf9e338599
folderAsset: yes
timeCreated: 1492007252
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,17 @@
{
"name": "Klak.Spout.Editor",
"references": [
"Klak.Spout.Runtime"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 21435214e6169c649985b5540a63188a
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,85 @@
using UnityEngine;
using UnityEditor;
using System.Linq;
namespace Klak.Spout.Editor {
static class MaterialPropertySelector
{
#region Public method
// Material property dropdown list
public static void DropdownList
(SerializedProperty rendererProperty,
SerializedProperty materialProperty)
{
var shader = GetShaderFromRenderer(rendererProperty);
// Abandon the current value if there is no shader assignment.
if (shader == null)
{
materialProperty.stringValue = "";
return;
}
var names = CachePropertyNames(shader);
// Abandon the current value if there is no option.
if (names.Length == 0)
{
materialProperty.stringValue = "";
return;
}
// Dropdown GUI
var index = System.Array.IndexOf(names, materialProperty.stringValue);
var newIndex = EditorGUILayout.Popup("Property", index, names);
if (index != newIndex) materialProperty.stringValue = names[newIndex];
}
#endregion
#region Utility function
// Shader retrieval function
static Shader GetShaderFromRenderer(SerializedProperty property)
{
var renderer = property.objectReferenceValue as Renderer;
if (renderer == null) return null;
var material = renderer.sharedMaterial;
if (material == null) return null;
return material.shader;
}
#endregion
#region Property name cache
static Shader _cachedShader;
static string[] _cachedPropertyNames;
static bool IsPropertyTexture(Shader shader, int index)
=> ShaderUtil.GetPropertyType(shader, index) ==
ShaderUtil.ShaderPropertyType.TexEnv;
static string[] CachePropertyNames(Shader shader)
{
if (shader == _cachedShader) return _cachedPropertyNames;
var names =
Enumerable.Range(0, ShaderUtil.GetPropertyCount(shader))
.Where(i => IsPropertyTexture(shader, i))
.Select(i => ShaderUtil.GetPropertyName(shader, i));
_cachedShader = shader;
_cachedPropertyNames = names.ToArray();
return _cachedPropertyNames;
}
#endregion
}
} // namespace Klak.Spout.Editor

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 26d68abfa1fecd14a800e4473714aef8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,115 @@
using UnityEngine;
using UnityEditor;
namespace Klak.Spout.Editor {
[CanEditMultipleObjects]
[CustomEditor(typeof(SpoutReceiver))]
sealed class SpoutReceiverEditor : UnityEditor.Editor
{
SerializedProperty _sourceName;
SerializedProperty _targetTexture;
SerializedProperty _targetRenderer;
SerializedProperty _targetMaterialProperty;
static class Labels
{
public static Label Property = "Property";
public static Label Select = "Select";
}
// Create and show the source name dropdown.
void ShowSourceNameDropdown(Rect rect)
{
var menu = new GenericMenu();
var sources = SpoutManager.GetSourceNames();
if (sources.Length > 0)
{
foreach (var name in sources)
menu.AddItem(new GUIContent(name), false, OnSelectSource, name);
}
else
{
menu.AddItem(new GUIContent("No source available"), false, null);
}
menu.DropDown(rect);
}
// Source name selection callback
void OnSelectSource(object nameObject)
{
var name = (string)nameObject;
serializedObject.Update();
_sourceName.stringValue = name;
serializedObject.ApplyModifiedProperties();
RequestRestart();
}
// Receiver restart request
void RequestRestart()
{
// Dirty trick: We only can restart receivers by modifying the
// sourceName property, so we modify it by an invalid name, then
// revert it.
foreach (SpoutReceiver recv in targets)
{
recv.sourceName = "";
recv.sourceName = _sourceName.stringValue;
}
}
void OnEnable()
{
var finder = new PropertyFinder(serializedObject);
_sourceName = finder["_sourceName"];
_targetTexture = finder["_targetTexture"];
_targetRenderer = finder["_targetRenderer"];
_targetMaterialProperty = finder["_targetMaterialProperty"];
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.BeginHorizontal();
// Source name text field
EditorGUI.BeginChangeCheck();
EditorGUILayout.DelayedTextField(_sourceName);
var restart = EditorGUI.EndChangeCheck();
// Source name dropdown
var rect = EditorGUILayout.GetControlRect(false, GUILayout.Width(60));
if (EditorGUI.DropdownButton(rect, Labels.Select, FocusType.Keyboard))
ShowSourceNameDropdown(rect);
EditorGUILayout.EndHorizontal();
// Target texture/renderer
EditorGUILayout.PropertyField(_targetTexture);
EditorGUILayout.PropertyField(_targetRenderer);
EditorGUI.indentLevel++;
if (_targetRenderer.hasMultipleDifferentValues)
{
// Multiple renderers selected: Show a simple text field.
EditorGUILayout.PropertyField(_targetMaterialProperty, Labels.Property);
}
else if (_targetRenderer.objectReferenceValue != null)
{
// Single renderer: Show the material property selection dropdown.
MaterialPropertySelector.DropdownList(_targetRenderer, _targetMaterialProperty);
}
EditorGUI.indentLevel--;
serializedObject.ApplyModifiedProperties();
if (restart) RequestRestart();
}
}
} // namespace Klak.Spout.Editor

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e66c46a000456b34e95a2661f5d5391b
timeCreated: 1492008499
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,15 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 12527eb854f97c84cac3b04dc699db09, type: 3}
m_Name: SpoutResources
m_EditorClassIdentifier:
blitShader: {fileID: 4800000, guid: eb56c59e60b76874692c486f3bdd860d, type: 3}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f449ebbe2051c2e4d993eaa773a410de
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,73 @@
using UnityEngine;
using UnityEditor;
namespace Klak.Spout.Editor {
[CanEditMultipleObjects]
[CustomEditor(typeof(SpoutSender))]
sealed class SpoutSenderEditor : UnityEditor.Editor
{
SerializedProperty _spoutName;
SerializedProperty _keepAlpha;
SerializedProperty _captureMethod;
SerializedProperty _sourceCamera;
SerializedProperty _sourceTexture;
static class Labels
{
public static Label SpoutName = "Spout Name";
}
// Sender restart request
void RequestRestart()
{
// Dirty trick: We only can restart senders by modifying the
// spoutName property, so we modify it by an invalid name, then
// revert it.
foreach (SpoutSender send in targets)
{
send.spoutName = "";
send.spoutName = _spoutName.stringValue;
}
}
void OnEnable()
{
var finder = new PropertyFinder(serializedObject);
_spoutName = finder["_spoutName"];
_keepAlpha = finder["_keepAlpha"];
_captureMethod = finder["_captureMethod"];
_sourceCamera = finder["_sourceCamera"];
_sourceTexture = finder["_sourceTexture"];
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUI.BeginChangeCheck();
EditorGUILayout.DelayedTextField(_spoutName, Labels.SpoutName);
var restart = EditorGUI.EndChangeCheck();
EditorGUILayout.PropertyField(_keepAlpha);
EditorGUILayout.PropertyField(_captureMethod);
EditorGUI.indentLevel++;
if (_captureMethod.hasMultipleDifferentValues ||
_captureMethod.enumValueIndex == (int)CaptureMethod.Camera)
EditorGUILayout.PropertyField(_sourceCamera);
if (_captureMethod.hasMultipleDifferentValues ||
_captureMethod.enumValueIndex == (int)CaptureMethod.Texture)
EditorGUILayout.PropertyField(_sourceTexture);
EditorGUI.indentLevel--;
serializedObject.ApplyModifiedProperties();
if (restart) RequestRestart();
}
}
} // namespace Klak.Spout.Editor

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b452d1bad3a57344d9b54f2cea6f252c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,30 @@
using UnityEngine;
using UnityEditor;
namespace Klak.Spout.Editor {
// Simple string label with GUIContent
struct Label
{
GUIContent _guiContent;
public static implicit operator GUIContent(Label label)
=> label._guiContent;
public static implicit operator Label(string text)
=> new Label { _guiContent = new GUIContent(text) };
}
// Utilities for finding serialized properties
struct PropertyFinder
{
SerializedObject _so;
public PropertyFinder(SerializedObject so)
=> _so = so;
public SerializedProperty this[string name]
=> _so.FindProperty(name);
}
} // namespace Klak.Spout.Editor

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b0cafe26b1cd89b4ca76bb015cfd16d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b6f63dbd21960c44aaa8fe4a6d55ad3e
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 52a684d8086688f419f6ae65f667fdd3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/External/Hap Player/jp.keijiro.klak.spout/Plugin/KlakSpout.dll (Stored with Git LFS) vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,63 @@
fileFormatVersion: 2
guid: dc935766d7c9fd44181cb4b58ef3627e
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Editor: 0
Exclude Linux64: 0
Exclude OSXUniversal: 0
Exclude Win: 1
Exclude Win64: 0
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: x86_64
DefaultValueInitialized: true
OS: Windows
- first:
Standalone: Linux64
second:
enabled: 1
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 1
settings:
CPU: None
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 1
settings:
CPU: x86_64
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/External/Hap Player/jp.keijiro.klak.spout/README.md (Stored with Git LFS) vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: bfad8b30f2b4f23449e5fa78280668ec
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2644ca45e639e424183c45d850424f0d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 82c81c4751c9a7145a4d491944d132ab
folderAsset: yes
timeCreated: 1491924284
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,99 @@
Shader "Hidden/Klak/Spout/Blit"
{
Properties
{
_MainTex("", 2D) = "white" {}
}
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
// Note: The effect of the v-flip option is reversed here.
// We have to do v-flip actually on no-v-flip passes.
void Vertex(float4 position : POSITION,
float2 texCoord : TEXCOORD0,
out float4 outPosition : SV_Position,
out float2 outTexCoord : TEXCOORD0)
{
outPosition = UnityObjectToClipPos(position);
outTexCoord = float2(texCoord.x, 1 - texCoord.y);
}
void VertexVFlip(float4 position : POSITION,
float2 texCoord : TEXCOORD0,
out float4 outPosition : SV_Position,
out float2 outTexCoord : TEXCOORD0)
{
outPosition = UnityObjectToClipPos(position);
outTexCoord = texCoord;
}
float4 BlitSimple(float4 position : SV_Position,
float2 texCoord : TEXCOORD0) : SV_Target
{
return tex2D(_MainTex, texCoord);
}
float4 BlitClearAlpha(float4 position : SV_Position,
float2 texCoord : TEXCOORD0) : SV_Target
{
return float4(tex2D(_MainTex, texCoord).rgb, 1);
}
float4 BlitFromSrgb(float4 position : SV_Position,
float2 texCoord : TEXCOORD0) : SV_Target
{
float4 c = tex2D(_MainTex, texCoord);
#ifndef UNITY_COLORSPACE_GAMMA
c.rgb = GammaToLinearSpace(c.rgb);
#endif
return c;
}
ENDCG
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex Vertex
#pragma fragment BlitSimple
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex Vertex
#pragma fragment BlitClearAlpha
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex VertexVFlip
#pragma fragment BlitSimple
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex VertexVFlip
#pragma fragment BlitClearAlpha
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex Vertex
#pragma fragment BlitFromSrgb
#pragma multi_compile _ UNITY_COLORSPACE_GAMMA
ENDCG
}
}
}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: eb56c59e60b76874692c486f3bdd860d
timeCreated: 1491925542
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,65 @@
using UnityEngine;
using UnityEngine.Rendering;
using System.Runtime.InteropServices;
using System;
namespace Klak.Spout {
// Render event IDs
// Should match with KlakSpout::EventID (Event.h)
enum EventID
{
UpdateSender,
UpdateReceiver,
CloseSender,
CloseReceiver
}
// Render event attachment data structure
// Should match with KlakSpout::EventData (Event.h)
[StructLayout(LayoutKind.Sequential)]
struct EventData
{
public IntPtr instancePointer;
public IntPtr texturePointer;
public EventData(IntPtr instance, IntPtr texture)
{
instancePointer = instance;
texturePointer = texture;
}
public EventData(IntPtr instance)
{
instancePointer = instance;
texturePointer = IntPtr.Zero;
}
}
class EventKicker : IDisposable
{
public EventKicker(EventData data)
=> _dataMem = GCHandle.Alloc(data, GCHandleType.Pinned);
public void Dispose()
=> MemoryPool.FreeOnEndOfFrame(_dataMem);
public void IssuePluginEvent(EventID eventID)
{
if (_cmdBuffer == null)
_cmdBuffer = new CommandBuffer();
else
_cmdBuffer.Clear();
_cmdBuffer.IssuePluginEventAndData
(Plugin.GetRenderEventCallback(),
(int)eventID, _dataMem.AddrOfPinnedObject());
Graphics.ExecuteCommandBuffer(_cmdBuffer);
}
static CommandBuffer _cmdBuffer;
GCHandle _dataMem;
}
} // namespace Klak.Spout

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 711afc65662fee5429d958cdc98ea404
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,70 @@
using UnityEngine.LowLevel;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
namespace Klak.Spout {
//
// "Memory pool" class without actual memory pool functionality
// At the moment, it only provides the delayed destruction method.
//
static class MemoryPool
{
#region Public method
public static void FreeOnEndOfFrame(GCHandle gch)
=> _toBeFreed.Push(gch);
#endregion
#region Delayed destruction
static Stack<GCHandle> _toBeFreed = new Stack<GCHandle>();
static void OnEndOfFrame()
{
while (_toBeFreed.Count > 0) _toBeFreed.Pop().Free();
}
#endregion
#region PlayerLoopSystem implementation
static MemoryPool()
{
InsertPlayerLoopSystem();
#if UNITY_EDITOR
// We use not only PlayerLoopSystem but also the
// EditorApplication.update callback because the PlayerLoop events are
// not invoked in the edit mode.
UnityEditor.EditorApplication.update += OnEndOfFrame;
#endif
}
static void InsertPlayerLoopSystem()
{
var customSystem = new PlayerLoopSystem()
{ type = typeof(MemoryPool), updateDelegate = OnEndOfFrame };
var playerLoop = PlayerLoop.GetCurrentPlayerLoop();
for (var i = 0; i < playerLoop.subSystemList.Length; i++)
{
ref var phase = ref playerLoop.subSystemList[i];
if (phase.type == typeof(UnityEngine.PlayerLoop.PostLateUpdate))
{
phase.subSystemList = phase.subSystemList
.Concat(new [] { customSystem }).ToArray();
break;
}
}
PlayerLoop.SetPlayerLoop(playerLoop);
}
#endregion
}
} // namespace Klak.Spout

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3d6cd0890fa1bb44c9cc572948deacd4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,61 @@
using System.Runtime.InteropServices;
using IntPtr = System.IntPtr;
namespace Klak.Spout {
static class Plugin
{
// Receiver interop data structure
// Should match with KlakSpout::Receiver::InteropData (Receiver.h)
[StructLayout(LayoutKind.Sequential)]
public struct ReceiverData
{
public uint width, height;
public IntPtr texturePointer;
}
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
[DllImport("KlakSpout")]
public static extern IntPtr GetRenderEventCallback();
[DllImport("KlakSpout")]
public static extern IntPtr CreateSender(string name, int width, int height);
[DllImport("KlakSpout")]
public static extern IntPtr CreateReceiver(string name);
[DllImport("KlakSpout")]
public static extern ReceiverData GetReceiverData(IntPtr receiver);
[DllImport("KlakSpout")]
public static extern void GetSenderNames
([Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
out IntPtr[] names, out int count);
#else
public static IntPtr GetRenderEventCallback()
=> IntPtr.Zero;
public static IntPtr CreateSender(string name, int width, int height)
=> IntPtr.Zero;
public static IntPtr CreateReceiver(string name)
=> IntPtr.Zero;
public static ReceiverData GetReceiverData(IntPtr receiver)
=> new ReceiverData();
public static void GetSenderNames
([Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
out IntPtr[] names, out int count)
{
names = null;
count = 0;
}
#endif
}
} // namespace Klak.Spout

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a6bde715fc227c74abc7562678c323de
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,99 @@
using UnityEngine;
using System.Runtime.InteropServices;
using IntPtr = System.IntPtr;
namespace Klak.Spout {
//
// Wrapper class for receiver instances on the native plugin side
//
sealed class Receiver : System.IDisposable
{
#region Public property
public Texture2D Texture => _texture;
#endregion
#region Private objects
IntPtr _plugin;
EventKicker _event;
Texture2D _texture;
#endregion
#region Object lifecycle
public Receiver(string sourceName)
{
if (string.IsNullOrEmpty(sourceName)) return;
// Plugin object allocation
_plugin = Plugin.CreateReceiver(sourceName);
if (_plugin == IntPtr.Zero) return;
// Event kicker (heap block for interop communication)
_event = new EventKicker(new EventData(_plugin));
// Initial update event
_event.IssuePluginEvent(EventID.UpdateReceiver);
}
public void Dispose()
{
if (_plugin != IntPtr.Zero)
{
// Isssue the closer event to destroy the plugin object from the
// render thread.
_event.IssuePluginEvent(EventID.CloseReceiver);
// Event kicker (interop memory) deallocation:
// The close event above will refer to the block from the render
// thread, so we actually can't free the memory here. To avoid this
// problem, EventKicker uses MemoryPool to delay the memory
// deallocation by the end of the frame.
_event.Dispose();
_plugin = IntPtr.Zero;
}
Utility.Destroy(_texture);
_texture = null;
}
#endregion
#region Frame update method
public void Update()
{
if (_plugin == IntPtr.Zero) return;
var data = Plugin.GetReceiverData(_plugin);
// Texture refresh:
// If we are referring to an old texture pointer, destroy it first.
if (_texture != null &&
_texture.GetNativeTexturePtr() != data.texturePointer)
{
Utility.Destroy(_texture);
_texture = null;
}
// Lazy initialization:
// We try creating a receiver texture every frame until getting a
// correct one.
if (_texture == null && data.texturePointer != IntPtr.Zero)
_texture = Texture2D.CreateExternalTexture
((int)data.width, (int)data.height, TextureFormat.BGRA32,
false, true, data.texturePointer);
// Update event for the render thread
_event.IssuePluginEvent(EventID.UpdateReceiver);
}
#endregion
}
} // namespace Klak.Spout

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8219c164418947e43be8c668062162cc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,64 @@
using UnityEngine;
using System.Runtime.InteropServices;
using IntPtr = System.IntPtr;
namespace Klak.Spout {
//
// Wrapper class for sender instances on the native plugin side
//
sealed class Sender : System.IDisposable
{
#region Private objects
IntPtr _plugin;
EventKicker _event;
#endregion
#region Object lifecycle
public Sender(string target, Texture texture)
{
// Plugin object allocation
_plugin = Plugin.CreateSender(target, texture.width, texture.height);
if (_plugin == IntPtr.Zero) return;
// Event kicker (heap block for interop communication)
_event = new EventKicker
(new EventData(_plugin, texture.GetNativeTexturePtr()));
// Initial update event
_event.IssuePluginEvent(EventID.UpdateSender);
}
public void Dispose()
{
if (_plugin != IntPtr.Zero)
{
// Isssue the closer event to destroy the plugin object from the
// render thread.
_event.IssuePluginEvent(EventID.CloseSender);
// Event kicker (interop memory) deallocation:
// The close event above will refer to the block from the render
// thread, so we actually can't free the memory here. To avoid this
// problem, EventKicker uses MemoryPool to delay the memory
// deallocation by the end of the frame.
_event.Dispose();
_plugin = IntPtr.Zero;
}
}
#endregion
#region Frame update method
public void Update()
=> _event?.IssuePluginEvent(EventID.UpdateSender);
#endregion
}
} // namespace Klak.Spout

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ab35b32382688a747a0fa6b0b1d2b6e6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,65 @@
using UnityEngine;
using UnityEngine.Rendering;
using RTID = UnityEngine.Rendering.RenderTargetIdentifier;
namespace Klak.Spout {
static class RendererOverride
{
static MaterialPropertyBlock _block;
public static void SetTexture
(Renderer renderer, string property, Texture texture)
{
if (_block == null) _block = new MaterialPropertyBlock();
renderer.GetPropertyBlock(_block);
_block.SetTexture(property, texture);
renderer.SetPropertyBlock(_block);
}
}
static class Blitter
{
public static void Blit
(SpoutResources resrc, Texture src, RenderTexture dst, bool alpha)
=> Graphics.Blit(src, dst, GetMaterial(resrc), alpha ? 0 : 1);
public static void BlitVFlip
(SpoutResources resrc, Texture src, RenderTexture dst, bool alpha)
=> Graphics.Blit(src, dst, GetMaterial(resrc), alpha ? 2 : 3);
public static void Blit
(SpoutResources resrc, CommandBuffer cb, RTID src, RTID dst, bool alpha)
=> cb.Blit(src, dst, GetMaterial(resrc), alpha ? 0 : 1);
public static void BlitFromSrgb
(SpoutResources resrc, Texture src, RenderTexture dst)
=> Graphics.Blit(src, dst, GetMaterial(resrc), 4);
static Material _material;
static Material GetMaterial(SpoutResources resrc)
{
if (_material == null)
{
_material = new Material(resrc.blitShader);
_material.hideFlags = HideFlags.DontSave;
}
return _material;
}
}
static class Utility
{
public static void Destroy(Object obj)
{
if (obj == null) return;
if (Application.isPlaying)
Object.Destroy(obj);
else
Object.DestroyImmediate(obj);
}
}
} // namespace Klak.Spout

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2cceadc7283581c4aa2eafb2fb43d58a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,22 @@
{
"name": "Klak.Spout.Runtime",
"rootNamespace": "",
"references": [
"GUID:df380645f10b7bc4b97d4f5eb6303d95"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.unity.render-pipelines.core",
"expression": "0.0.0",
"define": "KLAK_SPOUT_HAS_SRP"
}
],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7cdfac5ef1f961d4ebfe51361a2020bd
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,33 @@
using System.Runtime.InteropServices;
using IntPtr = System.IntPtr;
namespace Klak.Spout {
public static class SpoutManager
{
//
// GetSourceNames - Enumerates names of all available Spout sources
//
// This method invokes GC memory allocations every time, so it's
// recommended to cache the results for frequent use.
//
public static string[] GetSourceNames()
{
// Retrieve an array of string pointers from the plugin.
IntPtr[] pointers;
int count;
Plugin.GetSenderNames(out pointers, out count);
// Convert them into managed strings.
var names = new string[count];
for (var i = 0; i < count; i++)
{
names[i] = Marshal.PtrToStringAnsi(pointers[i]);
Marshal.FreeCoTaskMem(pointers[i]);
}
return names;
}
}
} // namespace Klak.Spout

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fad61147ab755e74aaa5b14138432a5a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,101 @@
using UnityEngine;
namespace Klak.Spout {
//
// Spout receiver class (main implementation)
//
[ExecuteInEditMode]
[AddComponentMenu("Klak/Spout/Spout Receiver")]
public sealed partial class SpoutReceiver : MonoBehaviour
{
#region Receiver plugin object
Receiver _receiver;
void ReleaseReceiver()
{
_receiver?.Dispose();
_receiver = null;
}
#endregion
#region Buffer texture object
RenderTexture _buffer;
RenderTexture PrepareBuffer()
{
// Receive-to-Texture mode:
// Destroy the internal buffer and return the target texture.
if (_targetTexture != null)
{
if (_buffer != null)
{
Utility.Destroy(_buffer);
_buffer = null;
}
return _targetTexture;
}
var src = _receiver.Texture;
// If the buffer exists but has wrong dimensions, destroy it first.
if (_buffer != null &&
(_buffer.width != src.width || _buffer.height != src.height))
{
Utility.Destroy(_buffer);
_buffer = null;
}
// Create a buffer if it hasn't been allocated yet.
if (_buffer == null)
{
_buffer = new RenderTexture(src.width, src.height, 0);
_buffer.hideFlags = HideFlags.DontSave;
_buffer.Create();
}
return _buffer;
}
#endregion
#region MonoBehaviour implementation
void OnDisable()
=> ReleaseReceiver();
void OnDestroy()
{
Utility.Destroy(_buffer);
_buffer = null;
}
void Update()
{
// Receiver lazy initialization
if (_receiver == null)
_receiver = new Receiver(_sourceName);
// Receiver plugin-side update
_receiver.Update();
// Do nothing further if no texture is ready yet.
if (_receiver.Texture == null) return;
// Received texture buffering
var buffer = PrepareBuffer();
Blitter.BlitFromSrgb(_resources, _receiver.Texture, buffer);
// Renderer override
if (_targetRenderer != null)
RendererOverride.SetTexture
(_targetRenderer, _targetMaterialProperty, buffer);
}
#endregion
}
} // namespace Klak.Spout

View File

@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 62f7dec0b00674947bc631624c21970a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- _targetTexture: {instanceID: 0}
- _targetRenderer: {instanceID: 0}
- _resources: {fileID: 11400000, guid: f449ebbe2051c2e4d993eaa773a410de, type: 2}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,67 @@
using UnityEngine;
namespace Klak.Spout {
//
// Spout receiver class (properties)
//
partial class SpoutReceiver
{
#region Spout source
[SerializeField] string _sourceName = null;
public string sourceName
{ get => _sourceName;
set => ChangeSourceName(value); }
void ChangeSourceName(string name)
{
// Receiver refresh on source changes
if (_sourceName == name) return;
_sourceName = name;
ReleaseReceiver();
}
#endregion
#region Destination settings
[SerializeField] RenderTexture _targetTexture = null;
public RenderTexture targetTexture
{ get => _targetTexture;
set => _targetTexture = value; }
[SerializeField] Renderer _targetRenderer = null;
public Renderer targetRenderer
{ get => _targetRenderer;
set => _targetRenderer = value; }
[SerializeField] string _targetMaterialProperty = null;
public string targetMaterialProperty
{ get => _targetMaterialProperty;
set => _targetMaterialProperty = value; }
#endregion
#region Runtime property
public RenderTexture receivedTexture
=> _buffer != null ? _buffer : _targetTexture;
#endregion
#region Resource asset reference
[SerializeField, HideInInspector] SpoutResources _resources = null;
public void SetResources(SpoutResources resources)
=> _resources = resources;
#endregion
}
} // namespace Klak.Spout

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 127d037496fc9b34da364f6785a8b896
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,17 @@
using UnityEngine;
namespace Klak.Spout {
//
// Spout "Resources" class
// This is used to provide a reference to the shader asset.
//
//[CreateAssetMenu(fileName = "SpoutResources",
// menuName = "ScriptableObjects/Klak/Spout/Spout Resources")]
public sealed class SpoutResources : ScriptableObject
{
public Shader blitShader;
}
} // namespace Klak.Spout

Some files were not shown because too many files have changed in this diff Show More