ADD : 스트림 덱 기능 추가를 위한 프로젝트와 스크립트 추가
This commit is contained in:
parent
ac631592e8
commit
b92ba71dd7
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e.meta
vendored
Normal file
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56444d14b6c5a3e47a3952005eb45071
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor.meta
vendored
Normal file
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aaf22bd5628ec0b48846a14ad7d42515
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
156
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor/HapPlayerEditor.cs
vendored
Normal file
156
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor/HapPlayerEditor.cs
vendored
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor/HapPlayerEditor.cs.meta
vendored
Normal file
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor/HapPlayerEditor.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a374e606a0d24345b93bc348a6fbf54
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
16
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor/Klak.Hap.Editor.asmdef
vendored
Normal file
16
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor/Klak.Hap.Editor.asmdef
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Klak.Hap.Editor",
|
||||
"references": [
|
||||
"Klak.Hap"
|
||||
],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": []
|
||||
}
|
||||
7
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor/Klak.Hap.Editor.asmdef.meta
vendored
Normal file
7
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor/Klak.Hap.Editor.asmdef.meta
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26694ad9b328c7148a8fb73421baa7fe
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
87
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor/MaterialPropertySelector.cs
vendored
Normal file
87
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor/MaterialPropertySelector.cs
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor/MaterialPropertySelector.cs.meta
vendored
Normal file
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Editor/MaterialPropertySelector.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe3e2d486287f2f40936cd00c558818d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
215
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/LICENSE
vendored
Normal file
215
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/LICENSE
vendored
Normal 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/>
|
||||
7
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/LICENSE.meta
vendored
Normal file
7
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/LICENSE.meta
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cafc978caabfcd84e8dc32d52b4f2b79
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin.meta
vendored
Normal file
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd3bd64373abe6d4bac999a0b5b69bcd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/Linux.meta
vendored
Normal file
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/Linux.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47a9aaa064c67514da9f5ff173be35fb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/Linux/libKlakHap.so
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/Linux/libKlakHap.so
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
88
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/Linux/libKlakHap.so.meta
vendored
Normal file
88
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/Linux/libKlakHap.so.meta
vendored
Normal 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:
|
||||
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/MacOS.meta
vendored
Normal file
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/MacOS.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93e3b14ab64306d4a85ce4feb6c9b2fd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/MacOS/KlakHap.bundle
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/MacOS/KlakHap.bundle
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
73
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/MacOS/KlakHap.bundle.meta
vendored
Normal file
73
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/MacOS/KlakHap.bundle.meta
vendored
Normal 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:
|
||||
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/Windows.meta
vendored
Normal file
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/Windows.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afcc650d93eee184aa34e7d62096bf27
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/Windows/KlakHap.dll
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/Windows/KlakHap.dll
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
88
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/Windows/KlakHap.dll.meta
vendored
Normal file
88
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Plugin/Windows/KlakHap.dll.meta
vendored
Normal 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/jp.keijiro.klak.hap@9a47acf6295e/README.md
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/README.md
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
7
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/README.md.meta
vendored
Normal file
7
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/README.md.meta
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76ac0e324de156547a580e86fdd8ea2f
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources.meta
vendored
Normal file
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b78bdcad9737cf48a8f9b23254b7f84
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
57
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources/Hap1.shader
vendored
Normal file
57
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources/Hap1.shader
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources/Hap1.shader.meta
vendored
Normal file
9
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources/Hap1.shader.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49f216cf9a0966d4493e7ba1af11c3d6
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
59
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources/Hap5.shader
vendored
Normal file
59
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources/Hap5.shader
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources/Hap5.shader.meta
vendored
Normal file
9
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources/Hap5.shader.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90b82a87346a5254286d43f76863782c
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
72
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources/HapY.shader
vendored
Normal file
72
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources/HapY.shader
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources/HapY.shader.meta
vendored
Normal file
9
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Resources/HapY.shader.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 807e261a8905cde469501ab123338e05
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime.meta
vendored
Normal file
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a1ee959e394fc54bb43e56fdae7a146
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
4
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Common.cs
vendored
Normal file
4
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Common.cs
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
namespace Klak.Hap
|
||||
{
|
||||
public enum CodecType { Unsupported, Hap, HapQ, HapAlpha }
|
||||
}
|
||||
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Common.cs.meta
vendored
Normal file
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Common.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec81190dde6b4d24fb7fdb8f562fccbe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
45
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/FlipBlit.shader
vendored
Normal file
45
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/FlipBlit.shader
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/FlipBlit.shader.meta
vendored
Normal file
9
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/FlipBlit.shader.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 83fc09b934829ee489c1947480fcc03e
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
339
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/HapPlayer.cs
vendored
Normal file
339
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/HapPlayer.cs
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/HapPlayer.cs.meta
vendored
Normal file
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/HapPlayer.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8ea76979ef31fb42882178890076b16
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal.meta
vendored
Normal file
8
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9826f2ed5102c594db39cb240eb1a004
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
146
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/Decoder.cs
vendored
Normal file
146
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/Decoder.cs
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/Decoder.cs.meta
vendored
Normal file
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/Decoder.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb63cbce06802f644820b09291d8dfb0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
103
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/Demuxer.cs
vendored
Normal file
103
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/Demuxer.cs
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/Demuxer.cs.meta
vendored
Normal file
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/Demuxer.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 01e2f3e55fcbb10448e3b4976da8097d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
48
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/ReadBuffer.cs
vendored
Normal file
48
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/ReadBuffer.cs
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/ReadBuffer.cs.meta
vendored
Normal file
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/ReadBuffer.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4489c695e7711e44bbe985cac12755c0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
266
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/StreamReader.cs
vendored
Normal file
266
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/StreamReader.cs
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/StreamReader.cs.meta
vendored
Normal file
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/StreamReader.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5b51807ae8c7e749b98a930666f136b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
77
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/TextureUpdater.cs
vendored
Normal file
77
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/TextureUpdater.cs
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/TextureUpdater.cs.meta
vendored
Normal file
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/TextureUpdater.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 430fee5c2bdcf0c4492d6b8d742439f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
48
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/Utility.cs
vendored
Normal file
48
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/Utility.cs
vendored
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/Utility.cs.meta
vendored
Normal file
11
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Internal/Utility.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6abcc4e09417604ca245a0c5a5a1f0c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Klak.Hap.asmdef
vendored
Normal file
21
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Klak.Hap.asmdef
vendored
Normal 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
|
||||
}
|
||||
7
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Klak.Hap.asmdef.meta
vendored
Normal file
7
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/Runtime/Klak.Hap.asmdef.meta
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d30a992d73d108f4eaaafff3ed9490e3
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/package.json
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/package.json
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
7
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/package.json.meta
vendored
Normal file
7
Assets/External/jp.keijiro.klak.hap@9a47acf6295e/package.json.meta
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52bab5075038b8c46ac3f7bb51b068b2
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/Streamdeck.meta
Normal file
8
Assets/Scripts/Streamdeck.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4fcd9eb3395efa844aedc41188018b29
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/Scripts/Streamdeck/DebugTest.cs
Normal file
9
Assets/Scripts/Streamdeck/DebugTest.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class DebugTest : MonoBehaviour
|
||||
{
|
||||
public void DebugLog()
|
||||
{
|
||||
Debug.Log("message");
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Streamdeck/DebugTest.cs.meta
Normal file
2
Assets/Scripts/Streamdeck/DebugTest.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88aefb43401e8a94f820bc478c2202d5
|
||||
101
Assets/Scripts/Streamdeck/SimpleEventExample.cs
Normal file
101
Assets/Scripts/Streamdeck/SimpleEventExample.cs
Normal file
@ -0,0 +1,101 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class SimpleEventExample : MonoBehaviour
|
||||
{
|
||||
[Header("StreamDock 통신")]
|
||||
[SerializeField] private SimpleStreamDockCommunicator streamDock;
|
||||
|
||||
void Start()
|
||||
{
|
||||
// StreamDock 이벤트 구독
|
||||
if (streamDock != null)
|
||||
{
|
||||
streamDock.OnStreamDockMessageReceived.AddListener(OnStreamDockMessage);
|
||||
streamDock.OnConnected.AddListener(OnStreamDockConnected);
|
||||
streamDock.OnDisconnected.AddListener(OnStreamDockDisconnected);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// StreamDock에서 메시지 수신 시 처리
|
||||
/// </summary>
|
||||
private void OnStreamDockMessage(string eventType, object data)
|
||||
{
|
||||
//Debug.Log($"StreamDock 이벤트 수신: {eventType}");
|
||||
|
||||
switch (eventType)
|
||||
{
|
||||
case "button_clicked":
|
||||
// 버튼 클릭 시 실행할 코드
|
||||
Debug.Log("버튼 클릭 이벤트 실행!");
|
||||
DoSomething();
|
||||
break;
|
||||
|
||||
case "dial_rotate":
|
||||
// 다이얼 회전 시 실행할 코드
|
||||
Debug.Log("다이얼 회전 이벤트 실행!");
|
||||
DoSomethingElse();
|
||||
break;
|
||||
|
||||
case "dial_press":
|
||||
// 다이얼 누름 시 실행할 코드
|
||||
Debug.Log("다이얼 누름 이벤트 실행!");
|
||||
DoAnotherThing();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// StreamDock 연결 시 처리
|
||||
/// </summary>
|
||||
private void OnStreamDockConnected()
|
||||
{
|
||||
Debug.Log("StreamDock에 연결되었습니다!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// StreamDock 연결 해제 시 처리
|
||||
/// </summary>
|
||||
private void OnStreamDockDisconnected()
|
||||
{
|
||||
Debug.Log("StreamDock 연결이 해제되었습니다.");
|
||||
}
|
||||
|
||||
// 여기에 원하는 동작들을 구현하세요
|
||||
private void DoSomething()
|
||||
{
|
||||
Debug.Log("버튼 클릭으로 실행된 동작!");
|
||||
// 예: 오브젝트 활성화/비활성화, 애니메이션 재생, 사운드 재생 등
|
||||
}
|
||||
|
||||
private void DoSomethingElse()
|
||||
{
|
||||
Debug.Log("다이얼 회전으로 실행된 동작!");
|
||||
// 예: 볼륨 조절, 카메라 회전, 값 변경 등
|
||||
}
|
||||
|
||||
private void DoAnotherThing()
|
||||
{
|
||||
Debug.Log("다이얼 누름으로 실행된 동작!");
|
||||
// 예: 특수 기능 실행, 모드 변경 등
|
||||
}
|
||||
|
||||
// 공개 메서드들 (Inspector에서 호출 가능)
|
||||
[ContextMenu("테스트 동작 1")]
|
||||
public void TestAction1()
|
||||
{
|
||||
DoSomething();
|
||||
}
|
||||
|
||||
[ContextMenu("테스트 동작 2")]
|
||||
public void TestAction2()
|
||||
{
|
||||
DoSomethingElse();
|
||||
}
|
||||
|
||||
[ContextMenu("테스트 동작 3")]
|
||||
public void TestAction3()
|
||||
{
|
||||
DoAnotherThing();
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Streamdeck/SimpleEventExample.cs.meta
Normal file
2
Assets/Scripts/Streamdeck/SimpleEventExample.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e65616cccbfc27348b6c11acf939a5f4
|
||||
274
Assets/Scripts/Streamdeck/SimpleStreamDockCommunicator.cs
Normal file
274
Assets/Scripts/Streamdeck/SimpleStreamDockCommunicator.cs
Normal file
@ -0,0 +1,274 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
[System.Serializable]
|
||||
public class StreamDockEvent : UnityEvent<string, object> { }
|
||||
|
||||
public class SimpleStreamDockCommunicator : MonoBehaviour
|
||||
{
|
||||
[Header("연결 설정")]
|
||||
[SerializeField] private string serverUrl = "ws://localhost:15732";
|
||||
[SerializeField] private bool autoConnect = true;
|
||||
[SerializeField] private float reconnectInterval = 5f;
|
||||
|
||||
[Header("이벤트")]
|
||||
public StreamDockEvent OnStreamDockMessageReceived;
|
||||
public UnityEvent OnConnected;
|
||||
public UnityEvent OnDisconnected;
|
||||
|
||||
// 내부 변수
|
||||
private ClientWebSocket webSocket;
|
||||
private CancellationTokenSource cancellationTokenSource;
|
||||
private bool isConnecting = false;
|
||||
private bool isConnected = false;
|
||||
|
||||
// 프로퍼티
|
||||
public bool IsConnected => isConnected;
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (autoConnect)
|
||||
{
|
||||
ConnectToStreamDock();
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
DisconnectFromStreamDock();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// StreamDock에 연결
|
||||
/// </summary>
|
||||
public async void ConnectToStreamDock()
|
||||
{
|
||||
if (isConnecting || isConnected) return;
|
||||
|
||||
isConnecting = true;
|
||||
|
||||
try
|
||||
{
|
||||
webSocket = new ClientWebSocket();
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
Debug.Log($"StreamDock에 연결 중... {serverUrl}");
|
||||
|
||||
await webSocket.ConnectAsync(new Uri(serverUrl), cancellationTokenSource.Token);
|
||||
|
||||
isConnected = true;
|
||||
isConnecting = false;
|
||||
|
||||
Debug.Log("StreamDock에 연결되었습니다!");
|
||||
OnConnected?.Invoke();
|
||||
|
||||
// 메시지 수신 시작
|
||||
_ = ReceiveMessages();
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"StreamDock 연결 실패: {e.Message}");
|
||||
isConnecting = false;
|
||||
OnDisconnected?.Invoke();
|
||||
|
||||
// 재연결 시도
|
||||
StartCoroutine(TryReconnect());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// StreamDock 연결 해제
|
||||
/// </summary>
|
||||
public async void DisconnectFromStreamDock()
|
||||
{
|
||||
if (!isConnected) return;
|
||||
|
||||
try
|
||||
{
|
||||
cancellationTokenSource?.Cancel();
|
||||
|
||||
if (webSocket != null && webSocket.State == WebSocketState.Open)
|
||||
{
|
||||
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Unity 종료", CancellationToken.None);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"연결 해제 중 오류: {e.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
isConnected = false;
|
||||
webSocket?.Dispose();
|
||||
webSocket = null;
|
||||
OnDisconnected?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// StreamDock으로 메시지 전송
|
||||
/// </summary>
|
||||
public async void SendMessageToStreamDock(string eventType, object data = null)
|
||||
{
|
||||
if (!isConnected)
|
||||
{
|
||||
Debug.LogWarning("StreamDock에 연결되지 않았습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var message = new
|
||||
{
|
||||
type = eventType,
|
||||
data = data,
|
||||
timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
|
||||
};
|
||||
|
||||
string jsonMessage = JsonUtility.ToJson(message);
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(jsonMessage);
|
||||
|
||||
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, cancellationTokenSource.Token);
|
||||
|
||||
Debug.Log($"StreamDock으로 메시지 전송: {eventType}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"메시지 전송 실패: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 메시지 수신 처리
|
||||
/// </summary>
|
||||
private async Task ReceiveMessages()
|
||||
{
|
||||
var buffer = new byte[4096];
|
||||
|
||||
try
|
||||
{
|
||||
while (webSocket.State == WebSocketState.Open)
|
||||
{
|
||||
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationTokenSource.Token);
|
||||
|
||||
if (result.MessageType == WebSocketMessageType.Text)
|
||||
{
|
||||
string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
||||
ProcessReceivedMessage(message);
|
||||
}
|
||||
else if (result.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
Debug.Log("StreamDock에서 연결을 종료했습니다.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"메시지 수신 중 오류: {e.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
isConnected = false;
|
||||
OnDisconnected?.Invoke();
|
||||
StartCoroutine(TryReconnect());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 수신된 메시지 처리
|
||||
/// </summary>
|
||||
private void ProcessReceivedMessage(string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Debug.Log($"StreamDock에서 메시지 수신: {message}");
|
||||
|
||||
// JSON 파싱 (간단한 구조)
|
||||
if (message.Contains("type"))
|
||||
{
|
||||
// UnityEvent 호출
|
||||
OnStreamDockMessageReceived?.Invoke("streamdock_message", message);
|
||||
|
||||
// 특정 이벤트 타입 처리
|
||||
if (message.Contains("streamdock_button_clicked"))
|
||||
{
|
||||
HandleButtonClick(message);
|
||||
}
|
||||
else if (message.Contains("dial_rotate"))
|
||||
{
|
||||
HandleDialRotate(message);
|
||||
}
|
||||
else if (message.Contains("dial_press"))
|
||||
{
|
||||
HandleDialPress(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"메시지 처리 중 오류: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 버튼 클릭 이벤트 처리
|
||||
/// </summary>
|
||||
private void HandleButtonClick(string message)
|
||||
{
|
||||
Debug.Log("StreamDock 버튼이 클릭되었습니다!");
|
||||
OnStreamDockMessageReceived?.Invoke("button_clicked", message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 다이얼 회전 이벤트 처리
|
||||
/// </summary>
|
||||
private void HandleDialRotate(string message)
|
||||
{
|
||||
Debug.Log("StreamDock 다이얼이 회전했습니다!");
|
||||
OnStreamDockMessageReceived?.Invoke("dial_rotate", message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 다이얼 누름 이벤트 처리
|
||||
/// </summary>
|
||||
private void HandleDialPress(string message)
|
||||
{
|
||||
Debug.Log("StreamDock 다이얼이 눌렸습니다!");
|
||||
OnStreamDockMessageReceived?.Invoke("dial_press", message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 재연결 시도
|
||||
/// </summary>
|
||||
private IEnumerator TryReconnect()
|
||||
{
|
||||
yield return new WaitForSeconds(reconnectInterval);
|
||||
|
||||
if (!isConnected && !isConnecting)
|
||||
{
|
||||
Debug.Log("StreamDock 재연결 시도...");
|
||||
ConnectToStreamDock();
|
||||
}
|
||||
}
|
||||
|
||||
// 테스트용 메서드들
|
||||
[ContextMenu("테스트 메시지 전송")]
|
||||
public void SendTestMessage()
|
||||
{
|
||||
SendMessageToStreamDock("test_message", new { message = "Unity에서 테스트 메시지" });
|
||||
}
|
||||
|
||||
[ContextMenu("커스텀 이벤트 전송")]
|
||||
public void SendCustomEvent()
|
||||
{
|
||||
SendMessageToStreamDock("custom_event", new { action = "test_action", value = 123 });
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd2d6415e76fac64ea5a022f3cfefa97
|
||||
62
StreamDock-Plugin-SDK/.gitignore
vendored
Normal file
62
StreamDock-Plugin-SDK/.gitignore
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
**/.vscode/
|
||||
**/.vs/
|
||||
|
||||
# Package files
|
||||
**/package-lock.json
|
||||
|
||||
# Non-npm lockfiles
|
||||
**/pnpm-lock.yaml
|
||||
**/yarn.lock
|
||||
**/deno.lock
|
||||
**/bun.lockb
|
||||
**/bun.lock
|
||||
|
||||
# Dependencies
|
||||
**/node_modules/
|
||||
|
||||
# Build outputs
|
||||
**/build/
|
||||
**/dist/
|
||||
**/*.build/
|
||||
**/out/
|
||||
**/__pycache__/
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# IDE and editor files
|
||||
**/.idea/
|
||||
**/*.swp
|
||||
**/*.swo
|
||||
**/*.swn
|
||||
**/.history/
|
||||
*.sublime-workspace
|
||||
*.sublime-project
|
||||
|
||||
# Logs and databases
|
||||
**/logs
|
||||
**/*.log
|
||||
**/*.sqlite
|
||||
**/*.db
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
.env.development
|
||||
.env.test
|
||||
.env.production
|
||||
|
||||
# Testing
|
||||
**/coverage/
|
||||
**/.nyc_output/
|
||||
|
||||
# Temporary files
|
||||
**/tmp/
|
||||
**/temp/
|
||||
BIN
StreamDock-Plugin-SDK/Icon/unity.png
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/Icon/unity.png
(Stored with Git LFS)
Normal file
Binary file not shown.
21
StreamDock-Plugin-SDK/LICENSE
Normal file
21
StreamDock-Plugin-SDK/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 MiraboxSpace
|
||||
|
||||
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.
|
||||
BIN
StreamDock-Plugin-SDK/README.md
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/README.md
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
StreamDock-Plugin-SDK/README.zh-CN.md
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/README.zh-CN.md
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
StreamDock-Plugin-SDK/README_한국어.md
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/README_한국어.md
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/en.json
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/en.json
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/manifest.json
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/manifest.json
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>插件调试</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="./utils/common.js"></script>
|
||||
<script src="./index.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -0,0 +1,19 @@
|
||||
/// <reference path="./utils/common.js" />
|
||||
/// <reference path="./utils/axios.js" />
|
||||
|
||||
const plugin = new Plugins("xxx");
|
||||
|
||||
// 操作一
|
||||
plugin.action1 = new Actions({
|
||||
default: {},
|
||||
_willAppear({ context }) {
|
||||
window.socket.setTitle(context, "Hello world!");
|
||||
},
|
||||
_willDisappear({ context }) { },
|
||||
dialRotate(data) {//旋钮旋转
|
||||
console.log(data);
|
||||
},
|
||||
dialDown(data) {//旋钮按下
|
||||
console.log(data);
|
||||
}
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,155 @@
|
||||
const Timer = new Worker('./utils/worker.js');
|
||||
const TimerSubscribe = { setTimeout: {}, setInterval: {} };
|
||||
Timer.addEventListener('message', function ({ data }) {
|
||||
TimerSubscribe[data.event][data.id]?.();
|
||||
});
|
||||
|
||||
class Actions {
|
||||
constructor(data) {
|
||||
this.data = {};
|
||||
this.default = {};
|
||||
Object.assign(this, data);
|
||||
}
|
||||
// 属性检查器显示时
|
||||
static currentAction = null;
|
||||
static currentContext = null;
|
||||
propertyInspectorDidAppear({ action, context }) {
|
||||
Actions.currentAction = action;
|
||||
Actions.currentContext = context;
|
||||
this._propertyInspectorDidAppear?.(data);
|
||||
}
|
||||
// 初始化数据
|
||||
willAppear(data) {
|
||||
const { context, payload: { settings } } = data;
|
||||
this.data[context] = Object.assign({ ...this.default }, settings);
|
||||
this._willAppear?.(data);
|
||||
}
|
||||
// 行动销毁
|
||||
willDisappear(data) {
|
||||
this._willDisappear?.(data);
|
||||
delete this.data[data.context];
|
||||
}
|
||||
}
|
||||
|
||||
class Plugins {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
}
|
||||
// 延时器/清除延时
|
||||
clearTimeout(id) { Timer.postMessage({ event: 'clearTimeout', id }); }
|
||||
setTimeout(id, callback, delay) {
|
||||
this.clearTimeout(id);
|
||||
TimerSubscribe.setTimeout[id] = callback;
|
||||
Timer.postMessage({
|
||||
event: 'setTimeout',
|
||||
id, delay
|
||||
});
|
||||
}
|
||||
// 定时器/清除定时器
|
||||
clearInterval(id) { Timer.postMessage({ event: 'clearInterval', id }); }
|
||||
setInterval(id, callback, delay) {
|
||||
this.clearInterval(id);
|
||||
TimerSubscribe.setInterval[id] = callback;
|
||||
Timer.postMessage({
|
||||
event: 'setInterval',
|
||||
id, delay
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 软件通信
|
||||
window.connectElgatoStreamDeckSocket = function () {
|
||||
const uuid = arguments[1], event = arguments[2];
|
||||
window.info = JSON.parse(arguments[3]);
|
||||
window.socket = new WebSocket("ws://127.0.0.1:" + arguments[0]);
|
||||
|
||||
// 打开网页
|
||||
WebSocket.prototype.openUrl = function (url) {
|
||||
this.send(JSON.stringify({
|
||||
event: "openUrl",
|
||||
payload: { url }
|
||||
}));
|
||||
};
|
||||
|
||||
// 与当前属性检查器通信
|
||||
WebSocket.prototype.sendToPropertyInspector = function (payload) {
|
||||
this.send(JSON.stringify({
|
||||
payload,
|
||||
event: "sendToPropertyInspector",
|
||||
action: Actions.currentAction,
|
||||
context: Actions.currentContext
|
||||
}));
|
||||
};
|
||||
|
||||
// 保存持久化数据
|
||||
WebSocket.prototype.setSettings = function (context, payload) {
|
||||
this.send(JSON.stringify({
|
||||
event: "setSettings",
|
||||
context, payload
|
||||
}));
|
||||
};
|
||||
|
||||
// 设置背景
|
||||
WebSocket.prototype.setImage = function (context, url) {
|
||||
const image = new Image();
|
||||
image.src = url;
|
||||
image.onload = () => {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = image.naturalWidth;
|
||||
canvas.height = image.naturalHeight;
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(image, 0, 0);
|
||||
this.send(JSON.stringify({
|
||||
event: "setImage",
|
||||
context, payload: {
|
||||
target: 0,
|
||||
image: canvas.toDataURL("image/png")
|
||||
}
|
||||
}));
|
||||
};
|
||||
};
|
||||
|
||||
// 设置标题
|
||||
WebSocket.prototype.setTitle = function (context, str, row = 0, num = 6) {
|
||||
let newStr = '';
|
||||
if (row) {
|
||||
let nowRow = 1, strArr = str.split('');
|
||||
strArr.forEach((item, index) => {
|
||||
if (nowRow < row && index >= nowRow * num) {
|
||||
nowRow++;
|
||||
newStr += '\n';
|
||||
}
|
||||
if (nowRow <= row && index < nowRow * num) {
|
||||
newStr += item;
|
||||
}
|
||||
});
|
||||
if (strArr.length > row * num) {
|
||||
newStr = newStr.substring(0, newStr.length - 1);
|
||||
newStr += '..';
|
||||
}
|
||||
}
|
||||
this.send(JSON.stringify({
|
||||
event: "setTitle",
|
||||
context, payload: {
|
||||
target: 0,
|
||||
title: newStr || str
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
// 设置状态
|
||||
WebSocket.prototype.setState = function (context, state) {
|
||||
this.send(JSON.stringify({
|
||||
event: "setState",
|
||||
payload: { state },
|
||||
context
|
||||
}));
|
||||
};
|
||||
|
||||
window.socket.onopen = () => window.socket.send(JSON.stringify({ uuid, event }));
|
||||
window.socket.onmessage = e => {
|
||||
const data = JSON.parse(e.data);
|
||||
plugin[data.action?.split('.').pop()]?.[data.event]?.(data);
|
||||
plugin[data.event]?.(data);
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,30 @@
|
||||
const that = this, Timer = {}
|
||||
|
||||
const handle = {
|
||||
setTimeout(data) {
|
||||
Timer[data.id] = setTimeout(() => {
|
||||
that.self.postMessage({
|
||||
event: 'setTimeout',
|
||||
id: data.id
|
||||
})
|
||||
}, data.delay)
|
||||
},
|
||||
setInterval(data) {
|
||||
Timer[data.id] = setInterval(() => {
|
||||
that.self.postMessage({
|
||||
event: 'setInterval',
|
||||
id: data.id
|
||||
})
|
||||
}, data.delay)
|
||||
},
|
||||
clearTimeout(data) {
|
||||
clearTimeout(Timer[data.id])
|
||||
},
|
||||
clearInterval(data) {
|
||||
clearInterval(Timer[data.id])
|
||||
}
|
||||
}
|
||||
|
||||
this.self.onmessage = function ({ data }) {
|
||||
handle[data?.event]?.(data)
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>模板 - 属性检查器</title>
|
||||
<link rel="stylesheet" href="../../static/css/sdpi.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="sdpi-wrapper" style="display: none">
|
||||
<div class="sdpi-heading">模板</div>
|
||||
</div>
|
||||
<script src="../utils/common.js"></script>
|
||||
<script src="../utils/action.js"></script>
|
||||
<script src="index.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -0,0 +1,21 @@
|
||||
/// <reference path="../utils/common.js" />
|
||||
/// <reference path="../utils/action.js" />
|
||||
|
||||
/**
|
||||
* 基础参数说明:
|
||||
* @global websocket uuid action context settings lang
|
||||
* @settings local back 是否国际化 | 是否自行回显
|
||||
* @policy dom propEvent 缓存文档元素 | 软件触发事件 - 策略模式
|
||||
* =======================================================================>
|
||||
*/
|
||||
|
||||
const $local = false, $back = false, $dom = {
|
||||
main: $('.sdpi-wrapper')
|
||||
};
|
||||
|
||||
const $propEvent = {
|
||||
didReceiveSettings(data) {
|
||||
console.log(data);
|
||||
},
|
||||
sendToPropertyInspector(data) { }
|
||||
};
|
||||
@ -0,0 +1,130 @@
|
||||
/**
|
||||
* PropertyInspector 2.5.0 新特性 =>
|
||||
*
|
||||
* 1 => 工具与主文件相分离 - 按需引入
|
||||
* 2 => $settings - 全局持久化数据代理 ※
|
||||
* 3 => 无需关注上下文 - 随时随地与插件通信
|
||||
* 4 => 注意事项: 为了避免命名冲突,请勿使用 $ 相关的名称以及JQuery库
|
||||
*
|
||||
* ===== CJHONG ========================================== 2023.10.10 =====>
|
||||
*/
|
||||
|
||||
let $websocket, $uuid, $action, $context, $settings, $lang, $FileID = '';
|
||||
|
||||
// 与插件通信
|
||||
WebSocket.prototype.sendToPlugin = function (payload) {
|
||||
this.send(JSON.stringify({
|
||||
event: "sendToPlugin",
|
||||
action: $action,
|
||||
context: $uuid,
|
||||
payload
|
||||
}));
|
||||
};
|
||||
|
||||
// 设置状态
|
||||
WebSocket.prototype.setState = function (state) {
|
||||
this.send(JSON.stringify({
|
||||
event: "setState",
|
||||
context: $context,
|
||||
payload: { state }
|
||||
}));
|
||||
};
|
||||
|
||||
// 设置背景
|
||||
WebSocket.prototype.setImage = function (url) {
|
||||
let image = new Image();
|
||||
image.src = url;
|
||||
image.onload = () => {
|
||||
let canvas = document.createElement("canvas");
|
||||
canvas.width = image.naturalWidth;
|
||||
canvas.height = image.naturalHeight;
|
||||
let ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(image, 0, 0);
|
||||
this.send(JSON.stringify({
|
||||
event: "setImage",
|
||||
context: $context,
|
||||
payload: {
|
||||
target: 0,
|
||||
image: canvas.toDataURL("image/png")
|
||||
}
|
||||
}));
|
||||
};
|
||||
};
|
||||
|
||||
// 打开网页
|
||||
WebSocket.prototype.openUrl = function (url) {
|
||||
this.send(JSON.stringify({
|
||||
event: "openUrl",
|
||||
payload: { url }
|
||||
}));
|
||||
};
|
||||
|
||||
// 保存持久化数据
|
||||
WebSocket.prototype.saveData = $.debounce(function (payload) {
|
||||
this.send(JSON.stringify({
|
||||
event: "setSettings",
|
||||
context: $uuid,
|
||||
payload
|
||||
}));
|
||||
});
|
||||
|
||||
// StreamDock 软件入口函数
|
||||
async function connectElgatoStreamDeckSocket(port, uuid, event, app, info) {
|
||||
info = JSON.parse(info);
|
||||
$uuid = uuid; $action = info.action; $context = info.context;
|
||||
$websocket = new WebSocket('ws://127.0.0.1:' + port);
|
||||
$websocket.onopen = () => $websocket.send(JSON.stringify({ event, uuid }));
|
||||
|
||||
// 持久数据代理
|
||||
$websocket.onmessage = e => {
|
||||
let data = JSON.parse(e.data);
|
||||
if (data.event === 'didReceiveSettings') {
|
||||
$settings = new Proxy(data.payload.settings, {
|
||||
get(target, property) {
|
||||
return target[property];
|
||||
},
|
||||
set(target, property, value) {
|
||||
target[property] = value;
|
||||
$websocket.saveData(data.payload.settings);
|
||||
}
|
||||
});
|
||||
if (!$back) $dom.main.style.display = 'block';
|
||||
}
|
||||
$propEvent[data.event]?.(data.payload);
|
||||
};
|
||||
|
||||
// 自动翻译页面
|
||||
if (!$local) return;
|
||||
$lang = await new Promise(resolve => {
|
||||
const req = new XMLHttpRequest();
|
||||
req.open('GET', `../../${JSON.parse(app).application.language}.json`);
|
||||
req.send();
|
||||
req.onreadystatechange = () => {
|
||||
if (req.readyState === 4) {
|
||||
resolve(JSON.parse(req.responseText).Localization);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// 遍历文本节点并翻译所有文本节点
|
||||
const walker = document.createTreeWalker($dom.main, NodeFilter.SHOW_TEXT, (e) => {
|
||||
return e.data.trim() && NodeFilter.FILTER_ACCEPT;
|
||||
});
|
||||
while (walker.nextNode()) {
|
||||
console.log(walker.currentNode.data);
|
||||
walker.currentNode.data = $lang[walker.currentNode.data];
|
||||
}
|
||||
// placeholder 特殊处理
|
||||
const translate = item => {
|
||||
if (item.placeholder?.trim()) {
|
||||
console.log(item.placeholder);
|
||||
item.placeholder = $lang[item.placeholder];
|
||||
}
|
||||
};
|
||||
$('input', true).forEach(translate);
|
||||
$('textarea', true).forEach(translate);
|
||||
}
|
||||
|
||||
// StreamDock 文件路径回调
|
||||
Array.from($('input[type="file"]', true)).forEach(item => item.addEventListener('click', () => $FileID = item.id));
|
||||
const onFilePickerReturn = (url) => $emit.send(`File-${$FileID}`, JSON.parse(url));
|
||||
@ -0,0 +1,81 @@
|
||||
// 自定义事件类
|
||||
class EventPlus {
|
||||
constructor() {
|
||||
this.event = new EventTarget();
|
||||
}
|
||||
on(name, callback) {
|
||||
this.event.addEventListener(name, e => callback(e.detail));
|
||||
}
|
||||
send(name, data) {
|
||||
this.event.dispatchEvent(new CustomEvent(name, {
|
||||
detail: data,
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// 补零
|
||||
String.prototype.fill = function () {
|
||||
return this >= 10 ? this : '0' + this;
|
||||
};
|
||||
|
||||
// unicode编码转换字符串
|
||||
String.prototype.uTs = function () {
|
||||
return eval('"' + Array.from(this).join('') + '"');
|
||||
};
|
||||
|
||||
// 字符串转换unicode编码
|
||||
String.prototype.sTu = function (str = '') {
|
||||
Array.from(this).forEach(item => str += `\\u${item.charCodeAt(0).toString(16)}`);
|
||||
return str;
|
||||
};
|
||||
|
||||
// 全局变量/方法
|
||||
const $emit = new EventPlus(), $ = (selector, isAll = false) => {
|
||||
const element = document.querySelector(selector), methods = {
|
||||
on: function (event, callback) {
|
||||
this.addEventListener(event, callback);
|
||||
},
|
||||
attr: function (name, value = '') {
|
||||
value && this.setAttribute(name, value);
|
||||
return this;
|
||||
}
|
||||
};
|
||||
if (!isAll && element) {
|
||||
return Object.assign(element, methods);
|
||||
} else if (!isAll && !element) {
|
||||
throw `HTML没有 ${selector} 元素! 请检查是否拼写错误`;
|
||||
}
|
||||
return Array.from(document.querySelectorAll(selector)).map(item => Object.assign(item, methods));
|
||||
};
|
||||
|
||||
// 节流函数
|
||||
$.throttle = (fn, delay) => {
|
||||
let Timer = null;
|
||||
return function () {
|
||||
if (Timer) return;
|
||||
Timer = setTimeout(() => {
|
||||
fn.apply(this, arguments);
|
||||
Timer = null;
|
||||
}, delay);
|
||||
};
|
||||
};
|
||||
|
||||
// 防抖函数
|
||||
$.debounce = (fn, delay) => {
|
||||
let Timer = null;
|
||||
return function () {
|
||||
clearTimeout(Timer);
|
||||
Timer = setTimeout(() => fn.apply(this, arguments), delay);
|
||||
};
|
||||
};
|
||||
|
||||
// 绑定限制数字方法
|
||||
Array.from($('input[type="num"]', true)).forEach(item => {
|
||||
item.addEventListener('input', function limitNum() {
|
||||
if (!item.value || /^\d+$/.test(item.value)) return;
|
||||
item.value = item.value.slice(0, -1);
|
||||
limitNum(item);
|
||||
});
|
||||
});
|
||||
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/readme.md
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/readme.md
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/static/CH.png
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/static/CH.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="6" viewBox="0 0 12 6">
|
||||
<polygon fill="#8E8E92" fill-rule="evenodd" points="5 4 9 0 10 1 5 6 0 1 1 0"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 171 B |
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/static/css/check.png
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/static/css/check.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="10" viewBox="0 0 12 10">
|
||||
<polygon fill="#FFF" points="7.2 7.5 7.2 -1.3 8.7 -1.3 8.6 9.1 2.7 8.7 2.7 7.2" transform="rotate(37 5.718 3.896)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 210 B |
@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#9C9C9C" fill-rule="nonzero" d="M1,5 L1,14 L14,14 L14,5 L1,5 Z M0,1 L15,1 L15,15 L0,15 L0,1 Z M14,4 L14,2 L1,2 L1,4 L14,4 Z"/>
|
||||
<rect width="1" height="1" x="2" fill="#9C9C9C" fill-rule="nonzero"/>
|
||||
<rect width="1" height="1" x="12" fill="#9C9C9C" fill-rule="nonzero"/>
|
||||
<g transform="translate(3 7)">
|
||||
<rect width="1" height="1" x="2" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" fill="#666"/>
|
||||
<rect width="1" height="1" x="4" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" x="6" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" x="8" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" y="2" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" x="2" y="2" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" x="4" y="2" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" x="6" y="2" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" x="8" y="2" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" y="4" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" x="2" y="4" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" x="4" y="4" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" x="6" y="4" fill="#9C9C9C"/>
|
||||
<rect width="1" height="1" x="8" y="4" fill="#666"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="#9C9C9C">
|
||||
<path d="M15,15 L1.77635684e-15,15 L1.77635684e-15,1 L15,1 L15,15 Z M5,7 L5,8 L6,8 L6,7 L5,7 Z M3,7 L3,8 L4,8 L4,7 L3,7 Z M7,7 L7,8 L8,8 L8,7 L7,7 Z M9,7 L9,8 L10,8 L10,7 L9,7 Z M11,7 L11,8 L12,8 L12,7 L11,7 Z M3,9 L3,10 L4,10 L4,9 L3,9 Z M5,9 L5,10 L6,10 L6,9 L5,9 Z M7,9 L7,10 L8,10 L8,9 L7,9 Z M9,9 L9,10 L10,10 L10,9 L9,9 Z M11,9 L11,10 L12,10 L12,9 L11,9 Z M3,11 L3,12 L4,12 L4,11 L3,11 Z M5,11 L5,12 L6,12 L6,11 L5,11 Z M7,11 L7,12 L8,12 L8,11 L7,11 Z M9,11 L9,12 L10,12 L10,11 L9,11 Z M11,11 L11,12 L12,12 L12,11 L11,11 Z M14,4 L14,2 L1,2 L1,4 L14,4 Z"/>
|
||||
<rect width="1" height="1" x="2"/>
|
||||
<rect width="1" height="1" x="12"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 764 B |
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Keyshape -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="46" height="46" viewBox="0 0 46 46">
|
||||
<style>
|
||||
@keyframes a0_t { 0% { transform: translate(0px,0px) scale(1,1); } 50% { transform: translate(23px,0px) scale(0,1); } 100% { transform: translate(0px,0px) scale(1,1); } }
|
||||
@keyframes a0_f { 0% { fill: #d8d8d8; } 100% { fill: #d8d8d8; } }
|
||||
@keyframes a0_d { 0% { d: path('M26.7002,16.1301L26.6501,16.0924L18.4447,11.4398L14.3373,13.7874L14.3373,31.9187L18.4511,34.2437L30.0827,27.5941L26.0878,25.3292L18.3286,29.7648L18.3286,15.9149L40.8363,28.6881L40.8228,28.7688C39.6065,32.4179,37.3047,35.5576,34.1665,37.8484C30.9632,40.1865,27.1667,41.4225,23.1877,41.4225C12.9466,41.4225,4.6147,33.1581,4.6147,22.9999C4.6147,12.8415,12.9466,4.57726,23.1877,4.57726C31.0308,4.57726,38.0657,9.51032,40.6929,16.8527C40.888,17.3976,41.0585,17.9576,41.201,18.5197L45.3224,16.1504C45.1466,15.5908,44.9476,15.0335,44.7302,14.4923C43.0331,10.2647,40.1339,6.65801,36.3464,4.0619C32.4692,1.40466,27.9189,0,23.1877,0C16.994,0,11.1711,2.39237,6.7916,6.73651C2.4119,11.0806,0,16.8563,0,22.9999C0,29.1433,2.4119,34.9192,6.7916,39.2635C11.1711,43.6076,16.994,46,23.1877,46C28.6714,46,33.9912,44.0654,38.1673,40.553C42.2755,37.0973,45.0531,32.3177,46,27.0878L26.7002,16.1301L26.7002,16.1301Z'); } 100% { d: path('M26.7002,16.1301L26.6501,16.0924L18.4447,11.4398L14.3373,13.7874L14.3373,31.9187L18.4511,34.2437L30.0827,27.5941L26.0878,25.3292L18.3286,29.7648L18.3286,15.9149L40.8363,28.6881L40.8228,28.7688C39.6065,32.4179,37.3047,35.5576,34.1665,37.8484C30.9632,40.1865,27.1667,41.4225,23.1877,41.4225C12.9466,41.4225,4.6147,33.1581,4.6147,22.9999C4.6147,12.8415,12.9466,4.57726,23.1877,4.57726C31.0308,4.57726,38.0657,9.51032,40.6929,16.8527C40.888,17.3976,41.0585,17.9576,41.201,18.5197L45.3224,16.1504C45.1466,15.5908,44.9476,15.0335,44.7302,14.4923C43.0331,10.2647,40.1339,6.65801,36.3464,4.0619C32.4692,1.40466,27.9189,0,23.1877,0C16.994,0,11.1711,2.39237,6.7916,6.73651C2.4119,11.0806,0,16.8563,0,22.9999C0,29.1433,2.4119,34.9192,6.7916,39.2635C11.1711,43.6076,16.994,46,23.1877,46C28.6714,46,33.9912,44.0654,38.1673,40.553C42.2755,37.0973,45.0531,32.3177,46,27.0878L26.7002,16.1301L26.7002,16.1301Z'); } }
|
||||
</style>
|
||||
<path fill="#d8d8d8" fill-rule="evenodd" d="M26.7002,16.1301L26.6501,16.0924L18.4447,11.4398L14.3373,13.7874L14.3373,31.9187L18.4511,34.2437L30.0827,27.5941L26.0878,25.3292L18.3286,29.7648L18.3286,15.9149L40.8363,28.6881L40.8228,28.7688C39.6065,32.4179,37.3047,35.5576,34.1665,37.8484C30.9632,40.1865,27.1667,41.4225,23.1877,41.4225C12.9466,41.4225,4.6147,33.1581,4.6147,22.9999C4.6147,12.8415,12.9466,4.57726,23.1877,4.57726C31.0308,4.57726,38.0657,9.51032,40.6929,16.8527C40.888,17.3976,41.0585,17.9576,41.201,18.5197L45.3224,16.1504C45.1466,15.5908,44.9476,15.0335,44.7302,14.4923C43.0331,10.2647,40.1339,6.65801,36.3464,4.0619C32.4692,1.40466,27.9189,0,23.1877,0C16.994,0,11.1711,2.39237,6.7916,6.73651C2.4119,11.0806,0,16.8563,0,22.9999C0,29.1433,2.4119,34.9192,6.7916,39.2635C11.1711,43.6076,16.994,46,23.1877,46C28.6714,46,33.9912,44.0654,38.1673,40.553C42.2755,37.0973,45.0531,32.3177,46,27.0878L26.7002,16.1301L26.7002,16.1301Z" style="animation: 6s linear infinite both a0_t, 6s linear infinite both a0_f, 6s linear infinite both a0_d;"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="6" height="6" viewBox="0 0 6 6">
|
||||
<circle cx="3" cy="3" r="3" fill="#FFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 131 B |
@ -0,0 +1,230 @@
|
||||
:root{--sdpi-bgcolor:#2D2D2D;--sdpi-background:#3D3D3D;--sdpi-color:#d8d8d8;--sdpi-bordercolor:#3a3a3a;--sdpi-buttonbordercolor:#969696;--sdpi-borderradius:0px;--sdpi-width:224px;--sdpi-fontweight:600;--sdpi-letterspacing:-0.25pt}
|
||||
html{--sdpi-bgcolor:#2D2D2D;--sdpi-background:#3D3D3D;--sdpi-color:#d8d8d8;--sdpi-bordercolor:#3a3a3a;--sdpi-buttonbordercolor:#969696;--sdpi-borderradius:0px;--sdpi-width:224px;--sdpi-fontweight:600;--sdpi-letterspacing:-0.25pt;height:100%;width:100%;overflow:hidden;touch-action:none;user-select:none}
|
||||
html,body{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:9pt;background-color:var(--sdpi-bgcolor);color:#9a9a9a}
|
||||
body{height:100%;padding:0;overflow-x:hidden;overflow-y:auto;margin:0;-webkit-overflow-scrolling:touch;-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased}
|
||||
mark{background-color:var(--sdpi-bgcolor);color:var(--sdpi-color)}
|
||||
hr,hr2{-webkit-margin-before:1em;-webkit-margin-after:1em;border-style:none;background:var(--sdpi-background);height:1px}
|
||||
hr2,.sdpi-heading{display:flex;flex-basis:100%;align-items:center;color:inherit;font-size:9pt;margin:8px 0px}
|
||||
.sdpi-heading::before,.sdpi-heading::after{content:"";flex-grow:1;background:var(--sdpi-background);height:1px;font-size:0px;line-height:0px;margin:0px 16px}
|
||||
hr2{height:2px}
|
||||
hr,hr2{margin-left:16px;margin-right:16px}
|
||||
.sdpi-item-value,option,input,select,button{font-size:10pt;font-weight:var(--sdpi-fontweight);letter-spacing:var(--sdpi-letterspacing)}
|
||||
.win .sdpi-item-value,.win option,.win input,.win select,.win button{font-size:11px;font-style:normal;letter-spacing:inherit;font-weight:100}
|
||||
.win button{font-size:12px}
|
||||
::-webkit-progress-value,meter::-webkit-meter-optimum-value{border-radius:2px}
|
||||
::-webkit-progress-bar,meter::-webkit-meter-bar{border-radius:3px;background:var(--sdpi-background)}
|
||||
::-webkit-progress-bar:active,meter::-webkit-meter-bar:active{border-radius:3px;background:#222222}
|
||||
::-webkit-progress-value:active,meter::-webkit-meter-optimum-value:active{background:#99f}
|
||||
progress,progress.sdpi-item-value{min-height:5px !important;height:5px;background-color:#303030}
|
||||
progress{margin-top:8px !important;margin-bottom:8px !important}
|
||||
.full progress,progress.full{margin-top:3px !important}
|
||||
::-webkit-progress-inner-element{background-color:transparent}
|
||||
.sdpi-item[type="progress"]{margin-top:4px !important;margin-bottom:12px;min-height:15px}
|
||||
.sdpi-item-child.full:last-child{margin-bottom:4px}
|
||||
.tabs{display:flex;border-bottom:1px solid #D7DBDD}
|
||||
.tab{cursor:pointer;padding:5px 30px;color:#16a2d7;font-size:9pt;border-bottom:2px solid transparent}
|
||||
.tab.is-tab-selected{border-bottom-color:#4ebbe4}
|
||||
select{width:100%;-webkit-appearance:none;-moz-appearance:none;-o-appearance:none;appearance:none;background:url(caret.svg) no-repeat 97% center}
|
||||
label.sdpi-file-label,input[type="button"],input[type="submit"],input[type="reset"],input[type="file"],input[type=file]::-webkit-file-upload-button,button,select{color:var(--sdpi-color);border:1pt solid #303030;font-size:8pt;background-color:var(--sdpi-background);border-radius:var(--sdpi-borderradius)}
|
||||
label.sdpi-file-label,input[type="button"],input[type="submit"],input[type="reset"],input[type="file"],input[type=file]::-webkit-file-upload-button,button{border:1pt solid var(--sdpi-buttonbordercolor);border-radius:var(--sdpi-borderradius);border-color:var(--sdpi-buttonbordercolor);min-height:23px !important;height:23px !important;margin-right:8px}
|
||||
input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
|
||||
input[type="file"]{border-radius:var(--sdpi-borderradius);max-width:220px}
|
||||
option{height:1.5em;padding:4px}
|
||||
.sdpi-wrapper{overflow-x:hidden;height:100%}
|
||||
.sdpi-item{display:flex;flex-direction:row;min-height:32px;align-items:center;margin-top:2px;max-width:344px;-webkit-user-drag:none}
|
||||
.sdpi-item:first-child{margin-top:-1px}
|
||||
.sdpi-item:last-child{margin-bottom:0px}
|
||||
.sdpi-item>*:not(.sdpi-item-label):not(meter):not(details):not(canvas){min-height:26px;padding:0px 4px 0px 4px}
|
||||
.sdpi-item>*:not(.sdpi-item-label.empty):not(meter){min-height:26px;padding:0px 4px 0px 4px}
|
||||
.sdpi-item-group{padding:0 !important}
|
||||
meter.sdpi-item-value{margin-left:6px}
|
||||
.sdpi-item[type="group"]{display:block;margin-top:12px;margin-bottom:12px;flex-direction:unset;text-align:left}
|
||||
.sdpi-item[type="group"]>.sdpi-item-label,.sdpi-item[type="group"].sdpi-item-label{width:96%;text-align:left;font-weight:700;margin-bottom:4px;padding-left:4px}
|
||||
dl,ul,ol{-webkit-margin-before:0px;-webkit-margin-after:4px;-webkit-padding-start:1em;max-height:90px;overflow-y:scroll;cursor:pointer;user-select:none}
|
||||
table.sdpi-item-value,dl.sdpi-item-value,ul.sdpi-item-value,ol.sdpi-item-value{-webkit-margin-before:4px;-webkit-margin-after:8px;-webkit-padding-start:1em;width:var(--sdpi-width);text-align:center}
|
||||
table>caption{margin:2px}
|
||||
.list,.sdpi-item[type="list"]{align-items:baseline}
|
||||
.sdpi-item-label{text-align:right;flex:none;width:94px;padding-right:4px;font-weight:600}
|
||||
.win .sdpi-item-label,.sdpi-item-label>small{font-weight:normal}
|
||||
.sdpi-item-label:after{content:":"}
|
||||
.sdpi-item-label.empty:after{content:""}
|
||||
.sdpi-test,.sdpi-item-value{flex:1 0 0;margin-right:14px;margin-left:4px;justify-content:space-evenly}
|
||||
canvas.sdpi-item-value{max-width:144px;max-height:144px;width:144px;height:144px;margin:0 auto;cursor:pointer}
|
||||
input.sdpi-item-value{margin-left:5px}
|
||||
.sdpi-item-value button,button.sdpi-item-value{margin-left:6px;margin-right:14px}
|
||||
.sdpi-item-value.range{margin-left:0px}
|
||||
table,dl.sdpi-item-value,ul.sdpi-item-value,ol.sdpi-item-value,.sdpi-item-value>dl,.sdpi-item-value>ul,.sdpi-item-value>ol{list-style-type:none;list-style-position:outside;margin-left:-4px;margin-right:-4px;padding:4px;border:1px solid var(--sdpi-bordercolor)}
|
||||
dl.sdpi-item-value,ul.sdpi-item-value,ol.sdpi-item-value,.sdpi-item-value>ol{list-style-type:none;list-style-position:inside;margin-left:5px;margin-right:12px;padding:4px !important;display:flex;flex-direction:column}
|
||||
.two-items li{display:flex}
|
||||
.two-items li>*:first-child{flex:0 0 50%;text-align:left}
|
||||
.two-items.thirtyseventy li>*:first-child{flex:0 0 30%}
|
||||
ol.sdpi-item-value,.sdpi-item-value>ol[listtype="none"]{list-style-type:none}
|
||||
ol.sdpi-item-value[type="decimal"],.sdpi-item-value>ol[type="decimal"]{list-style-type:decimal}
|
||||
ol.sdpi-item-value[type="decimal-leading-zero"],.sdpi-item-value>ol[type="decimal-leading-zero"]{list-style-type:decimal-leading-zero}
|
||||
ol.sdpi-item-value[type="lower-alpha"],.sdpi-item-value>ol[type="lower-alpha"]{list-style-type:lower-alpha}
|
||||
ol.sdpi-item-value[type="upper-alpha"],.sdpi-item-value>ol[type="upper-alpha"]{list-style-type:upper-alpha}
|
||||
ol.sdpi-item-value[type="upper-roman"],.sdpi-item-value>ol[type="upper-roman"]{list-style-type:upper-roman}
|
||||
ol.sdpi-item-value[type="lower-roman"],.sdpi-item-value>ol[type="lower-roman"]{list-style-type:upper-roman}
|
||||
tr:nth-child(even),.sdpi-item-value>ul>li:nth-child(even),.sdpi-item-value>ol>li:nth-child(even),li:nth-child(even){background-color:rgba(0,0,0,.2)}
|
||||
td:hover,.sdpi-item-value>ul>li:hover:nth-child(even),.sdpi-item-value>ol>li:hover:nth-child(even),li:hover:nth-child(even),li:hover{background-color:rgba(255,255,255,.1)}
|
||||
td.selected,td.selected:hover,li.selected:hover,li.selected{color:white;background-color:#77f}
|
||||
tr{border:1px solid var(--sdpi-bordercolor)}
|
||||
td{border-right:1px solid var(--sdpi-bordercolor)}
|
||||
tr:last-child,td:last-child{border:none}
|
||||
.sdpi-item-value.select,.sdpi-item-value>select{margin-right:13px;margin-left:4px}
|
||||
.sdpi-item-child,.sdpi-item-group>.sdpi-item>input[type="color"]{margin-top:0.4em;margin-right:4px}
|
||||
.full,.full *,.sdpi-item-value.full,.sdpi-item-child>full>*,.sdpi-item-child.full,.sdpi-item-child.full>*,.full>.sdpi-item-child,.full>.sdpi-item-child>*{display:flex;flex:1 1 0;margin-bottom:4px;margin-left:0px;width:100%;justify-content:space-evenly}
|
||||
.sdpi-item-group>.sdpi-item>input[type="color"]{margin-top:0px}
|
||||
::-webkit-calendar-picker-indicator:focus,input[type=file]::-webkit-file-upload-button:focus,button:focus,textarea:focus,input:focus,select:focus,option:focus,details:focus,summary:focus,.custom-select select{outline:none}
|
||||
summary{cursor:default;padding-left:90px;padding-right:70px}
|
||||
.pointer,summary .pointer{cursor:pointer}
|
||||
details *{font-size:12px;font-weight:normal;word-break:break-all;}
|
||||
details.message{padding:4px 18px 4px 12px}
|
||||
details.message summary{min-height:18px}
|
||||
details.message:first-child{margin-top:4px;margin-left:0;padding-left:102px}
|
||||
details.message h1{text-align:left}
|
||||
.message>summary::-webkit-details-marker{display:none}
|
||||
.info20,.question,.caution,.info{background-repeat:no-repeat;background-position:72px center}
|
||||
.info20{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cpath fill='%23999' d='M10,20 C4.4771525,20 0,15.5228475 0,10 C0,4.4771525 4.4771525,0 10,0 C15.5228475,0 20,4.4771525 20,10 C20,15.5228475 15.5228475,20 10,20 Z M10,8 C8.8954305,8 8,8.84275812 8,9.88235294 L8,16.1176471 C8,17.1572419 8.8954305,18 10,18 C11.1045695,18 12,17.1572419 12,16.1176471 L12,9.88235294 C12,8.84275812 11.1045695,8 10,8 Z M10,3 C8.8954305,3 8,3.88165465 8,4.96923077 L8,5.03076923 C8,6.11834535 8.8954305,7 10,7 C11.1045695,7 12,6.11834535 12,5.03076923 L12,4.96923077 C12,3.88165465 11.1045695,3 10,3 Z'/%3E%3C/svg%3E%0A")}
|
||||
.info{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cpath fill='%23999' d='M10,18 C5.581722,18 2,14.418278 2,10 C2,5.581722 5.581722,2 10,2 C14.418278,2 18,5.581722 18,10 C18,14.418278 14.418278,18 10,18 Z M10,8 C9.44771525,8 9,8.42137906 9,8.94117647 L9,14.0588235 C9,14.5786209 9.44771525,15 10,15 C10.5522847,15 11,14.5786209 11,14.0588235 L11,8.94117647 C11,8.42137906 10.5522847,8 10,8 Z M10,5 C9.44771525,5 9,5.44082732 9,5.98461538 L9,6.01538462 C9,6.55917268 9.44771525,7 10,7 C10.5522847,7 11,6.55917268 11,6.01538462 L11,5.98461538 C11,5.44082732 10.5522847,5 10,5 Z'/%3E%3C/svg%3E%0A")}
|
||||
.info2{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 15 15'%3E%3Cpath fill='%23999' d='M7.5,15 C3.35786438,15 0,11.6421356 0,7.5 C0,3.35786438 3.35786438,0 7.5,0 C11.6421356,0 15,3.35786438 15,7.5 C15,11.6421356 11.6421356,15 7.5,15 Z M7.5,2 C6.67157287,2 6,2.66124098 6,3.47692307 L6,3.52307693 C6,4.33875902 6.67157287,5 7.5,5 C8.32842705,5 9,4.33875902 9,3.52307693 L9,3.47692307 C9,2.66124098 8.32842705,2 7.5,2 Z M5,6 L5,7.02155172 L6,7 L6,12 L5,12.0076778 L5,13 L10,13 L10,12 L9,12.0076778 L9,6 L5,6 Z'/%3E%3C/svg%3E%0A")}
|
||||
.sdpi-more-info{background-image:linear-gradient(to right,#00000000 0%,#00000040 80%),url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpolygon fill='%23999' points='4 7 8 7 8 5 12 8 8 11 8 9 4 9'/%3E%3C/svg%3E%0A")}
|
||||
.caution{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cpath fill='%23999' fill-rule='evenodd' d='M9.03952676,0.746646542 C9.57068894,-0.245797319 10.4285735,-0.25196227 10.9630352,0.746646542 L19.7705903,17.2030214 C20.3017525,18.1954653 19.8777595,19 18.8371387,19 L1.16542323,19 C0.118729947,19 -0.302490098,18.2016302 0.231971607,17.2030214 L9.03952676,0.746646542 Z M10,2.25584053 L1.9601405,17.3478261 L18.04099,17.3478261 L10,2.25584053 Z M10,5.9375 C10.531043,5.9375 10.9615385,6.37373537 10.9615385,6.91185897 L10.9615385,11.6923077 C10.9615385,12.2304313 10.531043,12.6666667 10,12.6666667 C9.46895697,12.6666667 9.03846154,12.2304313 9.03846154,11.6923077 L9.03846154,6.91185897 C9.03846154,6.37373537 9.46895697,5.9375 10,5.9375 Z M10,13.4583333 C10.6372516,13.4583333 11.1538462,13.9818158 11.1538462,14.6275641 L11.1538462,14.6641026 C11.1538462,15.3098509 10.6372516,15.8333333 10,15.8333333 C9.36274837,15.8333333 8.84615385,15.3098509 8.84615385,14.6641026 L8.84615385,14.6275641 C8.84615385,13.9818158 9.36274837,13.4583333 10,13.4583333 Z'/%3E%3C/svg%3E%0A")}
|
||||
.question{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cpath fill='%23999' d='M10,18 C5.581722,18 2,14.418278 2,10 C2,5.581722 5.581722,2 10,2 C14.418278,2 18,5.581722 18,10 C18,14.418278 14.418278,18 10,18 Z M6.77783203,7.65332031 C6.77783203,7.84798274 6.85929281,8.02888914 7.0222168,8.19604492 C7.18514079,8.36320071 7.38508996,8.44677734 7.62207031,8.44677734 C8.02409055,8.44677734 8.29703704,8.20768468 8.44091797,7.72949219 C8.59326248,7.27245865 8.77945854,6.92651485 8.99951172,6.69165039 C9.2195649,6.45678594 9.56233491,6.33935547 10.027832,6.33935547 C10.4256205,6.33935547 10.7006836,6.37695313 11.0021973,6.68847656 C11.652832,7.53271484 10.942627,8.472229 10.3750916,9.1321106 C9.80755615,9.79199219 8.29492188,11.9897461 10.027832,12.1347656 C10.4498423,12.1700818 10.7027991,11.9147157 10.7832031,11.4746094 C11.0021973,9.59857178 13.1254883,8.82415771 13.1254883,7.53271484 C13.1254883,7.07568131 12.9974785,6.65250846 12.7414551,6.26318359 C12.4854317,5.87385873 12.1225609,5.56600048 11.652832,5.33959961 C11.1831031,5.11319874 10.6414419,5 10.027832,5 C9.36767248,5 8.79004154,5.13541531 8.29492187,5.40625 C7.79980221,5.67708469 7.42317837,6.01879677 7.16503906,6.43139648 C6.90689975,6.8439962 6.77783203,7.25130007 6.77783203,7.65332031 Z M10.0099668,15 C10.2713191,15 10.5016601,14.9108147 10.7009967,14.7324415 C10.9003332,14.5540682 11,14.3088087 11,13.9966555 C11,13.7157177 10.9047629,13.4793767 10.7142857,13.2876254 C10.5238086,13.0958742 10.2890379,13 10.0099668,13 C9.72646591,13 9.48726565,13.0958742 9.2923588,13.2876254 C9.09745196,13.4793767 9,13.7157177 9,13.9966555 C9,14.313268 9.10077419,14.5596424 9.30232558,14.735786 C9.50387698,14.9119295 9.73975502,15 10.0099668,15 Z'/%3E%3C/svg%3E%0A")}
|
||||
.sdpi-more-info{position:fixed;left:0px;right:0px;bottom:0px;min-height:16px;padding-right:16px;text-align:right;-webkit-touch-callout:none;cursor:pointer;user-select:none;background-position:right center;background-repeat:no-repeat;border-radius:var(--sdpi-borderradius);text-decoration:none;color:var(--sdpi-color)}
|
||||
.sdpi-more-info-button{display:flex;align-self:right;margin-left:auto;position:fixed;right:17px;bottom:0px;user-select:none}
|
||||
.sdpi-bottom-bar{display:flex;align-self:right;margin-left:auto;position:fixed;right:17px;bottom:0px;user-select:none}
|
||||
.sdpi-bottom-bar.right{right:0px}
|
||||
.sdpi-bottom-bar button{min-height:20px !important;height:20px !important}
|
||||
details a{background-position:right !important;min-height:24px;display:inline-block;line-height:24px;padding-right:28px}
|
||||
input:not([type="range"]),textarea{-webkit-appearance:none;appearance:none;background:var(--sdpi-background);color:var(--sdpi-color);font-weight:normal;font-size:9pt;border:none;margin-top:2px;margin-bottom:2px;min-width:219px}
|
||||
textarea+label{display:flex;justify-content:flex-end}
|
||||
input[type="radio"],input[type="checkbox"]{display:none}
|
||||
input[type="radio"]+label,input[type="checkbox"]+label{font-size:9pt;color:var(--sdpi-color);font-weight:normal;margin-right:8px}
|
||||
input[type="radio"]+label:after,input[type="checkbox"]+label:after{content:" " !important}
|
||||
.sdpi-item[type="radio"]>.sdpi-item-value,.sdpi-item[type="checkbox"]>.sdpi-item-value{padding-top:2px}
|
||||
.sdpi-item[type="checkbox"]>.sdpi-item-value>*{margin-top:4px}
|
||||
.sdpi-item[type="checkbox"] .sdpi-item-child,.sdpi-item[type="radio"] .sdpi-item-child{display:inline-block}
|
||||
.sdpi-item[type="range"] .sdpi-item-value,.sdpi-item[type="meter"] .sdpi-item-child,.sdpi-item[type="progress"] .sdpi-item-child{display:flex}
|
||||
.sdpi-item[type="range"] .sdpi-item-value{min-height:26px}
|
||||
.sdpi-item[type="range"] .sdpi-item-value span,.sdpi-item[type="meter"] .sdpi-item-child span,.sdpi-item[type="progress"] .sdpi-item-child span{margin-top:-2px;min-width:8px;text-align:right;user-select:none;cursor:pointer;-webkit-user-select:none;user-select:none}
|
||||
.sdpi-item[type="range"] .sdpi-item-value span{margin-top:7px;text-align:right}
|
||||
span+input[type="range"]{display:flex;max-width:168px}
|
||||
.sdpi-item[type="range"] .sdpi-item-value span:first-child,.sdpi-item[type="meter"] .sdpi-item-child span:first-child,.sdpi-item[type="progress"] .sdpi-item-child span:first-child{margin-right:4px}
|
||||
.sdpi-item[type="range"] .sdpi-item-value span:last-child,.sdpi-item[type="meter"] .sdpi-item-child span:last-child,.sdpi-item[type="progress"] .sdpi-item-child span:last-child{margin-left:4px}
|
||||
.reverse{transform:rotate(180deg)}
|
||||
.sdpi-item[type="meter"] .sdpi-item-child meter+span:last-child{margin-left:-10px}
|
||||
.sdpi-item[type="progress"] .sdpi-item-child meter+span:last-child{margin-left:-14px}
|
||||
.sdpi-item[type="radio"]>.sdpi-item-value>*{margin-top:2px}
|
||||
details{padding:8px 18px 8px 12px;min-width:86px}
|
||||
details>h4{border-bottom:1px solid var(--sdpi-bordercolor)}
|
||||
legend{display:none}
|
||||
.sdpi-item-value>textarea{padding:0px;width:219px;margin-left:1px;margin-top:3px;padding:4px}
|
||||
input[type="radio"]+label span,input[type="checkbox"]+label span{display:inline-block;width:16px;height:16px;margin:2px 4px 2px 0;border-radius:3px;vertical-align:middle;background:var(--sdpi-background);cursor:pointer;border:1px solid rgb(0,0,0,.2)}
|
||||
input[type="radio"]+label span{border-radius:100%}
|
||||
input[type="radio"]:checked+label span,input[type="checkbox"]:checked+label span{background-color:#77f;background-image:url(check.svg);background-repeat:no-repeat;background-position:center center;border:1px solid rgb(0,0,0,.4)}
|
||||
input[type="radio"]:active:checked+label span,input[type="radio"]:active+label span,input[type="checkbox"]:active:checked+label span,input[type="checkbox"]:active+label span{background-color:#303030}
|
||||
input[type="radio"]:checked+label span{background-image:url(rcheck.svg)}
|
||||
input[type="range"]{width:var(--sdpi-width);height:30px;overflow:hidden;cursor:pointer;background:transparent !important}
|
||||
.sdpi-item>input[type="range"]{margin-left:2px;max-width:var(--sdpi-width);width:var(--sdpi-width);padding:0px;margin-top:2px}
|
||||
input[type="range"]::-webkit-slider-runnable-track{height:5px;background:#979797;border-radius:3px;padding:0px !important;border:1px solid var(--sdpi-background)}
|
||||
input[type="range"]::-webkit-slider-thumb{position:relative;-webkit-appearance:none;background-color:var(--sdpi-color);width:12px;height:12px;border-radius:20px;margin-top:-5px;border:none}
|
||||
input[type="range" i]{margin:0}
|
||||
input[type="range"]::-webkit-slider-thumb::before{position:absolute;content:"";height:5px;width:500px;left:-502px;top:8px;background:#77f}
|
||||
input[type="color"]{min-width:32px;min-height:32px;width:32px;height:32px;padding:0;background-color:var(--sdpi-bgcolor);flex:none}
|
||||
::-webkit-color-swatch{min-width:24px}
|
||||
textarea{height:3em;word-break:break-word;line-height:1.5em}
|
||||
.textarea{padding:0px !important}
|
||||
textarea{width:219px;height:96%;min-height:6em;resize:none;border-radius:var(--sdpi-borderradius)}
|
||||
.sdpi-item.card-carousel-wrapper,.sdpi-item>.card-carousel-wrapper{padding:0}
|
||||
.card-carousel-wrapper{display:flex;align-items:center;justify-content:center;margin:12px auto;color:#666a73}
|
||||
.card-carousel{display:flex;justify-content:center;width:278px}
|
||||
.card-carousel--overflow-container{overflow:hidden}
|
||||
.card-carousel--nav__left,.card-carousel--nav__right{width:12px;height:12px;border-top:2px solid #42b883;border-right:2px solid #42b883;cursor:pointer;margin:0 4px;transition:transform 150ms linear}
|
||||
.card-carousel--nav__left[disabled],.card-carousel--nav__right[disabled]{opacity:0.2;border-color:black}
|
||||
.card-carousel--nav__left{transform:rotate(-135deg)}
|
||||
.card-carousel--nav__left:active{transform:rotate(-135deg) scale(0.85)}
|
||||
.card-carousel--nav__right{transform:rotate(45deg)}
|
||||
.card-carousel--nav__right:active{transform:rotate(45deg) scale(0.85)}
|
||||
.card-carousel-cards{display:flex;transition:transform 150ms ease-out;transform:translatex(0px)}
|
||||
.card-carousel-cards .card-carousel--card{margin:0 5px;cursor:pointer;background-color:#fff;border-radius:4px;z-index:3}
|
||||
.xxcard-carousel-cards .card-carousel--card:first-child{margin-left:0}
|
||||
.xxcard-carousel-cards .card-carousel--card:last-child{margin-right:0}
|
||||
.card-carousel-cards .card-carousel--card img{vertical-align:bottom;border-top-left-radius:4px;border-top-right-radius:4px;transition:opacity 150ms linear;width:60px}
|
||||
.card-carousel-cards .card-carousel--card img:hover{opacity:0.5}
|
||||
.card-carousel-cards .card-carousel--card--footer{border-top:0;max-width:80px;overflow:hidden;display:flex;height:100%;flex-direction:column}
|
||||
.card-carousel-cards .card-carousel--card--footer p{padding:3px 0;margin:0;margin-bottom:2px;font-size:15px;font-weight:500;color:#2c3e50}
|
||||
.card-carousel-cards .card-carousel--card--footer p:nth-of-type(2){font-size:12px;font-weight:300;padding:6px;color:#666a73}
|
||||
h1{font-size:1.3em;font-weight:500;text-align:center;margin-bottom:12px}
|
||||
::-webkit-datetime-edit{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";background:url(elg_calendar_inv.svg) no-repeat left center;padding-right:1em;padding-left:25px;background-position:4px 0px}
|
||||
::-webkit-calendar-picker-indicator{background:transparent;font-size:17px}
|
||||
::-webkit-calendar-picker-indicator:focus{background-color:rgba(0,0,0,0.2)}
|
||||
input[type="date"]{-webkit-align-items:center;align-items:center;display:-webkit-inline-flex;font-family:monospace;overflow:hidden;padding:0;-webkit-padding-start:1px}
|
||||
input::-webkit-datetime-edit{-webkit-flex:1;-webkit-user-modify:read-only !important;display:inline-block;min-width:0;overflow:hidden}
|
||||
input[type="file"]{opacity:0;display:none}
|
||||
.sdpi-item>input[type="file"]{opacity:1;display:flex}
|
||||
input[type="file"]+span{display:flex;flex:0 1 auto;background-color:#0000ff50}
|
||||
label.sdpi-file-label{cursor:pointer;user-select:none;display:inline-block;min-height:21px !important;height:21px !important;line-height:20px;padding:0px 4px;margin:auto;margin-right:0px}
|
||||
.sdpi-file-label>label:active,.sdpi-file-label.file:active,label.sdpi-file-label:active,label.sdpi-file-info:active,input[type="file"]::-webkit-file-upload-button:active,button:active{background-color:var(--sdpi-color);color:#303030}
|
||||
input:required:invalid,input:focus:invalid{background:var(--sdpi-background) url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5IiBoZWlnaHQ9IjkiIHZpZXdCb3g9IjAgMCA5IDkiPgogICAgPHBhdGggZmlsbD0iI0Q4RDhEOCIgZD0iTTQuNSwwIEM2Ljk4NTI4MTM3LC00LjU2NTM4NzgyZS0xNiA5LDIuMDE0NzE4NjMgOSw0LjUgQzksNi45ODUyODEzNyA2Ljk4NTI4MTM3LDkgNC41LDkgQzIuMDE0NzE4NjMsOSAzLjA0MzU5MTg4ZS0xNiw2Ljk4NTI4MTM3IDAsNC41IEMtMy4wNDM1OTE4OGUtMTYsMi4wMTQ3MTg2MyAyLjAxNDcxODYzLDQuNTY1Mzg3ODJlLTE2IDQuNSwwIFogTTQsMSBMNCw2IEw1LDYgTDUsMSBMNCwxIFogTTQuNSw4IEM0Ljc3NjE0MjM3LDggNSw3Ljc3NjE0MjM3IDUsNy41IEM1LDcuMjIzODU3NjMgNC43NzYxNDIzNyw3IDQuNSw3IEM0LjIyMzg1NzYzLDcgNCw3LjIyMzg1NzYzIDQsNy41IEM0LDcuNzc2MTQyMzcgNC4yMjM4NTc2Myw4IDQuNSw4IFoiLz4KICA8L3N2Zz4) no-repeat 98% center}
|
||||
input:required:valid{background:var(--sdpi-background) url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5IiBoZWlnaHQ9IjkiIHZpZXdCb3g9IjAgMCA5IDkiPjxwb2x5Z29uIGZpbGw9IiNEOEQ4RDgiIHBvaW50cz0iNS4yIDEgNi4yIDEgNi4yIDcgMy4yIDcgMy4yIDYgNS4yIDYiIHRyYW5zZm9ybT0icm90YXRlKDQwIDQuNjc3IDQpIi8+PC9zdmc+) no-repeat 98% center}
|
||||
.tooltip,:tooltip,:title{color:yellow}
|
||||
.sdpi-item-group.file{width:232px;display:flex;align-items:center}
|
||||
.sdpi-file-info{overflow-wrap:break-word;word-wrap:break-word;hyphens:auto;min-width:132px;max-width:144px;max-height:32px;margin-top:0px;margin-left:5px;display:inline-block;overflow:hidden;padding:6px 4px;background-color:var(--sdpi-background)}
|
||||
::-webkit-scrollbar{width:8px}
|
||||
::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,0.3)}
|
||||
::-webkit-scrollbar-thumb{background-color:#999999;outline:1px solid slategrey;border-radius:8px}
|
||||
a{color:#7397d2}
|
||||
.testcontainer{display:flex;background-color:#0000ff20;max-width:400px;height:200px;align-content:space-evenly}
|
||||
input[type=range]{-webkit-appearance:none;appearance:none;height:6px;margin-top:12px;z-index:0;overflow:visible}
|
||||
:-webkit-slider-thumb{-webkit-appearance:none;background-color:var(--sdpi-color);width:16px;height:16px;border-radius:20px;margin-top:-6px;border:1px solid #999999}
|
||||
.sdpi-item[type="range"] .sdpi-item-group{display:flex;flex-direction:column}
|
||||
.xxsdpi-item[type="range"] .sdpi-item-group input{max-width:204px}
|
||||
.sdpi-item[type="range"] .sdpi-item-group span{margin-left:0px !important}
|
||||
.sdpi-item[type="range"] .sdpi-item-group>.sdpi-item-child{display:flex;flex-direction:row}
|
||||
.rangeLabel{position:absolute;font-weight:normal;margin-top:22px}
|
||||
:disabled{color:#993333}
|
||||
select,select option{color:var(--sdpi-color)}
|
||||
select.disabled,select option:disabled{color:#fd9494;font-style:italic}
|
||||
.runningAppsContainer{display:none}
|
||||
.one-line{min-height:1.5em}
|
||||
.two-lines{min-height:3em}
|
||||
.three-lines{min-height:4.5em}
|
||||
.four-lines{min-height:6em}
|
||||
.min80>.sdpi-item-child{min-width:80px}
|
||||
.min100>.sdpi-item-child{min-width:100px}
|
||||
.min120>.sdpi-item-child{min-width:120px}
|
||||
.min140>.sdpi-item-child{min-width:140px}
|
||||
.min160>.sdpi-item-child{min-width:160px}
|
||||
.min200>.sdpi-item-child{min-width:200px}
|
||||
.max40{flex-basis:40%;flex-grow:0}
|
||||
.max30{flex-basis:30%;flex-grow:0}
|
||||
.max20{flex-basis:20%;flex-grow:0}
|
||||
.up20{margin-top:-20px}
|
||||
.alignCenter{align-items:center}
|
||||
.alignTop{align-items:flex-start}
|
||||
.alignBaseline{align-items:baseline}
|
||||
.noMargins,.noMargins *,.noInnerMargins *{margin:0;padding:0}
|
||||
.hidden{display:none}
|
||||
.icon-help,.icon-help-line,.icon-help-fill,.icon-help-inv,.icon-brighter,.icon-darker,.icon-warmer,.icon-cooler{min-width:20px;width:20px;background-repeat:no-repeat;opacity:1}
|
||||
.icon-help:active,.icon-help-line:active,.icon-help-fill:active,.icon-help-inv:active,.icon-brighter:active,.icon-darker:active,.icon-warmer:active,.icon-cooler:active{opacity:0.5}
|
||||
.icon-brighter,.icon-darker,.icon-warmer,.icon-cooler{margin-top:5px !important}
|
||||
.icon-help,.icon-help-line,.icon-help-fill,.icon-help-inv{cursor:pointer;margin:0px;margin-left:4px}
|
||||
.icon-brighter{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cg fill='%23999' fill-rule='evenodd'%3E%3Ccircle cx='10' cy='10' r='4'/%3E%3Cpath d='M14.8532861,7.77530426 C14.7173255,7.4682615 14.5540843,7.17599221 14.3666368,6.90157083 L16.6782032,5.5669873 L17.1782032,6.4330127 L14.8532861,7.77530426 Z M10.5,4.5414007 C10.2777625,4.51407201 10.051423,4.5 9.82179677,4.5 C9.71377555,4.5 9.60648167,4.50311409 9.5,4.50925739 L9.5,2 L10.5,2 L10.5,4.5414007 Z M5.38028092,6.75545367 C5.18389364,7.02383457 5.01124349,7.31068015 4.86542112,7.61289977 L2.82179677,6.4330127 L3.32179677,5.5669873 L5.38028092,6.75545367 Z M4.86542112,12.3871002 C5.01124349,12.6893198 5.18389364,12.9761654 5.38028092,13.2445463 L3.32179677,14.4330127 L2.82179677,13.5669873 L4.86542112,12.3871002 Z M9.5,15.4907426 C9.60648167,15.4968859 9.71377555,15.5 9.82179677,15.5 C10.051423,15.5 10.2777625,15.485928 10.5,15.4585993 L10.5,18 L9.5,18 L9.5,15.4907426 Z M14.3666368,13.0984292 C14.5540843,12.8240078 14.7173255,12.5317385 14.8532861,12.2246957 L17.1782032,13.5669873 L16.6782032,14.4330127 L14.3666368,13.0984292 Z'/%3E%3C/g%3E%3C/svg%3E")}
|
||||
.icon-darker{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cg fill='%23999' fill-rule='evenodd'%3E%3Cpath d='M10 14C7.790861 14 6 12.209139 6 10 6 7.790861 7.790861 6 10 6 12.209139 6 14 7.790861 14 10 14 12.209139 12.209139 14 10 14zM10 13C11.6568542 13 13 11.6568542 13 10 13 8.34314575 11.6568542 7 10 7 8.34314575 7 7 8.34314575 7 10 7 11.6568542 8.34314575 13 10 13zM14.8532861 7.77530426C14.7173255 7.4682615 14.5540843 7.17599221 14.3666368 6.90157083L16.6782032 5.5669873 17.1782032 6.4330127 14.8532861 7.77530426zM10.5 4.5414007C10.2777625 4.51407201 10.051423 4.5 9.82179677 4.5 9.71377555 4.5 9.60648167 4.50311409 9.5 4.50925739L9.5 2 10.5 2 10.5 4.5414007zM5.38028092 6.75545367C5.18389364 7.02383457 5.01124349 7.31068015 4.86542112 7.61289977L2.82179677 6.4330127 3.32179677 5.5669873 5.38028092 6.75545367zM4.86542112 12.3871002C5.01124349 12.6893198 5.18389364 12.9761654 5.38028092 13.2445463L3.32179677 14.4330127 2.82179677 13.5669873 4.86542112 12.3871002zM9.5 15.4907426C9.60648167 15.4968859 9.71377555 15.5 9.82179677 15.5 10.051423 15.5 10.2777625 15.485928 10.5 15.4585993L10.5 18 9.5 18 9.5 15.4907426zM14.3666368 13.0984292C14.5540843 12.8240078 14.7173255 12.5317385 14.8532861 12.2246957L17.1782032 13.5669873 16.6782032 14.4330127 14.3666368 13.0984292z'/%3E%3C/g%3E%3C/svg%3E")}
|
||||
.icon-warmer{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cg fill='%23999' fill-rule='evenodd'%3E%3Cpath d='M12.3247275 11.4890349C12.0406216 11.0007637 11.6761954 10.5649925 11.2495475 10.1998198 11.0890394 9.83238991 11 9.42659309 11 9 11 7.34314575 12.3431458 6 14 6 15.6568542 6 17 7.34314575 17 9 17 10.6568542 15.6568542 12 14 12 13.3795687 12 12.8031265 11.8116603 12.3247275 11.4890349zM17.6232392 11.6692284C17.8205899 11.4017892 17.9890383 11.1117186 18.123974 10.8036272L20.3121778 12.0669873 19.8121778 12.9330127 17.6232392 11.6692284zM18.123974 7.19637279C17.9890383 6.88828142 17.8205899 6.5982108 17.6232392 6.33077158L19.8121778 5.0669873 20.3121778 5.9330127 18.123974 7.19637279zM14.5 4.52746439C14.3358331 4.50931666 14.1690045 4.5 14 4.5 13.8309955 4.5 13.6641669 4.50931666 13.5 4.52746439L13.5 2 14.5 2 14.5 4.52746439zM13.5 13.4725356C13.6641669 13.4906833 13.8309955 13.5 14 13.5 14.1690045 13.5 14.3358331 13.4906833 14.5 13.4725356L14.5 16 13.5 16 13.5 13.4725356zM14 11C15.1045695 11 16 10.1045695 16 9 16 7.8954305 15.1045695 7 14 7 12.8954305 7 12 7.8954305 12 9 12 10.1045695 12.8954305 11 14 11zM9.5 11C10.6651924 11.4118364 11.5 12.5 11.5 14 11.5 16 10 17.5 8 17.5 6 17.5 4.5 16 4.5 14 4.5 12.6937812 5 11.5 6.5 11L6.5 7 9.5 7 9.5 11z'/%3E%3Cpath d='M12,14 C12,16.209139 10.209139,18 8,18 C5.790861,18 4,16.209139 4,14 C4,12.5194353 4.80439726,11.2267476 6,10.5351288 L6,4 C6,2.8954305 6.8954305,2 8,2 C9.1045695,2 10,2.8954305 10,4 L10,10.5351288 C11.1956027,11.2267476 12,12.5194353 12,14 Z M11,14 C11,12.6937812 10.1651924,11.5825421 9,11.1707057 L9,4 C9,3.44771525 8.55228475,3 8,3 C7.44771525,3 7,3.44771525 7,4 L7,11.1707057 C5.83480763,11.5825421 5,12.6937812 5,14 C5,15.6568542 6.34314575,17 8,17 C9.65685425,17 11,15.6568542 11,14 Z'/%3E%3C/g%3E%3C/svg%3E")}
|
||||
.icon-cooler{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cg fill='%23999' fill-rule='evenodd'%3E%3Cpath d='M10.4004569 11.6239517C10.0554735 10.9863849 9.57597206 10.4322632 9 9.99963381L9 9.7450467 9.53471338 9.7450467 10.8155381 8.46422201C10.7766941 8.39376637 10.7419749 8.32071759 10.7117062 8.2454012L9 8.2454012 9 6.96057868 10.6417702 6.96057868C10.6677696 6.86753378 10.7003289 6.77722682 10.7389179 6.69018783L9.44918707 5.40045694 9 5.40045694 9 4.34532219 9.32816127 4.34532219 9.34532219 2.91912025 10.4004569 2.91912025 10.4004569 4.53471338 11.6098599 5.74411634C11.7208059 5.68343597 11.8381332 5.63296451 11.9605787 5.59396526L11.9605787 3.8884898 10.8181818 2.74609294 11.5642748 2 12.5727518 3.00847706 13.5812289 2 14.3273218 2.74609294 13.2454012 3.82801356 13.2454012 5.61756719C13.3449693 5.65339299 13.4408747 5.69689391 13.5324038 5.74735625L14.7450467 4.53471338 14.7450467 2.91912025 15.8001815 2.91912025 15.8001815 4.34532219 17.2263834 4.34532219 17.2263834 5.40045694 15.6963166 5.40045694 14.4002441 6.69652946C14.437611 6.78161093 14.4692249 6.86979146 14.4945934 6.96057868L16.2570138 6.96057868 17.3994107 5.81818182 18.1455036 6.56427476 17.1370266 7.57275182 18.1455036 8.58122888 17.3994107 9.32732182 16.3174901 8.2454012 14.4246574 8.2454012C14.3952328 8.31861737 14.3616024 8.38969062 14.3240655 8.45832192L15.6107903 9.7450467 17.2263834 9.7450467 17.2263834 10.8001815 15.8001815 10.8001815 15.8001815 12.2263834 14.7450467 12.2263834 14.7450467 10.6963166 13.377994 9.32926387C13.3345872 9.34850842 13.2903677 9.36625331 13.2454012 9.38243281L13.2454012 11.3174901 14.3273218 12.3994107 13.5812289 13.1455036 12.5848864 12.1491612 11.5642748 13.1455036 10.8181818 12.3994107 11.9605787 11.2570138 11.9605787 9.40603474C11.8936938 9.38473169 11.828336 9.36000556 11.7647113 9.33206224L10.4004569 10.6963166 10.4004569 11.6239517zM12.75 8.5C13.3022847 8.5 13.75 8.05228475 13.75 7.5 13.75 6.94771525 13.3022847 6.5 12.75 6.5 12.1977153 6.5 11.75 6.94771525 11.75 7.5 11.75 8.05228475 12.1977153 8.5 12.75 8.5zM9.5 14C8.5 16.3333333 7.33333333 17.5 6 17.5 4.66666667 17.5 3.5 16.3333333 2.5 14L9.5 14z'/%3E%3Cpath d='M10,14 C10,16.209139 8.209139,18 6,18 C3.790861,18 2,16.209139 2,14 C2,12.5194353 2.80439726,11.2267476 4,10.5351288 L4,4 C4,2.8954305 4.8954305,2 6,2 C7.1045695,2 8,2.8954305 8,4 L8,10.5351288 C9.19560274,11.2267476 10,12.5194353 10,14 Z M9,14 C9,12.6937812 8.16519237,11.5825421 7,11.1707057 L7,4 C7,3.44771525 6.55228475,3 6,3 C5.44771525,3 5,3.44771525 5,4 L5,11.1707057 C3.83480763,11.5825421 3,12.6937812 3,14 C3,15.6568542 4.34314575,17 6,17 C7.65685425,17 9,15.6568542 9,14 Z'/%3E%3C/g%3E%3C/svg%3E")}
|
||||
.icon-help{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20'%3E%3Cpath fill='%23999' d='M11.292 12.516l.022 1.782H9.07v-1.804c0-1.98 1.276-2.574 2.662-3.278h-.022c.814-.44 1.65-.88 1.694-2.2.044-1.386-1.122-2.728-3.234-2.728-1.518 0-2.662.902-3.366 2.354L5 5.608C5.946 3.584 7.662 2 10.17 2c3.564 0 5.632 2.442 5.588 5.06-.066 2.618-1.716 3.41-3.102 4.158-.704.374-1.364.682-1.364 1.298zm-1.122 2.442c.858 0 1.452.594 1.452 1.452 0 .682-.594 1.408-1.452 1.408-.77 0-1.386-.726-1.386-1.408 0-.858.616-1.452 1.386-1.452z'/%3E%3C/svg%3E")}
|
||||
.icon-help-line{background-image:url("data:image/svg+xml,%3Csvg width='20' height='20' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23999' fill-rule='evenodd'%3E%3Cpath d='M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-1a9 9 0 1 0 0-18 9 9 0 0 0 0 18z'/%3E%3Cpath d='M10.848 12.307l.02 1.578H8.784v-1.597c0-1.753 1.186-2.278 2.474-2.901h-.02c.756-.39 1.533-.78 1.574-1.948.041-1.226-1.043-2.414-3.006-2.414-1.41 0-2.474.798-3.128 2.083L5 6.193C5.88 4.402 7.474 3 9.805 3 13.118 3 15.04 5.161 15 7.478c-.061 2.318-1.595 3.019-2.883 3.68-.654.332-1.268.604-1.268 1.15zM9.805 14.47c.798 0 1.35.525 1.35 1.285 0 .603-.552 1.246-1.35 1.246-.715 0-1.288-.643-1.288-1.246 0-.76.573-1.285 1.288-1.285z' fill-rule='nonzero'/%3E%3C/g%3E%3C/svg%3E")}
|
||||
.icon-help-fill{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Ccircle cx='10' cy='10' r='10' fill='%23999'/%3E%3Cpath fill='%23FFF' fill-rule='nonzero' d='M8.368 7.189H5C5 3.5 7.668 2 10.292 2 13.966 2 16 4.076 16 7.012c0 3.754-3.849 3.136-3.849 5.211v1.656H8.455v-1.832c0-2.164 1.4-2.893 2.778-3.6.437-.242 1.006-.574 1.006-1.236 0-2.208-3.871-2.142-3.871-.022zM10.25 18a1.75 1.75 0 1 1 0-3.5 1.75 1.75 0 0 1 0 3.5z'/%3E%3C/g%3E%3C/svg%3E")}
|
||||
.icon-help-inv{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20'%3E%3Cpath fill='%23999' fill-rule='evenodd' d='M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zM8.368 7.189c0-2.12 3.87-2.186 3.87.022 0 .662-.568.994-1.005 1.236-1.378.707-2.778 1.436-2.778 3.6v1.832h3.696v-1.656c0-2.075 3.849-1.457 3.849-5.21C16 4.075 13.966 2 10.292 2 7.668 2 5 3.501 5 7.189h3.368zM10.25 18a1.75 1.75 0 1 0 0-3.5 1.75 1.75 0 0 0 0 3.5z'/%3E%3C/svg%3E")}
|
||||
.kelvin::after{content:"K"}
|
||||
.mired::after{content:" Mired"}
|
||||
.percent::after{content:"%"}
|
||||
.sdpi-item-value+.icon-cooler,.sdpi-item-value+.icon-warmer{margin-left:0px !important;margin-top:15px !important}
|
||||
input[type="range"].colorbrightness::-webkit-slider-runnable-track,input[type="range"].colortemperature::-webkit-slider-runnable-track{height:8px;background:#979797;border-radius:4px;background-image:linear-gradient(to right,#94d0ec,#ffb165)}
|
||||
input[type="range"].colorbrightness::-webkit-slider-runnable-track{background-color:#efefef;background-image:linear-gradient(to right,black,rgba(0,0,0,0))}
|
||||
input[type="range"].colorbrightness::-webkit-slider-thumb,input[type="range"].colortemperature::-webkit-slider-thumb{width:16px;height:16px;border-radius:20px;margin-top:-5px;background-color:#86c6e8;box-shadow:0px 0px 1px #000000;border:1px solid #d8d8d8}
|
||||
.sdpi-info-label{display:inline-block;user-select:none;position:absolute;height:15px;width:auto;text-align:center;border-radius:4px;min-width:44px;max-width:80px;background:white;font-size:11px;color:black;z-index:1000;box-shadow:0px 0px 12px rgba(0,0,0,.8);padding:2px}
|
||||
.sdpi-info-label.hidden{opacity:0;transition:opacity 0.25s linear}
|
||||
.sdpi-info-label.shown{position:absolute;opacity:1;transition:opacity 0.25s ease-out}
|
||||
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/static/default.jpg
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/static/default.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/zh_CN.json
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/SDJavaScriptSDK/com.mirabox.streamdock.xxx.sdPlugin/zh_CN.json
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
StreamDock-Plugin-SDK/SDNodeJsSDK/com.mirabox.streamdock.demo.sdPlugin/manifest.json
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/SDNodeJsSDK/com.mirabox.streamdock.demo.sdPlugin/manifest.json
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
StreamDock-Plugin-SDK/SDNodeJsSDK/com.mirabox.streamdock.demo.sdPlugin/package.json
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/SDNodeJsSDK/com.mirabox.streamdock.demo.sdPlugin/package.json
(Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
@ -0,0 +1,46 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
console.log('开始执行自动化构建...');
|
||||
|
||||
const currentDir = __dirname;
|
||||
|
||||
// 获取父文件夹的路径
|
||||
const parentDir = path.join(currentDir, '..');
|
||||
// 获取父文件夹的名称
|
||||
const PluginName = path.basename(parentDir);
|
||||
|
||||
|
||||
const PluginPath = path.join(process.env.APPDATA, 'HotSpot/StreamDock/plugins', PluginName);
|
||||
|
||||
try {
|
||||
// 删除旧的插件目录
|
||||
fs.removeSync(PluginPath);
|
||||
|
||||
// 确保目标目录存在
|
||||
fs.ensureDirSync(path.dirname(PluginPath));
|
||||
|
||||
// 复制当前目录到目标路径,排除 node_modules
|
||||
fs.copySync(path.resolve(__dirname, '..'), PluginPath, {
|
||||
filter: (src) => {
|
||||
const relativePath = path.relative(path.resolve(__dirname, '..'), src);
|
||||
// 排除 'node_modules' 和 '.git' 目录及其子文件
|
||||
return !relativePath.startsWith('plugin\\node_modules')
|
||||
&&!relativePath.startsWith('plugin\\index.js')
|
||||
&&!relativePath.startsWith('plugin\\package.json')
|
||||
&&!relativePath.startsWith('plugin\\package-lock.json')
|
||||
&&!relativePath.startsWith('plugin\\yarn.lock')
|
||||
&&!relativePath.startsWith('plugin\\build')
|
||||
&&!relativePath.startsWith('plugin\\log')
|
||||
&&!relativePath.startsWith('.git')
|
||||
&&!relativePath.startsWith('.vscode');
|
||||
}
|
||||
});
|
||||
|
||||
fs.copySync( path.join(__dirname, "build"), path.join(PluginPath,'plugin'))
|
||||
|
||||
console.log(`插件 "${PluginName}" 已成功复制到 "${PluginPath}"`);
|
||||
console.log('构建成功-------------');
|
||||
} catch (err) {
|
||||
console.error(`复制出错 "${PluginName}":`, err);
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
const { Plugins, Actions, log } = require('./utils/plugin');
|
||||
|
||||
const plugin = new Plugins();
|
||||
|
||||
// 操作一
|
||||
plugin.action1 = new Actions({
|
||||
default: {},
|
||||
_willAppear({ context }) {
|
||||
plugin.setTitle(context, "Hello world!");
|
||||
},
|
||||
_willDisappear(data) { },
|
||||
_propertyInspectorDidAppear(data) { },
|
||||
dialRotate(data) {//旋钮旋转
|
||||
log.info(data);
|
||||
},
|
||||
dialDown(data) {//旋钮按下
|
||||
log.info(data);
|
||||
}
|
||||
});
|
||||
BIN
StreamDock-Plugin-SDK/SDNodeJsSDK/com.mirabox.streamdock.demo.sdPlugin/plugin/package.json
(Stored with Git LFS)
Normal file
BIN
StreamDock-Plugin-SDK/SDNodeJsSDK/com.mirabox.streamdock.demo.sdPlugin/plugin/package.json
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,139 @@
|
||||
// 配置日志文件
|
||||
const now = new Date();
|
||||
const log = require('log4js').configure({
|
||||
appenders: {
|
||||
file: { type: 'file', filename: `./log/${now.getFullYear()}.${now.getMonth() + 1}.${now.getDate()}.log` }
|
||||
},
|
||||
categories: {
|
||||
default: { appenders: ['file'], level: 'info' }
|
||||
}
|
||||
}).getLogger();
|
||||
|
||||
// 主线程错误处理
|
||||
process.on('uncaughtException', (error) => {
|
||||
log.error('Uncaught Exception:', error);
|
||||
});
|
||||
process.on('unhandledRejection', (reason) => {
|
||||
log.error('Unhandled Rejection:', reason);
|
||||
});
|
||||
|
||||
// 插件类
|
||||
const ws = require('ws');
|
||||
class Plugins {
|
||||
static language = process.argv[5];
|
||||
constructor() {
|
||||
if (Plugins.instance) {
|
||||
return Plugins.instance;
|
||||
}
|
||||
this.ws = new ws("ws://127.0.0.1:" + process.argv[2]);
|
||||
this.ws.on('open', () => this.ws.send(JSON.stringify({ uuid: process.argv[3], event: process.argv[4] })));
|
||||
this.ws.on('close', process.exit);
|
||||
this.ws.on('message', e => {
|
||||
const data = JSON.parse(e.toString());
|
||||
const action = data.action?.split('.').pop();
|
||||
this[action]?.[data.event]?.(data);
|
||||
this[data.event]?.(data);
|
||||
});
|
||||
Plugins.instance = this;
|
||||
}
|
||||
// 设置标题
|
||||
setTitle(context, str, row = 0, num = 6) {
|
||||
let newStr = '';
|
||||
if (row) {
|
||||
let nowRow = 1, strArr = str.split('');
|
||||
strArr.forEach((item, index) => {
|
||||
if (nowRow < row && index >= nowRow * num) { nowRow++; newStr += '\n'; }
|
||||
if (nowRow <= row && index < nowRow * num) { newStr += item; }
|
||||
});
|
||||
if (strArr.length > row * num) { newStr = newStr.substring(0, newStr.length - 1); newStr += '..'; }
|
||||
}
|
||||
this.ws.send(JSON.stringify({
|
||||
event: "setTitle",
|
||||
context, payload: {
|
||||
target: 0,
|
||||
title: newStr || str
|
||||
}
|
||||
}));
|
||||
}
|
||||
// 设置背景
|
||||
setImage(context, url) {
|
||||
const image = new Image();
|
||||
image.src = url; image.onload = () => {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = image.naturalWidth;
|
||||
canvas.height = image.naturalHeight;
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(image, 0, 0);
|
||||
this.ws.send(JSON.stringify({
|
||||
event: "setImage",
|
||||
context, payload: {
|
||||
target: 0,
|
||||
image: canvas.toDataURL("image/png")
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
// 设置状态
|
||||
setState(context, state) {
|
||||
this.ws.send(JSON.stringify({
|
||||
event: "setState",
|
||||
context, payload: { state }
|
||||
}));
|
||||
}
|
||||
// 保存持久化数据
|
||||
setSettings(context, payload) {
|
||||
this.ws.send(JSON.stringify({
|
||||
event: "setSettings",
|
||||
context, payload
|
||||
}));
|
||||
}
|
||||
// 发送给属性检测器
|
||||
sendToPropertyInspector(payload) {
|
||||
this.ws.send(JSON.stringify({
|
||||
action: Actions.currentAction,
|
||||
context: Actions.currentContext,
|
||||
payload, event: "sendToPropertyInspector"
|
||||
}));
|
||||
}
|
||||
// 用默认浏览器打开网页
|
||||
openUrl(url) {
|
||||
this.ws.send(JSON.stringify({
|
||||
event: "openUrl",
|
||||
payload: { url }
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// 操作类
|
||||
class Actions {
|
||||
constructor(data) {
|
||||
this.data = {};
|
||||
this.default = {};
|
||||
Object.assign(this, data);
|
||||
}
|
||||
// 属性检查器显示时
|
||||
static currentAction = null;
|
||||
static currentContext = null;
|
||||
propertyInspectorDidAppear(data) {
|
||||
Actions.currentAction = data.action;
|
||||
Actions.currentContext = data.context;
|
||||
this._propertyInspectorDidAppear?.(data);
|
||||
}
|
||||
// 初始化数据
|
||||
willAppear(data) {
|
||||
const { context, payload: { settings } } = data;
|
||||
this.data[context] = Object.assign({ ...this.default }, settings);
|
||||
this._willAppear?.(data);
|
||||
}
|
||||
// 行动销毁
|
||||
willDisappear(data) {
|
||||
this._willDisappear?.(data);
|
||||
delete this.data[data.context];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
log,
|
||||
Plugins,
|
||||
Actions,
|
||||
};
|
||||
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>模板 - 属性检查器</title>
|
||||
<link rel="stylesheet" href="../../static/css/sdpi.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="sdpi-wrapper" style="display: none">
|
||||
<div class="sdpi-heading">模板</div>
|
||||
</div>
|
||||
<script src="../utils/common.js"></script>
|
||||
<script src="../utils/action.js"></script>
|
||||
<script src="index.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -0,0 +1,14 @@
|
||||
/// <reference path="../utils/common.js" />
|
||||
/// <reference path="../utils/action.js" />
|
||||
|
||||
// $local 是否国际化
|
||||
// $back 是否自行决定回显时机
|
||||
// $dom 获取文档元素 - 不是动态的都写在这里面
|
||||
const $local = false, $back = false, $dom = {
|
||||
main: $('.sdpi-wrapper')
|
||||
};
|
||||
|
||||
const $propEvent = {
|
||||
didReceiveSettings(data) { },
|
||||
sendToPropertyInspector(data) { }
|
||||
};
|
||||
@ -0,0 +1,131 @@
|
||||
/**
|
||||
* PropertyInspector 2.5.0 新特性 =>
|
||||
*
|
||||
* 1 => 工具与主文件相分离 - 按需引入
|
||||
* 2 => $settings - 全局持久化数据代理 ※
|
||||
* 3 => 无需关注上下文 - 随时随地与插件通信
|
||||
* 4 => 注意事项: 为了避免命名冲突,请勿使用 $ 相关的名称以及JQuery库
|
||||
*
|
||||
* ===== CJHONG ========================================== 2023.10.10 =====>
|
||||
*/
|
||||
|
||||
let $websocket, $uuid, $action, $context, $settings, $lang, $FileID = '';
|
||||
|
||||
// 与插件通信
|
||||
WebSocket.prototype.sendToPlugin = function (payload) {
|
||||
this.send(JSON.stringify({
|
||||
event: "sendToPlugin",
|
||||
action: $action,
|
||||
context: $uuid,
|
||||
payload
|
||||
}));
|
||||
};
|
||||
|
||||
// 设置状态
|
||||
WebSocket.prototype.setState = function (state) {
|
||||
this.send(JSON.stringify({
|
||||
event: "setState",
|
||||
context: $context,
|
||||
payload: { state }
|
||||
}));
|
||||
};
|
||||
|
||||
// 设置背景
|
||||
WebSocket.prototype.setImage = function (url) {
|
||||
let image = new Image();
|
||||
image.src = url;
|
||||
image.onload = () => {
|
||||
let canvas = document.createElement("canvas");
|
||||
canvas.width = image.naturalWidth;
|
||||
canvas.height = image.naturalHeight;
|
||||
let ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(image, 0, 0);
|
||||
this.send(JSON.stringify({
|
||||
event: "setImage",
|
||||
context: $context,
|
||||
payload: {
|
||||
target: 0,
|
||||
image: canvas.toDataURL("image/png")
|
||||
}
|
||||
}));
|
||||
};
|
||||
};
|
||||
|
||||
// 打开网页
|
||||
WebSocket.prototype.openUrl = function (url) {
|
||||
this.send(JSON.stringify({
|
||||
event: "openUrl",
|
||||
payload: { url }
|
||||
}));
|
||||
};
|
||||
|
||||
// 保存持久化数据
|
||||
WebSocket.prototype.saveData = $.debounce(function (payload) {
|
||||
this.send(JSON.stringify({
|
||||
event: "setSettings",
|
||||
context: $uuid,
|
||||
payload
|
||||
}));
|
||||
});
|
||||
|
||||
// StreamDock 软件入口函数
|
||||
async function connectElgatoStreamDeckSocket(port, uuid, event, app, info) {
|
||||
info = JSON.parse(info);
|
||||
$uuid = uuid; $action = info.action;
|
||||
$context = info.context;
|
||||
$websocket = new WebSocket('ws://127.0.0.1:' + port);
|
||||
$websocket.onopen = () => $websocket.send(JSON.stringify({ event, uuid }));
|
||||
|
||||
// 持久数据代理
|
||||
$websocket.onmessage = e => {
|
||||
let data = JSON.parse(e.data);
|
||||
if (data.event === 'didReceiveSettings') {
|
||||
$settings = new Proxy(data.payload.settings, {
|
||||
get(target, property) {
|
||||
return target[property];
|
||||
},
|
||||
set(target, property, value) {
|
||||
target[property] = value;
|
||||
$websocket.saveData(data.payload.settings);
|
||||
}
|
||||
});
|
||||
if (!$back) $dom.main.style.display = 'block';
|
||||
}
|
||||
$propEvent[data.event]?.(data.payload);
|
||||
};
|
||||
|
||||
// 自动翻译页面
|
||||
if (!$local) return;
|
||||
$lang = await new Promise(resolve => {
|
||||
const req = new XMLHttpRequest();
|
||||
req.open('GET', `../../${JSON.parse(app).application.language}.json`);
|
||||
req.send();
|
||||
req.onreadystatechange = () => {
|
||||
if (req.readyState === 4) {
|
||||
resolve(JSON.parse(req.responseText).Localization);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// 遍历文本节点并翻译所有文本节点
|
||||
const walker = document.createTreeWalker($dom.main, NodeFilter.SHOW_TEXT, (e) => {
|
||||
return e.data.trim() && NodeFilter.FILTER_ACCEPT;
|
||||
});
|
||||
while (walker.nextNode()) {
|
||||
console.log(walker.currentNode.data);
|
||||
walker.currentNode.data = $lang[walker.currentNode.data];
|
||||
}
|
||||
// placeholder 特殊处理
|
||||
const translate = item => {
|
||||
if (item.placeholder?.trim()) {
|
||||
console.log(item.placeholder);
|
||||
item.placeholder = $lang[item.placeholder];
|
||||
}
|
||||
};
|
||||
$('input', true).forEach(translate);
|
||||
$('textarea', true).forEach(translate);
|
||||
}
|
||||
|
||||
// StreamDock 文件路径回调
|
||||
Array.from($('input[type="file"]', true)).forEach(item => item.addEventListener('click', () => $FileID = item.id));
|
||||
const onFilePickerReturn = (url) => $emit.send(`File-${$FileID}`, JSON.parse(url));
|
||||
@ -0,0 +1,81 @@
|
||||
// 自定义事件类
|
||||
class EventPlus {
|
||||
constructor() {
|
||||
this.event = new EventTarget();
|
||||
}
|
||||
on(name, callback) {
|
||||
this.event.addEventListener(name, e => callback(e.detail));
|
||||
}
|
||||
send(name, data) {
|
||||
this.event.dispatchEvent(new CustomEvent(name, {
|
||||
detail: data,
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// 补零
|
||||
String.prototype.fill = function () {
|
||||
return this >= 10 ? this : '0' + this;
|
||||
};
|
||||
|
||||
// unicode编码转换字符串
|
||||
String.prototype.uTs = function () {
|
||||
return eval('"' + Array.from(this).join('') + '"');
|
||||
};
|
||||
|
||||
// 字符串转换unicode编码
|
||||
String.prototype.sTu = function (str = '') {
|
||||
Array.from(this).forEach(item => str += `\\u${item.charCodeAt(0).toString(16)}`);
|
||||
return str;
|
||||
};
|
||||
|
||||
// 全局变量/方法
|
||||
const $emit = new EventPlus(), $ = (selector, isAll = false) => {
|
||||
const element = document.querySelector(selector), methods = {
|
||||
on: function (event, callback) {
|
||||
this.addEventListener(event, callback);
|
||||
},
|
||||
attr: function (name, value = '') {
|
||||
value && this.setAttribute(name, value);
|
||||
return this;
|
||||
}
|
||||
};
|
||||
if (!isAll && element) {
|
||||
return Object.assign(element, methods);
|
||||
} else if (!isAll && !element) {
|
||||
throw `HTML没有 ${selector} 元素! 请检查是否拼写错误`;
|
||||
}
|
||||
return Array.from(document.querySelectorAll(selector)).map(item => Object.assign(item, methods));
|
||||
};
|
||||
|
||||
// 节流函数
|
||||
$.throttle = (fn, delay) => {
|
||||
let Timer = null;
|
||||
return function () {
|
||||
if (Timer) return;
|
||||
Timer = setTimeout(() => {
|
||||
fn.apply(this, arguments);
|
||||
Timer = null;
|
||||
}, delay);
|
||||
};
|
||||
};
|
||||
|
||||
// 防抖函数
|
||||
$.debounce = (fn, delay) => {
|
||||
let Timer = null;
|
||||
return function () {
|
||||
clearTimeout(Timer);
|
||||
Timer = setTimeout(() => fn.apply(this, arguments), delay);
|
||||
};
|
||||
};
|
||||
|
||||
// 绑定限制数字方法
|
||||
Array.from($('input[type="num"]', true)).forEach(item => {
|
||||
item.addEventListener('input', function limitNum() {
|
||||
if (!item.value || /^\d+$/.test(item.value)) return;
|
||||
item.value = item.value.slice(0, -1);
|
||||
limitNum(item);
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user