Browse Source

Merge remote-tracking branch 'snozbot/master'

master
zvinless 8 years ago
parent
commit
20203e6410
  1. 10
      Assets/AssetStoreTools/Editor/AssetStoreTools.dll.meta
  2. 62
      Assets/Fungus/EditorResources/FungusEditorResources.asset
  3. 4
      Assets/Fungus/EditorResources/FungusEditorResources.asset.meta
  4. BIN
      Assets/Fungus/EditorResources/Textures/connection_point.png
  5. 59
      Assets/Fungus/EditorResources/Textures/connection_point.png.meta
  6. 138
      Assets/Fungus/Resources/GLLineDraw.mat
  7. 11
      Assets/Fungus/Resources/GLLineDraw.shader
  8. 9
      Assets/Fungus/Resources/GLLineDraw.shader.meta
  9. 349
      Assets/Fungus/Scripts/Editor/FlowchartWindow.cs
  10. 195
      Assets/Fungus/Scripts/Editor/FungusEditorResources.cs
  11. 66
      Assets/Fungus/Scripts/Editor/FungusEditorResourcesGenerated.cs
  12. 292
      Assets/Fungus/Scripts/Editor/GLDraw.cs
  13. 8
      Assets/Fungus/Scripts/Editor/GLDraw.cs.meta

10
Assets/AssetStoreTools/Editor/AssetStoreTools.dll.meta

@ -7,8 +7,16 @@ PluginImporter:
isPreloaded: 0
platformData:
Any:
enabled: 1
enabled: 0
settings: {}
Editor:
enabled: 1
settings:
DefaultValueInitialized: true
WindowsStoreApps:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

62
Assets/Fungus/EditorResources/FungusEditorResources.asset

@ -0,0 +1,62 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d2af387304e4b454b9ce8b815799cad0, type: 3}
m_Name: FungusEditorResources
m_EditorClassIdentifier:
updateOnReloadScripts: 0
add:
free: {fileID: 2800000, guid: 24a867d6b4cdda04cb3aa3350f9ec7d0, type: 3}
pro: {fileID: 2800000, guid: 4e43c476b4a7a49a08c37378fb01ce99, type: 3}
add_small:
free: {fileID: 2800000, guid: 288aff1a0e5c14fd3a0039d24149df73, type: 3}
pro: {fileID: 2800000, guid: 64534dfaa17844231a9a9dd2df89d0db, type: 3}
delete:
free: {fileID: 2800000, guid: d6fc8a97e8a5b0947a49b780f787e504, type: 3}
pro: {fileID: 2800000, guid: 29c4d29b1678042a5b3516c732ccc507, type: 3}
down:
free: {fileID: 2800000, guid: 51a973f446c2e664582861480cce6215, type: 3}
pro: {fileID: 2800000, guid: 5a87a7d3683164a238377d948572805f, type: 3}
duplicate:
free: {fileID: 2800000, guid: c97f334c466215a4f93eff31de3c1591, type: 3}
pro: {fileID: 2800000, guid: 2f17490d993c84bd7872ef6588ffba47, type: 3}
up:
free: {fileID: 2800000, guid: 8f1242ad894201f43b2b6d52fd990f77, type: 3}
pro: {fileID: 2800000, guid: 2a76a781db2994b33b83cd84b8835da7, type: 3}
choice_node_off:
free: {fileID: 2800000, guid: 7b6fc04aac74540e39e9502da5312ce7, type: 3}
pro: {fileID: 0}
choice_node_on:
free: {fileID: 2800000, guid: cfc05494b71a0446182868aab5f7febf, type: 3}
pro: {fileID: 0}
command_background:
free: {fileID: 2800000, guid: a5c9a4271b3de4e4f86eff7f8a1bd768, type: 3}
pro: {fileID: 0}
connection_point:
free: {fileID: 2800000, guid: f08a4c27d7efe4aa6a35348a4e8aec8f, type: 3}
pro: {fileID: 0}
event_node_off:
free: {fileID: 2800000, guid: 0e16a209826864df7b05f6d3901aae7a, type: 3}
pro: {fileID: 0}
event_node_on:
free: {fileID: 2800000, guid: 9434488a4efb54da5986eba5d5619baf, type: 3}
pro: {fileID: 0}
play_big:
free: {fileID: 2800000, guid: bff2ba39f5f4448589e80522ebfcd0a0, type: 3}
pro: {fileID: 0}
play_small:
free: {fileID: 2800000, guid: a48a2b9b06deb469d9da1777b094521b, type: 3}
pro: {fileID: 0}
process_node_off:
free: {fileID: 2800000, guid: ea3a4228e6c214149bfe5c741b56ae0c, type: 3}
pro: {fileID: 0}
process_node_on:
free: {fileID: 2800000, guid: c2dceb780784240ccbe8d3cde89f7671, type: 3}
pro: {fileID: 0}

4
Assets/Fungus/Resources/GLLineDraw.mat.meta → Assets/Fungus/EditorResources/FungusEditorResources.asset.meta

@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: 4209d966cfca44792ad45389a996015e
timeCreated: 1434115586
guid: 29cae11326cb84802b83fc3ff25a47e8
timeCreated: 1478978272
licenseType: Free
NativeFormatImporter:
userData:

BIN
Assets/Fungus/EditorResources/Textures/connection_point.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

59
Assets/Fungus/EditorResources/Textures/connection_point.png.meta

@ -0,0 +1,59 @@
fileFormatVersion: 2
guid: f08a4c27d7efe4aa6a35348a4e8aec8f
timeCreated: 1478932274
licenseType: Free
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
cubemapConvolution: 0
cubemapConvolutionSteps: 7
cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
rGBM: 0
compressionQuality: 50
allowsAlphaSplitting: 0
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
buildTargetSettings: []
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

138
Assets/Fungus/Resources/GLLineDraw.mat

@ -1,138 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: GLLineDraw
m_Shader: {fileID: 4800000, guid: ef64b0d30343049d4a634192975fab73, type: 3}
m_ShaderKeywords:
m_LightmapFlags: 5
m_CustomRenderQueue: -1
stringTagMap: {}
m_SavedProperties:
serializedVersion: 2
m_TexEnvs:
data:
first:
name: _MainTex
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _BumpMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailNormalMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _ParallaxMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _OcclusionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _EmissionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailMask
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailAlbedoMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _MetallicGlossMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
data:
first:
name: _SrcBlend
second: 1
data:
first:
name: _DstBlend
second: 0
data:
first:
name: _Cutoff
second: .5
data:
first:
name: _Parallax
second: .0199999996
data:
first:
name: _ZWrite
second: 1
data:
first:
name: _Glossiness
second: .5
data:
first:
name: _BumpScale
second: 1
data:
first:
name: _OcclusionStrength
second: 1
data:
first:
name: _DetailNormalMapScale
second: 1
data:
first:
name: _UVSec
second: 0
data:
first:
name: _Mode
second: 0
data:
first:
name: _Metallic
second: 0
m_Colors:
data:
first:
name: _EmissionColor
second: {r: 0, g: 0, b: 0, a: 1}
data:
first:
name: _Color
second: {r: 1, g: 1, b: 1, a: 1}

11
Assets/Fungus/Resources/GLLineDraw.shader

@ -1,11 +0,0 @@
Shader "Lines/Colored Blended" {
SubShader {
Pass {
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off Cull Off Fog { Mode Off }
BindChannels {
Bind "vertex", vertex Bind "color", color
}
}
}
}

9
Assets/Fungus/Resources/GLLineDraw.shader.meta

@ -1,9 +0,0 @@
fileFormatVersion: 2
guid: ef64b0d30343049d4a634192975fab73
timeCreated: 1434114816
licenseType: Free
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

349
Assets/Fungus/Scripts/Editor/FlowchartWindow.cs

@ -3,16 +3,101 @@
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using Object = UnityEngine.Object;
namespace Fungus.EditorUtils
{
public class FlowchartWindow : EditorWindow
{
protected class ClipboardObject
{
internal SerializedObject serializedObject;
internal Type type;
internal ClipboardObject(Object obj)
{
serializedObject = new SerializedObject(obj);
type = obj.GetType();
}
}
protected class BlockCopy
{
private SerializedObject block = null;
private List<ClipboardObject> commands = new List<ClipboardObject>();
private ClipboardObject eventHandler = null;
internal BlockCopy(Block block)
{
this.block = new SerializedObject(block);
foreach (var command in block.CommandList)
{
commands.Add(new ClipboardObject(command));
}
if (block._EventHandler != null)
{
eventHandler = new ClipboardObject(block._EventHandler);
}
}
private void CopyProperties(SerializedObject source, Object dest, params SerializedPropertyType[] excludeTypes)
{
var newSerializedObject = new SerializedObject(dest);
var prop = source.GetIterator();
while (prop.NextVisible(true))
{
if (!excludeTypes.Contains(prop.propertyType))
{
newSerializedObject.CopyFromSerializedProperty(prop);
}
}
newSerializedObject.ApplyModifiedProperties();
}
internal Block PasteBlock(Flowchart flowchart)
{
var newBlock = FlowchartWindow.CreateBlock(flowchart, Vector2.zero);
// Copy all command serialized properties
// Copy references to match duplication behavior
foreach (var command in commands)
{
var newCommand = Undo.AddComponent(flowchart.gameObject, command.type) as Command;
CopyProperties(command.serializedObject, newCommand);
newCommand.ItemId = flowchart.NextItemId();
newBlock.CommandList.Add(newCommand);
}
// Copy event handler
if (eventHandler != null)
{
var newEventHandler = Undo.AddComponent(flowchart.gameObject, eventHandler.type) as EventHandler;
CopyProperties(eventHandler.serializedObject, newEventHandler);
newEventHandler.ParentBlock = newBlock;
newBlock._EventHandler = newEventHandler;
}
// Copy block properties, but do not copy references because those were just assigned
CopyProperties(
block,
newBlock,
SerializedPropertyType.ObjectReference,
SerializedPropertyType.Generic,
SerializedPropertyType.ArraySize
);
newBlock.BlockName = flowchart.GetUniqueBlockKey(block.FindProperty("blockName").stringValue + " (Copy)");
return newBlock;
}
}
protected List<BlockCopy> copyList = new List<BlockCopy>();
public static List<Block> deleteList = new List<Block>();
protected List<Block> windowBlockMap = new List<Block>();
@ -34,11 +119,15 @@ namespace Fungus.EditorUtils
protected int forceRepaintCount;
protected Texture2D addTexture;
protected Texture2D connectionPointTexture;
protected Rect selectionBox;
protected Vector2 startSelectionBoxPosition = -Vector2.one;
protected List<Block> mouseDownSelectionState = new List<Block>();
protected Color gridLineColor = Color.black;
protected readonly Color connectionColor = new Color(0.65f, 0.65f, 0.65f, 1.0f);
// Context Click occurs on MouseDown which interferes with panning
// Track right click positions manually to show menus on MouseUp
protected Vector2 rightClickDown = -Vector2.one;
@ -66,6 +155,10 @@ namespace Fungus.EditorUtils
nodeStyle.wordWrap = true;
addTexture = FungusEditorResources.AddSmall;
connectionPointTexture = FungusEditorResources.ConnectionPoint;
gridLineColor.a = EditorGUIUtility.isProSkin ? 0.5f : 0.25f;
copyList.Clear();
}
protected virtual void OnInspectorUpdate()
@ -156,6 +249,11 @@ namespace Fungus.EditorUtils
Undo.DestroyObjectImmediate(command);
}
if (deleteBlock._EventHandler != null)
{
Undo.DestroyObjectImmediate(deleteBlock._EventHandler);
}
Undo.DestroyObjectImmediate((Block)deleteBlock);
flowchart.ClearSelectedCommands();
@ -299,6 +397,13 @@ namespace Fungus.EditorUtils
flowchart.ScrollViewRect = newRect;
}
// Draw background color / drop shadow
if (Event.current.type == EventType.Repaint)
{
UnityEditor.Graphs.Styles.graphBackground.Draw(
new Rect(0, 17, position.width, position.height - 17), false, false, false, false
);
}
// Calc rect for script view
Rect scriptViewRect = new Rect(0, 0, this.position.width / flowchart.Zoom, this.position.height / flowchart.Zoom);
@ -320,9 +425,10 @@ namespace Fungus.EditorUtils
EditorZoomArea.Begin(flowchart.Zoom, scriptViewRect);
DrawGrid(flowchart);
GLDraw.BeginGroup(scriptViewRect);
if (Event.current.type == EventType.Repaint)
{
DrawGrid(flowchart);
}
// The center of the Flowchart depends on the block positions and window dimensions, so we calculate it
// here in the FlowchartWindow class and store it on the Flowchart object for use later.
@ -485,8 +591,6 @@ namespace Fungus.EditorUtils
PanAndZoom(flowchart);
GLDraw.EndGroup();
EditorZoomArea.End();
// Handle right click up outside of EditorZoomArea to avoid strange offsets
@ -512,14 +616,26 @@ namespace Fungus.EditorUtils
// Use a copy because flowchart.SelectedBlocks gets modified
var blockList = new List<Block>(flowchart.SelectedBlocks);
menu.AddItem(new GUIContent ("Duplicate"), false, DuplicateBlocks, blockList);
menu.AddItem(new GUIContent ("Copy"), false, () => Copy(flowchart));
menu.AddItem(new GUIContent ("Cut"), false, () => Cut(flowchart));
menu.AddItem(new GUIContent ("Duplicate"), false, () => Duplicate(flowchart));
menu.AddItem(new GUIContent ("Delete"), false, DeleteBlocks, blockList);
}
// Clicked on empty space in grid
else
{
DeselectAll(flowchart);
menu.AddItem(new GUIContent("Add Block"), false, () => CreateBlock(flowchart, mousePosition / flowchart.Zoom - flowchart.ScrollPos));
if (copyList.Count > 0)
{
menu.AddItem(new GUIContent("Paste"), false, () => Paste(flowchart, mousePosition));
}
else
{
menu.AddDisabledItem(new GUIContent("Paste"));
}
}
var menuRect = new Rect();
@ -720,26 +836,14 @@ namespace Fungus.EditorUtils
float width = this.position.width / flowchart.Zoom;
float height = this.position.height / flowchart.Zoom;
// Match background color of scene view
if (EditorGUIUtility.isProSkin)
{
GUI.color = new Color32(71, 71, 71, 255);
}
else
{
GUI.color = new Color32(86, 86, 86, 255);
}
GUI.DrawTexture( new Rect(0,0, width, height), EditorGUIUtility.whiteTexture );
GUI.color = Color.white;
Color color = new Color32(96, 96, 96, 255);
Handles.color = gridLineColor;
float gridSize = 128f;
float x = flowchart.ScrollPos.x % gridSize;
while (x < width)
{
GLDraw.DrawLine(new Vector2(x, 0), new Vector2(x, height), color, 1f);
Handles.DrawLine(new Vector2(x, 0), new Vector2(x, height));
x += gridSize;
}
@ -748,10 +852,12 @@ namespace Fungus.EditorUtils
{
if (y >= 0)
{
GLDraw.DrawLine(new Vector2(0, y), new Vector2(width, y), color, 1f);
Handles.DrawLine(new Vector2(0, y), new Vector2(width, y));
}
y += gridSize;
}
Handles.color = Color.white;
}
protected virtual void SelectBlock(Flowchart flowchart, Block block)
@ -990,17 +1096,17 @@ namespace Fungus.EditorUtils
protected virtual void DrawRectConnection(Rect rectA, Rect rectB, bool highlight)
{
Vector2[] pointsA = new Vector2[] {
new Vector2(rectA.xMin + 5, rectA.center.y),
new Vector2(rectA.xMin + rectA.width / 2, rectA.yMin + 2),
new Vector2(rectA.xMin + rectA.width / 2, rectA.yMax - 2),
new Vector2(rectA.xMax - 5, rectA.center.y)
new Vector2(rectA.xMin, rectA.center.y),
new Vector2(rectA.xMin + rectA.width / 2, rectA.yMin),
new Vector2(rectA.xMin + rectA.width / 2, rectA.yMax),
new Vector2(rectA.xMax, rectA.center.y)
};
Vector2[] pointsB = new Vector2[] {
new Vector2(rectB.xMin + 5, rectB.center.y),
new Vector2(rectB.xMin + rectB.width / 2, rectB.yMin + 2),
new Vector2(rectB.xMin + rectB.width / 2, rectB.yMax - 2),
new Vector2(rectB.xMax - 5, rectB.center.y)
new Vector2(rectB.xMin, rectB.center.y),
new Vector2(rectB.xMin + rectB.width / 2, rectB.yMin),
new Vector2(rectB.xMin + rectB.width / 2, rectB.yMax),
new Vector2(rectB.xMax, rectB.center.y)
};
Vector2 pointA = Vector2.zero;
@ -1021,90 +1127,60 @@ namespace Fungus.EditorUtils
}
}
Color color = Color.grey;
Color color = connectionColor;
if (highlight)
{
color = Color.green;
}
GLDraw.DrawConnectingCurve(pointA, pointB, color, 1.025f);
Handles.color = color;
// Place control based on distance between points
// Weight the min component more so things don't get overly curvy
var diff = pointA - pointB;
diff.x = Mathf.Abs(diff.x);
diff.y = Mathf.Abs(diff.y);
var min = Mathf.Min(diff.x, diff.y);
var max = Mathf.Max(diff.x, diff.y);
var mod = min * 0.75f + max * 0.25f;
// Draw bezier curve connecting blocks
var directionA = (rectA.center - pointA).normalized;
var directionB = (rectB.center - pointB).normalized;
var controlA = pointA - directionA * mod * 0.67f;
var controlB = pointB - directionB * mod * 0.67f;
Handles.DrawBezier(pointA, pointB, controlA, controlB, color, null, 3f);
// Draw arrow on curve
var point = GetPointOnCurve(pointA, controlA, pointB, controlB, 0.7f);
var direction = (GetPointOnCurve(pointA, controlA, pointB, controlB, 0.6f) - point).normalized;
var perp = new Vector2(direction.y, -direction.x);
Handles.DrawAAConvexPolygon(
point, point + direction * 10 + perp * 5, point + direction * 10 - perp * 5
);
Rect dotARect = new Rect(pointA.x - 5, pointA.y - 5, 10, 10);
GUI.Label(dotARect, "", new GUIStyle("U2D.dragDotActive"));
var connectionPointA = pointA + directionA * 4f;
var connectionRectA = new Rect(connectionPointA.x - 4f, connectionPointA.y - 4f, 8f, 8f);
var connectionPointB = pointB + directionB * 4f;
var connectionRectB = new Rect(connectionPointB.x - 4f, connectionPointB.y - 4f, 8f, 8f);
Rect dotBRect = new Rect(pointB.x - 5, pointB.y - 5, 10, 10);
GUI.Label(dotBRect, "", new GUIStyle("U2D.dragDotActive"));
}
GUI.DrawTexture(connectionRectA, connectionPointTexture, ScaleMode.ScaleToFit);
GUI.DrawTexture(connectionRectB, connectionPointTexture, ScaleMode.ScaleToFit);
public static void DeleteBlocks(object obj)
{
var blocks = obj as List<Block>;
blocks.ForEach(block => FlowchartWindow.deleteList.Add(block));
Handles.color = Color.white;
}
protected static void DuplicateBlocks(object obj)
private static Vector2 GetPointOnCurve(Vector2 s, Vector2 st, Vector2 e, Vector2 et, float t)
{
DuplicateBlocks(obj, new Vector2(20, 0));
float rt = 1 - t;
float rtt = rt * t;
return rt * rt * rt * s + 3 * rt * rtt * st + 3 * rtt * t * et + t * t * t * e;
}
protected static void DuplicateBlocks(object obj, Vector2 offset)
public static void DeleteBlocks(object obj)
{
var flowchart = GetFlowchart();
Undo.RecordObject(flowchart, "Select");
flowchart.ClearSelectedBlocks();
var blocks = obj as List<Block>;
foreach (var block in blocks)
{
Vector2 newPosition = block._NodeRect.position + offset;
Block oldBlock = block;
Block newBlock = FlowchartWindow.CreateBlock(flowchart, newPosition);
newBlock.BlockName = flowchart.GetUniqueBlockKey(oldBlock.BlockName + " (Copy)");
Undo.RecordObject(newBlock, "Duplicate Block");
var commandList = oldBlock.CommandList;
foreach (var command in commandList)
{
if (ComponentUtility.CopyComponent(command))
{
if (ComponentUtility.PasteComponentAsNew(flowchart.gameObject))
{
Command[] commands = flowchart.GetComponents<Command>();
Command pastedCommand = commands.Last<Command>();
if (pastedCommand != null)
{
pastedCommand.ItemId = flowchart.NextItemId();
newBlock.CommandList.Add(pastedCommand);
}
}
// This stops the user pasting the command manually into another game object.
ComponentUtility.CopyComponent(flowchart.transform);
}
}
if (oldBlock._EventHandler != null)
{
if (ComponentUtility.CopyComponent(oldBlock._EventHandler))
{
if (ComponentUtility.PasteComponentAsNew(flowchart.gameObject))
{
EventHandler[] eventHandlers = flowchart.GetComponents<EventHandler>();
EventHandler pastedEventHandler = eventHandlers.Last<EventHandler>();
if (pastedEventHandler != null)
{
pastedEventHandler.ParentBlock = newBlock;
newBlock._EventHandler = pastedEventHandler;
}
}
}
}
}
blocks.ForEach(block => FlowchartWindow.deleteList.Add(block));
}
protected static void ShowBlockInspector(Flowchart flowchart)
@ -1149,18 +1225,74 @@ namespace Fungus.EditorUtils
return Event.current.shift || EditorGUI.actionKey;
}
protected virtual void Copy(Flowchart flowchart)
{
copyList.Clear();
foreach (var block in flowchart.SelectedBlocks)
{
copyList.Add(new BlockCopy(block));
}
}
protected virtual void Cut(Flowchart flowchart)
{
Copy(flowchart);
Undo.RecordObject(flowchart, "Cut");
DeleteBlocks(flowchart.SelectedBlocks);
}
// Center is position in unscaled window space
protected virtual void Paste(Flowchart flowchart, Vector2 center, bool relative = false)
{
Undo.RecordObject(flowchart, "Deselect");
DeselectAll(flowchart);
var pasteList = new List<Block>();
foreach (var copy in copyList)
{
pasteList.Add(copy.PasteBlock(flowchart));
}
var copiedCenter = GetBlockCenter(flowchart, pasteList.ToArray()) + flowchart.ScrollPos;
var delta = relative ? center : (center / flowchart.Zoom - copiedCenter);
foreach (var block in pasteList)
{
var tempRect = block._NodeRect;
tempRect.position += delta;
block._NodeRect = tempRect;
}
}
protected virtual void Duplicate(Flowchart flowchart)
{
var tempCopyList = new List<BlockCopy>(copyList);
Copy(flowchart);
Paste(flowchart, new Vector2(20, 0), true);
copyList = tempCopyList;
}
protected virtual void ValidateCommands(Flowchart flowchart)
{
if (Event.current.type == EventType.ValidateCommand)
{
var c = Event.current.commandName;
if (c == "Delete" || c == "Duplicate")
if (c == "Copy" || c == "Cut" || c == "Delete" || c == "Duplicate")
{
if (flowchart.SelectedBlocks.Count > 0)
{
Event.current.Use();
}
}
else if (c == "Paste")
{
if (copyList.Count > 0)
{
Event.current.Use();
}
}
else if (c == "SelectAll")
{
Event.current.Use();
@ -1174,13 +1306,28 @@ namespace Fungus.EditorUtils
{
switch (Event.current.commandName)
{
case "Copy":
Copy(flowchart);
Event.current.Use();
break;
case "Cut":
Cut(flowchart);
Event.current.Use();
break;
case "Paste":
Paste(flowchart, position.center - position.position);
Event.current.Use();
break;
case "Delete":
DeleteBlocks(flowchart.SelectedBlocks);
Event.current.Use();
break;
case "Duplicate":
DuplicateBlocks(new List<Block>(flowchart.SelectedBlocks));
Duplicate(flowchart);
Event.current.Use();
break;

195
Assets/Fungus/Scripts/Editor/FungusEditorResources.cs

@ -3,65 +3,132 @@
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
#if UNITY_5_0 || UNITY_5_1
using System.Reflection;
#endif
namespace Fungus.EditorUtils
{
internal static partial class FungusEditorResources
[CustomEditor(typeof(FungusEditorResources))]
internal class FungusEditorResourcesInspector : Editor
{
private static Dictionary<string, Texture2D> textures = new Dictionary<string, Texture2D>();
private static readonly string editorResourcesFolderName = "\"EditorResources\"";
static FungusEditorResources()
public override void OnInspectorGUI()
{
LoadTexturesFromNames();
if (serializedObject.FindProperty("updateOnReloadScripts").boolValue)
{
GUILayout.Label("Updating...");
}
else
{
if (GUILayout.Button("Sync with EditorResources folder"))
{
FungusEditorResources.GenerateResourcesScript();
}
DrawDefaultInspector();
}
}
}
private static void LoadTexturesFromNames()
// Handle reimporting all assets
internal class EditorResourcesPostProcessor : AssetPostprocessor
{
private static void OnPostprocessAllAssets(string[] importedAssets, string[] _, string[] __, string[] ___)
{
var baseDirectories = AssetDatabase.FindAssets(editorResourcesFolderName).Select(
guid => AssetDatabase.GUIDToAssetPath(guid)
).ToArray();
foreach (var name in resourceNames)
foreach (var path in importedAssets)
{
LoadTexturesFromGUIDs(AssetDatabase.FindAssets(name + " t:Texture2D", baseDirectories));
if (path.EndsWith("FungusEditorResources.asset"))
{
var asset = AssetDatabase.LoadAssetAtPath(path, typeof(FungusEditorResources)) as FungusEditorResources;
if (asset != null)
{
FungusEditorResources.UpdateTextureReferences(asset);
AssetDatabase.SaveAssets();
return;
}
}
}
}
}
private static void LoadAllTexturesInFolder()
internal partial class FungusEditorResources : ScriptableObject
{
[Serializable]
internal class EditorTexture
{
var rootGuid = AssetDatabase.FindAssets(editorResourcesFolderName)[0];
var root = AssetDatabase.GUIDToAssetPath(rootGuid);
LoadTexturesFromGUIDs(AssetDatabase.FindAssets("t:Texture2D", new [] { root }));
[SerializeField] private Texture2D free;
[SerializeField] private Texture2D pro;
public Texture2D Texture2D
{
get { return EditorGUIUtility.isProSkin && pro != null ? pro : free; }
}
public EditorTexture(Texture2D free, Texture2D pro)
{
this.free = free;
this.pro = pro;
}
}
private static void LoadTexturesFromGUIDs(string[] guids)
{
var paths = guids.Select(guid => AssetDatabase.GUIDToAssetPath(guid)).OrderBy(path => path.ToLower().Contains("/pro/"));
private static FungusEditorResources instance;
private static readonly string editorResourcesFolderName = "\"EditorResources\"";
[SerializeField] [HideInInspector] private bool updateOnReloadScripts = false;
foreach (var path in paths)
internal static FungusEditorResources Instance
{
get
{
if (path.ToLower().Contains("/pro/") && !EditorGUIUtility.isProSkin)
if (instance == null)
{
return;
var guids = AssetDatabase.FindAssets("FungusEditorResources t:FungusEditorResources");
if (guids.Length == 0)
{
instance = ScriptableObject.CreateInstance(typeof(FungusEditorResources)) as FungusEditorResources;
AssetDatabase.CreateAsset(instance, GetRootFolder() + "/FungusEditorResources.asset");
}
else
{
if (guids.Length > 1)
{
Debug.LogWarning("Multiple FungusEditorResources assets found!");
}
var path = AssetDatabase.GUIDToAssetPath(guids[0]);
instance = AssetDatabase.LoadAssetAtPath(path, typeof(FungusEditorResources)) as FungusEditorResources;
}
}
var texture = AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)) as Texture2D;
textures[texture.name] = texture;
return instance;
}
}
[MenuItem("Tools/Fungus/Utilities/Update Editor Resources Script")]
private static void GenerateResourcesScript()
private static string GetRootFolder()
{
var rootGuid = AssetDatabase.FindAssets(editorResourcesFolderName)[0];
return AssetDatabase.GUIDToAssetPath(rootGuid);
}
internal static void GenerateResourcesScript()
{
textures.Clear();
LoadAllTexturesInFolder();
// Get all unique filenames
var textureNames = new HashSet<string>();
var guids = AssetDatabase.FindAssets("t:Texture2D", new [] { GetRootFolder() });
var paths = guids.Select(guid => AssetDatabase.GUIDToAssetPath(guid));
foreach (var path in paths)
{
textureNames.Add(Path.GetFileNameWithoutExtension(path));
}
var guid = AssetDatabase.FindAssets("FungusEditorResources t:MonoScript")[0];
var relativePath = AssetDatabase.GUIDToAssetPath(guid).Replace("FungusEditorResources.cs", "FungusEditorResourcesGenerated.cs");
var scriptGuid = AssetDatabase.FindAssets("FungusEditorResources t:MonoScript")[0];
var relativePath = AssetDatabase.GUIDToAssetPath(scriptGuid).Replace("FungusEditorResources.cs", "FungusEditorResourcesGenerated.cs");
var absolutePath = Application.dataPath + relativePath.Substring("Assets".Length);
using (var writer = new StreamWriter(absolutePath))
@ -73,43 +140,83 @@ namespace Fungus.EditorUtils
writer.WriteLine("");
writer.WriteLine("namespace Fungus.EditorUtils");
writer.WriteLine("{");
writer.WriteLine(" internal static partial class FungusEditorResources");
writer.WriteLine(" internal partial class FungusEditorResources : ScriptableObject");
writer.WriteLine(" {");
writer.WriteLine(" private static readonly string[] resourceNames = new [] {");
foreach (var pair in textures)
foreach (var name in textureNames)
{
writer.WriteLine(" \"" + pair.Key + "\",");
writer.WriteLine(" [SerializeField] private EditorTexture " + name + ";");
}
writer.WriteLine(" };");
writer.WriteLine("");
foreach (var pair in textures)
foreach (var name in textureNames)
{
var name = pair.Key;
var pascalCase = string.Join("", name.Split(new [] { '_' }, StringSplitOptions.RemoveEmptyEntries).Select(
s => s.Substring(0, 1).ToUpper() + s.Substring(1)).ToArray()
);
writer.WriteLine(" public static Texture2D " + pascalCase + " { get { return GetTexture(\"" + name + "\"); } }");
writer.WriteLine(" public static Texture2D " + pascalCase + " { get { return Instance." + name + ".Texture2D; } }");
}
writer.WriteLine(" }");
writer.WriteLine("}");
}
Instance.updateOnReloadScripts = true;
AssetDatabase.ImportAsset(relativePath);
}
private static Texture2D GetTexture(string name)
[DidReloadScripts]
private static void OnDidReloadScripts()
{
Texture2D texture;
if (!textures.TryGetValue(name, out texture))
if (Instance.updateOnReloadScripts)
{
Debug.LogWarning("Texture \"" + name + "\" not found!");
UpdateTextureReferences(Instance);
}
}
internal static void UpdateTextureReferences(FungusEditorResources instance)
{
// Iterate through all fields in instance and set texture references
var serializedObject = new SerializedObject(instance);
var prop = serializedObject.GetIterator();
var rootFolder = new [] { GetRootFolder() };
prop.NextVisible(true);
while (prop.NextVisible(false))
{
if (prop.propertyType == SerializedPropertyType.Generic)
{
var guids = AssetDatabase.FindAssets(prop.name + " t:Texture2D", rootFolder);
var paths = guids.Select(guid => AssetDatabase.GUIDToAssetPath(guid)).Where(
path => path.Contains(prop.name + ".")
);
foreach (var path in paths)
{
var texture = AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)) as Texture2D;
if (path.ToLower().Contains("/pro/"))
{
prop.FindPropertyRelative("pro").objectReferenceValue = texture;
}
else
{
prop.FindPropertyRelative("free").objectReferenceValue = texture;
}
}
}
}
serializedObject.FindProperty("updateOnReloadScripts").boolValue = false;
return texture;
// The ApplyModifiedPropertiesWithoutUndo() function wasn't documented until Unity 5.2
#if UNITY_5_0 || UNITY_5_1
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
var applyMethod = typeof(SerializedObject).GetMethod("ApplyModifiedPropertiesWithoutUndo", flags);
applyMethod.Invoke(serializedObject, null);
#else
serializedObject.ApplyModifiedPropertiesWithoutUndo();
#endif
}
}
}

66
Assets/Fungus/Scripts/Editor/FungusEditorResourcesGenerated.cs

@ -5,40 +5,40 @@ using UnityEngine;
namespace Fungus.EditorUtils
{
internal static partial class FungusEditorResources
internal partial class FungusEditorResources : ScriptableObject
{
private static readonly string[] resourceNames = new [] {
"add",
"add_small",
"delete",
"down",
"duplicate",
"up",
"choice_node_off",
"choice_node_on",
"command_background",
"event_node_off",
"event_node_on",
"play_big",
"play_small",
"process_node_off",
"process_node_on",
};
[SerializeField] private EditorTexture add;
[SerializeField] private EditorTexture add_small;
[SerializeField] private EditorTexture delete;
[SerializeField] private EditorTexture down;
[SerializeField] private EditorTexture duplicate;
[SerializeField] private EditorTexture up;
[SerializeField] private EditorTexture choice_node_off;
[SerializeField] private EditorTexture choice_node_on;
[SerializeField] private EditorTexture command_background;
[SerializeField] private EditorTexture connection_point;
[SerializeField] private EditorTexture event_node_off;
[SerializeField] private EditorTexture event_node_on;
[SerializeField] private EditorTexture play_big;
[SerializeField] private EditorTexture play_small;
[SerializeField] private EditorTexture process_node_off;
[SerializeField] private EditorTexture process_node_on;
public static Texture2D Add { get { return GetTexture("add"); } }
public static Texture2D AddSmall { get { return GetTexture("add_small"); } }
public static Texture2D Delete { get { return GetTexture("delete"); } }
public static Texture2D Down { get { return GetTexture("down"); } }
public static Texture2D Duplicate { get { return GetTexture("duplicate"); } }
public static Texture2D Up { get { return GetTexture("up"); } }
public static Texture2D ChoiceNodeOff { get { return GetTexture("choice_node_off"); } }
public static Texture2D ChoiceNodeOn { get { return GetTexture("choice_node_on"); } }
public static Texture2D CommandBackground { get { return GetTexture("command_background"); } }
public static Texture2D EventNodeOff { get { return GetTexture("event_node_off"); } }
public static Texture2D EventNodeOn { get { return GetTexture("event_node_on"); } }
public static Texture2D PlayBig { get { return GetTexture("play_big"); } }
public static Texture2D PlaySmall { get { return GetTexture("play_small"); } }
public static Texture2D ProcessNodeOff { get { return GetTexture("process_node_off"); } }
public static Texture2D ProcessNodeOn { get { return GetTexture("process_node_on"); } }
public static Texture2D Add { get { return Instance.add.Texture2D; } }
public static Texture2D AddSmall { get { return Instance.add_small.Texture2D; } }
public static Texture2D Delete { get { return Instance.delete.Texture2D; } }
public static Texture2D Down { get { return Instance.down.Texture2D; } }
public static Texture2D Duplicate { get { return Instance.duplicate.Texture2D; } }
public static Texture2D Up { get { return Instance.up.Texture2D; } }
public static Texture2D ChoiceNodeOff { get { return Instance.choice_node_off.Texture2D; } }
public static Texture2D ChoiceNodeOn { get { return Instance.choice_node_on.Texture2D; } }
public static Texture2D CommandBackground { get { return Instance.command_background.Texture2D; } }
public static Texture2D ConnectionPoint { get { return Instance.connection_point.Texture2D; } }
public static Texture2D EventNodeOff { get { return Instance.event_node_off.Texture2D; } }
public static Texture2D EventNodeOn { get { return Instance.event_node_on.Texture2D; } }
public static Texture2D PlayBig { get { return Instance.play_big.Texture2D; } }
public static Texture2D PlaySmall { get { return Instance.play_small.Texture2D; } }
public static Texture2D ProcessNodeOff { get { return Instance.process_node_off.Texture2D; } }
public static Texture2D ProcessNodeOn { get { return Instance.process_node_on.Texture2D; } }
}
}

292
Assets/Fungus/Scripts/Editor/GLDraw.cs

@ -1,292 +0,0 @@
// This code is part of the Fungus library (http://fungusgames.com) maintained by Chris Gregan (http://twitter.com/gofungus).
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
using UnityEngine;
namespace Fungus.EditorUtils
{
/// <summary>
/// Clipping code: http://forum.unity3d.com/threads/17066-How-to-draw-a-GUI-2D-quot-line-quot?p=230386#post230386
/// Thick line drawing code: http://unifycommunity.com/wiki/index.php?title=VectorLine
/// Credit: "http://cs-people.bu.edu/jalon/cs480/Oct11Lab/clip.c"
/// </summary>
public class GLDraw
{
protected static bool clippingEnabled;
protected static Rect clippingBounds;
public static Material lineMaterial = null;
protected static bool clip_test(float p, float q, ref float u1, ref float u2)
{
float r;
bool retval = true;
if (p < 0.0)
{
r = q / p;
if (r > u2)
retval = false;
else if (r > u1)
u1 = r;
}
else if (p > 0.0)
{
r = q / p;
if (r < u1)
retval = false;
else if (r < u2)
u2 = r;
}
else if (q < 0.0)
retval = false;
return retval;
}
public static bool segment_rect_intersection(Rect bounds, ref Vector2 p1, ref Vector2 p2)
{
float u1 = 0.0f, u2 = 1.0f, dx = p2.x - p1.x, dy;
if (clip_test(-dx, p1.x - bounds.xMin, ref u1, ref u2))
{
if (clip_test(dx, bounds.xMax - p1.x, ref u1, ref u2))
{
dy = p2.y - p1.y;
if (clip_test(-dy, p1.y - bounds.yMin, ref u1, ref u2))
{
if (clip_test(dy, bounds.yMax - p1.y, ref u1, ref u2))
{
if (u2 < 1.0)
{
p2.x = p1.x + u2 * dx;
p2.y = p1.y + u2 * dy;
}
if (u1 > 0.0)
{
p1.x += u1 * dx;
p1.y += u1 * dy;
}
return true;
}
}
}
}
return false;
}
public static void BeginGroup(Rect position)
{
clippingEnabled = true;
clippingBounds = new Rect(0, 0, position.width, position.height);
GUI.BeginGroup(position);
}
public static void EndGroup()
{
GUI.EndGroup();
clippingBounds = new Rect(0, 0, Screen.width, Screen.height);
clippingEnabled = false;
}
public static Vector2 BeginScrollView(Rect position, Vector2 scrollPos, Rect viewRect, Rect clipRect)
{
clippingEnabled = true;
clippingBounds = clipRect;
return GUI.BeginScrollView(position, scrollPos, viewRect, GUIStyle.none, GUIStyle.none);
}
public static void EndScrollView()
{
GUI.EndScrollView();
clippingBounds = new Rect(0, 0, Screen.width, Screen.height);
clippingEnabled = false;
}
public static void CreateMaterial()
{
if (lineMaterial != null)
return;
lineMaterial = Resources.Load("GLLineDraw", typeof(Material)) as Material;
}
public static void DrawLine(Vector2 start, Vector2 end, Color color, float width)
{
if (Event.current == null)
return;
if (Event.current.type != EventType.repaint)
return;
if (clippingEnabled)
if (!segment_rect_intersection(clippingBounds, ref start, ref end))
return;
CreateMaterial();
lineMaterial.SetPass(0);
Vector3 startPt;
Vector3 endPt;
if (width == 1)
{
GL.Begin(GL.LINES);
GL.Color(color);
startPt = new Vector3(start.x, start.y, 0);
endPt = new Vector3(end.x, end.y, 0);
GL.Vertex(startPt);
GL.Vertex(endPt);
}
else
{
GL.Begin(GL.QUADS);
GL.Color(color);
startPt = new Vector3(end.y, start.x, 0);
endPt = new Vector3(start.y, end.x, 0);
Vector3 perpendicular = (startPt - endPt).normalized * width;
Vector3 v1 = new Vector3(start.x, start.y, 0);
Vector3 v2 = new Vector3(end.x, end.y, 0);
GL.Vertex(v1 - perpendicular);
GL.Vertex(v1 + perpendicular);
GL.Vertex(v2 + perpendicular);
GL.Vertex(v2 - perpendicular);
}
GL.End();
}
public static void DrawRect(Rect rect, Color color)
{
if (Event.current == null)
return;
if (Event.current.type != EventType.repaint)
return;
CreateMaterial();
// set the current material
lineMaterial.SetPass( 0 );
GL.Begin( GL.QUADS );
GL.Color( color );
GL.Vertex3( rect.xMin, rect.yMin, 0 );
GL.Vertex3( rect.xMax, rect.yMin, 0 );
GL.Vertex3( rect.xMax, rect.yMax, 0 );
GL.Vertex3( rect.xMin, rect.yMax, 0 );
GL.End();
}
public static void DrawBox(Rect box, Color color, float width)
{
Vector2 p1 = new Vector2(box.xMin, box.yMin);
Vector2 p2 = new Vector2(box.xMax, box.yMin);
Vector2 p3 = new Vector2(box.xMax, box.yMax);
Vector2 p4 = new Vector2(box.xMin, box.yMax);
DrawLine(p1, p2, color, width);
DrawLine(p2, p3, color, width);
DrawLine(p3, p4, color, width);
DrawLine(p4, p1, color, width);
}
public static void DrawBox(Vector2 topLeftCorner, Vector2 bottomRightCorner, Color color, float width)
{
Rect box = new Rect(topLeftCorner.x, topLeftCorner.y, bottomRightCorner.x - topLeftCorner.x, bottomRightCorner.y - topLeftCorner.y);
DrawBox(box, color, width);
}
public static void DrawRoundedBox(Rect box, float radius, Color color, float width)
{
Vector2 p1, p2, p3, p4, p5, p6, p7, p8;
p1 = new Vector2(box.xMin + radius, box.yMin);
p2 = new Vector2(box.xMax - radius, box.yMin);
p3 = new Vector2(box.xMax, box.yMin + radius);
p4 = new Vector2(box.xMax, box.yMax - radius);
p5 = new Vector2(box.xMax - radius, box.yMax);
p6 = new Vector2(box.xMin + radius, box.yMax);
p7 = new Vector2(box.xMin, box.yMax - radius);
p8 = new Vector2(box.xMin, box.yMin + radius);
DrawLine(p1, p2, color, width);
DrawLine(p3, p4, color, width);
DrawLine(p5, p6, color, width);
DrawLine(p7, p8, color, width);
Vector2 t1, t2;
float halfRadius = radius / 2;
t1 = new Vector2(p8.x, p8.y + halfRadius);
t2 = new Vector2(p1.x - halfRadius, p1.y);
DrawBezier(p8, t1, p1, t2, color, width);
t1 = new Vector2(p2.x + halfRadius, p2.y);
t2 = new Vector2(p3.x, p3.y - halfRadius);
DrawBezier(p2, t1, p3, t2, color, width);
t1 = new Vector2(p4.x, p4.y + halfRadius);
t2 = new Vector2(p5.x + halfRadius, p5.y);
DrawBezier(p4, t1, p5, t2, color, width);
t1 = new Vector2(p6.x - halfRadius, p6.y);
t2 = new Vector2(p7.x, p7.y + halfRadius);
DrawBezier(p6, t1, p7, t2, color, width);
}
public static void DrawConnectingCurve(Vector2 start, Vector2 end, Color color, float width)
{
Vector2 distance = start - end;
Vector2 tangentA = start;
tangentA.x -= distance.x * 0.5f;
Vector2 tangentB = end;
tangentB.x += distance.x * 0.5f;
int segments = Mathf.FloorToInt((distance.magnitude / 20) * 3);
DrawBezier(start, tangentA, end, tangentB, color, width, segments);
Vector2 pA = CubeBezier(start, tangentA, end, tangentB, 0.6f);
Vector2 pB = CubeBezier(start, tangentA, end, tangentB, 0.7f);
float arrowHeadSize = 5;
Vector2 arrowPosA = pB;
Vector2 arrowPosB = arrowPosA;
Vector2 arrowPosC = arrowPosA;
Vector2 dir = (pB - pA).normalized;
arrowPosB.x += dir.y * arrowHeadSize;
arrowPosB.y -= dir.x * arrowHeadSize;
arrowPosB -= dir * arrowHeadSize;
arrowPosC.x -= dir.y * arrowHeadSize;
arrowPosC.y += dir.x * arrowHeadSize;
arrowPosC -= dir * arrowHeadSize;
DrawLine(arrowPosA, arrowPosB, color, 1.025f);
DrawLine(arrowPosA, arrowPosC, color, 1.025f);
}
public static void DrawBezier(Vector2 start, Vector2 startTangent, Vector2 end, Vector2 endTangent, Color color, float width)
{
int segments = Mathf.FloorToInt((start - end).magnitude / 20) * 3; // Three segments per distance of 20
DrawBezier(start, startTangent, end, endTangent, color, width, segments);
}
public static void DrawBezier(Vector2 start, Vector2 startTangent, Vector2 end, Vector2 endTangent, Color color, float width, int segments)
{
Vector2 startVector = CubeBezier(start, startTangent, end, endTangent, 0);
for (int i = 1; i <= segments; i++)
{
Vector2 endVector = CubeBezier(start, startTangent, end, endTangent, i / (float)segments);
DrawLine(startVector, endVector, color, width);
startVector = endVector;
}
}
private static Vector2 CubeBezier(Vector2 s, Vector2 st, Vector2 e, Vector2 et, float t)
{
float rt = 1 - t;
float rtt = rt * t;
return rt * rt * rt * s + 3 * rt * rtt * st + 3 * rtt * t * et + t * t * t * e;
}
}
}

8
Assets/Fungus/Scripts/Editor/GLDraw.cs.meta

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 5184535fd41514a0ebd42c1d70a53545
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
Loading…
Cancel
Save