diff --git a/Changelog.txt b/Changelog.txt deleted file mode 100644 index 0f5be94e..00000000 --- a/Changelog.txt +++ /dev/null @@ -1,249 +0,0 @@ -1.4.0: - -Added experimental support for procedural CSG usage, this can be activated in the SabreCSG tab in Unity Preferences -Added the start of per face vertex color support -Added draw brush tool -Added option to set up a 4 split optimised for level design (Window -> CSG 4 Split) -Improved results from Select All -Fixed clipping not resetting brush pivot immediately -Default brush is now created on top of the grid (at 0,1,0) rather than centered on 0,0,0 as this is more consistent with brush drawing -Pressing D activates Draw mode, pressing C activates Clip mode -Added default physics material to build settings -Added new icon buttons for creating brushes instead of the old Create drop down -Started on a new default material type that tints based on vertex color -Started on new shaders for vertex color and tri-planar support -Created new docs for the 1.4 procedural API at http://sabrecsg.com/docs/ -Started on a shortcut for swapping the active scene view to the closest axis-aligned iso view (Edit -> Iso Align Nearest Angle), this will have a nicer shortcut in a later beta -NoCSG brushes are now displayed differently to add and subtract brushes to make it clearer that they behave differently. Both brush color and hierarchy icon are new. -While copying material with the C key held, you can now click and drag it over multiple polygons rather than each polygon requiring a click -New radial menu when you press the J key in the scene view for aligning the camera more quickly -UI for CSG Model build settings has been rewritten, making it much clearer and easier to use -Added option in Build Settings for setting the default visual material -Three new presets for default visual material - lit texture, lit texture that tints by vertex color, unlit vertex color -Changing the visual material on the CSG Model instantly updates the built meshes and doesn't require a rebuild -Brushes from other CSG Models are now displayed while editing a CSG Model and are selectable. Selecting a brush from a different CSG Model will automatically switch the active CSG Model to the new selection's parent. -Copy material and follow last face now support copying vertex colors -Removed the margin from the Create Brush buttons so they look a little nicer -When you change any of the build settings, the build engine is now aware that a full rebuild is necessary. If auto rebuild is on this build will occur immediately, otherwise it will occur when you next activate rebuild. Note that the build engine compares against the last rebuild, so changing a flag and changing it back before a rebuild occurs will not trigger an unnecessary full rebuild. -The tag on the CSG Model object is now copied to built meshes in addition to the existing support for layer and static flags -When duplicating objects inside a CSG Model, the order of the objects is now respected. This works around a Unity bug by transparently overriding the duplication command when CSG is being edited. -Key mappings have been moved to a ScriptableObject, you can reconfigure key mappings from the Inspector now -You can now change cylinder and sphere side counts in the same way as a prism -Fixed an changing physics material doesn't require a rebuild, but one takes place. It actually instantly marks the built meshes correctly, so no rebuild is necessary -Fixed an error from dragging a brush prefab into the scene, note that brushes must still be under a CSGModel to build -Added new visualisation of excluded faces which can be turned on in Prefs -Fixed an error that was displayed when deleting a prefab that included multiple intersecting brushes -Brushes and CSG Models are now stripped out at build time rather than on first play. This makes final builds significantly more optimal and fixes serializer warnings. The CSGModelRuntime component previously required on CSG Models is now obsolete and will be automatically removed from existing CSG Models. -Fixed some issues with missing polygons -Fixed a rare case where a build would error -Material meshes and collision meshes are now generated local to the CSG Model, making it easier to manipulate them at runtime -As part of the new experimental run-time support, you can now build a CSG Model in a background thread via scripting -Excluding and reincluding a face in the face tool now respects vertex colors -Stopped polygon hovering when your mouse is over the face tool UI -Fixed subtractions not using vertex colors -Fixed issues with translating vertices resetting vertex normals for smoothed polygons -Fixed selecting a brush prefab in the project producing a null reference exception -Fixed dragging a brush prefab into the scene but not under a CSG Model producing an error -Fixed flipped UVs when drawing brushes in certain situations -Fixed regression in 1.4 Beta 1 with layer and static flags not being preserved in built objects -Fixed static flags, layer and tag not being copied when transferring polygon material (which creates a temporary new mesh game object) -Fixed an issue with lightmap UV unwrapping producing overlapping UVs that caused lightmap artefacts -Fixed an issue with hidden geometry not being removed -Fixed a performance slow down when deleting a brush in scenes that have huge numbers of brushes -When reincluding a polygon, tangents are now generated in all cases where the last build had generate tangents enabled -Fixed issues with auto rebuild and partial rebuilds not picking up changes to nested brushes if the parent is transformed -Fixed some performance issues in the Face tool - - -1.3.2: - -Lightmap UV unwrapping can now be configured on the CSG Model build settings -Fixed issue with unloading a level with high brush counts taking longer -Fixed building hanging in certain situations -Fixed issue with extraneous polygons -Fixed issue with missing polygons -Rewritten subtraction code -Fixed some inconsistencies in moving a CSG Model and rebuilding -Fixed an issue where a Force Rebuild could ignore root transform changes - - -1.3.1: - -Includes support for Unity 5.4 Retina Editor -Fixes some issues relating to a serialiser conflict -Fixed minor errors thrown if you delete a brush while currently translating or rotating the UVs on its face - - -1.3.0: - -SabreCSG build engine has been rewritten from the ground up, it now tracks changes and only rebuilds brushes that have actually changed -Added an option for Auto-Rebuild, when enabled this will continually check for changes to brushes and rebuild them while you work -Meshes built when Generate Lightmap UVs is set will always have the lightmap static flag set -Built meshes now also inherit layer from the CSG Model -Built mesh objects now inherit the static flags of the CSG Model -Can now press Shift-Enter to split a brush in clip tool (in addition to the existing Enter shortcut for clip) -Clip tool now supports multi-select -When you split brushes all parts are now selected rather than just the original brush -Clip tool now traces the intersected geometry in black -Added option to clip tool to insert an edge loop (shortcut is L) -Added an option in resize tool for snapping a brush center to the absolute grid -Added buttons to the resize tool for local flipping a brush at its pivot -In axis-aligned isometric modes you can now resize a brush by using the edge of the brush, rather than just the resize handles, making it quicker to resize -Edge tool has been merged into the vertex tool, this makes it a lot more intuitive as when you split an edge the vertex is selected, or when you join two vertcies the edge is selected without changing mode. -Added option to vertex tool to split edges, inserting a vertex at their mid point. When used in conjunction with the vertex connect option this allows lots of new topologies, such as connecting a corner vertex to the centre of an edge. The previous "Split" button which would split two edges and then connect them has been renamed "Connect Mid-Points". -Vertex auto-merge is now done when you release the mouse rather than at build time. This now makes it possible to undo and redo vertex auto-merges -Added multi-select support to the vertex tool -Vertex tool now selects newly welded vertices -Connecting mid-points now supports dealing with multiple polygons across multiple brushes -Vertex tool's connect now supports vertices across multiple faces -Added an align to centre button on the face tools -Ctrl+Alt left click to paste the last selected face's material on faces -Added support for flatten and smoothing face normals -Added support to the UV scale value to take both a uniform value (e.g. 5) and a U/V scale pair (e.g. 5,2), making it possible scale U and V independently -Added support for Follow Last Face (Ctrl+Shift left click), taking the material and UVs from the last selected face and mapping them across the next selected face. -Added Copy Material - while holding C and clicking a face will apply the last selected polygon's material -Fixed some errors if you select a brush's faces and try to align them when some of them haven't actually been built. E.g. two cubes overlap, you select one which results in 6 source polygons being selected but in reality there's only 5 built polygons. -Current texture scale values are now displayed for selected faces, you can also change the values by enterring a new scale and hitting enter -Improved surface tool's handling of certain topologies -Selection helpers have been moved to a foldable section on the same page -Extrude brush now uses face orientation as a basis for the new brush's rotation, making it easier and more intuitive to resize -Face mode UI has been greatly improved, now displays a preview of both the active material and the material's main texture -Added UV offset to Face tool, works in a similar way to adjusting the UV scale. -Added axis-aligned planar mapping to Face tool -Completely new SabreCSG Grid implementation, fixes numerous issues in the old grid -Green triangulation lines on brushes have been removed and brush selection has been moved to a new method -Brushes that don't interact with CSG calculations have been renamed from Detail to NoCSG to be less confusing -Changing brush boolean mode on the toolbar now supports multiselect -Changing NoCSG, Collision and Visible flags on the toolbar now supports multiselect -Added support for changing brush boolean mode with shortcuts whith the hierarchy window focussed -Added shortcut for toggle brushes hidden (H) -Removed free mode as it is now obsolete with the changes to support disabling CSG UI when a non-CSG object is selected and the introduction of a brushes hidden shortcut -Added support for group and ungroup (shortcuts are G for group and Shift+G for ungroup) -Reintroduced the green tint for selected faces, but at a fainter level -Hierarchy ordering buttons on the brush inspector now support multiselect, also renamed as Set as First and Send Earlier, etc as it's easier to understand and less ambiguous -Added option on the brush inspector to resize a brush to fit a specified certain local bounds in addition the the existing rescale option -Fixed some issues with pressing , and . in face UI changing grid -Can now hit enter to apply resize/rescale values on the brush inspector -Fixed some issues with vertex sharing occuring when it shouldn't leading to weird problems in the surface tool -Selection cycle now resets if the selection possibilities change, this should make selection a bit more intuitive -When creating a new brush by clicking Create from the toolbar it now determines the position of the new brush by raycasting against the existing brushes, if no brushes are hit it will position the new brush at the scene view camera pivot point -Added button the brush inspector to shell a brush (create a new brush from the source brush inset by the current positional snapping value) -Added a requested preference to hide the grid in perspective scene views -Fixed the grid displaying incorrect horizontal lines when in iso horizontal views (left, front etc). The grid also now colours origin lines by axis -OBJs are now exported local to the CSG Model (this affects vertex positions and normals). -Active tool no longer resets each time you recompile -Fixed some issues with the grid drawing over brushes in certain situations -Integrated a new Linear FPS Cam which can be enabled in preferences, this overrides the scene view FPS camera with one that moves at a constant speed -Added shortcuts for changing the angular snapping (the same as the position snapping shortcuts, but with Shift held) -Angular snapping increase/decrease behaviour has now changed. While the angle is above 15 degrees it changes in 15 degree increments, below 15 degrees it changes in 5 degree increments. -Added IPostBuildListener, scripts implementing the interface that are attached or under a CSG Model will recieve a call to OnBuildFinished when the associated CSG Model build completes. This is useful if you want to use CSG Models for dynamic objects such as moving platforms. -Shell brush will no longer create invalid brushes if you try to shell a brush that is too small -Fixed some issues with resizing by bound edge with rotated bounds in Isometric Axis-Aligned scene views -Fixed some of the textures being marked as compressed, all textures that ship with SabreCSG are now marked as true color for faster import times -Fixed some issues with vertex connecting -Fixed some issues with follow last face, it will now also handle following over edges that don't share a vertex -Fixed an issue with it being difficult to resize a brush far from the origin if Unity was set to both local orientation and center pivot. -Fixed an issue with undoing a multi-select resize not rescaling all the brushes correctly -Fixed a null-reference if you undid a weld, then try to weld again without reselecting -Fixed error when selecting a CSG Model that has been disabled after changing scene -Fixed rotated brushes not displaying correct handles in axis-aligned views -Fixed exporting OBJ from a disabled CSG Model in a reloaded scene -New faces created from using the clip tool no longer use the default material, instead they use the material of one of the clipped source faces -Fixed use of Generate Lightmap UVs causing errors in Face tool -Changing a polygon's material in the face tool now preserves any UV2 or tangent information without a rebuild -Fixed a couple of errors relating to changing material when multiple polygons with a particular material set up -Fixed some issues with bounds resizing of complicated brushes with position snapping on causing vertices to drift or brushes becoming concave -Fixed an issue with handles not drawing in deferred HDR setups - - -1.2.0: - -Fixed new obsolesence code warnings in 5.3 relating to the multiscene changes -OBJ Exporter will now reset any values that are non-rational (e.g. NaN), this fixes importing into some modelling tools. This is mainly relevant to overlapping geometry built with < 1.2. -Auto UV now works off world position, rather than local position. When Auto UV'ing multiple coplanar faces they will now lay out more intuitively. -Worked around a bug in 5.3 that was throwing a passive error error "srcAttach < m_CurrentFramebuffer.colorCount && "We should always resolve only current RT"" -Fixed a null reference when selecting the face of a built brush that has been deleted and hasn't been rebuilt yet -Brush rescaling on the Inspector now supports scale triplets (e.g. 6,1,6) -Fixed handles rendering incorrectly (too dark) when Linear color space is selected -Interior geometry is now removed when building CSG -Added support to select adjacent wall faces -Added support to select adjacent ceiling or floor faces -Added support to select all adjacent geometry -Added support to select excluded faces -When you click a brush in the hierarchy in face mode, the brush faces will now be selected -Added extrude brush from face feature in face mode -Added option to weld vertices to their center in vertex mode -Added option to weld nearby vertices together within a distance tolerance -Overlapping vertices will now automatically merge on build. This means you can now collapse geometry just by moving vertices together in vertex mode. -Prisms and cylinders are now constructed with their cap faces containing a mid vertex -Added support for marquee selection of brushes in resize mode -Fixed an issue where brushes would report as being concave when they were rotated and resized -Added undo to Face tools -Added ability to select all faces with the current material (select a face with desired material first) -Added vertex connect option for splitting a face between two vertices -Added new edge mode, similar to the vertex mode, but selection is tied to edges -Added edge splitting for splitting a face between the mid-points of two edges -New rescale triplet now updates normals -Resize tool now updates normals -Fixed some bugs relating to UVs not setting dirty -Fixed a bug with brushes not automatically retracking until rebuild when restored via undo/redo -Fixed some issues relating to brush preview meshes being displayed when they should be hidden -Fixed some issues relating to the new 1.2 multiple CSG model support -Extrude brush from face will now switch to Resize mode with the new brush selected -Backfire selection is now prevented in face mode, making it easier to select faces -Fixed occasional lockup of resizing brushes -Resize cursor should no longer persist when changing modes -New 1.2 welding now updates normals and UVs -Multiselected brush tools should now work correctly with brushes nested within brushes -Fixed some issues with face aligning not working correctly with undo -Fixed issues with wrong grid being displayed in certain situations -Fixed some false negatives with concave detection to do with winding order. -Fixed some false positives with concave detection to do with scaling of angular geometry (e.g. scale a prism by 900) -Fixed some issues with missing polygons -Translation in face mode now respects UV scale and will now stay exactly aligned with the cursor at non-default scales -UV snapping in face mode now respects the positional snap distance including with faces at different UV scales -Before clicking the "x 2" button or entering a scaler of 2 would make the face twice as tiled but that seemed counterintuitive. UV scaling values have been inverted. Now clicking x 2 will make the UVs twice as big (and half as tiled). -Fixed brush resizing going off integer in some cases - - -1.1.0: - -Added support for All, None and Invert face selection modes -Added support for Auto Fit face -Added support for aligning faces to edges -Added support for excluding faces from final geometry -Resize bounds is now for the entire selection and works with local/global modes -Added support for multi-select translation by dragging the face of the resize box -Added support for multi-select translation by box handle (and ctrl) -Added support for multi-select rotation by ctrl-dragging resize handles -Added support for local/global modes in resizing -Added support for multi-select resizing -Added support for multi-select ctrl-drag copying -Added support for widgeted translation -Added support for widgeted rotation (Global pivot only) -SabreCSG interface will disappear if you select a non SabreCSG object in the hierarchy -Removed the need for CurrentSettings game object, these will auto cleanup from existing scenes -Add support for post build points, e.g. if using SuperCharacterController then you could have a hook which adds a BSPTree component to the collider -OBJ Exporter now groups exported geometry by material -Added support for prefab brushes -SabreCSG folder location is no longer hard coded, you can move the SabreCSG folder inside subfolders in Assets/ -Fixed deleted brushes remaining in brush count until rebuild -Fixed clip tool having issues with scaled brushes -Fixed shortcut issues on Windows (Rebuild is now Ctrl-Shift-R on Windows and Cmd-Shift-R on OSX) -Fixed compiler issue on Web Player platform -Fixed some issues with shift selection picking the wrong objects -Fixed some issues with disabling SabreCSG interface not persisting -Fixed issues with Unity 5.3 display -Fixed prefab support -Fixed Create and Grid dropdowns now display in correct place -Split parts from the clip tool now share the source position in the hierarchy (before one part was going to the end) - - -1.0.1: - -Fix for a build issue - - -1.0.0: - -Initial release \ No newline at end of file diff --git a/Example Materials.meta b/Example Materials.meta index 2a09c257..c3d348bb 100644 --- a/Example Materials.meta +++ b/Example Materials.meta @@ -1,5 +1,10 @@ fileFormatVersion: 2 -guid: a988c9733123f4117a68493bf4725aa9 +guid: 06844674c66487c45bc7046e52ca067f folderAsset: yes +timeCreated: 1522131882 +licenseType: Free DefaultImporter: + externalObjects: {} userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Default_Map_PaleBlue.mat.meta b/Example Materials/Default_Map_PaleBlue.mat.meta deleted file mode 100644 index 7d2bcf2b..00000000 --- a/Example Materials/Default_Map_PaleBlue.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: eb2201db09b154ec3bb3eb2f7e7aad93 -timeCreated: 1442060906 -licenseType: Free -NativeFormatImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Example Materials/Default_Map_Purple.mat.meta b/Example Materials/Default_Map_Purple.mat.meta deleted file mode 100644 index 21d5285f..00000000 --- a/Example Materials/Default_Map_Purple.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 4826ee4895e4244569956aa2fd1b6a76 -timeCreated: 1442060945 -licenseType: Free -NativeFormatImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Example Materials/Default_Map_Red.mat b/Example Materials/Default_Map_Red.mat deleted file mode 100644 index 1bc11e1c..00000000 --- a/Example Materials/Default_Map_Red.mat +++ /dev/null @@ -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: Default_Map_Red - m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} - m_ShaderKeywords: - m_LightmapFlags: 5 - m_CustomRenderQueue: -1 - stringTagMap: {} - m_SavedProperties: - serializedVersion: 2 - m_TexEnvs: - data: - first: - name: _MainTex - second: - m_Texture: {fileID: 2800000, guid: 8afdb452080da4823806bfed94123b72, type: 3} - 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} diff --git a/Example Materials/Default_Map_Red.mat.meta b/Example Materials/Default_Map_Red.mat.meta deleted file mode 100644 index 827a0f62..00000000 --- a/Example Materials/Default_Map_Red.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d49a882345078496495630533487df69 -timeCreated: 1442060941 -licenseType: Free -NativeFormatImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Example Materials/Floor_Planks.mat b/Example Materials/Floor_Planks.mat deleted file mode 100644 index 1b085460..00000000 --- a/Example Materials/Floor_Planks.mat +++ /dev/null @@ -1,149 +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: Floor_Planks - m_Shader: {fileID: 45, guid: 0000000000000000f000000000000000, type: 0} - m_ShaderKeywords: _METALLICGLOSSMAP _NORMALMAP _SPECGLOSSMAP - m_LightmapFlags: 5 - m_CustomRenderQueue: -1 - stringTagMap: {} - m_SavedProperties: - serializedVersion: 2 - m_TexEnvs: - data: - first: - name: _MainTex - second: - m_Texture: {fileID: 2800000, guid: 69ecf8e758fda4825964614013231477, type: 3} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - data: - first: - name: _BumpMap - second: - m_Texture: {fileID: 2800000, guid: a948c45b0ee794cafb8f44bf35a7cfc8, type: 3} - 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: 2800000, guid: cc4a2f15d1cef42f2a7de5b4c7c84a33, type: 3} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - data: - first: - name: _SpecGlossMap - second: - m_Texture: {fileID: 2800000, guid: cc4a2f15d1cef42f2a7de5b4c7c84a33, type: 3} - 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: 0.5 - data: - first: - name: _Parallax - second: 0.02 - data: - first: - name: _ZWrite - second: 1 - data: - first: - name: _Glossiness - second: 0.5 - data: - first: - name: _BumpScale - second: 0.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} - data: - first: - name: _SpecColor - second: {r: 0.2, g: 0.2, b: 0.2, a: 1} diff --git a/Example Materials/Floor_Planks.mat.meta b/Example Materials/Floor_Planks.mat.meta deleted file mode 100644 index 60264c8d..00000000 --- a/Example Materials/Floor_Planks.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 2b8ef763b5374480391d28a289b72ebb -timeCreated: 1442059803 -licenseType: Free -NativeFormatImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Example Materials/Textures.meta b/Example Materials/Textures.meta index cc43c154..10c14244 100644 --- a/Example Materials/Textures.meta +++ b/Example Materials/Textures.meta @@ -1,7 +1,7 @@ fileFormatVersion: 2 -guid: 9b0a3572b621a44dbbf3553a1b173c22 +guid: a195aa9d73972cb46a98d11c04e92462 folderAsset: yes -timeCreated: 1442059645 +timeCreated: 1522286777 licenseType: Free DefaultImporter: userData: diff --git a/Example Materials/Textures/Brick.png b/Example Materials/Textures/Brick.png deleted file mode 100644 index de0fb461..00000000 Binary files a/Example Materials/Textures/Brick.png and /dev/null differ diff --git a/Example Materials/Textures/Brick.png.meta b/Example Materials/Textures/Brick.png.meta deleted file mode 100644 index 0a85a666..00000000 --- a/Example Materials/Textures/Brick.png.meta +++ /dev/null @@ -1,57 +0,0 @@ -fileFormatVersion: 2 -guid: ed76038382bde4d33afbf6cceda43ae7 -timeCreated: 1442059655 -licenseType: Free -TextureImporter: - fileIDToRecycleName: {} - serializedVersion: 2 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - linearTexture: 0 - 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: 8 - cubemapConvolutionExponent: 1.5 - seamlessCubemap: 0 - textureFormat: -3 - maxTextureSize: 2048 - textureSettings: - filterMode: -1 - aniso: -1 - mipBias: -1 - wrapMode: -1 - nPOTScale: 1 - 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: 0 - textureType: -1 - buildTargetSettings: [] - spriteSheet: - sprites: [] - outline: [] - spritePackingTag: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Example Materials/Textures/Brick_Normal.png b/Example Materials/Textures/Brick_Normal.png deleted file mode 100644 index 7d514a6e..00000000 Binary files a/Example Materials/Textures/Brick_Normal.png and /dev/null differ diff --git a/Example Materials/Textures/Bricksmooth.png b/Example Materials/Textures/Bricksmooth.png deleted file mode 100644 index baf5a034..00000000 Binary files a/Example Materials/Textures/Bricksmooth.png and /dev/null differ diff --git a/Example Materials/Textures/Bricksmooth_N.png b/Example Materials/Textures/Bricksmooth_N.png deleted file mode 100644 index a800bca0..00000000 Binary files a/Example Materials/Textures/Bricksmooth_N.png and /dev/null differ diff --git a/Example Materials/Textures/Floor_Planks.png b/Example Materials/Textures/Floor_Planks.png deleted file mode 100644 index dcfd5c95..00000000 Binary files a/Example Materials/Textures/Floor_Planks.png and /dev/null differ diff --git a/Example Materials/Textures/Floor_Planks_N.png b/Example Materials/Textures/Floor_Planks_N.png deleted file mode 100644 index ab646343..00000000 Binary files a/Example Materials/Textures/Floor_Planks_N.png and /dev/null differ diff --git a/Example Materials/Textures/Floor_Planks_spec.png b/Example Materials/Textures/Floor_Planks_spec.png deleted file mode 100644 index 792e2618..00000000 Binary files a/Example Materials/Textures/Floor_Planks_spec.png and /dev/null differ diff --git a/Example Materials/Textures/default_map_GREY.png b/Example Materials/Textures/default_map_GREY.png deleted file mode 100644 index 91fc983f..00000000 Binary files a/Example Materials/Textures/default_map_GREY.png and /dev/null differ diff --git a/Example Materials/Textures/default_map_RED.png b/Example Materials/Textures/default_map_RED.png deleted file mode 100644 index a342d921..00000000 Binary files a/Example Materials/Textures/default_map_RED.png and /dev/null differ diff --git a/Example Materials/Textures/default_map_RED.png.meta b/Example Materials/Textures/default_map_RED.png.meta deleted file mode 100644 index 3364de6d..00000000 --- a/Example Materials/Textures/default_map_RED.png.meta +++ /dev/null @@ -1,57 +0,0 @@ -fileFormatVersion: 2 -guid: 8afdb452080da4823806bfed94123b72 -timeCreated: 1442059650 -licenseType: Free -TextureImporter: - fileIDToRecycleName: {} - serializedVersion: 2 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - linearTexture: 0 - 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: 8 - cubemapConvolutionExponent: 1.5 - seamlessCubemap: 0 - textureFormat: -3 - maxTextureSize: 2048 - textureSettings: - filterMode: -1 - aniso: -1 - mipBias: -1 - wrapMode: -1 - nPOTScale: 1 - 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: 0 - textureType: -1 - buildTargetSettings: [] - spriteSheet: - sprites: [] - outline: [] - spritePackingTag: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Example Materials/Textures/default_map_blue.png b/Example Materials/Textures/default_map_blue.png deleted file mode 100644 index feb1f8c7..00000000 Binary files a/Example Materials/Textures/default_map_blue.png and /dev/null differ diff --git a/Example Materials/Textures/default_map_blue.png.meta b/Example Materials/Textures/default_map_blue.png.meta deleted file mode 100644 index 5badef52..00000000 --- a/Example Materials/Textures/default_map_blue.png.meta +++ /dev/null @@ -1,57 +0,0 @@ -fileFormatVersion: 2 -guid: 742d262fda73f49e582c4ee563ab00e6 -timeCreated: 1442059649 -licenseType: Free -TextureImporter: - fileIDToRecycleName: {} - serializedVersion: 2 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - linearTexture: 0 - 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: 8 - cubemapConvolutionExponent: 1.5 - seamlessCubemap: 0 - textureFormat: -3 - maxTextureSize: 2048 - textureSettings: - filterMode: -1 - aniso: -1 - mipBias: -1 - wrapMode: -1 - nPOTScale: 1 - 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: 0 - textureType: -1 - buildTargetSettings: [] - spriteSheet: - sprites: [] - outline: [] - spritePackingTag: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Example Materials/Textures/default_map_paleBlue.png b/Example Materials/Textures/default_map_paleBlue.png deleted file mode 100644 index d8d085cf..00000000 Binary files a/Example Materials/Textures/default_map_paleBlue.png and /dev/null differ diff --git a/Example Materials/Textures/default_map_paleBlue.png.meta b/Example Materials/Textures/default_map_paleBlue.png.meta deleted file mode 100644 index f859933d..00000000 --- a/Example Materials/Textures/default_map_paleBlue.png.meta +++ /dev/null @@ -1,57 +0,0 @@ -fileFormatVersion: 2 -guid: e74ed056bfe91423bbb20a4ba62dad0c -timeCreated: 1442059654 -licenseType: Free -TextureImporter: - fileIDToRecycleName: {} - serializedVersion: 2 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - linearTexture: 0 - 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: 8 - cubemapConvolutionExponent: 1.5 - seamlessCubemap: 0 - textureFormat: -3 - maxTextureSize: 2048 - textureSettings: - filterMode: -1 - aniso: -1 - mipBias: -1 - wrapMode: -1 - nPOTScale: 1 - 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: 0 - textureType: -1 - buildTargetSettings: [] - spriteSheet: - sprites: [] - outline: [] - spritePackingTag: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Example Materials/Textures/default_map_purple.png b/Example Materials/Textures/default_map_purple.png deleted file mode 100644 index 81e75284..00000000 Binary files a/Example Materials/Textures/default_map_purple.png and /dev/null differ diff --git a/Example Materials/Textures/default_map_purple.png.meta b/Example Materials/Textures/default_map_purple.png.meta deleted file mode 100644 index 3a0b434d..00000000 --- a/Example Materials/Textures/default_map_purple.png.meta +++ /dev/null @@ -1,57 +0,0 @@ -fileFormatVersion: 2 -guid: c355a8222563c41d7a3c6cfa9c9cb23a -timeCreated: 1442059653 -licenseType: Free -TextureImporter: - fileIDToRecycleName: {} - serializedVersion: 2 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - linearTexture: 0 - 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: 8 - cubemapConvolutionExponent: 1.5 - seamlessCubemap: 0 - textureFormat: -3 - maxTextureSize: 2048 - textureSettings: - filterMode: -1 - aniso: -1 - mipBias: -1 - wrapMode: -1 - nPOTScale: 1 - 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: 0 - textureType: -1 - buildTargetSettings: [] - spriteSheet: - sprites: [] - outline: [] - spritePackingTag: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Example Materials/Textures/lambert1_Base_Color.png b/Example Materials/Textures/lambert1_Base_Color.png deleted file mode 100644 index 93c4e128..00000000 Binary files a/Example Materials/Textures/lambert1_Base_Color.png and /dev/null differ diff --git a/Example Materials/Textures/lambert1_Base_Color.png.meta b/Example Materials/Textures/lambert1_Base_Color.png.meta deleted file mode 100644 index cef3ded5..00000000 --- a/Example Materials/Textures/lambert1_Base_Color.png.meta +++ /dev/null @@ -1,57 +0,0 @@ -fileFormatVersion: 2 -guid: 865e653fc118e42bdb478e709b97134b -timeCreated: 1442059649 -licenseType: Free -TextureImporter: - fileIDToRecycleName: {} - serializedVersion: 2 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - linearTexture: 0 - 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: 8 - cubemapConvolutionExponent: 1.5 - seamlessCubemap: 0 - textureFormat: -3 - maxTextureSize: 2048 - textureSettings: - filterMode: -1 - aniso: -1 - mipBias: -1 - wrapMode: -1 - nPOTScale: 1 - 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: 0 - textureType: -1 - buildTargetSettings: [] - spriteSheet: - sprites: [] - outline: [] - spritePackingTag: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Example Materials/Textures/lambert1_Base_Normal.png b/Example Materials/Textures/lambert1_Base_Normal.png deleted file mode 100644 index e27114c9..00000000 Binary files a/Example Materials/Textures/lambert1_Base_Normal.png and /dev/null differ diff --git a/Example Materials/Textures/lambert1_Base_Spec.png b/Example Materials/Textures/lambert1_Base_Spec.png deleted file mode 100644 index 89ce24eb..00000000 Binary files a/Example Materials/Textures/lambert1_Base_Spec.png and /dev/null differ diff --git a/Example Materials/Textures/lambert1_Base_Spec.png.meta b/Example Materials/Textures/lambert1_Base_Spec.png.meta deleted file mode 100644 index d66da6c6..00000000 --- a/Example Materials/Textures/lambert1_Base_Spec.png.meta +++ /dev/null @@ -1,57 +0,0 @@ -fileFormatVersion: 2 -guid: 02a47c8c0e09744f58f40b6ef9f83956 -timeCreated: 1442059646 -licenseType: Free -TextureImporter: - fileIDToRecycleName: {} - serializedVersion: 2 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - linearTexture: 0 - 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: 8 - cubemapConvolutionExponent: 1.5 - seamlessCubemap: 0 - textureFormat: -3 - maxTextureSize: 2048 - textureSettings: - filterMode: -1 - aniso: -1 - mipBias: -1 - wrapMode: -1 - nPOTScale: 1 - 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: 0 - textureType: -1 - buildTargetSettings: [] - spriteSheet: - sprites: [] - outline: [] - spritePackingTag: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Example Materials/Textures/scsg_bricks_0_d.tga b/Example Materials/Textures/scsg_bricks_0_d.tga new file mode 100644 index 00000000..dbad9c8a Binary files /dev/null and b/Example Materials/Textures/scsg_bricks_0_d.tga differ diff --git a/Example Materials/Textures/default_map_GREY.png.meta b/Example Materials/Textures/scsg_bricks_0_d.tga.meta similarity index 93% rename from Example Materials/Textures/default_map_GREY.png.meta rename to Example Materials/Textures/scsg_bricks_0_d.tga.meta index 7abcf243..fdb25e29 100644 --- a/Example Materials/Textures/default_map_GREY.png.meta +++ b/Example Materials/Textures/scsg_bricks_0_d.tga.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 459f141e45d4345f1b14462a560d9520 -timeCreated: 1450706013 +guid: 2a7fb32a0866ac04894b42589662a4b8 +timeCreated: 1522286800 licenseType: Free TextureImporter: fileIDToRecycleName: {} @@ -26,7 +26,7 @@ TextureImporter: cubemapConvolutionSteps: 7 cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: -3 + textureFormat: -1 maxTextureSize: 2048 textureSettings: filterMode: -1 diff --git a/Example Materials/Textures/scsg_bricks_0_d2.tga b/Example Materials/Textures/scsg_bricks_0_d2.tga new file mode 100644 index 00000000..839878b8 Binary files /dev/null and b/Example Materials/Textures/scsg_bricks_0_d2.tga differ diff --git a/Example Materials/Textures/Floor_Planks.png.meta b/Example Materials/Textures/scsg_bricks_0_d2.tga.meta similarity index 90% rename from Example Materials/Textures/Floor_Planks.png.meta rename to Example Materials/Textures/scsg_bricks_0_d2.tga.meta index 106af308..d1f1c7e5 100644 --- a/Example Materials/Textures/Floor_Planks.png.meta +++ b/Example Materials/Textures/scsg_bricks_0_d2.tga.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 69ecf8e758fda4825964614013231477 -timeCreated: 1442059648 +guid: 55f9a5d4d58ec754e80dc2210c213ff5 +timeCreated: 1522286800 licenseType: Free TextureImporter: fileIDToRecycleName: {} @@ -23,10 +23,10 @@ TextureImporter: grayScaleToAlpha: 0 generateCubemap: 0 cubemapConvolution: 0 - cubemapConvolutionSteps: 8 + cubemapConvolutionSteps: 7 cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: -3 + textureFormat: -1 maxTextureSize: 2048 textureSettings: filterMode: -1 diff --git a/Example Materials/Textures/scsg_bricks_0_m.tga b/Example Materials/Textures/scsg_bricks_0_m.tga new file mode 100644 index 00000000..039c3ccb Binary files /dev/null and b/Example Materials/Textures/scsg_bricks_0_m.tga differ diff --git a/Example Materials/Textures/Bricksmooth.png.meta b/Example Materials/Textures/scsg_bricks_0_m.tga.meta similarity index 90% rename from Example Materials/Textures/Bricksmooth.png.meta rename to Example Materials/Textures/scsg_bricks_0_m.tga.meta index 97ee4f82..007595ba 100644 --- a/Example Materials/Textures/Bricksmooth.png.meta +++ b/Example Materials/Textures/scsg_bricks_0_m.tga.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: a07fb9adf062b4cd6bbef7ba4462450c -timeCreated: 1442059651 +guid: 3353858f61a67cd4c9d99784f76e8e66 +timeCreated: 1522286800 licenseType: Free TextureImporter: fileIDToRecycleName: {} @@ -23,10 +23,10 @@ TextureImporter: grayScaleToAlpha: 0 generateCubemap: 0 cubemapConvolution: 0 - cubemapConvolutionSteps: 8 + cubemapConvolutionSteps: 7 cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: -3 + textureFormat: -1 maxTextureSize: 2048 textureSettings: filterMode: -1 diff --git a/Example Materials/Textures/scsg_bricks_0_n.tga b/Example Materials/Textures/scsg_bricks_0_n.tga new file mode 100644 index 00000000..2464f99e Binary files /dev/null and b/Example Materials/Textures/scsg_bricks_0_n.tga differ diff --git a/Example Materials/Textures/Floor_Planks_N.png.meta b/Example Materials/Textures/scsg_bricks_0_n.tga.meta similarity index 90% rename from Example Materials/Textures/Floor_Planks_N.png.meta rename to Example Materials/Textures/scsg_bricks_0_n.tga.meta index 633cfd04..e50efbf3 100644 --- a/Example Materials/Textures/Floor_Planks_N.png.meta +++ b/Example Materials/Textures/scsg_bricks_0_n.tga.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: a948c45b0ee794cafb8f44bf35a7cfc8 -timeCreated: 1442059652 +guid: 90bb2075cc819e2479d0286ac978cc6e +timeCreated: 1522286835 licenseType: Free TextureImporter: fileIDToRecycleName: {} @@ -23,10 +23,10 @@ TextureImporter: grayScaleToAlpha: 0 generateCubemap: 0 cubemapConvolution: 0 - cubemapConvolutionSteps: 8 + cubemapConvolutionSteps: 7 cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: -3 + textureFormat: -1 maxTextureSize: 2048 textureSettings: filterMode: -1 diff --git a/Example Materials/Textures/scsg_bricks_0_n2.tga b/Example Materials/Textures/scsg_bricks_0_n2.tga new file mode 100644 index 00000000..e6b807a6 Binary files /dev/null and b/Example Materials/Textures/scsg_bricks_0_n2.tga differ diff --git a/Example Materials/Textures/Brick_Normal.png.meta b/Example Materials/Textures/scsg_bricks_0_n2.tga.meta similarity index 90% rename from Example Materials/Textures/Brick_Normal.png.meta rename to Example Materials/Textures/scsg_bricks_0_n2.tga.meta index 399b3a23..4bac71d4 100644 --- a/Example Materials/Textures/Brick_Normal.png.meta +++ b/Example Materials/Textures/scsg_bricks_0_n2.tga.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 49b9559fc6589480f98c273103741078 -timeCreated: 1442059647 +guid: 69a672569f3684c46aedfaadba2bdca2 +timeCreated: 1522286841 licenseType: Free TextureImporter: fileIDToRecycleName: {} @@ -23,10 +23,10 @@ TextureImporter: grayScaleToAlpha: 0 generateCubemap: 0 cubemapConvolution: 0 - cubemapConvolutionSteps: 8 + cubemapConvolutionSteps: 7 cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: -3 + textureFormat: -1 maxTextureSize: 2048 textureSettings: filterMode: -1 diff --git a/Example Materials/Textures/scsg_bricks_0_o.tga b/Example Materials/Textures/scsg_bricks_0_o.tga new file mode 100644 index 00000000..c79f9a19 Binary files /dev/null and b/Example Materials/Textures/scsg_bricks_0_o.tga differ diff --git a/Example Materials/Textures/Floor_Planks_spec.png.meta b/Example Materials/Textures/scsg_bricks_0_o.tga.meta similarity index 90% rename from Example Materials/Textures/Floor_Planks_spec.png.meta rename to Example Materials/Textures/scsg_bricks_0_o.tga.meta index 9e4eaa46..7e4fe003 100644 --- a/Example Materials/Textures/Floor_Planks_spec.png.meta +++ b/Example Materials/Textures/scsg_bricks_0_o.tga.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: cc4a2f15d1cef42f2a7de5b4c7c84a33 -timeCreated: 1442059654 +guid: 015d3ae8bb7fdc24586590079f00191e +timeCreated: 1522286799 licenseType: Free TextureImporter: fileIDToRecycleName: {} @@ -23,10 +23,10 @@ TextureImporter: grayScaleToAlpha: 0 generateCubemap: 0 cubemapConvolution: 0 - cubemapConvolutionSteps: 8 + cubemapConvolutionSteps: 7 cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: -3 + textureFormat: -1 maxTextureSize: 2048 textureSettings: filterMode: -1 diff --git a/Example Materials/Textures/scsg_bricks_1_d.tga b/Example Materials/Textures/scsg_bricks_1_d.tga new file mode 100644 index 00000000..2e06fd3e Binary files /dev/null and b/Example Materials/Textures/scsg_bricks_1_d.tga differ diff --git a/Example Materials/Textures/scsg_bricks_1_d.tga.meta b/Example Materials/Textures/scsg_bricks_1_d.tga.meta new file mode 100644 index 00000000..cf2ab903 --- /dev/null +++ b/Example Materials/Textures/scsg_bricks_1_d.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: b81a4798a14591a448b6c21a1eb340b4 +timeCreated: 1522286804 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_bricks_1_m.tga b/Example Materials/Textures/scsg_bricks_1_m.tga new file mode 100644 index 00000000..4c57951e Binary files /dev/null and b/Example Materials/Textures/scsg_bricks_1_m.tga differ diff --git a/Example Materials/Textures/scsg_bricks_1_m.tga.meta b/Example Materials/Textures/scsg_bricks_1_m.tga.meta new file mode 100644 index 00000000..c0faa3ff --- /dev/null +++ b/Example Materials/Textures/scsg_bricks_1_m.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 80a6fb8fc412b8e4584281c08b695f30 +timeCreated: 1522286802 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_bricks_1_n.tga b/Example Materials/Textures/scsg_bricks_1_n.tga new file mode 100644 index 00000000..9ad34a3f Binary files /dev/null and b/Example Materials/Textures/scsg_bricks_1_n.tga differ diff --git a/Example Materials/Textures/lambert1_Base_Normal.png.meta b/Example Materials/Textures/scsg_bricks_1_n.tga.meta similarity index 90% rename from Example Materials/Textures/lambert1_Base_Normal.png.meta rename to Example Materials/Textures/scsg_bricks_1_n.tga.meta index 48167c1f..c4427d52 100644 --- a/Example Materials/Textures/lambert1_Base_Normal.png.meta +++ b/Example Materials/Textures/scsg_bricks_1_n.tga.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: b55d4524f543a4b63902a71e67a16a8b -timeCreated: 1442059653 +guid: 0032764f85b91f64e83dd49c3a74a7e7 +timeCreated: 1522286876 licenseType: Free TextureImporter: fileIDToRecycleName: {} @@ -23,10 +23,10 @@ TextureImporter: grayScaleToAlpha: 0 generateCubemap: 0 cubemapConvolution: 0 - cubemapConvolutionSteps: 8 + cubemapConvolutionSteps: 7 cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: -3 + textureFormat: -1 maxTextureSize: 2048 textureSettings: filterMode: -1 diff --git a/Example Materials/Textures/scsg_bricks_1_o.tga b/Example Materials/Textures/scsg_bricks_1_o.tga new file mode 100644 index 00000000..dfc8d131 Binary files /dev/null and b/Example Materials/Textures/scsg_bricks_1_o.tga differ diff --git a/Example Materials/Textures/scsg_bricks_1_o.tga.meta b/Example Materials/Textures/scsg_bricks_1_o.tga.meta new file mode 100644 index 00000000..d342e05f --- /dev/null +++ b/Example Materials/Textures/scsg_bricks_1_o.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: fce541d616219a543b85f2136008491a +timeCreated: 1522286804 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_default_map_blue.tga b/Example Materials/Textures/scsg_default_map_blue.tga new file mode 100644 index 00000000..7a1361d9 Binary files /dev/null and b/Example Materials/Textures/scsg_default_map_blue.tga differ diff --git a/Example Materials/Textures/scsg_default_map_blue.tga.meta b/Example Materials/Textures/scsg_default_map_blue.tga.meta new file mode 100644 index 00000000..03429b14 --- /dev/null +++ b/Example Materials/Textures/scsg_default_map_blue.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: a76ef12d19981244fa01a5976ed56df9 +timeCreated: 1522286803 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_default_map_cyan.tga b/Example Materials/Textures/scsg_default_map_cyan.tga new file mode 100644 index 00000000..dd7fd367 Binary files /dev/null and b/Example Materials/Textures/scsg_default_map_cyan.tga differ diff --git a/Example Materials/Textures/scsg_default_map_cyan.tga.meta b/Example Materials/Textures/scsg_default_map_cyan.tga.meta new file mode 100644 index 00000000..5795710d --- /dev/null +++ b/Example Materials/Textures/scsg_default_map_cyan.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: a322c74676422ab4d8c3c604778cd532 +timeCreated: 1522286802 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_default_map_grey.tga b/Example Materials/Textures/scsg_default_map_grey.tga new file mode 100644 index 00000000..d764e434 Binary files /dev/null and b/Example Materials/Textures/scsg_default_map_grey.tga differ diff --git a/Example Materials/Textures/scsg_default_map_grey.tga.meta b/Example Materials/Textures/scsg_default_map_grey.tga.meta new file mode 100644 index 00000000..b6bf2c5a --- /dev/null +++ b/Example Materials/Textures/scsg_default_map_grey.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: f7731c2f2a066b1409997521e9be5d92 +timeCreated: 1522286804 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_default_map_purple.tga b/Example Materials/Textures/scsg_default_map_purple.tga new file mode 100644 index 00000000..d3a10a23 Binary files /dev/null and b/Example Materials/Textures/scsg_default_map_purple.tga differ diff --git a/Example Materials/Textures/scsg_default_map_purple.tga.meta b/Example Materials/Textures/scsg_default_map_purple.tga.meta new file mode 100644 index 00000000..6fbc0b7a --- /dev/null +++ b/Example Materials/Textures/scsg_default_map_purple.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 94427715ad753ef41881b7d6a9f79b66 +timeCreated: 1522286802 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_default_map_red.tga b/Example Materials/Textures/scsg_default_map_red.tga new file mode 100644 index 00000000..edfb3392 Binary files /dev/null and b/Example Materials/Textures/scsg_default_map_red.tga differ diff --git a/Example Materials/Textures/scsg_default_map_red.tga.meta b/Example Materials/Textures/scsg_default_map_red.tga.meta new file mode 100644 index 00000000..a0256eaa --- /dev/null +++ b/Example Materials/Textures/scsg_default_map_red.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 728d23cbb90607c45bdb995b6d24f727 +timeCreated: 1522286802 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_planks_0_d.tga b/Example Materials/Textures/scsg_planks_0_d.tga new file mode 100644 index 00000000..5e5a0a98 Binary files /dev/null and b/Example Materials/Textures/scsg_planks_0_d.tga differ diff --git a/Example Materials/Textures/scsg_planks_0_d.tga.meta b/Example Materials/Textures/scsg_planks_0_d.tga.meta new file mode 100644 index 00000000..41f26c50 --- /dev/null +++ b/Example Materials/Textures/scsg_planks_0_d.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: af9769b0812737240af6dba2f662c450 +timeCreated: 1522286803 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_planks_0_m.tga b/Example Materials/Textures/scsg_planks_0_m.tga new file mode 100644 index 00000000..66292b9c Binary files /dev/null and b/Example Materials/Textures/scsg_planks_0_m.tga differ diff --git a/Example Materials/Textures/scsg_planks_0_m.tga.meta b/Example Materials/Textures/scsg_planks_0_m.tga.meta new file mode 100644 index 00000000..f7751f9f --- /dev/null +++ b/Example Materials/Textures/scsg_planks_0_m.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: e0e282cf17e43494c975d225777142db +timeCreated: 1522286804 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_planks_0_n.tga b/Example Materials/Textures/scsg_planks_0_n.tga new file mode 100644 index 00000000..6afd7519 Binary files /dev/null and b/Example Materials/Textures/scsg_planks_0_n.tga differ diff --git a/Example Materials/Textures/Bricksmooth_N.png.meta b/Example Materials/Textures/scsg_planks_0_n.tga.meta similarity index 90% rename from Example Materials/Textures/Bricksmooth_N.png.meta rename to Example Materials/Textures/scsg_planks_0_n.tga.meta index 70d5e1f7..58c36324 100644 --- a/Example Materials/Textures/Bricksmooth_N.png.meta +++ b/Example Materials/Textures/scsg_planks_0_n.tga.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: f01935cef2d114d65b6c6e1c38559720 -timeCreated: 1442059656 +guid: 091fc14d3cb4fd8459bc8b7e992e50ed +timeCreated: 1522286951 licenseType: Free TextureImporter: fileIDToRecycleName: {} @@ -23,10 +23,10 @@ TextureImporter: grayScaleToAlpha: 0 generateCubemap: 0 cubemapConvolution: 0 - cubemapConvolutionSteps: 8 + cubemapConvolutionSteps: 7 cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: -3 + textureFormat: -1 maxTextureSize: 2048 textureSettings: filterMode: -1 diff --git a/Example Materials/Textures/scsg_planks_1_d.tga b/Example Materials/Textures/scsg_planks_1_d.tga new file mode 100644 index 00000000..37219428 Binary files /dev/null and b/Example Materials/Textures/scsg_planks_1_d.tga differ diff --git a/Example Materials/Textures/scsg_planks_1_d.tga.meta b/Example Materials/Textures/scsg_planks_1_d.tga.meta new file mode 100644 index 00000000..da2b97cb --- /dev/null +++ b/Example Materials/Textures/scsg_planks_1_d.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 5fc34faead95a864880618c4bdeea39d +timeCreated: 1522286802 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_planks_1_m.tga b/Example Materials/Textures/scsg_planks_1_m.tga new file mode 100644 index 00000000..75c193d6 Binary files /dev/null and b/Example Materials/Textures/scsg_planks_1_m.tga differ diff --git a/Example Materials/Textures/scsg_planks_1_m.tga.meta b/Example Materials/Textures/scsg_planks_1_m.tga.meta new file mode 100644 index 00000000..9ec42878 --- /dev/null +++ b/Example Materials/Textures/scsg_planks_1_m.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: f76f06c6b7257764286e92a1d94112af +timeCreated: 1522286804 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_planks_1_n.tga b/Example Materials/Textures/scsg_planks_1_n.tga new file mode 100644 index 00000000..ea7a55bc Binary files /dev/null and b/Example Materials/Textures/scsg_planks_1_n.tga differ diff --git a/Example Materials/Textures/scsg_planks_1_n.tga.meta b/Example Materials/Textures/scsg_planks_1_n.tga.meta new file mode 100644 index 00000000..a1294346 --- /dev/null +++ b/Example Materials/Textures/scsg_planks_1_n.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 56ecc4c928b407a4f80a22c48396fdc1 +timeCreated: 1522286980 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 1 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: 1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/scsg_planks_1_o.tga b/Example Materials/Textures/scsg_planks_1_o.tga new file mode 100644 index 00000000..cd204090 Binary files /dev/null and b/Example Materials/Textures/scsg_planks_1_o.tga differ diff --git a/Example Materials/Textures/scsg_planks_1_o.tga.meta b/Example Materials/Textures/scsg_planks_1_o.tga.meta new file mode 100644 index 00000000..28b27e16 --- /dev/null +++ b/Example Materials/Textures/scsg_planks_1_o.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 10fb91745d5dda34ca06e018683492b9 +timeCreated: 1522286800 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + 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: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + 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: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Textures/update.txt b/Example Materials/Textures/update.txt new file mode 100644 index 00000000..e4b31e58 --- /dev/null +++ b/Example Materials/Textures/update.txt @@ -0,0 +1,17 @@ +Content updated by Daniel Cornelius (Kerfuffles) +Wood textures provided by Textures.com (formerly CGTextures.com) + +[3.28.2018] +* fixed wrong project version - was using the wrong version of unity and had .meta issues with older versions. +* added credit for wood textures to the top of update.txt + +[3.27.2018] +* updated all materials +* updated all textures +* updated default materials to use mobile diffuse shaders +* updated naming of materials and textures to help when searching for other content in a project +* updated default material textures to correspond to their names more accurately +* converted all textures to targa and adjusted their alpha channels where appropriate ++ added black material +- removed old materials +- removed old textures \ No newline at end of file diff --git a/Changelog.txt.meta b/Example Materials/Textures/update.txt.meta similarity index 64% rename from Changelog.txt.meta rename to Example Materials/Textures/update.txt.meta index fd5a7109..7f5b8589 100644 --- a/Changelog.txt.meta +++ b/Example Materials/Textures/update.txt.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 8efb6caa64f9b488aba6a8d4965d1efa -timeCreated: 1466691621 +guid: 0c50319e406d5144385e584e08ab11ae +timeCreated: 1522286804 licenseType: Free TextScriptImporter: userData: diff --git a/Example Materials/lambert1.mat b/Example Materials/lambert1.mat deleted file mode 100644 index 15420161..00000000 --- a/Example Materials/lambert1.mat +++ /dev/null @@ -1,127 +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: lambert1 - m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} - m_ShaderKeywords: _EMISSION _NORMALMAP - m_LightmapFlags: 1 - m_CustomRenderQueue: -1 - stringTagMap: {} - m_SavedProperties: - serializedVersion: 2 - m_TexEnvs: - - first: - name: _BumpMap - second: - m_Texture: {fileID: 2800000, guid: b55d4524f543a4b63902a71e67a16a8b, type: 3} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _DetailAlbedoMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _DetailMask - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _DetailNormalMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _EmissionMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _MainTex - second: - m_Texture: {fileID: 2800000, guid: 865e653fc118e42bdb478e709b97134b, type: 3} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _MetallicGlossMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _OcclusionMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _ParallaxMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - m_Floats: - - first: - name: _BumpScale - second: 1 - - first: - name: _Cutoff - second: 0.5 - - first: - name: _DetailNormalMapScale - second: 1 - - first: - name: _DstBlend - second: 0 - - first: - name: _GlossMapScale - second: 1 - - first: - name: _Glossiness - second: 0.5 - - first: - name: _GlossyReflections - second: 1 - - first: - name: _Metallic - second: 0 - - first: - name: _Mode - second: 0 - - first: - name: _OcclusionStrength - second: 1 - - first: - name: _Parallax - second: 0.02 - - first: - name: _SmoothnessTextureChannel - second: 0 - - first: - name: _SpecularHighlights - second: 1 - - first: - name: _SrcBlend - second: 1 - - first: - name: _UVSec - second: 0 - - first: - name: _ZWrite - second: 1 - m_Colors: - - first: - name: _Color - second: {r: 1, g: 1, b: 1, a: 1} - - first: - name: _EmissionColor - second: {r: 0, g: 0, b: 0, a: 1} diff --git a/Example Materials/lambert1.mat.meta b/Example Materials/lambert1.mat.meta deleted file mode 100644 index 9b053a59..00000000 --- a/Example Materials/lambert1.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a72c410acd75c47a5b984cbba98a8345 -timeCreated: 1442060190 -licenseType: Free -NativeFormatImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Example Materials/scsg_black.mat b/Example Materials/scsg_black.mat new file mode 100644 index 00000000..95a57a51 --- /dev/null +++ b/Example Materials/scsg_black.mat @@ -0,0 +1,23 @@ +%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: scsg_black + m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_CustomRenderQueue: -1 + stringTagMap: {} + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: {} + m_Floats: {} + m_Colors: + data: + first: + name: _Color + second: {r: 0, g: 0, b: 0, a: 1} diff --git a/Example Materials/Bricksmooth.mat.meta b/Example Materials/scsg_black.mat.meta similarity index 52% rename from Example Materials/Bricksmooth.mat.meta rename to Example Materials/scsg_black.mat.meta index d1c11001..9b8a5847 100644 --- a/Example Materials/Bricksmooth.mat.meta +++ b/Example Materials/scsg_black.mat.meta @@ -1,8 +1,10 @@ fileFormatVersion: 2 -guid: 1a4acdb6c13bb40ec96d9ba8f86c21e1 -timeCreated: 1442059792 +guid: 0e8665057841d2941967f9c75c25b26a +timeCreated: 1522131906 licenseType: Free NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 userData: assetBundleName: assetBundleVariant: diff --git a/Example Materials/scsg_bricks_0.mat b/Example Materials/scsg_bricks_0.mat new file mode 100644 index 00000000..46d76b2f --- /dev/null +++ b/Example Materials/scsg_bricks_0.mat @@ -0,0 +1,138 @@ +%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: scsg_bricks_0 + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _DETAIL_MULX2 _METALLICGLOSSMAP _NORMALMAP + m_LightmapFlags: 4 + m_CustomRenderQueue: -1 + stringTagMap: {} + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 2800000, guid: 2a7fb32a0866ac04894b42589662a4b8, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + data: + first: + name: _BumpMap + second: + m_Texture: {fileID: 2800000, guid: 90bb2075cc819e2479d0286ac978cc6e, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + data: + first: + name: _DetailNormalMap + second: + m_Texture: {fileID: 2800000, guid: 69a672569f3684c46aedfaadba2bdca2, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + data: + first: + name: _MetallicGlossMap + second: + m_Texture: {fileID: 2800000, guid: 3353858f61a67cd4c9d99784f76e8e66, type: 3} + 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: 2800000, guid: 015d3ae8bb7fdc24586590079f00191e, type: 3} + 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: 2800000, guid: 55f9a5d4d58ec754e80dc2210c213ff5, type: 3} + 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: 0.5 + data: + first: + name: _Glossiness + second: 0.5 + data: + first: + name: _Metallic + second: 0 + data: + first: + name: _ZWrite + second: 1 + data: + first: + name: _BumpScale + second: 1 + data: + first: + name: _Parallax + second: 0.02 + data: + first: + name: _OcclusionStrength + second: 0.689 + data: + first: + name: _DetailNormalMapScale + second: 1 + data: + first: + name: _UVSec + second: 0 + data: + first: + name: _Mode + 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} diff --git a/Example Materials/Default_Map_Grey.mat.meta b/Example Materials/scsg_bricks_0.mat.meta similarity index 52% rename from Example Materials/Default_Map_Grey.mat.meta rename to Example Materials/scsg_bricks_0.mat.meta index 0ff1c3c8..6a17850b 100644 --- a/Example Materials/Default_Map_Grey.mat.meta +++ b/Example Materials/scsg_bricks_0.mat.meta @@ -1,8 +1,10 @@ fileFormatVersion: 2 -guid: 5d183e271493e4e988b8df27b1197056 -timeCreated: 1450706018 +guid: 391688459a53ab741b5d286d68f4236a +timeCreated: 1522131906 licenseType: Free NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 userData: assetBundleName: assetBundleVariant: diff --git a/Example Materials/scsg_bricks_1.mat b/Example Materials/scsg_bricks_1.mat new file mode 100644 index 00000000..027c82f7 --- /dev/null +++ b/Example Materials/scsg_bricks_1.mat @@ -0,0 +1,138 @@ +%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: scsg_bricks_1 + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _METALLICGLOSSMAP _NORMALMAP + m_LightmapFlags: 4 + m_CustomRenderQueue: -1 + stringTagMap: {} + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 2800000, guid: b81a4798a14591a448b6c21a1eb340b4, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + data: + first: + name: _BumpMap + second: + m_Texture: {fileID: 2800000, guid: 0032764f85b91f64e83dd49c3a74a7e7, type: 3} + 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: _MetallicGlossMap + second: + m_Texture: {fileID: 2800000, guid: 80a6fb8fc412b8e4584281c08b695f30, type: 3} + 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: 2800000, guid: fce541d616219a543b85f2136008491a, type: 3} + 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} + m_Floats: + data: + first: + name: _SrcBlend + second: 1 + data: + first: + name: _DstBlend + second: 0 + data: + first: + name: _Cutoff + second: 0.5 + data: + first: + name: _Glossiness + second: 0.5 + data: + first: + name: _Metallic + second: 0 + data: + first: + name: _ZWrite + second: 1 + data: + first: + name: _BumpScale + second: 1 + data: + first: + name: _Parallax + second: 0.02 + data: + first: + name: _OcclusionStrength + second: 0.496 + data: + first: + name: _DetailNormalMapScale + second: 1 + data: + first: + name: _UVSec + second: 0 + data: + first: + name: _Mode + 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} diff --git a/Example Materials/Default_Map_Blue.mat.meta b/Example Materials/scsg_bricks_1.mat.meta similarity index 52% rename from Example Materials/Default_Map_Blue.mat.meta rename to Example Materials/scsg_bricks_1.mat.meta index 0931052b..49be8cd7 100644 --- a/Example Materials/Default_Map_Blue.mat.meta +++ b/Example Materials/scsg_bricks_1.mat.meta @@ -1,8 +1,10 @@ fileFormatVersion: 2 -guid: e3c00a71048f24b2f990776b26eb586d -timeCreated: 1442060902 +guid: 1cbea93bab7a05749bd23c4408d0792a +timeCreated: 1522131906 licenseType: Free NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 userData: assetBundleName: assetBundleVariant: diff --git a/Example Materials/Default_Map_PaleBlue.mat b/Example Materials/scsg_defaultmaterial_blue.mat similarity index 93% rename from Example Materials/Default_Map_PaleBlue.mat rename to Example Materials/scsg_defaultmaterial_blue.mat index 1cc9f96a..9985cc40 100644 --- a/Example Materials/Default_Map_PaleBlue.mat +++ b/Example Materials/scsg_defaultmaterial_blue.mat @@ -6,10 +6,10 @@ Material: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} - m_Name: Default_Map_PaleBlue + m_Name: scsg_defaultmaterial_blue m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} m_ShaderKeywords: - m_LightmapFlags: 5 + m_LightmapFlags: 4 m_CustomRenderQueue: -1 stringTagMap: {} m_SavedProperties: @@ -19,7 +19,7 @@ Material: first: name: _MainTex second: - m_Texture: {fileID: 2800000, guid: e74ed056bfe91423bbb20a4ba62dad0c, type: 3} + m_Texture: {fileID: 2800000, guid: a76ef12d19981244fa01a5976ed56df9, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: @@ -90,11 +90,11 @@ Material: data: first: name: _Cutoff - second: .5 + second: 0.5 data: first: name: _Parallax - second: .0199999996 + second: 0.02 data: first: name: _ZWrite @@ -102,7 +102,7 @@ Material: data: first: name: _Glossiness - second: .5 + second: 0.365 data: first: name: _BumpScale diff --git a/Example Materials/Brick.mat.meta b/Example Materials/scsg_defaultmaterial_blue.mat.meta similarity index 52% rename from Example Materials/Brick.mat.meta rename to Example Materials/scsg_defaultmaterial_blue.mat.meta index aa92e358..81c7deac 100644 --- a/Example Materials/Brick.mat.meta +++ b/Example Materials/scsg_defaultmaterial_blue.mat.meta @@ -1,8 +1,10 @@ fileFormatVersion: 2 -guid: 8f032e6d2ebf04782b629996289e009b -timeCreated: 1442059783 +guid: c11485e230b79f147b6b04cee2e77440 +timeCreated: 1522131907 licenseType: Free NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 userData: assetBundleName: assetBundleVariant: diff --git a/Example Materials/Default_Map_Blue.mat b/Example Materials/scsg_defaultmaterial_cyan.mat similarity index 93% rename from Example Materials/Default_Map_Blue.mat rename to Example Materials/scsg_defaultmaterial_cyan.mat index fcf7f18f..3a45a774 100644 --- a/Example Materials/Default_Map_Blue.mat +++ b/Example Materials/scsg_defaultmaterial_cyan.mat @@ -6,10 +6,10 @@ Material: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} - m_Name: Default_Map_Blue + m_Name: scsg_defaultmaterial_cyan m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} m_ShaderKeywords: - m_LightmapFlags: 5 + m_LightmapFlags: 4 m_CustomRenderQueue: -1 stringTagMap: {} m_SavedProperties: @@ -19,7 +19,7 @@ Material: first: name: _MainTex second: - m_Texture: {fileID: 2800000, guid: 742d262fda73f49e582c4ee563ab00e6, type: 3} + m_Texture: {fileID: 2800000, guid: a322c74676422ab4d8c3c604778cd532, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: @@ -90,11 +90,11 @@ Material: data: first: name: _Cutoff - second: .5 + second: 0.5 data: first: name: _Parallax - second: .0199999996 + second: 0.02 data: first: name: _ZWrite @@ -102,7 +102,7 @@ Material: data: first: name: _Glossiness - second: .5 + second: 0.365 data: first: name: _BumpScale diff --git a/Example Materials/scsg_defaultmaterial_cyan.mat.meta b/Example Materials/scsg_defaultmaterial_cyan.mat.meta new file mode 100644 index 00000000..d81d5141 --- /dev/null +++ b/Example Materials/scsg_defaultmaterial_cyan.mat.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 02c0737bf00317d4084c9cd9982eb01f +timeCreated: 1522131906 +licenseType: Free +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Default_Map_Purple.mat b/Example Materials/scsg_defaultmaterial_grey.mat similarity index 93% rename from Example Materials/Default_Map_Purple.mat rename to Example Materials/scsg_defaultmaterial_grey.mat index 25327677..e3d4f211 100644 --- a/Example Materials/Default_Map_Purple.mat +++ b/Example Materials/scsg_defaultmaterial_grey.mat @@ -6,10 +6,10 @@ Material: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} - m_Name: Default_Map_Purple + m_Name: scsg_defaultmaterial_grey m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} m_ShaderKeywords: - m_LightmapFlags: 5 + m_LightmapFlags: 4 m_CustomRenderQueue: -1 stringTagMap: {} m_SavedProperties: @@ -19,7 +19,7 @@ Material: first: name: _MainTex second: - m_Texture: {fileID: 2800000, guid: c355a8222563c41d7a3c6cfa9c9cb23a, type: 3} + m_Texture: {fileID: 2800000, guid: f7731c2f2a066b1409997521e9be5d92, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: @@ -90,11 +90,11 @@ Material: data: first: name: _Cutoff - second: .5 + second: 0.5 data: first: name: _Parallax - second: .0199999996 + second: 0.02 data: first: name: _ZWrite @@ -102,7 +102,7 @@ Material: data: first: name: _Glossiness - second: .5 + second: 0.365 data: first: name: _BumpScale diff --git a/Example Materials/scsg_defaultmaterial_grey.mat.meta b/Example Materials/scsg_defaultmaterial_grey.mat.meta new file mode 100644 index 00000000..7128f02f --- /dev/null +++ b/Example Materials/scsg_defaultmaterial_grey.mat.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: a3612dfc395be5b4bb7ebd52848dfaae +timeCreated: 1522131907 +licenseType: Free +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/scsg_defaultmaterial_purple.mat b/Example Materials/scsg_defaultmaterial_purple.mat new file mode 100644 index 00000000..e0bde83e --- /dev/null +++ b/Example Materials/scsg_defaultmaterial_purple.mat @@ -0,0 +1,138 @@ +%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: scsg_defaultmaterial_purple + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_CustomRenderQueue: -1 + stringTagMap: {} + m_SavedProperties: + serializedVersion: 2 + m_TexEnvs: + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 2800000, guid: 94427715ad753ef41881b7d6a9f79b66, type: 3} + 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: 0.5 + data: + first: + name: _Parallax + second: 0.02 + data: + first: + name: _ZWrite + second: 1 + data: + first: + name: _Glossiness + second: 0.365 + 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} diff --git a/Example Materials/scsg_defaultmaterial_purple.mat.meta b/Example Materials/scsg_defaultmaterial_purple.mat.meta new file mode 100644 index 00000000..2b8539a5 --- /dev/null +++ b/Example Materials/scsg_defaultmaterial_purple.mat.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 355f39a1ac320f44095c58db21c4d6fd +timeCreated: 1522131906 +licenseType: Free +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Default_Map_Grey.mat b/Example Materials/scsg_defaultmaterial_red.mat similarity index 94% rename from Example Materials/Default_Map_Grey.mat rename to Example Materials/scsg_defaultmaterial_red.mat index 8697d631..c62ff861 100644 --- a/Example Materials/Default_Map_Grey.mat +++ b/Example Materials/scsg_defaultmaterial_red.mat @@ -6,10 +6,10 @@ Material: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} - m_Name: Default_Map_Grey + m_Name: scsg_defaultmaterial_red m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} m_ShaderKeywords: - m_LightmapFlags: 5 + m_LightmapFlags: 4 m_CustomRenderQueue: -1 stringTagMap: {} m_SavedProperties: @@ -19,7 +19,7 @@ Material: first: name: _MainTex second: - m_Texture: {fileID: 2800000, guid: 459f141e45d4345f1b14462a560d9520, type: 3} + m_Texture: {fileID: 2800000, guid: 728d23cbb90607c45bdb995b6d24f727, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: @@ -102,7 +102,7 @@ Material: data: first: name: _Glossiness - second: 0.5 + second: 0.365 data: first: name: _BumpScale diff --git a/Example Materials/scsg_defaultmaterial_red.mat.meta b/Example Materials/scsg_defaultmaterial_red.mat.meta new file mode 100644 index 00000000..ae49f026 --- /dev/null +++ b/Example Materials/scsg_defaultmaterial_red.mat.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8a27828de5a6f314a94962886ec3d659 +timeCreated: 1522131907 +licenseType: Free +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Bricksmooth.mat b/Example Materials/scsg_planks_0.mat similarity index 87% rename from Example Materials/Bricksmooth.mat rename to Example Materials/scsg_planks_0.mat index cd6852a0..790dd3f0 100644 --- a/Example Materials/Bricksmooth.mat +++ b/Example Materials/scsg_planks_0.mat @@ -6,10 +6,10 @@ Material: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} - m_Name: Bricksmooth + m_Name: scsg_planks_0 m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} - m_ShaderKeywords: _NORMALMAP - m_LightmapFlags: 5 + m_ShaderKeywords: _METALLICGLOSSMAP _NORMALMAP + m_LightmapFlags: 4 m_CustomRenderQueue: -1 stringTagMap: {} m_SavedProperties: @@ -19,14 +19,14 @@ Material: first: name: _MainTex second: - m_Texture: {fileID: 2800000, guid: a07fb9adf062b4cd6bbef7ba4462450c, type: 3} + m_Texture: {fileID: 2800000, guid: af9769b0812737240af6dba2f662c450, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: first: name: _BumpMap second: - m_Texture: {fileID: 2800000, guid: f01935cef2d114d65b6c6e1c38559720, type: 3} + m_Texture: {fileID: 2800000, guid: 091fc14d3cb4fd8459bc8b7e992e50ed, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: @@ -38,42 +38,42 @@ Material: m_Offset: {x: 0, y: 0} data: first: - name: _ParallaxMap + name: _MetallicGlossMap second: - m_Texture: {fileID: 0} + m_Texture: {fileID: 2800000, guid: e0e282cf17e43494c975d225777142db, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: first: - name: _OcclusionMap + name: _ParallaxMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: first: - name: _EmissionMap + name: _OcclusionMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: first: - name: _DetailMask + name: _EmissionMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: first: - name: _DetailAlbedoMap + name: _DetailMask second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: first: - name: _MetallicGlossMap + name: _DetailAlbedoMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} @@ -90,23 +90,27 @@ Material: data: first: name: _Cutoff - second: .5 + second: 0.5 data: first: - name: _Parallax - second: .0199999996 + name: _Glossiness + second: 0.5 data: first: - name: _ZWrite - second: 1 + name: _Metallic + second: 0 data: first: - name: _Glossiness - second: .5 + name: _ZWrite + second: 1 data: first: name: _BumpScale second: 1 + data: + first: + name: _Parallax + second: 0.02 data: first: name: _OcclusionStrength @@ -123,10 +127,6 @@ Material: first: name: _Mode second: 0 - data: - first: - name: _Metallic - second: 0 m_Colors: data: first: diff --git a/Example Materials/scsg_planks_0.mat.meta b/Example Materials/scsg_planks_0.mat.meta new file mode 100644 index 00000000..321ccbc4 --- /dev/null +++ b/Example Materials/scsg_planks_0.mat.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ec0b7a7f114fcfc4cac3fcb906d7edb2 +timeCreated: 1522131907 +licenseType: Free +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Example Materials/Brick.mat b/Example Materials/scsg_planks_1.mat similarity index 84% rename from Example Materials/Brick.mat rename to Example Materials/scsg_planks_1.mat index 4152dd3a..697bcc05 100644 --- a/Example Materials/Brick.mat +++ b/Example Materials/scsg_planks_1.mat @@ -6,10 +6,10 @@ Material: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} - m_Name: Brick + m_Name: scsg_planks_1 m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} - m_ShaderKeywords: _NORMALMAP - m_LightmapFlags: 5 + m_ShaderKeywords: _METALLICGLOSSMAP _NORMALMAP _SPECGLOSSMAP + m_LightmapFlags: 4 m_CustomRenderQueue: -1 stringTagMap: {} m_SavedProperties: @@ -19,14 +19,14 @@ Material: first: name: _MainTex second: - m_Texture: {fileID: 2800000, guid: ed76038382bde4d33afbf6cceda43ae7, type: 3} + m_Texture: {fileID: 2800000, guid: 5fc34faead95a864880618c4bdeea39d, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: first: name: _BumpMap second: - m_Texture: {fileID: 2800000, guid: 49b9559fc6589480f98c273103741078, type: 3} + m_Texture: {fileID: 2800000, guid: 56ecc4c928b407a4f80a22c48396fdc1, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: @@ -38,42 +38,42 @@ Material: m_Offset: {x: 0, y: 0} data: first: - name: _ParallaxMap + name: _MetallicGlossMap second: - m_Texture: {fileID: 0} + m_Texture: {fileID: 2800000, guid: f76f06c6b7257764286e92a1d94112af, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: first: - name: _OcclusionMap + name: _ParallaxMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: first: - name: _EmissionMap + name: _OcclusionMap second: - m_Texture: {fileID: 0} + m_Texture: {fileID: 2800000, guid: 10fb91745d5dda34ca06e018683492b9, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: first: - name: _DetailMask + name: _EmissionMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: first: - name: _DetailAlbedoMap + name: _DetailMask second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} data: first: - name: _MetallicGlossMap + name: _DetailAlbedoMap second: m_Texture: {fileID: 0} m_Scale: {x: 1, y: 1} @@ -90,23 +90,27 @@ Material: data: first: name: _Cutoff - second: .5 + second: 0.5 data: first: - name: _Parallax - second: .0199999996 + name: _Glossiness + second: 0.5 data: first: - name: _ZWrite - second: 1 + name: _Metallic + second: 0 data: first: - name: _Glossiness - second: .5 + name: _ZWrite + second: 1 data: first: name: _BumpScale second: 1 + data: + first: + name: _Parallax + second: 0.02 data: first: name: _OcclusionStrength @@ -123,10 +127,6 @@ Material: first: name: _Mode second: 0 - data: - first: - name: _Metallic - second: 0 m_Colors: data: first: diff --git a/Example Materials/scsg_planks_1.mat.meta b/Example Materials/scsg_planks_1.mat.meta new file mode 100644 index 00000000..69cc7f87 --- /dev/null +++ b/Example Materials/scsg_planks_1.mat.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 693f824b522c16046a69225b62f978cc +timeCreated: 1522131907 +licenseType: Free +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Gizmos/ButtonCone.png.meta b/Gizmos/ButtonCone.png.meta index f56d6c11..289613fa 100644 --- a/Gizmos/ButtonCone.png.meta +++ b/Gizmos/ButtonCone.png.meta @@ -4,17 +4,14 @@ timeCreated: 1516191689 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ButtonCube.png.meta b/Gizmos/ButtonCube.png.meta index 86161736..8dfd89ba 100644 --- a/Gizmos/ButtonCube.png.meta +++ b/Gizmos/ButtonCube.png.meta @@ -46,7 +46,6 @@ TextureImporter: spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 buildTargetSettings: [] spriteSheet: diff --git a/Gizmos/ButtonCurvedStairs.png.meta b/Gizmos/ButtonCurvedStairs.png.meta index 8ae3d6f0..eded995c 100644 --- a/Gizmos/ButtonCurvedStairs.png.meta +++ b/Gizmos/ButtonCurvedStairs.png.meta @@ -4,17 +4,14 @@ timeCreated: 1516366704 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ButtonCylinder.png.meta b/Gizmos/ButtonCylinder.png.meta index c37fa4e6..e7d95398 100644 --- a/Gizmos/ButtonCylinder.png.meta +++ b/Gizmos/ButtonCylinder.png.meta @@ -29,7 +29,7 @@ TextureImporter: textureFormat: -3 maxTextureSize: 2048 textureSettings: - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 wrapMode: 1 @@ -46,7 +46,6 @@ TextureImporter: spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 buildTargetSettings: [] spriteSheet: diff --git a/Gizmos/ButtonIcoSphere.png.meta b/Gizmos/ButtonIcoSphere.png.meta index 725ea93a..197078da 100644 --- a/Gizmos/ButtonIcoSphere.png.meta +++ b/Gizmos/ButtonIcoSphere.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518470967 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ButtonPrism.png.meta b/Gizmos/ButtonPrism.png.meta index b2380e84..ef8a6c66 100644 --- a/Gizmos/ButtonPrism.png.meta +++ b/Gizmos/ButtonPrism.png.meta @@ -29,7 +29,7 @@ TextureImporter: textureFormat: -3 maxTextureSize: 2048 textureSettings: - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 wrapMode: 1 @@ -46,7 +46,6 @@ TextureImporter: spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 buildTargetSettings: [] spriteSheet: diff --git a/Gizmos/ButtonShapeEditor.png.meta b/Gizmos/ButtonShapeEditor.png.meta index d71773e1..74faa3e3 100644 --- a/Gizmos/ButtonShapeEditor.png.meta +++ b/Gizmos/ButtonShapeEditor.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518471344 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ButtonSphere.png.meta b/Gizmos/ButtonSphere.png.meta index ca65a3f2..bd84eeda 100644 --- a/Gizmos/ButtonSphere.png.meta +++ b/Gizmos/ButtonSphere.png.meta @@ -29,7 +29,7 @@ TextureImporter: textureFormat: -3 maxTextureSize: 2048 textureSettings: - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 wrapMode: 1 @@ -46,7 +46,6 @@ TextureImporter: spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 buildTargetSettings: [] spriteSheet: diff --git a/Gizmos/ButtonStairs.png.meta b/Gizmos/ButtonStairs.png.meta index 1f92e1f4..039d866d 100644 --- a/Gizmos/ButtonStairs.png.meta +++ b/Gizmos/ButtonStairs.png.meta @@ -29,7 +29,7 @@ TextureImporter: textureFormat: -3 maxTextureSize: 2048 textureSettings: - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 wrapMode: 1 @@ -46,7 +46,6 @@ TextureImporter: spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 buildTargetSettings: [] spriteSheet: diff --git a/Gizmos/Group.png b/Gizmos/Group.png new file mode 100644 index 00000000..b9362a22 Binary files /dev/null and b/Gizmos/Group.png differ diff --git a/Gizmos/Group.png.meta b/Gizmos/Group.png.meta new file mode 100644 index 00000000..24fcda58 --- /dev/null +++ b/Gizmos/Group.png.meta @@ -0,0 +1,87 @@ +fileFormatVersion: 2 +guid: d3111939d820a4f45bd920faf050f29a +timeCreated: 1521296720 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + 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 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Gizmos/ImporterBackground.png b/Gizmos/ImporterBackground.png new file mode 100644 index 00000000..c1c721bc Binary files /dev/null and b/Gizmos/ImporterBackground.png differ diff --git a/Gizmos/ImporterBackground.png.meta b/Gizmos/ImporterBackground.png.meta new file mode 100644 index 00000000..ff384295 --- /dev/null +++ b/Gizmos/ImporterBackground.png.meta @@ -0,0 +1,87 @@ +fileFormatVersion: 2 +guid: e8fe8099d37fdf742a13bb041e5b67a1 +timeCreated: 1526753113 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + 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 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Gizmos/ImporterUnrealGold.png b/Gizmos/ImporterUnrealGold.png new file mode 100644 index 00000000..36b7f967 Binary files /dev/null and b/Gizmos/ImporterUnrealGold.png differ diff --git a/Gizmos/ImporterUnrealGold.png.meta b/Gizmos/ImporterUnrealGold.png.meta new file mode 100644 index 00000000..f0c6be2c --- /dev/null +++ b/Gizmos/ImporterUnrealGold.png.meta @@ -0,0 +1,87 @@ +fileFormatVersion: 2 +guid: 543dd96d3d3752d479482d09e478e7b0 +timeCreated: 1526752452 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + 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 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Gizmos/ImporterValveMapFormat2006.png b/Gizmos/ImporterValveMapFormat2006.png new file mode 100644 index 00000000..5f8ff2ae Binary files /dev/null and b/Gizmos/ImporterValveMapFormat2006.png differ diff --git a/Gizmos/ImporterValveMapFormat2006.png.meta b/Gizmos/ImporterValveMapFormat2006.png.meta new file mode 100644 index 00000000..5815773b --- /dev/null +++ b/Gizmos/ImporterValveMapFormat2006.png.meta @@ -0,0 +1,87 @@ +fileFormatVersion: 2 +guid: 0c70bdc34f6ab3646b63c29de2c3f0bb +timeCreated: 1526754071 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + 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 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Gizmos/NoCSG.png.meta b/Gizmos/NoCSG.png.meta index f1cb888e..5267b648 100644 --- a/Gizmos/NoCSG.png.meta +++ b/Gizmos/NoCSG.png.meta @@ -29,7 +29,7 @@ TextureImporter: textureFormat: -3 maxTextureSize: 2048 textureSettings: - filterMode: 0 + filterMode: 1 aniso: 1 mipBias: -1 wrapMode: 1 @@ -46,7 +46,6 @@ TextureImporter: spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 buildTargetSettings: [] spriteSheet: diff --git a/Gizmos/ShapeEditorCreatePolygon.png.meta b/Gizmos/ShapeEditorCreatePolygon.png.meta index e092e4cd..35875492 100644 --- a/Gizmos/ShapeEditorCreatePolygon.png.meta +++ b/Gizmos/ShapeEditorCreatePolygon.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518385415 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorDelete.png.meta b/Gizmos/ShapeEditorDelete.png.meta index 9aa875f3..fff386b6 100644 --- a/Gizmos/ShapeEditorDelete.png.meta +++ b/Gizmos/ShapeEditorDelete.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518386878 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorExtrudeBevel.png.meta b/Gizmos/ShapeEditorExtrudeBevel.png.meta index 3c8ae7a1..c1cd508f 100644 --- a/Gizmos/ShapeEditorExtrudeBevel.png.meta +++ b/Gizmos/ShapeEditorExtrudeBevel.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518385415 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorExtrudePoint.png.meta b/Gizmos/ShapeEditorExtrudePoint.png.meta index b3dc5c50..10a9c032 100644 --- a/Gizmos/ShapeEditorExtrudePoint.png.meta +++ b/Gizmos/ShapeEditorExtrudePoint.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518385415 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorExtrudeRevolve.png.meta b/Gizmos/ShapeEditorExtrudeRevolve.png.meta index d71d4b29..40a4f21b 100644 --- a/Gizmos/ShapeEditorExtrudeRevolve.png.meta +++ b/Gizmos/ShapeEditorExtrudeRevolve.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518385415 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorExtrudeShape.png.meta b/Gizmos/ShapeEditorExtrudeShape.png.meta index 5b92fc97..59057101 100644 --- a/Gizmos/ShapeEditorExtrudeShape.png.meta +++ b/Gizmos/ShapeEditorExtrudeShape.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518385415 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorFlipHorizontally.png.meta b/Gizmos/ShapeEditorFlipHorizontally.png.meta index a47762b6..0019f03b 100644 --- a/Gizmos/ShapeEditorFlipHorizontally.png.meta +++ b/Gizmos/ShapeEditorFlipHorizontally.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518386878 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorFlipVertically.png.meta b/Gizmos/ShapeEditorFlipVertically.png.meta index 5528fb0c..08033781 100644 --- a/Gizmos/ShapeEditorFlipVertically.png.meta +++ b/Gizmos/ShapeEditorFlipVertically.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518386878 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorHome.png.meta b/Gizmos/ShapeEditorHome.png.meta index 7222a4ce..9f89d645 100644 --- a/Gizmos/ShapeEditorHome.png.meta +++ b/Gizmos/ShapeEditorHome.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518723652 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorNew.png.meta b/Gizmos/ShapeEditorNew.png.meta index 117d8e82..79fd6e60 100644 --- a/Gizmos/ShapeEditorNew.png.meta +++ b/Gizmos/ShapeEditorNew.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518386878 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorOpen.png.meta b/Gizmos/ShapeEditorOpen.png.meta index efd48cbb..497b9a4a 100644 --- a/Gizmos/ShapeEditorOpen.png.meta +++ b/Gizmos/ShapeEditorOpen.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518386878 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorRotate90Left.png.meta b/Gizmos/ShapeEditorRotate90Left.png.meta index 053012c0..9bf6d4eb 100644 --- a/Gizmos/ShapeEditorRotate90Left.png.meta +++ b/Gizmos/ShapeEditorRotate90Left.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518440229 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorRotate90Right.png.meta b/Gizmos/ShapeEditorRotate90Right.png.meta index 090b31df..39422916 100644 --- a/Gizmos/ShapeEditorRotate90Right.png.meta +++ b/Gizmos/ShapeEditorRotate90Right.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518440229 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorSave.png.meta b/Gizmos/ShapeEditorSave.png.meta index 71788a74..4e5d1c48 100644 --- a/Gizmos/ShapeEditorSave.png.meta +++ b/Gizmos/ShapeEditorSave.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518386878 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorSegmentBezier.png.meta b/Gizmos/ShapeEditorSegmentBezier.png.meta index 8fa47f47..6e3a037e 100644 --- a/Gizmos/ShapeEditorSegmentBezier.png.meta +++ b/Gizmos/ShapeEditorSegmentBezier.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518385415 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorSegmentBezierDetail.png.meta b/Gizmos/ShapeEditorSegmentBezierDetail.png.meta index 4548787d..73611315 100644 --- a/Gizmos/ShapeEditorSegmentBezierDetail.png.meta +++ b/Gizmos/ShapeEditorSegmentBezierDetail.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518467959 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorSegmentInsert.png.meta b/Gizmos/ShapeEditorSegmentInsert.png.meta index 790a3d89..7b51135c 100644 --- a/Gizmos/ShapeEditorSegmentInsert.png.meta +++ b/Gizmos/ShapeEditorSegmentInsert.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518386878 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorSegmentLinear.png.meta b/Gizmos/ShapeEditorSegmentLinear.png.meta index d4b11b83..1f9f35f9 100644 --- a/Gizmos/ShapeEditorSegmentLinear.png.meta +++ b/Gizmos/ShapeEditorSegmentLinear.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518385415 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorShapeCreate.png.meta b/Gizmos/ShapeEditorShapeCreate.png.meta index 3f2bccc6..b7bee740 100644 --- a/Gizmos/ShapeEditorShapeCreate.png.meta +++ b/Gizmos/ShapeEditorShapeCreate.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518453820 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorShapeDuplicate.png.meta b/Gizmos/ShapeEditorShapeDuplicate.png.meta index 5f68a14a..169b8524 100644 --- a/Gizmos/ShapeEditorShapeDuplicate.png.meta +++ b/Gizmos/ShapeEditorShapeDuplicate.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518953319 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorZoomIn.png.meta b/Gizmos/ShapeEditorZoomIn.png.meta index 05035782..ace22990 100644 --- a/Gizmos/ShapeEditorZoomIn.png.meta +++ b/Gizmos/ShapeEditorZoomIn.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518386878 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Gizmos/ShapeEditorZoomOut.png.meta b/Gizmos/ShapeEditorZoomOut.png.meta index 4013b968..8b76b191 100644 --- a/Gizmos/ShapeEditorZoomOut.png.meta +++ b/Gizmos/ShapeEditorZoomOut.png.meta @@ -4,17 +4,14 @@ timeCreated: 1518386878 licenseType: Free TextureImporter: fileIDToRecycleName: {} - externalObjects: {} - serializedVersion: 4 + serializedVersion: 2 mipmaps: mipMapMode: 0 enableMipMap: 0 - sRGBTexture: 0 - linearTexture: 0 + linearTexture: 1 + correctGamma: 0 fadeOut: 0 borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: @@ -24,22 +21,23 @@ TextureImporter: normalMapFilter: 0 isReadable: 0 grayScaleToAlpha: 0 - generateCubemap: 6 + generateCubemap: 0 cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 seamlessCubemap: 0 - textureFormat: 1 + textureFormat: -3 maxTextureSize: 2048 textureSettings: - serializedVersion: 2 - filterMode: -1 + filterMode: 1 aniso: 1 mipBias: -1 - wrapU: 1 - wrapV: 1 - wrapW: -1 + wrapMode: 1 nPOTScale: 0 lightmap: 0 + rGBM: 0 compressionQuality: 50 + allowsAlphaSplitting: 0 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 @@ -47,40 +45,12 @@ TextureImporter: spritePivot: {x: 0.5, y: 0.5} spriteBorder: {x: 0, y: 0, z: 0, w: 0} spritePixelsToUnits: 100 - alphaUsage: 1 alphaIsTransparency: 1 - spriteTessellationDetail: -1 textureType: 2 - textureShape: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - platformSettings: - - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 + buildTargetSettings: [] spriteSheet: - serializedVersion: 2 sprites: [] outline: [] - physicsShape: [] spritePackingTag: userData: assetBundleName: diff --git a/Internal/Shaders/BrushPreview.shader b/Internal/Shaders/BrushPreview.shader index ffafc061..609f718e 100644 --- a/Internal/Shaders/BrushPreview.shader +++ b/Internal/Shaders/BrushPreview.shader @@ -1,32 +1,35 @@ // Based on "Legacy Shaders/Transparent/Diffuse" Shader "SabreCSG/BrushPreview" { -Properties { - _Color ("Main Color", Color) = (1,1,1,1) -} + Properties + { + _Color ("Main Color", Color) = (1,1,1,1) + } -SubShader { - Fog { Mode Off } - Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} - LOD 200 + SubShader + { + Fog { Mode Off } + Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} + LOD 200 -CGPROGRAM -#pragma surface surf Lambert alpha:blend nofog + CGPROGRAM + #pragma surface surf Lambert alpha:blend nofog -fixed4 _Color; + fixed4 _Color; -struct Input { - fixed4 color; // Can't declare empty structs in CG, so just put a filler variable to get it compiling -}; + struct Input + { + fixed4 color; // Can't declare empty structs in CG, so just put a filler variable to get it compiling + }; -void surf (Input IN, inout SurfaceOutput o) { - fixed4 c = _Color; - - o.Albedo = c.rgb; - o.Alpha = c.a; -} -ENDCG -} + void surf (Input IN, inout SurfaceOutput o) + { + fixed4 c = _Color; + o.Albedo = c.rgb; + o.Alpha = c.a; + } + ENDCG + } -Fallback "Legacy Shaders/Transparent/VertexLit" -} + Fallback "Legacy Shaders/Transparent/VertexLit" +} \ No newline at end of file diff --git a/Internal/Shaders/Grayscale-GUITexture.shader b/Internal/Shaders/Grayscale-GUITexture.shader index d0641748..0740d98d 100644 --- a/Internal/Shaders/Grayscale-GUITexture.shader +++ b/Internal/Shaders/Grayscale-GUITexture.shader @@ -1,60 +1,63 @@ - -Shader "Hidden/Grayscale-GUITexture" +Shader "Hidden/Grayscale-GUITexture" { - Properties { _MainTex ("Texture", any) = "" {} } - - SubShader { + Properties + { + _MainTex ("Texture", any) = "" {} + } - Tags { "ForceSupported" = "True" "RenderType"="Overlay" } + SubShader + { + Tags { "ForceSupported" = "True" "RenderType"="Overlay" } + Lighting Off + Blend SrcAlpha OneMinusSrcAlpha + Cull Off + ZWrite Off + ZTest Always - Lighting Off - Blend SrcAlpha OneMinusSrcAlpha - Cull Off - ZWrite Off - ZTest Always - - Pass { + Pass + { CGPROGRAM - #pragma vertex vert - #pragma fragment frag + #pragma vertex vert + #pragma fragment frag - #include "UnityCG.cginc" + #include "UnityCG.cginc" - struct appdata_t { - float4 vertex : POSITION; - fixed4 color : COLOR; - float2 texcoord : TEXCOORD0; - }; + struct appdata_t + { + float4 vertex : POSITION; + fixed4 color : COLOR; + float2 texcoord : TEXCOORD0; + }; - struct v2f { - float4 vertex : SV_POSITION; - fixed4 color : COLOR; - float2 texcoord : TEXCOORD0; - }; + struct v2f + { + float4 vertex : SV_POSITION; + fixed4 color : COLOR; + float2 texcoord : TEXCOORD0; + }; - sampler2D _MainTex; + sampler2D _MainTex; - uniform float4 _MainTex_ST; + uniform float4 _MainTex_ST; - v2f vert (appdata_t v) - { - v2f o; - o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); - o.color = v.color; - o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex); - return o; - } - - fixed4 frag (v2f i) : SV_Target - { - fixed4 col = tex2D(_MainTex, i.texcoord); - col.rgb = dot(float3(0.222, 0.707, 0.071), col.rgb); - - return 2.0f * col * i.color; - } - ENDCG + v2f vert (appdata_t v) + { + v2f o; + o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); + o.color = v.color; + o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex); + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + fixed4 col = tex2D(_MainTex, i.texcoord); + col.rgb = dot(float3(0.222, 0.707, 0.071), col.rgb); + return 2.0f * col * i.color; + } + ENDCG } - } + } - Fallback off -} + Fallback off +} \ No newline at end of file diff --git a/Resources/Materials/Default_Map.mat b/Resources/Materials/Default_Map.mat index 412ccdf5..a4269713 100644 --- a/Resources/Materials/Default_Map.mat +++ b/Resources/Materials/Default_Map.mat @@ -8,120 +8,131 @@ Material: m_PrefabInternal: {fileID: 0} m_Name: Default_Map m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} - m_ShaderKeywords: _EMISSION - m_LightmapFlags: 1 + m_ShaderKeywords: + m_LightmapFlags: 5 m_CustomRenderQueue: -1 stringTagMap: {} m_SavedProperties: serializedVersion: 2 m_TexEnvs: - - first: - name: _BumpMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _DetailAlbedoMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _DetailMask - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _DetailNormalMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _EmissionMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _MainTex - second: - m_Texture: {fileID: 2800000, guid: bc294e81e859f4f22805f2590df93571, type: 3} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _MetallicGlossMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _OcclusionMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - first: - name: _ParallaxMap - second: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} + data: + first: + name: _MainTex + second: + m_Texture: {fileID: 2800000, guid: 854edb35bcc9f4b7cbf8efafd877d736, type: 3} + 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: - - first: - name: _BumpScale - second: 1 - - first: - name: _Cutoff - second: 0.5 - - first: - name: _DetailNormalMapScale - second: 1 - - first: - name: _DstBlend - second: 0 - - first: - name: _GlossMapScale - second: 1 - - first: - name: _Glossiness - second: 0.28 - - first: - name: _GlossyReflections - second: 1 - - first: - name: _Metallic - second: 0 - - first: - name: _Mode - second: 0 - - first: - name: _OcclusionStrength - second: 1 - - first: - name: _Parallax - second: 0.02 - - first: - name: _SmoothnessTextureChannel - second: 0 - - first: - name: _SpecularHighlights - second: 1 - - first: - name: _SrcBlend - second: 1 - - first: - name: _UVSec - second: 0 - - first: - name: _ZWrite - second: 1 + data: + first: + name: _SrcBlend + second: 1 + data: + first: + name: _DstBlend + second: 0 + data: + first: + name: _Cutoff + second: 0.5 + data: + first: + name: _Parallax + second: 0.02 + data: + first: + name: _ZWrite + second: 1 + data: + first: + name: _Glossiness + second: 0.365 + 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: - - first: - name: _Color - second: {r: 1, g: 1, b: 1, a: 1} - - first: - name: _EmissionColor - second: {r: 0, g: 0, b: 0, a: 1} + 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} diff --git a/Scripts/Brushes/CompoundBrush.cs b/Scripts/Brushes/CompoundBrush.cs index 3942cacc..e2987039 100644 --- a/Scripts/Brushes/CompoundBrush.cs +++ b/Scripts/Brushes/CompoundBrush.cs @@ -42,7 +42,19 @@ public CSGModelBase GetCSGModel() return parentCsgModel; } - protected virtual void Start() + /// + /// Gets the beautiful name of the brush used in auto-generation of the hierarchy name. + /// + /// The beautiful name of the brush. + public override string BeautifulBrushName + { + get + { + return GetType().Name; + } + } + + protected virtual void Start() { generatedBrushes = new List(GetComponentsInChildren()); for (int i = 0; i < generatedBrushes.Count; i++) @@ -53,6 +65,8 @@ protected virtual void Start() public override void Invalidate (bool polygonsChanged) { + base.Invalidate(polygonsChanged); + generatedBrushes.RemoveAll(item => item == null); if(generatedBrushes.Count > BrushCount) { @@ -180,6 +194,49 @@ public override Bounds GetBoundsLocalTo(Transform otherTransform) return bounds; } + /// + /// Gets all of the polygons from all brushes in this compound brush. + /// + /// All of the polygons from all brushes in this compound brush. + public Polygon[] GetPolygons() + { + List polygons = new List(); + // iterate through all child brushes: + foreach (Brush brush in GetComponentsInChildren()) + { + polygons.AddRange(GenerateTransformedPolygons(brush.transform, brush.GetPolygons())); + } + return polygons.ToArray(); + } + + /// + /// Generates transformed polygons to match the compound brush position. + /// + /// The transform of a child brush. + /// The polygons of a child brush. + /// The transformed polygons. + private Polygon[] GenerateTransformedPolygons(Transform t, Polygon[] polygons) + { + Polygon[] polygonsCopy = polygons.DeepCopy(); + + Vector3 center = t.localPosition; + Quaternion rotation = t.localRotation; + Vector3 scale = t.lossyScale; + + for (int i = 0; i < polygonsCopy.Length; i++) + { + for (int j = 0; j < polygonsCopy[i].Vertices.Length; j++) + { + polygonsCopy[i].Vertices[j].Position = rotation * polygonsCopy[i].Vertices[j].Position.Multiply(scale) + center; + polygonsCopy[i].Vertices[j].Normal = rotation * polygonsCopy[i].Vertices[j].Normal; + } + + // Just updated a load of vertex positions, so make sure the cached plane is updated + polygonsCopy[i].CalculatePlane(); + } + + return polygonsCopy; + } public virtual PrimitiveBrush CreateBrush() { diff --git a/Scripts/Brushes/CompoundBrushes/CurvedStairBrush.cs b/Scripts/Brushes/CompoundBrushes/CurvedStairBrush.cs index 2fcd0819..f00681b6 100644 --- a/Scripts/Brushes/CompoundBrushes/CurvedStairBrush.cs +++ b/Scripts/Brushes/CompoundBrushes/CurvedStairBrush.cs @@ -18,53 +18,132 @@ public class CurvedStairBrush : CompoundBrush [SerializeField] float innerRadius = 1.0f; + /// + /// Gets or sets the radius in meters in the center of the staircase. + /// + /// The radius in meters in the center of the staircase. + public float InnerRadius { get { return innerRadius; } set { innerRadius = value; } } + /// The height of each step. [SerializeField] float stepHeight = 0.0625f; + /// + /// Gets or sets the height of each step. + /// + /// The height of each step. + public float StepHeight { get { return stepHeight; } set { stepHeight = value; } } + /// The width of each step. [SerializeField] float stepWidth = 1.0f; + /// + /// Gets or sets the width of each step. + /// + /// The width of each step. + public float StepWidth { get { return stepWidth; } set { stepWidth = value; } } + /// The amount of curvature in degrees. [SerializeField] float angleOfCurve = 90.0f; + /// + /// Gets or sets the amount of curvature in degrees. + /// + /// The amount of curvature in degrees. + public float AngleOfCurve { get { return angleOfCurve; } set { angleOfCurve = value; } } + /// The amount of steps on the staircase. [SerializeField] int numSteps = 4; + /// + /// Gets or sets the amount of steps on the staircase. + /// + /// The amount of steps on the staircase. + public int NumberOfSteps { get { return numSteps; } set { numSteps = value; } } + /// An amount of height to add to the first stair step. [SerializeField] float addToFirstStep = 0.0f; + /// + /// Gets or sets an amount of height to add to the first stair step. + /// + /// An amount of height to add to the first stair step. + public float AddToFirstStep { get { return addToFirstStep; } set { addToFirstStep = value; } } + /// Whether the stairs are mirrored counter-clockwise. [SerializeField] bool counterClockwise = false; + /// + /// Gets or sets a value indicating whether the stairs are mirrored counter-clockwise. + /// + /// true if the stairs are mirrored counter-clockwise; otherwise, false. + public bool CounterClockwise { get { return counterClockwise; } set { counterClockwise = value; } } + /// Whether the stairs reach down to the bottom. [SerializeField] bool fillToBottom = true; + /// + /// Gets or sets a value indicating whether the stairs reach down to the bottom. + /// + /// true if the stairs reach down to the bottom; otherwise, false. + public bool FillToBottom { get { return fillToBottom; } set { fillToBottom = value; } } + /// Whether to generate stairs or a curved wall. [SerializeField] bool curvedWall = false; + /// + /// Gets or sets a value indicating whether to generate stairs or a curved wall. + /// + /// true if it generates stairs; otherwise, false to generate a curved wall. + public bool CurvedWall { get { return curvedWall; } set { curvedWall = value; } } + /// Whether the floor is stairs or a smooth slope. [SerializeField] bool slopedFloor = false; + /// + /// Gets or sets a value indicating whether the floor is stairs or a smooth slope. + /// + /// true if the floor is a smooth slope; otherwise, false if the floor is stairs. + public bool SlopedFloor { get { return slopedFloor; } set { slopedFloor = value; } } + /// Whether the ceiling is stairs or a smooth slope. [SerializeField] bool slopedCeiling = false; + /// + /// Gets or sets a value indicating whether the ceiling is stairs or a smooth slope. + /// + /// true if the ceiling is a smooth slope; otherwise, false if the ceiling is stairs. + public bool SlopedCeiling { get { return slopedCeiling; } set { slopedCeiling = value; } } + /// The last known extents of the compound brush to detect user resizing the bounds. private Vector3 m_LastKnownExtents; /// The last known position of the compound brush to prevent movement on resizing the bounds. private Vector3 m_LastKnownPosition; - void Awake() + /// + /// Gets the beautiful name of the brush used in auto-generation of the hierarchy name. + /// + /// The beautiful name of the brush. + public override string BeautifulBrushName + { + get + { + return "Curved Stairs Brush"; + } + } + + protected override void Awake() { + base.Awake(); // get the last known extents and position (especially after scene changes). m_LastKnownExtents = localBounds.extents; m_LastKnownPosition = transform.localPosition; @@ -85,7 +164,7 @@ public override void UpdateVisibility () public override void Invalidate (bool polygonsChanged) { - base.Invalidate(polygonsChanged); + base.Invalidate(polygonsChanged); //////////////////////////////////////////////////////////////////// // a little hack to detect the user manually resizing the bounds. // @@ -101,7 +180,7 @@ public override void Invalidate (bool polygonsChanged) { // numSteps += 1; // m_LastKnownExtents = localBounds.extents; // - Invalidate(true); // recusion! <3 // + Invalidate(true); // recursion! <3 // return; // } // // user is trying to scale down. // @@ -110,7 +189,7 @@ public override void Invalidate (bool polygonsChanged) numSteps -= 1; // if (numSteps < 1) numSteps = 1; // m_LastKnownExtents = localBounds.extents; // - Invalidate(true); // recusion! <3 // + Invalidate(true); // recursion! <3 // return; // } // } // @@ -458,6 +537,8 @@ public override void Invalidate (bool polygonsChanged) localBounds = csgBounds; m_LastKnownExtents = localBounds.extents; m_LastKnownPosition = transform.localPosition; + // update the generated name in the hierarchy. + UpdateGeneratedHierarchyName(); } /// diff --git a/Scripts/Brushes/CompoundBrushes/Editor/CurvedStairBrushInspector.cs b/Scripts/Brushes/CompoundBrushes/Editor/CurvedStairBrushInspector.cs index 8a234335..fa6aa862 100644 --- a/Scripts/Brushes/CompoundBrushes/Editor/CurvedStairBrushInspector.cs +++ b/Scripts/Brushes/CompoundBrushes/Editor/CurvedStairBrushInspector.cs @@ -40,7 +40,7 @@ protected override void OnEnable() slopedCeiling = serializedObject.FindProperty("slopedCeiling"); } - public override void OnInspectorGUI() + public override void DoInspectorGUI() { bool oldBool; @@ -143,7 +143,7 @@ public override void OnInspectorGUI() } } - base.OnInspectorGUI(); + base.DoInspectorGUI(); } void ApplyAndInvalidate() diff --git a/Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorBrushInspector.cs b/Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorBrushInspector.cs index ad0c124a..7ff6a7db 100644 --- a/Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorBrushInspector.cs +++ b/Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorBrushInspector.cs @@ -12,7 +12,7 @@ namespace Sabresaurus.SabreCSG [CustomEditor(typeof(ShapeEditorBrush), true)] public class ShapeEditorBrushInspector : CompoundBrushInspector { - public override void OnInspectorGUI() + public override void DoInspectorGUI() { using (new NamedVerticalScope("Shape Editor Brush")) { @@ -36,7 +36,7 @@ public override void OnInspectorGUI() GUILayout.EndHorizontal(); } - base.OnInspectorGUI(); + base.DoInspectorGUI(); } } } diff --git a/Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorWindow.cs b/Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorWindow.cs index da4f2fd1..73ea04d8 100644 --- a/Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorWindow.cs +++ b/Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorWindow.cs @@ -1,4 +1,5 @@ #if UNITY_EDITOR || RUNTIME_CSG + using System; using System.Collections; using System.Collections.Generic; @@ -42,8 +43,31 @@ public class ShapeEditorWindow : EditorWindow /// private int gridScale = 16; + /// + /// The mouse position while dragging to calculate relative positioning. + /// private Vector2Int mouseDragLastGridPosition = new Vector2Int(); + /// + /// The mouse drag starting position used for marquee selections. + /// + private Vector2Int mouseDragStartGridPosition = new Vector2Int(); + + /// + /// Whether the current drag is a marquee selection box. + /// + private bool isMarqueeSelect = false; + + /// + /// The selected objects before the marquee selection started. + /// + private List marqueeSelectedObjectsBackup = new List(); + + /// + /// Whether the current drag is valid (invalid if sliding from the toolbar onto the grid). + /// + private bool isValidDrag = false; + /// /// The currently selected objects. /// @@ -145,11 +169,11 @@ private Segment GetNextSegment(Segment segment) } /// - /// Gets the segment at grid position. + /// Gets the object at the specified grid position. /// /// The x-coordinate on the grid. /// The y-coordinate on the grid. - /// The segment if found else null. + /// The object if found else null. private ISelectable GetObjectAtGridPosition(Vector2Int position) { // the global pivot point has the highest selection priority. @@ -165,7 +189,7 @@ private ISelectable GetObjectAtGridPosition(Vector2Int position) if (segment != null) return segment.bezierPivot2; } - // the segments have the medium-low priority. + // the segments have medium-low priority. foreach (Shape shape in project.shapes) { Segment segment = shape.segments.FirstOrDefault((s) => s.position == position); @@ -182,6 +206,42 @@ private ISelectable GetObjectAtGridPosition(Vector2Int position) return null; } + /// + /// Selects most objects within a marquee rectangle with multi-marquee selection support. + /// + /// The start grid position of the marquee selection. + /// The stop grid position of the marquee selection. + private void MarqueeSelectObjectsInRectangle(Vector2Int startPosition, Vector2Int stopPosition) + { + // calculate a rectangle that always uses positive numbers. + int x = stopPosition.x - startPosition.x < 0 ? stopPosition.x : startPosition.x; + int y = stopPosition.y - startPosition.y < 0 ? stopPosition.y : startPosition.y; + int w = stopPosition.x - startPosition.x < 0 ? startPosition.x - stopPosition.x : stopPosition.x - startPosition.x; + int h = stopPosition.y - startPosition.y < 0 ? startPosition.y - stopPosition.y : stopPosition.y - startPosition.y; + Rect rect = new Rect(x, y, w, h); + + List results = new List(); + // the bezier segment pivots have medium-high priority. + foreach (Shape shape in project.shapes) + { + results.AddRange(shape.segments.Where(s => s.type == SegmentType.Bezier && rect.Contains(s.bezierPivot1.position)).Select(s => (ISelectable)s.bezierPivot1)); + results.AddRange(shape.segments.Where(s => s.type == SegmentType.Bezier && rect.Contains(s.bezierPivot2.position)).Select(s => (ISelectable)s.bezierPivot2)); + } + // the segments have medium-low priority. + foreach (Shape shape in project.shapes) + { + results.AddRange(shape.segments.Where(s => rect.Contains(s.position)).Select(s => (ISelectable)s)); + } + // add all of the previously selected objects. + foreach (ISelectable obj in marqueeSelectedObjectsBackup) + { + if (!results.Contains(obj)) + results.Add(obj); + } + // select the objects in the editor. + selectedObjects = results; + } + /// /// Determines whether the global pivot is on the right side or the left side of the project /// but not inside of any shapes. @@ -248,9 +308,22 @@ private void OnGUI() // move object around with the left mouse button. if (Event.current.button == 0) { + // can't slide from the toolbar onto the grid. + if (!isValidDrag) return; + Vector2Int grid = ScreenPointToGrid(new Vector3(Event.current.mousePosition.x, Event.current.mousePosition.y)); if (GetViewportRect().Contains(Event.current.mousePosition)) { + // if we are drawing a marquee selection: + if (isMarqueeSelect) + { + // select the objects in the current marquee selection. + mouseDragLastGridPosition = grid; + MarqueeSelectObjectsInRectangle(mouseDragStartGridPosition, mouseDragLastGridPosition); + this.Repaint(); + return; // stop here so we don't move anything. + } + Vector2Int mouseGridDelta = grid - mouseDragLastGridPosition; // move the global pivot. @@ -321,25 +394,56 @@ private void OnGUI() if (Event.current.type == EventType.MouseDown) { - if (Event.current.button == 0 && GetViewportRect().Contains(Event.current.mousePosition)) + if (Event.current.button == 0) { - // if the user is not holding CTRL or SHIFT we clear the selected objects. - if ((Event.current.modifiers & EventModifiers.Control) == 0 && (Event.current.modifiers & EventModifiers.Shift) == 0) - selectedObjects.Clear(); + isValidDrag = false; - // try finding an object under the mouse cursor. - Vector2Int grid = ScreenPointToGrid(new Vector3(Event.current.mousePosition.x, Event.current.mousePosition.y)); - ISelectable found = GetObjectAtGridPosition(grid); - // if the object was already selected, deselect it. - if (found != null && selectedObjects.Contains(found)) - // deselect the object. - selectedObjects.Remove(found); - else if (found != null && !selectedObjects.Contains(found)) - // select the object. - selectedObjects.Add(found); - // store the grid position for relative dragging. - mouseDragLastGridPosition = grid; - this.Repaint(); + if (GetViewportRect().Contains(Event.current.mousePosition)) + { + // the user did not click on the toolbar so dragging is valid. + isValidDrag = true; + + // if the user is not holding CTRL or SHIFT we clear the selected objects. + if ((Event.current.modifiers & EventModifiers.Control) == 0 && (Event.current.modifiers & EventModifiers.Shift) == 0) + selectedObjects.Clear(); + + // try finding an object under the mouse cursor. + Vector2Int grid = ScreenPointToGrid(new Vector3(Event.current.mousePosition.x, Event.current.mousePosition.y)); + ISelectable found = GetObjectAtGridPosition(grid); + // if the object was already selected, deselect it. + if (found != null && selectedObjects.Contains(found)) + // deselect the object. + selectedObjects.Remove(found); + else if (found != null && !selectedObjects.Contains(found)) + // select the object. + selectedObjects.Add(found); + // store the grid position for relative dragging. + mouseDragStartGridPosition = grid; + mouseDragLastGridPosition = grid; + // if nothing was selected or the user is holding CTRL but SHIFT is not held in either case then we start a(nother) marquee selection. + if ((selectedObjects.Count == 0 || (Event.current.modifiers & EventModifiers.Control) != 0) && (Event.current.modifiers & EventModifiers.Shift) == 0) + { + // store a copy of the current selection and start the marquee select. + marqueeSelectedObjectsBackup = selectedObjects.ToList(); + isMarqueeSelect = true; + } + this.Repaint(); + } + } + } + + // have to check the raw type in case the mouse is released outside of this window. + if (Event.current.type == EventType.MouseUp || Event.current.rawType == EventType.MouseUp) + { + // if the left mouse button is released: + if (Event.current.button == 0) + { + // stop the marquee select. + if (isMarqueeSelect) + { + isMarqueeSelect = false; + this.Repaint(); + } } } @@ -490,7 +594,6 @@ private void OnGUI() // Event.current.Use(); //} - if (Event.current.type == EventType.Repaint) { if (!initialized) @@ -613,6 +716,14 @@ private void OnGUI() // draw the global pivot point. Vector2 pivotScreenPosition = GridPointToScreen(project.globalPivot.position); Handles.DrawSolidRectangleWithOutline(new Rect(pivotScreenPosition.x - 4.0f, pivotScreenPosition.y - 4.0f, 8.0f, 8.0f), Color.white, isGlobalPivotSelected ? Color.red : Color.green); + + // draw the current marquee selection. + if (isMarqueeSelect) + { + Vector2 marqueeStart = GridPointToScreen(mouseDragStartGridPosition); + Vector2 marqueeStop = GridPointToScreen(mouseDragLastGridPosition); + Handles.DrawSolidRectangleWithOutline(new Rect(marqueeStart.x, marqueeStart.y, marqueeStop.x - marqueeStart.x, marqueeStop.y - marqueeStart.y), new Color(0.2f, 0.3f, 0.8f, 0.3f), new Color(0.1f, 0.2f, 0.7f, 0.3f)); + } } GUILayout.BeginHorizontal(EditorStyles.toolbar); @@ -724,6 +835,8 @@ private void OnGUI() GenericMenu toolsMenu = new GenericMenu(); toolsMenu.AddItem(new GUIContent("Background/Load Image..."), false, OnToolsBackgroundLoadImage); toolsMenu.AddItem(new GUIContent("Background/Clear Background"), false, OnToolsBackgroundClearBackground); + toolsMenu.AddItem(new GUIContent("Global Pivot/Set Position..."), false, OnToolsPivotSetPosition); + toolsMenu.AddItem(new GUIContent("Global Pivot/Reset Position"), false, OnToolsPivotResetPosition); #if UNITY_5_4_OR_NEWER toolsMenu.DropDown(new Rect((Screen.width - 50) / EditorGUIUtility.pixelsPerPoint, 0, 0, 16)); #else @@ -778,8 +891,6 @@ private void RotateSegments(Shape[] shapes, float degrees, Vector2Int pivot) } } - - /// /// Called when the new button is pressed. Will reset the shape. /// @@ -934,9 +1045,9 @@ private void OnZoomIn() { switch (gridScale) { - case 2 : gridScale = 4 ; break; - case 4 : gridScale = 8 ; break; - case 8 : gridScale = 16; break; + case 2: gridScale = 4; break; + case 4: gridScale = 8; break; + case 8: gridScale = 16; break; case 16: gridScale = 32; break; case 32: gridScale = 64; break; case 64: gridScale = 64; break; @@ -951,10 +1062,10 @@ private void OnZoomOut() { switch (gridScale) { - case 2 : gridScale = 2 ; break; - case 4 : gridScale = 2 ; break; - case 8 : gridScale = 4 ; break; - case 16: gridScale = 8 ; break; + case 2: gridScale = 2; break; + case 4: gridScale = 2; break; + case 8: gridScale = 4; break; + case 16: gridScale = 8; break; case 32: gridScale = 16; break; case 64: gridScale = 32; break; default: gridScale = 16; break; @@ -967,10 +1078,10 @@ private void OnZoomOut() private void OnHome() { // scroll to the center of the screen. -#if UNITY_5_4_OR_NEWER +#if UNITY_2017_2_OR_NEWER viewportScroll = new Vector2(Screen.safeArea.width / 2.0f / EditorGUIUtility.pixelsPerPoint, Screen.safeArea.height / 2.0f / EditorGUIUtility.pixelsPerPoint); #else - viewportScroll = new Vector2(Screen.safeArea.width / 2.0f, Screen.safeArea.height / 2.0f); + viewportScroll = new Vector2(Screen.width / 2.0f, Screen.height / 2.0f); #endif } @@ -1112,7 +1223,8 @@ private void OnSegmentBezier() private void OnSegmentBezierDetail() { // let the user choose the amount of bezier curve detail. - ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.BezierDetailLevel, project, (self) => { + ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.BezierDetailLevel, project, (self) => + { foreach (Shape shape in project.shapes) { foreach (Segment segment in shape.segments) @@ -1144,7 +1256,8 @@ private void OnCreatePolygon(bool popup) if (popup) { // let the user choose the creation parameters. - ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.CreatePolygon, project, (self) => { + ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.CreatePolygon, project, (self) => + { // create the polygon. Selection.activeGameObject.GetComponent().CreatePolygon(project); })); @@ -1178,20 +1291,13 @@ private void OnRevolveShape(bool popup) if (popup) { // let the user choose the extrude parameters. - ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.RevolveShape, project, (self) => { + ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.RevolveShape, project, (self) => + { // store generated parameters. - if (extremeRight) - { - project.revolveDirection = true; - project.revolveRadius = project.globalPivot.position.x - minX; - project.revolveDistance = minX; - } - else - { - project.revolveDirection = false; - project.revolveRadius = maxX - project.globalPivot.position.x; - project.revolveDistance = maxX; - } + project.revolveRadius = project.globalPivot.position.x - minX; + project.revolveDistance = minX; + project.revolveDirection = extremeRight; + // extrude the shape revolved. Selection.activeGameObject.GetComponent().RevolveShape(project); })); @@ -1199,18 +1305,10 @@ private void OnRevolveShape(bool popup) else { // store generated parameters. - if (extremeRight) - { - project.revolveDirection = true; - project.revolveRadius = project.globalPivot.position.x - minX; - project.revolveDistance = minX; - } - else - { - project.revolveDirection = false; - project.revolveRadius = maxX - project.globalPivot.position.x; - project.revolveDistance = maxX; - } + project.revolveRadius = project.globalPivot.position.x - minX; + project.revolveDistance = minX; + project.revolveDirection = extremeRight; + // extrude the shape revolved. Selection.activeGameObject.GetComponent().RevolveShape(project); } @@ -1231,7 +1329,8 @@ private void OnExtrudeShape(bool popup) if (popup) { // let the user choose the extrude parameters. - ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.ExtrudeShape, project, (self) => { + ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.ExtrudeShape, project, (self) => + { // extrude the shape. Selection.activeGameObject.GetComponent().ExtrudeShape(project); })); @@ -1258,7 +1357,8 @@ private void OnExtrudePoint(bool popup) if (popup) { // let the user choose the extrude parameters. - ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.ExtrudePoint, project, (self) => { + ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.ExtrudePoint, project, (self) => + { // extrude the shape to a point. Selection.activeGameObject.GetComponent().ExtrudePoint(project); })); @@ -1285,7 +1385,8 @@ private void OnExtrudeBevel(bool popup) if (popup) { // let the user choose the extrude parameters. - ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.ExtrudeBevel, project, (self) => { + ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.ExtrudeBevel, project, (self) => + { // extrude the shape to a point but capped to cause a trapezoid. Selection.activeGameObject.GetComponent().ExtrudeBevel(project); })); @@ -1325,14 +1426,42 @@ private void OnToolsBackgroundClearBackground() backgroundImage = null; } + /// + /// Called when the tools 'menu/pivot/set position' item is pressed. + /// + private void OnToolsPivotSetPosition() + { + // let the user choose the global pivot position. + ShowCenteredPopupWindowContent(new ShapeEditorWindowPopup(ShapeEditorWindowPopup.PopupMode.GlobalPivotPosition, project, (self) => + { + // set the new global pivot position. + project.globalPivot.position = self.GlobalPivotPosition_Position; + + // show the changes. + Repaint(); + })); + } + + /// + /// Called when the tools 'menu/pivot/reset position' item is pressed. + /// + private void OnToolsPivotResetPosition() + { + project.globalPivot.position = Vector2Int.zero; + } + private Rect GetViewportRect() { +#if UNITY_2017_2_OR_NEWER Rect viewportRect = Screen.safeArea; +#else + Rect viewportRect = new Rect(0, 0, Screen.width, Screen.height); +#endif viewportRect.y += 18; viewportRect.height -= 40; return viewportRect; } - + private void GlDrawLine(float thickness, float x1, float y1, float x2, float y2) { var point1 = new Vector2(x1, y1); @@ -1453,11 +1582,15 @@ private Vector2 GridPointToScreen(Vector2Int point) private void ShowCenteredPopupWindowContent(PopupWindowContent popup) { Vector2 size = popup.GetWindowSize(); -#if UNITY_5_4_OR_NEWER - PopupWindow.Show(new Rect((Screen.safeArea.width / 2.0f / EditorGUIUtility.pixelsPerPoint) - (size.x / 2.0f), (Screen.safeArea.height / 2.0f / EditorGUIUtility.pixelsPerPoint) - (size.y / 2.0f), 0, 0), popup); + try + { +#if UNITY_2017_2_OR_NEWER + PopupWindow.Show(new Rect((Screen.safeArea.width / 2.0f / EditorGUIUtility.pixelsPerPoint) - (size.x / 2.0f), (Screen.safeArea.height / 2.0f / EditorGUIUtility.pixelsPerPoint) - (size.y / 2.0f), 0, 0), popup); #else - PopupWindow.Show(new Rect((Screen.safeArea.width / 2.0f) - (size.x / 2.0f), (Screen.safeArea.height / 2.0f) - (size.y / 2.0f), 0, 0), popup); + PopupWindow.Show(new Rect((Screen.width / 2.0f) - (size.x / 2.0f), (Screen.height / 2.0f) - (size.y / 2.0f), 0, 0), popup); #endif + } + catch (ExitGUIException) { } } /// diff --git a/Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorWindowPopup.cs b/Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorWindowPopup.cs index 8d18bde5..49db3715 100644 --- a/Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorWindowPopup.cs +++ b/Scripts/Brushes/CompoundBrushes/Editor/ShapeEditorWindowPopup.cs @@ -1,4 +1,5 @@ #if UNITY_EDITOR || RUNTIME_CSG + using System; using System.Collections.Generic; using System.Linq; @@ -17,11 +18,12 @@ public class ShapeEditorWindowPopup : PopupWindowContent public enum PopupMode { BezierDetailLevel, + GlobalPivotPosition, CreatePolygon, RevolveShape, ExtrudeShape, ExtrudePoint, - ExtrudeBevel + ExtrudeBevel, } private PopupMode popupMode; @@ -32,6 +34,9 @@ public enum PopupMode public Vector2 extrudeScale = Vector2.one; public int revolve360 = 8; public int revolveSteps = 4; + public bool revolveSpiralSloped = false; + public Vector2Int GlobalPivotPosition_Position; + public bool convexBrushes = true; private Action onApply; @@ -45,30 +50,43 @@ public ShapeEditorWindowPopup(PopupMode popupMode, ShapeEditor.Project project, extrudeScale = project.extrudeScale; revolve360 = project.revolve360; revolveSteps = project.revolveSteps; + revolveSpiralSloped = project.revolveSpiralSloped; + convexBrushes = project.convexBrushes; + GlobalPivotPosition_Position = project.globalPivot.position; - this.onApply = (self) => { - + this.onApply = (self) => + { // store the extrude settings in the project. switch (popupMode) { case PopupMode.CreatePolygon: project.extrudeScale = extrudeScale; + project.convexBrushes = convexBrushes; break; + case PopupMode.RevolveShape: project.extrudeScale = extrudeScale; + project.convexBrushes = convexBrushes; project.revolve360 = revolve360; project.revolveSteps = revolveSteps; + project.revolveSpiralSloped = revolveSpiralSloped; break; + case PopupMode.ExtrudeShape: project.extrudeScale = extrudeScale; + project.convexBrushes = convexBrushes; project.extrudeDepth = extrudeDepth; break; + case PopupMode.ExtrudePoint: project.extrudeScale = extrudeScale; + project.convexBrushes = convexBrushes; project.extrudeDepth = extrudeDepth; break; + case PopupMode.ExtrudeBevel: project.extrudeScale = extrudeScale; + project.convexBrushes = convexBrushes; project.extrudeDepth = extrudeDepth; project.extrudeClipDepth = extrudeClipDepth; break; @@ -82,20 +100,30 @@ public ShapeEditorWindowPopup(PopupMode popupMode, ShapeEditor.Project project, public override Vector2 GetWindowSize() { + // + 18 for every element switch (popupMode) { case PopupMode.BezierDetailLevel: return new Vector2(205, 140); + + case PopupMode.GlobalPivotPosition: + return new Vector2(300, 68); + case PopupMode.CreatePolygon: - return new Vector2(300, 50 + 18); + return new Vector2(300, 50 + 36); + case PopupMode.RevolveShape: - return new Vector2(300, 86 + 18); + return new Vector2(300, 104 + 36); + case PopupMode.ExtrudeShape: - return new Vector2(300, 68 + 18); + return new Vector2(300, 68 + 36); + case PopupMode.ExtrudePoint: - return new Vector2(300, 68 + 18); + return new Vector2(300, 68 + 36); + case PopupMode.ExtrudeBevel: - return new Vector2(300, 86 + 18); + return new Vector2(300, 86 + 36); + default: return new Vector2(300, 150); } @@ -104,12 +132,14 @@ public override Vector2 GetWindowSize() public override void OnGUI(Rect rect) { bool hasScale = true; + bool hasConvexBrushes = true; string accept = ""; switch (popupMode) { case PopupMode.BezierDetailLevel: GUILayout.Label("Bezier Detail Level", EditorStyles.boldLabel); hasScale = false; + hasConvexBrushes = false; accept = "Apply"; GUILayout.BeginHorizontal(EditorStyles.toolbar); @@ -161,6 +191,23 @@ public override void OnGUI(Rect rect) if (bezierDetailLevel_Detail > 999) bezierDetailLevel_Detail = 999; break; + case PopupMode.GlobalPivotPosition: + GUILayout.Label("Global Pivot Position", EditorStyles.boldLabel); + hasScale = false; + hasConvexBrushes = false; + accept = "Set Position"; + +#if !UNITY_2017_2_OR_NEWER + EditorGUIUtility.wideMode = true; + GlobalPivotPosition_Position = Vector2Int.FloorToInt(EditorGUILayout.Vector2Field("Position", GlobalPivotPosition_Position)); + EditorGUIUtility.wideMode = false; +#else + EditorGUIUtility.wideMode = true; + GlobalPivotPosition_Position = EditorGUILayout.Vector2IntField("Position", GlobalPivotPosition_Position); + EditorGUIUtility.wideMode = false; +#endif + break; + case PopupMode.CreatePolygon: GUILayout.Label("Create Polygon", EditorStyles.boldLabel); accept = "Create"; @@ -175,6 +222,8 @@ public override void OnGUI(Rect rect) revolveSteps = EditorGUILayout.IntField("Steps", revolveSteps); if (revolveSteps < 1) revolveSteps = 1; + revolveSpiralSloped = EditorGUILayout.Toggle("Sloped Spiral", revolveSpiralSloped); + // steps can't be more than 360. if (revolveSteps > revolve360) revolveSteps = revolve360; break; @@ -207,6 +256,11 @@ public override void OnGUI(Rect rect) break; } + if (hasConvexBrushes) + { + convexBrushes = EditorGUILayout.Toggle("Convex Brushes", convexBrushes); + } + if (hasScale) { EditorGUIUtility.wideMode = true; diff --git a/Scripts/Brushes/CompoundBrushes/Editor/StairBrushInspector.cs b/Scripts/Brushes/CompoundBrushes/Editor/StairBrushInspector.cs index 7744cf21..a6ecab80 100644 --- a/Scripts/Brushes/CompoundBrushes/Editor/StairBrushInspector.cs +++ b/Scripts/Brushes/CompoundBrushes/Editor/StairBrushInspector.cs @@ -44,7 +44,7 @@ protected override void OnEnable () fillToBottom = serializedObject.FindProperty ("fillToBottom"); } - public override void OnInspectorGUI() + public override void DoInspectorGUI() { Rect rect = GUILayoutUtility.GetRect(new GUIContent(), GUI.skin.box, GUILayout.ExpandWidth(true), GUILayout.Height(130)); @@ -105,7 +105,7 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); } - base.OnInspectorGUI(); + base.DoInspectorGUI(); } private void DrawStairPreview(Rect rect) diff --git a/Scripts/Brushes/CompoundBrushes/Editor/TrimBrushInspector.cs b/Scripts/Brushes/CompoundBrushes/Editor/TrimBrushInspector.cs index 26236b77..e657be91 100644 --- a/Scripts/Brushes/CompoundBrushes/Editor/TrimBrushInspector.cs +++ b/Scripts/Brushes/CompoundBrushes/Editor/TrimBrushInspector.cs @@ -20,7 +20,7 @@ protected override void OnEnable () trimSizeProp = serializedObject.FindProperty ("trimSize"); } - public override void OnInspectorGUI() + public override void DoInspectorGUI() { using (new NamedVerticalScope("TrimBrush")) { @@ -34,7 +34,7 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); } - base.OnInspectorGUI(); + base.DoInspectorGUI(); } void ApplyAndInvalidate() diff --git a/Scripts/Brushes/CompoundBrushes/ShapeEditor/Project.cs b/Scripts/Brushes/CompoundBrushes/ShapeEditor/Project.cs index d5518001..74cff746 100644 --- a/Scripts/Brushes/CompoundBrushes/ShapeEditor/Project.cs +++ b/Scripts/Brushes/CompoundBrushes/ShapeEditor/Project.cs @@ -1,4 +1,5 @@ #if UNITY_EDITOR || RUNTIME_CSG + using System; using System.Collections.Generic; using System.Linq; @@ -94,6 +95,18 @@ public class Project [SerializeField] public bool revolveDirection = true; + /// + /// Whether the spiral is like stairs or a smooth slope. + /// + [SerializeField] + public bool revolveSpiralSloped = false; + + /// + /// Whether the shape uses Convex Decomposition or Concave Shapes. + /// + [SerializeField] + public bool convexBrushes = true; + /// /// Clones this project and returns the copy. /// @@ -105,4 +118,5 @@ public Project Clone() } } } + #endif \ No newline at end of file diff --git a/Scripts/Brushes/CompoundBrushes/ShapeEditor/ShapeEditorBrush.cs b/Scripts/Brushes/CompoundBrushes/ShapeEditor/ShapeEditorBrush.cs index 86113e62..0283eb1d 100644 --- a/Scripts/Brushes/CompoundBrushes/ShapeEditor/ShapeEditorBrush.cs +++ b/Scripts/Brushes/CompoundBrushes/ShapeEditor/ShapeEditorBrush.cs @@ -1,4 +1,5 @@ #if UNITY_EDITOR || RUNTIME_CSG + using Sabresaurus.SabreCSG.ShapeEditor.Decomposition; using System; using System.Collections; @@ -28,18 +29,22 @@ public enum ExtrudeMode /// Creates a flat polygon in NoCSG mode. /// CreatePolygon, + /// /// Revolves the shapes. /// RevolveShape, + /// /// Extrudes the shapes. /// ExtrudeShape, + /// /// Extrudes the shapes to a point. /// ExtrudePoint, + /// /// Extrudes the shapes bevelled. /// @@ -48,29 +53,42 @@ public enum ExtrudeMode /// The 2D Shape Editor Project (latest project used to build this brush). [SerializeField] - Project project = JsonUtility.FromJson("{\"version\":1,\"shapes\":[{\"segments\":[{\"_position\":{\"x\":-18,\"y\":-8},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-14,\"y\":-11},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-14,\"y\":-13},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-20,\"y\":-13},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-10,\"y\":-19},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-6,\"y\":-19},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-6,\"y\":-16},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-3,\"y\":-19},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":6,\"y\":-19},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":9,\"y\":-16},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":11,\"y\":-16},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":14,\"y\":-12},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":14,\"y\":-2},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":10,\"y\":-8},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":9,\"y\":-11},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":5,\"y\":-15},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-2,\"y\":-16},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-3,\"y\":-11},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":9,\"y\":-11},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":10,\"y\":-8},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":6,\"y\":-8},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-2,\"y\":-1},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-2,\"y\":3},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":5,\"y\":6},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":12,\"y\":6},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":10,\"y\":8},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-10,\"y\":8},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-18,\"y\":0},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3}],\"pivot\":{\"_position\":{\"x\":0,\"y\":-8}}}],\"globalPivot\":{\"_position\":{\"x\":0,\"y\":0}},\"flipHorizontally\":false,\"flipVertically\":false,\"extrudeDepth\":1.0,\"extrudeClipDepth\":0.5,\"extrudeScale\":{\"x\":1.0,\"y\":1.0},\"revolve360\":8,\"revolveSteps\":4,\"revolveDistance\":1,\"revolveRadius\":1,\"revolveDirection\":true}"); + private Project project = JsonUtility.FromJson("{\"version\":1,\"shapes\":[{\"segments\":[{\"_position\":{\"x\":-18,\"y\":-8},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-14,\"y\":-11},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-14,\"y\":-13},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-20,\"y\":-13},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-10,\"y\":-19},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-6,\"y\":-19},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-6,\"y\":-16},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-3,\"y\":-19},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":6,\"y\":-19},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":9,\"y\":-16},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":11,\"y\":-16},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":14,\"y\":-12},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":14,\"y\":-2},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":10,\"y\":-8},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":9,\"y\":-11},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":5,\"y\":-15},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-2,\"y\":-16},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-3,\"y\":-11},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":9,\"y\":-11},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":10,\"y\":-8},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":6,\"y\":-8},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-2,\"y\":-1},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-2,\"y\":3},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":5,\"y\":6},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":12,\"y\":6},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":10,\"y\":8},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-10,\"y\":8},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3},{\"_position\":{\"x\":-18,\"y\":0},\"type\":0,\"bezierPivot1\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierPivot2\":{\"_position\":{\"x\":-2,\"y\":-6}},\"bezierDetail\":3}],\"pivot\":{\"_position\":{\"x\":0,\"y\":-8}}}],\"globalPivot\":{\"_position\":{\"x\":0,\"y\":0}},\"flipHorizontally\":false,\"flipVertically\":false,\"extrudeDepth\":1.0,\"extrudeClipDepth\":0.5,\"extrudeScale\":{\"x\":1.0,\"y\":1.0},\"revolve360\":8,\"revolveSteps\":4,\"revolveDistance\":1,\"revolveRadius\":1,\"revolveDirection\":true}"); /// /// The extrude mode (latest operation used to build this brush). /// [SerializeField] - ExtrudeMode extrudeMode = ExtrudeMode.ExtrudeShape; + private ExtrudeMode extrudeMode = ExtrudeMode.ExtrudeShape; /// /// The last built polygons determine the needed to build the /// compound brush. /// [SerializeField] - int desiredBrushCount; + private int desiredBrushCount; /// /// Whether the geometry has been changed through one of the extrude methods. /// [SerializeField] - bool isDirty = true; + private bool isDirty = true; + + /// + /// Gets the beautiful name of the brush used in auto-generation of the hierarchy name. + /// + /// The beautiful name of the brush. + public override string BeautifulBrushName + { + get + { + return "2D Shape Editor Brush"; + } + } /// The last known extents of the compound brush to detect user resizing the bounds. private Vector3 m_LastKnownExtents; + /// The last known position of the compound brush to prevent movement on resizing the bounds. private Vector3 m_LastKnownPosition; @@ -80,8 +98,9 @@ public enum ExtrudeMode /// private List m_LastBuiltPolygons; - void Awake() + protected override void Awake() { + base.Awake(); // get the last known extents and position (especially after scene changes). m_LastKnownExtents = localBounds.extents; m_LastKnownPosition = transform.localPosition; @@ -91,6 +110,10 @@ public override int BrushCount { get { + // if the user desires a single concave brush we return 1. + if (!project.convexBrushes) + return 1; + // we already know the amount of brushes we need. if (!isDirty) return desiredBrushCount; @@ -122,10 +145,22 @@ public override void Invalidate(bool polygonsChanged) //////////////////////////////////////////////////////////////////// Bounds csgBounds = new Bounds(); + // force nocsg when creating a flat polygon sheet as sabrecsg doesn't support it. + if (extrudeMode == ExtrudeMode.CreatePolygon) + this.IsNoCSG = true; + + // force nocsg when revolving with a sloped spiral as there are non-planar polygons. + if (extrudeMode == ExtrudeMode.RevolveShape && project.revolveSpiralSloped && project.globalPivot.position.y != 0) + this.IsNoCSG = true; + + // force nocsg when using concave brushes as sabrecsg doesn't support it. + if (!project.convexBrushes) + this.IsNoCSG = true; + // nothing to do except copy csg information to our child brushes. if (!isDirty) { - for (int i = 0; i < BrushCount; i++) + for (int i = 0; i < (project.convexBrushes ? desiredBrushCount : 1); i++) { generatedBrushes[i].Mode = this.Mode; generatedBrushes[i].IsNoCSG = this.IsNoCSG; @@ -148,20 +183,22 @@ public override void Invalidate(bool polygonsChanged) if (m_LastBuiltPolygons == null) m_LastBuiltPolygons = BuildConvexPolygons(); - // iterate through the brushes we received: - int brushCount = BrushCount; + // prepare a list of polygons for concave brushes. + List concavePolygons = null; + if (!project.convexBrushes) + concavePolygons = new List(); - // force nocsg when creating a flat polygon sheet as sabrecsg doesn't support it. - if (extrudeMode == ExtrudeMode.CreatePolygon) - this.IsNoCSG = true; + // iterate through the brushes we received: + int brushCount = desiredBrushCount; + // iterate through the brushes we received: for (int i = 0; i < brushCount; i++) { // copy our csg information to our child brushes. - generatedBrushes[i].Mode = this.Mode; - generatedBrushes[i].IsNoCSG = this.IsNoCSG; - generatedBrushes[i].IsVisible = this.IsVisible; - generatedBrushes[i].HasCollision = this.HasCollision; + generatedBrushes[project.convexBrushes ? i : 0].Mode = this.Mode; + generatedBrushes[project.convexBrushes ? i : 0].IsNoCSG = this.IsNoCSG; + generatedBrushes[project.convexBrushes ? i : 0].IsVisible = this.IsVisible; + generatedBrushes[project.convexBrushes ? i : 0].HasCollision = this.HasCollision; // local variables. Quaternion rot; @@ -175,11 +212,17 @@ public override void Invalidate(bool polygonsChanged) GenerateUvCoordinates(m_LastBuiltPolygons[i], false); Polygon poly1 = m_LastBuiltPolygons[i].DeepCopy(); poly1.Flip(); - generatedBrushes[i].SetPolygons(new Polygon[] { poly1 }); + + if (project.convexBrushes) + generatedBrushes[i].SetPolygons(new Polygon[] { poly1 }); + else + concavePolygons.Add(poly1); break; - // generate 3d cube-ish shapes that revolve around the pivot. + // generate 3d cube-ish shapes that revolve around the pivot and spirals up or down. case ExtrudeMode.RevolveShape: + float spiralHeight = ((((project.globalPivot.position.y * project.extrudeScale.y) / 8.0f) * (i / m_LastBuiltPolygons.Count)) / project.revolve360) * (project.revolve360 / project.revolveSteps); + float spiralStep = ((((project.globalPivot.position.y * project.extrudeScale.y) / 8.0f)) / project.revolve360) * (project.revolve360 / project.revolveSteps); int labpIndex = i % m_LastBuiltPolygons.Count; Polygon poly2 = m_LastBuiltPolygons[labpIndex].DeepCopy(); @@ -188,16 +231,17 @@ public override void Invalidate(bool polygonsChanged) foreach (Vertex v in poly2.Vertices) { float step = 360.0f / project.revolve360; - v.Position = RotatePointAroundPivot(v.Position, new Vector3(((project.revolveDistance / 8.0f) * project.extrudeScale.x) + ((project.revolveRadius * project.extrudeScale.x) / 8.0f), 0.0f, 0.0f), new Vector3(0.0f, (project.revolveDirection ? 0 : 180) + ((i / m_LastBuiltPolygons.Count) * step), 0.0f)); + v.Position = new Vector3(0, -spiralHeight, 0) + RotatePointAroundPivot(v.Position, new Vector3(((project.revolveDistance / 8.0f) * project.extrudeScale.x) + ((project.revolveRadius * project.extrudeScale.x) / 8.0f), 0.0f, 0.0f), new Vector3(0.0f, ((i / m_LastBuiltPolygons.Count) * step), 0.0f)); } + GenerateNormals(poly2); + Polygon nextPoly = m_LastBuiltPolygons[labpIndex].DeepCopy(); nextPoly.Flip(); foreach (Vertex v in nextPoly.Vertices) { float step = 360.0f / project.revolve360; - v.Position = RotatePointAroundPivot(v.Position, new Vector3(((project.revolveDistance / 8.0f) * project.extrudeScale.x) + ((project.revolveRadius * project.extrudeScale.x) / 8.0f), 0.0f, 0.0f), new Vector3(0.0f, (project.revolveDirection ? 0 : 180) + (((i / m_LastBuiltPolygons.Count) * step) + step), 0.0f)); + v.Position = new Vector3(0, -spiralHeight - (project.revolveSpiralSloped ? spiralStep : 0), 0) + RotatePointAroundPivot(v.Position, new Vector3(((project.revolveDistance / 8.0f) * project.extrudeScale.x) + ((project.revolveRadius * project.extrudeScale.x) / 8.0f), 0.0f, 0.0f), new Vector3(0.0f, (((i / m_LastBuiltPolygons.Count) * step) + step), 0.0f)); } - GenerateNormals(poly2); List polygons = new List() { poly2 }; List backPolyVertices = new List(); Edge[] myEdges = poly2.GetEdges(); @@ -228,7 +272,10 @@ public override void Invalidate(bool polygonsChanged) GenerateUvCoordinates(backPoly, false); polygons.Add(backPoly); - generatedBrushes[i].SetPolygons(polygons.ToArray()); + if (project.convexBrushes) + generatedBrushes[i].SetPolygons(polygons.ToArray()); + else + concavePolygons.AddRange(polygons); break; // generate a 3d cube-ish shape. @@ -237,7 +284,10 @@ public override void Invalidate(bool polygonsChanged) SurfaceUtility.ExtrudePolygon(m_LastBuiltPolygons[i], project.extrudeDepth, out outputPolygons, out rot); foreach (Polygon poly in outputPolygons) GenerateUvCoordinates(poly, false); - generatedBrushes[i].SetPolygons(outputPolygons); + if (project.convexBrushes) + generatedBrushes[i].SetPolygons(outputPolygons); + else + concavePolygons.AddRange(outputPolygons); break; // generate a 3d cone-ish shape. @@ -246,7 +296,10 @@ public override void Invalidate(bool polygonsChanged) ExtrudePolygonToPoint(m_LastBuiltPolygons[i], project.extrudeDepth, new Vector2((project.globalPivot.position.x * project.extrudeScale.x) / 8.0f, -(project.globalPivot.position.y * project.extrudeScale.y) / 8.0f), out outputPolygons, out rot); foreach (Polygon poly in outputPolygons) GenerateUvCoordinates(poly, false); - generatedBrushes[i].SetPolygons(outputPolygons); + if (project.convexBrushes) + generatedBrushes[i].SetPolygons(outputPolygons); + else + concavePolygons.AddRange(outputPolygons); break; // generate a 3d trapezoid-ish shape. @@ -255,18 +308,106 @@ public override void Invalidate(bool polygonsChanged) ExtrudePolygonBevel(m_LastBuiltPolygons[i], project.extrudeDepth, project.extrudeClipDepth / project.extrudeDepth, new Vector2((project.globalPivot.position.x * project.extrudeScale.x) / 8.0f, -(project.globalPivot.position.y * project.extrudeScale.y) / 8.0f), out outputPolygons, out rot); foreach (Polygon poly in outputPolygons) GenerateUvCoordinates(poly, false); - generatedBrushes[i].SetPolygons(outputPolygons); + if (project.convexBrushes) + generatedBrushes[i].SetPolygons(outputPolygons); + else + concavePolygons.AddRange(outputPolygons); break; } - generatedBrushes[i].Invalidate(true); - csgBounds.Encapsulate(generatedBrushes[i].GetBounds()); + // we invalidate every brush after hidden surface removal. + } + + // we exclude hidden faces automatically. + // this step will automatically optimize NoCSG output the same way additive brushes would have. + // it also excludes a couple faces that CSG doesn't exclude due to floating point precision errors. + // the latter is especially noticable with complex revolved shapes. + + // hidden surface removal for convex brushes. + if (project.convexBrushes) + { + // compare each brush to another brush: + for (int i = 0; i < brushCount; i++) + { + for (int j = 0; j < brushCount; j++) + { + // can't check for hidden faces on the same brush. + if (i == j) continue; + + // compare each polygon on brush i to each polygon on brush j: + foreach (Polygon pa in generatedBrushes[i].GetPolygons()) + { + foreach (Polygon pb in generatedBrushes[j].GetPolygons()) + { + // check they both have this polygon: + bool identical = true; + foreach (Vertex va in pa.Vertices) + { + if (!pb.Vertices.Any(vb => vb.Position == va.Position)) + { + identical = false; + break; + } + } + // identical polygons on both brushes means it can be excluded: + if (identical) + { + pa.UserExcludeFromFinal = true; + pb.UserExcludeFromFinal = true; + } + } + } + } + + // invalidate every brush. + generatedBrushes[i].Invalidate(true); + csgBounds.Encapsulate(generatedBrushes[i].GetBounds()); + } + } + + // hidden surface removal for a concave brush. + else + { + List concavePolygonsCopy = concavePolygons.ToList(); + + // compare each polygon and find duplicates: + foreach (Polygon pa in concavePolygonsCopy) + { + foreach (Polygon pb in concavePolygonsCopy) + { + // can't be the same polygon. + if (pa == pb) continue; + + // check they both have this polygon: + bool identical = true; + foreach (Vertex va in pa.Vertices) + { + if (!pb.Vertices.Any(vb => vb.Position == va.Position)) + { + identical = false; + break; + } + } + // identical polygons on both brushes means it can be excluded: + if (identical) + { + concavePolygons.Remove(pa); + concavePolygons.Remove(pb); + } + } + } + + // invalidate the brush. + generatedBrushes[0].SetPolygons(concavePolygons.ToArray()); + csgBounds.Encapsulate(generatedBrushes[0].GetBounds()); } // apply the generated csg bounds. localBounds = csgBounds; m_LastKnownExtents = localBounds.extents; m_LastKnownPosition = transform.localPosition; + // update the generated name in the hierarchy. + UpdateGeneratedHierarchyName(); } /// @@ -284,7 +425,6 @@ private Segment GetNextSegment(Shape parent, Segment segment) /// /// Builds convex polygons out of the currently loaded 2D Shape Editor project. - /// Note: Currently simply triangulates everything instead. /// /// A list of convex polygons. private List BuildConvexPolygons() @@ -341,18 +481,22 @@ private List BuildConvexPolygons() // we make a brush for every polgon. desiredBrushCount = polygons.Count; break; - // we need another brush for every revolve step. + case ExtrudeMode.RevolveShape: + // we need another brush for every revolve step. desiredBrushCount = polygons.Count * project.revolveSteps; break; + case ExtrudeMode.ExtrudeShape: // we make a brush for every polgon. desiredBrushCount = polygons.Count; break; + case ExtrudeMode.ExtrudePoint: // we make a brush for every polgon. desiredBrushCount = polygons.Count; break; + case ExtrudeMode.ExtrudeBevel: // we make a brush for every polgon. desiredBrushCount = polygons.Count; @@ -648,6 +792,30 @@ private Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 ang return Quaternion.Euler(angles) * (point - pivot) + pivot; } + /// + /// Flips a project horizontally. This code was stolen from the ShapeEditorWindow. + /// + private void FlipProjectHorizontally() + { + // store this flip inside of the project. + project.flipHorizontally = !project.flipHorizontally; + + foreach (Shape shape in project.shapes) + { + foreach (Segment segment in shape.segments) + { + // flip segment. + segment.position = new Vector2Int(-segment.position.x + (project.globalPivot.position.x * 2), segment.position.y); + // flip bezier pivot handles. + segment.bezierPivot1.position = new Vector2Int(-segment.bezierPivot1.position.x + (project.globalPivot.position.x * 2), segment.bezierPivot1.position.y); + segment.bezierPivot2.position = new Vector2Int(-segment.bezierPivot2.position.x + (project.globalPivot.position.x * 2), segment.bezierPivot2.position.y); + } + + // recalculate the pivot position of the shape. + shape.CalculatePivotPosition(); + } + } + /////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC API // /////////////////////////////////////////////////////////////////////////////////////////// @@ -687,6 +855,8 @@ public void RevolveShape(Project project) { // store a project copy inside of this brush. this.project = project.Clone(); + // flip project horizontally if revolving left. + if (!this.project.revolveDirection) FlipProjectHorizontally(); // store the extrude mode inside of this brush. extrudeMode = ExtrudeMode.RevolveShape; // build the polygons out of the project. @@ -694,6 +864,8 @@ public void RevolveShape(Project project) // build the brush. isDirty = true; Invalidate(true); + // un-flip project horizontally if revolving left. + if (!this.project.revolveDirection) FlipProjectHorizontally(); } /// diff --git a/Scripts/Brushes/CompoundBrushes/StairBrush.cs b/Scripts/Brushes/CompoundBrushes/StairBrush.cs index 61ee9c09..1e7af398 100644 --- a/Scripts/Brushes/CompoundBrushes/StairBrush.cs +++ b/Scripts/Brushes/CompoundBrushes/StairBrush.cs @@ -9,31 +9,115 @@ namespace Sabresaurus.SabreCSG [ExecuteInEditMode] public class StairBrush : CompoundBrush { + /// + /// The depth of each step. + /// [SerializeField] float stepDepth = 0.2f; + /// + /// Gets or sets the depth of each step. + /// + /// The depth of each step. + public float StepDepth { get { return stepDepth; } set { stepDepth = value; } } + + /// + /// The height of each step. + /// [SerializeField] float stepHeight = 0.1f; + /// + /// Gets or sets the height of each step. + /// + /// The height of each step. + public float StepHeight { get { return stepHeight; } set { stepHeight = value; } } + + /// + /// The step depth spacing. + /// [SerializeField] float stepDepthSpacing = 0f; + /// + /// Gets or sets the step depth spacing. + /// + /// The step depth spacing. + public float StepDepthSpacing { get { return stepDepthSpacing; } set { stepDepthSpacing = value; } } + + /// + /// The step height spacing. + /// [SerializeField] float stepHeightSpacing = 0f; - [SerializeField] + /// + /// Gets or sets the step height spacing. + /// + /// The step height spacing. + public float StepHeightSpacing { get { return stepHeightSpacing; } set { stepHeightSpacing = value; } } + + /// + /// Whether to automatically determine the best step depth. + /// + [SerializeField] bool autoDepth = false; + /// + /// Gets or sets a value indicating whether to automatically determine the best step depth. + /// + /// true to automatically determine the best step depth; otherwise, false. + public bool AutomaticDepth { get { return autoDepth; } set { autoDepth = value; } } + + /// + /// Whether to automatically determine the best step height. + /// [SerializeField] bool autoHeight = false; - [SerializeField] + /// + /// Gets or sets a value indicating whether to automatically determine the best step height. + /// + /// true to automatically determine the best step height; otherwise, false. + public bool AutomaticHeight { get { return autoDepth; } set { autoDepth = value; } } + + /// + /// Whether to lead from the top. + /// + [SerializeField] bool leadFromTop = false; + /// + /// Gets or sets a value indicating whether to lead from the top. + /// + /// true to lead from the top; otherwise, false. + public bool LeadFromTop { get { return leadFromTop; } set { leadFromTop = value; } } + + /// + /// Whether to fill steps to the bottom to make a solid staircase. + /// [SerializeField] bool fillToBottom = false; - public override int BrushCount + /// + /// Gets or sets a value indicating whether to fill steps to the bottom to make a solid staircase. + /// + /// true to fill steps to the bottom to make a solid staircase; otherwise, false. + public bool FillToBottom { get { return fillToBottom; } set { fillToBottom = value; } } + + /// + /// Gets the beautiful name of the brush used in auto-generation of the hierarchy name. + /// + /// The beautiful name of the brush. + public override string BeautifulBrushName + { + get + { + return "Linear Stairs Brush"; + } + } + + public override int BrushCount { get { diff --git a/Scripts/Brushes/CompoundBrushes/TrimBrush.cs b/Scripts/Brushes/CompoundBrushes/TrimBrush.cs index 09ce1f3d..49f08fff 100644 --- a/Scripts/Brushes/CompoundBrushes/TrimBrush.cs +++ b/Scripts/Brushes/CompoundBrushes/TrimBrush.cs @@ -9,11 +9,31 @@ namespace Sabresaurus.SabreCSG [ExecuteInEditMode] public class TrimBrush : CompoundBrush { - - [SerializeField] + /// + /// The size of the trim. + /// + [SerializeField] float trimSize = 0.25f; - public override int BrushCount + /// + /// Gets or sets the size of the trim. + /// + /// The size of the trim. + public float TrimSize { get { return trimSize; } set { trimSize = value; } } + + /// + /// Gets the beautiful name of the brush used in auto-generation of the hierarchy name. + /// + /// The beautiful name of the brush. + public override string BeautifulBrushName + { + get + { + return "Trim Brush"; + } + } + + public override int BrushCount { get { diff --git a/Scripts/Brushes/GroupBrush.cs b/Scripts/Brushes/GroupBrush.cs new file mode 100644 index 00000000..b9df0fb3 --- /dev/null +++ b/Scripts/Brushes/GroupBrush.cs @@ -0,0 +1,272 @@ +#if UNITY_EDITOR || RUNTIME_CSG +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using System.Reflection; +using System.Linq; + +namespace Sabresaurus.SabreCSG +{ + /// + /// Brush groups are created when the user wants to group together some brushes. + /// + [ExecuteInEditMode] + public class GroupBrush : BrushBase + { + [SerializeField] + protected Bounds localBounds = new Bounds(Vector3.zero, new Vector3(2, 2, 2)); + + /// + /// Gets a value indicating whether this brush supports CSG operations. Setting this to false + /// will hide CSG brush related options in the editor. + /// For example a does not have any CSG operations. + /// + /// true if this brush supports CSG operations; otherwise, false. + public override bool SupportsCsgOperations { get { return false; } } + + /// + /// Gets the beautiful name of the brush used in auto-generation of the hierarchy name. + /// + /// The beautiful name of the brush. + public override string BeautifulBrushName + { + get + { + return "Group"; + } + } + + /// The last known extents of the compound brush to detect user resizing the bounds. + private Vector3 m_LastKnownExtents; + /// The last known position of the compound brush to prevent movement on resizing the bounds. + private Vector3 m_LastKnownPosition; + + protected override void Awake() + { + base.Awake(); + // get the last known extents and position (especially after scene changes). + m_LastKnownExtents = localBounds.extents; + m_LastKnownPosition = transform.localPosition; + } + + public override Bounds GetBounds() + { + return localBounds; + } + + public override Bounds GetBoundsLocalTo(Transform otherTransform) + { + Vector3[] points = new Vector3[8]; + + // Calculate the positions of the bounds corners local to the other transform + for (int i = 0; i < 8; i++) + { + Vector3 point = localBounds.center; + Vector3 offset = localBounds.extents; + + if (i % 2 == 0) + { + offset.x = -offset.x; + } + + if (i % 4 < 2) + { + offset.y = -offset.y; + } + + if (i % 8 < 4) + { + offset.z = -offset.z; + } + + point += offset; + + // Transform to world space then to the other transform's local space + point = otherTransform.InverseTransformPoint(transform.TransformPoint(point)); + points[i] = point; + } + + // Construct the bounds, starting with the first bounds corner + Bounds bounds = new Bounds(points[0], Vector3.zero); + + // Add the rest of the corners to the bounds + for (int i = 1; i < 8; i++) + { + bounds.Encapsulate(points[i]); + } + + return bounds; + } + + public override Bounds GetBoundsTransformed() + { + Vector3[] points = new Vector3[8]; + + // Calculate the world positions of the bounds corners + for (int i = 0; i < 8; i++) + { + Vector3 point = localBounds.center; + Vector3 offset = localBounds.extents; + + if (i % 2 == 0) + { + offset.x = -offset.x; + } + + if (i % 4 < 2) + { + offset.y = -offset.y; + } + + if (i % 8 < 4) + { + offset.z = -offset.z; + } + + point += offset; + + // Transform to world space + point = transform.TransformPoint(point); + points[i] = point; + } + + // Construct the bounds, starting with the first bounds corner + Bounds bounds = new Bounds(points[0], Vector3.zero); + + // Add the rest of the corners to the bounds + for (int i = 1; i < 8; i++) + { + bounds.Encapsulate(points[i]); + } + + return bounds; + } + + public override void OnUndoRedoPerformed() + { + } + + public override void SetBounds(Bounds newBounds) + { + localBounds.center = Vector3.zero; + localBounds.extents = newBounds.extents; + + transform.Translate(newBounds.center); + } + + public override void UpdateVisibility() + { + } + + public override void Invalidate(bool polygonsChanged) + { + //////////////////////////////////////////////////////////////////// + // a little hack to detect the user manually resizing the bounds. // + // it's probably good to build a more 'official' way to detect // + // user scaling events in compound brushes sometime. // + if (m_LastKnownExtents != localBounds.extents && m_LastKnownPosition != Vector3.zero) + { // + // undo any position movement. // + transform.localPosition = m_LastKnownPosition; // + } // + //////////////////////////////////////////////////////////////////// + Bounds csgBounds = new Bounds(); + + // nothing to do except copy csg information to our child brushes. + foreach (Transform childTransform in transform) + { + BrushBase child = childTransform.GetComponent(); + if (child == null) continue; + + // we do not override these properties in a group. + // it wouldn't make much sense and break whatever the user grouped. + //child.Mode = this.Mode; + //child.IsNoCSG = this.IsNoCSG; + //child.IsVisible = this.IsVisible; + //child.HasCollision = this.HasCollision; + child.Invalidate(polygonsChanged); + csgBounds.Encapsulate(child.GetBoundsLocalTo(transform)); + } + // apply the generated csg bounds. + localBounds = csgBounds; + m_LastKnownExtents = localBounds.extents; + m_LastKnownPosition = transform.localPosition; + // update name in hierarchy. + base.Invalidate(polygonsChanged); + } + + protected override void Update() + { + base.Update(); + // encapsulate all of the child objects in our bounds. + Bounds csgBounds = new Bounds(); + foreach (Transform childTransform in transform) + { + BrushBase child = childTransform.GetComponent(); + if (child == null) continue; + csgBounds.Encapsulate(child.GetBoundsLocalTo(transform)); + } + // apply the generated csg bounds. + localBounds = csgBounds; + // update the generated name in the hierarchy. + UpdateGeneratedHierarchyName(); + } + + /// + /// Gets all of the polygons from all brushes in this group brush. + /// + /// All of the polygons from all brushes in this group brush. + public Polygon[] GetPolygons() + { + List polygons = new List(); + // iterate through all child brushes: + foreach (BrushBase brush in GetComponentsInChildren().Where(c => c.transform != transform)) + { + Polygon[] polys; + + // try getting the polygons depending on the brush type. + if (brush is PrimitiveBrush) + polys = ((PrimitiveBrush)brush).GetPolygons(); + else if (brush is CompoundBrush) + polys = ((CompoundBrush)brush).GetPolygons(); + else if (brush is GroupBrush) + polys = ((GroupBrush)brush).GetPolygons(); + else continue; + + polygons.AddRange(GenerateTransformedPolygons(brush.transform, polys)); + } + return polygons.ToArray(); + } + + /// + /// Generates transformed polygons to match the group brush position. + /// + /// The transform of a child brush. + /// The polygons of a child brush. + /// The transformed polygons. + private Polygon[] GenerateTransformedPolygons(Transform t, Polygon[] polygons) + { + Polygon[] polygonsCopy = polygons.DeepCopy(); + + Vector3 center = t.localPosition; + Quaternion rotation = t.localRotation; + Vector3 scale = t.lossyScale; + + for (int i = 0; i < polygonsCopy.Length; i++) + { + for (int j = 0; j < polygonsCopy[i].Vertices.Length; j++) + { + polygonsCopy[i].Vertices[j].Position = rotation * polygonsCopy[i].Vertices[j].Position.Multiply(scale) + center; + polygonsCopy[i].Vertices[j].Normal = rotation * polygonsCopy[i].Vertices[j].Normal; + } + + // Just updated a load of vertex positions, so make sure the cached plane is updated + polygonsCopy[i].CalculatePlane(); + } + + return polygonsCopy; + } + } +} +#endif \ No newline at end of file diff --git a/Scripts/Brushes/GroupBrush.cs.meta b/Scripts/Brushes/GroupBrush.cs.meta new file mode 100644 index 00000000..d92ac00b --- /dev/null +++ b/Scripts/Brushes/GroupBrush.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 3cff19230f770174fb80be4a4fd74062 +timeCreated: 1521045202 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Brushes/PrimitiveBrush.cs b/Scripts/Brushes/PrimitiveBrush.cs index 19dc6a59..f42745d7 100755 --- a/Scripts/Brushes/PrimitiveBrush.cs +++ b/Scripts/Brushes/PrimitiveBrush.cs @@ -1,4 +1,5 @@ #if UNITY_EDITOR || RUNTIME_CSG + using System; using System.Collections; using System.Collections.Generic; @@ -6,72 +7,121 @@ namespace Sabresaurus.SabreCSG { - public enum PrimitiveBrushType { - Cube, - Sphere, - Cylinder, - Prism, - Custom, - IcoSphere, + public enum PrimitiveBrushType + { + Cube, + Sphere, + Cylinder, + Prism, + Custom, + IcoSphere, Cone, - }; + }; - /// - /// A simple brush that represents a single convex shape - /// + /// + /// A simple brush that represents a single convex shape. + /// [ExecuteInEditMode] public class PrimitiveBrush : Brush { [SerializeField] - Polygon[] polygons; + private Polygon[] polygons; - [SerializeField,HideInInspector] - int prismSideCount = 6; + /// + /// The prism side count. + /// + [SerializeField, HideInInspector] + private int prismSideCount = 6; - [SerializeField,HideInInspector] - int cylinderSideCount = 20; + /// + /// Gets or sets the prism side count. + /// + /// The prism side count. + public int PrismSideCount { get { return prismSideCount; } set { prismSideCount = value; } } + /// + /// The cylinder side count. + /// [SerializeField, HideInInspector] - int coneSideCount = 20; + private int cylinderSideCount = 20; - [SerializeField,HideInInspector] - int sphereSideCount = 6; + /// + /// Gets or sets the cylinder side count. + /// + /// The cylinder side count. + public int CylinderSideCount { get { return cylinderSideCount; } set { cylinderSideCount = value; } } - [SerializeField,HideInInspector] - int icoSphereIterationCount = 1; + /// + /// The cone side count. + /// + [SerializeField, HideInInspector] + private int coneSideCount = 20; - [SerializeField,HideInInspector] - PrimitiveBrushType brushType = PrimitiveBrushType.Cube; + /// + /// Gets or sets the cone side count. + /// + /// The cone side count. + public int ConeSideCount { get { return coneSideCount; } set { coneSideCount = value; } } - [SerializeField,HideInInspector] - bool tracked = false; + /// + /// The sphere side count. + /// + [SerializeField, HideInInspector] + private int sphereSideCount = 6; + + /// + /// Gets or sets the sphere side count. + /// + /// The sphere side count. + public int SphereSideCount { get { return sphereSideCount; } set { sphereSideCount = value; } } - [SerializeField,HideInInspector] - BrushOrder cachedBrushOrder = null; + /// + /// The icon sphere iteration count. + /// + [SerializeField, HideInInspector] + private int icoSphereIterationCount = 1; - [SerializeField] - BrushBase brushController = null; + /// + /// Gets or sets the icon sphere iteration count. + /// + /// The icon sphere iteration count. + public int IcoSphereIterationCount { get { return icoSphereIterationCount; } set { icoSphereIterationCount = value; } } - int cachedInstanceID = 0; + [SerializeField, HideInInspector] + private PrimitiveBrushType brushType = PrimitiveBrushType.Cube; - private CSGModelBase parentCsgModel; + [SerializeField, HideInInspector] + private bool tracked = false; - [SerializeField] - WorldTransformData cachedWorldTransform; + [SerializeField, HideInInspector] + private BrushOrder cachedBrushOrder = null; - [SerializeField] - int objectVersionSerialized; + [SerializeField] + private BrushBase brushController = null; - int objectVersionUnserialized; + private int cachedInstanceID = 0; - public PrimitiveBrushType BrushType { - get { - return brushType; - } - set { - brushType = value; - } - } + private CSGModelBase parentCsgModel; + + [SerializeField] + private WorldTransformData cachedWorldTransform; + + [SerializeField] + private int objectVersionSerialized; + + private int objectVersionUnserialized; + + public PrimitiveBrushType BrushType + { + get + { + return brushType; + } + set + { + brushType = value; + } + } public BrushBase BrushController { @@ -83,68 +133,107 @@ public BrushBase BrushController } public bool IsReadOnly - { - get - { - // If this brush is being controlled by something else, it's read only - return (brushController != null); - } - } + { + get + { + // If this brush is being controlled by something else, it's read only + return (brushController != null); + } + } - public void SetBrushController(BrushBase brushController) - { - this.brushController = brushController; - } + /// + /// Gets the beautiful name of the brush used in auto-generation of the hierarchy name. + /// + /// The beautiful name of the brush. + public override string BeautifulBrushName + { + get + { + switch (brushType) + { + case PrimitiveBrushType.Cube: + return "Cube Brush"; + + case PrimitiveBrushType.Sphere: + return "Sphere Brush"; + + case PrimitiveBrushType.Cylinder: + return "Cylinder Brush"; + + case PrimitiveBrushType.Prism: + return "Prism Brush"; + + case PrimitiveBrushType.Custom: + return "Custom Brush"; + + case PrimitiveBrushType.IcoSphere: + return "Icosphere Brush"; + + case PrimitiveBrushType.Cone: + return "Cone Brush"; + + default: + return base.BeautifulBrushName; + } + } + } + + public void SetBrushController(BrushBase brushController) + { + this.brushController = brushController; + } - /// - /// Provide new polygons for the brush - /// - /// New polygons. - /// If the brush type has changed set this to true. For example if you change a cuboid into a wedge, the brush type should no longer be Cube. See BreakTypeRelation() for more details - public void SetPolygons(Polygon[] polygons, bool breakTypeRelation = true) + /// + /// Provide new polygons for the brush + /// + /// New polygons. + /// If the brush type has changed set this to true. For example if you change a cuboid into a wedge, the brush type should no longer be Cube. See BreakTypeRelation() for more details + public void SetPolygons(Polygon[] polygons, bool breakTypeRelation = true) { this.polygons = polygons; Invalidate(true); - if(breakTypeRelation) - { - BreakTypeRelation(); - } + if (breakTypeRelation) + { + BreakTypeRelation(); + } } - /// - /// Brushes retain knowledge of what they were made from, so it's easy to adjust the side count on a prism for example, while retaining some of its transform information. If you start cutting away at a prism using the clip tool for instance, it should stop tracking it as following the initial form. This method allows you to tell the brush it is no longer tracking a base form. - /// - public void BreakTypeRelation() - { - brushType = PrimitiveBrushType.Custom; - } + /// + /// Brushes retain knowledge of what they were made from, so it's easy to adjust the side count on a prism for example, while retaining some of its transform information. If you start cutting away at a prism using the clip tool for instance, it should stop tracking it as following the initial form. This method allows you to tell the brush it is no longer tracking a base form. + /// + public void BreakTypeRelation() + { + brushType = PrimitiveBrushType.Custom; + } #if UNITY_EDITOR - [UnityEditor.Callbacks.DidReloadScripts] - static void OnReloadedScripts() - { - PrimitiveBrush[] brushes = FindObjectsOfType(); - for (int i = 0; i < brushes.Length; i++) - { - brushes[i].UpdateVisibility(); - } - } + [UnityEditor.Callbacks.DidReloadScripts] + private static void OnReloadedScripts() + { + PrimitiveBrush[] brushes = FindObjectsOfType(); + + for (int i = 0; i < brushes.Length; i++) + { + brushes[i].UpdateVisibility(); + } + } + #endif - void Start() + private void Start() { - cachedWorldTransform = new WorldTransformData(transform); - EnsureWellFormed(); + cachedWorldTransform = new WorldTransformData(transform); + EnsureWellFormed(); - Invalidate(false); + Invalidate(false); - if(brushCache == null || brushCache.Polygons == null || brushCache.Polygons.Length == 0) - { - RecachePolygons(true); - } + if (brushCache == null || brushCache.Polygons == null || brushCache.Polygons.Length == 0) + { + RecachePolygons(true); + } #if UNITY_EDITOR #if UNITY_5_5_OR_NEWER @@ -156,56 +245,56 @@ void Start() #endif #endif - objectVersionUnserialized = objectVersionSerialized; + objectVersionUnserialized = objectVersionSerialized; } - /// - /// Reset the polygons to those specified in the brush type. For example if the brush type is a cube, the polygons are reset to a cube. - /// - public void ResetPolygons() - { - if (brushType == PrimitiveBrushType.Cube) - { - polygons = BrushFactory.GenerateCube(); - } - else if (brushType == PrimitiveBrushType.Cylinder) - { - if(cylinderSideCount < 3) - { - cylinderSideCount = 3; - } - polygons = BrushFactory.GenerateCylinder(cylinderSideCount); - } - else if (brushType == PrimitiveBrushType.Sphere) - { - if(sphereSideCount < 3) - { - sphereSideCount = 3; - } - // Lateral only goes halfway around the sphere (180 deg), longitudinal goes all the way (360 deg) - polygons = BrushFactory.GeneratePolarSphere(sphereSideCount, sphereSideCount * 2); - } - else if (brushType == PrimitiveBrushType.IcoSphere) - { - if(icoSphereIterationCount < 0) - { - icoSphereIterationCount = 0; - } - else if(icoSphereIterationCount > 2) - { - icoSphereIterationCount = 2; - } - - polygons = BrushFactory.GenerateIcoSphere(icoSphereIterationCount); - } - else if (brushType == PrimitiveBrushType.Prism) - { - if(prismSideCount < 3) - { - prismSideCount = 3; - } - polygons = BrushFactory.GeneratePrism(prismSideCount); - } + /// + /// Reset the polygons to those specified in the brush type. For example if the brush type is a cube, the polygons are reset to a cube. + /// + public void ResetPolygons() + { + if (brushType == PrimitiveBrushType.Cube) + { + polygons = BrushFactory.GenerateCube(); + } + else if (brushType == PrimitiveBrushType.Cylinder) + { + if (cylinderSideCount < 3) + { + cylinderSideCount = 3; + } + polygons = BrushFactory.GenerateCylinder(cylinderSideCount); + } + else if (brushType == PrimitiveBrushType.Sphere) + { + if (sphereSideCount < 3) + { + sphereSideCount = 3; + } + // Lateral only goes halfway around the sphere (180 deg), longitudinal goes all the way (360 deg) + polygons = BrushFactory.GeneratePolarSphere(sphereSideCount, sphereSideCount * 2); + } + else if (brushType == PrimitiveBrushType.IcoSphere) + { + if (icoSphereIterationCount < 0) + { + icoSphereIterationCount = 0; + } + else if (icoSphereIterationCount > 2) + { + icoSphereIterationCount = 2; + } + + polygons = BrushFactory.GenerateIcoSphere(icoSphereIterationCount); + } + else if (brushType == PrimitiveBrushType.Prism) + { + if (prismSideCount < 3) + { + prismSideCount = 3; + } + polygons = BrushFactory.GeneratePrism(prismSideCount); + } else if (brushType == PrimitiveBrushType.Cone) { if (coneSideCount < 3) @@ -214,358 +303,363 @@ public void ResetPolygons() } polygons = BrushFactory.GenerateCone(coneSideCount); } - else if(brushType == Sabresaurus.SabreCSG.PrimitiveBrushType.Custom) - { - // Do nothing - Debug.LogError("PrimitiveBrushType.Custom is not a valid type for new brush creation"); - } - else - { - throw new NotImplementedException(); - } - } + else if (brushType == Sabresaurus.SabreCSG.PrimitiveBrushType.Custom) + { + // Do nothing + Debug.LogError("PrimitiveBrushType.Custom is not a valid type for new brush creation"); + } + else + { + throw new NotImplementedException(); + } + } - void DrawPolygons(Color color, params Polygon[] polygons) - { - GL.Begin(GL.TRIANGLES); - color.a = 0.7f; - GL.Color(color); - - for (int j = 0; j < polygons.Length; j++) - { - Polygon polygon = polygons[j]; - Vector3 position1 = polygon.Vertices[0].Position; - - for (int i = 1; i < polygon.Vertices.Length - 1; i++) - { - GL.Vertex(transform.TransformPoint(position1)); - GL.Vertex(transform.TransformPoint(polygon.Vertices[i].Position)); - GL.Vertex(transform.TransformPoint(polygon.Vertices[i + 1].Position)); - } - } - GL.End(); - } + private void DrawPolygons(Color color, params Polygon[] polygons) + { + GL.Begin(GL.TRIANGLES); + color.a = 0.7f; + GL.Color(color); + + for (int j = 0; j < polygons.Length; j++) + { + Polygon polygon = polygons[j]; + Vector3 position1 = polygon.Vertices[0].Position; + + for (int i = 1; i < polygon.Vertices.Length - 1; i++) + { + GL.Vertex(transform.TransformPoint(position1)); + GL.Vertex(transform.TransformPoint(polygon.Vertices[i].Position)); + GL.Vertex(transform.TransformPoint(polygon.Vertices[i + 1].Position)); + } + } + GL.End(); + } #if UNITY_EDITOR + public void OnRepaint(UnityEditor.SceneView sceneView, Event e) { // Selected brush green outline - if(!isBrushConvex) - { - SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); - DrawPolygons(Color.red, polygons); - } + if (!isBrushConvex) + { + SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); + DrawPolygons(Color.red, polygons); + } } + #endif - public override Polygon[] GenerateTransformedPolygons() - { - Polygon[] polygonsCopy = polygons.DeepCopy(); + public override Polygon[] GenerateTransformedPolygons() + { + Polygon[] polygonsCopy = polygons.DeepCopy(); - Vector3 center = transform.position; - Quaternion rotation = transform.rotation; - Vector3 scale = transform.localScale; + Vector3 center = transform.position; + Quaternion rotation = transform.rotation; + Vector3 scale = transform.lossyScale; - for (int i = 0; i < polygons.Length; i++) - { - for (int j = 0; j < polygons[i].Vertices.Length; j++) - { - polygonsCopy[i].Vertices[j].Position = rotation * polygonsCopy[i].Vertices[j].Position.Multiply(scale) + center; - polygonsCopy[i].Vertices[j].Normal = rotation * polygonsCopy[i].Vertices[j].Normal; - } - - // Just updated a load of vertex positions, so make sure the cached plane is updated - polygonsCopy[i].CalculatePlane(); - } + for (int i = 0; i < polygons.Length; i++) + { + for (int j = 0; j < polygons[i].Vertices.Length; j++) + { + polygonsCopy[i].Vertices[j].Position = rotation * polygonsCopy[i].Vertices[j].Position.Multiply(scale) + center; + polygonsCopy[i].Vertices[j].Normal = rotation * polygonsCopy[i].Vertices[j].Normal; + } - return polygonsCopy; - } + // Just updated a load of vertex positions, so make sure the cached plane is updated + polygonsCopy[i].CalculatePlane(); + } - public override void RecalculateBrushCache () - { - RecachePolygons(true); + return polygonsCopy; + } - RecalculateIntersections(); - } + public override void RecalculateBrushCache() + { + RecachePolygons(true); - public override void RecachePolygons(bool markUnbuilt) - { - if(brushCache == null) - { - brushCache = new BrushCache(); - } - Polygon[] cachedTransformedPolygons = GenerateTransformedPolygons(); - Bounds cachedTransformedBounds = GetBoundsTransformed(); - brushCache.Set(mode, cachedTransformedPolygons, cachedTransformedBounds, markUnbuilt); - } + RecalculateIntersections(); + } - public override void RecalculateIntersections() - { - CSGModelBase csgModel = GetCSGModel(); - if(csgModel != null) - { - List brushes = GetCSGModel().GetBrushes(); - - // Tracked brushes at edit time can be added in any order, so sort them - IComparer comparer = new BrushOrderComparer(); - for (int i = 0; i < brushes.Count; i++) - { - if(brushes[i] == null) - { - brushes.RemoveAt(i); - i--; - } - } - - for (int i = 0; i < brushes.Count; i++) - { - brushes[i].UpdateCachedBrushOrder(); - } - - brushes.Sort(comparer); - - RecalculateIntersections(brushes, true); - } - } + public override void RecachePolygons(bool markUnbuilt) + { + if (brushCache == null) + { + brushCache = new BrushCache(); + } + Polygon[] cachedTransformedPolygons = GenerateTransformedPolygons(); + Bounds cachedTransformedBounds = GetBoundsTransformed(); + brushCache.Set(mode, cachedTransformedPolygons, cachedTransformedBounds, markUnbuilt); + } - public override void RecalculateIntersections(List brushes, bool isRootChange) - { - List previousVisualIntersections = brushCache.IntersectingVisualBrushes; - List previousCollisionIntersections = brushCache.IntersectingCollisionBrushes; + public override void RecalculateIntersections() + { + CSGModelBase csgModel = GetCSGModel(); + if (csgModel != null) + { + List brushes = GetCSGModel().GetBrushes(); - List intersectingVisualBrushes = CalculateIntersectingBrushes(this, brushes, false); - List intersectingCollisionBrushes = CalculateIntersectingBrushes(this, brushes, true); + // Tracked brushes at edit time can be added in any order, so sort them + IComparer comparer = new BrushOrderComparer(); + for (int i = 0; i < brushes.Count; i++) + { + if (brushes[i] == null) + { + brushes.RemoveAt(i); + i--; + } + } - brushCache.SetIntersection(intersectingVisualBrushes, intersectingCollisionBrushes); + for (int i = 0; i < brushes.Count; i++) + { + brushes[i].UpdateCachedBrushOrder(); + } - if(isRootChange) - { - // Brushes that are either newly intersecting or no longer intersecting, they need to recalculate their - // intersections, but also rebuild - List brushesToRecalcAndRebuild = new List(); - - // Brushes that are still intersecting, these should recalculate their intersections any way in case - // sibling order has changed to make sure their intersection order is still correct - List brushesToRecalculateOnly = new List(); - - // Brushes that are either new or existing intersections - for (int i = 0; i < intersectingVisualBrushes.Count; i++) - { - if(intersectingVisualBrushes[i] != null) - { - if(!previousVisualIntersections.Contains(intersectingVisualBrushes[i])) - { - // It's a newly intersecting brush - if(!brushesToRecalcAndRebuild.Contains(intersectingVisualBrushes[i])) - { - brushesToRecalcAndRebuild.Add(intersectingVisualBrushes[i]); - } - } - else - { - // Intersection was already present - if(!brushesToRecalculateOnly.Contains(intersectingVisualBrushes[i])) - { - brushesToRecalculateOnly.Add(intersectingVisualBrushes[i]); - } - } - } - } - - // Find any brushes that no longer intersect - for (int i = 0; i < previousVisualIntersections.Count; i++) - { - if(previousVisualIntersections[i] != null && !intersectingVisualBrushes.Contains(previousVisualIntersections[i])) - { - if(!brushesToRecalcAndRebuild.Contains(previousVisualIntersections[i])) - { - brushesToRecalcAndRebuild.Add(previousVisualIntersections[i]); - } - } - } - - // Collision Pass - - // Brushes that are either new or existing intersections - for (int i = 0; i < intersectingCollisionBrushes.Count; i++) - { - if(intersectingCollisionBrushes[i] != null) - { - if(!previousCollisionIntersections.Contains(intersectingCollisionBrushes[i])) - { - // It's a newly intersecting brush - if(!brushesToRecalcAndRebuild.Contains(intersectingCollisionBrushes[i])) - { - brushesToRecalcAndRebuild.Add(intersectingCollisionBrushes[i]); - } - } - else - { - // Intersection was already present - if(!brushesToRecalculateOnly.Contains(intersectingCollisionBrushes[i])) - { - brushesToRecalculateOnly.Add(intersectingCollisionBrushes[i]); - } - } - } - } - - // Find any brushes that no longer intersect - for (int i = 0; i < previousCollisionIntersections.Count; i++) - { - if(previousCollisionIntersections[i] != null && !intersectingCollisionBrushes.Contains(previousCollisionIntersections[i])) - { - if(!brushesToRecalcAndRebuild.Contains(previousCollisionIntersections[i])) - { - brushesToRecalcAndRebuild.Add(previousCollisionIntersections[i]); - } - } - } - - // Notify brushes that are either newly intersecting or no longer intersecting that they need to recalculate and rebuild - for (int i = 0; i < brushesToRecalcAndRebuild.Count; i++) - { - // Brush intersection has changed - brushesToRecalcAndRebuild[i].RecalculateIntersections(brushes, false); - // Brush needs to be built - brushesToRecalcAndRebuild[i].BrushCache.SetUnbuilt(); - } - - // Brushes that remain intersecting should recalc their intersection lists just in case sibling order has changed - for (int i = 0; i < brushesToRecalculateOnly.Count; i++) - { - // Brush intersection has changed - brushesToRecalculateOnly[i].RecalculateIntersections(brushes, false); - } - } - } + brushes.Sort(comparer); + + RecalculateIntersections(brushes, true); + } + } + + public override void RecalculateIntersections(List brushes, bool isRootChange) + { + List previousVisualIntersections = brushCache.IntersectingVisualBrushes; + List previousCollisionIntersections = brushCache.IntersectingCollisionBrushes; + + List intersectingVisualBrushes = CalculateIntersectingBrushes(this, brushes, false); + List intersectingCollisionBrushes = CalculateIntersectingBrushes(this, brushes, true); + + brushCache.SetIntersection(intersectingVisualBrushes, intersectingCollisionBrushes); + + if (isRootChange) + { + // Brushes that are either newly intersecting or no longer intersecting, they need to recalculate their + // intersections, but also rebuild + List brushesToRecalcAndRebuild = new List(); + + // Brushes that are still intersecting, these should recalculate their intersections any way in case + // sibling order has changed to make sure their intersection order is still correct + List brushesToRecalculateOnly = new List(); + + // Brushes that are either new or existing intersections + for (int i = 0; i < intersectingVisualBrushes.Count; i++) + { + if (intersectingVisualBrushes[i] != null) + { + if (!previousVisualIntersections.Contains(intersectingVisualBrushes[i])) + { + // It's a newly intersecting brush + if (!brushesToRecalcAndRebuild.Contains(intersectingVisualBrushes[i])) + { + brushesToRecalcAndRebuild.Add(intersectingVisualBrushes[i]); + } + } + else + { + // Intersection was already present + if (!brushesToRecalculateOnly.Contains(intersectingVisualBrushes[i])) + { + brushesToRecalculateOnly.Add(intersectingVisualBrushes[i]); + } + } + } + } + + // Find any brushes that no longer intersect + for (int i = 0; i < previousVisualIntersections.Count; i++) + { + if (previousVisualIntersections[i] != null && !intersectingVisualBrushes.Contains(previousVisualIntersections[i])) + { + if (!brushesToRecalcAndRebuild.Contains(previousVisualIntersections[i])) + { + brushesToRecalcAndRebuild.Add(previousVisualIntersections[i]); + } + } + } + // Collision Pass - // Fired by the CSG Model + // Brushes that are either new or existing intersections + for (int i = 0; i < intersectingCollisionBrushes.Count; i++) + { + if (intersectingCollisionBrushes[i] != null) + { + if (!previousCollisionIntersections.Contains(intersectingCollisionBrushes[i])) + { + // It's a newly intersecting brush + if (!brushesToRecalcAndRebuild.Contains(intersectingCollisionBrushes[i])) + { + brushesToRecalcAndRebuild.Add(intersectingCollisionBrushes[i]); + } + } + else + { + // Intersection was already present + if (!brushesToRecalculateOnly.Contains(intersectingCollisionBrushes[i])) + { + brushesToRecalculateOnly.Add(intersectingCollisionBrushes[i]); + } + } + } + } + + // Find any brushes that no longer intersect + for (int i = 0; i < previousCollisionIntersections.Count; i++) + { + if (previousCollisionIntersections[i] != null && !intersectingCollisionBrushes.Contains(previousCollisionIntersections[i])) + { + if (!brushesToRecalcAndRebuild.Contains(previousCollisionIntersections[i])) + { + brushesToRecalcAndRebuild.Add(previousCollisionIntersections[i]); + } + } + } + + // Notify brushes that are either newly intersecting or no longer intersecting that they need to recalculate and rebuild + for (int i = 0; i < brushesToRecalcAndRebuild.Count; i++) + { + // Brush intersection has changed + brushesToRecalcAndRebuild[i].RecalculateIntersections(brushes, false); + // Brush needs to be built + brushesToRecalcAndRebuild[i].BrushCache.SetUnbuilt(); + } + + // Brushes that remain intersecting should recalc their intersection lists just in case sibling order has changed + for (int i = 0; i < brushesToRecalculateOnly.Count; i++) + { + // Brush intersection has changed + brushesToRecalculateOnly[i].RecalculateIntersections(brushes, false); + } + } + } + + // Fired by the CSG Model public override void OnUndoRedoPerformed() - { - if(objectVersionSerialized != objectVersionUnserialized) - { - Invalidate(true); - } + { + if (objectVersionSerialized != objectVersionUnserialized) + { + Invalidate(true); + } } - void EnsureWellFormed() + private void EnsureWellFormed() { if (polygons == null || polygons.Length == 0) { - // Reset custom brushes back to a cube - if(brushType == PrimitiveBrushType.Custom) - { - brushType = PrimitiveBrushType.Cube; - } - - ResetPolygons(); - } - } - -// public void OnDrawGizmosSelected() -// { -// // Ensure Edit Mode is on -// GetCSGModel().EditMode = true; -// } -// -// public void OnDrawGizmos() -// { -// EnsureWellFormed(); -// -// // Gizmos.color = Color.green; -// // for (int i = 0; i < PolygonFactory.hackyDisplay1.Count; i++) -// // { -// // Gizmos.DrawSphere(PolygonFactory.hackyDisplay1[i], 0.2f); -// // } -// // -// // Gizmos.color = Color.red; -// // for (int i = 0; i < PolygonFactory.hackyDisplay2.Count; i++) -// // { -// // Gizmos.DrawSphere(PolygonFactory.hackyDisplay2[i], 0.2f); -// // } -// } - - - void OnDisable() - { - // OnDisable is called on recompilation, so make sure we only process when needed - if(this.enabled == false || (gameObject.activeInHierarchy == false && transform.root.gameObject.activeInHierarchy == true)) - { - GetCSGModel().OnBrushDisabled(this); - // Copy the intersections list since the source list will change as we call recalculate on other brushes - List intersectingVisualBrushes = new List(brushCache.IntersectingVisualBrushes); - - for (int i = 0; i < intersectingVisualBrushes.Count; i++) - { - if(intersectingVisualBrushes[i] != null) - { - intersectingVisualBrushes[i].RecalculateIntersections(); - intersectingVisualBrushes[i].BrushCache.SetUnbuilt(); - } - } - } - } + // Reset custom brushes back to a cube + if (brushType == PrimitiveBrushType.Custom) + { + brushType = PrimitiveBrushType.Cube; + } - void UpdateTracking() - { - CSGModelBase parentCSGModel = GetCSGModel(); + ResetPolygons(); + } + } - // Make sure the CSG Model knows about this brush. If they duplicated a brush in the hierarchy then this - // allows us to make sure the CSG Model knows about it - if(parentCSGModel != null) - { - bool newBrush = parentCSGModel.TrackBrush(this); - - if(newBrush) - { - MeshFilter meshFilter = gameObject.AddOrGetComponent(); - - meshFilter.sharedMesh = new Mesh(); - brushCache = new BrushCache(); - EnsureWellFormed(); - RecalculateBrushCache(); - } - Invalidate(false); - tracked = true; - } - else - { - tracked = false; - } - } + // public void OnDrawGizmosSelected() + // { + // // Ensure Edit Mode is on + // GetCSGModel().EditMode = true; + // } + // + // public void OnDrawGizmos() + // { + // EnsureWellFormed(); + // + // // Gizmos.color = Color.green; + // // for (int i = 0; i < PolygonFactory.hackyDisplay1.Count; i++) + // // { + // // Gizmos.DrawSphere(PolygonFactory.hackyDisplay1[i], 0.2f); + // // } + // // + // // Gizmos.color = Color.red; + // // for (int i = 0; i < PolygonFactory.hackyDisplay2.Count; i++) + // // { + // // Gizmos.DrawSphere(PolygonFactory.hackyDisplay2[i], 0.2f); + // // } + // } + + private void OnDisable() + { + // OnDisable is called on recompilation, so make sure we only process when needed + if (this.enabled == false || (gameObject.activeInHierarchy == false && transform.root.gameObject.activeInHierarchy == true)) + { + GetCSGModel().OnBrushDisabled(this); + // Copy the intersections list since the source list will change as we call recalculate on other brushes + List intersectingVisualBrushes = new List(brushCache.IntersectingVisualBrushes); - void OnEnable() - { - UpdateTracking(); - } + for (int i = 0; i < intersectingVisualBrushes.Count; i++) + { + if (intersectingVisualBrushes[i] != null) + { + intersectingVisualBrushes[i].RecalculateIntersections(); + intersectingVisualBrushes[i].BrushCache.SetUnbuilt(); + } + } + } + } - void Update() - { - if(!tracked) - { - UpdateTracking(); - } + private void UpdateTracking() + { + CSGModelBase parentCSGModel = GetCSGModel(); - // If the transform has changed, needs rebuild - if(cachedWorldTransform.SetFromTransform(transform)) - { - Invalidate(true); - } - } + // Make sure the CSG Model knows about this brush. If they duplicated a brush in the hierarchy then this + // allows us to make sure the CSG Model knows about it + if (parentCSGModel != null) + { + // don't track brushes while a large scene update is going on. + if (parentCsgModel.IsUpdating) return; + + bool newBrush = parentCSGModel.TrackBrush(this); + + if (newBrush) + { + MeshFilter meshFilter = gameObject.AddOrGetComponent(); + + meshFilter.sharedMesh = new Mesh(); + brushCache = new BrushCache(); + EnsureWellFormed(); + RecalculateBrushCache(); + } + Invalidate(false); + tracked = true; + } + else + { + tracked = false; + } + } + + private void OnEnable() + { + UpdateTracking(); + } + + protected override void Update() + { + base.Update(); + + if (!tracked) + { + UpdateTracking(); + } - /// - /// Tells the brush it has changed - /// - /// If set to true polygons will be recached. + // If the transform has changed, needs rebuild + if (cachedWorldTransform.SetFromTransform(transform)) + { + Invalidate(true); + } + } + + /// + /// Tells the brush it has changed + /// + /// If set to true polygons will be recached. public override void Invalidate(bool polygonsChanged) { - base.Invalidate(polygonsChanged); - if(!gameObject.activeInHierarchy) - { - return; - } + base.Invalidate(polygonsChanged); + if (!gameObject.activeInHierarchy) + { + return; + } // previous versions of sabrecsg used to use mesh colliders for ray collision, but that's no longer the case so we clean them up. MeshCollider[] meshColliders = GetComponents(); @@ -573,7 +667,6 @@ public override void Invalidate(bool polygonsChanged) for (int i = 0; i < meshColliders.Length; i++) DestroyImmediate(meshColliders[i]); - // Make sure there is a mesh filter on this object MeshFilter meshFilter = gameObject.AddOrGetComponent(); MeshRenderer meshRenderer = gameObject.AddOrGetComponent(); @@ -597,17 +690,16 @@ public override void Invalidate(bool polygonsChanged) if (polygons != null) { - List polygonIndices; - BrushFactory.GenerateMeshFromPolygons(polygons, ref renderMesh, out polygonIndices); + // generate a mesh preview for the transparent brushes. + // we also displace the triangles along the normals slightly so we can overlay built geometry + // with semi-transparent geometry and avoid depth fighting. + BrushFactory.GenerateMeshFromPolygonsFast(polygons, ref renderMesh, mode == CSGMode.Add ? 0.001f : -0.001f); } if (mode == CSGMode.Subtract) { MeshHelper.Invert(ref renderMesh); } - // Displace the triangles for display along the normals very slightly (this is so we can overlay built - // geometry with semi-transparent geometry and avoid depth fighting) - MeshHelper.Displace(ref renderMesh, 0.001f); meshFilter.sharedMesh = renderMesh; @@ -639,34 +731,34 @@ public override void Invalidate(bool polygonsChanged) meshRenderer.sharedMaterial = material; } #endif -// isBrushConvex = GeometryHelper.IsBrushConvex(polygons); + // isBrushConvex = GeometryHelper.IsBrushConvex(polygons); - if(polygonsChanged) - { - RecalculateBrushCache(); - } + if (polygonsChanged) + { + RecalculateBrushCache(); + } - UpdateVisibility(); + UpdateVisibility(); - objectVersionSerialized++; - objectVersionUnserialized = objectVersionSerialized; + objectVersionSerialized++; + objectVersionUnserialized = objectVersionSerialized; - if(cachedWorldTransform == null) - { - cachedWorldTransform = new WorldTransformData(transform); - } - cachedWorldTransform.SetFromTransform(transform); + if (cachedWorldTransform == null) + { + cachedWorldTransform = new WorldTransformData(transform); + } + cachedWorldTransform.SetFromTransform(transform); } - public override void UpdateVisibility() + public override void UpdateVisibility() { - // Display brush if the CSG Model says to or if the brush isn't under a CSG Model - CSGModelBase csgModel = GetCSGModel(); - bool isVisible = false; - if(csgModel == null || csgModel.AreBrushesVisible) - { - isVisible = true; - } + // Display brush if the CSG Model says to or if the brush isn't under a CSG Model + CSGModelBase csgModel = GetCSGModel(); + bool isVisible = false; + if (csgModel == null || csgModel.AreBrushesVisible) + { + isVisible = true; + } MeshRenderer meshRenderer = GetComponent(); if (meshRenderer != null) { @@ -674,58 +766,58 @@ public override void UpdateVisibility() } } -// public Polygon GetPolygonFromTriangle(int triangleIndex) -// { -// int polygonIndex = polygonIndices[triangleIndex]; -// return polygons[polygonIndex]; -// } + // public Polygon GetPolygonFromTriangle(int triangleIndex) + // { + // int polygonIndex = polygonIndices[triangleIndex]; + // return polygons[polygonIndex]; + // } public override Bounds GetBounds() { - if (polygons.Length > 0) - { - Bounds bounds = new Bounds(polygons[0].Vertices[0].Position, Vector3.zero); - - for (int i = 0; i < polygons.Length; i++) - { - for (int j = 0; j < polygons[i].Vertices.Length; j++) - { - bounds.Encapsulate(polygons[i].Vertices[j].Position); - } - } - return bounds; - } - else - { - return new Bounds(Vector3.zero, Vector3.zero); - } + if (polygons != null && polygons.Length > 0) + { + Bounds bounds = new Bounds(polygons[0].Vertices[0].Position, Vector3.zero); + + for (int i = 0; i < polygons.Length; i++) + { + for (int j = 0; j < polygons[i].Vertices.Length; j++) + { + bounds.Encapsulate(polygons[i].Vertices[j].Position); + } + } + return bounds; + } + else + { + return new Bounds(Vector3.zero, Vector3.zero); + } } - public override void SetBounds (Bounds newBounds) - { - throw new NotImplementedException (); - } + public override void SetBounds(Bounds newBounds) + { + throw new NotImplementedException(); + } - public override Bounds GetBoundsTransformed() - { - if (polygons.Length > 0) - { - Bounds bounds = new Bounds(transform.TransformPoint(polygons[0].Vertices[0].Position), Vector3.zero); - - for (int i = 0; i < polygons.Length; i++) - { - for (int j = 0; j < polygons[i].Vertices.Length; j++) - { - bounds.Encapsulate(transform.TransformPoint(polygons[i].Vertices[j].Position)); - } - } - return bounds; - } - else - { - return new Bounds(Vector3.zero, Vector3.zero); - } - } + public override Bounds GetBoundsTransformed() + { + if (polygons.Length > 0) + { + Bounds bounds = new Bounds(transform.TransformPoint(polygons[0].Vertices[0].Position), Vector3.zero); + + for (int i = 0; i < polygons.Length; i++) + { + for (int j = 0; j < polygons[i].Vertices.Length; j++) + { + bounds.Encapsulate(transform.TransformPoint(polygons[i].Vertices[j].Position)); + } + } + return bounds; + } + else + { + return new Bounds(Vector3.zero, Vector3.zero); + } + } public override Bounds GetBoundsLocalTo(Transform otherTransform) { @@ -749,168 +841,175 @@ public override Bounds GetBoundsLocalTo(Transform otherTransform) } public float CalculateExtentsInAxis(Vector3 worldAxis) - { - // Transform the world axis direction to local - Vector3 localAxis = transform.InverseTransformDirection(worldAxis); + { + // Transform the world axis direction to local + Vector3 localAxis = transform.InverseTransformDirection(worldAxis); - float minDot = Vector3.Dot(polygons[0].Vertices[0].Position, localAxis); - float maxDot = minDot; + float minDot = Vector3.Dot(polygons[0].Vertices[0].Position, localAxis); + float maxDot = minDot; - for (int i = 0; i < polygons.Length; i++) - { - for (int j = 0; j < polygons[i].Vertices.Length; j++) - { - float dot = Vector3.Dot(polygons[i].Vertices[j].Position, localAxis); - minDot = Mathf.Min(dot, minDot); - maxDot = Mathf.Max(dot, maxDot); - } - } + for (int i = 0; i < polygons.Length; i++) + { + for (int j = 0; j < polygons[i].Vertices.Length; j++) + { + float dot = Vector3.Dot(polygons[i].Vertices[j].Position, localAxis); + minDot = Mathf.Min(dot, minDot); + maxDot = Mathf.Max(dot, maxDot); + } + } - return maxDot - minDot; - } - - public override int[] GetPolygonIDs () - { - int[] ids = new int[polygons.Length]; - for (int i = 0; i < polygons.Length; i++) - { - ids[i] = polygons[i].UniqueIndex; - } - return ids; - } + return maxDot - minDot; + } - public override Polygon[] GetPolygons () - { - return polygons; - } + public override int[] GetPolygonIDs() + { + int[] ids = new int[polygons.Length]; + for (int i = 0; i < polygons.Length; i++) + { + ids[i] = polygons[i].UniqueIndex; + } + return ids; + } - public override int AssignUniqueIDs (int startingIndex) - { - for (int i = 0; i < polygons.Length; i++) - { - int uniqueIndex = startingIndex + i; - polygons[i].UniqueIndex = uniqueIndex; - } + public override Polygon[] GetPolygons() + { + return polygons; + } - int assignedCount = polygons.Length; - - return assignedCount; - } + public override int AssignUniqueIDs(int startingIndex) + { + for (int i = 0; i < polygons.Length; i++) + { + int uniqueIndex = startingIndex + i; + polygons[i].UniqueIndex = uniqueIndex; + } - /// - /// Resets the pivot to the center of the brush. The world position of vertices remains unchanged, but the brush position and local vertex positions are updated so that the pivot is at the center. - /// - public void ResetPivot() - { - Vector3 delta = GetBounds().center; + int assignedCount = polygons.Length; - for (int i = 0; i < polygons.Length; i++) - { - for (int j = 0; j < polygons[i].Vertices.Length; j++) - { - polygons[i].Vertices[j].Position -= delta; - } - } + return assignedCount; + } - // Bounds is aligned with the object - transform.Translate(delta.Multiply(transform.localScale)); + /// + /// Resets the pivot to the center of the brush. The world position of vertices remains unchanged, but the brush position and local vertex positions are updated so that the pivot is at the center. + /// + public void ResetPivot() + { + Vector3 delta = GetBounds().center; - // Counter the delta offset - Transform[] childTransforms = transform.GetComponentsInChildren(true); + for (int i = 0; i < polygons.Length; i++) + { + for (int j = 0; j < polygons[i].Vertices.Length; j++) + { + polygons[i].Vertices[j].Position -= delta; + } + } - for (int i = 0; i < childTransforms.Length; i++) - { - if(childTransforms[i] != transform) - { - childTransforms[i].Translate(-delta); - } - } + // Bounds is aligned with the object + transform.Translate(delta.Multiply(transform.localScale)); - // Only invalidate if it's actually been realigned - if(delta != Vector3.zero) - { - Invalidate(true); - } - } - - /// - /// Duplicates the brush game object and returns the new object. - /// - /// The game object of the new brush. - public GameObject Duplicate() - { - GameObject newObject = Instantiate(this.gameObject); + // Counter the delta offset + Transform[] childTransforms = transform.GetComponentsInChildren(true); - newObject.name = this.gameObject.name; + for (int i = 0; i < childTransforms.Length; i++) + { + if (childTransforms[i] != transform) + { + childTransforms[i].Translate(-delta); + } + } - newObject.transform.parent = this.transform.parent; + // Only invalidate if it's actually been realigned + if (delta != Vector3.zero) + { + Invalidate(true); + } + } - return newObject; - } + /// + /// Duplicates the brush game object and returns the new object. + /// + /// The game object of the new brush. + public GameObject Duplicate() + { + GameObject newObject = Instantiate(this.gameObject); - public override void PrepareToBuild(List brushes, bool forceRebuild) - { - if(forceRebuild) - { - brushCache.SetUnbuilt(); - RecachePolygons(true); - RecalculateIntersections(brushes, false); - } - } + newObject.name = this.gameObject.name; - /// - /// Get the CSG Model that the brush is under - /// - /// The CSG Model. - public CSGModelBase GetCSGModel() - { - if (parentCsgModel == null) - { - CSGModelBase[] models = transform.GetComponentsInParent(true); - if(models.Length > 0) - { - parentCsgModel = models[0]; - } - } - return parentCsgModel; - } + // copy the scale with checks for scaled parents and being of a scaled child. + newObject.transform.parent = null; + newObject.transform.localScale = this.transform.lossyScale; + newObject.transform.parent = this.transform.parent; - public override void UpdateCachedBrushOrder () - { - Transform csgModelTransform = GetCSGModel().transform; + // copy the world position as compound brush children brushes have position 0,0,0. + // once parented they will end up at world position 0,0,0 if this step isn't done. + newObject.transform.position = this.transform.position; + + return newObject; + } + + public override void PrepareToBuild(List brushes, bool forceRebuild) + { + if (forceRebuild) + { + brushCache.SetUnbuilt(); + RecachePolygons(true); + RecalculateIntersections(brushes, false); + } + } - List reversePositions = new List(); + /// + /// Get the CSG Model that the brush is under + /// + /// The CSG Model. + public CSGModelBase GetCSGModel() + { + if (parentCsgModel == null) + { + CSGModelBase[] models = transform.GetComponentsInParent(true); + if (models.Length > 0) + { + parentCsgModel = models[0]; + } + } + return parentCsgModel; + } - Transform traversedTransform = transform; + public override void UpdateCachedBrushOrder() + { + Transform csgModelTransform = GetCSGModel().transform; - reversePositions.Add(traversedTransform.GetSiblingIndex()); + List reversePositions = new List(); - while(traversedTransform.parent != null && traversedTransform.parent != csgModelTransform) - { - traversedTransform = traversedTransform.parent; - reversePositions.Add(traversedTransform.GetSiblingIndex()); - } + Transform traversedTransform = transform; - BrushOrder brushOrder = new BrushOrder(); - int count = reversePositions.Count; - brushOrder.Position = new int[count]; - for (int i = 0; i < count; i++) - { - brushOrder.Position[i] = reversePositions[count-1-i]; - } + reversePositions.Add(traversedTransform.GetSiblingIndex()); - cachedBrushOrder = brushOrder; - } + while (traversedTransform.parent != null && traversedTransform.parent != csgModelTransform) + { + traversedTransform = traversedTransform.parent; + reversePositions.Add(traversedTransform.GetSiblingIndex()); + } - public override BrushOrder GetBrushOrder () - { - if(cachedBrushOrder == null) - { - UpdateCachedBrushOrder(); - } + BrushOrder brushOrder = new BrushOrder(); + int count = reversePositions.Count; + brushOrder.Position = new int[count]; + for (int i = 0; i < count; i++) + { + brushOrder.Position[i] = reversePositions[count - 1 - i]; + } - return cachedBrushOrder; - } + cachedBrushOrder = brushOrder; + } + + public override BrushOrder GetBrushOrder() + { + if (cachedBrushOrder == null) + { + UpdateCachedBrushOrder(); + } + + return cachedBrushOrder; + } #if (UNITY_5_0 || UNITY_5_1) void OnDrawGizmosSelected() diff --git a/Scripts/CSGModel.cs b/Scripts/CSGModel.cs index 76fa47b8..c5add3bc 100644 --- a/Scripts/CSGModel.cs +++ b/Scripts/CSGModel.cs @@ -14,138 +14,148 @@ namespace Sabresaurus.SabreCSG { [ExecuteInEditMode] - public class CSGModel : CSGModelBase - { + public class CSGModel : CSGModelBase + { #if UNITY_EDITOR - [SerializeField,HideInInspector] - bool firstRun = true; - const int MODEL_VERSION = 1; + [SerializeField, HideInInspector] + private bool firstRun = true; + + private const int MODEL_VERSION = 1; + + // Warning disabled as this field is not in use yet, but helps future proof some cases +#pragma warning disable 414 + + [SerializeField, HideInInspector] + private int modelVersion = 0; - // Warning disabled as this field is not in use yet, but helps future proof some cases -#pragma warning disable 414 - [SerializeField,HideInInspector] - int modelVersion = 0; #pragma warning restore 414 - - [SerializeField,HideInInspector] - bool autoRebuild = false; - bool editMode = false; - static CSGModel editModeModel = null; + [SerializeField, HideInInspector] + private bool autoRebuild = false; - bool mouseIsDragging = false; - bool mouseIsHeld = false; - DateTime mouseReleaseTime = DateTime.MinValue; + private bool editMode = false; + private static CSGModel editModeModel = null; - // Tools - Tool activeTool = null; + private bool mouseIsDragging = false; + private bool mouseIsHeld = false; + private bool mouseIsDoubleClick = false; + private DateTime mouseReleaseTime = DateTime.MinValue; - // Used to track what objects have been previously clicked on, so that the user can cycle click through objects - // on the same (or similar) ray cast - List previousHits = new List(); - List lastHitSet = new List(); + // Tools + private Tool activeTool = null; - // Marked as serialized to persist through recompiles, used by draw tool - [SerializeField,HideInInspector] - Brush lastSelectedBrush = null; + // Used to track what objects have been previously clicked on, so that the user can cycle click through objects + // on the same (or similar) ray cast + private List previousHits = new List(); - float currentFrameTimestamp = 0; - float currentFrameDelta = 0; + private List lastHitSet = new List(); - static bool anyCSGModelsInEditMode = false; + // Marked as serialized to persist through recompiles, used by draw tool + [SerializeField, HideInInspector] + private Brush lastSelectedBrush = null; - static UnityEngine.Object[] deferredSelection = null; + private float currentFrameTimestamp = 0; + private float currentFrameDelta = 0; - public float CurrentFrameDelta { - get { - return currentFrameDelta; - } - } + private static bool anyCSGModelsInEditMode = false; - Dictionary tools = new Dictionary() - { - { MainMode.Resize, new ResizeEditor() }, - { MainMode.Vertex, new VertexEditor() }, - { MainMode.Face, new SurfaceEditor() }, - { MainMode.Clip, new ClipEditor() }, - { MainMode.Draw, new DrawEditor() }, - }; - - Dictionary overrideTools = new Dictionary() + private static UnityEngine.Object[] deferredSelection = null; + + public float CurrentFrameDelta + { + get + { + return currentFrameDelta; + } + } + + private Dictionary tools = new Dictionary() + { + { MainMode.Resize, new ResizeEditor() }, + { MainMode.Vertex, new VertexEditor() }, + { MainMode.Face, new SurfaceEditor() }, + { MainMode.Clip, new ClipEditor() }, + { MainMode.Draw, new DrawEditor() }, + }; + + private Dictionary overrideTools = new Dictionary() { { OverrideMode.TransformModel, new TransformModelEditor() }, //{ OverrideMode.Clip, new ClipEditor() }, //{ OverrideMode.Draw, new DrawEditor() }, }; - public bool MouseIsDragging - { - get - { - return mouseIsDragging; - } - } + public bool MouseIsDragging + { + get + { + return mouseIsDragging; + } + } - public bool MouseIsHeld - { - get - { - return mouseIsHeld; - } - } + public bool MouseIsHeld + { + get + { + return mouseIsHeld; + } + } - public bool MouseIsHeldOrRecent - { - get - { - return mouseIsHeld || (MouseReleaseDuration < 0.22f); - } - } + public bool MouseIsHeldOrRecent + { + get + { + return mouseIsHeld || (MouseReleaseDuration < 0.22f); + } + } - public double MouseReleaseDuration - { - get - { - return (DateTime.UtcNow - mouseReleaseTime).TotalSeconds; - } - } + public double MouseReleaseDuration + { + get + { + return (DateTime.UtcNow - mouseReleaseTime).TotalSeconds; + } + } - public Brush LastSelectedBrush - { - get - { - return lastSelectedBrush; - } - } + public Brush LastSelectedBrush + { + get + { + return lastSelectedBrush; + } + } - public bool AutoRebuild { - get { - return autoRebuild; - } - set { - autoRebuild = value; - } - } + public bool AutoRebuild + { + get + { + return autoRebuild; + } + set + { + autoRebuild = value; + } + } + + protected override void Start() + { + UpdateUtility.RunCleanup(); - protected override void Start () - { - UpdateUtility.RunCleanup(); - // SabreCSG turns off Auto Generate, but loading a scene in editor will look too dark without it, so force refresh DynamicGI.UpdateEnvironment(); - base.Start (); + base.Start(); - if(firstRun) - { - // Make sure editing is turned on - EditMode = true; + if (firstRun) + { + // Make sure editing is turned on + EditMode = true; brushes = new List(transform.GetComponentsInChildren(false)); // Only create a brush if the model doesn't already contain one - if(brushes.Count == 0) + if (brushes.Count == 0) { // Create the default brush GameObject newBrushObject = CreateBrush(PrimitiveBrushType.Cube, new Vector3(0, 1, 0)); @@ -154,64 +164,64 @@ protected override void Start () } firstRun = false; - EditorHelper.SetDirty(this); - } + EditorHelper.SetDirty(this); + } - // Make sure we are correctly tracking whether any CSG Models are actually in edit mode - bool wereAnyInEditMode = anyCSGModelsInEditMode; - anyCSGModelsInEditMode = false; - CSGModel[] csgModels = FindObjectsOfType(); + // Make sure we are correctly tracking whether any CSG Models are actually in edit mode + bool wereAnyInEditMode = anyCSGModelsInEditMode; + anyCSGModelsInEditMode = false; + CSGModel[] csgModels = FindObjectsOfType(); - // Loop through all the CSG Models in the scene and check if any are in edit mode - for (int i = 0; i < csgModels.Length; i++) - { - if(csgModels[i] != this - && csgModels[i].EditMode) - { - anyCSGModelsInEditMode = true; - } - } + // Loop through all the CSG Models in the scene and check if any are in edit mode + for (int i = 0; i < csgModels.Length; i++) + { + if (csgModels[i] != this + && csgModels[i].EditMode) + { + anyCSGModelsInEditMode = true; + } + } - // If the status of whether any Models are in edit mode has changed, make sure all the brushes update their - // visibility. For example we moved from editing a CSG Model to opening another scene where no CSG Model is - // in edit mode. wereAnyInEditMode would be true and anyCSGModelsInEditMode would now be false - if(anyCSGModelsInEditMode != wereAnyInEditMode) - { + // If the status of whether any Models are in edit mode has changed, make sure all the brushes update their + // visibility. For example we moved from editing a CSG Model to opening another scene where no CSG Model is + // in edit mode. wereAnyInEditMode would be true and anyCSGModelsInEditMode would now be false + if (anyCSGModelsInEditMode != wereAnyInEditMode) + { UpdateAllBrushesVisibility(); - } + } - if(modelVersion < MODEL_VERSION) - { - // Upgrading or a new model, so grab all the brushes in case it's an upgrade - brushes = new List(transform.GetComponentsInChildren(false)); + if (modelVersion < MODEL_VERSION) + { + // Upgrading or a new model, so grab all the brushes in case it's an upgrade + brushes = new List(transform.GetComponentsInChildren(false)); - // Make sure all brushes have a valid brush cache and need rebuilding - for (int i = 0; i < brushes.Count; i++) - { - if(brushes[i] != null) - { - brushes[i].RecachePolygons(true); - } - } + // Make sure all brushes have a valid brush cache and need rebuilding + for (int i = 0; i < brushes.Count; i++) + { + if (brushes[i] != null) + { + brushes[i].RecachePolygons(true); + } + } - // Force all brushes to recalculate intersections - for (int i = 0; i < brushes.Count; i++) - { - if(brushes[i] != null) - { - brushes[i].RecalculateIntersections(brushes, false); - } - } + // Force all brushes to recalculate intersections + for (int i = 0; i < brushes.Count; i++) + { + if (brushes[i] != null) + { + brushes[i].RecalculateIntersections(brushes, false); + } + } - // Finally now that the potential upgrade is complete, track that the model is the correct version now - modelVersion = MODEL_VERSION; - } - } + // Finally now that the potential upgrade is complete, track that the model is the correct version now + modelVersion = MODEL_VERSION; + } + } public override void Build(bool forceRebuild, bool buildInBackground) { // Build can take place if meshes are not saved to the DB, or if the scene is saved - if(!buildSettings.SaveMeshesAsAssets || EnsureUntitledSceneHasBeenSaved("Scene must be saved for SaveMeshesAsAssets to work")) + if (!buildSettings.SaveMeshesAsAssets || EnsureUntitledSceneHasBeenSaved("Scene must be saved for SaveMeshesAsAssets to work")) { base.Build(forceRebuild, buildInBackground); } @@ -221,13 +231,13 @@ private bool EnsureUntitledSceneHasBeenSaved(string message) { #if UNITY_5_6_OR_NEWER || UNITY_5_6 return UnityEditor.SceneManagement.EditorSceneManager.EnsureUntitledSceneHasBeenSaved(message); - + #elif UNITY_5_3_OR_NEWER if(string.IsNullOrEmpty(SceneManager.GetActiveScene().path)) // Scene not saved { // Ask the user to save UnityEditor.SceneManagement.EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo(); - + // Check that the scene was saved if(!string.IsNullOrEmpty(SceneManager.GetActiveScene().path)) { @@ -265,234 +275,232 @@ private bool EnsureUntitledSceneHasBeenSaved(string message) #endif } - public override void OnBuildComplete () - { - base.OnBuildComplete (); + public override void OnBuildComplete() + { + base.OnBuildComplete(); - EditorUtility.ClearProgressBar(); + EditorUtility.ClearProgressBar(); UpdateAllBrushesVisibility(); - EditorHelper.SetDirty(this); - SetContextDirty(); - } + EditorHelper.SetDirty(this); + SetContextDirty(); + } - public void OnSceneGUI(SceneView sceneView) - { - if(Event.current.type == EventType.ExecuteCommand) - { - if(Event.current.commandName == "Duplicate") - { - if(EditorHelper.DuplicateSelection()) - { - Event.current.Use(); - } - } - } - Event e = Event.current; + public void OnSceneGUI(SceneView sceneView) + { + if (Event.current.type == EventType.ExecuteCommand) + { + if (Event.current.commandName == "Duplicate") + { + if (EditorHelper.DuplicateSelection()) + { + Event.current.Use(); + } + } + } + Event e = Event.current; - if(!EditMode) - { - return; - } + if (!EditMode) + { + return; + } - RadialMenu.OnEarlySceneGUI(sceneView); + RadialMenu.OnEarlySceneGUI(sceneView); - // Frame rate tracking - if(e.type == EventType.Repaint) - { - currentFrameDelta = Time.realtimeSinceStartup - currentFrameTimestamp; - currentFrameTimestamp = Time.realtimeSinceStartup; - } + // Frame rate tracking + if (e.type == EventType.Repaint) + { + currentFrameDelta = Time.realtimeSinceStartup - currentFrameTimestamp; + currentFrameTimestamp = Time.realtimeSinceStartup; + } - // Raw checks for tracking mouse events (use raw so that consumed events are not ignored) - if (e.rawType == EventType.MouseDown) - { - mouseIsDragging = false; - mouseIsHeld = true; + // Raw checks for tracking mouse events (use raw so that consumed events are not ignored) + if (e.rawType == EventType.MouseDown) + { + mouseIsDragging = false; + mouseIsHeld = true; - if(e.button == 0 && GUIUtility.hotControl == 0 ) - { - GUIUtility.keyboardControl = 0; - } + if (e.button == 0 && GUIUtility.hotControl == 0) + { + GUIUtility.keyboardControl = 0; + } + } + else if (e.rawType == EventType.MouseDrag) + { + mouseIsDragging = true; + } + else if (e.rawType == EventType.MouseUp) + { + mouseIsHeld = false; + mouseReleaseTime = DateTime.UtcNow; + } - } - else if (e.rawType == EventType.MouseDrag) - { - mouseIsDragging = true; - } - else if (e.rawType == EventType.MouseUp) - { - mouseIsHeld = false; - mouseReleaseTime = DateTime.UtcNow; - } + // if (CurrentSettings.BrushesVisible) + { + // No idea what this line of code means, but it seems to stop normal mouse selection + HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive)); + } -// if (CurrentSettings.BrushesVisible) - { - // No idea what this line of code means, but it seems to stop normal mouse selection - HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive)); - } + if (EditMode && CurrentSettings.OverrideMode != OverrideMode.TransformModel) + { + // In CSG mode, prevent the normal tools, so that the user must use our tools instead + Tools.current = UnityEditor.Tool.None; + } - if(EditMode && CurrentSettings.OverrideMode != OverrideMode.TransformModel) - { - // In CSG mode, prevent the normal tools, so that the user must use our tools instead - Tools.current = UnityEditor.Tool.None; - } + int concaveBrushCount = 0; + for (int i = 0; i < brushes.Count; i++) + { + if (brushes[i] != null && !brushes[i].IsBrushConvex) + { + concaveBrushCount++; + } + } + if (concaveBrushCount > 0) + { + Toolbar.WarningMessage = concaveBrushCount + " Concave Brush" + (concaveBrushCount > 1 ? "es" : "") + " Detected"; + } + else + { + // Toolbar.WarningMessage = ""; + } - int concaveBrushCount = 0; - for (int i = 0; i < brushes.Count; i++) - { - if(brushes[i] != null && !brushes[i].IsBrushConvex) - { - concaveBrushCount++; - } - } - if(concaveBrushCount > 0) - { - Toolbar.WarningMessage = concaveBrushCount + " Concave Brush" + (concaveBrushCount > 1 ? "es" : "") + " Detected"; - } - else - { - // Toolbar.WarningMessage = ""; - } + Toolbar.CSGModel = this; + Toolbar.OnSceneGUI(sceneView, e); - Toolbar.CSGModel = this; - Toolbar.OnSceneGUI(sceneView, e); + if (e.type == EventType.Repaint)// || e.type == EventType.Layout) + { + if (CurrentSettings.ShowExcludedPolygons) + { + List allPolygons = BuildContext.VisualPolygons ?? new List(); + List excluded = new List(); + for (int i = 0; i < allPolygons.Count; i++) + { + if (allPolygons[i].UserExcludeFromFinal) + { + excluded.Add(allPolygons[i]); + } + } + SabreCSGResources.GetExcludedMaterial().SetPass(0); - if (e.type == EventType.Repaint)// || e.type == EventType.Layout) - { - if(CurrentSettings.ShowExcludedPolygons) - { - List allPolygons = BuildContext.VisualPolygons ?? new List(); - List excluded = new List(); - for (int i = 0; i < allPolygons.Count; i++) - { - if(allPolygons[i].UserExcludeFromFinal) - { - excluded.Add(allPolygons[i]); - } - } - SabreCSGResources.GetExcludedMaterial().SetPass(0); + Mesh mesh = new Mesh(); + BrushFactory.GenerateMeshFromPolygonsFast(excluded.ToArray(), ref mesh, 0.0f); - Mesh mesh = new Mesh(); - List indices = new List(); - BrushFactory.GenerateMeshFromPolygons(excluded.ToArray(), ref mesh, out indices); + Graphics.DrawMeshNow(mesh, Vector3.zero, Quaternion.identity); - Graphics.DrawMeshNow(mesh, Vector3.zero, Quaternion.identity); + // SabreGraphics.DrawPolygons(new Color(1,1,0,0.65f), new Color(1,0.8f,0,0.9f), excluded.ToArray()); + } -// SabreGraphics.DrawPolygons(new Color(1,1,0,0.65f), new Color(1,0.8f,0,0.9f), excluded.ToArray()); - } + if (activeTool == null || activeTool.BrushesHandleDrawing) + { + SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); + // Selection + GL.Begin(GL.LINES); + Color outlineColor = Color.blue; - if (activeTool == null || activeTool.BrushesHandleDrawing) - { - SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); - // Selection - GL.Begin(GL.LINES); - Color outlineColor = Color.blue; + for (int brushIndex = 0; brushIndex < brushes.Count; brushIndex++) + { + Brush brush = brushes[brushIndex]; + if (brush == null) + { + continue; + } + GameObject brushGameObject = brush.gameObject; - for (int brushIndex = 0; brushIndex < brushes.Count; brushIndex++) - { - Brush brush = brushes[brushIndex]; - if(brush == null) - { - continue; - } - GameObject brushGameObject = brush.gameObject; - - if(!brushGameObject.activeInHierarchy) - { - continue; - } - - if (Selection.Contains(brushGameObject)) - { - if (brushes[brushIndex].IsNoCSG) - { - outlineColor = new Color(1f,0.6f,1.0f); - } - else - { - if (brushes[brushIndex].Mode == CSGMode.Add) - { - outlineColor = Color.cyan; - } - else - { - outlineColor = Color.yellow; - } - } - } - else if(CurrentSettings.BrushesVisible) - { - if (brushes[brushIndex].IsNoCSG) - { - outlineColor = new Color(0.8f,0.3f,1.0f); - } - else - { - if (brushes[brushIndex].Mode == CSGMode.Add) - { - outlineColor = Color.blue; - } - else - { - outlineColor = new Color32(255, 130, 0, 255); - } - } - } - else - { - continue; - } - - GL.Color(outlineColor); - - Polygon[] polygons = brush.GetPolygons(); - Transform brushTransform = brush.transform; - - // Brush Outline - for (int i = 0; i < polygons.Length; i++) - { - Polygon polygon = polygons[i]; - - for (int j = 0; j < polygon.Vertices.Length; j++) - { - Vector3 position = brushTransform.TransformPoint(polygon.Vertices[j].Position); - GL.Vertex(position); - - if (j < polygon.Vertices.Length - 1) - { - Vector3 position2 = brushTransform.TransformPoint(polygon.Vertices[j + 1].Position); - GL.Vertex(position2); - } - else - { - Vector3 position2 = brushTransform.TransformPoint(polygon.Vertices[0].Position); - GL.Vertex(position2); - } - } - } - } + if (!brushGameObject.activeInHierarchy) + { + continue; + } - GL.End(); + if (Selection.Contains(brushGameObject)) + { + if (brushes[brushIndex].IsNoCSG) + { + outlineColor = new Color(1f, 0.6f, 1.0f); + } + else + { + if (brushes[brushIndex].Mode == CSGMode.Add) + { + outlineColor = Color.cyan; + } + else + { + outlineColor = Color.yellow; + } + } + } + else if (CurrentSettings.BrushesVisible) + { + if (brushes[brushIndex].IsNoCSG) + { + outlineColor = new Color(0.8f, 0.3f, 1.0f); + } + else + { + if (brushes[brushIndex].Mode == CSGMode.Add) + { + outlineColor = Color.blue; + } + else + { + outlineColor = new Color32(255, 130, 0, 255); + } + } + } + else + { + continue; + } - for (int i = 0; i < brushes.Count; i++) - { - if (brushes[i] is PrimitiveBrush && brushes[i] != null && brushes[i].gameObject.activeInHierarchy) - { - ((PrimitiveBrush)brushes[i]).OnRepaint(sceneView, e); - } - } - } - } + GL.Color(outlineColor); - if (e.type == EventType.Repaint) - { - Rect rect = new Rect(0, 0, Screen.width, Screen.height); - EditorGUIUtility.AddCursorRect(rect, SabreMouse.ActiveCursor); - } + Polygon[] polygons = brush.GetPolygons(); + Transform brushTransform = brush.transform; + + // Brush Outline + for (int i = 0; i < polygons.Length; i++) + { + Polygon polygon = polygons[i]; + + for (int j = 0; j < polygon.Vertices.Length; j++) + { + Vector3 position = brushTransform.TransformPoint(polygon.Vertices[j].Position); + GL.Vertex(position); + + if (j < polygon.Vertices.Length - 1) + { + Vector3 position2 = brushTransform.TransformPoint(polygon.Vertices[j + 1].Position); + GL.Vertex(position2); + } + else + { + Vector3 position2 = brushTransform.TransformPoint(polygon.Vertices[0].Position); + GL.Vertex(position2); + } + } + } + } + + GL.End(); + + for (int i = 0; i < brushes.Count; i++) + { + if (brushes[i] is PrimitiveBrush && brushes[i] != null && brushes[i].gameObject.activeInHierarchy) + { + ((PrimitiveBrush)brushes[i]).OnRepaint(sceneView, e); + } + } + } + } + + if (e.type == EventType.Repaint) + { + Rect rect = new Rect(0, 0, Screen.width, Screen.height); + EditorGUIUtility.AddCursorRect(rect, SabreMouse.ActiveCursor); + } - if(e.type == EventType.Layout) + if (e.type == EventType.Layout) { // Don't need to do this for every OnSceneGUI call, so limit it to Layout events if (activeTool == null @@ -501,119 +509,159 @@ public void OnSceneGUI(SceneView sceneView) UpdateActiveTool(); } } - - if(activeTool != null) - { - activeTool.CSGModel = this; - activeTool.SetSelection(Selection.activeGameObject, Selection.gameObjects); - activeTool.OnSceneGUI(sceneView, e); - } -// if(e.type == EventType.DragPerform) -// { -// Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); -// -// RaycastHit hit = new RaycastHit(); -// -// int layerMask = 1 << LayerMask.NameToLayer("CSGMesh"); -// // Invert the layer mask -// layerMask = ~layerMask; -// -// // Shift mode means only add what they click (clicking nothing does nothing) -// if (Physics.Raycast(ray, out hit, float.PositiveInfinity, layerMask)) -// { -// OnDragDrop(hit.collider.gameObject); -// } -// } - - if (e.type == EventType.MouseUp && !RadialMenu.IsActive) - { - OnMouseUp(sceneView, e); - SabreMouse.ResetCursor(); - } - else if (e.type == EventType.KeyDown || e.type == EventType.KeyUp) - { - OnKeyAction(sceneView, e); - } + if (activeTool != null) + { + activeTool.CSGModel = this; + activeTool.SetSelection(Selection.activeGameObject, Selection.gameObjects); + activeTool.OnSceneGUI(sceneView, e); + } - if(CurrentSettings.OverrideFlyCamera) - { - LinearFPSCam.OnSceneGUI(sceneView); - } + // if(e.type == EventType.DragPerform) + // { + // Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); + // + // RaycastHit hit = new RaycastHit(); + // + // int layerMask = 1 << LayerMask.NameToLayer("CSGMesh"); + // // Invert the layer mask + // layerMask = ~layerMask; + // + // // Shift mode means only add what they click (clicking nothing does nothing) + // if (Physics.Raycast(ray, out hit, float.PositiveInfinity, layerMask)) + // { + // OnDragDrop(hit.collider.gameObject); + // } + // } + + if (e.type == EventType.MouseDown && e.clickCount == 2) + { + mouseIsDoubleClick = true; + OnMouseDoubleClick(sceneView, e); + } + if (e.type == EventType.MouseUp && !RadialMenu.IsActive) + { + OnMouseUp(sceneView, e); + mouseIsDoubleClick = false; - RadialMenu.OnLateSceneGUI(sceneView); - } + SabreMouse.ResetCursor(); + } + else if (e.type == EventType.KeyDown || e.type == EventType.KeyUp) + { + OnKeyAction(sceneView, e); + } - void OnMouseUp(SceneView sceneView, Event e) - { - if (mouseIsDragging - || (activeTool != null && activeTool.PreventBrushSelection) - || EditorHelper.IsMousePositionInInvalidRects(e.mousePosition)) - { - SceneView.RepaintAll(); - return; - } + if (CurrentSettings.OverrideFlyCamera) + { + LinearFPSCam.OnSceneGUI(sceneView); + } - // Left click - select - if (e.button == 0) - { - Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); - List hits = RaycastBrushesAll(ray, true); - List hitBrushes = hits.Select(hit => hit.GameObject.GetComponent()).ToList(); - List hitBases = ExtractBrushBases(hitBrushes); - List hitObjects = hitBases.Select(hit => hit.gameObject).ToList(); + RadialMenu.OnLateSceneGUI(sceneView); + } - GameObject selectedObject = null; + private void OnMouseDoubleClick(SceneView sceneView, Event e) + { + if (mouseIsDragging + || (activeTool != null && activeTool.PreventBrushSelection) + || EditorHelper.IsMousePositionInInvalidRects(e.mousePosition)) + { + SceneView.RepaintAll(); + return; + } - if(hitObjects.Count == 0) // Didn't hit anything, blank the selection - { - previousHits.Clear(); - lastHitSet.Clear(); - } - else if(hitObjects.Count == 1) // Only hit one thing, no ambiguity, this is what is selected - { - selectedObject = hitObjects[0]; - previousHits.Clear(); - lastHitSet.Clear(); - } - else - { - if(!hitObjects.ContentsEquals(lastHitSet)) - { - selectedObject = hitObjects[0]; - previousHits.Clear(); - lastHitSet = hitObjects; - } - else - { - // First try and select anything other than what has been previously hit - for (int i = 0; i < hitObjects.Count; i++) - { - if(!previousHits.Contains(hitObjects[i])) - { - selectedObject = hitObjects[i]; - break; - } - } - - // Only found previously hit objects - if(selectedObject == null) - { - // Walk backwards to find the oldest previous hit that has been hit by this ray - for (int i = previousHits.Count-1; i >= 0 && selectedObject == null; i--) - { - for (int j = 0; j < hitObjects.Count; j++) - { - if(hitObjects[j] == previousHits[i]) - { - selectedObject = previousHits[i]; - break; - } - } - } - } - } - } + // Left double click - select individual brush inside of a group. + if (e.button == 0) + { + Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); + List hits = RaycastBrushesAll(ray, true); + List hitBrushes = hits.Select(hit => hit.GameObject.GetComponent()).ToList(); + List hitObjects = hitBrushes.Select(hit => hit.gameObject).ToList(); + + if (hitObjects.Count >= 1) + { + if (hitObjects[0].transform.parent && hitObjects[0].transform.parent.GetComponent() != null) + { + Selection.activeGameObject = hitObjects[0]; + previousHits.Clear(); + lastHitSet.Clear(); + } + } + } + } + + private void OnMouseUp(SceneView sceneView, Event e) + { + if (mouseIsDragging + || (activeTool != null && activeTool.PreventBrushSelection) + || EditorHelper.IsMousePositionInInvalidRects(e.mousePosition)) + { + SceneView.RepaintAll(); + return; + } + + // don't change the selection when double clicked. + if (mouseIsDoubleClick) return; + + // Left click - select + if (e.button == 0) + { + Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); + List hits = RaycastBrushesAll(ray, true); + List hitBrushes = hits.Select(hit => hit.GameObject.GetComponent()).ToList(); + List hitBases = ExtractBrushBases(hitBrushes); + List hitObjects = hitBases.Select(hit => hit.gameObject).ToList(); + + GameObject selectedObject = null; + + if (hitObjects.Count == 0) // Didn't hit anything, blank the selection + { + previousHits.Clear(); + lastHitSet.Clear(); + } + else if (hitObjects.Count == 1) // Only hit one thing, no ambiguity, this is what is selected + { + selectedObject = hitObjects[0]; + previousHits.Clear(); + lastHitSet.Clear(); + } + else + { + if (!hitObjects.ContentsEquals(lastHitSet)) + { + selectedObject = hitObjects[0]; + previousHits.Clear(); + lastHitSet = hitObjects; + } + else + { + // First try and select anything other than what has been previously hit + for (int i = 0; i < hitObjects.Count; i++) + { + if (!previousHits.Contains(hitObjects[i])) + { + selectedObject = hitObjects[i]; + break; + } + } + + // Only found previously hit objects + if (selectedObject == null) + { + // Walk backwards to find the oldest previous hit that has been hit by this ray + for (int i = previousHits.Count - 1; i >= 0 && selectedObject == null; i--) + { + for (int j = 0; j < hitObjects.Count; j++) + { + if (hitObjects[j] == previousHits[i]) + { + selectedObject = previousHits[i]; + break; + } + } + } + } + } + } if (selectedObject != null) { @@ -623,122 +671,122 @@ void OnMouseUp(SceneView sceneView, Event e) } if (EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Shift) - || EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control) - || EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Command)) - { - List objects = new List(Selection.objects); + || EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control) + || EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Command)) + { + List objects = new List(Selection.objects); - if (objects.Contains(selectedObject)) - { - objects.Remove(selectedObject); - } - else - { - objects.Add(selectedObject); - } - Selection.objects = objects.ToArray(); - } - else - { - Selection.activeGameObject = selectedObject; - } - - e.Use(); - } - } + if (objects.Contains(selectedObject)) + { + objects.Remove(selectedObject); + } + else + { + objects.Add(selectedObject); + } + Selection.objects = objects.ToArray(); + } + else + { + Selection.activeGameObject = selectedObject; + } - /// - /// Subscribes to both KeyDown and KeyUp events from the SceneView delegate. This allows us to easily store key - /// events in one place and mark them as used as necessary (for example to prevent error sounds on key down) - /// - void OnKeyAction(SceneView sceneView, Event e) - { - OnGenericKeyAction(sceneView, e); - } + e.Use(); + } + } - private void OnGenericKeyAction(SceneView sceneView, Event e) - { - if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ToggleMode)) - || KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ToggleModeBack))) - { - // Toggle mode - immediately (key down) - if (e.type == EventType.KeyDown) - { - int currentModeInt = (int)CurrentSettings.CurrentMode; - int count = Enum.GetNames(typeof(MainMode)).Length; + /// + /// Subscribes to both KeyDown and KeyUp events from the SceneView delegate. This allows us to easily store key + /// events in one place and mark them as used as necessary (for example to prevent error sounds on key down) + /// + private void OnKeyAction(SceneView sceneView, Event e) + { + OnGenericKeyAction(sceneView, e); + } - if(KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ToggleModeBack))) - { - currentModeInt--; - } - else - { - currentModeInt++; - } + private void OnGenericKeyAction(SceneView sceneView, Event e) + { + if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ToggleMode)) + || KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ToggleModeBack))) + { + // Toggle mode - immediately (key down) + if (e.type == EventType.KeyDown) + { + int currentModeInt = (int)CurrentSettings.CurrentMode; + int count = Enum.GetNames(typeof(MainMode)).Length; - if (currentModeInt >= count) - { - currentModeInt = 0; - } - else if (currentModeInt < 0) - { - currentModeInt = count - 1; - } - - SetCurrentMode((MainMode)currentModeInt); + if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ToggleModeBack))) + { + currentModeInt--; + } + else + { + currentModeInt++; + } - SceneView.RepaintAll(); - } - e.Use(); - } - else if (!MouseIsHeld && KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ActivateClipMode))) - { - // Activate mode - immediately (key down) - if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) - { - SetCurrentMode(MainMode.Clip); -// SetOverrideMode(OverrideMode.Clip); + if (currentModeInt >= count) + { + currentModeInt = 0; + } + else if (currentModeInt < 0) + { + currentModeInt = count - 1; + } - SceneView.RepaintAll(); - } - e.Use(); - } - else if (!MouseIsHeld && KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ActivateDrawMode))) - { - // Activate mode - immediately (key down) - if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) - { - SetCurrentMode(MainMode.Draw); -// SetOverrideMode(OverrideMode.Draw); + SetCurrentMode((MainMode)currentModeInt); - SceneView.RepaintAll(); - } - e.Use(); - } - else if (!MouseIsHeld && KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ActivateFaceMode))) - { - // Activate mode - immediately (key down) - if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) - { - SetCurrentMode(MainMode.Face); -// SetOverrideMode(OverrideMode.Face); + SceneView.RepaintAll(); + } + e.Use(); + } + else if (!MouseIsHeld && KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ActivateClipMode))) + { + // Activate mode - immediately (key down) + if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) + { + SetCurrentMode(MainMode.Clip); + // SetOverrideMode(OverrideMode.Clip); - SceneView.RepaintAll(); - } - e.Use(); - } - else if (!MouseIsHeld && KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ActivateVertexMode))) - { - // Activate mode - immediately (key down) - if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) - { - SetCurrentMode(MainMode.Vertex); -// SetOverrideMode(OverrideMode.Vertex); + SceneView.RepaintAll(); + } + e.Use(); + } + else if (!MouseIsHeld && KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ActivateDrawMode))) + { + // Activate mode - immediately (key down) + if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) + { + SetCurrentMode(MainMode.Draw); + // SetOverrideMode(OverrideMode.Draw); - SceneView.RepaintAll(); - } - e.Use(); - } + SceneView.RepaintAll(); + } + e.Use(); + } + else if (!MouseIsHeld && KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ActivateFaceMode))) + { + // Activate mode - immediately (key down) + if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) + { + SetCurrentMode(MainMode.Face); + // SetOverrideMode(OverrideMode.Face); + + SceneView.RepaintAll(); + } + e.Use(); + } + else if (!MouseIsHeld && KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ActivateVertexMode))) + { + // Activate mode - immediately (key down) + if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) + { + SetCurrentMode(MainMode.Vertex); + // SetOverrideMode(OverrideMode.Vertex); + + SceneView.RepaintAll(); + } + e.Use(); + } else if (!MouseIsHeld && KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ActivateResizeMode))) { if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) @@ -748,298 +796,298 @@ private void OnGenericKeyAction(SceneView sceneView, Event e) } e.Use(); } - else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.IncreasePosSnapping)) - && !SabreGUIHelper.AnyControlFocussed) - { - if (e.type == EventType.KeyUp) - { - CurrentSettings.ChangePosSnapDistance(2f); - SceneView.RepaintAll(); - } - e.Use(); - } - else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.DecreasePosSnapping)) - && !SabreGUIHelper.AnyControlFocussed) - { - if (e.type == EventType.KeyUp) - { - CurrentSettings.ChangePosSnapDistance(.5f); - SceneView.RepaintAll(); - } - e.Use(); - } - else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.TogglePosSnapping)) - && !SabreGUIHelper.AnyControlFocussed) - { - if (e.type == EventType.KeyUp) - { - CurrentSettings.PositionSnappingEnabled = !CurrentSettings.PositionSnappingEnabled; - SceneView.RepaintAll(); - } - e.Use(); - } - else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.IncreaseAngSnapping)) - && !SabreGUIHelper.AnyControlFocussed) - { - if (e.type == EventType.KeyUp) - { - if(CurrentSettings.AngleSnapDistance >= 15) - { - CurrentSettings.AngleSnapDistance += 15; - } - else - { - CurrentSettings.AngleSnapDistance += 5; - } - SceneView.RepaintAll(); - } - e.Use(); - } - else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.DecreaseAngSnapping)) - && !SabreGUIHelper.AnyControlFocussed) - { - if (e.type == EventType.KeyUp) - { - if(CurrentSettings.AngleSnapDistance > 15) - { - CurrentSettings.AngleSnapDistance -= 15; - } - else - { - CurrentSettings.AngleSnapDistance -= 5; - } - SceneView.RepaintAll(); - } - e.Use(); - } - else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ToggleAngSnapping)) - && !SabreGUIHelper.AnyControlFocussed) - { - if (e.type == EventType.KeyUp) - { - CurrentSettings.AngleSnappingEnabled = !CurrentSettings.AngleSnappingEnabled; - SceneView.RepaintAll(); - } - e.Use(); - } - else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ToggleBrushesHidden)) - && !SabreGUIHelper.AnyControlFocussed) - { - if (e.type == EventType.KeyUp) - { - CurrentSettings.BrushesHidden = !CurrentSettings.BrushesHidden; + else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.IncreasePosSnapping)) + && !SabreGUIHelper.AnyControlFocussed) + { + if (e.type == EventType.KeyUp) + { + CurrentSettings.ChangePosSnapDistance(2f); + SceneView.RepaintAll(); + } + e.Use(); + } + else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.DecreasePosSnapping)) + && !SabreGUIHelper.AnyControlFocussed) + { + if (e.type == EventType.KeyUp) + { + CurrentSettings.ChangePosSnapDistance(.5f); + SceneView.RepaintAll(); + } + e.Use(); + } + else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.TogglePosSnapping)) + && !SabreGUIHelper.AnyControlFocussed) + { + if (e.type == EventType.KeyUp) + { + CurrentSettings.PositionSnappingEnabled = !CurrentSettings.PositionSnappingEnabled; + SceneView.RepaintAll(); + } + e.Use(); + } + else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.IncreaseAngSnapping)) + && !SabreGUIHelper.AnyControlFocussed) + { + if (e.type == EventType.KeyUp) + { + if (CurrentSettings.AngleSnapDistance >= 15) + { + CurrentSettings.AngleSnapDistance += 15; + } + else + { + CurrentSettings.AngleSnapDistance += 5; + } + SceneView.RepaintAll(); + } + e.Use(); + } + else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.DecreaseAngSnapping)) + && !SabreGUIHelper.AnyControlFocussed) + { + if (e.type == EventType.KeyUp) + { + if (CurrentSettings.AngleSnapDistance > 15) + { + CurrentSettings.AngleSnapDistance -= 15; + } + else + { + CurrentSettings.AngleSnapDistance -= 5; + } + SceneView.RepaintAll(); + } + e.Use(); + } + else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ToggleAngSnapping)) + && !SabreGUIHelper.AnyControlFocussed) + { + if (e.type == EventType.KeyUp) + { + CurrentSettings.AngleSnappingEnabled = !CurrentSettings.AngleSnappingEnabled; + SceneView.RepaintAll(); + } + e.Use(); + } + else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ToggleBrushesHidden)) + && !SabreGUIHelper.AnyControlFocussed) + { + if (e.type == EventType.KeyUp) + { + CurrentSettings.BrushesHidden = !CurrentSettings.BrushesHidden; UpdateAllBrushesVisibility(); - SceneView.RepaintAll(); - } - e.Use(); - } - else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.EnableRadialMenu)) - && !SabreGUIHelper.AnyControlFocussed) - { - if (e.type == EventType.KeyUp) - { - RadialMenu.IsActive = true; - SceneView.RepaintAll(); - } - e.Use(); - } - else if(!MouseIsHeld && (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ChangeBrushToAdditive)) - || KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ChangeBrushToAdditive2))) - ) - { - if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) - { - bool anyChanged = false; - - for (int i = 0; i < Selection.gameObjects.Length; i++) - { - BrushBase brushBase = Selection.gameObjects[i].GetComponent(); - if (brushBase != null) - { - Undo.RecordObject(brushBase, "Change Brush To Add"); - brushBase.Mode = CSGMode.Add; - anyChanged = true; - } - } - if(anyChanged) - { - // Need to update the icon for the csg mode in the hierarchy - EditorApplication.RepaintHierarchyWindow(); - SceneView.RepaintAll(); - } - } - e.Use(); - } - else if(!MouseIsHeld && (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ChangeBrushToSubtractive)) - || KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ChangeBrushToSubtractive2))) - ) - { - if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) - { - bool anyChanged = false; + SceneView.RepaintAll(); + } + e.Use(); + } + else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.EnableRadialMenu)) + && !SabreGUIHelper.AnyControlFocussed) + { + if (e.type == EventType.KeyUp) + { + RadialMenu.IsActive = true; + SceneView.RepaintAll(); + } + e.Use(); + } + else if (!MouseIsHeld && (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ChangeBrushToAdditive)) + || KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ChangeBrushToAdditive2))) + ) + { + if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) + { + bool anyChanged = false; - for (int i = 0; i < Selection.gameObjects.Length; i++) - { - BrushBase brushBase = Selection.gameObjects[i].GetComponent(); - if (brushBase != null) - { - Undo.RecordObject(brushBase, "Change Brush To Subtract"); - brushBase.Mode = CSGMode.Subtract; - anyChanged = true; - } - } - if(anyChanged) - { - // Need to update the icon for the csg mode in the hierarchy - EditorApplication.RepaintHierarchyWindow(); - SceneView.RepaintAll(); - } - } - e.Use(); - } - else if(!MouseIsHeld && (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.Group)) - && !SabreGUIHelper.AnyControlFocussed) - ) - { - if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) - { - TransformHelper.GroupSelection(); - } - e.Use(); - } - else if(!MouseIsHeld && (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.Ungroup)) - && !SabreGUIHelper.AnyControlFocussed) - ) - { - if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) - { - TransformHelper.UngroupSelection(); - } - e.Use(); - } - } + for (int i = 0; i < Selection.gameObjects.Length; i++) + { + BrushBase brushBase = Selection.gameObjects[i].GetComponent(); + if (brushBase != null) + { + Undo.RecordObject(brushBase, "Change Brush To Add"); + brushBase.Mode = CSGMode.Add; + anyChanged = true; + } + } + if (anyChanged) + { + // Need to update the icon for the csg mode in the hierarchy + EditorApplication.RepaintHierarchyWindow(); + SceneView.RepaintAll(); + } + } + e.Use(); + } + else if (!MouseIsHeld && (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ChangeBrushToSubtractive)) + || KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.ChangeBrushToSubtractive2))) + ) + { + if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) + { + bool anyChanged = false; + for (int i = 0; i < Selection.gameObjects.Length; i++) + { + BrushBase brushBase = Selection.gameObjects[i].GetComponent(); + if (brushBase != null) + { + Undo.RecordObject(brushBase, "Change Brush To Subtract"); + brushBase.Mode = CSGMode.Subtract; + anyChanged = true; + } + } + if (anyChanged) + { + // Need to update the icon for the csg mode in the hierarchy + EditorApplication.RepaintHierarchyWindow(); + SceneView.RepaintAll(); + } + } + e.Use(); + } + else if (!MouseIsHeld && (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.Group)) + && !SabreGUIHelper.AnyControlFocussed) + ) + { + if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) + { + TransformHelper.GroupSelection(); + } + e.Use(); + } + else if (!MouseIsHeld && (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.Ungroup)) + && !SabreGUIHelper.AnyControlFocussed) + ) + { + if (e.type == EventType.KeyDown && !MouseIsHeldOrRecent) + { + TransformHelper.UngroupSelection(); + } + e.Use(); + } + } #if !(UNITY_5_0 || UNITY_5_1) - void OnSelectionChanged() - { + + private void OnSelectionChanged() + { bool onlyCSGModelsSelected = true; // Does not include brushes - bool anyCSGObjectsSelected = false; // Includes brushes and models - bool anyNonCSGSelected = false; + bool anyCSGObjectsSelected = false; // Includes brushes and models + bool anyNonCSGSelected = false; - List foundModels = new List(); - Dictionary> selectedBrushes = new Dictionary>(); + List foundModels = new List(); + Dictionary> selectedBrushes = new Dictionary>(); - for (int i = 0; i < Selection.gameObjects.Length; i++) - { - // Skip any selected prefabs in the project window - if(PrefabUtility.GetPrefabParent(Selection.gameObjects[i]) == null - && PrefabUtility.GetPrefabObject(Selection.gameObjects[i].transform) != null) - { - continue; - } + for (int i = 0; i < Selection.gameObjects.Length; i++) + { + // Skip any selected prefabs in the project window + if (PrefabUtility.GetPrefabParent(Selection.gameObjects[i]) == null + && PrefabUtility.GetPrefabObject(Selection.gameObjects[i].transform) != null) + { + continue; + } - PrimitiveBrush primitiveBrush = Selection.gameObjects[i].GetComponent(); - CSGModel csgModel = Selection.gameObjects[i].GetComponent(); + PrimitiveBrush primitiveBrush = Selection.gameObjects[i].GetComponent(); + CSGModel csgModel = Selection.gameObjects[i].GetComponent(); - if(csgModel == null) + if (csgModel == null) { // Something other than a CSG Model has been selected onlyCSGModelsSelected = false; } - if(primitiveBrush != null) - { - csgModel = primitiveBrush.GetCSGModel() as CSGModel; + if (primitiveBrush != null) + { + csgModel = primitiveBrush.GetCSGModel() as CSGModel; - if(csgModel != null) - { - if(!foundModels.Contains(csgModel)) - { - foundModels.Add(csgModel); - selectedBrushes[csgModel] = new List(); - } + if (csgModel != null) + { + if (!foundModels.Contains(csgModel)) + { + foundModels.Add(csgModel); + selectedBrushes[csgModel] = new List(); + } - selectedBrushes[csgModel].Add(primitiveBrush.gameObject); - } - } + selectedBrushes[csgModel].Add(primitiveBrush.gameObject); + } + } - if(csgModel != null) // If a CSG Model is selected, or a brush has told us about its parent CSG Model - { - anyCSGObjectsSelected = true; + if (csgModel != null) // If a CSG Model is selected, or a brush has told us about its parent CSG Model + { + anyCSGObjectsSelected = true; - if(!foundModels.Contains(csgModel)) - { - foundModels.Add(csgModel); - selectedBrushes[csgModel] = new List(); - } - } - else // None found, try recursing up to find a CSG Model - { - CSGModel[] parentCSGModels = Selection.gameObjects[i].GetComponentsInParent(true); - if(parentCSGModels.Length > 0) - { - csgModel = parentCSGModels[0]; - - if(Selection.gameObjects[i].GetComponent() != null - || Selection.gameObjects[i].GetComponent() != null) - { - anyNonCSGSelected = true; - } - else - { - anyCSGObjectsSelected = true; - - if(!foundModels.Contains(csgModel)) - { - foundModels.Add(csgModel); - selectedBrushes[csgModel] = new List(); - } - } - } - else - { - anyNonCSGSelected = true; - } - } - } + if (!foundModels.Contains(csgModel)) + { + foundModels.Add(csgModel); + selectedBrushes[csgModel] = new List(); + } + } + else // None found, try recursing up to find a CSG Model + { + CSGModel[] parentCSGModels = Selection.gameObjects[i].GetComponentsInParent(true); + if (parentCSGModels.Length > 0) + { + csgModel = parentCSGModels[0]; - if(anyCSGObjectsSelected) - { - CSGModel activeModel = null; - if(foundModels.Count == 1) - { - if(!foundModels[0].EditMode) - { - foundModels[0].EditMode = true; - } - activeModel = foundModels[0]; - } - else - { - bool anyActive = false; + if (Selection.gameObjects[i].GetComponent() != null + || Selection.gameObjects[i].GetComponent() != null) + { + anyNonCSGSelected = true; + } + else + { + anyCSGObjectsSelected = true; - for (int i = 0; i < foundModels.Count; i++) - { - if(foundModels[i].EditMode) - { - anyActive = true; - activeModel = foundModels[i]; - break; - } - } + if (!foundModels.Contains(csgModel)) + { + foundModels.Add(csgModel); + selectedBrushes[csgModel] = new List(); + } + } + } + else + { + anyNonCSGSelected = true; + } + } + } - if(!anyActive) - { - foundModels[0].EditMode = true; - activeModel = foundModels[0]; - } - } + if (anyCSGObjectsSelected) + { + CSGModel activeModel = null; + if (foundModels.Count == 1) + { + if (!foundModels[0].EditMode) + { + foundModels[0].EditMode = true; + } + activeModel = foundModels[0]; + } + else + { + bool anyActive = false; - if(anyNonCSGSelected && activeModel != null) - { - deferredSelection = selectedBrushes[activeModel].ToArray(); - } + for (int i = 0; i < foundModels.Count; i++) + { + if (foundModels[i].EditMode) + { + anyActive = true; + activeModel = foundModels[i]; + break; + } + } + + if (!anyActive) + { + foundModels[0].EditMode = true; + activeModel = foundModels[0]; + } + } + + if (anyNonCSGSelected && activeModel != null) + { + deferredSelection = selectedBrushes[activeModel].ToArray(); + } if (this != null && this.EditMode) // Current model can be destroyed { @@ -1054,98 +1102,100 @@ void OnSelectionChanged() { SetOverrideMode(OverrideMode.None); } - } + } } - } - else if(anyNonCSGSelected) - { - EditMode = false; - } + } + else if (anyNonCSGSelected) + { + EditMode = false; + } + if (EditMode) + { + // Walk backwards until we find the last selected brush + for (int i = Selection.gameObjects.Length - 1; i >= 0; i--) + { + Brush brush = Selection.gameObjects[i].GetComponent(); - if(EditMode) - { - // Walk backwards until we find the last selected brush - for (int i = Selection.gameObjects.Length-1; i >= 0; i--) - { - Brush brush = Selection.gameObjects[i].GetComponent(); + if (brush != null) + { + lastSelectedBrush = brush; + break; + } + } + } + } - if(brush != null) - { - lastSelectedBrush = brush; - break; - } - } - } - } #endif - public void SetLastSelectedBrush(Brush brush) - { - lastSelectedBrush = brush; - } - - void OnHierarchyItemGUI(int instanceID, Rect drawRect) - { - if(Event.current.type == EventType.ExecuteCommand) - { - if(Event.current.commandName == "Duplicate") - { - if(EditorHelper.DuplicateSelection()) - { - Event.current.Use(); - } - } - } - - GameObject gameObject = EditorUtility.InstanceIDToObject (instanceID) as GameObject; + public void SetLastSelectedBrush(Brush brush) + { + lastSelectedBrush = brush; + } - if(Event.current.type == EventType.DragPerform) - { - if(drawRect.Contains(Event.current.mousePosition)) - { - if(gameObject != null) - { - OnDragDrop(gameObject); - } - } - } + private void OnHierarchyItemGUI(int instanceID, Rect drawRect) + { + if (Event.current.type == EventType.ExecuteCommand) + { + if (Event.current.commandName == "Duplicate") + { + if (EditorHelper.DuplicateSelection()) + { + Event.current.Use(); + } + } + } + GameObject gameObject = EditorUtility.InstanceIDToObject(instanceID) as GameObject; - if(gameObject != null) - { - BrushBase brushBase = gameObject.GetComponent(); - if(brushBase != null) - { - drawRect.xMax -= 2; - drawRect.xMin = drawRect.xMax - 16; - drawRect.height = 16; + if (Event.current.type == EventType.DragPerform) + { + if (drawRect.Contains(Event.current.mousePosition)) + { + if (gameObject != null) + { + OnDragDrop(gameObject); + } + } + } - Material iconMaterial = null; - // Read only brushes have a greyscale icon - if(brushBase is PrimitiveBrush) - { - if(((PrimitiveBrush)brushBase).IsReadOnly) - { - iconMaterial = SabreCSGResources.GetGreyscaleUIMaterial(); - } - } - if(brushBase.IsNoCSG) - { - Graphics.DrawTexture(drawRect, SabreCSGResources.NoCSGIconTexture, iconMaterial); - } - else if(brushBase.Mode == CSGMode.Add) - { - Graphics.DrawTexture(drawRect, SabreCSGResources.AddIconTexture, iconMaterial); - } - else - { - Graphics.DrawTexture(drawRect, SabreCSGResources.SubtractIconTexture, iconMaterial); - } - } + if (gameObject != null) + { + BrushBase brushBase = gameObject.GetComponent(); + if (brushBase != null) + { + drawRect.xMax -= 2; + drawRect.xMin = drawRect.xMax - 16; + drawRect.height = 16; + Material iconMaterial = null; + // Read only brushes have a greyscale icon + if (brushBase is PrimitiveBrush) + { + if (((PrimitiveBrush)brushBase).IsReadOnly) + { + iconMaterial = SabreCSGResources.GetGreyscaleUIMaterial(); + } + } + if (gameObject.GetComponent()) + { + Graphics.DrawTexture(drawRect, SabreCSGResources.GroupIconTexture, iconMaterial); + } + else if (brushBase.IsNoCSG) + { + Graphics.DrawTexture(drawRect, SabreCSGResources.NoCSGIconTexture, iconMaterial); + } + else if (brushBase.Mode == CSGMode.Add) + { + Graphics.DrawTexture(drawRect, SabreCSGResources.AddIconTexture, iconMaterial); + } + else + { + Graphics.DrawTexture(drawRect, SabreCSGResources.SubtractIconTexture, iconMaterial); + } + } - if(EditMode) + if (EditMode) { Event e = Event.current; @@ -1154,159 +1204,161 @@ void OnHierarchyItemGUI(int instanceID, Rect drawRect) OnGenericKeyAction(null, e); } } - } - } + } + } - int frameIndex; - void OnEditorUpdate () - { - if(deferredSelection != null) - { - Selection.objects = deferredSelection; - deferredSelection = null; - SceneView.RepaintAll(); - EditorApplication.RepaintHierarchyWindow(); - } + private int frameIndex; - if(EditMode) - { - frameIndex++; - if(frameIndex > 1000) - { - frameIndex -= 1000; - } + private void OnEditorUpdate() + { + if (deferredSelection != null) + { + Selection.objects = deferredSelection; + deferredSelection = null; + SceneView.RepaintAll(); + EditorApplication.RepaintHierarchyWindow(); + } - if(AutoRebuild && gameObject.activeInHierarchy && this.enabled) - { -// if(frameIndex % 30 == 0) - { - Build(false, false); - } - } + if (EditMode) + { + frameIndex++; + if (frameIndex > 1000) + { + frameIndex -= 1000; + } - if(CurrentSettings.OverrideFlyCamera) - { - LinearFPSCam.OnUpdate(); - } - } + if (AutoRebuild && gameObject.activeInHierarchy && this.enabled) + { + // if(frameIndex % 30 == 0) + { + Build(false, false); + } + } - if(!Application.isPlaying) - { - bool buildOccurred = CSGFactory.Tick(); - if(buildOccurred) - { - OnBuildComplete(); - } - } - } + if (CurrentSettings.OverrideFlyCamera) + { + LinearFPSCam.OnUpdate(); + } + } - protected override void Update() - { - if(editMode && !anyCSGModelsInEditMode) - { - anyCSGModelsInEditMode = true; + if (!Application.isPlaying) + { + bool buildOccurred = CSGFactory.Tick(); + if (buildOccurred) + { + OnBuildComplete(); + } + } + } + + protected override void Update() + { + if (editMode && !anyCSGModelsInEditMode) + { + anyCSGModelsInEditMode = true; UpdateAllBrushesVisibility(); - } - - base.Update(); + } - // Make sure the events we need to listen for are all bound (recompilation removes listeners, so it is - // necessary to rebind dynamically) - if(!EditorHelper.SceneViewHasDelegate(OnSceneGUI)) - { - // Then resubscribe and repaint - SceneView.onSceneGUIDelegate += OnSceneGUI; - SceneView.RepaintAll(); - } + base.Update(); + + // Make sure the events we need to listen for are all bound (recompilation removes listeners, so it is + // necessary to rebind dynamically) + if (!EditorHelper.SceneViewHasDelegate(OnSceneGUI)) + { + // Then resubscribe and repaint + SceneView.onSceneGUIDelegate += OnSceneGUI; + SceneView.RepaintAll(); + } #if !(UNITY_5_0 || UNITY_5_1) - if(!EditorHelper.HasDelegate(Selection.selectionChanged, (Action)OnSelectionChanged)) - { - Selection.selectionChanged += OnSelectionChanged; - } + if (!EditorHelper.HasDelegate(Selection.selectionChanged, (Action)OnSelectionChanged)) + { + Selection.selectionChanged += OnSelectionChanged; + // When we come out of play mode we lose this event handler and are no longer in edit mode. + // We call OnSelectionChanged() manually to make sure we go back into edit mode, if a brush is still selected. + OnSelectionChanged(); + } #endif - if(!EditorHelper.HasDelegate(EditorApplication.hierarchyWindowItemOnGUI, (EditorApplication.HierarchyWindowItemCallback)OnHierarchyItemGUI)) - { - EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyItemGUI; - } - - if (EditMode) - { - if(!EditorHelper.HasDelegate(EditorApplication.projectWindowItemOnGUI, (EditorApplication.ProjectWindowItemCallback)OnProjectItemGUI)) - { - EditorApplication.projectWindowItemOnGUI += OnProjectItemGUI; - } - - - if(!EditorHelper.HasDelegate(EditorApplication.update, (EditorApplication.CallbackFunction)OnEditorUpdate)) - { - EditorApplication.update += OnEditorUpdate; - } - - if(!EditorHelper.HasDelegate(Undo.undoRedoPerformed, (Undo.UndoRedoCallback)OnUndoRedoPerformed)) - { - Undo.undoRedoPerformed += OnUndoRedoPerformed; - } + if (!EditorHelper.HasDelegate(EditorApplication.hierarchyWindowItemOnGUI, (EditorApplication.HierarchyWindowItemCallback)OnHierarchyItemGUI)) + { + EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyItemGUI; + } - // Track whether all the brushes have been destroyed - bool anyBrushes = false; + if (EditMode) + { + if (!EditorHelper.HasDelegate(EditorApplication.projectWindowItemOnGUI, (EditorApplication.ProjectWindowItemCallback)OnProjectItemGUI)) + { + EditorApplication.projectWindowItemOnGUI += OnProjectItemGUI; + } - if(brushes != null) - { - for (int i = 0; i < brushes.Count; i++) - { - if(brushes[i] != null) - { - anyBrushes = true; - break; - } - } - } + if (!EditorHelper.HasDelegate(EditorApplication.update, (EditorApplication.CallbackFunction)OnEditorUpdate)) + { + EditorApplication.update += OnEditorUpdate; + } - Toolbar.WarningMessage = ""; - Brush firstBrush = GetComponentInChildren(); - if(firstBrush != null) - { - if(firstBrush.Mode == CSGMode.Subtract) - { - Toolbar.WarningMessage = "First brush must be additive"; - } - // anyBrushes = true; - } + if (!EditorHelper.HasDelegate(Undo.undoRedoPerformed, (Undo.UndoRedoCallback)OnUndoRedoPerformed)) + { + Undo.undoRedoPerformed += OnUndoRedoPerformed; + } - // All the brushes have been destroyed so add a default cube brush - if(!Application.isPlaying && !anyBrushes) - { - // Create the default brush - //GameObject newBrushObject = CreateBrush(PrimitiveBrushType.Cube, new Vector3(0,1,0)); - //// Set the selection to the new object - //Selection.activeGameObject = newBrushObject; - } - } - } + // Track whether all the brushes have been destroyed + bool anyBrushes = false; + if (brushes != null) + { + for (int i = 0; i < brushes.Count; i++) + { + if (brushes[i] != null) + { + anyBrushes = true; + break; + } + } + } - void OnDestroy() - { - EditorApplication.update -= OnEditorUpdate; - EditorApplication.hierarchyWindowItemOnGUI -= OnHierarchyItemGUI; - EditorApplication.projectWindowItemOnGUI -= OnProjectItemGUI; - SceneView.onSceneGUIDelegate -= OnSceneGUI; - Undo.undoRedoPerformed -= OnUndoRedoPerformed; + Toolbar.WarningMessage = ""; + Brush firstBrush = GetComponentInChildren(); + if (firstBrush != null) + { + if (firstBrush.Mode == CSGMode.Subtract) + { + Toolbar.WarningMessage = "First brush must be additive"; + } + // anyBrushes = true; + } - GridManager.UpdateGrid(); - } + // All the brushes have been destroyed so add a default cube brush + if (!Application.isPlaying && !anyBrushes) + { + // Create the default brush + //GameObject newBrushObject = CreateBrush(PrimitiveBrushType.Cube, new Vector3(0,1,0)); + //// Set the selection to the new object + //Selection.activeGameObject = newBrushObject; + } + } + } - public void RebindToOnSceneGUI() - { - // Unbind the delegate, then rebind to ensure our method gets called last - SceneView.onSceneGUIDelegate -= OnSceneGUI; - SceneView.onSceneGUIDelegate += OnSceneGUI; - } + private void OnDestroy() + { + EditorApplication.update -= OnEditorUpdate; + EditorApplication.hierarchyWindowItemOnGUI -= OnHierarchyItemGUI; + EditorApplication.projectWindowItemOnGUI -= OnProjectItemGUI; + SceneView.onSceneGUIDelegate -= OnSceneGUI; + Undo.undoRedoPerformed -= OnUndoRedoPerformed; - public void ExportOBJ (bool limitToSelection) - { + GridManager.UpdateGrid(); + } + + public void RebindToOnSceneGUI() + { + // Unbind the delegate, then rebind to ensure our method gets called last + SceneView.onSceneGUIDelegate -= OnSceneGUI; + SceneView.onSceneGUIDelegate += OnSceneGUI; + } + + public void ExportOBJ(bool limitToSelection) + { List polygonsToExport = new List(); if (limitToSelection) @@ -1328,7 +1380,7 @@ public void ExportOBJ (bool limitToSelection) } } - if(polygonsToExport.Count > 0) + if (polygonsToExport.Count > 0) { string path = EditorUtility.SaveFilePanel("Save Geometry As OBJ", "Assets", this.name + ".obj", "obj"); if (!string.IsNullOrEmpty(path)) @@ -1352,44 +1404,44 @@ public void ExportOBJ (bool limitToSelection) } public static string GetSabreCSGPath() - { - // Find all the scripts with CSGModel in their name - string[] guids = AssetDatabase.FindAssets("CSGModel t:Script"); + { + // Find all the scripts with CSGModel in their name + string[] guids = AssetDatabase.FindAssets("CSGModel t:Script"); - foreach (string guid in guids) - { - // Find the path of the file - string path = AssetDatabase.GUIDToAssetPath(guid); + foreach (string guid in guids) + { + // Find the path of the file + string path = AssetDatabase.GUIDToAssetPath(guid); - string suffix = "Scripts/CSGModel.cs"; - // If it is the target file, i.e. CSGModel.cs not CSGModelInspector - if(path.EndsWith(suffix)) - { - // Remove the suffix, to get for example Assets/SabreCSG - path = path.Remove(path.Length-suffix.Length, suffix.Length); + string suffix = "Scripts/CSGModel.cs"; + // If it is the target file, i.e. CSGModel.cs not CSGModelInspector + if (path.EndsWith(suffix)) + { + // Remove the suffix, to get for example Assets/SabreCSG + path = path.Remove(path.Length - suffix.Length, suffix.Length); - return path; - } - } + return path; + } + } - // None matched - return string.Empty; - } + // None matched + return string.Empty; + } - /// - /// Marks the Build Context associated with this CSG Model as changed - /// - public void SetContextDirty() - { - EditorHelper.SetDirty(buildContextBehaviour); - } + /// + /// Marks the Build Context associated with this CSG Model as changed + /// + public void SetContextDirty() + { + EditorHelper.SetDirty(buildContextBehaviour); + } - public void UndoRecordContext(string name) - { - Undo.RecordObject(buildContextBehaviour, name); - } + public void UndoRecordContext(string name) + { + Undo.RecordObject(buildContextBehaviour, name); + } - Tool GetActiveTool() + private Tool GetActiveTool() { if (CurrentSettings.OverrideMode != OverrideMode.None) { @@ -1401,158 +1453,154 @@ Tool GetActiveTool() } } - private void UpdateActiveTool() - { - Tool lastTool = activeTool; + private void UpdateActiveTool() + { + Tool lastTool = activeTool; activeTool = GetActiveTool(); - if(activeTool != lastTool) - { - if(lastTool != null) - { - lastTool.Deactivated(); - } - activeTool.ResetTool(); - } + if (activeTool != lastTool) + { + if (lastTool != null) + { + lastTool.Deactivated(); + } + activeTool.ResetTool(); + } UpdateAllBrushesVisibility(); } - public Tool GetTool(MainMode mode) - { - return tools[mode]; - } + public Tool GetTool(MainMode mode) + { + return tools[mode]; + } - public void SetCurrentMode(MainMode newMode) - { - if(CurrentSettings.OverrideMode == OverrideMode.TransformModel) + public void SetCurrentMode(MainMode newMode) + { + if (CurrentSettings.OverrideMode == OverrideMode.TransformModel) { - // If we're leaving TransformModel + // If we're leaving TransformModel bool onlyModelsSelected = true; for (int i = 0; i < Selection.gameObjects.Length; i++) { - if(Selection.gameObjects[i].GetComponent() == null) + if (Selection.gameObjects[i].GetComponent() == null) { onlyModelsSelected = false; break; } } // Deselect if only CSG Models are selected - if(onlyModelsSelected) + if (onlyModelsSelected) { Selection.activeGameObject = null; } } - CurrentSettings.OverrideMode = OverrideMode.None; + CurrentSettings.OverrideMode = OverrideMode.None; - CurrentSettings.CurrentMode = newMode; + CurrentSettings.CurrentMode = newMode; - UpdateActiveTool(); - } + UpdateActiveTool(); + } - public void SetOverrideMode(OverrideMode newMode) - { - CurrentSettings.OverrideMode = newMode; + public void SetOverrideMode(OverrideMode newMode) + { + CurrentSettings.OverrideMode = newMode; - UpdateActiveTool(); - } + UpdateActiveTool(); + } - public void ExitOverrideMode() - { - CurrentSettings.OverrideMode = OverrideMode.None; + public void ExitOverrideMode() + { + CurrentSettings.OverrideMode = OverrideMode.None; - UpdateActiveTool(); - } + UpdateActiveTool(); + } - public bool EditMode - { - get - { - return this.editMode; - } - set - { - // Has edit mode changed - if (editMode != value) - { - editMode = value; + public bool EditMode + { + get + { + return this.editMode; + } + set + { + // Has edit mode changed + if (editMode != value) + { + editMode = value; editModeModel = this; CSGModel[] csgModels = Resources.FindObjectsOfTypeAll(); - if (value == true) // Edit mode enabled - { - // If there are any other CSG Models in the scene, disabling their editing - if(csgModels.Length > 1) - { - for (int i = 0; i < csgModels.Length; i++) - { - if(csgModels[i] != this) - { - csgModels[i].EditMode = false; - } - } - } + if (value == true) // Edit mode enabled + { + // If there are any other CSG Models in the scene, disabling their editing + if (csgModels.Length > 1) + { + for (int i = 0; i < csgModels.Length; i++) + { + if (csgModels[i] != this) + { + csgModels[i].EditMode = false; + } + } + } - // This CSG Model is now in edit mode, so we know for sure one is - anyCSGModelsInEditMode = true; + // This CSG Model is now in edit mode, so we know for sure one is + anyCSGModelsInEditMode = true; - // Bind listeners - EditorApplication.update += OnEditorUpdate; + // Bind listeners + EditorApplication.update += OnEditorUpdate; - // Force the scene views to repaint (shows our own UI) - SceneView.RepaintAll(); + // Force the scene views to repaint (shows our own UI) + SceneView.RepaintAll(); - // if(Event.current != null) - // { - // Event.current.Use(); - // } + // if(Event.current != null) + // { + // Event.current.Use(); + // } - // SceneView.onSceneGUIDelegate += OnSceneGUI; + // SceneView.onSceneGUIDelegate += OnSceneGUI; + } + else // Edit mode disabled + { + // Unbind listeners + EditorApplication.update -= OnEditorUpdate; + // SceneView.onSceneGUIDelegate -= OnSceneGUI; - } - else // Edit mode disabled - { - // Unbind listeners - EditorApplication.update -= OnEditorUpdate; - - // SceneView.onSceneGUIDelegate -= OnSceneGUI; - - // Force the scene views to repaint (hides our own UI) - SceneView.RepaintAll(); - // HandleUtility.Repaint(); - - // This CSG Model is no longer in edit mode, so find out if any are - anyCSGModelsInEditMode = false; - if(csgModels.Length > 1) - { - for (int i = 0; i < csgModels.Length; i++) - { - if(csgModels[i] != this - && csgModels[i].EditMode) - { + // Force the scene views to repaint (hides our own UI) + SceneView.RepaintAll(); + // HandleUtility.Repaint(); + + // This CSG Model is no longer in edit mode, so find out if any are + anyCSGModelsInEditMode = false; + if (csgModels.Length > 1) + { + for (int i = 0; i < csgModels.Length; i++) + { + if (csgModels[i] != this + && csgModels[i].EditMode) + { editModeModel = csgModels[i]; - anyCSGModelsInEditMode = true; - } - } - } - } + anyCSGModelsInEditMode = true; + } + } + } + } UpdateAllBrushesVisibility(); - GridManager.UpdateGrid(); - } - } - } - - + GridManager.UpdateGrid(); + } + } + } - void OnProjectItemGUI (string guid, Rect selectionRect) - { - // Debug.Log(Event.current.type.ToString()); - /* + private void OnProjectItemGUI(string guid, Rect selectionRect) + { + // Debug.Log(Event.current.type.ToString()); + /* if (Event.current.type == EventType.MouseDrag) { if(selectionRect.Contains(Event.current.mousePosition)) @@ -1565,89 +1613,91 @@ void OnProjectItemGUI (string guid, Rect selectionRect) DragAndDrop.paths = new string[] { path }; DragAndDrop.StartDrag ("Dragging material"); - + // Make sure no one else uses this event Event.current.Use(); } } } */ - } + } - void OnDragDrop(GameObject gameObject) - { - // PrimitiveBrush brush = gameObject.GetComponent(); - // - // if(brush != null) - // { - // if(DragAndDrop.objectReferences.Length == 1) - // { - // if(DragAndDrop.objectReferences[0] is Material) - // { - // brush.Material = (Material)DragAndDrop.objectReferences[0]; - // DragAndDrop.AcceptDrag(); - // Event.current.Use(); - // } - // } - // } - } + private void OnDragDrop(GameObject gameObject) + { + // PrimitiveBrush brush = gameObject.GetComponent(); + // + // if(brush != null) + // { + // if(DragAndDrop.objectReferences.Length == 1) + // { + // if(DragAndDrop.objectReferences[0] is Material) + // { + // brush.Material = (Material)DragAndDrop.objectReferences[0]; + // DragAndDrop.AcceptDrag(); + // Event.current.Use(); + // } + // } + // } + } - private void OnUndoRedoPerformed() - { - // An undo or redo operation may restore a brush, so make sure we track all - brushes = new List(transform.GetComponentsInChildren(false)); + private void OnUndoRedoPerformed() + { + // An undo or redo operation may restore a brush, so make sure we track all + brushes = new List(transform.GetComponentsInChildren(false)); - BrushBase[] brushBases = transform.GetComponentsInChildren(false); + BrushBase[] brushBases = transform.GetComponentsInChildren(false); - // Tell each brush base that an undo/redo has been performed so it can make sure the render mesh is updated - for (int i = 0; i < brushBases.Length; i++) - { - if(brushBases[i] != null) - { - brushBases[i].OnUndoRedoPerformed(); - } - } + // Tell each brush base that an undo/redo has been performed so it can make sure the render mesh is updated + for (int i = 0; i < brushBases.Length; i++) + { + if (brushBases[i] != null) + { + brushBases[i].OnUndoRedoPerformed(); + } + } - activeTool.OnUndoRedoPerformed(); + activeTool.OnUndoRedoPerformed(); - // If the user undos or redos a face change then a shared mesh may be updated. - // Unity won't automatically refresh the mesh filters that use a shared mesh, so we need to force refresh - // all of them so they fetch the latest revision of the mesh - Transform meshGroup = GetMeshGroupTransform(); + // If the user undos or redos a face change then a shared mesh may be updated. + // Unity won't automatically refresh the mesh filters that use a shared mesh, so we need to force refresh + // all of them so they fetch the latest revision of the mesh + Transform meshGroup = GetMeshGroupTransform(); - if(meshGroup != null) - { - MeshFilter[] meshFilters = meshGroup.GetComponentsInChildren(); - for (int i = 0; i < meshFilters.Length; i++) - { - meshFilters[i].ForceRefreshSharedMesh(); - } - } + if (meshGroup != null) + { + MeshFilter[] meshFilters = meshGroup.GetComponentsInChildren(); + for (int i = 0; i < meshFilters.Length; i++) + { + meshFilters[i].ForceRefreshSharedMesh(); + } + } - EditorApplication.RepaintHierarchyWindow(); - } + EditorApplication.RepaintHierarchyWindow(); + } - public override bool AreBrushesVisible { - get { - if(!Application.isPlaying) - { + public override bool AreBrushesVisible + { + get + { + if (!Application.isPlaying) + { return CurrentSettings.BrushesVisible - && anyCSGModelsInEditMode - && editModeModel != null + && anyCSGModelsInEditMode + && editModeModel != null && (editModeModel.activeTool == null || editModeModel.activeTool.BrushesHandleDrawing); - } - return base.AreBrushesVisible; - } - } + } + return base.AreBrushesVisible; + } + } public static void UpdateAllBrushesVisibility() { CSGModel[] csgModels = Resources.FindObjectsOfTypeAll(); - for (int i = 0; i < csgModels.Length; i++) + for (int i = 0; i < csgModels.Length; i++) { Transform meshGroup = csgModels[i].transform.Find("MeshGroup"); - if(meshGroup != null) + if (meshGroup != null) { meshGroup.gameObject.SetActive(!CurrentSettings.MeshHidden); } @@ -1663,244 +1713,238 @@ public static void UpdateAllBrushesVisibility() } } + public override Material GetDefaultFallbackMaterial() + { + if (!Application.isPlaying) + { + // To allow users to move the SabreCSG folder, we must base the material loading on the asset path + return AssetDatabase.LoadMainAssetAtPath(GetSabreCSGPath() + "Resources/" + DEFAULT_FALLBACK_MATERIAL_PATH + ".mat") as Material; + } + else + { + return base.GetDefaultFallbackMaterial(); + } + } + public override void OnBuildProgressChanged(float progress) + { + base.OnBuildProgressChanged(progress); - public override Material GetDefaultFallbackMaterial () - { - if(!Application.isPlaying) - { - // To allow users to move the SabreCSG folder, we must base the material loading on the asset path - return AssetDatabase.LoadMainAssetAtPath(GetSabreCSGPath() + "Resources/" + DEFAULT_FALLBACK_MATERIAL_PATH + ".mat") as Material; - } - else - { - return base.GetDefaultFallbackMaterial (); - } - } - - public override void OnBuildProgressChanged (float progress) - { - base.OnBuildProgressChanged (progress); - - EditorUtility.DisplayProgressBar("Building", "Building geometry from brushes", progress); - } - - private void BreakMeshTest(Mesh mesh) - { - Vector3[] vertices = new Vector3[mesh.triangles.Length]; - Vector3[] normals = new Vector3[mesh.triangles.Length]; - Color32[] colors32 = new Color32[mesh.triangles.Length]; - Vector2[] uvs = new Vector2[mesh.triangles.Length]; - Vector4[] tangents = new Vector4[mesh.triangles.Length]; - int[] triangles = new int[mesh.triangles.Length]; - for (int i = 0; i < mesh.triangles.Length; i++) - { - int oldIndex = mesh.triangles[i]; - vertices[i] = mesh.vertices[oldIndex]; - normals[i] = mesh.normals[oldIndex]; - colors32[i] = mesh.colors32[oldIndex]; - uvs[i] = mesh.uv[oldIndex]; - tangents[i] = mesh.tangents[oldIndex]; - triangles[i] = i; - } - mesh.vertices = vertices; - mesh.normals = normals; - mesh.colors32 = colors32; - mesh.uv = uvs; - mesh.tangents = tangents; - mesh.triangles = triangles; - } - - public override void OnFinalizeVisualMesh (GameObject newGameObject, Mesh mesh) - { - base.OnFinalizeVisualMesh (newGameObject, mesh); - - if (buildSettings.GenerateLightmapUVs) - { -// BreakMeshTest(mesh); + EditorUtility.DisplayProgressBar("Building", "Building geometry from brushes", progress); + } - // Create a copy of the mesh, which we can then unwrap - Mesh meshCopy = new Mesh(); + private void BreakMeshTest(Mesh mesh) + { + Vector3[] vertices = new Vector3[mesh.triangles.Length]; + Vector3[] normals = new Vector3[mesh.triangles.Length]; + Color32[] colors32 = new Color32[mesh.triangles.Length]; + Vector2[] uvs = new Vector2[mesh.triangles.Length]; + Vector4[] tangents = new Vector4[mesh.triangles.Length]; + int[] triangles = new int[mesh.triangles.Length]; + for (int i = 0; i < mesh.triangles.Length; i++) + { + int oldIndex = mesh.triangles[i]; + vertices[i] = mesh.vertices[oldIndex]; + normals[i] = mesh.normals[oldIndex]; + colors32[i] = mesh.colors32[oldIndex]; + uvs[i] = mesh.uv[oldIndex]; + tangents[i] = mesh.tangents[oldIndex]; + triangles[i] = i; + } + mesh.vertices = vertices; + mesh.normals = normals; + mesh.colors32 = colors32; + mesh.uv = uvs; + mesh.tangents = tangents; + mesh.triangles = triangles; + } - meshCopy.vertices = mesh.vertices; - meshCopy.normals = mesh.normals; - meshCopy.colors32 = mesh.colors32; - meshCopy.uv = mesh.uv; - meshCopy.tangents = mesh.tangents; - meshCopy.triangles = mesh.triangles; + public override void OnFinalizeVisualMesh(GameObject newGameObject, Mesh mesh) + { + base.OnFinalizeVisualMesh(newGameObject, mesh); - // Vector2[] perTriangleUVs = UnityEditor.Unwrapping.GeneratePerTriangleUV(meshCopy); + if (buildSettings.GenerateLightmapUVs) + { + // BreakMeshTest(mesh); - UnityEditor.UnwrapParam unwrapParameters = new UnityEditor.UnwrapParam() - { - angleError = buildSettings.UnwrapAngleError, - areaError = buildSettings.UnwrapAreaError, - hardAngle = buildSettings.UnwrapHardAngle, - packMargin = buildSettings.UnwrapPackMargin, - }; + // Create a copy of the mesh, which we can then unwrap + Mesh meshCopy = new Mesh(); - // Unwrap the mesh copy, note that this also changes the vertex buffer, which is why we do it on a copy - UnityEditor.Unwrapping.GenerateSecondaryUVSet(meshCopy, unwrapParameters); + meshCopy.vertices = mesh.vertices; + meshCopy.normals = mesh.normals; + meshCopy.colors32 = mesh.colors32; + meshCopy.uv = mesh.uv; + meshCopy.tangents = mesh.tangents; + meshCopy.triangles = mesh.triangles; - // Now transfer the unwrapped UVs to the original mesh, since the two vertex counts differ - Vector2[] uv2 = new Vector2[mesh.vertices.Length]; + // Vector2[] perTriangleUVs = UnityEditor.Unwrapping.GeneratePerTriangleUV(meshCopy); - if(meshCopy.triangles.Length == mesh.triangles.Length) - { -// VisualDebug.ClearAll(); -// for (int i = 0; i < meshCopy.triangles.Length/3; i++) -// { -// int index1 = meshCopy.triangles[i*3 + 0]; -// int index2 = meshCopy.triangles[i*3 + 1]; -// int index3 = meshCopy.triangles[i*3 + 2]; -//// if(index1 == index2 || index2 == index3 || index1 == index3) -//// { -//// Debug.LogError("Degen found"); -//// } -// VisualDebug.AddLinePolygon(new Vector3[]{ -// meshCopy.uv2[index1], -// meshCopy.uv2[index2], -// meshCopy.uv2[index3], -// }, Color.white); -// } - - int triangleCount = mesh.triangles.Length; - for (int i = 0; i < triangleCount; i++) - { - int originalIndex = mesh.triangles[i]; - int copyIndex = meshCopy.triangles[i]; - -// if(mesh.vertices[originalIndex] != meshCopy.vertices[copyIndex]) -// { -// Debug.LogError("Vertex mismatch found"); -// } -// -// if(uv2[originalIndex] != Vector2.zero -// && uv2[originalIndex] != meshCopy.uv2[copyIndex]) -// { -// Debug.Log("Overwriting " + uv2[originalIndex] + " with " + meshCopy.uv2[copyIndex]); -// } - uv2[originalIndex] = meshCopy.uv2[copyIndex]; + UnityEditor.UnwrapParam unwrapParameters = new UnityEditor.UnwrapParam() + { + angleError = buildSettings.UnwrapAngleError, + areaError = buildSettings.UnwrapAreaError, + hardAngle = buildSettings.UnwrapHardAngle, + packMargin = buildSettings.UnwrapPackMargin, + }; - } + // Unwrap the mesh copy, note that this also changes the vertex buffer, which is why we do it on a copy + UnityEditor.Unwrapping.GenerateSecondaryUVSet(meshCopy, unwrapParameters); + // Now transfer the unwrapped UVs to the original mesh, since the two vertex counts differ + Vector2[] uv2 = new Vector2[mesh.vertices.Length]; - mesh.uv2 = uv2; - - -// for (int i = 0; i < mesh.triangles.Length/3; i++) -// { -// int index1 = mesh.triangles[i*3 + 0]; -// int index2 = mesh.triangles[i*3 + 1]; -// int index3 = mesh.triangles[i*3 + 2]; -//// if(index1 == index2 || index2 == index3 || index1 == index3) -//// { -//// Debug.LogError("Degen found"); -//// } -// VisualDebug.AddLinePolygon(new Vector3[]{ -// mesh.uv2[index1] + Vector2.right, -// mesh.uv2[index2] + Vector2.right, -// mesh.uv2[index3] + Vector2.right, -// }, Color.blue); -// } -// for (int i = 0; i < uv2.Length/3; i++) -// { -// VisualDebug.AddLinePolygon(new Vector3[]{ -// uv2[i*3 + 0] + Vector2.right, -// uv2[i*3 + 1] + Vector2.right, -// uv2[i*3 + 2] + Vector2.right, -// }, Color.blue); -// } - } - else - { - Debug.LogError("Unwrapped mesh triangle count mismatches source mesh"); - } + if (meshCopy.triangles.Length == mesh.triangles.Length) + { + // VisualDebug.ClearAll(); + // for (int i = 0; i < meshCopy.triangles.Length/3; i++) + // { + // int index1 = meshCopy.triangles[i*3 + 0]; + // int index2 = meshCopy.triangles[i*3 + 1]; + // int index3 = meshCopy.triangles[i*3 + 2]; + //// if(index1 == index2 || index2 == index3 || index1 == index3) + //// { + //// Debug.LogError("Degen found"); + //// } + // VisualDebug.AddLinePolygon(new Vector3[]{ + // meshCopy.uv2[index1], + // meshCopy.uv2[index2], + // meshCopy.uv2[index3], + // }, Color.white); + // } + + int triangleCount = mesh.triangles.Length; + for (int i = 0; i < triangleCount; i++) + { + int originalIndex = mesh.triangles[i]; + int copyIndex = meshCopy.triangles[i]; + + // if(mesh.vertices[originalIndex] != meshCopy.vertices[copyIndex]) + // { + // Debug.LogError("Vertex mismatch found"); + // } + // + // if(uv2[originalIndex] != Vector2.zero + // && uv2[originalIndex] != meshCopy.uv2[copyIndex]) + // { + // Debug.Log("Overwriting " + uv2[originalIndex] + " with " + meshCopy.uv2[copyIndex]); + // } + uv2[originalIndex] = meshCopy.uv2[copyIndex]; + } - // GameObject.DestroyImmediate(meshCopy); - } + mesh.uv2 = uv2; + + // for (int i = 0; i < mesh.triangles.Length/3; i++) + // { + // int index1 = mesh.triangles[i*3 + 0]; + // int index2 = mesh.triangles[i*3 + 1]; + // int index3 = mesh.triangles[i*3 + 2]; + //// if(index1 == index2 || index2 == index3 || index1 == index3) + //// { + //// Debug.LogError("Degen found"); + //// } + // VisualDebug.AddLinePolygon(new Vector3[]{ + // mesh.uv2[index1] + Vector2.right, + // mesh.uv2[index2] + Vector2.right, + // mesh.uv2[index3] + Vector2.right, + // }, Color.blue); + // } + // for (int i = 0; i < uv2.Length/3; i++) + // { + // VisualDebug.AddLinePolygon(new Vector3[]{ + // uv2[i*3 + 0] + Vector2.right, + // uv2[i*3 + 1] + Vector2.right, + // uv2[i*3 + 2] + Vector2.right, + // }, Color.blue); + // } + } + else + { + Debug.LogError("Unwrapped mesh triangle count mismatches source mesh"); + } - // Apply the model layer, tag and appropriate static flags - ApplyModelAttributes(newGameObject, true); - } + // GameObject.DestroyImmediate(meshCopy); + } - public override void OnFinalizeCollisionMesh (GameObject newGameObject, Mesh mesh) - { - base.OnFinalizeCollisionMesh (newGameObject, mesh); + // Apply the model layer, tag and appropriate static flags + ApplyModelAttributes(newGameObject, true); + } - // Apply the model layer, tag and appropriate static flags - ApplyModelAttributes(newGameObject, false); - } + public override void OnFinalizeCollisionMesh(GameObject newGameObject, Mesh mesh) + { + base.OnFinalizeCollisionMesh(newGameObject, mesh); + // Apply the model layer, tag and appropriate static flags + ApplyModelAttributes(newGameObject, false); + } - public Mesh GetMeshForMaterial(Material sourceMaterial, int fitVertices = 0) - { - if(materialMeshDictionary.Contains(sourceMaterial)) - { - List mappings = materialMeshDictionary[sourceMaterial]; + public Mesh GetMeshForMaterial(Material sourceMaterial, int fitVertices = 0) + { + if (materialMeshDictionary.Contains(sourceMaterial)) + { + List mappings = materialMeshDictionary[sourceMaterial]; - Mesh lastMesh = mappings[mappings.Count-1].Mesh; + Mesh lastMesh = mappings[mappings.Count - 1].Mesh; - if(lastMesh.vertices.Length + fitVertices < MESH_VERTEX_LIMIT) - { - return lastMesh; - } - } + if (lastMesh.vertices.Length + fitVertices < MESH_VERTEX_LIMIT) + { + return lastMesh; + } + } - Mesh mesh = new Mesh(); + Mesh mesh = new Mesh(); - materialMeshDictionary.Add(sourceMaterial, mesh, null); + materialMeshDictionary.Add(sourceMaterial, mesh, null); - Material materialToApply = sourceMaterial; - if(sourceMaterial == null) - { - materialToApply = GetDefaultMaterial(); - } + Material materialToApply = sourceMaterial; + if (sourceMaterial == null) + { + materialToApply = GetDefaultMaterial(); + } - GameObject newGameObject = CSGFactory.CreateMaterialMesh(this.transform, materialToApply, mesh); + GameObject newGameObject = CSGFactory.CreateMaterialMesh(this.transform, materialToApply, mesh); - // Apply the model layer, tag and appropriate static flags - ApplyModelAttributes(newGameObject, false); + // Apply the model layer, tag and appropriate static flags + ApplyModelAttributes(newGameObject, false); - return mesh; - } + return mesh; + } - public Mesh GetMeshForCollision(int fitVertices = 0) - { - Mesh lastMesh = collisionMeshDictionary[collisionMeshDictionary.Count-1]; - if(lastMesh.vertices.Length + fitVertices < MESH_VERTEX_LIMIT) - { - return lastMesh; - } + public Mesh GetMeshForCollision(int fitVertices = 0) + { + Mesh lastMesh = collisionMeshDictionary[collisionMeshDictionary.Count - 1]; + if (lastMesh.vertices.Length + fitVertices < MESH_VERTEX_LIMIT) + { + return lastMesh; + } - Mesh mesh = new Mesh(); - collisionMeshDictionary.Add(mesh); - GameObject newGameObject = CSGFactory.CreateCollisionMesh(this.transform, mesh); + Mesh mesh = new Mesh(); + collisionMeshDictionary.Add(mesh); + GameObject newGameObject = CSGFactory.CreateCollisionMesh(this.transform, mesh); - // Apply the model layer, tag and appropriate static flags - ApplyModelAttributes(newGameObject, false); + // Apply the model layer, tag and appropriate static flags + ApplyModelAttributes(newGameObject, false); - return mesh; - } + return mesh; + } - void ApplyModelAttributes(GameObject newGameObject, bool isVisual) - { - // Inherit any static flags from the CSG model - UnityEditor.StaticEditorFlags rootStaticFlags = UnityEditor.GameObjectUtility.GetStaticEditorFlags(this.gameObject); - UnityEditor.GameObjectUtility.SetStaticEditorFlags(newGameObject, rootStaticFlags); + private void ApplyModelAttributes(GameObject newGameObject, bool isVisual) + { + // Inherit any static flags from the CSG model + UnityEditor.StaticEditorFlags rootStaticFlags = UnityEditor.GameObjectUtility.GetStaticEditorFlags(this.gameObject); + UnityEditor.GameObjectUtility.SetStaticEditorFlags(newGameObject, rootStaticFlags); - // Inherit the layer and tag from the CSG model - newGameObject.layer = this.gameObject.layer; - newGameObject.tag = this.gameObject.tag; + // Inherit the layer and tag from the CSG model + newGameObject.layer = this.gameObject.layer; + newGameObject.tag = this.gameObject.tag; - // If the mesh is lightmap UV'd then make sure the object is lightmap static - if(buildSettings.GenerateLightmapUVs) - { - UnityEditor.StaticEditorFlags staticFlags = UnityEditor.GameObjectUtility.GetStaticEditorFlags(newGameObject); - staticFlags |= UnityEditor.StaticEditorFlags.LightmapStatic; - UnityEditor.GameObjectUtility.SetStaticEditorFlags(newGameObject, staticFlags); - } - } + // If the mesh is lightmap UV'd then make sure the object is lightmap static + if (buildSettings.GenerateLightmapUVs) + { + UnityEditor.StaticEditorFlags staticFlags = UnityEditor.GameObjectUtility.GetStaticEditorFlags(newGameObject); + staticFlags |= UnityEditor.StaticEditorFlags.LightmapStatic; + UnityEditor.GameObjectUtility.SetStaticEditorFlags(newGameObject, staticFlags); + } + } public static CSGModel GetActiveCSGModel() { @@ -1919,28 +1963,28 @@ public static CSGModel GetActiveCSGModel() return null; } - static void CleanupForBuild(Transform csgModelTransform) - { - Transform meshGroup = csgModelTransform.Find("MeshGroup"); - if(meshGroup != null) - { - // Reanchor the meshes to the parent of the CSG Model + private static void CleanupForBuild(Transform csgModelTransform) + { + Transform meshGroup = csgModelTransform.Find("MeshGroup"); + if (meshGroup != null) + { + // Reanchor the meshes to the parent of the CSG Model meshGroup.SetParent(csgModelTransform.parent, true); - } + } - // Remove the CSG Model and its brushes - DestroyImmediate (csgModelTransform.gameObject); - } + // Remove the CSG Model and its brushes + DestroyImmediate(csgModelTransform.gameObject); + } - [PostProcessScene(1)] - public static void OnPostProcessScene() - { + [PostProcessScene(1)] + public static void OnPostProcessScene() + { CSGModel[] csgModels = Resources.FindObjectsOfTypeAll(); - for (int i = 0; i < csgModels.Length; i++) - { - CleanupForBuild(csgModels[i].transform); - } - } + for (int i = 0; i < csgModels.Length; i++) + { + CleanupForBuild(csgModels[i].transform); + } + } #if UNITY_EDITOR && (UNITY_5_0 || UNITY_5_1) void OnDrawGizmosSelected() @@ -1951,6 +1995,7 @@ void OnDrawGizmosSelected() } #endif #endif - } + } } + #endif \ No newline at end of file diff --git a/Scripts/CSGModelBase.cs b/Scripts/CSGModelBase.cs index 9ba04c2a..00d4468c 100644 --- a/Scripts/CSGModelBase.cs +++ b/Scripts/CSGModelBase.cs @@ -9,309 +9,342 @@ namespace Sabresaurus.SabreCSG { - /// - /// Base class for CSG Model, can be used on its own for run-time deployed CSG - /// -// [ExecuteInEditMode] - public class CSGModelBase : MonoBehaviour - { - public const string VERSION_STRING = "1.5.1"; - protected const string DEFAULT_FALLBACK_MATERIAL_PATH = "Materials/Default_Map"; - - // Limit to how many vertices a Unity mesh can hold, before it must be split into a second mesh (just under 2^16) - protected const int MESH_VERTEX_LIMIT = 65500; - - [SerializeField,HideInInspector] - protected List brushes = new List(); // Store the sequence of brushes and their operation (e.g. add, subtract) - - [SerializeField,HideInInspector] - protected List builtBrushes = new List(); - - [SerializeField,HideInInspector] - protected MaterialMeshDictionary materialMeshDictionary = new MaterialMeshDictionary(); - - [SerializeField,HideInInspector] - protected List collisionMeshDictionary = new List(); - - // An additional hint to the builder to tell it rebuilding is required - [SerializeField,HideInInspector] - protected bool polygonsRemoved = false; - - [SerializeField,HideInInspector] - protected CSGBuildSettings buildSettings = new CSGBuildSettings(); - - [SerializeField,HideInInspector] - protected CSGBuildSettings lastBuildSettings = new CSGBuildSettings(); - - [NonSerialized] - protected CSGBuildContext buildContextBehaviour; - - // A reference to a component which holds a lot of build time data that helps change built geometry on the fly - // This is used by the surface tools heavily. - [NonSerialized] - protected CSGBuildContext.BuildContext buildContext; - - public CSGBuildContext.BuildContext BuildContext - { - get - { - if(buildContext == null) - { - SetUpBuildContext(); - } - return buildContext; - } - } - - public BuildMetrics BuildMetrics - { - get - { - return BuildContext.buildMetrics; - } - } - - public int BrushCount - { - get - { - int brushCount = 0; - for (int i = 0; i < brushes.Count; i++) - { - if(brushes[i] != null) - { - brushCount++; - } - } - return brushCount; - } - } - - - public PolygonEntry GetVisualPolygonEntry(int index) - { - int entryCount = BuildContext.VisualPolygonIndex.Length; - - if(entryCount == 0 || index >= entryCount || index < 0) - { - // Return null if no polygons have been built or the index is out of range - return null; - } - else - { - return BuildContext.VisualPolygonIndex[index]; - } - } - - public PolygonEntry GetCollisionPolygonEntry(int index) - { - int entryCount = BuildContext.CollisionPolygonIndex.Length; - - if(entryCount == 0 || index >= entryCount || index < 0) - { - // Return null if no polygons have been built or the index is out of range - return null; - } - else - { - return BuildContext.CollisionPolygonIndex[index]; - } - } - - public bool LastBuildHadTangents - { - get - { - return lastBuildSettings.GenerateTangents; - } - } - - /// - /// Get the list of brushes the CSG Model knows about - /// - /// List of brushes. - public List GetBrushes() - { - return brushes; - } - - void Awake() - { - SetUpBuildContext(); - } - - void SetUpBuildContext() - { - // Get a reference to the build context (which holds post build helper data) - buildContextBehaviour = this.AddOrGetComponent(); - buildContext = buildContextBehaviour.GetBuildContext(); - } - - protected virtual void Start() - { - } - - protected virtual void Update() - { - if(Application.isPlaying) - { - bool buildOccurred = CSGFactory.Tick(); - if(buildOccurred) - { - OnBuildComplete(); - } - } - } - - /// - /// Builds the brushes into final meshes - /// - /// If set to true all brushes will be built and cached data ignored, otherwise SabreCSG will only rebuild brushes it knows have changed - /// If set to true the majority of the build will occur in a background thread - public virtual void Build (bool forceRebuild, bool buildInBackground) - { - // If any of the build settings have changed, force all brushes to rebuild - if(!lastBuildSettings.IsBuilt || CSGBuildSettings.AreDifferent(buildSettings, lastBuildSettings)) - { - forceRebuild = true; - } - - // Make sure we have the most accurate list of brushes, ignoring inactive objects - brushes = new List(transform.GetComponentsInChildren(false)); - - // Let each brush know it's about to be built - for (int i = 0; i < brushes.Count; i++) - { - brushes[i].PrepareToBuild(brushes, forceRebuild); - } - - // Perform a check to make sure the default material is OK - Material defaultMaterial = GetDefaultMaterial(); - - if(defaultMaterial == null) - { - Debug.LogError("Default fallback material file is missing, try reimporting SabreCSG"); - } - - BuildStatus buildStatus = CSGFactory.Build(brushes, - buildSettings, - buildContext, - this.transform, - materialMeshDictionary, - collisionMeshDictionary, - polygonsRemoved, - forceRebuild, - OnBuildProgressChanged, - OnFinalizeVisualMesh, - OnFinalizeCollisionMesh, - buildInBackground); - - if(buildStatus == BuildStatus.Complete) - { - OnBuildComplete(); - } - } - - public virtual void OnBuildComplete() - { - polygonsRemoved = false; - - // Mark the brushes that have been built (so we can differentiate later if new brushes are built or not) - builtBrushes.Clear(); - builtBrushes.AddRange(brushes); - - // Copy the last build settings, so that we can make minor changes to built meshes that are consistent - // with how they were built. E.g. maintaining tangents as appropriate - lastBuildSettings = buildSettings.ShallowCopy(); - lastBuildSettings.IsBuilt = true; // Make it clear that the lastBuildSettings refers to a completed build - - // Fire any post process build events - FirePostBuildEvents(); - } - - - void FirePostBuildEvents() - { - Transform meshGroupTransform = GetMeshGroupTransform(); - - // Inform all methods with the PostProcessCSGBuildAttribute that a build just finished - Assembly[] allAssemblies = AppDomain.CurrentDomain.GetAssemblies(); - foreach (Assembly assembly in allAssemblies) - { - if(assembly.FullName.StartsWith("Assembly-CSharp")) - { - Type[] types = assembly.GetTypes(); - - for (int i = 0; i < types.Length; i++) - { - MethodInfo[] methods = types[i].GetMethods(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); - for (int j = 0; j < methods.Length; j++) - { - if(Attribute.IsDefined(methods[j], typeof(PostProcessCSGBuildAttribute))) - { - methods[j].Invoke(null, new object[] { meshGroupTransform } ); - } - } - } - } - } - - // Inform all the scripts implementing IPostBuildListener on this model and inside it that a build finished - IPostBuildListener[] postBuildListeners = this.transform.GetComponentsInChildren(); - - for (int i = 0; i < postBuildListeners.Length; i++) - { - postBuildListeners[i].OnBuildFinished(meshGroupTransform); - } - } - - /// - /// Called to alert the CSG Model that a new brush has been created - /// - public bool TrackBrush(Brush brush) - { - // If we don't already know about the brush, add it - if (!brushes.Contains(brush)) - { - brushes.Add(brush); - return true; - } - else - { - return false; - } - } - - public void OnBrushDisabled(PrimitiveBrush brush) - { - polygonsRemoved = true; - } - - public virtual bool AreBrushesVisible - { - get - { - return false; - } - } - - public Polygon RaycastBuiltPolygons(Ray ray) - { - if(BuildContext.VisualPolygons != null) - { - float distance = 0; - return GeometryHelper.RaycastPolygons(BuildContext.VisualPolygons, ray, out distance); - } - else - { - return null; - } - } + /// + /// Base class for CSG Model, can be used on its own for run-time deployed CSG + /// + // [ExecuteInEditMode] + public class CSGModelBase : MonoBehaviour + { + public const string VERSION_STRING = "1.6.3"; + protected const string DEFAULT_FALLBACK_MATERIAL_PATH = "Materials/Default_Map"; + + // Limit to how many vertices a Unity mesh can hold, before it must be split into a second mesh (just under 2^16) + protected const int MESH_VERTEX_LIMIT = 65500; + + [SerializeField, HideInInspector] + protected List brushes = new List(); // Store the sequence of brushes and their operation (e.g. add, subtract) + + [SerializeField, HideInInspector] + protected List builtBrushes = new List(); + + [SerializeField, HideInInspector] + protected MaterialMeshDictionary materialMeshDictionary = new MaterialMeshDictionary(); + + [SerializeField, HideInInspector] + protected List collisionMeshDictionary = new List(); + + // An additional hint to the builder to tell it rebuilding is required + [SerializeField, HideInInspector] + protected bool polygonsRemoved = false; + + [SerializeField, HideInInspector] + protected CSGBuildSettings buildSettings = new CSGBuildSettings(); + + [SerializeField, HideInInspector] + protected CSGBuildSettings lastBuildSettings = new CSGBuildSettings(); + + [NonSerialized] + protected CSGBuildContext buildContextBehaviour; + + // A reference to a component which holds a lot of build time data that helps change built geometry on the fly + // This is used by the surface tools heavily. + [NonSerialized] + protected CSGBuildContext.BuildContext buildContext; + + public CSGBuildContext.BuildContext BuildContext + { + get + { + if (buildContext == null) + { + SetUpBuildContext(); + } + return buildContext; + } + } + + /// + /// The internal update counter to determine whether a large update is currently happening. + /// This is a hack! It does not fix the underlying cause of a too slow tracking method! + /// + private int updateCounter = 0; + + /// + /// Begin a very large and extreme scene update where you plan to add hundreds of brushes. + /// This will skip several (usually important) methods related to brush tracking until the + /// update has completed to prevent exponential slowdown. + /// This is a hack! It does not fix the underlying cause of a too slow tracking method! + /// + internal void BeginUpdate() + { + updateCounter++; + } + + /// + /// Ends a very large and extreme scene update where several hundred brushes were added to the scene. + /// This is a hack! It does not fix the underlying cause of a too slow tracking method! + /// + internal void EndUpdate() + { + updateCounter--; + if (updateCounter < 0) updateCounter = 0; + // todo: it seems the update call in new primitive brushes tracks them for us. this works with level importers but perhaps not in all cases. + } + + /// + /// Gets a value indicating whether a very large scene update is currently occuring. + /// This is a hack! It does not fix the underlying cause of a too slow tracking method! + /// + /// true if there is a large scene update in progress; otherwise, false. + internal bool IsUpdating { get { return updateCounter > 0; } } + + public BuildMetrics BuildMetrics + { + get + { + return BuildContext.buildMetrics; + } + } + + public int BrushCount + { + get + { + int brushCount = 0; + for (int i = 0; i < brushes.Count; i++) + { + if (brushes[i] != null) + { + brushCount++; + } + } + return brushCount; + } + } + + public PolygonEntry GetVisualPolygonEntry(int index) + { + int entryCount = BuildContext.VisualPolygonIndex.Length; + + if (entryCount == 0 || index >= entryCount || index < 0) + { + // Return null if no polygons have been built or the index is out of range + return null; + } + else + { + return BuildContext.VisualPolygonIndex[index]; + } + } + + public PolygonEntry GetCollisionPolygonEntry(int index) + { + int entryCount = BuildContext.CollisionPolygonIndex.Length; + + if (entryCount == 0 || index >= entryCount || index < 0) + { + // Return null if no polygons have been built or the index is out of range + return null; + } + else + { + return BuildContext.CollisionPolygonIndex[index]; + } + } + + public bool LastBuildHadTangents + { + get + { + return lastBuildSettings.GenerateTangents; + } + } + + /// + /// Get the list of brushes the CSG Model knows about + /// + /// List of brushes. + public List GetBrushes() + { + return brushes; + } + + private void Awake() + { + SetUpBuildContext(); + } + + private void SetUpBuildContext() + { + // Get a reference to the build context (which holds post build helper data) + buildContextBehaviour = this.AddOrGetComponent(); + buildContext = buildContextBehaviour.GetBuildContext(); + } + + protected virtual void Start() + { + } + + protected virtual void Update() + { + if (Application.isPlaying) + { + bool buildOccurred = CSGFactory.Tick(); + if (buildOccurred) + { + OnBuildComplete(); + } + } + } + + /// + /// Builds the brushes into final meshes + /// + /// If set to true all brushes will be built and cached data ignored, otherwise SabreCSG will only rebuild brushes it knows have changed + /// If set to true the majority of the build will occur in a background thread + public virtual void Build(bool forceRebuild, bool buildInBackground) + { + // If any of the build settings have changed, force all brushes to rebuild + if (!lastBuildSettings.IsBuilt || CSGBuildSettings.AreDifferent(buildSettings, lastBuildSettings)) + { + forceRebuild = true; + } + + // Make sure we have the most accurate list of brushes, ignoring inactive objects + brushes = new List(transform.GetComponentsInChildren(false)); + + // Let each brush know it's about to be built + for (int i = 0; i < brushes.Count; i++) + { + brushes[i].PrepareToBuild(brushes, forceRebuild); + } + + // Perform a check to make sure the default material is OK + Material defaultMaterial = GetDefaultMaterial(); + + if (defaultMaterial == null) + { + Debug.LogError("Default fallback material file is missing, try reimporting SabreCSG"); + } + + BuildStatus buildStatus = CSGFactory.Build(brushes, + buildSettings, + buildContext, + this.transform, + materialMeshDictionary, + collisionMeshDictionary, + polygonsRemoved, + forceRebuild, + OnBuildProgressChanged, + OnFinalizeVisualMesh, + OnFinalizeCollisionMesh, + buildInBackground); + + if (buildStatus == BuildStatus.Complete) + { + OnBuildComplete(); + } + } + + public virtual void OnBuildComplete() + { + polygonsRemoved = false; + + // Mark the brushes that have been built (so we can differentiate later if new brushes are built or not) + builtBrushes.Clear(); + builtBrushes.AddRange(brushes); + + // Copy the last build settings, so that we can make minor changes to built meshes that are consistent + // with how they were built. E.g. maintaining tangents as appropriate + lastBuildSettings = buildSettings.ShallowCopy(); + lastBuildSettings.IsBuilt = true; // Make it clear that the lastBuildSettings refers to a completed build + + // Fire any post process build events + FirePostBuildEvents(); + } + + private void FirePostBuildEvents() + { + Transform meshGroupTransform = GetMeshGroupTransform(); + + // Inform all methods with the PostProcessCSGBuildAttribute that a build just finished + Assembly[] allAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (Assembly assembly in allAssemblies) + { + if (assembly.FullName.StartsWith("Assembly-CSharp")) + { + Type[] types = assembly.GetTypes(); + + for (int i = 0; i < types.Length; i++) + { + MethodInfo[] methods = types[i].GetMethods(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + for (int j = 0; j < methods.Length; j++) + { + if (Attribute.IsDefined(methods[j], typeof(PostProcessCSGBuildAttribute))) + { + methods[j].Invoke(null, new object[] { meshGroupTransform }); + } + } + } + } + } + + // Inform all the scripts implementing IPostBuildListener on this model and inside it that a build finished + IPostBuildListener[] postBuildListeners = this.transform.GetComponentsInChildren(); + + for (int i = 0; i < postBuildListeners.Length; i++) + { + postBuildListeners[i].OnBuildFinished(meshGroupTransform); + } + } + + /// + /// Called to alert the CSG Model that a new brush has been created + /// + public bool TrackBrush(Brush brush) + { + // If we don't already know about the brush, add it + if (!brushes.Contains(brush)) + { + brushes.Add(brush); + return true; + } + else + { + return false; + } + } + + public void OnBrushDisabled(PrimitiveBrush brush) + { + polygonsRemoved = true; + } + + public virtual bool AreBrushesVisible + { + get + { + return false; + } + } + + public Polygon RaycastBuiltPolygons(Ray ray) + { + if (BuildContext.VisualPolygons != null) + { + float distance = 0; + return GeometryHelper.RaycastPolygons(BuildContext.VisualPolygons, ray, out distance); + } + else + { + return null; + } + } public List RaycastBuiltPolygonsAll(Ray ray) { if (BuildContext.VisualPolygons != null) - { + { return GeometryHelper.RaycastPolygonsAll(BuildContext.VisualPolygons, ray); } else @@ -321,162 +354,162 @@ public List RaycastBuiltPolygonsAll(Ray ray) } public Brush FindBrushFromPolygon(Polygon sourcePolygon) - { - // Find which brush contains the source polygon - for (int i = 0; i < brushes.Count; i++) - { - if(brushes[i] != null) - { - if(Array.IndexOf(brushes[i].GetPolygonIDs(), sourcePolygon.UniqueIndex) != -1) - { - return brushes[i]; - } - } - } - - // None found - return null; - } - - // Consider getting rid of this accessor! - public List VisualPolygons - { - get - { - return BuildContext.VisualPolygons; - } - } - - public List GetAllSourcePolygons() - { - // Find the source polygon unique indexes of all the visual polygons - List visualPolygons = BuildContext.VisualPolygons; - List visualPolygonIndexes = new List(); - - for (int i = 0; i < visualPolygons.Count; i++) - { - if(!visualPolygonIndexes.Contains(visualPolygons[i].UniqueIndex)) - { - visualPolygonIndexes.Add(visualPolygons[i].UniqueIndex); - } - } - - List sourcePolygons = new List(visualPolygonIndexes.Count); - - for (int i = 0; i < visualPolygonIndexes.Count; i++) - { - Polygon sourcePolygon = GetSourcePolygon(visualPolygonIndexes[i]); - sourcePolygons.Add(sourcePolygon); - } - return sourcePolygons; - } - - public Polygon[] BuiltPolygonsByIndex(int uniquePolygonIndex) - { -// if(CurrentSettings.NewBuildEngine) -// { -// // TODO: Optimise this once Nova 1 is removed -// List foundPolygons = new List(); -// for (int i = 0; i < brushes.Count; i++) -// { -// if(brushes[i] != null) -// { -// List brushPolygons = brushes[i].BrushCache.BuiltPolygons; -// for (int j = 0; j < brushPolygons.Count; j++) -// { -// if(brushPolygons[j].UniqueIndex == uniquePolygonIndex) -// { -// foundPolygons.Add(brushPolygons[j]); -// } -// } -// } -// } -// return foundPolygons.ToArray(); -// } -// else - { - if(BuildContext == null || BuildContext.VisualPolygons == null) - { - return new Polygon[0]; - } - - List matchedPolygons = new List(); - - // Match all the polygons with the same index that are built - for (int i = 0; i < BuildContext.VisualPolygons.Count; i++) - { - Polygon poly = BuildContext.VisualPolygons[i]; - - if(poly.UniqueIndex == uniquePolygonIndex && !poly.ExcludeFromFinal) - { - matchedPolygons.Add(poly); - } - } - - return matchedPolygons.ToArray(); - } - } - -// public Polygon[] BuiltCollisionPolygonsByIndex(int uniquePolygonIndex) -// { -// if(buildContext == null || buildContext.collisionPolygons == null) -// { -// return new Polygon[0]; -// } -// -// return buildContext.collisionPolygons.Where(poly => (poly.UniqueIndex == uniquePolygonIndex && !poly.ExcludeFromFinal)).ToArray(); -// } - - public List RaycastBrushesAll(Ray ray, bool testAllModels) - { - List hits = new List(); - - List brushesToTest; - - if(testAllModels) - { - brushesToTest = new List(); - CSGModelBase[] csgModels = FindObjectsOfType(); - for (int i = 0; i < csgModels.Length; i++) - { - brushesToTest.AddRange(csgModels[i].brushes); - } - } - else - { - brushesToTest = brushes; - } - - for (int i = 0; i < brushesToTest.Count; i++) - { - if(brushesToTest[i] == null) - { - continue; - } -// Bounds bounds = brushes[i].GetBoundsTransformed(); -// if(bounds.IntersectRay(ray)) - { - Polygon[] polygons = brushesToTest[i].GenerateTransformedPolygons(); - float hitDistance; - Polygon hitPolygon = GeometryHelper.RaycastPolygons(new List(polygons), ray, out hitDistance); - if(hitPolygon != null) - { - hits.Add(new PolygonRaycastHit() - { - Distance = hitDistance, - Point = ray.GetPoint(hitDistance), - Normal = hitPolygon.Plane.normal, - GameObject = brushesToTest[i].gameObject, - Polygon = hitPolygon, - } - ); - } - } - } - - hits.Sort((x,y) => x.Distance.CompareTo(y.Distance)); - return hits; - } + { + // Find which brush contains the source polygon + for (int i = 0; i < brushes.Count; i++) + { + if (brushes[i] != null) + { + if (Array.IndexOf(brushes[i].GetPolygonIDs(), sourcePolygon.UniqueIndex) != -1) + { + return brushes[i]; + } + } + } + + // None found + return null; + } + + // Consider getting rid of this accessor! + public List VisualPolygons + { + get + { + return BuildContext.VisualPolygons; + } + } + + public List GetAllSourcePolygons() + { + // Find the source polygon unique indexes of all the visual polygons + List visualPolygons = BuildContext.VisualPolygons; + List visualPolygonIndexes = new List(); + + for (int i = 0; i < visualPolygons.Count; i++) + { + if (!visualPolygonIndexes.Contains(visualPolygons[i].UniqueIndex)) + { + visualPolygonIndexes.Add(visualPolygons[i].UniqueIndex); + } + } + + List sourcePolygons = new List(visualPolygonIndexes.Count); + + for (int i = 0; i < visualPolygonIndexes.Count; i++) + { + Polygon sourcePolygon = GetSourcePolygon(visualPolygonIndexes[i]); + sourcePolygons.Add(sourcePolygon); + } + return sourcePolygons; + } + + public Polygon[] BuiltPolygonsByIndex(int uniquePolygonIndex) + { + // if(CurrentSettings.NewBuildEngine) + // { + // // TODO: Optimise this once Nova 1 is removed + // List foundPolygons = new List(); + // for (int i = 0; i < brushes.Count; i++) + // { + // if(brushes[i] != null) + // { + // List brushPolygons = brushes[i].BrushCache.BuiltPolygons; + // for (int j = 0; j < brushPolygons.Count; j++) + // { + // if(brushPolygons[j].UniqueIndex == uniquePolygonIndex) + // { + // foundPolygons.Add(brushPolygons[j]); + // } + // } + // } + // } + // return foundPolygons.ToArray(); + // } + // else + { + if (BuildContext == null || BuildContext.VisualPolygons == null) + { + return new Polygon[0]; + } + + List matchedPolygons = new List(); + + // Match all the polygons with the same index that are built + for (int i = 0; i < BuildContext.VisualPolygons.Count; i++) + { + Polygon poly = BuildContext.VisualPolygons[i]; + + if (poly.UniqueIndex == uniquePolygonIndex && !poly.ExcludeFromFinal) + { + matchedPolygons.Add(poly); + } + } + + return matchedPolygons.ToArray(); + } + } + + // public Polygon[] BuiltCollisionPolygonsByIndex(int uniquePolygonIndex) + // { + // if(buildContext == null || buildContext.collisionPolygons == null) + // { + // return new Polygon[0]; + // } + // + // return buildContext.collisionPolygons.Where(poly => (poly.UniqueIndex == uniquePolygonIndex && !poly.ExcludeFromFinal)).ToArray(); + // } + + public List RaycastBrushesAll(Ray ray, bool testAllModels) + { + List hits = new List(); + + List brushesToTest; + + if (testAllModels) + { + brushesToTest = new List(); + CSGModelBase[] csgModels = FindObjectsOfType(); + for (int i = 0; i < csgModels.Length; i++) + { + brushesToTest.AddRange(csgModels[i].brushes); + } + } + else + { + brushesToTest = brushes; + } + + for (int i = 0; i < brushesToTest.Count; i++) + { + if (brushesToTest[i] == null) + { + continue; + } + // Bounds bounds = brushes[i].GetBoundsTransformed(); + // if(bounds.IntersectRay(ray)) + { + Polygon[] polygons = brushesToTest[i].GenerateTransformedPolygons(); + float hitDistance; + Polygon hitPolygon = GeometryHelper.RaycastPolygons(new List(polygons), ray, out hitDistance); + if (hitPolygon != null) + { + hits.Add(new PolygonRaycastHit() + { + Distance = hitDistance, + Point = ray.GetPoint(hitDistance), + Normal = hitPolygon.Plane.normal, + GameObject = brushesToTest[i].gameObject, + Polygon = hitPolygon, + } + ); + } + } + } + + hits.Sort((x, y) => x.Distance.CompareTo(y.Distance)); + return hits; + } public List ExtractBrushBases(List sourceBrushes) { @@ -484,14 +517,28 @@ public List ExtractBrushBases(List sourceBrushes) List brushBases = new List(); for (int i = 0; i < sourceBrushes.Count; i++) { - if(sourceBrushes[i].GetType() == typeof(PrimitiveBrush)) + if (sourceBrushes[i].GetType() == typeof(PrimitiveBrush)) { + // Get any group this brush is a child of. + GroupBrush group = null; + if (sourceBrushes[i].transform.parent) + group = sourceBrushes[i].transform.parent.GetComponent(); + // Get any controller (e.g. compound brush) that is driving the selected brush BrushBase controller = ((PrimitiveBrush)sourceBrushes[i]).BrushController; - if (controller != null) + + if (group != null) + { + // Group with 'always select group' found, add it instead if it's not already in the list + if (!brushBases.Contains(group)) + { + brushBases.Add(group); + } + } + else if (controller != null) { // Controller found, add it instead if it's not already in the list - if(!brushBases.Contains(controller)) + if (!brushBases.Contains(controller)) { brushBases.Add(controller); } @@ -511,50 +558,51 @@ public List ExtractBrushBases(List sourceBrushes) return brushBases; } - public bool HasBrushBeenBuilt(Brush candidateBrush) - { - return builtBrushes.Contains(candidateBrush); - } - - /// - /// Creates a brush under the CSG Model with the specified attributes. - /// - /// The created game object. - /// Brush type. - /// Local position of the brush's transform - /// Local bounds size of the brush (Optional, defaults to 2,2,2). - /// Local rotation of the brush (Optional, defaults to identity quaternion). - /// Material to apply to all faces, (Optional, defaults to null for default material). - /// Whether the brush is additive or subtractive (Optional, defaults to additive). - /// Name for the game object (Optional, defaults to "AppliedBrush"). - public GameObject CreateBrush(PrimitiveBrushType brushType, Vector3 localPosition, Vector3 localSize = default(Vector3), Quaternion localRotation = default(Quaternion), Material material = null, CSGMode csgMode = CSGMode.Add, string brushName = null) - { - GameObject brushObject; - if(!string.IsNullOrEmpty(brushName)) - { - brushObject = new GameObject(brushName); - } - else - { - brushObject = new GameObject("AppliedBrush"); - } - - brushObject.transform.parent = this.transform; - brushObject.transform.localPosition = localPosition; - if(localRotation != default(Quaternion)) - { - brushObject.transform.localRotation = localRotation; - } - PrimitiveBrush primitiveBrush = brushObject.AddComponent(); - primitiveBrush.BrushType = brushType; - primitiveBrush.Mode = csgMode; - primitiveBrush.ResetPolygons(); - - if(localSize != default(Vector3) - && localSize != new Vector3(2,2,2)) - { - BrushUtility.Resize(primitiveBrush, localSize); - } + public bool HasBrushBeenBuilt(Brush candidateBrush) + { + return builtBrushes.Contains(candidateBrush); + } + + /// + /// Creates a brush under the CSG Model with the specified attributes. + /// + /// The created game object. + /// Brush type. + /// Local position of the brush's transform + /// Local bounds size of the brush (Optional, defaults to 2,2,2). + /// Local rotation of the brush (Optional, defaults to identity quaternion). + /// Material to apply to all faces, (Optional, defaults to null for default material). + /// Whether the brush is additive or subtractive (Optional, defaults to additive). + /// Name for the game object (Optional, defaults to "AppliedBrush"). + public GameObject CreateBrush(PrimitiveBrushType brushType, Vector3 localPosition, Vector3 localSize = default(Vector3), Quaternion localRotation = default(Quaternion), Material material = null, CSGMode csgMode = CSGMode.Add, string brushName = null) + { + GameObject brushObject; + if (!string.IsNullOrEmpty(brushName)) + { + brushObject = new GameObject(brushName); + } + else + { + brushObject = new GameObject(""); + } + + brushObject.transform.localScale = this.transform.lossyScale; + brushObject.transform.parent = this.transform; + brushObject.transform.localPosition = localPosition; + if (localRotation != default(Quaternion)) + { + brushObject.transform.localRotation = localRotation; + } + PrimitiveBrush primitiveBrush = brushObject.AddComponent(); + primitiveBrush.BrushType = brushType; + primitiveBrush.Mode = csgMode; + primitiveBrush.ResetPolygons(); + + if (localSize != default(Vector3) + && localSize != new Vector3(2, 2, 2)) + { + BrushUtility.Resize(primitiveBrush, localSize); + } else { // Resize automatically invalidates a brush with changed polygons set, if no resize took place we still need to make sure it happens @@ -562,168 +610,170 @@ public bool HasBrushBeenBuilt(Brush candidateBrush) } if (material != null) - { - SurfaceUtility.SetAllPolygonsMaterials(primitiveBrush, material); - } - - return brushObject; - } - - public GameObject CreateCompoundBrush(Vector3 localPosition, Vector3 localSize = default(Vector3), Quaternion localRotation = default(Quaternion), Material material = null, CSGMode csgMode = CSGMode.Add, string brushName = null) where T : CompoundBrush - { - return CreateCompoundBrush(typeof(T), localPosition, localSize, localRotation, material, csgMode, brushName); - } - - public GameObject CreateCompoundBrush(Type compoundBrushType, Vector3 localPosition, Vector3 localSize = default(Vector3), Quaternion localRotation = default(Quaternion), Material material = null, CSGMode csgMode = CSGMode.Add, string brushName = null) - { - // Make sure we're actually being asked to create a compound brush - if(!typeof(CompoundBrush).IsAssignableFrom(compoundBrushType)) - { - throw new ArgumentException("Specified type must be derived from CompoundBrush"); - } - - GameObject brushObject; - if(!string.IsNullOrEmpty(brushName)) - { - brushObject = new GameObject(brushName); - } - else - { - brushObject = new GameObject(compoundBrushType.Name); - } - - brushObject.transform.parent = this.transform; - brushObject.transform.localPosition = localPosition; - if(localRotation != default(Quaternion)) - { - brushObject.transform.localRotation = localRotation; - } - CompoundBrush compoundBrush = (CompoundBrush)brushObject.AddComponent(compoundBrushType); - compoundBrush.Mode = csgMode; - compoundBrush.Invalidate(true); -// if(localSize != default(Vector3) -// && localSize != new Vector3(2,2,2)) -// { -// BrushUtility.Resize(compoundBrush, localSize); -// } - - if(material != null) - { -// SurfaceUtility.SetAllPolygonsMaterials(compoundBrush, material); - } - - return brushObject; - } - - /// - /// Create a brush at the origin using a specified set of polygons - /// - /// The custom brush game object. - /// Polygons. - public GameObject CreateCustomBrush(Polygon[] polygons) - { - GameObject brushObject = new GameObject("AppliedBrush"); - brushObject.transform.parent = this.transform; - PrimitiveBrush primitiveBrush = brushObject.AddComponent(); - primitiveBrush.SetPolygons(polygons, true); - - return brushObject; - } - - public Polygon GetSourcePolygon(int uniqueIndex) - { - for (int i = 0; i < brushes.Count; i++) - { - if(brushes[i] != null) - { - Polygon[] polygons = brushes[i].GetPolygons(); - for (int j = 0; j < polygons.Length; j++) - { - if(polygons[j].UniqueIndex == uniqueIndex) - { - return polygons[j]; - } - } - } - } - - // None found - return null; - } - - public Transform GetMeshGroupTransform() - { - Transform meshGroup = transform.Find("MeshGroup"); - return meshGroup; - } - - public void RefreshMeshGroup() - { - // For some reason mesh colliders don't update when you change the mesh, you have to flush them by - // either setting the mesh null and resetting it, or turning the object off and on again - Transform meshGroup = GetMeshGroupTransform(); - - if(meshGroup != null && meshGroup.gameObject.activeInHierarchy) - { - meshGroup.gameObject.SetActive(false); - meshGroup.gameObject.SetActive(true); - } - } - - public virtual void OnBuildProgressChanged(float progress) - { - } - - public virtual void OnFinalizeVisualMesh(GameObject newGameObject, Mesh mesh) - { - } - - public virtual void OnFinalizeCollisionMesh(GameObject newGameObject, Mesh mesh) - { - } - - public void NotifyPolygonsRemoved() - { - polygonsRemoved = true; - } - - public Material GetDefaultMaterial() - { - // Make sure there is a default material set, if not use the fallback - EnsureDefaultMaterialSet(); - - // Return the active default material set for the Model - return buildSettings.DefaultVisualMaterial; - } - -// public void SetDefaultMaterial(Material newMaterial) -// { -// buildSettings.DefaultVisualMaterial = newMaterial; -// // Make sure there is a material set, setting null with reset to default -// EnsureDefaultMaterialSet(); -// } - - public void EnsureDefaultMaterialSet() - { - // Make sure there is a default material set, if not use the fallback - if(buildSettings.DefaultVisualMaterial == null) - { - buildSettings.DefaultVisualMaterial = GetDefaultFallbackMaterial(); - } - } - - public virtual Material GetDefaultFallbackMaterial() - { - return Resources.Load(DEFAULT_FALLBACK_MATERIAL_PATH) as Material; - } - - public class RayHitComparer : IComparer - { - public int Compare(object x, object y) - { - return ((RaycastHit) x).distance.CompareTo(((RaycastHit) y).distance); - } - } - } + { + SurfaceUtility.SetAllPolygonsMaterials(primitiveBrush, material); + } + + return brushObject; + } + + public GameObject CreateCompoundBrush(Vector3 localPosition, Vector3 localSize = default(Vector3), Quaternion localRotation = default(Quaternion), Material material = null, CSGMode csgMode = CSGMode.Add, string brushName = null) where T : CompoundBrush + { + return CreateCompoundBrush(typeof(T), localPosition, localSize, localRotation, material, csgMode, brushName); + } + + public GameObject CreateCompoundBrush(Type compoundBrushType, Vector3 localPosition, Vector3 localSize = default(Vector3), Quaternion localRotation = default(Quaternion), Material material = null, CSGMode csgMode = CSGMode.Add, string brushName = null) + { + // Make sure we're actually being asked to create a compound brush + if (!typeof(CompoundBrush).IsAssignableFrom(compoundBrushType)) + { + throw new ArgumentException("Specified type must be derived from CompoundBrush"); + } + + GameObject brushObject; + if (!string.IsNullOrEmpty(brushName)) + { + brushObject = new GameObject(brushName); + } + else + { + brushObject = new GameObject(""); + } + + brushObject.transform.localScale = this.transform.lossyScale; + brushObject.transform.parent = this.transform; + brushObject.transform.localPosition = localPosition; + if (localRotation != default(Quaternion)) + { + brushObject.transform.localRotation = localRotation; + } + CompoundBrush compoundBrush = (CompoundBrush)brushObject.AddComponent(compoundBrushType); + compoundBrush.Mode = csgMode; + compoundBrush.Invalidate(true); + // if(localSize != default(Vector3) + // && localSize != new Vector3(2,2,2)) + // { + // BrushUtility.Resize(compoundBrush, localSize); + // } + + if (material != null) + { + // SurfaceUtility.SetAllPolygonsMaterials(compoundBrush, material); + } + + return brushObject; + } + + /// + /// Create a brush at the origin using a specified set of polygons + /// + /// The custom brush game object. + /// Polygons. + public GameObject CreateCustomBrush(Polygon[] polygons) + { + GameObject brushObject = new GameObject(""); + brushObject.transform.parent = this.transform; + PrimitiveBrush primitiveBrush = brushObject.AddComponent(); + primitiveBrush.SetPolygons(polygons, true); + + return brushObject; + } + + public Polygon GetSourcePolygon(int uniqueIndex) + { + for (int i = 0; i < brushes.Count; i++) + { + if (brushes[i] != null) + { + Polygon[] polygons = brushes[i].GetPolygons(); + for (int j = 0; j < polygons.Length; j++) + { + if (polygons[j].UniqueIndex == uniqueIndex) + { + return polygons[j]; + } + } + } + } + + // None found + return null; + } + + public Transform GetMeshGroupTransform() + { + Transform meshGroup = transform.Find("MeshGroup"); + return meshGroup; + } + + public void RefreshMeshGroup() + { + // For some reason mesh colliders don't update when you change the mesh, you have to flush them by + // either setting the mesh null and resetting it, or turning the object off and on again + Transform meshGroup = GetMeshGroupTransform(); + + if (meshGroup != null && meshGroup.gameObject.activeInHierarchy) + { + meshGroup.gameObject.SetActive(false); + meshGroup.gameObject.SetActive(true); + } + } + + public virtual void OnBuildProgressChanged(float progress) + { + } + + public virtual void OnFinalizeVisualMesh(GameObject newGameObject, Mesh mesh) + { + } + + public virtual void OnFinalizeCollisionMesh(GameObject newGameObject, Mesh mesh) + { + } + + public void NotifyPolygonsRemoved() + { + polygonsRemoved = true; + } + + public Material GetDefaultMaterial() + { + // Make sure there is a default material set, if not use the fallback + EnsureDefaultMaterialSet(); + + // Return the active default material set for the Model + return buildSettings.DefaultVisualMaterial; + } + + // public void SetDefaultMaterial(Material newMaterial) + // { + // buildSettings.DefaultVisualMaterial = newMaterial; + // // Make sure there is a material set, setting null with reset to default + // EnsureDefaultMaterialSet(); + // } + + public void EnsureDefaultMaterialSet() + { + // Make sure there is a default material set, if not use the fallback + if (buildSettings.DefaultVisualMaterial == null) + { + buildSettings.DefaultVisualMaterial = GetDefaultFallbackMaterial(); + } + } + + public virtual Material GetDefaultFallbackMaterial() + { + return Resources.Load(DEFAULT_FALLBACK_MATERIAL_PATH) as Material; + } + + public class RayHitComparer : IComparer + { + public int Compare(object x, object y) + { + return ((RaycastHit)x).distance.CompareTo(((RaycastHit)y).distance); + } + } + } } + #endif \ No newline at end of file diff --git a/Scripts/Compatibility.meta b/Scripts/Compatibility.meta new file mode 100644 index 00000000..b0b9a903 --- /dev/null +++ b/Scripts/Compatibility.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2c869506319936e48871703f87ed0f83 +folderAsset: yes +timeCreated: 1521408336 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Compatibility/Vector2Int.cs b/Scripts/Compatibility/Vector2Int.cs new file mode 100644 index 00000000..ed785dcf --- /dev/null +++ b/Scripts/Compatibility/Vector2Int.cs @@ -0,0 +1,260 @@ +#if (UNITY_EDITOR || RUNTIME_CSG) && !UNITY_2017_2_OR_NEWER +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace UnityEngine +{ + /// + /// A complete reimplementation of Vector2Int for older Unity versions. + /// + [System.Serializable] + public struct Vector2Int + { + [SerializeField] + public int x; + + [SerializeField] + public int y; + + private static readonly Vector2Int s_Zero = new Vector2Int(0, 0); + + private static readonly Vector2Int s_One = new Vector2Int(1, 1); + + private static readonly Vector2Int s_Up = new Vector2Int(0, 1); + + private static readonly Vector2Int s_Down = new Vector2Int(0, -1); + + private static readonly Vector2Int s_Left = new Vector2Int(-1, 0); + + private static readonly Vector2Int s_Right = new Vector2Int(1, 0); + + public int this[int index] + { + get + { + int result; + if (index != 0) + { + if (index != 1) + { + throw new IndexOutOfRangeException(string.Format("Invalid Vector2Int index addressed: {0}!", index)); + } + result = this.y; + } + else + { + result = this.x; + } + return result; + } + set + { + if (index != 0) + { + if (index != 1) + { + throw new IndexOutOfRangeException(string.Format("Invalid Vector2Int index addressed: {0}!", index)); + } + this.y = value; + } + else + { + this.x = value; + } + } + } + + public float magnitude + { + get + { + return Mathf.Sqrt((float)(this.x * this.x + this.y * this.y)); + } + } + + public int sqrMagnitude + { + get + { + return this.x * this.x + this.y * this.y; + } + } + + public static Vector2Int zero + { + get + { + return Vector2Int.s_Zero; + } + } + + public static Vector2Int one + { + get + { + return Vector2Int.s_One; + } + } + + public static Vector2Int up + { + get + { + return Vector2Int.s_Up; + } + } + + public static Vector2Int down + { + get + { + return Vector2Int.s_Down; + } + } + + public static Vector2Int left + { + get + { + return Vector2Int.s_Left; + } + } + + public static Vector2Int right + { + get + { + return Vector2Int.s_Right; + } + } + + public Vector2Int(int x, int y) + { + this.x = x; + this.y = y; + } + + public void Set(int x, int y) + { + this.x = x; + this.y = y; + } + + public static float Distance(Vector2Int a, Vector2Int b) + { + return (a - b).magnitude; + } + + public static Vector2Int Min(Vector2Int lhs, Vector2Int rhs) + { + return new Vector2Int(Mathf.Min(lhs.x, rhs.x), Mathf.Min(lhs.y, rhs.y)); + } + + public static Vector2Int Max(Vector2Int lhs, Vector2Int rhs) + { + return new Vector2Int(Mathf.Max(lhs.x, rhs.x), Mathf.Max(lhs.y, rhs.y)); + } + + public static Vector2Int Scale(Vector2Int a, Vector2Int b) + { + return new Vector2Int(a.x * b.x, a.y * b.y); + } + + public void Scale(Vector2Int scale) + { + this.x *= scale.x; + this.y *= scale.y; + } + + public void Clamp(Vector2Int min, Vector2Int max) + { + this.x = Math.Max(min.x, this.x); + this.x = Math.Min(max.x, this.x); + this.y = Math.Max(min.y, this.y); + this.y = Math.Min(max.y, this.y); + } + + public static implicit operator Vector2(Vector2Int v) + { + return new Vector2((float)v.x, (float)v.y); + } + + public static Vector2Int FloorToInt(Vector2 v) + { + return new Vector2Int(Mathf.FloorToInt(v.x), Mathf.FloorToInt(v.y)); + } + + public static Vector2Int CeilToInt(Vector2 v) + { + return new Vector2Int(Mathf.CeilToInt(v.x), Mathf.CeilToInt(v.y)); + } + + public static Vector2Int RoundToInt(Vector2 v) + { + return new Vector2Int(Mathf.RoundToInt(v.x), Mathf.RoundToInt(v.y)); + } + + public static Vector2Int operator +(Vector2Int a, Vector2Int b) + { + return new Vector2Int(a.x + b.x, a.y + b.y); + } + + public static Vector2Int operator -(Vector2Int a, Vector2Int b) + { + return new Vector2Int(a.x - b.x, a.y - b.y); + } + + public static Vector2Int operator *(Vector2Int a, Vector2Int b) + { + return new Vector2Int(a.x * b.x, a.y * b.y); + } + + public static Vector2Int operator *(Vector2Int a, int b) + { + return new Vector2Int(a.x * b, a.y * b); + } + + public static bool operator ==(Vector2Int lhs, Vector2Int rhs) + { + return lhs.x == rhs.x && lhs.y == rhs.y; + } + + public static bool operator !=(Vector2Int lhs, Vector2Int rhs) + { + return !(lhs == rhs); + } + + public override bool Equals(object other) + { + bool result; + if (!(other is Vector2Int)) + { + result = false; + } + else + { + Vector2Int vector2Int = (Vector2Int)other; + result = (this.x.Equals(vector2Int.x) && this.y.Equals(vector2Int.y)); + } + return result; + } + + public override int GetHashCode() + { + return this.x.GetHashCode() ^ this.y.GetHashCode() << 2; + } + + public override string ToString() + { + return String.Format("({0}, {1})", new object[] + { + this.x, + this.y + }); + } + } +} +#endif \ No newline at end of file diff --git a/Scripts/Compatibility/Vector2Int.cs.meta b/Scripts/Compatibility/Vector2Int.cs.meta new file mode 100644 index 00000000..c7252ae1 --- /dev/null +++ b/Scripts/Compatibility/Vector2Int.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fce035588f48edc48b5dcca89ead0105 +timeCreated: 1521408337 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Core/BrushBase.cs b/Scripts/Core/BrushBase.cs index 5a6e4f5f..8b2cfb55 100644 --- a/Scripts/Core/BrushBase.cs +++ b/Scripts/Core/BrushBase.cs @@ -10,6 +10,7 @@ namespace Sabresaurus.SabreCSG { public enum CSGMode { Add, Subtract }; + [ExecuteInEditMode] public abstract class BrushBase : MonoBehaviour { [SerializeField] @@ -26,7 +27,9 @@ public abstract class BrushBase : MonoBehaviour protected bool destroyed = false; - public CSGMode Mode + protected string previousHierarchyName = ""; + + public CSGMode Mode { get { @@ -87,7 +90,60 @@ public bool HasCollision } } - public virtual void Invalidate(bool polygonsChanged){} + /// + /// Gets the beautiful name of the brush used in auto-generation of the hierarchy name. + /// + /// The beautiful name of the brush. + public virtual string BeautifulBrushName + { + get + { + return "AppliedBrush"; + } + } + + /// + /// Gets an auto-generated name for use in the hierarchy. + /// + /// An auto-generated name for use in the hierarchy. + public string GeneratedHierarchyName + { + get + { + return BeautifulBrushName + " (" + GetBounds().ToGeneratedHierarchyString() + ")"; + } + } + + /// + /// Updates the auto-generated name of the brush in the hierarchy. This must be called when + /// the bounds of a brush change without a call to . The name of the + /// brush is not updated when the user changed it to something else manually. The only + /// exception to that is when the user resets the name to an empty string. + /// + public void UpdateGeneratedHierarchyName() + { + // this may happen after the brush is duplicated. + if (previousHierarchyName == "" && GeneratedHierarchyName == transform.name) + previousHierarchyName = transform.name; + + if (transform.name == previousHierarchyName || transform.name == "") + transform.name = previousHierarchyName = GeneratedHierarchyName; + } + + /// + /// Gets a value indicating whether this brush supports CSG operations. Setting this to false + /// will hide CSG brush related options in the editor. + /// For example a does not have any CSG operations. + /// + /// true if this brush supports CSG operations; otherwise, false. + public virtual bool SupportsCsgOperations { get { return true; } } + + public virtual void Invalidate(bool polygonsChanged) + { + // when a modification to a brush occured we update the auto-generated name. + if (polygonsChanged) + UpdateGeneratedHierarchyName(); + } public abstract void UpdateVisibility(); @@ -102,12 +158,21 @@ public virtual void Invalidate(bool polygonsChanged){} // Fired by the CSG Model on each brush it knows about when Unity triggers Undo.undoRedoPerformed public abstract void OnUndoRedoPerformed (); - protected virtual void OnDestroy() { destroyed = true; - } - } + } + + protected virtual void Awake() + { + // if the brush name is equal to the auto-generated one, + // we store the name so we can check for manual user changes. + if (previousHierarchyName == "" && GeneratedHierarchyName == transform.name) + previousHierarchyName = transform.name; + } + + protected virtual void Update() { } + } } #endif \ No newline at end of file diff --git a/Scripts/Core/BuildEngine/MeshGroupManager.cs b/Scripts/Core/BuildEngine/MeshGroupManager.cs index 29f14399..8c71974d 100755 --- a/Scripts/Core/BuildEngine/MeshGroupManager.cs +++ b/Scripts/Core/BuildEngine/MeshGroupManager.cs @@ -33,7 +33,7 @@ internal static void Cleanup(Transform meshGroupHolder) for (int i = 0; i < colliders.Length; i++) { #if UNITY_EDITOR - if(filters[i].sharedMesh != null && !UnityEditor.AssetDatabase.Contains(filters[i].sharedMesh)) + if(colliders[i].sharedMesh != null && !UnityEditor.AssetDatabase.Contains(colliders[i].sharedMesh)) #endif GameObject.DestroyImmediate(colliders[i].sharedMesh); } diff --git a/Scripts/Core/CSG/Polygon.cs b/Scripts/Core/CSG/Polygon.cs index 0603629f..fec8e651 100644 --- a/Scripts/Core/CSG/Polygon.cs +++ b/Scripts/Core/CSG/Polygon.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Reflection; +using System; namespace Sabresaurus.SabreCSG { @@ -107,6 +108,36 @@ public Polygon(Vertex[] vertices, Material material, bool isTemporary, bool user CalculatePlane(); } + /// + /// Initializes a new instance of the class. + /// + /// The vertex positions of a that make up this polygonal shape. Normals and UVs will be zero (see and to generate them automatically). + /// The Unity applied to the surface of this polygon. + /// If set to true excludes the polygon from the final CSG build, it's only temporarily created during the build process to determine whether a point is inside/outside of a convex chunk (usually you set this argument to false, also see ). + /// If set to true the user requested that this polygon be excluded from the final CSG build (i.e. not rendered, it does affect CSG operations). + /// When a polygon is split or cloned, this number is preserved inside of those new polygons so they can track where they originally came from. + /// Thrown when is null. + /// A polygon must have at least 3 vertices. + public Polygon(Vector3[] vertices, Material material, bool isTemporary, bool userExcludeFromFinal, int uniqueIndex = -1) + { + if (vertices == null) throw new ArgumentNullException("vertices"); + if (vertices.Length < 3) throw new ArgumentOutOfRangeException("A polygon must have at least 3 vertices."); + // consideration: check array for null elements? + + // create vertices from the vector3 array. + this.vertices = new Vertex[vertices.Length]; + for (int i = 0; i < vertices.Length; i++) + this.vertices[i] = new Vertex(vertices[i], Vector3.zero, Vector2.zero); + + this.material = material; + this.uniqueIndex = uniqueIndex; + this.excludeFromFinal = isTemporary; + this.userExcludeFromFinal = userExcludeFromFinal; + + // calculate the cached plane. + CalculatePlane(); + } + public Polygon DeepCopy() { return new Polygon(this.vertices.DeepCopy(), this.material, this.excludeFromFinal, this.userExcludeFromFinal, this.uniqueIndex); @@ -402,6 +433,21 @@ public void RemoveExtraneousVertices() } } + /// + /// Generates the UV coordinates for this polygon automatically. This works similarly to the + /// "AutoUV" button in the surface editor. This method may throw warnings in the console if + /// the normal of the polygon is zero. + /// You may have to call first if you modified the polygon. + /// + public void GenerateUvCoordinates() + { + // stolen code from the surface editor "AutoUV". + Quaternion cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(-Plane.normal)); + // sets the uv at each point to the position on the plane. + for (int i = 0; i < vertices.Length; i++) + vertices[i].UV = (cancellingRotation * vertices[i].Position) * 0.5f; + } + public static bool SplitPolygon(Polygon polygon, out Polygon frontPolygon, out Polygon backPolygon, out Vertex newVertex1, out Vertex newVertex2, UnityEngine.Plane clipPlane) { newVertex1 = null; diff --git a/Scripts/CurrentSettings.cs b/Scripts/CurrentSettings.cs index dc6a1875..5c7e8fc4 100644 --- a/Scripts/CurrentSettings.cs +++ b/Scripts/CurrentSettings.cs @@ -1,4 +1,5 @@ #if UNITY_EDITOR + using UnityEngine; using System.Collections; using System; @@ -6,52 +7,52 @@ namespace Sabresaurus.SabreCSG { - public enum MainMode - { - Resize, - Vertex, - Face, - - Clip, - Draw, - }; - - public enum OverrideMode - { - None, + public enum MainMode + { + Resize, + Vertex, + Face, + + Clip, + Draw, + }; + + public enum OverrideMode + { + None, TransformModel, // Dummy mode that prevents active tools conflicting - //Clip, - //Draw, - }; - - public enum GridMode - { - Unity, - SabreCSG, - None - } - - [ExecuteInEditMode] + //Clip, + //Draw, + }; + + public enum GridMode + { + Unity, + SabreCSG, + None + } + + [ExecuteInEditMode] public class CurrentSettings : ScriptableObject - { - bool brushesHidden = false; - bool meshHidden = false; - Material foregroundMaterial; + { + private bool brushesHidden = false; + private bool meshHidden = false; + private Material foregroundMaterial; - static CurrentSettings instance = null; + private static CurrentSettings instance = null; - static CurrentSettings Instance + private static CurrentSettings Instance { get { // Instance reference lost or not set - if(instance == null) + if (instance == null) { // First of all see if a CurrentSettings object exists instance = FindObjectOfType(); // Couldn't find an existing object, make a new one - if(instance == null) + if (instance == null) { instance = ScriptableObject.CreateInstance(); } @@ -60,82 +61,82 @@ static CurrentSettings Instance } } - const string KEY_PREFIX = "SabreCSG"; - - public static bool PositionSnappingEnabled - { - get - { - return PlayerPrefs.GetInt(KEY_PREFIX + "positionSnappingEnabled", 1) != 0; - } - set - { - PlayerPrefs.SetInt(KEY_PREFIX + "positionSnappingEnabled", value ? 1 : 0); - } - } - - public static float PositionSnapDistance - { - get - { - return PlayerPrefs.GetFloat(KEY_PREFIX + "positionSnapDistance", 1f); - } - set - { - if(value > 0) - { - PlayerPrefs.SetFloat(KEY_PREFIX + "positionSnapDistance", value); - } - } - } - - public static bool AngleSnappingEnabled - { - get - { - return PlayerPrefs.GetInt(KEY_PREFIX + "angleSnappingEnabled", 1) != 0; - } - set - { - PlayerPrefs.SetInt(KEY_PREFIX + "angleSnappingEnabled", value ? 1 : 0); - } - } - - public static bool HideGridInPerspective - { - get - { - return PlayerPrefs.GetInt(KEY_PREFIX + "HideGridInPerspective", 0) != 0; - } - set - { - PlayerPrefs.SetInt(KEY_PREFIX + "HideGridInPerspective", value ? 1 : 0); - } - } - - public static bool OverrideFlyCamera - { - get - { - return PlayerPrefs.GetInt(KEY_PREFIX + "OverrideFlyCamera", 0) != 0; - } - set - { - PlayerPrefs.SetInt(KEY_PREFIX + "OverrideFlyCamera", value ? 1 : 0); - } - } - - public static bool ShowExcludedPolygons - { - get - { - return PlayerPrefs.GetInt(KEY_PREFIX + "ShowExcludedPolygons", 0) != 0; - } - set - { - PlayerPrefs.SetInt(KEY_PREFIX + "ShowExcludedPolygons", value ? 1 : 0); - } - } + private const string KEY_PREFIX = "SabreCSG"; + + public static bool PositionSnappingEnabled + { + get + { + return PlayerPrefs.GetInt(KEY_PREFIX + "positionSnappingEnabled", 1) != 0; + } + set + { + PlayerPrefs.SetInt(KEY_PREFIX + "positionSnappingEnabled", value ? 1 : 0); + } + } + + public static float PositionSnapDistance + { + get + { + return PlayerPrefs.GetFloat(KEY_PREFIX + "positionSnapDistance", 1f); + } + set + { + if (value > 0) + { + PlayerPrefs.SetFloat(KEY_PREFIX + "positionSnapDistance", value); + } + } + } + + public static bool AngleSnappingEnabled + { + get + { + return PlayerPrefs.GetInt(KEY_PREFIX + "angleSnappingEnabled", 1) != 0; + } + set + { + PlayerPrefs.SetInt(KEY_PREFIX + "angleSnappingEnabled", value ? 1 : 0); + } + } + + public static bool HideGridInPerspective + { + get + { + return PlayerPrefs.GetInt(KEY_PREFIX + "HideGridInPerspective", 0) != 0; + } + set + { + PlayerPrefs.SetInt(KEY_PREFIX + "HideGridInPerspective", value ? 1 : 0); + } + } + + public static bool OverrideFlyCamera + { + get + { + return PlayerPrefs.GetInt(KEY_PREFIX + "OverrideFlyCamera", 0) != 0; + } + set + { + PlayerPrefs.SetInt(KEY_PREFIX + "OverrideFlyCamera", value ? 1 : 0); + } + } + + public static bool ShowExcludedPolygons + { + get + { + return PlayerPrefs.GetInt(KEY_PREFIX + "ShowExcludedPolygons", 0) != 0; + } + set + { + PlayerPrefs.SetInt(KEY_PREFIX + "ShowExcludedPolygons", value ? 1 : 0); + } + } public static bool ShowBrushesAsWireframes { @@ -149,163 +150,176 @@ public static bool ShowBrushesAsWireframes } } + public static bool ShowBrushBoundsGuideLines + { + get + { + return PlayerPrefs.GetInt(KEY_PREFIX + "ShowBrushBoundsGuideLines", 0) != 0; + } + set + { + PlayerPrefs.SetInt(KEY_PREFIX + "ShowBrushBoundsGuideLines", value ? 1 : 0); + } + } + public static bool ReducedHandleThreshold - { - get - { - return PlayerPrefs.GetInt(KEY_PREFIX + "ReducedHandleThreshold", 0) != 0; - } - set - { - PlayerPrefs.SetInt(KEY_PREFIX + "ReducedHandleThreshold", value ? 1 : 0); - } - } - - public static float AngleSnapDistance - { - get - { - return PlayerPrefs.GetFloat(KEY_PREFIX + "angleSnapDistance", 15); - } - set - { - if(value > 0) - { - PlayerPrefs.SetFloat(KEY_PREFIX + "angleSnapDistance", value); - } - } - } - - public static Material ForegroundMaterial - { - get - { - return Instance.foregroundMaterial; - } - set - { - Instance.foregroundMaterial = value; - } - } - - public static GridMode GridMode - { - get - { - string storedValue = PlayerPrefs.GetString(KEY_PREFIX + "gridMode"); - if(Enum.IsDefined(typeof(GridMode), storedValue)) - { - return (GridMode)Enum.Parse(typeof(GridMode), storedValue); - } - else - { - return GridMode.SabreCSG; - } - } - set - { - PlayerPrefs.SetString(KEY_PREFIX + "gridMode", value.ToString()); - } - } - - public static void ChangePosSnapDistance(float multiplier) - { - PositionSnapDistance *= multiplier; - } - - public static void ChangeAngSnapDistance(float multiplier) - { - AngleSnapDistance *= multiplier; - } - - public static bool BrushesHidden - { - get - { - return Instance.brushesHidden; - } - set - { + { + get + { + return PlayerPrefs.GetInt(KEY_PREFIX + "ReducedHandleThreshold", 0) != 0; + } + set + { + PlayerPrefs.SetInt(KEY_PREFIX + "ReducedHandleThreshold", value ? 1 : 0); + } + } + + public static float AngleSnapDistance + { + get + { + return PlayerPrefs.GetFloat(KEY_PREFIX + "angleSnapDistance", 15); + } + set + { + if (value > 0) + { + PlayerPrefs.SetFloat(KEY_PREFIX + "angleSnapDistance", value); + } + } + } + + public static Material ForegroundMaterial + { + get + { + return Instance.foregroundMaterial; + } + set + { + Instance.foregroundMaterial = value; + } + } + + public static GridMode GridMode + { + get + { + string storedValue = PlayerPrefs.GetString(KEY_PREFIX + "gridMode"); + if (Enum.IsDefined(typeof(GridMode), storedValue)) + { + return (GridMode)Enum.Parse(typeof(GridMode), storedValue); + } + else + { + return GridMode.SabreCSG; + } + } + set + { + PlayerPrefs.SetString(KEY_PREFIX + "gridMode", value.ToString()); + } + } + + public static void ChangePosSnapDistance(float multiplier) + { + PositionSnapDistance *= multiplier; + } + + public static void ChangeAngSnapDistance(float multiplier) + { + AngleSnapDistance *= multiplier; + } + + public static bool BrushesHidden + { + get + { + return Instance.brushesHidden; + } + set + { Instance.brushesHidden = value; - } - } - - public static bool MeshHidden - { - get - { - return Instance.meshHidden; - } - set - { + } + } + + public static bool MeshHidden + { + get + { + return Instance.meshHidden; + } + set + { Instance.meshHidden = value; - } - } - - // TODO: This behaves differently to just !brushesHidden, need to make the two properties less ambiguous - public static bool BrushesVisible - { - get - { + } + } + + // TODO: This behaves differently to just !brushesHidden, need to make the two properties less ambiguous + public static bool BrushesVisible + { + get + { return !Instance.brushesHidden; - } - } - - public static bool AllowMeshSelection - { - get - { - return false; - } - } - - public static MainMode CurrentMode + } + } + + public static bool AllowMeshSelection + { + get + { + return false; + } + } + + public static MainMode CurrentMode { get { int storedValue = PlayerPrefs.GetInt(KEY_PREFIX + "-CurrentMode", 0); if (storedValue >= Enum.GetNames(typeof(MainMode)).Length || storedValue < 0) - { - return default(MainMode); - } - else - { - return (MainMode)storedValue; - } - } - set - { - PlayerPrefs.SetInt(KEY_PREFIX + "-CurrentMode", (int)value); - // Occassionally have experienced issues where camera locks up, resetting the Tools class seems to fix it - Tools.viewTool = ViewTool.None; - Tools.current = UnityEditor.Tool.None; - } - } - - public static OverrideMode OverrideMode - { - get - { - int storedValue = PlayerPrefs.GetInt(KEY_PREFIX + "-OverrideMode", 0); - - if(storedValue >= Enum.GetNames(typeof(OverrideMode)).Length || storedValue < 0) - { - return default(OverrideMode); - } - else - { - return (OverrideMode)storedValue; - } - } - set - { - PlayerPrefs.SetInt(KEY_PREFIX + "-OverrideMode", (int)value); - // Occassionally have experienced issues where camera locks up, resetting the Tools class seems to fix it - Tools.viewTool = ViewTool.None; - Tools.current = UnityEditor.Tool.None; - } - } - } + { + return default(MainMode); + } + else + { + return (MainMode)storedValue; + } + } + set + { + PlayerPrefs.SetInt(KEY_PREFIX + "-CurrentMode", (int)value); + // Occassionally have experienced issues where camera locks up, resetting the Tools class seems to fix it + Tools.viewTool = ViewTool.None; + Tools.current = UnityEditor.Tool.None; + } + } + + public static OverrideMode OverrideMode + { + get + { + int storedValue = PlayerPrefs.GetInt(KEY_PREFIX + "-OverrideMode", 0); + + if (storedValue >= Enum.GetNames(typeof(OverrideMode)).Length || storedValue < 0) + { + return default(OverrideMode); + } + else + { + return (OverrideMode)storedValue; + } + } + set + { + PlayerPrefs.SetInt(KEY_PREFIX + "-OverrideMode", (int)value); + // Occassionally have experienced issues where camera locks up, resetting the Tools class seems to fix it + Tools.viewTool = ViewTool.None; + Tools.current = UnityEditor.Tool.None; + } + } + } } + #endif \ No newline at end of file diff --git a/Scripts/Editor/Inspectors/BrushBaseInspector.cs b/Scripts/Editor/Inspectors/BrushBaseInspector.cs index 67d30ff2..bca1f7f3 100644 --- a/Scripts/Editor/Inspectors/BrushBaseInspector.cs +++ b/Scripts/Editor/Inspectors/BrushBaseInspector.cs @@ -30,9 +30,58 @@ protected BrushBase[] BrushTargets } } + /// + /// Whether to show the group editor in the inspector. + /// + protected virtual bool ShowGroupInspector { get { return true; } } - public override void OnInspectorGUI() + /// + /// Implement this function to make a custom inspector. + /// + public virtual void DoInspectorGUI() + { + + } + + public sealed override void OnInspectorGUI() { + // group editing: + if (ShowGroupInspector) + { + using (new NamedVerticalScope("Group")) + { + GUILayout.BeginHorizontal(); + + // find whether we are currently inside of a group: + GroupBrush group = null; + if (BrushTarget.transform.parent) + group = BrushTarget.transform.parent.GetComponent(); + + // we are in a group: + if (group != null) + { + if (GUILayout.Button("Select Group")) + { + // select the group. + Selection.objects = new Object[] { BrushTarget.transform.parent.gameObject }; + } + } + + if (GUILayout.Button("Create Group")) + { + // create a group. + TransformHelper.GroupSelection(); + } + + GUILayout.EndHorizontal(); + } + } + + // custom inspector: + DoInspectorGUI(); + + + // generic brush editing: using (new NamedVerticalScope("Order")) { List orderedTargets = BrushTargets.ToList(); diff --git a/Scripts/Editor/Inspectors/BrushGroupInspector.cs b/Scripts/Editor/Inspectors/BrushGroupInspector.cs new file mode 100644 index 00000000..720bf616 --- /dev/null +++ b/Scripts/Editor/Inspectors/BrushGroupInspector.cs @@ -0,0 +1,44 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace Sabresaurus.SabreCSG +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(GroupBrush), true)] + public class BrushGroupInspector : BrushBaseInspector + { + // disable the group editor. + protected override bool ShowGroupInspector { get { return false; } } + + public override void DoInspectorGUI() + { + using (new NamedVerticalScope("Group")) + { + GroupBrush group = (GroupBrush)target; + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button("Select Brushes")) + { + // select all of the child brush objects. + List objects = Selection.objects.ToList(); + objects.Remove(group.gameObject); + foreach (Transform child in group.transform) + if (child.GetComponent()) + objects.Add(child.gameObject); + Selection.objects = objects.ToArray(); + } + + if (GUILayout.Button("Ungroup Brushes")) + { + TransformHelper.UngroupSelection(); + } + + GUILayout.EndHorizontal(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Editor/Inspectors/BrushGroupInspector.cs.meta b/Scripts/Editor/Inspectors/BrushGroupInspector.cs.meta new file mode 100644 index 00000000..defb08e6 --- /dev/null +++ b/Scripts/Editor/Inspectors/BrushGroupInspector.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: e3b003598f23e3946a6b1a9bc44aa4c1 +timeCreated: 1521045582 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Editor/Inspectors/CSGModelInspector.cs b/Scripts/Editor/Inspectors/CSGModelInspector.cs index 72b328fe..7948db4b 100644 --- a/Scripts/Editor/Inspectors/CSGModelInspector.cs +++ b/Scripts/Editor/Inspectors/CSGModelInspector.cs @@ -2,89 +2,95 @@ using System.Collections; using UnityEditor; using System.Collections.Generic; +using System; namespace Sabresaurus.SabreCSG { [CustomEditor(typeof(CSGModel))] public class CSGModelInspector : Editor { - // Build settings for the next build - SerializedProperty generateCollisionMeshesProperty; - SerializedProperty generateTangentsProperty; - SerializedProperty optimizeGeometryProperty; - SerializedProperty saveMeshesAsAssetsProperty; - SerializedProperty generateLightmapUVsProperty; - - SerializedProperty unwrapAngleErrorProperty; - SerializedProperty unwrapAreaErrorProperty; - SerializedProperty unwrapHardAngleProperty; - SerializedProperty unwrapPackMarginProperty; - - SerializedProperty shadowCastingModeProperty; - - SerializedProperty defaultPhysicsMaterialProperty; - SerializedProperty defaultVisualMaterialProperty; - - // Build settings from the last build - SerializedProperty lastBuildDefaultPhysicsMaterialProperty; - SerializedProperty lastBuildDefaultVisualMaterialProperty; - - public void OnEnable() - { - // Build settings for the next build - generateCollisionMeshesProperty = serializedObject.FindProperty("buildSettings.GenerateCollisionMeshes"); - generateTangentsProperty = serializedObject.FindProperty("buildSettings.GenerateTangents"); + // Build settings for the next build + + private SerializedProperty generateCollisionMeshesProperty; + private SerializedProperty generateTangentsProperty; + private SerializedProperty optimizeGeometryProperty; + private SerializedProperty saveMeshesAsAssetsProperty; + private SerializedProperty generateLightmapUVsProperty; + + private SerializedProperty unwrapAngleErrorProperty; + private SerializedProperty unwrapAreaErrorProperty; + private SerializedProperty unwrapHardAngleProperty; + private SerializedProperty unwrapPackMarginProperty; + + private SerializedProperty shadowCastingModeProperty; + + private SerializedProperty defaultPhysicsMaterialProperty; + private SerializedProperty defaultVisualMaterialProperty; + + // Build settings from the last build + + private SerializedProperty lastBuildDefaultPhysicsMaterialProperty; + private SerializedProperty lastBuildDefaultVisualMaterialProperty; + + // Temporary importer settings. + + private static int importerValveMapFormatScale = 32; + private static int importerUnrealGoldScale = 64; + + public void OnEnable() + { + // Build settings for the next build + generateCollisionMeshesProperty = serializedObject.FindProperty("buildSettings.GenerateCollisionMeshes"); + generateTangentsProperty = serializedObject.FindProperty("buildSettings.GenerateTangents"); optimizeGeometryProperty = serializedObject.FindProperty("buildSettings.OptimizeGeometry"); saveMeshesAsAssetsProperty = serializedObject.FindProperty("buildSettings.SaveMeshesAsAssets"); - generateLightmapUVsProperty = serializedObject.FindProperty("buildSettings.GenerateLightmapUVs"); + generateLightmapUVsProperty = serializedObject.FindProperty("buildSettings.GenerateLightmapUVs"); - unwrapAngleErrorProperty = serializedObject.FindProperty("buildSettings.UnwrapAngleError"); - unwrapAreaErrorProperty = serializedObject.FindProperty("buildSettings.UnwrapAreaError"); - unwrapHardAngleProperty = serializedObject.FindProperty("buildSettings.UnwrapHardAngle"); + unwrapAngleErrorProperty = serializedObject.FindProperty("buildSettings.UnwrapAngleError"); + unwrapAreaErrorProperty = serializedObject.FindProperty("buildSettings.UnwrapAreaError"); + unwrapHardAngleProperty = serializedObject.FindProperty("buildSettings.UnwrapHardAngle"); unwrapPackMarginProperty = serializedObject.FindProperty("buildSettings.UnwrapPackMargin"); - + shadowCastingModeProperty = serializedObject.FindProperty("buildSettings.ShadowCastingMode"); - defaultPhysicsMaterialProperty = serializedObject.FindProperty("buildSettings.DefaultPhysicsMaterial"); - defaultVisualMaterialProperty = serializedObject.FindProperty("buildSettings.DefaultVisualMaterial"); + defaultPhysicsMaterialProperty = serializedObject.FindProperty("buildSettings.DefaultPhysicsMaterial"); + defaultVisualMaterialProperty = serializedObject.FindProperty("buildSettings.DefaultVisualMaterial"); - // Build settings from the last build - lastBuildDefaultPhysicsMaterialProperty = serializedObject.FindProperty("lastBuildSettings.DefaultPhysicsMaterial"); - lastBuildDefaultVisualMaterialProperty = serializedObject.FindProperty("lastBuildSettings.DefaultVisualMaterial"); - } + // Build settings from the last build + lastBuildDefaultPhysicsMaterialProperty = serializedObject.FindProperty("lastBuildSettings.DefaultPhysicsMaterial"); + lastBuildDefaultVisualMaterialProperty = serializedObject.FindProperty("lastBuildSettings.DefaultVisualMaterial"); + } public override void OnInspectorGUI() { - CSGModel csgModel = (CSGModel)target; + CSGModel csgModel = (CSGModel)target; - // Ensure the default material is set - csgModel.EnsureDefaultMaterialSet(); + // Ensure the default material is set + csgModel.EnsureDefaultMaterialSet(); - DrawDefaultInspector(); + DrawDefaultInspector(); - this.serializedObject.Update(); - using (new NamedVerticalScope("Build Settings")) - { - EditorGUIUtility.fieldWidth = 0; - EditorGUIUtility.labelWidth = 160; + this.serializedObject.Update(); + using (new NamedVerticalScope("Build Settings")) + { + EditorGUIUtility.fieldWidth = 0; + EditorGUIUtility.labelWidth = 160; - EditorGUILayout.PropertyField(generateCollisionMeshesProperty, new GUIContent("Generate Collision Meshes")); - EditorGUILayout.PropertyField(generateTangentsProperty, new GUIContent("Generate Tangents")); - + EditorGUILayout.PropertyField(generateCollisionMeshesProperty, new GUIContent("Generate Collision Meshes")); + EditorGUILayout.PropertyField(generateTangentsProperty, new GUIContent("Generate Tangents")); EditorGUILayout.PropertyField(generateLightmapUVsProperty, new GUIContent("Generate Lightmap UVs")); - EditorGUIUtility.labelWidth = 125; - + EditorGUIUtility.labelWidth = 125; - GUI.enabled = generateLightmapUVsProperty.boolValue; - EditorGUI.indentLevel = 1; - EditorGUILayout.PropertyField(unwrapAngleErrorProperty, new GUIContent("Unwrap Angle Error")); - EditorGUILayout.PropertyField(unwrapAreaErrorProperty, new GUIContent("Unwrap Area Error")); - EditorGUILayout.PropertyField(unwrapHardAngleProperty, new GUIContent("Unwrap Hard Angle")); - EditorGUILayout.PropertyField(unwrapPackMarginProperty, new GUIContent("Unwrap Pack Margin")); - EditorGUI.indentLevel = 0; - EditorGUIUtility.labelWidth = 0; - GUI.enabled = true; + GUI.enabled = generateLightmapUVsProperty.boolValue; + EditorGUI.indentLevel = 1; + EditorGUILayout.PropertyField(unwrapAngleErrorProperty, new GUIContent("Unwrap Angle Error")); + EditorGUILayout.PropertyField(unwrapAreaErrorProperty, new GUIContent("Unwrap Area Error")); + EditorGUILayout.PropertyField(unwrapHardAngleProperty, new GUIContent("Unwrap Hard Angle")); + EditorGUILayout.PropertyField(unwrapPackMarginProperty, new GUIContent("Unwrap Pack Margin")); + EditorGUI.indentLevel = 0; + EditorGUIUtility.labelWidth = 0; + GUI.enabled = true; EditorGUILayout.PropertyField(shadowCastingModeProperty, new GUIContent("Shadow Casting Mode")); @@ -97,189 +103,296 @@ public override void OnInspectorGUI() EditorGUI.indentLevel = 0; } - using (new NamedVerticalScope("Default Material")) - { - PhysicMaterial lastPhysicsMaterial = defaultPhysicsMaterialProperty.objectReferenceValue as PhysicMaterial; - - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(defaultPhysicsMaterialProperty, new GUIContent("Default Physics Material")); - if(EditorGUI.EndChangeCheck()) - { - PhysicMaterial newPhysicsMaterial = defaultPhysicsMaterialProperty.objectReferenceValue as PhysicMaterial; - - // Update the built mesh colliders that use the old material - UpdatePhysicsMaterial(lastPhysicsMaterial, newPhysicsMaterial); - } - - // Track the last visual material, so that if the user changes it we can update built renderers instantly - Material lastVisualMaterial = defaultVisualMaterialProperty.objectReferenceValue as Material; - - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(defaultVisualMaterialProperty, new GUIContent("Default Visual Material")); - if(EditorGUI.EndChangeCheck()) - { - // User has changed the material, so grab the new material - Material newVisualMaterial = defaultVisualMaterialProperty.objectReferenceValue as Material; - // EnsureDefaultMaterialSet hasn't had a chance to run yet, so make sure we have a solid material reference - if(newVisualMaterial == null) - { - newVisualMaterial = csgModel.GetDefaultFallbackMaterial(); - defaultVisualMaterialProperty.objectReferenceValue = newVisualMaterial; - } - - // Update the built renderers that use the old material, also update source brush polygons - UpdateVisualMaterial(lastVisualMaterial, newVisualMaterial); - - // Update the last build's default material because we don't need to build again - lastBuildDefaultVisualMaterialProperty.objectReferenceValue = newVisualMaterial; - } - - EditorGUILayout.BeginHorizontal(); - if(GUILayout.Button("Lit Texture (No Tint)")) - { - Material newVisualMaterial = AssetDatabase.LoadMainAssetAtPath(CSGModel.GetSabreCSGPath() + "Resources/Materials/Default_Map.mat") as Material; - SetVisualMaterial(lastVisualMaterial, newVisualMaterial); - } - if(GUILayout.Button("Lit Vertex Tint")) - { - Material newVisualMaterial = AssetDatabase.LoadMainAssetAtPath(CSGModel.GetSabreCSGPath() + "Resources/Materials/Default_LitWithTint.mat") as Material; - SetVisualMaterial(lastVisualMaterial, newVisualMaterial); - } - EditorGUILayout.EndHorizontal(); - - EditorGUILayout.BeginHorizontal(); - if(GUILayout.Button("Unlit Vertex Color")) - { - Material newVisualMaterial = AssetDatabase.LoadMainAssetAtPath(CSGModel.GetSabreCSGPath() + "Resources/Materials/Default_VertexColor.mat") as Material; - SetVisualMaterial(lastVisualMaterial, newVisualMaterial); - } - if(GUILayout.Button("Lit Vertex Color")) - { - Material newVisualMaterial = AssetDatabase.LoadMainAssetAtPath(CSGModel.GetSabreCSGPath() + "Resources/Materials/Default_VertexColorLit.mat") as Material; - SetVisualMaterial(lastVisualMaterial, newVisualMaterial); - } - EditorGUILayout.EndHorizontal(); - } - - using (new NamedVerticalScope("Export")) - { - if(GUILayout.Button("Export All To OBJ")) - { - csgModel.ExportOBJ(false); - } - - if (GUILayout.Button("Export Selected To OBJ")) - { - csgModel.ExportOBJ(true); - } - } - - using (new NamedVerticalScope("Stats")) - { - BuildMetrics buildMetrics = csgModel.BuildMetrics; - - GUILayout.Label("Vertices: " + buildMetrics.TotalVertices); - GUILayout.Label("Triangles: " + buildMetrics.TotalTriangles); - GUILayout.Label("Meshes: " + buildMetrics.TotalMeshes); - GUILayout.Label("Build Time: " + buildMetrics.BuildTime.ToString()); - } - - // Make sure any serialize property changes are committed to the underlying Unity Object - bool anyApplied = this.serializedObject.ApplyModifiedProperties(); - - if(anyApplied) - { - // Make sure that nothing else is included in the Undo, as an immediate rebuild may take place and - // we don't want the rebuild's lastBuildSettings being included in the undo step - Undo.IncrementCurrentGroup(); - } + using (new NamedVerticalScope("Default Material")) + { + PhysicMaterial lastPhysicsMaterial = defaultPhysicsMaterialProperty.objectReferenceValue as PhysicMaterial; + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(defaultPhysicsMaterialProperty, new GUIContent("Default Physics Material")); + if (EditorGUI.EndChangeCheck()) + { + PhysicMaterial newPhysicsMaterial = defaultPhysicsMaterialProperty.objectReferenceValue as PhysicMaterial; + + // Update the built mesh colliders that use the old material + UpdatePhysicsMaterial(lastPhysicsMaterial, newPhysicsMaterial); + } + + // Track the last visual material, so that if the user changes it we can update built renderers instantly + Material lastVisualMaterial = defaultVisualMaterialProperty.objectReferenceValue as Material; + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(defaultVisualMaterialProperty, new GUIContent("Default Visual Material")); + if (EditorGUI.EndChangeCheck()) + { + // User has changed the material, so grab the new material + Material newVisualMaterial = defaultVisualMaterialProperty.objectReferenceValue as Material; + // EnsureDefaultMaterialSet hasn't had a chance to run yet, so make sure we have a solid material reference + if (newVisualMaterial == null) + { + newVisualMaterial = csgModel.GetDefaultFallbackMaterial(); + defaultVisualMaterialProperty.objectReferenceValue = newVisualMaterial; + } + + // Update the built renderers that use the old material, also update source brush polygons + UpdateVisualMaterial(lastVisualMaterial, newVisualMaterial); + + // Update the last build's default material because we don't need to build again + lastBuildDefaultVisualMaterialProperty.objectReferenceValue = newVisualMaterial; + } + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Lit Texture (No Tint)")) + { + Material newVisualMaterial = AssetDatabase.LoadMainAssetAtPath(CSGModel.GetSabreCSGPath() + "Resources/Materials/Default_Map.mat") as Material; + SetVisualMaterial(lastVisualMaterial, newVisualMaterial); + } + if (GUILayout.Button("Lit Vertex Tint")) + { + Material newVisualMaterial = AssetDatabase.LoadMainAssetAtPath(CSGModel.GetSabreCSGPath() + "Resources/Materials/Default_LitWithTint.mat") as Material; + SetVisualMaterial(lastVisualMaterial, newVisualMaterial); + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Unlit Vertex Color")) + { + Material newVisualMaterial = AssetDatabase.LoadMainAssetAtPath(CSGModel.GetSabreCSGPath() + "Resources/Materials/Default_VertexColor.mat") as Material; + SetVisualMaterial(lastVisualMaterial, newVisualMaterial); + } + if (GUILayout.Button("Lit Vertex Color")) + { + Material newVisualMaterial = AssetDatabase.LoadMainAssetAtPath(CSGModel.GetSabreCSGPath() + "Resources/Materials/Default_VertexColorLit.mat") as Material; + SetVisualMaterial(lastVisualMaterial, newVisualMaterial); + } + EditorGUILayout.EndHorizontal(); + } + + using (new NamedVerticalScope("Export")) + { + if (GUILayout.Button("Export All To OBJ")) + { + csgModel.ExportOBJ(false); + } + + if (GUILayout.Button("Export Selected To OBJ")) + { + csgModel.ExportOBJ(true); + } + } + + using (new NamedVerticalScope("Import")) + { + GuiLayoutBeginImporterSection(SabreCSGResources.ImporterUnrealGoldTexture, "Unreal Gold Importer", "Henry de Jongh"); + + importerUnrealGoldScale = EditorGUILayout.IntField("Scale", importerUnrealGoldScale); + if (importerUnrealGoldScale < 1) importerUnrealGoldScale = 1; + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Import Unreal Gold Map (*.t3d)")) + { + try + { + string path = EditorUtility.OpenFilePanel("Import Unreal Gold Map", "", "t3d"); + if (path.Length != 0) + { + EditorUtility.DisplayProgressBar("SabreCSG: Importing Unreal Gold Map", "Parsing Unreal Text File (*.t3d)...", 0.0f); + var importer = new Importers.UnrealGold.T3dImporter(); + var map = importer.Import(path); + Importers.UnrealGold.T3dMapConverter.Import(csgModel, map, importerUnrealGoldScale); + } + } + catch (Exception ex) + { + EditorUtility.ClearProgressBar(); + EditorUtility.DisplayDialog("Unreal Gold Map Import", "An exception occurred while importing the map:\r\n" + ex.Message, "Ohno!"); + } + } + if (GUILayout.Button("?", GUILayout.Width(16))) + { + EditorUtility.DisplayDialog("Unreal Gold Importer", "This importer was created using Unreal Gold 227 (http://oldunreal.com/).\n\nImportant Notes:\n* It will try to find the materials in your project automatically. First it looks for the full name like 'PlayrShp.Ceiling.Hullwk' then the last word 'Hullwk'. The latter option could cause some false positives, try creating a material with the full name if this happens.\n* This importer requires you to place a massive additive cube around your whole level as Unreal Editor uses the subtractive workflow.\n\nKnown Issues:\n* Concave brushes may cause corruptions.", "Okay"); + } + EditorGUILayout.EndHorizontal(); + GuiLayoutEndImporterSection(); + + // + EditorGUILayout.Space(); + // + + GuiLayoutBeginImporterSection(SabreCSGResources.ImporterImporterValveMapFormat2006Texture, "Source Engine 2006 Importer", "Henry de Jongh"); + + importerValveMapFormatScale = EditorGUILayout.IntField("Scale", importerValveMapFormatScale); + if (importerValveMapFormatScale < 1) importerValveMapFormatScale = 1; + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Import Source Engine Map (*.vmf)")) + { + try + { + string path = EditorUtility.OpenFilePanel("Import Source Engine Map", "", "vmf"); + if (path.Length != 0) + { + EditorUtility.DisplayProgressBar("SabreCSG: Importing Source Engine Map", "Parsing Valve Map Format File (*.vmf)...", 0.0f); + var importer = new Importers.ValveMapFormat2006.VmfImporter(); + var map = importer.Import(path); + Importers.ValveMapFormat2006.VmfWorldConverter.Import(csgModel, map, importerValveMapFormatScale); + } + } + catch (Exception ex) + { + EditorUtility.ClearProgressBar(); + EditorUtility.DisplayDialog("Source Engine Map Import", "An exception occurred while importing the map:\r\n" + ex.Message + ex.StackTrace, "Ohno!"); + } + } + + if (GUILayout.Button("?", GUILayout.Width(16))) + { + EditorUtility.DisplayDialog("Source Engine 2006 Importer", "This importer was created using Source SDK maps and Hammer 4.1.\n\nImportant Notes:\n* It will try to find the materials in your project automatically. First it looks for the full name with forward slashes '/' replaced by periods '.' like 'BRICK.BRICKFLOOR001A' then the last word 'BRICKFLOOR001A'. The latter option could cause some false positives, try creating a material with the full name if this happens.\n\nKnown Issues:\n* Some UVs' panning appears to be completely off but I have been unable to replicate it. If anyone knows why it happens please do contact me!", "Okay"); + } + EditorGUILayout.EndHorizontal(); + + GuiLayoutEndImporterSection(); + } + + using (new NamedVerticalScope("Stats")) + { + BuildMetrics buildMetrics = csgModel.BuildMetrics; + + GUILayout.Label("Vertices: " + buildMetrics.TotalVertices); + GUILayout.Label("Triangles: " + buildMetrics.TotalTriangles); + GUILayout.Label("Meshes: " + buildMetrics.TotalMeshes); + GUILayout.Label("Build Time: " + buildMetrics.BuildTime.ToString()); + } + + // Make sure any serialize property changes are committed to the underlying Unity Object + bool anyApplied = this.serializedObject.ApplyModifiedProperties(); + + if (anyApplied) + { + // Make sure that nothing else is included in the Undo, as an immediate rebuild may take place and + // we don't want the rebuild's lastBuildSettings being included in the undo step + Undo.IncrementCurrentGroup(); + } + } + + private void SetVisualMaterial(Material lastVisualMaterial, Material newVisualMaterial) + { + // EnsureDefaultMaterialSet hasn't had a chance to run yet, so make sure we have a solid material reference + if (newVisualMaterial == null) + { + CSGModel csgModel = (CSGModel)target; + newVisualMaterial = csgModel.GetDefaultFallbackMaterial(); + } + + // Update the built renderers that use the old material, also update source brush polygons + UpdateVisualMaterial(lastVisualMaterial, newVisualMaterial); + + defaultVisualMaterialProperty.objectReferenceValue = newVisualMaterial; + // Update the last build's default material because we don't need to build again + lastBuildDefaultVisualMaterialProperty.objectReferenceValue = newVisualMaterial; + } + + private void UpdateVisualMaterial(Material oldMaterial, Material newMaterial) + { + // If the material has changed and the new material is not null + if (newMaterial != oldMaterial && newMaterial != null) + { + CSGModel csgModel = (CSGModel)target; + + // Update the built mesh renderers that use the old material + Transform meshGroup = csgModel.GetMeshGroupTransform(); + + if (meshGroup != null) + { + MeshRenderer[] meshRenderers = meshGroup.GetComponentsInChildren(); + for (int i = 0; i < meshRenderers.Length; i++) + { + if (meshRenderers[i].sharedMaterial == oldMaterial) + { + meshRenderers[i].sharedMaterial = newMaterial; + } + } + } + + // Update all the polygons in the source brushes + List brushes = csgModel.GetBrushes(); + for (int i = 0; i < brushes.Count; i++) + { + if (brushes[i] != null) // Make sure the tracked brush still exists + { + Polygon[] polygons = brushes[i].GetPolygons(); + for (int j = 0; j < polygons.Length; j++) + { + // If the polygon uses the old material (as an override) + if (polygons[j].Material == oldMaterial) + { + // Set the polygon to null, this removes the material override which gives consistent behaviour + polygons[j].Material = null; + } + } + } + } + } + } + + private void UpdatePhysicsMaterial(PhysicMaterial oldMaterial, PhysicMaterial newMaterial) + { + // If the physics material has changed + if (newMaterial != oldMaterial) + { + CSGModel csgModel = (CSGModel)target; + + // Update the built mesh renderers that use the old material + Transform meshGroup = csgModel.GetMeshGroupTransform(); + + if (meshGroup != null) + { + MeshCollider[] meshColliders = meshGroup.GetComponentsInChildren(); + for (int i = 0; i < meshColliders.Length; i++) + { + if (meshColliders[i].sharedMaterial == oldMaterial) + { + meshColliders[i].sharedMaterial = newMaterial; + } + } + } + + // Update the last build's default material because we don't need to build again + lastBuildDefaultPhysicsMaterialProperty.objectReferenceValue = newMaterial; + } + } + + private void GuiLayoutBeginImporterSection(Texture2D icon, string title, string author) + { + GUIStyle style = new GUIStyle(); + style.normal.background = SabreCSGResources.ImporterBackgroundTexture; + + EditorGUILayout.BeginVertical(style); + EditorGUILayout.BeginHorizontal(); + + GUILayout.Label(icon); + + EditorGUILayout.BeginVertical(); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.Label(title, SabreGUILayout.GetTitleStyle()); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.Label("Author: " + author); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + EditorGUILayout.EndVertical(); + + EditorGUILayout.EndHorizontal(); } - private void SetVisualMaterial(Material lastVisualMaterial, Material newVisualMaterial) - { - // EnsureDefaultMaterialSet hasn't had a chance to run yet, so make sure we have a solid material reference - if(newVisualMaterial == null) - { - CSGModel csgModel = (CSGModel)target; - newVisualMaterial = csgModel.GetDefaultFallbackMaterial(); - } - - // Update the built renderers that use the old material, also update source brush polygons - UpdateVisualMaterial(lastVisualMaterial, newVisualMaterial); - - defaultVisualMaterialProperty.objectReferenceValue = newVisualMaterial; - // Update the last build's default material because we don't need to build again - lastBuildDefaultVisualMaterialProperty.objectReferenceValue = newVisualMaterial; - } - - private void UpdateVisualMaterial(Material oldMaterial, Material newMaterial) - { - // If the material has changed and the new material is not null - if(newMaterial != oldMaterial && newMaterial != null) - { - CSGModel csgModel = (CSGModel)target; - - // Update the built mesh renderers that use the old material - Transform meshGroup = csgModel.GetMeshGroupTransform(); - - if(meshGroup != null) - { - MeshRenderer[] meshRenderers = meshGroup.GetComponentsInChildren(); - for (int i = 0; i < meshRenderers.Length; i++) - { - if(meshRenderers[i].sharedMaterial == oldMaterial) - { - meshRenderers[i].sharedMaterial = newMaterial; - } - } - } - - // Update all the polygons in the source brushes - List brushes = csgModel.GetBrushes(); - for (int i = 0; i < brushes.Count; i++) - { - if(brushes[i] != null) // Make sure the tracked brush still exists - { - Polygon[] polygons = brushes[i].GetPolygons(); - for (int j = 0; j < polygons.Length; j++) - { - // If the polygon uses the old material (as an override) - if(polygons[j].Material == oldMaterial) - { - // Set the polygon to null, this removes the material override which gives consistent behaviour - polygons[j].Material = null; - } - } - } - } - } - } - - private void UpdatePhysicsMaterial(PhysicMaterial oldMaterial, PhysicMaterial newMaterial) - { - // If the physics material has changed - if(newMaterial != oldMaterial) - { - CSGModel csgModel = (CSGModel)target; - - // Update the built mesh renderers that use the old material - Transform meshGroup = csgModel.GetMeshGroupTransform(); - - if(meshGroup != null) - { - MeshCollider[] meshColliders = meshGroup.GetComponentsInChildren(); - for (int i = 0; i < meshColliders.Length; i++) - { - if(meshColliders[i].sharedMaterial == oldMaterial) - { - meshColliders[i].sharedMaterial = newMaterial; - } - } - } - - // Update the last build's default material because we don't need to build again - lastBuildDefaultPhysicsMaterialProperty.objectReferenceValue = newMaterial; - } - } + private void GuiLayoutEndImporterSection() + { + EditorGUILayout.EndVertical(); + } } } \ No newline at end of file diff --git a/Scripts/Editor/Inspectors/CompoundBrushInspector.cs b/Scripts/Editor/Inspectors/CompoundBrushInspector.cs index d3d7e74c..d3d70f58 100644 --- a/Scripts/Editor/Inspectors/CompoundBrushInspector.cs +++ b/Scripts/Editor/Inspectors/CompoundBrushInspector.cs @@ -15,7 +15,7 @@ public class CompoundBrushInspector : BrushBaseInspector // base.OnEnable (); // } // - public override void OnInspectorGUI() + public override void DoInspectorGUI() { using (new NamedVerticalScope("Compound")) { @@ -28,7 +28,7 @@ public override void OnInspectorGUI() } } - base.OnInspectorGUI(); + base.DoInspectorGUI(); } } } \ No newline at end of file diff --git a/Scripts/Editor/Inspectors/PrimitiveBrushInspector.cs b/Scripts/Editor/Inspectors/PrimitiveBrushInspector.cs index f01f847d..603dd9a4 100644 --- a/Scripts/Editor/Inspectors/PrimitiveBrushInspector.cs +++ b/Scripts/Editor/Inspectors/PrimitiveBrushInspector.cs @@ -111,9 +111,9 @@ void DrawBrushButton(PrimitiveBrushType brushType, PrimitiveBrushType? activeTyp GUI.Label(lastRect, name, labelStyle); } - public override void OnInspectorGUI() + public override void DoInspectorGUI() { - float drawableWidth = EditorGUIUtility.currentViewWidth; + float drawableWidth = EditorGUIUtility.currentViewWidth; drawableWidth -= 42; // Take some off for scroll bars and padding PrimitiveBrushType[] selectedTypes = BrushTargets.Select(item => ((PrimitiveBrush)item).BrushType).ToArray(); @@ -403,7 +403,7 @@ public override void OnInspectorGUI() //} } - base.OnInspectorGUI(); + base.DoInspectorGUI(); } /// diff --git a/Scripts/Extensions/EditorHelper.cs b/Scripts/Extensions/EditorHelper.cs index dee1c592..511c4137 100644 --- a/Scripts/Extensions/EditorHelper.cs +++ b/Scripts/Extensions/EditorHelper.cs @@ -373,9 +373,11 @@ public static bool DuplicateSelection() Unsupported.DuplicateGameObjectsUsingPasteboard(); // Cache the new entry, so when we're done we reselect all new objects newObjects[i] = Selection.activeGameObject; - } - // Finished duplicating, select all new objects - Selection.objects = newObjects; + // Remove the 'Brush (1)', 'Brush (2)', etc. from the name. + newObjects[i].name = Regex.Replace(newObjects[i].name, " \\(\\d+\\)$", ""); + } + // Finished duplicating, select all new objects + Selection.objects = newObjects; } // Whether custom duplication took place and whether the Duplicate event should be consumed diff --git a/Scripts/Extensions/Extensions.cs b/Scripts/Extensions/Extensions.cs index abfff1c6..0c366006 100644 --- a/Scripts/Extensions/Extensions.cs +++ b/Scripts/Extensions/Extensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Text; using UnityEngine; @@ -413,5 +414,19 @@ internal static bool ContainsApproximate(this Bounds bounds1, Vector3 point) && point.y < bounds1.max.y + EPSILON_LOWER_2 && point.z < bounds1.max.z + EPSILON_LOWER_2); } + + /// + /// Creates a beautiful string that matches the numbers shown in the resize tool. + /// Used in the hierarchy. + /// + /// The bounds 'this' reference. + /// The beautiful string. + internal static string ToGeneratedHierarchyString(this Bounds bounds) + { + string x = MathHelper.RoundFloat(bounds.size.x, 0.0001f).ToString(CultureInfo.InvariantCulture); + string y = MathHelper.RoundFloat(bounds.size.y, 0.0001f).ToString(CultureInfo.InvariantCulture); + string z = MathHelper.RoundFloat(bounds.size.z, 0.0001f).ToString(CultureInfo.InvariantCulture); + return x + " x " + y + " x " + z; + } } } \ No newline at end of file diff --git a/Scripts/Extensions/TransformHelper.cs b/Scripts/Extensions/TransformHelper.cs index 20552e3f..7f4827a8 100644 --- a/Scripts/Extensions/TransformHelper.cs +++ b/Scripts/Extensions/TransformHelper.cs @@ -58,7 +58,8 @@ public static void GroupSelection() } // Create group - GameObject groupObject = new GameObject("Group"); + GameObject groupObject = new GameObject(""); + GroupBrush groupBrush = groupObject.AddComponent(); Undo.RegisterCreatedObjectUndo (groupObject, "Group"); Undo.SetTransformParent(groupObject.transform, rootTransform, "Group"); @@ -74,6 +75,9 @@ public static void GroupSelection() Undo.SetTransformParent(selectedTransforms[i], groupObject.transform, "Group"); } + // Ensure it gets a correct name in the hierarchy. + groupBrush.UpdateGeneratedHierarchyName(); + Selection.activeGameObject = groupObject; // EditorApplication.RepaintHierarchyWindow(); // SceneView.RepaintAll(); @@ -82,7 +86,7 @@ public static void GroupSelection() public static void UngroupSelection() { - if(Selection.activeTransform != null && Selection.activeGameObject.GetComponents().Length == 0) + if (Selection.activeTransform != null && Selection.activeGameObject.GetComponent()) { Transform rootTransform = Selection.activeTransform.parent; int siblingIndex = Selection.activeTransform.GetSiblingIndex(); diff --git a/Scripts/Geometry/BrushFactory.cs b/Scripts/Geometry/BrushFactory.cs index bcc3e895..4104e332 100644 --- a/Scripts/Geometry/BrushFactory.cs +++ b/Scripts/Geometry/BrushFactory.cs @@ -674,6 +674,71 @@ public static void GenerateMeshFromPolygons(Polygon[] polygons, ref Mesh mesh, o mesh.uv = uvs.ToArray(); mesh.triangles = triangles.ToArray(); } - } + + /// + /// Generates a mesh from the supplied polygons. particularly useful for visualising a + /// brush's polygons on a MeshFilter. This method can optionally displace the vertices along + /// the normal slightly. This is a faster method than as it doesn't + /// generate optimized indices. + /// + /// The polygons to be triangulated. + /// + /// Mesh to be written to. If the existing mesh is null it will be set to a new one, + /// otherwise the existing mesh is cleared. + /// + /// The amount of vertex displacement. + public static void GenerateMeshFromPolygonsFast(Polygon[] polygons, ref Mesh mesh, float displacement) + { + if (mesh == null) + { + mesh = new Mesh(); + } + mesh.Clear(); + + int vertexIndex = 0; + int vertexCount = 0; + for (int i = 0; i < polygons.Length; i++) + vertexCount += polygons[i].Vertices.Length * 3; + + Vector3[] vertices = new Vector3[vertexCount]; + Vector3[] normals = new Vector3[vertexCount]; + Vector2[] uvs = new Vector2[vertexCount]; + int[] triangles = new int[vertexCount]; + int tri = 0; + + // Iterate through every polygon and triangulate + int offset = 0; + for (int i = 0; i < polygons.Length; i++) + { + Polygon polygon = polygons[i]; + offset += polygon.Vertices.Length; + + for (int j = 0; j < polygon.Vertices.Length; j++) + { + Vertex v = polygon.Vertices[j]; + vertices[vertexIndex] = v.Position + v.Normal * displacement; + normals[vertexIndex] = v.Normal; + uvs[vertexIndex] = v.UV; + vertexIndex++; + } + + // Triangulate the n-sided polygon and allow vertex reuse by using indexed geometry + for (int j = 2; j < polygon.Vertices.Length; j++) + { + int start = offset - polygon.Vertices.Length; + triangles[tri] = start; tri++; + triangles[tri] = start + j - 1; tri++; + triangles[tri] = start + j; tri++; + } + } + + // Set the mesh buffers + mesh.vertices = vertices; + mesh.normals = normals; + mesh.uv = uvs; + mesh.triangles = triangles; + } + } } #endif \ No newline at end of file diff --git a/Scripts/Importers.meta b/Scripts/Importers.meta new file mode 100644 index 00000000..a48dbb42 --- /dev/null +++ b/Scripts/Importers.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8fab114c07a5e6449a4d3595f8831d94 +folderAsset: yes +timeCreated: 1526493642 +licenseType: Free +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/UnrealGold.meta b/Scripts/Importers/UnrealGold.meta new file mode 100644 index 00000000..60b1fd0e --- /dev/null +++ b/Scripts/Importers/UnrealGold.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c5cc3a1a20a462143840efff01f3014f +folderAsset: yes +timeCreated: 1526493642 +licenseType: Free +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/UnrealGold/T3dActor.cs b/Scripts/Importers/UnrealGold/T3dActor.cs new file mode 100644 index 00000000..3a96bf1f --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dActor.cs @@ -0,0 +1,170 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Sabresaurus.SabreCSG.Importers.UnrealGold +{ + /// + /// Represents an Unreal Editor 1 Actor. + /// + public class T3dActor + { + /// + /// Gets the class of the actor. + /// + /// The class of the actor. + public string Class /*{ get; }*/; + + /// + /// Gets the name of the actor. + /// + /// The name of the actor. + public string Name /*{ get; }*/; + + /// + /// Gets the actor properties. + /// + /// The actor properties. + public Dictionary Properties /*{ get; }*/ = new Dictionary(); + + /// + /// The T3D map this actor is a part of. + /// + private T3dMap m_T3dMap; + + /// + /// Gets the location of the actor. + /// + /// The location of the actor. + public T3dVector3 Location + { + get + { + object value; + if (Properties.TryGetValue("Location", out value)) + return value as T3dVector3; + return new T3dVector3(); + } + } + + /// + /// Gets the rotation of the actor. + /// + /// The rotation of the actor. + public T3dRotator Rotation + { + get + { + object value; + if (Properties.TryGetValue("Rotation", out value)) + return value as T3dRotator; + return new T3dRotator(); + } + } + + /// + /// Gets the main scale of the actor. + /// + /// The main scale of the actor. + public T3dVector3 MainScale + { + get + { + object value; + if (Properties.TryGetValue("MainScale", out value)) + return value as T3dVector3; + return new T3dVector3(1.0f, 1.0f, 1.0f); + } + } + + /// + /// Gets the post scale of the actor. + /// + /// The post scale of the actor. + public T3dVector3 PostScale + { + get + { + object value; + if (Properties.TryGetValue("PostScale", out value)) + return value as T3dVector3; + return new T3dVector3(1.0f, 1.0f, 1.0f); + } + } + + /// + /// Gets the pre pivot of the actor. + /// + /// The pre pivot of the actor. + public T3dVector3 PrePivot + { + get + { + object value; + if (Properties.TryGetValue("PrePivot", out value)) + return value as T3dVector3; + return new T3dVector3(0.0f, 0.0f, 0.0f); + } + } + + /// + /// Gets the brush name. + /// + /// + /// The brush name. + /// + public string BrushName + { + get + { + object value; + if (Properties.TryGetValue("Brush", out value)) + { + string brush = (string)value; + int i = brush.IndexOf('.'); + return brush.Substring(i + 1, brush.Length - i - 2); + } + return null; + } + } + + /// + /// Gets the brush associated with the actor. + /// + /// + /// The brush associated with the actor. + /// + public T3dBrush Brush + { + get + { + return m_T3dMap.BrushModels.FirstOrDefault(b => b.Name == BrushName); + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The class of the actor. + /// The name of the actor. + public T3dActor(T3dMap map, string @class, string name) + { + m_T3dMap = map; + Class = @class; + Name = name; + } + + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() + { + return "Unreal Engine 1 " + Class + " \"" + Name + "\""; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/UnrealGold/T3dActor.cs.meta b/Scripts/Importers/UnrealGold/T3dActor.cs.meta new file mode 100644 index 00000000..60b81c3b --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dActor.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: dc73adff2c2d6f84a8bf3fd59bdcb4a4 +timeCreated: 1526493642 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/UnrealGold/T3dBrush.cs b/Scripts/Importers/UnrealGold/T3dBrush.cs new file mode 100644 index 00000000..3969a418 --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dBrush.cs @@ -0,0 +1,45 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; +using System.Collections.Generic; + +namespace Sabresaurus.SabreCSG.Importers.UnrealGold +{ + /// + /// Represents an Unreal Editor 1 brush. + /// + public class T3dBrush + { + /// + /// Gets the name of the brush. + /// + /// The name of the brush. + public string Name /*{ get; }*/; + + /// + /// Gets or sets the brush polygons. + /// + /// The brush polygons. + public List Polygons /*{ get; }*/ = new List(); + + /// + /// Initializes a new instance of the class. + /// + /// The name of the brush. + public T3dBrush(string name) + { + Name = name; + } + + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() + { + return "Unreal Engine 1 Brush Model \"" + Name + "\" (" + Polygons.Count + " Polygons)"; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/UnrealGold/T3dBrush.cs.meta b/Scripts/Importers/UnrealGold/T3dBrush.cs.meta new file mode 100644 index 00000000..b54b2101 --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dBrush.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: b702694666fc5274b85d9ad9d52b4ae9 +timeCreated: 1526493642 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/UnrealGold/T3dBrushFlags.cs b/Scripts/Importers/UnrealGold/T3dBrushFlags.cs new file mode 100644 index 00000000..8976e7f1 --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dBrushFlags.cs @@ -0,0 +1,50 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; + +namespace Sabresaurus.SabreCSG.Importers.UnrealGold +{ + /// + /// Represents Unreal Editor 1's Brush Flags. + /// + [Flags] + public enum T3dBrushFlags + { + /// + /// Whether the brush is invisible. + /// + Invisible = 1, + + /// + /// Whether the brush is using masked textures. + /// + Masked = 2, + + /// + /// Whether the brush is using transparent rendering. + /// + Transparent = 4, + + /// + /// Whether the brush doesn't have collision. + /// + NonSolid = 8, + + /// + /// Whether the brush is essentially Sabre's NoCSG. + /// + SemiSolid = 32, + + /// + /// Whether the brush is used to split off sections of the world. + /// + ZonePortal = 67108864, + + /// + /// Whether the brush is using two-sided rendering. + /// + TwoSided = 256 + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/UnrealGold/T3dBrushFlags.cs.meta b/Scripts/Importers/UnrealGold/T3dBrushFlags.cs.meta new file mode 100644 index 00000000..12eec633 --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dBrushFlags.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 4728320ffffa67543af985f827ba71ea +timeCreated: 1526641126 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/UnrealGold/T3dImporter.cs b/Scripts/Importers/UnrealGold/T3dImporter.cs new file mode 100644 index 00000000..2dfb9b83 --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dImporter.cs @@ -0,0 +1,391 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Sabresaurus.SabreCSG.Importers.UnrealGold +{ + /// + /// Importer for Unreal Gold Text (*.t3d) format. Unreal Editor -> File -> Export. + /// + /// Created by Henry de Jongh for SabreCSG. + public class T3dImporter + { + /// + /// Imports the specified Unreal Text file. + /// + /// The file path. + /// A containing the imported map data. + public T3dMap Import(string path) + { + // create a new map. + T3dMap map = new T3dMap(); + + // open the file for reading. we use streams for additional performance. + // it's faster than File.ReadAllLines() as that requires two iterations. + using (FileStream stream = new FileStream(path, FileMode.Open)) + using (StreamReader reader = new StreamReader(stream)) + { + // read all the lines from the file. + bool inActor = false; T3dActor actor = null; + bool inBrush = false; T3dBrush brush = null; + bool inPolygon = false; T3dPolygon polygon = null; + string line; + while (!reader.EndOfStream) + { + line = reader.ReadLine().Trim(); + + // if we currently parsing an actor: + if (inActor) + { + if (!inBrush) + { + // if we done parsing the actor: + if (line == "End Actor") + { + inActor = false; + continue; + } + + // try parsing an actor property. + string key; + object value; + if (TryParseProperty(line, out key, out value)) + actor.Properties.Add(key, value); + + // make sure we detect brush declarations: + if (line.StartsWith("Begin Brush")) + { + // read the properties of the brush. + var properties = ParseKeyValuePairs(line); + if (properties.ContainsKey("Name")) + { + // this is a valid brush model that can be parsed further. + inBrush = true; + // create a new brush model and add it to the map. + brush = new T3dBrush(properties["Name"]); + map.BrushModels.Add(brush); + continue; + } + } + } + // we are currently parsing a brush: + else + { + // if we done parsing the brush: + if (line == "End Brush") + { + inBrush = false; + continue; + } + + if (!inPolygon) + { + // make sure we detect brush polygon declarations: + if (line.StartsWith("Begin Polygon")) + { + inPolygon = true; + // create a new brush polygon and add it to the brush. + polygon = new T3dPolygon(); + brush.Polygons.Add(polygon); + // read the properties of the brush polygon. + var properties = ParseKeyValuePairs(line); + if (properties.ContainsKey("Item")) + polygon.Item = properties["Item"]; + if (properties.ContainsKey("Texture")) + polygon.Texture = properties["Texture"]; + if (properties.ContainsKey("Flags")) + polygon.Flags = (T3dPolygonFlags)Int32.Parse(properties["Flags"]); + } + } + // we are currently parsing a brush polygon: + else + { + // if we done parsing the brush polygon: + if (line == "End Polygon") + { + inPolygon = false; + continue; + } + + if (line.StartsWith("Origin")) + polygon.Origin = ParsePolygonVector(line); + if (line.StartsWith("Normal")) + polygon.Normal = ParsePolygonVector(line); + if (line.StartsWith("TextureU")) + polygon.TextureU = ParsePolygonVector(line); + if (line.StartsWith("TextureV")) + polygon.TextureV = ParsePolygonVector(line); + if (line.StartsWith("Pan")) + { + int u, v; + ParsePolygonUV(line, out u, out v); + polygon.PanU = u; + polygon.PanV = v; + } + if (line.StartsWith("Vertex")) + polygon.Vertices.Add(ParsePolygonVector(line)); + } + } + } + // if we are looking for another begin declaration: + else + { + // if we are going to parse an actor: + if (line.StartsWith("Begin Actor")) + { + // read the properties of the actor. + var properties = ParseKeyValuePairs(line); + if (properties.ContainsKey("Class") && properties.ContainsKey("Name")) + { + // this is a valid actor that can be parsed further. + inActor = true; + // create a new actor and add it to the map. + actor = new T3dActor(map, properties["Class"], properties["Name"]); + map.Actors.Add(actor); + continue; + } + } + } + } + } + + // return the map data. + return map; + } + + /// + /// Parses a polygon vector. + /// + /// The line to be parsed (e.g. 'Origin -00128.000000,-00008.000000,+00008.000000'). + /// + private T3dVector3 ParsePolygonVector(string line) + { + // remove the first word, any +123 values and trim spaces. + string[] parts = line.Substring(line.IndexOf(' ')).Replace("+", "").Trim().Split(','); + return new T3dVector3(float.Parse(parts[0]), float.Parse(parts[1]), float.Parse(parts[2])); + } + + /// + /// Parses the polygon uv. + /// + /// The line to be parsed (e.g. 'Pan U=0 V=0'). + /// The u-coordinate. + /// The v-coordinate. + private void ParsePolygonUV(string line, out int u, out int v) + { + int ui = line.IndexOf("U="); + int vi = line.IndexOf("V="); + string x = line.Substring(ui + 2, line.IndexOf(' ', ui) - ui - 2); + string y = line.Substring(vi + 2); + Int32.TryParse(x, out u); + Int32.TryParse(y, out v); + } + + /// + /// Tries to parse a property. + /// + /// The line to be parsed (e.g. 'MaxCarcasses=50'). + /// The property key. + /// The property value. + /// True if successful else false. + private bool TryParseProperty(string line, out string key, out object value) + { + key = null; + value = null; + // find the first occurence of the '=' character. + int splitIndex = line.IndexOf('='); + if (splitIndex == -1) return false; // early exit. + + // get key and the value (as string). + key = line.Substring(0, splitIndex); + if (key.Contains(' ')) return false; // properties don't have spaces. + string rawvalue = line.Substring(splitIndex + 1); + + // determine and parse the value type. + int integer; + float number; + + // string value has been detected. + if (rawvalue[0] == '"') + { + // remove quotes. + value = rawvalue.Substring(1, rawvalue.Length - 2); + return true; + } + // complex struct has been detected. + else if (rawvalue[0] == '(') + { + // rotator has been detected. + if (rawvalue[1] == 'P' || (rawvalue[1] == 'Y' && rawvalue[2] == 'a') || rawvalue[1] == 'R') + { + int pi = rawvalue.IndexOf("Pitch="); + int yi = rawvalue.IndexOf("Yaw="); + int ri = rawvalue.IndexOf("Roll="); + if (pi == -1 && yi == -1 && ri == -1) return false; + + int v1 = 0; + int v2 = 0; + int v3 = 0; + + // pitch. + if (pi != -1) + { + int len = rawvalue.IndexOf(',', pi); + if (len == -1) len = rawvalue.IndexOf(')', pi); + string xs = rawvalue.Substring(pi + 6, len - 1 - 6); + Int32.TryParse(xs, out v1); + } + + // yaw. + if (yi != -1) + { + int len = rawvalue.IndexOf(',', yi); + if (len == -1) len = rawvalue.IndexOf(')', yi); + string ys = rawvalue.Substring(yi + 4, len - yi - 4); + Int32.TryParse(ys, out v2); + } + + // roll. + if (ri != -1) + { + int len = rawvalue.IndexOf(',', ri); + if (len == -1) len = rawvalue.IndexOf(')', ri); + string zs = rawvalue.Substring(ri + 5, len - ri - 5); + Int32.TryParse(zs, out v3); + } + + value = new T3dRotator(v1, v2, v3); + return true; + } + // vector has been detected. + if (rawvalue[1] == 'X' || rawvalue[1] == 'Y' || rawvalue[1] == 'Z') + { + int xi = rawvalue.IndexOf("X="); + int yi = rawvalue.IndexOf("Y="); + int zi = rawvalue.IndexOf("Z="); + if (xi == -1 && yi == -1 && zi == -1) return false; + + float v1 = 0.0f; + float v2 = 0.0f; + float v3 = 0.0f; + + // x-coordinate. + if (xi != -1) + { + int len = rawvalue.IndexOf(',', xi); + if (len == -1) len = rawvalue.IndexOf(')', xi); + string xs = rawvalue.Substring(xi + 2, len - 1 - 2); + float.TryParse(xs, out v1); + } + + // y-coordinate. + if (yi != -1) + { + int len = rawvalue.IndexOf(',', yi); + if (len == -1) len = rawvalue.IndexOf(')', yi); + string ys = rawvalue.Substring(yi + 2, len - yi - 2); + float.TryParse(ys, out v2); + } + + // z-coordinate. + if (zi != -1) + { + int len = rawvalue.IndexOf(',', zi); + if (len == -1) len = rawvalue.IndexOf(')', zi); + string zs = rawvalue.Substring(zi + 2, len - zi - 2); + float.TryParse(zs, out v3); + } + + value = new T3dVector3(v1, v2, v3); + return true; + } + // scale has been detected. + if (rawvalue[1] == 'S' && rawvalue[2] != 'h') + { + // (Scale=(X=0.173205,Y=0.150000,Z=0.125000),SheerAxis=SHEER_ZX) + string x = rawvalue.Replace("(Scale=", "x=").Replace(",SheerAxis=SHEER_ZX)", ""); + string k; + object v; + if (TryParseProperty(x, out k, out v)) + { + value = v; // vector. + return true; + } + } + } + // floating point number has been detected. + else if (rawvalue.Contains('.') && float.TryParse(rawvalue, out number)) + { + value = number; + return true; + } + // integer number has been detected. + else if (int.TryParse(rawvalue, out integer)) + { + value = integer; + return true; + } + // constant enum has been detected. + else + { + value = rawvalue; + return true; + } + + return false; + } + + /// + /// Parses the key value pairs on a single line. + /// + /// The line to be parsed (e.g. 'Begin Actor Class=Brush Name=Brush0'). + /// The key value pairs that could be found on the line. + private Dictionary ParseKeyValuePairs(string line) + { + Dictionary results = new Dictionary(); + + string name = ""; + StringBuilder buffer = new StringBuilder(128); + foreach (char c in line) + { + // spaces will clear the buffer and indicate a potential value. + if (c == ' ') + { + // do we have a valid key? + if (name != "") + { + // add a key/value pair to the dictionary. + results.Add(name, buffer.ToString()); + name = ""; + } + buffer.Remove(0, buffer.Length); + continue; + } + // equals character indicates we found a key. + if (c == '=') + { + name = buffer.ToString(); + buffer.Remove(0, buffer.Length); + continue; + } + // add character to the buffer. + buffer.Append(c); + } + + // do we have a valid key? + if (name != "") + { + // add a key/value pair to the dictionary. + results.Add(name, buffer.ToString()); + } + + return results; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/UnrealGold/T3dImporter.cs.meta b/Scripts/Importers/UnrealGold/T3dImporter.cs.meta new file mode 100644 index 00000000..0a46a46a --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dImporter.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: b1aafd48970347c47b462b769accf798 +timeCreated: 1526493642 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/UnrealGold/T3dMap.cs b/Scripts/Importers/UnrealGold/T3dMap.cs new file mode 100644 index 00000000..a2d6631f --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dMap.cs @@ -0,0 +1,81 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Sabresaurus.SabreCSG.Importers.UnrealGold +{ + /// + /// Represents an Unreal Editor 1 map. + /// + public class T3dMap + { + /// + /// Gets the actors in the map. + /// + /// The actors in the map. + public List Actors /*{ get; }*/ = new List(); + + /// + /// Gets the brush models in the map. + /// + /// The brush models in the map. + public List BrushModels /*{ get; }*/ = new List(); + + /// + /// Gets the brush actors in the level. + /// + /// The brush actors in the level. + public List Brushes { get { return Actors.Where(a => a.Class == "Brush" && a.BrushName != "Brush").ToList(); } } + + /// + /// Gets the map title. + /// + /// The map title. + public string Title + { + get + { + if (LevelInfo == null) return ""; + object value; + if (LevelInfo.Properties.TryGetValue("Title", out value)) + return value as string; + return ""; + } + } + + /// + /// Gets the map author. + /// + /// The map author. + public string Author + { + get + { + if (LevelInfo == null) return ""; + object value; + if (LevelInfo.Properties.TryGetValue("Author", out value)) + return value as string; + return ""; + } + } + + /// + /// Gets the level information actor. + /// + /// The level information actor. + public T3dActor LevelInfo { get { return Actors.FirstOrDefault(a => a.Class == "LevelInfo"); } } + + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() + { + return "Unreal Engine 1 Map \"" + Title + "\""; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/UnrealGold/T3dMap.cs.meta b/Scripts/Importers/UnrealGold/T3dMap.cs.meta new file mode 100644 index 00000000..1fdda830 --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dMap.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: c876fb4e6d7c1c344bd7908b5f5ef6aa +timeCreated: 1526493642 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/UnrealGold/T3dMapConverter.cs b/Scripts/Importers/UnrealGold/T3dMapConverter.cs new file mode 100644 index 00000000..1fed9f8f --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dMapConverter.cs @@ -0,0 +1,206 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace Sabresaurus.SabreCSG.Importers.UnrealGold +{ + /// + /// Converts an Unreal Editor 1 Map to SabreCSG Brushes. + /// + public static class T3dMapConverter + { + /// + /// Imports the specified map into the SabreCSG model. + /// + /// The model to import into. + /// The map to be imported. + /// The scale modifier. + public static void Import(CSGModel model, T3dMap map, int scale = 64) + { + try + { + model.BeginUpdate(); + + List brushes = map.Brushes; + Brush[] sabreBrushes = new Brush[brushes.Count]; + + // iterate through all brush actors. + for (int k = 0; k < brushes.Count; k++) + { + // get the underlying brush data. + T3dActor tactor = brushes[k]; + T3dBrush tbrush = tactor.Brush; +#if UNITY_EDITOR + UnityEditor.EditorUtility.DisplayProgressBar("SabreCSG: Importing Unreal Gold Map", "Converting Unreal Brushes To SabreCSG Brushes (" + (k + 1) + " / " + brushes.Count + ")...", k / (float)brushes.Count); +#endif + // iterate through the brush polygons. + Polygon[] polygons = new Polygon[tbrush.Polygons.Count]; + for (int i = 0; i < tbrush.Polygons.Count; i++) + { + T3dPolygon tpolygon = tbrush.Polygons[i]; + + // find the material in the unity project automatically. + Material material = FindMaterial(tpolygon.Texture); + + Vertex[] vertices = new Vertex[tpolygon.Vertices.Count]; + for (int j = 0; j < tpolygon.Vertices.Count; j++) + { + vertices[j] = new Vertex(ToVector3(tpolygon.Vertices[j]) / (float)scale, ToVector3(tpolygon.Normal), GenerateUV(tpolygon, j, material)); + } + + // detect the polygon flags. + bool userExcludeFromFinal = false; + if ((tpolygon.Flags & T3dPolygonFlags.Invisible) > 0) + userExcludeFromFinal = true; + + polygons[i] = new Polygon(vertices, material, false, userExcludeFromFinal); + } + + // position and rotate the brushes. + Transform transform = model.CreateCustomBrush(polygons).transform; + transform.position = (ToVector3(tactor.Location) / (float)scale) - (ToVector3(tactor.PrePivot) / (float)scale); + Vector3 axis; + float angle; + T3dRotatorToQuaternion(tactor.Rotation).ToAngleAxis(out angle, out axis); + transform.RotateAround(transform.position + (ToVector3(tactor.PrePivot) / (float)scale), axis, angle); + + PrimitiveBrush brush = transform.GetComponent(); + sabreBrushes[k] = brush; + + object value; + // detect the brush mode (additive, subtractive). + if (tactor.Properties.TryGetValue("CsgOper", out value)) + brush.Mode = (string)value == "CSG_Add" ? CSGMode.Add : CSGMode.Subtract; + // detect special brush flags. + if (tactor.Properties.TryGetValue("PolyFlags", out value)) + { + T3dBrushFlags flags = (T3dBrushFlags)value; + if ((flags & T3dBrushFlags.Invisible) > 0) + brush.IsVisible = false; + if ((flags & T3dBrushFlags.NonSolid) > 0) + brush.HasCollision = false; + if ((flags & T3dBrushFlags.SemiSolid) > 0) + brush.IsNoCSG = true; + } + // detect single polygons. + if (polygons.Length == 1) + brush.IsNoCSG = true; + } + + // add all new brushes to a group. + string title = "Unreal Gold Map"; + if (map.Title != "") + title += " '" + map.Title + "'"; + if (map.Author != "") + title += " (" + map.Author + ")"; + + GroupBrush groupBrush = new GameObject(title).AddComponent(); + groupBrush.transform.SetParent(model.transform); + for (int i = 0; i < sabreBrushes.Length; i++) + sabreBrushes[i].transform.SetParent(groupBrush.transform); + +#if UNITY_EDITOR + UnityEditor.EditorUtility.ClearProgressBar(); +#endif + } + catch (Exception) + { + throw; + } + finally + { + model.EndUpdate(); + } + } + + /// + /// Converts to . + /// + /// The to be converted. + /// The . + private static Vector3 ToVector3(T3dVector3 vector3) + { + return new Vector3(-vector3.X, vector3.Z, vector3.Y); + } + + private static float DotProduct(float ax, float ay, float az, float bx, float by, float bz) + { + return (ax * bx) + (ay * by) + (az * bz); + } + + private static Vector2 GenerateUV(T3dPolygon polygon, int vindex, Material material) + { + float uu; + float vv; + uu = DotProduct(polygon.Vertices[vindex].X - polygon.Origin.X, polygon.Vertices[vindex].Y - polygon.Origin.Y, polygon.Vertices[vindex].Z - polygon.Origin.Z, polygon.TextureU.X, polygon.TextureU.Y, polygon.TextureU.Z); + vv = DotProduct(polygon.Vertices[vindex].X - polygon.Origin.X, polygon.Vertices[vindex].Y - polygon.Origin.Y, polygon.Vertices[vindex].Z - polygon.Origin.Z, polygon.TextureV.X, polygon.TextureV.Y, polygon.TextureV.Z); + if (material == null || material.mainTexture == null) + return new Vector2(uu * (1.0f / 256f), 1.0f - (vv * (1.0f / 256f))); + else + return new Vector2((uu + polygon.PanU) * (1.0f / material.mainTexture.width), 1.0f - ((vv + polygon.PanV) * (1.0f / material.mainTexture.height))); + } + + private static Quaternion T3dRotatorToQuaternion(T3dRotator rotator) + { + // 227 variant: + float cosp = Mathf.Cos(rotator.Pitch * 0.0000479369f); + float cosy = Mathf.Cos(rotator.Yaw * 0.0000479369f); + float cosr = Mathf.Cos(rotator.Roll * 0.0000479369f); + float sinp = Mathf.Sin(rotator.Pitch * 0.0000479369f); + float siny = Mathf.Sin(rotator.Yaw * 0.0000479369f); + float sinr = Mathf.Sin(rotator.Roll * 0.0000479369f); + + Quaternion quaternion; + quaternion.w = cosp * cosy * cosr + sinp * siny * sinr; + quaternion.z = sinp * cosy * cosr + cosp * siny * sinr; + quaternion.y = cosp * siny * cosr - sinp * cosy * sinr; + quaternion.x = cosp * cosy * sinr - sinp * siny * cosr; + + float L = Mathf.Sqrt(Mathf.Pow(quaternion.w, 2) + Mathf.Pow(quaternion.x, 2) + Mathf.Pow(quaternion.y, 2) + Mathf.Pow(quaternion.z, 2)); + quaternion.w /= L; + quaternion.x /= L; + quaternion.y /= L; + quaternion.z /= L; + + quaternion.z = -quaternion.z; + + return quaternion; + } + + /// + /// Attempts to find a material in the project by name. + /// + /// The material name to search for. + /// The material if found or null. + private static Material FindMaterial(string name) + { +#if UNITY_EDITOR + // first try finding the fully qualified texture name like 'PlayrShp.Ceiling.Hullwk'. + string texture = ""; + string guid = UnityEditor.AssetDatabase.FindAssets("t:Material " + name).FirstOrDefault(); + if (guid == null) + { + // if it couldn't be found try a simplified name which UnrealEd typically exports like 'Hullwk'. + texture = name; + if (name.Contains('.')) + texture = name.Substring(name.LastIndexOf('.') + 1); + guid = UnityEditor.AssetDatabase.FindAssets("t:Material " + texture).FirstOrDefault(); + } + // if a material could be found using either option: + if (guid != null) + { + // load the material. + string path = UnityEditor.AssetDatabase.GUIDToAssetPath(guid); + return UnityEditor.AssetDatabase.LoadAssetAtPath(path); + } + else { Debug.Log("SabreCSG: Tried to find material '" + name + "' and also as '" + texture + "' but it couldn't be found in the project."); } +#endif + return null; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/UnrealGold/T3dMapConverter.cs.meta b/Scripts/Importers/UnrealGold/T3dMapConverter.cs.meta new file mode 100644 index 00000000..d992727e --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dMapConverter.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: d7836a96483abfe4f8b126daa4a78feb +timeCreated: 1526494056 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/UnrealGold/T3dPolygon.cs b/Scripts/Importers/UnrealGold/T3dPolygon.cs new file mode 100644 index 00000000..9eb93609 --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dPolygon.cs @@ -0,0 +1,84 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; +using System.Collections.Generic; + +namespace Sabresaurus.SabreCSG.Importers.UnrealGold +{ + /// + /// Represents an Unreal Editor 1 polygon. + /// + public class T3dPolygon + { + /// + /// Gets or sets the item. + /// + /// The item. + public string Item { get; set; } + + /// + /// Gets or sets the texture. + /// + /// The texture. + public string Texture { get; set; } + + /// + /// Gets or sets the polygon flags. + /// + /// The polygon flags. + public T3dPolygonFlags Flags { get; set; } + + /// + /// Gets or sets the origin. + /// + /// The origin. + public T3dVector3 Origin { get; set; } + + /// + /// Gets or sets the normal. + /// + /// The normal. + public T3dVector3 Normal { get; set; } + + /// + /// Gets or sets the texture u. + /// + /// The texture u. + public T3dVector3 TextureU { get; set; } + + /// + /// Gets or sets the texture v. + /// + /// The texture v. + public T3dVector3 TextureV { get; set; } + + /// + /// Gets or sets the pan u. + /// + /// The pan u. + public int PanU { get; set; } + + /// + /// Gets or sets the pan v. + /// + /// The pan v. + public int PanV { get; set; } + + /// + /// Gets or sets the vertices. + /// + /// The vertices. + public List Vertices /*{ get; }*/ = new List(); + + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() + { + return "Unreal Engine 1 Brush Polygon \"" + Item + "\" (" + Vertices.Count + " Vertices)"; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/UnrealGold/T3dPolygon.cs.meta b/Scripts/Importers/UnrealGold/T3dPolygon.cs.meta new file mode 100644 index 00000000..22eb05aa --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dPolygon.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 0c791253165b5ee4fa20c89f0dee741d +timeCreated: 1526493642 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/UnrealGold/T3dPolygonFlags.cs b/Scripts/Importers/UnrealGold/T3dPolygonFlags.cs new file mode 100644 index 00000000..9786a0b2 --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dPolygonFlags.cs @@ -0,0 +1,39 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; + +namespace Sabresaurus.SabreCSG.Importers.UnrealGold +{ + /// + /// Represents Unreal Editor 1's Polygon Flags. + /// + [Flags] + public enum T3dPolygonFlags + { + Invisible = 1, + Masked = 2, + Translucent = 4, + Environment = 16, + Modulated = 64, + FakeBackdrop = 128, + TwoSided = 256, + UPan = 512, + VPan = 1024, + NoSmooth = 2048, + SpecialPoly = 4096, + SmallWavy = 8192, + ForceViewZone = 16384, + LowShadowDetail = 32768, + AlphaBlend = 131072, + DirtyShadows = 262144, + BrightCorners = 524288, + SpecialLit = 1048576, + NoBoundsReject = 2097152, + Unlit = 4194304, + HighShadowDetail = 8388608, + Portal = 67108864, + Mirror = 134217728 + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/UnrealGold/T3dPolygonFlags.cs.meta b/Scripts/Importers/UnrealGold/T3dPolygonFlags.cs.meta new file mode 100644 index 00000000..1348d063 --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dPolygonFlags.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 69f1fc077691870469b28a313995245b +timeCreated: 1526643005 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/UnrealGold/T3dRotator.cs b/Scripts/Importers/UnrealGold/T3dRotator.cs new file mode 100644 index 00000000..4de4b225 --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dRotator.cs @@ -0,0 +1,61 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; + +namespace Sabresaurus.SabreCSG.Importers.UnrealGold +{ + /// + /// Represents an Unreal Editor 1 rotator type. + /// + public class T3dRotator + { + /// + /// Gets or sets the pitch. + /// + /// The pitch. + public int Pitch { get; set; } + + /// + /// Gets or sets the yaw. + /// + /// The yaw. + public int Yaw { get; set; } + + /// + /// Gets or sets the roll. + /// + /// The roll. + public int Roll { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public T3dRotator() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The pitch of the rotator. + /// The yaw of the rotator. + /// The roll of the rotator. + public T3dRotator(int pitch, int yaw, int roll) + { + Pitch = pitch; + Yaw = yaw; + Roll = roll; + } + + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() + { + return "Pitch: " + Pitch + ", Yaw: " + Yaw + ", Roll: " + Roll; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/UnrealGold/T3dRotator.cs.meta b/Scripts/Importers/UnrealGold/T3dRotator.cs.meta new file mode 100644 index 00000000..efa1d4bf --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dRotator.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 438ca48a5be62a742903418131152af7 +timeCreated: 1526493642 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/UnrealGold/T3dVector3.cs b/Scripts/Importers/UnrealGold/T3dVector3.cs new file mode 100644 index 00000000..1a8d573b --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dVector3.cs @@ -0,0 +1,61 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; + +namespace Sabresaurus.SabreCSG.Importers.UnrealGold +{ + /// + /// Represents an Unreal Editor 1 vector type. + /// + public class T3dVector3 + { + /// + /// Gets or sets the x-coordinate. + /// + /// The x-coordinate. + public float X { get; set; } + + /// + /// Gets or sets the y-coordinate. + /// + /// The y-coordinate. + public float Y { get; set; } + + /// + /// Gets or sets the z-coordinate. + /// + /// The z-coordinate. + public float Z { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public T3dVector3() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The x-coordinate of the vector. + /// The y-coordinate of the vector. + /// The z-coordinate of the vector. + public T3dVector3(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() + { + return "X: " + X + ", Y: " + Y + ", Z: " + Z; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/UnrealGold/T3dVector3.cs.meta b/Scripts/Importers/UnrealGold/T3dVector3.cs.meta new file mode 100644 index 00000000..814ebf80 --- /dev/null +++ b/Scripts/Importers/UnrealGold/T3dVector3.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 15f8a3ab64c9548458a5cd8999712cc7 +timeCreated: 1526493642 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/ValveMapFormat2006.meta b/Scripts/Importers/ValveMapFormat2006.meta new file mode 100644 index 00000000..44738929 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 86201f70c70059241bc3c9a1e3bb6a85 +folderAsset: yes +timeCreated: 1526731406 +licenseType: Free +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/ValveMapFormat2006/VmfAxis.cs b/Scripts/Importers/ValveMapFormat2006/VmfAxis.cs new file mode 100644 index 00000000..3e815c97 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfAxis.cs @@ -0,0 +1,53 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; + +namespace Sabresaurus.SabreCSG.Importers.ValveMapFormat2006 +{ + /// + /// Represents a Hammer UV Axis. + /// + public class VmfAxis + { + /// + /// The x, y, z vector. + /// + public VmfVector3 Vector; + + /// + /// The UV translation. + /// + public float Translation; + + /// + /// The UV scale. + /// + public float Scale; + + /// + /// Initializes a new instance of the class. + /// + /// The vector. + /// The translation. + /// The scale. + public VmfAxis(VmfVector3 vector, float translation, float scale) + { + Vector = vector; + Translation = translation; + Scale = scale; + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return "VmfAxis " + Vector + ", T=" + Translation + ", S=" + Scale; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/ValveMapFormat2006/VmfAxis.cs.meta b/Scripts/Importers/ValveMapFormat2006/VmfAxis.cs.meta new file mode 100644 index 00000000..3ede0275 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfAxis.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 3af06ab28da81b446ac4719047b0ec98 +timeCreated: 1526731450 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/ValveMapFormat2006/VmfEntity.cs b/Scripts/Importers/ValveMapFormat2006/VmfEntity.cs new file mode 100644 index 00000000..0616e4fb --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfEntity.cs @@ -0,0 +1,36 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; +using System.Collections.Generic; + +namespace Sabresaurus.SabreCSG.Importers.ValveMapFormat2006 +{ + /// + /// Represents a Hammer Entity. + /// + public class VmfEntity + { + public int Id = -1; + + /// + /// The class name of the entity. + /// + public string ClassName; + + /// + /// The solids in the entity if available. + /// + public List Solids = new List(); + + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() + { + return "VmfEntity " + ClassName + " " + Id + " (" + Solids.Count + " Solids)"; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/ValveMapFormat2006/VmfEntity.cs.meta b/Scripts/Importers/ValveMapFormat2006/VmfEntity.cs.meta new file mode 100644 index 00000000..ec8cec89 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfEntity.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 4c00653aad765474f89fc04a2362bfdd +timeCreated: 1526816208 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/ValveMapFormat2006/VmfImporter.cs b/Scripts/Importers/ValveMapFormat2006/VmfImporter.cs new file mode 100644 index 00000000..bb707001 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfImporter.cs @@ -0,0 +1,292 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; +using System.IO; +using System.Linq; + +namespace Sabresaurus.SabreCSG.Importers.ValveMapFormat2006 +{ + /// + /// Importer for Valve Map Format (*.vmf) format. + /// + /// Created by Henry de Jongh for SabreCSG. + public class VmfImporter + { + /// + /// Imports the specified Valve Map Format file. + /// + /// The file path. + /// A containing the imported world data. + public VmfWorld Import(string path) + { + // create a new world. + VmfWorld world = new VmfWorld(); + + // open the file for reading. we use streams for additional performance. + // it's faster than File.ReadAllLines() as that requires two iterations. + using (FileStream stream = new FileStream(path, FileMode.Open)) + using (StreamReader reader = new StreamReader(stream)) + { + // read all the lines from the file. + //bool inActor = false; T3dActor actor = null; + //bool inBrush = false; T3dBrush brush = null; + //bool inPolygon = false; T3dPolygon polygon = null; + string[] closures = new string[64]; + int depth = 0; + string line; + string previousLine = ""; + bool justEnteredClosure = false; + string key; + object value; + VmfSolid solid = null; + VmfSolidSide solidSide = null; + VmfEntity entity = null; + while (!reader.EndOfStream) + { + line = reader.ReadLine().Trim(); + if (line.Length == 0) continue; + + // parse closures and keep track of them. + if (line[0] == '{') { closures[depth] = previousLine; depth++; justEnteredClosure = true; continue; } + if (line[0] == '}') { depth--; closures[depth] = null; continue; } + + // parse version info. + if (closures[0] == "versioninfo") + { + if (TryParsekeyValue(line, out key, out value)) + { + switch (key) + { + case "editorversion": world.VersionInfoEditorVersion = (int)value; break; + case "editorbuild": world.VersionInfoEditorBuild = (int)value; break; + case "mapversion": world.VersionInfoMapVersion = (int)value; break; + case "formatversion": world.VersionInfoFormatVersion = (int)value; break; + case "prefab": world.VersionInfoPrefab = (int)value; break; + } + } + } + + // parse view settings. + if (closures[0] == "viewsettings") + { + if (TryParsekeyValue(line, out key, out value)) + { + switch (key) + { + case "bSnapToGrid": world.ViewSettingsSnapToGrid = (int)value; break; + case "bShowGrid": world.ViewSettingsShowGrid = (int)value; break; + case "bShowLogicalGrid": world.ViewSettingsShowLogicalGrid = (int)value; break; + case "nGridSpacing": world.ViewSettingsGridSpacing = (int)value; break; + case "bShow3DGrid": world.ViewSettingsShow3DGrid = (int)value; break; + } + } + } + + // parse world properties. + if (closures[0] == "world" && closures[1] == null) + { + if (TryParsekeyValue(line, out key, out value)) + { + switch (key) + { + case "id": world.Id = (int)value; break; + case "mapversion": world.MapVersion = (int)value; break; + case "classname": world.ClassName = (string)value; break; + case "detailmaterial": world.DetailMaterial = (string)value; break; + case "detailvbsp": world.DetailVBsp = (string)value; break; + case "maxpropscreenwidth": world.MaxPropScreenWidth = (int)value; break; + case "skyname": world.SkyName = (string)value; break; + } + } + } + + // parse world solid. + if (closures[0] == "world" && closures[1] == "solid" && closures[2] == null) + { + // create a new solid and add it to the world. + if (justEnteredClosure) + { + solid = new VmfSolid(); + world.Solids.Add(solid); + } + + // parse solid properties. + if (TryParsekeyValue(line, out key, out value)) + { + switch (key) + { + case "id": solid.Id = (int)value; break; + } + } + } + + // parse world solid side. + if (closures[0] == "world" && closures[1] == "solid" && closures[2] == "side" && closures[3] == null) + { + // create a new solid side and add it to the solid. + if (justEnteredClosure) + { + solidSide = new VmfSolidSide(); + solid.Sides.Add(solidSide); + } + + // parse solid side properties. + if (TryParsekeyValue(line, out key, out value)) + { + switch (key) + { + case "id": solidSide.Id = (int)value; break; + case "plane": solidSide.Plane = (VmfPlane)value; break; + case "material": solidSide.Material = (string)value; break; + //case "rotation": solidSide.Rotation = (float)value; break; + case "uaxis": solidSide.UAxis = (VmfAxis)value; break; + case "vaxis": solidSide.VAxis = (VmfAxis)value; break; + case "lightmapscale": solidSide.LightmapScale = (int)value; break; + case "smoothing_groups": solidSide.SmoothingGroups = (int)value; break; + } + } + } + + // HACK: detect displacements. + if (closures[0] == "world" && closures[1] == "solid" && closures[2] == "side" && closures[3] == "dispinfo") + { + solidSide.HasDisplacement = true; + } + + // parse entity. + if (closures[0] == "entity" && closures[1] == null) + { + // create a new entity and add it to the world. + if (justEnteredClosure) + { + entity = new VmfEntity(); + world.Entities.Add(entity); + } + + // parse entity properties. + if (TryParsekeyValue(line, out key, out value)) + { + switch (key) + { + case "id": entity.Id = (int)value; break; + case "classname": entity.ClassName = (string)value; break; + } + } + } + + // parse entity solid. + if (closures[0] == "entity" && closures[1] == "solid" && closures[2] == null) + { + // create a new solid and add it to the entity. + if (justEnteredClosure) + { + solid = new VmfSolid(); + entity.Solids.Add(solid); + } + + // parse solid properties. + if (TryParsekeyValue(line, out key, out value)) + { + switch (key) + { + case "id": solid.Id = (int)value; break; + } + } + } + + // parse entity solid side. + if (closures[0] == "entity" && closures[1] == "solid" && closures[2] == "side" && closures[3] == null) + { + // create a new solid side and add it to the solid. + if (justEnteredClosure) + { + solidSide = new VmfSolidSide(); + solid.Sides.Add(solidSide); + } + + // parse solid side properties. + if (TryParsekeyValue(line, out key, out value)) + { + switch (key) + { + case "id": solidSide.Id = (int)value; break; + case "plane": solidSide.Plane = (VmfPlane)value; break; + case "material": solidSide.Material = (string)value; break; + //case "rotation": solidSide.Rotation = (float)value; break; + case "uaxis": solidSide.UAxis = (VmfAxis)value; break; + case "vaxis": solidSide.VAxis = (VmfAxis)value; break; + case "lightmapscale": solidSide.LightmapScale = (int)value; break; + case "smoothing_groups": solidSide.SmoothingGroups = (int)value; break; + } + } + } + + previousLine = line; + justEnteredClosure = false; + } + } + + return world; + } + + /// + /// Tries to parse a key value line. + /// + /// The line (e.g. '"editorversion" "400"'). + /// The key that was found. + /// The value that was found. + /// True if successful else false. + private bool TryParsekeyValue(string line, out string key, out object value) + { + key = ""; + value = null; + + if (!line.Contains('"')) return false; + int idx = line.IndexOf('"', 1); + + key = line.Substring(1, idx - 1); + string rawvalue = line.Substring(idx + 3, line.Length - idx - 4); + if (rawvalue.Length == 0) return false; + + int vi; + float vf; + // detect plane definition. + if (rawvalue[0] == '(') + { + string[] values = rawvalue.Replace("(", "").Replace(")", "").Split(' '); + VmfVector3 p1 = new VmfVector3(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2])); + VmfVector3 p2 = new VmfVector3(float.Parse(values[3]), float.Parse(values[4]), float.Parse(values[5])); + VmfVector3 p3 = new VmfVector3(float.Parse(values[6]), float.Parse(values[7]), float.Parse(values[8])); + value = new VmfPlane(p1, p2, p3); + return true; + } + // detect uv definition. + else if (rawvalue[0] == '[') + { + string[] values = rawvalue.Replace("[", "").Replace("]", "").Split(' '); + value = new VmfAxis(new VmfVector3(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2])), float.Parse(values[3]), float.Parse(values[4])); + return true; + } + // detect floating point value. + else if (rawvalue.Contains('.') && float.TryParse(rawvalue, out vf)) + { + value = vf; + return true; + } + // detect integer value. + else if (Int32.TryParse(rawvalue, out vi)) + { + value = vi; + return true; + } + // probably a string value. + else + { + value = rawvalue; + return true; + } + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/ValveMapFormat2006/VmfImporter.cs.meta b/Scripts/Importers/ValveMapFormat2006/VmfImporter.cs.meta new file mode 100644 index 00000000..90f423c4 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfImporter.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 8ff05bf1a50934f4f9104b8807c917b3 +timeCreated: 1526731450 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/ValveMapFormat2006/VmfPlane.cs b/Scripts/Importers/ValveMapFormat2006/VmfPlane.cs new file mode 100644 index 00000000..86e5e92a --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfPlane.cs @@ -0,0 +1,51 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; + +namespace Sabresaurus.SabreCSG.Importers.ValveMapFormat2006 +{ + /// + /// Represents a Hammer Plane. + /// + public class VmfPlane + { + /// + /// The first point of the plane definition. + /// + public VmfVector3 P1; + + /// + /// The second point of the plane definition. + /// + public VmfVector3 P2; + + /// + /// The third point of the plane definition. + /// + public VmfVector3 P3; + + /// + /// Initializes a new instance of the class. + /// + /// The first point of the plane definition. + /// The second point of the plane definition. + /// The third point of the plane definition. + public VmfPlane(VmfVector3 p1, VmfVector3 p2, VmfVector3 p3) + { + P1 = p1; + P2 = p2; + P3 = p3; + } + + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() + { + return "VmfPlane (P1=" + P1 + ", P2=" + P2 + ", P3=" + P3 + ")"; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/ValveMapFormat2006/VmfPlane.cs.meta b/Scripts/Importers/ValveMapFormat2006/VmfPlane.cs.meta new file mode 100644 index 00000000..c27feb37 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfPlane.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 959e28fcebf49ea4ba3085c443fdc4e3 +timeCreated: 1526731450 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/ValveMapFormat2006/VmfSolid.cs b/Scripts/Importers/ValveMapFormat2006/VmfSolid.cs new file mode 100644 index 00000000..fc59b2fc --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfSolid.cs @@ -0,0 +1,31 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; +using System.Collections.Generic; + +namespace Sabresaurus.SabreCSG.Importers.ValveMapFormat2006 +{ + /// + /// Represents a Hammer Solid. + /// + public class VmfSolid + { + public int Id = -1; + + /// + /// The sides of the solid. + /// + public List Sides = new List(); + + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() + { + return "VMF Solid " + Id + " (" + Sides.Count + " Sides)"; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/ValveMapFormat2006/VmfSolid.cs.meta b/Scripts/Importers/ValveMapFormat2006/VmfSolid.cs.meta new file mode 100644 index 00000000..b5042ba7 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfSolid.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 35fec656706945d4298ac72533745472 +timeCreated: 1526731450 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/ValveMapFormat2006/VmfSolidSide.cs b/Scripts/Importers/ValveMapFormat2006/VmfSolidSide.cs new file mode 100644 index 00000000..2fa74252 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfSolidSide.cs @@ -0,0 +1,35 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; + +namespace Sabresaurus.SabreCSG.Importers.ValveMapFormat2006 +{ + /// + /// Represents a Hammer Solid Side. + /// + public class VmfSolidSide + { + public int Id = -1; + public VmfPlane Plane; + public string Material; + public float Rotation; + public VmfAxis UAxis; + public VmfAxis VAxis; + public int LightmapScale; + public int SmoothingGroups; + + // HACK: + public bool HasDisplacement = false; + + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() + { + return "VMF Solid Side " + Id + " '" + Material + "' " + " " + Plane; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/ValveMapFormat2006/VmfSolidSide.cs.meta b/Scripts/Importers/ValveMapFormat2006/VmfSolidSide.cs.meta new file mode 100644 index 00000000..4290f5a6 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfSolidSide.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: c18fd8aa8abdc5b47beba52c0b2ccf5c +timeCreated: 1526731450 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/ValveMapFormat2006/VmfVector3.cs b/Scripts/Importers/ValveMapFormat2006/VmfVector3.cs new file mode 100644 index 00000000..f79dbac4 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfVector3.cs @@ -0,0 +1,51 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; + +namespace Sabresaurus.SabreCSG.Importers.ValveMapFormat2006 +{ + /// + /// Represents a Hammer Vector3. + /// + public class VmfVector3 + { + /// + /// The x-coordinate of the vector. + /// + public float X; + + /// + /// The y-coordinate of the vector. + /// + public float Y; + + /// + /// The z-coordinate of the vector. + /// + public float Z; + + /// + /// Initializes a new instance of the class. + /// + /// The x-coordinate of the vector. + /// The y-coordinate of the vector. + /// The z-coordinate of the vector. + public VmfVector3(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() + { + return "VmfVector3 (X=" + X + ", Y=" + Y + ", Z=" + Z + ")"; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/ValveMapFormat2006/VmfVector3.cs.meta b/Scripts/Importers/ValveMapFormat2006/VmfVector3.cs.meta new file mode 100644 index 00000000..377b256b --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfVector3.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 6fa0ede7b47989748ad9ae3fd4c3c627 +timeCreated: 1526731450 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/ValveMapFormat2006/VmfWorld.cs b/Scripts/Importers/ValveMapFormat2006/VmfWorld.cs new file mode 100644 index 00000000..02a6a2c1 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfWorld.cs @@ -0,0 +1,46 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Sabresaurus.SabreCSG.Importers.ValveMapFormat2006 +{ + /// + /// Represents a Hammer World. + /// + public class VmfWorld + { + public int VersionInfoEditorVersion = -1; + public int VersionInfoEditorBuild = -1; + public int VersionInfoMapVersion = -1; + public int VersionInfoFormatVersion = -1; + public int VersionInfoPrefab = -1; + + public int ViewSettingsSnapToGrid = -1; + public int ViewSettingsShowGrid = -1; + public int ViewSettingsShowLogicalGrid = -1; + public int ViewSettingsGridSpacing = -1; + public int ViewSettingsShow3DGrid = -1; + + public int Id = -1; + public int MapVersion = -1; + public string ClassName = ""; + public string DetailMaterial = ""; + public string DetailVBsp = ""; + public int MaxPropScreenWidth = -1; + public string SkyName = ""; + + /// + /// The solids in the world. + /// + public List Solids = new List(); + + /// + /// The entities in the world. + /// + public List Entities = new List(); + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/ValveMapFormat2006/VmfWorld.cs.meta b/Scripts/Importers/ValveMapFormat2006/VmfWorld.cs.meta new file mode 100644 index 00000000..b85c1372 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfWorld.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: b0d9bbb3d70006f4d8ca1c266b0e8b15 +timeCreated: 1526731450 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Importers/ValveMapFormat2006/VmfWorldConverter.cs b/Scripts/Importers/ValveMapFormat2006/VmfWorldConverter.cs new file mode 100644 index 00000000..72967cd3 --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfWorldConverter.cs @@ -0,0 +1,314 @@ +#if UNITY_EDITOR || RUNTIME_CSG + +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace Sabresaurus.SabreCSG.Importers.ValveMapFormat2006 +{ + /// + /// Converts a Hammer Map to SabreCSG Brushes. + /// + public static class VmfWorldConverter + { + /// + /// Imports the specified world into the SabreCSG model. + /// + /// The model to import into. + /// The world to be imported. + /// The scale modifier. + public static void Import(CSGModel model, VmfWorld world, int scale = 32) + { + try + { + model.BeginUpdate(); + + // group all the brushes together. + GroupBrush groupBrush = new GameObject("Source Engine Map").AddComponent(); + groupBrush.transform.SetParent(model.transform); + + // iterate through all world solids. + for (int i = 0; i < world.Solids.Count; i++) + { +#if UNITY_EDITOR + UnityEditor.EditorUtility.DisplayProgressBar("SabreCSG: Importing Source Engine Map", "Converting Hammer Solids To SabreCSG Brushes (" + (i + 1) + " / " + world.Solids.Count + ")...", i / (float)world.Solids.Count); +#endif + VmfSolid solid = world.Solids[i]; + + // don't add triggers to the scene. + if (solid.Sides.Count > 0 && IsSpecialMaterial(solid.Sides[0].Material)) + continue; + + // build a very large cube brush. + var go = model.CreateBrush(PrimitiveBrushType.Cube, Vector3.zero); + var pr = go.GetComponent(); + BrushUtility.Resize(pr, new Vector3(8192, 8192, 8192)); + + // clip all the sides out of the brush. + for (int j = solid.Sides.Count; j-- > 0;) + { + VmfSolidSide side = solid.Sides[j]; + Plane clip = new Plane(pr.transform.InverseTransformPoint(new Vector3(side.Plane.P1.X, side.Plane.P1.Z, side.Plane.P1.Y) / scale), pr.transform.InverseTransformPoint(new Vector3(side.Plane.P2.X, side.Plane.P2.Z, side.Plane.P2.Y) / scale), pr.transform.InverseTransformPoint(new Vector3(side.Plane.P3.X, side.Plane.P3.Z, side.Plane.P3.Y) / scale)); + ClipUtility.ApplyClipPlane(pr, clip, false); + + // find the polygons associated with the clipping plane. + // the normal is unique and can never occur twice as that wouldn't allow the solid to be convex. + var polygons = pr.GetPolygons().Where(p => p.Plane.normal == clip.normal); + foreach (var polygon in polygons) + { + // detect excluded polygons. + if (IsExcludedMaterial(side.Material)) + polygon.UserExcludeFromFinal = true; + // detect collision-only brushes. + if (IsInvisibleMaterial(side.Material)) + pr.IsVisible = false; + // try finding the material in the project. + polygon.Material = FindMaterial(side.Material); + // calculate the texture coordinates. + int w = 256; + int h = 256; + if (polygon.Material != null && polygon.Material.mainTexture != null) + { + w = polygon.Material.mainTexture.width; + h = polygon.Material.mainTexture.height; + } + CalculateTextureCoordinates(polygon, w, h, side.UAxis, side.VAxis, scale); + } + } + + // add the brush to the group. + pr.transform.SetParent(groupBrush.transform); + } + + // iterate through all entities. + for (int e = 0; e < world.Entities.Count; e++) + { +#if UNITY_EDITOR + UnityEditor.EditorUtility.DisplayProgressBar("SabreCSG: Importing Source Engine Map", "Converting Hammer Entities To SabreCSG Brushes (" + (e + 1) + " / " + world.Entities.Count + ")...", e / (float)world.Entities.Count); +#endif + VmfEntity entity = world.Entities[e]; + + // skip entities that sabrecsg can't handle. + switch (entity.ClassName) + { + case "func_areaportal": + case "func_areaportalwindow": + case "func_capturezone": + case "func_changeclass": + case "func_combine_ball_spawner": + case "func_dustcloud": + case "func_dustmotes": + case "func_nobuild": + case "func_nogrenades": + case "func_occluder": + case "func_precipitation": + case "func_proprespawnzone": + case "func_regenerate": + case "func_respawnroom": + case "func_smokevolume": + case "func_viscluster": + continue; + } + + // iterate through all entity solids. + for (int i = 0; i < entity.Solids.Count; i++) + { + VmfSolid solid = entity.Solids[i]; + + // don't add triggers to the scene. + if (solid.Sides.Count > 0 && IsSpecialMaterial(solid.Sides[0].Material)) + continue; + + // build a very large cube brush. + var go = model.CreateBrush(PrimitiveBrushType.Cube, Vector3.zero); + var pr = go.GetComponent(); + BrushUtility.Resize(pr, new Vector3(8192, 8192, 8192)); + + // clip all the sides out of the brush. + for (int j = solid.Sides.Count; j-- > 0;) + { + VmfSolidSide side = solid.Sides[j]; + Plane clip = new Plane(pr.transform.InverseTransformPoint(new Vector3(side.Plane.P1.X, side.Plane.P1.Z, side.Plane.P1.Y) / scale), pr.transform.InverseTransformPoint(new Vector3(side.Plane.P2.X, side.Plane.P2.Z, side.Plane.P2.Y) / scale), pr.transform.InverseTransformPoint(new Vector3(side.Plane.P3.X, side.Plane.P3.Z, side.Plane.P3.Y) / scale)); + ClipUtility.ApplyClipPlane(pr, clip, false); + + // find the polygons associated with the clipping plane. + // the normal is unique and can never occur twice as that wouldn't allow the solid to be convex. + var polygons = pr.GetPolygons().Where(p => p.Plane.normal == clip.normal); + foreach (var polygon in polygons) + { + // detect excluded polygons. + if (IsExcludedMaterial(side.Material)) + polygon.UserExcludeFromFinal = true; + // detect collision-only brushes. + if (IsInvisibleMaterial(side.Material)) + pr.IsVisible = false; + // try finding the material in the project. + polygon.Material = FindMaterial(side.Material); + // calculate the texture coordinates. + int w = 256; + int h = 256; + if (polygon.Material != null && polygon.Material.mainTexture != null) + { + w = polygon.Material.mainTexture.width; + h = polygon.Material.mainTexture.height; + } + CalculateTextureCoordinates(polygon, w, h, side.UAxis, side.VAxis, scale); + } + } + + // detail brushes that do not affect the CSG world. + if (entity.ClassName == "func_detail") + pr.IsNoCSG = true; + // collision only brushes. + if (entity.ClassName == "func_vehicleclip") + pr.IsVisible = false; + + // add the brush to the group. + pr.transform.SetParent(groupBrush.transform); + } + } + +#if UNITY_EDITOR + UnityEditor.EditorUtility.ClearProgressBar(); +#endif + } + catch (Exception) + { + throw; + } + finally + { + model.EndUpdate(); + } + } + + // shoutouts to Stefan Hajnoczi for your map importer giving me a clue on how to do this. + private static void CalculateTextureCoordinates(Polygon polygon, int textureWidth, int textureHeight, VmfAxis UAxis, VmfAxis VAxis, int scale) + { + // calculate texture coordinates. + for (int i = 0; i < polygon.Vertices.Length; i++) + { + float U, V; + + Plane uplane = new Plane(new Vector3(UAxis.Vector.X, UAxis.Vector.Z, UAxis.Vector.Y), UAxis.Translation); + Plane vplane = new Plane(new Vector3(VAxis.Vector.X, VAxis.Vector.Z, VAxis.Vector.Y), VAxis.Translation); + + U = Vector3.Dot(uplane.normal, polygon.Vertices[i].Position); + U = (U / textureWidth) / (UAxis.Scale / scale); + U = U + (UAxis.Translation / textureWidth); + + V = Vector3.Dot(vplane.normal, polygon.Vertices[i].Position); + V = (V / textureHeight) / (VAxis.Scale / scale); + V = V + (VAxis.Translation / textureHeight); + + polygon.Vertices[i].UV.x = U; + polygon.Vertices[i].UV.y = 1.0f - V; + } + } + + /// + /// Determines whether the specified name is an excluded material. + /// + /// The name of the material. + /// true if the specified name is an excluded material; otherwise, false. + private static bool IsExcludedMaterial(string name) + { + switch (name) + { + case "TOOLS/TOOLSNODRAW": + return true; + } + return false; + } + + /// + /// Determines whether the specified name is an invisible material. + /// + /// The name of the material. + /// true if the specified name is an invisible material; otherwise, false. + private static bool IsInvisibleMaterial(string name) + { + switch (name) + { + case "TOOLS/TOOLSCLIP": + case "TOOLS/TOOLSNPCCLIP": + case "TOOLS/TOOLSPLAYERCLIP": + case "TOOLS/TOOLSGRENDADECLIP": + case "TOOLS/TOOLSSTAIRS": + return true; + } + return false; + } + + /// + /// Determines whether the specified name is a special material, these brush will not be + /// imported into SabreCSG. + /// + /// The name of the material. + /// true if the specified name is a special material; otherwise, false. + private static bool IsSpecialMaterial(string name) + { + switch (name) + { + case "TOOLS/TOOLSTRIGGER": + case "TOOLS/TOOLSBLOCK_LOS": + case "TOOLS/TOOLSBLOCKBULLETS": + case "TOOLS/TOOLSBLOCKBULLETS2": + case "TOOLS/TOOLSBLOCKSBULLETSFORCEFIELD": // did the wiki have a typo or is BLOCKS truly plural? + case "TOOLS/TOOLSBLOCKLIGHT": + case "TOOLS/TOOLSCLIMBVERSUS": + case "TOOLS/TOOLSHINT": + case "TOOLS/TOOLSINVISIBLE": + case "TOOLS/TOOLSINVISIBLENONSOLID": + case "TOOLS/TOOLSINVISIBLELADDER": + case "TOOLS/TOOLSINVISMETAL": + case "TOOLS/TOOLSNODRAWROOF": + case "TOOLS/TOOLSNODRAWWOOD": + case "TOOLS/TOOLSNODRAWPORTALABLE": + case "TOOLS/TOOLSSKIP": + case "TOOLS/TOOLSFOG": + case "TOOLS/TOOLSSKYBOX": + case "TOOLS/TOOLS2DSKYBOX": + case "TOOLS/TOOLSSKYFOG": + case "TOOLS/TOOLSFOGVOLUME": + return true; + } + return false; + } + + /// + /// Attempts to find a material in the project by name. + /// + /// The material name to search for. + /// The material if found or null. + private static Material FindMaterial(string name) + { +#if UNITY_EDITOR + // first try finding the fully qualified texture name with '/' replaced by '.' so 'BRICK.BRICKWALL052D'. + name = name.Replace("/", "."); + string texture = ""; + string guid = UnityEditor.AssetDatabase.FindAssets("t:Material " + name).FirstOrDefault(); + if (guid == null) + { + // if it couldn't be found try a simplified name like 'BRICKWALL052D'. + texture = name; + if (name.Contains('.')) + texture = name.Substring(name.LastIndexOf('.') + 1); + guid = UnityEditor.AssetDatabase.FindAssets("t:Material " + texture).FirstOrDefault(); + } + // if a material could be found using either option: + if (guid != null) + { + // load the material. + string path = UnityEditor.AssetDatabase.GUIDToAssetPath(guid); + return UnityEditor.AssetDatabase.LoadAssetAtPath(path); + } + else { Debug.Log("SabreCSG: Tried to find material '" + name + "' and also as '" + texture + "' but it couldn't be found in the project."); } +#endif + return null; + } + } +} + +#endif \ No newline at end of file diff --git a/Scripts/Importers/ValveMapFormat2006/VmfWorldConverter.cs.meta b/Scripts/Importers/ValveMapFormat2006/VmfWorldConverter.cs.meta new file mode 100644 index 00000000..d5b2927f --- /dev/null +++ b/Scripts/Importers/ValveMapFormat2006/VmfWorldConverter.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 219f26bf13ff0ec4681a6ad1755ded93 +timeCreated: 1526732201 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Tools/DrawEditor.cs b/Scripts/Tools/DrawEditor.cs index 088a0193..44b846ab 100644 --- a/Scripts/Tools/DrawEditor.cs +++ b/Scripts/Tools/DrawEditor.cs @@ -1,111 +1,170 @@ #if UNITY_EDITOR -using UnityEngine; -using System.Collections; -using UnityEditor; + using System.Collections.Generic; -using System.Linq; +using UnityEditor; +using UnityEngine; namespace Sabresaurus.SabreCSG { public class DrawEditor : Tool { - Polygon activePolygon = null; // The polygon currently overriding the grid plane - PrimitiveBrush activeBrush = null; // The polygon currently overriding the grid plane - - Vector3 downPoint; // The 3D point the mouse was over at the start of the mouse click - Vector3 hoverPoint; // The 3D point the mouse is hovering over - - // Whether a drawing operation is taking place and what it is - enum DrawMode - { - None, // Drawing is not active or has been cancelled - Ambiguous, // They've started drawing but we're not sure if it's a rectangle or point sequence - RectangleBase, // They're drawing a rectangle through a click and drag - PolygonBase // They're defining a polygon by clicking a sequence of points - }; - // Current drawing operation - DrawMode drawMode = DrawMode.None; - - CSGMode csgMode = CSGMode.Add; // What sort of brush is currently being created - - bool selectingHeight = false; // In 3D views after drawing the prism base the height maps to the mouse - float prismHeight = 0; // The height (or depth) of the prism being created - - float unroundedPrismHeight = 0; // Used to preserve height changes that have been snapped - - // The 3D points that they have clicked, in rectangle mode this is just the start and end point - List hitPoints = new List(); - - bool startedSubtract = false; - bool ignoreNextMouseUp = false; // Double clicks occur in the down event, so we need to then ignore next mouse up - - bool Is3DView - { - get - { - if(!Camera.current.orthographic - || EditorHelper.GetSceneViewCamera(Camera.current) == EditorHelper.SceneViewCamera.Other) - { - return true; - } - else - { - return false; - } - } - } + /// + /// The polygon currently overriding the grid plane. + /// + private Polygon activePolygon = null; + + /// + /// The polygon currently overriding the grid plane. + /// + private PrimitiveBrush activeBrush = null; + + /// + /// The 3D point the mouse was over at the start of the mouse click. + /// + private Vector3 downPoint; + + /// + /// The 3D point the mouse is hovering over. + /// + private Vector3 hoverPoint; + + /// + /// The types of drawing operations. + /// + private enum DrawMode + { + /// + /// Drawing is not active or has been cancelled. + /// + None, + + /// + /// They've started drawing but we're not sure if it's a rectangle or point sequence. + /// + Ambiguous, + + /// + /// They're drawing a rectangle through a click and drag. + /// + RectangleBase, + + /// + /// They're defining a polygon by clicking a sequence of points. + /// + PolygonBase + }; + + /// + /// The current draw mode. + /// + private DrawMode drawMode = DrawMode.None; + + /// + /// The CSG mode of the brush currently being drawn. + /// + private CSGMode csgMode = CSGMode.Add; + + /// + /// In 3D views after drawing the prism base, the height maps to the mouse. + /// + private bool selectingHeight = false; + + /// + /// The height (or depth) of the prism being created. + /// + private float prismHeight = 0; + + /// + /// Used to preserve height changes that have been snapped. + /// + private float unroundedPrismHeight = 0; + + /// + /// The 3D points that they have clicked, in rectangle mode this is just the start and end point. + /// + private List hitPoints = new List(); + + /// + /// Whether the user has been holding shift throughout the entire drawing process. + /// + private bool startedSubtract = false; + + /// + /// Double clicks occur in the mouse down event, so we need to then ignore next mouse up. + /// + private bool ignoreNextMouseUp = false; + + private bool Is3DView + { + get + { + if (!Camera.current.orthographic + || EditorHelper.GetSceneViewCamera(Camera.current) == EditorHelper.SceneViewCamera.Other) + { + return true; + } + else + { + return false; + } + } + } public override void ResetTool() { - Selection.activeGameObject = null; - drawMode = DrawMode.None; - hitPoints.Clear(); - activePolygon = null; - selectingHeight = false; - prismHeight = 0; + // Set the selection to the last selected brush (usually the last drawn brush) + if (CSGModel && CSGModel.LastSelectedBrush != null) + Selection.activeGameObject = CSGModel.LastSelectedBrush.gameObject; + else + Selection.activeGameObject = null; + drawMode = DrawMode.None; + hitPoints.Clear(); + activePolygon = null; + selectingHeight = false; + prismHeight = 0; unroundedPrismHeight = 0; } public override void OnSceneGUI(SceneView sceneView, Event e) { - base.OnSceneGUI(sceneView, e); // Allow the base logic to calculate first - - if(e.button == 0 - && !EditorHelper.IsMousePositionInInvalidRects(e.mousePosition) - && !CameraPanInProgress) - { - if (e.type == EventType.MouseDown) - { - OnMouseDown(sceneView, e); - } - else if (e.type == EventType.MouseDrag) - { - OnMouseDrag(sceneView, e); - } - else if (e.type == EventType.MouseMove) - { - OnMouseMove(sceneView, e); - } - // If you mouse up on a different scene view to the one you started on it's surpressed as Ignore, so - // make sure to check the real type - else if (e.type == EventType.MouseUp || e.rawType == EventType.MouseUp) - { - OnMouseUp(sceneView, e); - } - } - - if (e.type == EventType.KeyDown || e.type == EventType.KeyUp) - { - OnKeyAction(sceneView, e); - } - - if (e.type == EventType.Layout || e.type == EventType.Repaint) - { - OnRepaint(sceneView, e); - } + base.OnSceneGUI(sceneView, e); // Allow the base logic to calculate first + + if (e.button == 0 + && !EditorHelper.IsMousePositionInInvalidRects(e.mousePosition) + && !CameraPanInProgress) + { + if (e.type == EventType.MouseDown) + { + OnMouseDown(sceneView, e); + } + else if (e.type == EventType.MouseDrag) + { + OnMouseDrag(sceneView, e); + } + else if (e.type == EventType.MouseMove) + { + OnMouseMove(sceneView, e); + } + // If you mouse up on a different scene view to the one you started on it's surpressed as Ignore, so + // make sure to check the real type + else if (e.type == EventType.MouseUp || e.rawType == EventType.MouseUp) + { + OnMouseUp(sceneView, e); + } + } + + if (e.type == EventType.KeyDown || e.type == EventType.KeyUp) + { + OnKeyAction(sceneView, e); + } + + if (e.type == EventType.Layout || e.type == EventType.Repaint) + { + OnRepaint(sceneView, e); + } } - Polygon GetActivePolygon() + private Polygon GetActivePolygon() { if (Camera.current.orthographic && EditorHelper.GetSceneViewCamera(Camera.current) != EditorHelper.SceneViewCamera.Other) { @@ -118,55 +177,55 @@ Polygon GetActivePolygon() } } - Plane GetActivePlane() - { - if(Camera.current.orthographic && EditorHelper.GetSceneViewCamera(Camera.current) != EditorHelper.SceneViewCamera.Other) - { - // Axis aligned iso view - return new Plane() { normal = -Camera.current.transform.forward, distance = 0 }; - } - else - { - if(activePolygon != null) - { - // A polygon plane is overriding the grid plane, so return that - return activePolygon.Plane; - } - else - { - // No plane override, so use ground plane - return new Plane() { normal = Vector3.up, distance = 0 }; - } - } - } - - PolygonRaycastHit? CalculateHitPolygon(Vector2 currentPosition) - { - if(EditorHelper.GetSceneViewCamera(SceneView.lastActiveSceneView) == EditorHelper.SceneViewCamera.Other) - { - // Convert the mouse position into a ray to intersect with a plane in the world - Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); - List hits = csgModel.RaycastBrushesAll(currentRay, false); - if(hits.Count > 0) - { - return hits[0]; - } - else - { - return null; - } - } - else - { - // If the scene view is axis-aligned iso then we don't raycast polygons - return null; - } - } - - bool IsPrismBaseValid(List points) + private Plane GetActivePlane() + { + if (Camera.current.orthographic && EditorHelper.GetSceneViewCamera(Camera.current) != EditorHelper.SceneViewCamera.Other) + { + // Axis aligned iso view + return new Plane() { normal = -Camera.current.transform.forward, distance = 0 }; + } + else + { + if (activePolygon != null) + { + // A polygon plane is overriding the grid plane, so return that + return activePolygon.Plane; + } + else + { + // No plane override, so use ground plane + return new Plane() { normal = Vector3.up, distance = 0 }; + } + } + } + + private PolygonRaycastHit? CalculateHitPolygon(Vector2 currentPosition) + { + if (EditorHelper.GetSceneViewCamera(SceneView.lastActiveSceneView) == EditorHelper.SceneViewCamera.Other) + { + // Convert the mouse position into a ray to intersect with a plane in the world + Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); + List hits = csgModel.RaycastBrushesAll(currentRay, false); + if (hits.Count > 0) + { + return hits[0]; + } + else + { + return null; + } + } + else + { + // If the scene view is axis-aligned iso then we don't raycast polygons + return null; + } + } + + private bool IsPrismBaseValid(List points) { Vector2 hitPointsSize = CalculateHitPointsSize(points); - + if (hitPointsSize.x > 0 && hitPointsSize.y > 0) { return true; @@ -177,7 +236,7 @@ bool IsPrismBaseValid(List points) } } - Vector2 CalculateHitPointsSize(List points) + private Vector2 CalculateHitPointsSize(List points) { Vector3 normal = GetActivePlane().normal; Vector3 tangent = Vector3.zero; @@ -185,14 +244,14 @@ Vector2 CalculateHitPointsSize(List points) for (int i = 0; i < points.Count; i++) { Vector3 delta = points[(i + 1) % points.Count] - points[i]; - if(delta.magnitude > 0.01f) + if (delta.magnitude > 0.01f) { tangent = delta.normalized; break; } } - if(tangent == Vector3.zero) + if (tangent == Vector3.zero) { if (Vector3.Dot(normal.Abs(), Vector3.up) > 0.9f) { @@ -227,22 +286,22 @@ Vector2 CalculateHitPointsSize(List points) return new Vector2(maxX - minX, maxY - minY); } - Vector3? GetHitPoint(Vector2 currentPosition) - { - // Conver the mouse position into a ray to intersect with a plane in the world - Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); + private Vector3? GetHitPoint(Vector2 currentPosition) + { + // Conver the mouse position into a ray to intersect with a plane in the world + Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); - // Find the currently active plane - Plane plane = GetActivePlane(); + // Find the currently active plane + Plane plane = GetActivePlane(); - // If we hit the plane, return the hit point, otherwise return null - float distance; - if(plane.Raycast(currentRay, out distance)) - { - Vector3 hitPoint = currentRay.GetPoint(distance); + // If we hit the plane, return the hit point, otherwise return null + float distance; + if (plane.Raycast(currentRay, out distance)) + { + Vector3 hitPoint = currentRay.GetPoint(distance); - if(CurrentSettings.PositionSnappingEnabled) - { + if (CurrentSettings.PositionSnappingEnabled) + { Polygon activePolygon = GetActivePolygon(); if (activePolygon != null) @@ -260,265 +319,285 @@ Vector2 CalculateHitPointsSize(List points) } else { - hitPoint = MathHelper.RoundVector3(hitPoint, CurrentSettings.PositionSnapDistance); + hitPoint = MathHelper.RoundVector3(hitPoint, CurrentSettings.PositionSnapDistance); } - } - return hitPoint; - } - else - { - return null; - } - } - - void UpdateCSGMode(Event e) - { - csgMode = e.shift ? CSGMode.Subtract : CSGMode.Add; - if(csgMode == CSGMode.Add) - { - startedSubtract = false; - } - } - - void OnMouseDown(SceneView sceneView, Event e) - { + } + return hitPoint; + } + else + { + return null; + } + } + + private void UpdateCSGMode(Event e) + { + // if the user is drawing against a polygon: + if (activePolygon != null) + { + // drawing into the polygon makes us subtract. + csgMode = (prismHeight < 0.0f) ? CSGMode.Subtract : CSGMode.Add; + // the user can hold shift to invert the logic. + if (e.shift) + { + csgMode = (csgMode == CSGMode.Add) ? CSGMode.Subtract : CSGMode.Add; + } + } + + // if the user is drawing in the air: + else + { + // the user can hold shift to invert the logic. + csgMode = e.shift ? CSGMode.Subtract : CSGMode.Add; + } + } + + private void OnMouseDown(SceneView sceneView, Event e) + { + if (drawMode == DrawMode.None || drawMode == DrawMode.Ambiguous) + { + startedSubtract = e.shift; + } + UpdateCSGMode(e); if (selectingHeight) return; - - if(e.clickCount == 2) - { - // Double click, so finish the polygon - if(drawMode == DrawMode.PolygonBase) - { - if(Is3DView && !startedSubtract) - { - selectingHeight = true; - prismHeight = 0; - ignoreNextMouseUp = true; - SceneView.RepaintAll(); - } - else - { - CreateBrush(hitPoints); - - ResetTool(); - - sceneView.Repaint(); - } - } - } - else - { - if(drawMode == DrawMode.None) - { - PolygonRaycastHit? hit = CalculateHitPolygon(e.mousePosition); - if(hit.HasValue) - { - activePolygon = hit.Value.Polygon; - activeBrush = hit.Value.GameObject.GetComponent(); - } - else - { - activePolygon = null; - activeBrush = null; - } - - - Vector3? hitPoint = GetHitPoint(e.mousePosition); - if(hitPoint.HasValue) - { - downPoint = hitPoint.Value; - hoverPoint = downPoint; - } - - hitPoints.Clear(); - - if(hitPoint.HasValue) - { - drawMode = DrawMode.Ambiguous; - } - } - else - { - Vector3? hitPoint = GetHitPoint(e.mousePosition); - if(hitPoint.HasValue) - { - downPoint = hitPoint.Value; - hoverPoint = downPoint; - } - } - } - } - - void OnMouseDrag(SceneView sceneView, Event e) - { - UpdateCSGMode(e); - Vector3? hitPoint = GetHitPoint(e.mousePosition); - - if(hitPoint.HasValue) - { - if(drawMode == DrawMode.PolygonBase && !selectingHeight) + if (e.clickCount == 2) + { + // Double click, so finish the polygon + if (drawMode == DrawMode.PolygonBase) + { + if (Is3DView && !startedSubtract) + { + selectingHeight = true; + prismHeight = 0; + ignoreNextMouseUp = true; + SceneView.RepaintAll(); + } + else + { + CreateBrush(hitPoints); + + ResetTool(); + + sceneView.Repaint(); + } + } + } + else + { + if (drawMode == DrawMode.None) + { + PolygonRaycastHit? hit = CalculateHitPolygon(e.mousePosition); + if (hit.HasValue) + { + activePolygon = hit.Value.Polygon; + activeBrush = hit.Value.GameObject.GetComponent(); + } + else + { + activePolygon = null; + activeBrush = null; + } + + Vector3? hitPoint = GetHitPoint(e.mousePosition); + if (hitPoint.HasValue) + { + downPoint = hitPoint.Value; + hoverPoint = downPoint; + } + + hitPoints.Clear(); + + if (hitPoint.HasValue) + { + drawMode = DrawMode.Ambiguous; + } + } + else + { + Vector3? hitPoint = GetHitPoint(e.mousePosition); + if (hitPoint.HasValue) + { + downPoint = hitPoint.Value; + hoverPoint = downPoint; + } + } + } + } + + private void OnMouseDrag(SceneView sceneView, Event e) + { + // if the user stopped holding shift we cancel the automatic height. + if (!e.shift) + startedSubtract = false; + + UpdateCSGMode(e); + Vector3? hitPoint = GetHitPoint(e.mousePosition); + + if (hitPoint.HasValue) + { + if (drawMode == DrawMode.PolygonBase && !selectingHeight) + { + hoverPoint = hitPoint.Value; + SceneView.RepaintAll(); + } + + if (drawMode == DrawMode.Ambiguous) + { + hitPoints.Clear(); + drawMode = DrawMode.RectangleBase; + hitPoints.Add(downPoint); + } + + if (drawMode == DrawMode.Ambiguous || (drawMode == DrawMode.RectangleBase && !selectingHeight)) + { + if (hitPoints.Count < 2) + { + hitPoints.Add(hitPoint.Value); + } + else + { + hitPoints[1] = hitPoint.Value; + } + + // We have something to draw so make sure the sceneview repaints + sceneView.Repaint(); + + drawMode = DrawMode.RectangleBase; + } + } + } + + private void OnMouseMoveSelectHeight(SceneView sceneView, Event e) + { + Rect pixelRect = sceneView.camera.pixelRect; + + // Resize a handle + Vector2 currentPosition = e.mousePosition; + + // Clamp the current position to the screen rect. Otherwise we get some odd problems if you carry on + // resizing off screen. + currentPosition.x = Mathf.Clamp(currentPosition.x, pixelRect.xMin, pixelRect.xMax); + currentPosition.y = Mathf.Clamp(currentPosition.y, pixelRect.yMin, pixelRect.yMax); + + Vector2 lastPosition = currentPosition - e.delta; + + Ray lastRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(lastPosition)); + + Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); + Vector3 direction = GetActivePlane().normal; + + Vector3 lineStart = hitPoints[0]; + Vector3 lineEnd = hitPoints[0] + direction; + + Vector3 lastPositionWorld = MathHelper.ClosestPointOnLine(lastRay, lineStart, lineEnd); + Vector3 currentPositionWorld = MathHelper.ClosestPointOnLine(currentRay, lineStart, lineEnd); + + Vector3 deltaWorld = (currentPositionWorld - lastPositionWorld); + + float deltaScale = Vector3.Dot(direction, deltaWorld); + float snapDistance = CurrentSettings.PositionSnapDistance; + + if (CurrentSettings.PositionSnappingEnabled) + { + deltaScale += unroundedPrismHeight; + float roundedDeltaScale = MathHelper.RoundFloat(deltaScale, snapDistance); + + unroundedPrismHeight = deltaScale - roundedDeltaScale; + deltaScale = roundedDeltaScale; + } + + prismHeight += deltaScale; + + SceneView.RepaintAll(); + } + + private void OnMouseMove(SceneView sceneView, Event e) + { + // if the user stopped holding shift we cancel the automatic height. + if (!e.shift) + startedSubtract = false; + + UpdateCSGMode(e); + + if (selectingHeight) + { + // Mouse movement while selecting depth controls prism height + OnMouseMoveSelectHeight(sceneView, e); + } + else + { + // Not currently drawing, so update the active polygon to whatever they are currently hovering over + if (drawMode == DrawMode.None) + { + PolygonRaycastHit? hit = CalculateHitPolygon(e.mousePosition); + if (hit.HasValue) + { + activePolygon = hit.Value.Polygon; + activeBrush = hit.Value.GameObject.GetComponent(); + } + else + { + activePolygon = null; + activeBrush = null; + } + } + + // Find the snapped hover point based on any active polygon or the grid + Vector3? hitPoint = GetHitPoint(e.mousePosition); + if (hitPoint.HasValue) { hoverPoint = hitPoint.Value; SceneView.RepaintAll(); } + } + } + + private void OnMouseUp(SceneView sceneView, Event e) + { + if (ignoreNextMouseUp) + { + // Double click just occurred, so don't process the up event + ignoreNextMouseUp = false; + return; + } + + // if the user stopped holding shift we cancel the automatic height. + if (!e.shift) + startedSubtract = false; + + UpdateCSGMode(e); + + if (selectingHeight) + { + if (drawMode == DrawMode.RectangleBase) + { + CreateBrush(GetRectanglePoints()); + } + else + { + CreateBrush(hitPoints); + } + selectingHeight = false; - if(drawMode == DrawMode.Ambiguous) - { - if(drawMode != DrawMode.RectangleBase) - { - startedSubtract = e.shift; - } - hitPoints.Clear(); - drawMode = DrawMode.RectangleBase; - hitPoints.Add(downPoint); - } - - if(drawMode == DrawMode.Ambiguous - || (drawMode == DrawMode.RectangleBase && !selectingHeight)) - { - if(hitPoints.Count < 2) - { - hitPoints.Add(hitPoint.Value); - } - else - { - hitPoints[1] = hitPoint.Value; - } - - // We have something to draw so make sure the sceneview repaints - sceneView.Repaint(); - - if(drawMode != DrawMode.RectangleBase) - { - startedSubtract = e.shift; - } - drawMode = DrawMode.RectangleBase; - } - } - } - - void OnMouseMoveSelectHeight(SceneView sceneView, Event e) - { - Rect pixelRect = sceneView.camera.pixelRect; - - // Resize a handle - Vector2 currentPosition = e.mousePosition; - - // Clamp the current position to the screen rect. Otherwise we get some odd problems if you carry on - // resizing off screen. - currentPosition.x = Mathf.Clamp(currentPosition.x, pixelRect.xMin, pixelRect.xMax); - currentPosition.y = Mathf.Clamp(currentPosition.y, pixelRect.yMin, pixelRect.yMax); - - Vector2 lastPosition = currentPosition - e.delta; - - Ray lastRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(lastPosition)); - - Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); - Vector3 direction = GetActivePlane().normal; - - Vector3 lineStart = hitPoints[0]; - Vector3 lineEnd = hitPoints[0] + direction; - - Vector3 lastPositionWorld = MathHelper.ClosestPointOnLine(lastRay, lineStart, lineEnd); - Vector3 currentPositionWorld = MathHelper.ClosestPointOnLine(currentRay, lineStart, lineEnd); - - Vector3 deltaWorld = (currentPositionWorld - lastPositionWorld); - - float deltaScale = Vector3.Dot(direction, deltaWorld); - float snapDistance = CurrentSettings.PositionSnapDistance; - - if (CurrentSettings.PositionSnappingEnabled) - { - deltaScale += unroundedPrismHeight; - float roundedDeltaScale = MathHelper.RoundFloat(deltaScale, snapDistance); - - unroundedPrismHeight = deltaScale- roundedDeltaScale; - deltaScale = roundedDeltaScale; - } - - prismHeight += deltaScale; - - SceneView.RepaintAll(); - } - - void OnMouseMove(SceneView sceneView, Event e) - { - UpdateCSGMode(e); - - if(selectingHeight) - { - // Mouse movement while selecting depth controls prism height - OnMouseMoveSelectHeight(sceneView, e); - } - else - { - // Not currently drawing, so update the active polygon to whatever they are currently hovering over - if(drawMode == DrawMode.None) - { - PolygonRaycastHit? hit = CalculateHitPolygon(e.mousePosition); - if(hit.HasValue) - { - activePolygon = hit.Value.Polygon; - activeBrush = hit.Value.GameObject.GetComponent(); - } - else - { - activePolygon = null; - activeBrush = null; - } - } - - // Find the snapped hover point based on any active polygon or the grid - Vector3? hitPoint = GetHitPoint(e.mousePosition); - if(hitPoint.HasValue) - { - hoverPoint = hitPoint.Value; - SceneView.RepaintAll(); - } - } - } - - void OnMouseUp(SceneView sceneView, Event e) - { - if(ignoreNextMouseUp) - { - // Double click just occurred, so don't process the up event - ignoreNextMouseUp = false; - return; - } - UpdateCSGMode(e); - - if(selectingHeight) - { - if(drawMode == DrawMode.RectangleBase) - { - CreateBrush(GetRectanglePoints()); - } - else - { - CreateBrush(hitPoints); - } - selectingHeight = false; - - ResetTool(); - - sceneView.Repaint(); + ResetTool(); + + sceneView.Repaint(); } else { if (drawMode == DrawMode.RectangleBase) { if (Is3DView && !startedSubtract) - { + { // Verify that it will form a valid prism by trying to create a polygon out the base - if(IsPrismBaseValid(GetRectanglePoints())) + if (IsPrismBaseValid(GetRectanglePoints())) { - selectingHeight = true; - prismHeight = 0; + selectingHeight = true; + prismHeight = 0; } else { @@ -528,29 +607,29 @@ void OnMouseUp(SceneView sceneView, Event e) sceneView.Repaint(); } } - else - { - CreateBrush(GetRectanglePoints()); + else + { + CreateBrush(GetRectanglePoints()); - ResetTool(); + ResetTool(); - sceneView.Repaint(); - } - } - else if(drawMode == DrawMode.Ambiguous || drawMode == DrawMode.PolygonBase) - { - Vector3? hitPoint = GetHitPoint(e.mousePosition); + sceneView.Repaint(); + } + } + else if (drawMode == DrawMode.Ambiguous || drawMode == DrawMode.PolygonBase) + { + Vector3? hitPoint = GetHitPoint(e.mousePosition); - if(hitPoint.HasValue) - { - drawMode = DrawMode.PolygonBase; + if (hitPoint.HasValue) + { + drawMode = DrawMode.PolygonBase; - hitPoints.Add(hitPoint.Value); + hitPoints.Add(hitPoint.Value); - if(hitPoints.Count > 2 && hitPoint.Value.EqualsWithEpsilon(hitPoints[0])) - { - if(Is3DView && !startedSubtract) - { + if (hitPoints.Count > 2 && hitPoint.Value.EqualsWithEpsilon(hitPoints[0])) + { + if (Is3DView && !startedSubtract) + { // Verify that it will form a valid prism by trying to create a polygon out the base if (IsPrismBaseValid(hitPoints)) { @@ -565,31 +644,31 @@ void OnMouseUp(SceneView sceneView, Event e) sceneView.Repaint(); } } - else - { - CreateBrush(hitPoints); + else + { + CreateBrush(hitPoints); - ResetTool(); + ResetTool(); - sceneView.Repaint(); - } - } - } - } - } - } + sceneView.Repaint(); + } + } + } + } + } + } - void CreateBrush(List positions) - { - Polygon sourcePolygon = PolygonFactory.ConstructPolygon(positions, true); + private void CreateBrush(List positions) + { + Polygon sourcePolygon = PolygonFactory.ConstructPolygon(positions, true); - // Early out if it wasn't possible to create the polygon - if(sourcePolygon == null) - { - return; - } + // Early out if it wasn't possible to create the polygon + if (sourcePolygon == null) + { + return; + } - if(activePolygon != null) + if (activePolygon != null) { for (int i = 0; i < sourcePolygon.Vertices.Length; i++) { @@ -598,85 +677,85 @@ void CreateBrush(List positions) } } - Vector3 planeNormal = GetActivePlane().normal; - -// Debug.Log(Vector3.Dot(sourcePolygon.Plane.normal, planeNormal)); - - // Flip the polygon if the winding order is wrong - if(Vector3.Dot(sourcePolygon.Plane.normal, planeNormal) < 0) - { - sourcePolygon.Flip(); - - // Need to flip the UVs across the U (X) direction - for (int i = 0; i < sourcePolygon.Vertices.Length; i++) - { - Vector2 uv = sourcePolygon.Vertices[i].UV; - uv.x = 1 - uv.x; - sourcePolygon.Vertices[i].UV = uv; - } - } - - float extrusionDistance = 1; - Vector3 positionOffset = Vector3.zero; - - if(selectingHeight) - { - extrusionDistance = prismHeight; - } - else - { - if(activePolygon != null && activeBrush != null) - { - extrusionDistance = activeBrush.CalculateExtentsInAxis(planeNormal); - } - else - { - Brush lastSelectedBrush = csgModel.LastSelectedBrush; - if(lastSelectedBrush != null) - { - Bounds lastSelectedBrushBounds = lastSelectedBrush.GetBoundsTransformed(); - - for (int i = 0; i < 3; i++) - { - if(!planeNormal[i].EqualsWithEpsilon(0)) - { - if(lastSelectedBrushBounds.size[i] != 0) - { - extrusionDistance = lastSelectedBrushBounds.size[i]; - - if(planeNormal[i] > 0) - { - positionOffset[i] = lastSelectedBrushBounds.center[i] - lastSelectedBrushBounds.extents[i]; - } - else - { - positionOffset[i] = lastSelectedBrushBounds.center[i] + lastSelectedBrushBounds.extents[i]; - } - } - } - } - } - } - - // Subtractions should go through - if(csgMode == CSGMode.Subtract) - { - sourcePolygon.Flip(); - } - } - - Quaternion rotation; - Polygon[] polygons; - SurfaceUtility.ExtrudePolygon(sourcePolygon, extrusionDistance, out polygons, out rotation); - - GameObject newObject = csgModel.CreateCustomBrush(polygons); - - PrimitiveBrush newBrush = newObject.GetComponent(); - - newObject.transform.rotation = rotation; - newObject.transform.position += positionOffset; - - if(activePolygon != null + Vector3 planeNormal = GetActivePlane().normal; + + // Debug.Log(Vector3.Dot(sourcePolygon.Plane.normal, planeNormal)); + + // Flip the polygon if the winding order is wrong + if (Vector3.Dot(sourcePolygon.Plane.normal, planeNormal) < 0) + { + sourcePolygon.Flip(); + + // Need to flip the UVs across the U (X) direction + for (int i = 0; i < sourcePolygon.Vertices.Length; i++) + { + Vector2 uv = sourcePolygon.Vertices[i].UV; + uv.x = 1 - uv.x; + sourcePolygon.Vertices[i].UV = uv; + } + } + + float extrusionDistance = 1; + Vector3 positionOffset = Vector3.zero; + + if (selectingHeight) + { + extrusionDistance = prismHeight; + } + else + { + if (activePolygon != null && activeBrush != null) + { + extrusionDistance = activeBrush.CalculateExtentsInAxis(planeNormal); + } + else + { + Brush lastSelectedBrush = csgModel.LastSelectedBrush; + if (lastSelectedBrush != null) + { + Bounds lastSelectedBrushBounds = lastSelectedBrush.GetBoundsTransformed(); + + for (int i = 0; i < 3; i++) + { + if (!planeNormal[i].EqualsWithEpsilon(0)) + { + if (lastSelectedBrushBounds.size[i] != 0) + { + extrusionDistance = lastSelectedBrushBounds.size[i]; + + if (planeNormal[i] > 0) + { + positionOffset[i] = lastSelectedBrushBounds.center[i] - lastSelectedBrushBounds.extents[i]; + } + else + { + positionOffset[i] = lastSelectedBrushBounds.center[i] + lastSelectedBrushBounds.extents[i]; + } + } + } + } + } + } + + // Subtractions should go through + if (csgMode == CSGMode.Subtract) + { + sourcePolygon.Flip(); + } + } + + Quaternion rotation; + Polygon[] polygons; + SurfaceUtility.ExtrudePolygon(sourcePolygon, extrusionDistance, out polygons, out rotation); + + GameObject newObject = csgModel.CreateCustomBrush(polygons); + + PrimitiveBrush newBrush = newObject.GetComponent(); + + newObject.transform.rotation = rotation; + newObject.transform.position += positionOffset; + + if (activePolygon != null && activePolygon.Material != csgModel.GetDefaultMaterial()) { for (int i = 0; i < polygons.Length; i++) @@ -684,274 +763,270 @@ void CreateBrush(List positions) polygons[i].Material = activePolygon.Material; } } - // Finally give the new brush the other set of polygons - newBrush.SetPolygons(polygons, true); - - newBrush.Mode = csgMode; - - newBrush.ResetPivot(); - - // Use this brush as the basis for drawing the next brush - csgModel.SetLastSelectedBrush(newBrush); - - Undo.RegisterCreatedObjectUndo(newObject, "Draw Brush"); - } - - void OnKeyAction(SceneView sceneView, Event e) - { - if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.CancelCurrentOperation))) - { - if (e.type == EventType.KeyDown) - { - if(drawMode != DrawMode.None || hitPoints.Count > 0) - { - // Drawing is in progress so cancel it - ResetTool(); - } - else - { - // No draw in progress, so user wants to cancel out of draw mode - csgModel.ExitOverrideMode(); - } - } - e.Use(); - } - else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.Back)) - || KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.Delete), false, true)) - { - if (e.type == EventType.KeyDown) - { - if(drawMode == DrawMode.PolygonBase) - { - if(hitPoints.Count > 1) - { - // Remove the last point - hitPoints.RemoveAt(hitPoints.Count-1); - } - else - { - ResetTool(); - } - } - else - { - ResetTool(); - } - } - e.Use(); - } - } - - List GetRectanglePoints() - { - Plane plane = GetActivePlane(); + // Finally give the new brush the other set of polygons + newBrush.SetPolygons(polygons, true); + + newBrush.Mode = csgMode; + + newBrush.ResetPivot(); + + // Use this brush as the basis for drawing the next brush + csgModel.SetLastSelectedBrush(newBrush); + + Undo.RegisterCreatedObjectUndo(newObject, "Draw Brush"); + } + + private void OnKeyAction(SceneView sceneView, Event e) + { + if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.CancelCurrentOperation))) + { + if (e.type == EventType.KeyDown) + { + if (drawMode != DrawMode.None || hitPoints.Count > 0) + { + // Drawing is in progress so cancel it + ResetTool(); + } + else + { + // No draw in progress, so user wants to cancel out of draw mode + csgModel.ExitOverrideMode(); + } + } + e.Use(); + } + else if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.Back)) + || KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.Delete), false, true)) + { + if (e.type == EventType.KeyDown) + { + if (drawMode == DrawMode.PolygonBase) + { + if (hitPoints.Count > 1) + { + // Remove the last point + hitPoints.RemoveAt(hitPoints.Count - 1); + } + else + { + ResetTool(); + } + } + else + { + ResetTool(); + } + } + e.Use(); + } + } + + private List GetRectanglePoints() + { + Plane plane = GetActivePlane(); Vector3 planeNormal = plane.normal; //MathHelper.VectorAbs(plane.normal); - Vector3 axis1; - Vector3 axis2; - - if(Vector3.Dot(planeNormal.Abs(), Vector3.up) > 0.99f) - { - axis1 = Vector3.forward; - axis2 = Vector3.right; - } - else - { - axis1 = Vector3.up; - axis2 = Vector3.Cross(Vector3.up, planeNormal).normalized; - } - - - Vector3 startPoint = hitPoints[0]; - Vector3 endPoint = hitPoints[1]; - - List points = new List(4); - - Vector3 delta = endPoint - startPoint; - - Vector3 deltaAxis1 = Vector3.Dot(delta, axis1) * axis1; - Vector3 deltaAxis2 = Vector3.Dot(delta, axis2) * axis2; - - points.Add(startPoint); - points.Add(startPoint + deltaAxis1); - points.Add(endPoint); - points.Add(startPoint + deltaAxis2); - - return points; - } - - void OnRepaint(SceneView sceneView, Event e) - { - Camera sceneViewCamera = sceneView.camera; - -// if(hoverPoint.HasValue) - { - // Draw the active polygon - if(activePolygon != null) - { - SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); - - SabreGraphics.DrawPolygons(new Color(1,1,0,0.15f), new Color(1,1,0,0.5f), activePolygon); - } - - - SabreCSGResources.GetVertexMaterial().SetPass (0); - GL.PushMatrix(); - GL.LoadPixelMatrix(); - - GL.Begin(GL.QUADS); - - if(activePolygon != null) - { - GL.Color(Color.yellow);// new Color(0.75f,0.75f,0.75f,1)); - } - else - { - GL.Color(Color.white); - } - - - Vector3 target = sceneViewCamera.WorldToScreenPoint(hoverPoint); - - if(target.z > 0) - { - // Make it pixel perfect - target = MathHelper.RoundVector3(target); - SabreGraphics.DrawBillboardQuad(target, 8, 8); - } - - - for (int i = 0; i < hitPoints.Count; i++) { - target = sceneViewCamera.WorldToScreenPoint(hitPoints[i]); - GL.Color(Color.blue); - if(target.z > 0) - { - // Make it pixel perfect - target = MathHelper.RoundVector3(target); - SabreGraphics.DrawBillboardQuad(target, 8, 8); - } - } - - GL.End(); - GL.PopMatrix(); - } - - if(drawMode == DrawMode.RectangleBase || drawMode == DrawMode.PolygonBase) - { - List pointsToDraw = new List(); - if(drawMode == DrawMode.RectangleBase) - { - pointsToDraw.AddRange(GetRectanglePoints()); - } - else - { - pointsToDraw.AddRange(hitPoints); - pointsToDraw.Insert(pointsToDraw.Count, hoverPoint); - } - - SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); - -// GL.Begin(GL); -// GL.Color(new Color32(0, 181, 255, 100)); -// -// // Draw each point -// for (int i = 0; i < pointsToDraw.Count; i++) -// { -// GL.Vertex(pointsToDraw[i]); -// } -// -// GL.End(); - - // Marquee border - GL.Begin(GL.LINES); - - if(csgMode == CSGMode.Add) - { - GL.Color(Color.blue); - } - else - { - GL.Color(Color.yellow); - } - - // Draw lines between all the points - for (int i = 0; i < pointsToDraw.Count; i++) - { - // In polygon mode, if it's bigger than a line, draw the last edge in grey - if(i == pointsToDraw.Count-1 - && drawMode == DrawMode.PolygonBase - && pointsToDraw.Count > 2 - && !selectingHeight) - { - GL.Color(Color.grey); - } - // Draw a line from one point to the next - GL.Vertex(pointsToDraw[i]); - GL.Vertex(pointsToDraw[(i+1) % pointsToDraw.Count]); - } - - if(selectingHeight) - { - Vector3 offset = GetActivePlane().normal * prismHeight; - - for (int i = 0; i < pointsToDraw.Count; i++) - { - // Draw a line from one point to the next - GL.Vertex(pointsToDraw[i]); - GL.Vertex(pointsToDraw[i] + offset); - } - - GL.Color(Color.grey); - // Draw grid lines along the prism to indicate size - for (int heightLine = 1; heightLine < Mathf.Abs(prismHeight); heightLine++) - { - for (int i = 0; i < pointsToDraw.Count; i++) - { - Vector3 gridOffset = GetActivePlane().normal * heightLine * Mathf.Sign(prismHeight); - // Draw a line from one point to the next - GL.Vertex(pointsToDraw[i] + gridOffset); - GL.Vertex(pointsToDraw[(i+1) % pointsToDraw.Count] + gridOffset); - } - } - - GL.Color(Color.green); - for (int i = 0; i < pointsToDraw.Count; i++) - { - // Draw a line from one point to the next - GL.Vertex(pointsToDraw[i] + offset); - GL.Vertex(pointsToDraw[(i+1) % pointsToDraw.Count] + offset); - } - } - - GL.End(); - } - -// Rect rectangle = new Rect(0, 50, 210, 130); -// GUIStyle toolbar = new GUIStyle(EditorStyles.toolbar); -// toolbar.normal.background = SabreCSGResources.ClearTexture; -// toolbar.fixedHeight = rectangle.height; -// GUILayout.Window(140010, rectangle, OnToolbarGUI, "",toolbar); - } - -// void OnToolbarGUI(int windowID) -// { -// raycastBrushes = EditorGUILayout.Toggle("Raycast Brushes", raycastBrushes); -// } - - - public override void Deactivated () - { - - } - - public override bool PreventBrushSelection - { - get - { - // Some special logic for clicking brushes - return true; - } - } + Vector3 axis1; + Vector3 axis2; + + if (Vector3.Dot(planeNormal.Abs(), Vector3.up) > 0.99f) + { + axis1 = Vector3.forward; + axis2 = Vector3.right; + } + else + { + axis1 = Vector3.up; + axis2 = Vector3.Cross(Vector3.up, planeNormal).normalized; + } + + Vector3 startPoint = hitPoints[0]; + Vector3 endPoint = hitPoints[1]; + + List points = new List(4); + + Vector3 delta = endPoint - startPoint; + + Vector3 deltaAxis1 = Vector3.Dot(delta, axis1) * axis1; + Vector3 deltaAxis2 = Vector3.Dot(delta, axis2) * axis2; + + points.Add(startPoint); + points.Add(startPoint + deltaAxis1); + points.Add(endPoint); + points.Add(startPoint + deltaAxis2); + + return points; + } + + private void OnRepaint(SceneView sceneView, Event e) + { + Camera sceneViewCamera = sceneView.camera; + + // if(hoverPoint.HasValue) + { + // Draw the active polygon + if (activePolygon != null) + { + SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); + + SabreGraphics.DrawPolygons(new Color(1, 1, 0, 0.15f), new Color(1, 1, 0, 0.5f), activePolygon); + } + + SabreCSGResources.GetVertexMaterial().SetPass(0); + GL.PushMatrix(); + GL.LoadPixelMatrix(); + + GL.Begin(GL.QUADS); + + if (activePolygon != null) + { + GL.Color(Color.yellow);// new Color(0.75f,0.75f,0.75f,1)); + } + else + { + GL.Color(Color.white); + } + + Vector3 target = sceneViewCamera.WorldToScreenPoint(hoverPoint); + + if (target.z > 0) + { + // Make it pixel perfect + target = MathHelper.RoundVector3(target); + SabreGraphics.DrawBillboardQuad(target, 8, 8); + } + + for (int i = 0; i < hitPoints.Count; i++) + { + target = sceneViewCamera.WorldToScreenPoint(hitPoints[i]); + GL.Color(Color.blue); + if (target.z > 0) + { + // Make it pixel perfect + target = MathHelper.RoundVector3(target); + SabreGraphics.DrawBillboardQuad(target, 8, 8); + } + } + + GL.End(); + GL.PopMatrix(); + } + + if (drawMode == DrawMode.RectangleBase || drawMode == DrawMode.PolygonBase) + { + List pointsToDraw = new List(); + if (drawMode == DrawMode.RectangleBase) + { + pointsToDraw.AddRange(GetRectanglePoints()); + } + else + { + pointsToDraw.AddRange(hitPoints); + pointsToDraw.Insert(pointsToDraw.Count, hoverPoint); + } + + SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); + + // GL.Begin(GL); + // GL.Color(new Color32(0, 181, 255, 100)); + // + // // Draw each point + // for (int i = 0; i < pointsToDraw.Count; i++) + // { + // GL.Vertex(pointsToDraw[i]); + // } + // + // GL.End(); + + // Marquee border + GL.Begin(GL.LINES); + + if (csgMode == CSGMode.Add) + { + GL.Color(Color.blue); + } + else + { + GL.Color(Color.yellow); + } + + // Draw lines between all the points + for (int i = 0; i < pointsToDraw.Count; i++) + { + // In polygon mode, if it's bigger than a line, draw the last edge in grey + if (i == pointsToDraw.Count - 1 + && drawMode == DrawMode.PolygonBase + && pointsToDraw.Count > 2 + && !selectingHeight) + { + GL.Color(Color.grey); + } + // Draw a line from one point to the next + GL.Vertex(pointsToDraw[i]); + GL.Vertex(pointsToDraw[(i + 1) % pointsToDraw.Count]); + } + + if (selectingHeight) + { + Vector3 offset = GetActivePlane().normal * prismHeight; + + for (int i = 0; i < pointsToDraw.Count; i++) + { + // Draw a line from one point to the next + GL.Vertex(pointsToDraw[i]); + GL.Vertex(pointsToDraw[i] + offset); + } + + GL.Color(Color.grey); + // Draw grid lines along the prism to indicate size + for (int heightLine = 1; heightLine < Mathf.Abs(prismHeight); heightLine++) + { + for (int i = 0; i < pointsToDraw.Count; i++) + { + Vector3 gridOffset = GetActivePlane().normal * heightLine * Mathf.Sign(prismHeight); + // Draw a line from one point to the next + GL.Vertex(pointsToDraw[i] + gridOffset); + GL.Vertex(pointsToDraw[(i + 1) % pointsToDraw.Count] + gridOffset); + } + } + + GL.Color(Color.green); + for (int i = 0; i < pointsToDraw.Count; i++) + { + // Draw a line from one point to the next + GL.Vertex(pointsToDraw[i] + offset); + GL.Vertex(pointsToDraw[(i + 1) % pointsToDraw.Count] + offset); + } + } + + GL.End(); + } + + // Rect rectangle = new Rect(0, 50, 210, 130); + // GUIStyle toolbar = new GUIStyle(EditorStyles.toolbar); + // toolbar.normal.background = SabreCSGResources.ClearTexture; + // toolbar.fixedHeight = rectangle.height; + // GUILayout.Window(140010, rectangle, OnToolbarGUI, "",toolbar); + } + + // void OnToolbarGUI(int windowID) + // { + // raycastBrushes = EditorGUILayout.Toggle("Raycast Brushes", raycastBrushes); + // } + + public override void Deactivated() + { + } + + public override bool PreventBrushSelection + { + get + { + // Some special logic for clicking brushes + return true; + } + } } } + #endif \ No newline at end of file diff --git a/Scripts/Tools/ResizeEditor.cs b/Scripts/Tools/ResizeEditor.cs index f9e2df1d..d431b1c9 100644 --- a/Scripts/Tools/ResizeEditor.cs +++ b/Scripts/Tools/ResizeEditor.cs @@ -1,4 +1,5 @@ #if UNITY_EDITOR + using UnityEngine; using System.Collections; using UnityEditor; @@ -10,80 +11,83 @@ namespace Sabresaurus.SabreCSG { public class ResizeEditor : Tool { - // Whether in our special resize mode, or using standard Unity position/rotation handles - enum WidgetMode { Bounds, Translate, Rotate }; + // Whether in our special resize mode, or using standard Unity position/rotation handles + private enum WidgetMode + { Bounds, Translate, Rotate }; - // Used in Resize WidgetMode, for example to rotate using the resize handle - enum ActiveMode { None, Resize, Translate, Rotate }; + // Used in Resize WidgetMode, for example to rotate using the resize handle + private enum ActiveMode + { None, Resize, Translate, Rotate }; - ActiveMode currentMode = ActiveMode.None; - WidgetMode widgetMode = WidgetMode.Bounds; + private ActiveMode currentMode = ActiveMode.None; + private WidgetMode widgetMode = WidgetMode.Bounds; - ResizeHandlePair? selectedResizeHandlePair = null; - int selectedResizePointIndex = -1; // -1 is unset, 0 is Point1, 1 is Point2 + private ResizeHandlePair? selectedResizeHandlePair = null; + private int selectedResizePointIndex = -1; // -1 is unset, 0 is Point1, 1 is Point2 - ResizeHandlePair? hoveredResizeHandlePair = null; - int hoveredResizePointIndex = -1; // -1 is unset, 0 is Point1, 1 is Point2 + private ResizeHandlePair? hoveredResizeHandlePair = null; + private int hoveredResizePointIndex = -1; // -1 is unset, 0 is Point1, 1 is Point2 - Vector3 dotOffset3; + private Vector3 dotOffset3; - float fullDeltaAngle = 0; - float unroundedDeltaAngle = 0; + private float fullDeltaAngle = 0; + private float unroundedDeltaAngle = 0; - Vector3 initialRotationDirection; + private Vector3 initialRotationDirection; - Plane translationPlane; + private Plane translationPlane; /// Whether the user is using the vertex snapping tool by holding down V. - bool vertexSnapping = false; - bool vertexSnapping_HasVertex = false; - bool vertexSnapping_Cancel = false; - Vector3 vertexSnapping_VertexWorldPosition = Vector3.zero; + private bool vertexSnapping = false; + + private bool vertexSnapping_HasVertex = false; + private bool vertexSnapping_Cancel = false; + private Vector3 vertexSnapping_VertexWorldPosition = Vector3.zero; - bool isLeftMouseButtonDown = false; + private bool isLeftMouseButtonDown = false; - Vector3 originalPosition; // For duplicating when translating + private Vector3 originalPosition; // For duplicating when translating - bool moveCancelled = false; + private bool moveCancelled = false; - bool duplicationOccured = false; + private bool duplicationOccured = false; - Vector3 translationUnrounded = Vector3.zero; + private Vector3 translationUnrounded = Vector3.zero; - // WidgetMode - Translate - Vector3 startPosition; + // WidgetMode - Translate + private Vector3 startPosition; - string message; // The tip message being displayed e.g. the size or current delta angle + private string message; // The tip message being displayed e.g. the size or current delta angle - // Used in OnWidgetRotation so that when you first interact with a rotation arc we get rid of any existing - // delta. Ideally we wouldn't need to do this. - Quaternion? initialRotationOffset = null; + // Used in OnWidgetRotation so that when you first interact with a rotation arc we get rid of any existing + // delta. Ideally we wouldn't need to do this. + private Quaternion? initialRotationOffset = null; - bool isMarqueeSelection = false; // Whether the user is (or could be) dragging a marquee box - bool marqueeCancelled = false; + private bool isMarqueeSelection = false; // Whether the user is (or could be) dragging a marquee box + private bool marqueeCancelled = false; - Vector2 marqueeStart; - Vector2 marqueeEnd; + private Vector2 marqueeStart; + private Vector2 marqueeEnd; - ResizeHandlePair[] resizeHandlePairs = new ResizeHandlePair[] - { + private ResizeHandlePair[] resizeHandlePairs = new ResizeHandlePair[] + { // Edge Mid Points new ResizeHandlePair(new Vector3(0,1,1)), - new ResizeHandlePair(new Vector3(0,-1,1)), - new ResizeHandlePair(new Vector3(1,0,1)), - new ResizeHandlePair(new Vector3(-1,0,1)), - new ResizeHandlePair(new Vector3(1,1,0)), - new ResizeHandlePair(new Vector3(-1,1,0)), - + new ResizeHandlePair(new Vector3(0,-1,1)), + new ResizeHandlePair(new Vector3(1,0,1)), + new ResizeHandlePair(new Vector3(-1,0,1)), + new ResizeHandlePair(new Vector3(1,1,0)), + new ResizeHandlePair(new Vector3(-1,1,0)), + // Face Mid Points new ResizeHandlePair(new Vector3(1,0,0)), - new ResizeHandlePair(new Vector3(0,1,0)), - new ResizeHandlePair(new Vector3(0,0,1)), - }; + new ResizeHandlePair(new Vector3(0,1,0)), + new ResizeHandlePair(new Vector3(0,0,1)), + }; public override void OnSceneGUI(SceneView sceneView, Event e) { - base.OnSceneGUI(sceneView, e); // Allow the base logic to calculate first + base.OnSceneGUI(sceneView, e); // Allow the base logic to calculate first if (e.button == 0) { @@ -97,56 +101,54 @@ public override void OnSceneGUI(SceneView sceneView, Event e) } } - if (e.type == EventType.KeyDown || e.type == EventType.KeyUp) - { - OnKeyAction(sceneView, e); - } - - - if(widgetMode == WidgetMode.Translate) - { - OnWidgetTranslation(); - } - else if(widgetMode == WidgetMode.Rotate) - { - OnWidgetRotation(); - } - - if(e.button == 0 || e.button == 1) - { - if (e.type == EventType.MouseDown) - { - OnMouseDown(sceneView, e); - } - else if(e.type == EventType.MouseMove) - { - OnMouseMove(sceneView, e); - } - else if (e.type == EventType.MouseDrag) - { - OnMouseDrag(sceneView, e); - } - // If you mouse up on a different scene view to the one you started on it's surpressed as Ignore, when - // doing marquee selection make sure to check the real type - else if (e.type == EventType.MouseUp || (isMarqueeSelection && e.rawType == EventType.MouseUp)) - { - OnMouseUp(sceneView, e); - } - } - - + if (e.type == EventType.KeyDown || e.type == EventType.KeyUp) + { + OnKeyAction(sceneView, e); + } + + if (widgetMode == WidgetMode.Translate) + { + OnWidgetTranslation(); + } + else if (widgetMode == WidgetMode.Rotate) + { + OnWidgetRotation(); + } + + if (e.button == 0 || e.button == 1) + { + if (e.type == EventType.MouseDown) + { + OnMouseDown(sceneView, e); + } + else if (e.type == EventType.MouseMove) + { + OnMouseMove(sceneView, e); + } + else if (e.type == EventType.MouseDrag) + { + OnMouseDrag(sceneView, e); + } + // If you mouse up on a different scene view to the one you started on it's surpressed as Ignore, when + // doing marquee selection make sure to check the real type + else if (e.type == EventType.MouseUp || (isMarqueeSelection && e.rawType == EventType.MouseUp)) + { + OnMouseUp(sceneView, e); + } + } + if (e.type == EventType.Layout || e.type == EventType.Repaint) { OnRepaint(sceneView, e); } } - void OnWidgetTranslation() - { - if(primaryTargetBrushBase == null) - { - return; - } + private void OnWidgetTranslation() + { + if (primaryTargetBrushBase == null) + { + return; + } // cancel the translation if we come out of vertex snapping. if (vertexSnapping_Cancel) @@ -165,17 +167,17 @@ void OnWidgetTranslation() } } - // Make the handle respect the Unity Editor's Local/World orientation mode - Quaternion handleDirection = Quaternion.identity; - if(Tools.pivotRotation == PivotRotation.Local) - { - handleDirection = primaryTargetBrushTransform.rotation; - } + // Make the handle respect the Unity Editor's Local/World orientation mode + Quaternion handleDirection = Quaternion.identity; + if (Tools.pivotRotation == PivotRotation.Local) + { + handleDirection = primaryTargetBrushTransform.rotation; + } - // Grab a source point and convert from local space to world - Vector3 sourceWorldPosition = GetBrushesPivotPoint();//targetBrushTransform.position; + // Grab a source point and convert from local space to world + Vector3 sourceWorldPosition = GetBrushesPivotPoint();//targetBrushTransform.position; - EditorGUI.BeginChangeCheck(); + EditorGUI.BeginChangeCheck(); Vector3 newWorldPosition = sourceWorldPosition; @@ -218,156 +220,156 @@ void OnWidgetTranslation() newWorldPosition = Handles.PositionHandle(sourceWorldPosition, handleDirection); } - if(EditorGUI.EndChangeCheck()) - { - Vector3 delta = newWorldPosition-sourceWorldPosition; + if (EditorGUI.EndChangeCheck()) + { + Vector3 delta = newWorldPosition - sourceWorldPosition; - Vector3 newPosition = primaryTargetBrushTransform.position + delta; + Vector3 newPosition = primaryTargetBrushTransform.position + delta; - Vector3 accumulatedDelta = newPosition - startPosition; + Vector3 accumulatedDelta = newPosition - startPosition; if (CurrentSettings.PositionSnappingEnabled && !vertexSnapping) { - accumulatedDelta = InverseTransformDirection(accumulatedDelta); - - float snapDistance = CurrentSettings.PositionSnapDistance; - - accumulatedDelta = MathHelper.RoundVector3(accumulatedDelta, snapDistance); - - accumulatedDelta = TransformDirection(accumulatedDelta); - } - - newPosition = startPosition + accumulatedDelta; - - Vector3 finalDelta = newPosition - primaryTargetBrushTransform.position; - - TranslateBrushes(finalDelta); - - Event.current.Use(); - } - else - { - startPosition = primaryTargetBrushTransform.position; - } - } - - void OnWidgetRotation() - { - if(primaryTargetBrushBase == null) - { - return; - } - - Vector3 worldPosition = GetBrushesPivotPoint(); - - if (Event.current.type == EventType.MouseUp) - { - initialRotationOffset = null; - } - - DrawRotationAxis(Color.red, Vector3.right, worldPosition); - DrawRotationAxis(Color.green, Vector3.up, worldPosition); - DrawRotationAxis(Color.blue, Vector3.forward, worldPosition); - } - -// Quaternion compoundRotation = Quaternion.identity; - - void DrawRotationAxis(Color color, Vector3 axis, Vector3 worldPosition) - { -// EventType source = Event.current.rawType; - // Make the handle respect the Unity Editor's Local/World orientation mode -// Quaternion handleDirection = Quaternion.identity; -// if(Tools.pivotRotation == PivotRotation.Local) -// { -// handleDirection = targetBrush.transform.rotation; -// } - - // Grab a source point and convert from local space to world - Vector3 sourceWorldPosition = worldPosition; - - EditorGUI.BeginChangeCheck(); - // Display a handle and allow the user to determine a new position in world space - -// Vector3 lastEulerAngles = handleDirection.eulerAngles; - - Handles.color = color; - - float snapValue = 0; - if(CurrentSettings.AngleSnappingEnabled) - { - snapValue = CurrentSettings.AngleSnapDistance; - } - - Quaternion sourceRotation = Quaternion.identity;// targetBrushTransform.rotation; -// Quaternion sourceRotation = targetBrushTransform.rotation; - - Quaternion newRotation = Handles.Disc(sourceRotation, - sourceWorldPosition, - axis, - HandleUtility.GetHandleSize(sourceWorldPosition), - true, - snapValue); - - if(EditorGUI.EndChangeCheck()) - { - Quaternion deltaRotation = Quaternion.Inverse(primaryTargetBrushTransform.rotation) * newRotation; - if(!initialRotationOffset.HasValue) - { - initialRotationOffset = deltaRotation; - return; - } - deltaRotation = Quaternion.Inverse(initialRotationOffset.Value) * deltaRotation; -// Quaternion deltaRotation = newRotation; -// Quaternion deltaRotation = newRotation * Quaternion.Inverse(targetBrushTransform.rotation); - -// Debug.Log(deltaRotation.eulerAngles); - if(CurrentSettings.AngleSnappingEnabled) - { - Quaternion plusSnap = Quaternion.AngleAxis(CurrentSettings.AngleSnapDistance, axis);// * baseRotation; - Quaternion zeroSnap = Quaternion.identity;// * baseRotation; - Quaternion negativeSnap = Quaternion.AngleAxis(-CurrentSettings.AngleSnapDistance, axis);// * baseRotation; - - float angleZero = Quaternion.Angle(deltaRotation, zeroSnap); - float anglePlus = Quaternion.Angle(deltaRotation, plusSnap); - float angleNegative = Quaternion.Angle(deltaRotation, negativeSnap); - -// Debug.Log("A0 " + angleZero + ", A+ " + anglePlus + ", A- " + angleNegative); - - if(anglePlus < angleZero) - { - RotateBrushes(plusSnap, sourceWorldPosition); - } - else if(angleNegative < angleZero) - { - RotateBrushes(negativeSnap, sourceWorldPosition); - } - } - else - { - RotateBrushes(deltaRotation, sourceWorldPosition); - } - - Event.current.Use(); - } - } - - void OnKeyAction(SceneView sceneView, Event e) - { - if(widgetMode == WidgetMode.Bounds) - { - if (primaryTargetBrushBase != null - && KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.CancelCurrentOperation))) // Cancel move - { - if (e.type == EventType.KeyUp) - { - CancelMove(); - } - e.Use(); - } - } - - if(!CameraPanInProgress) - { + accumulatedDelta = InverseTransformDirection(accumulatedDelta); + + float snapDistance = CurrentSettings.PositionSnapDistance; + + accumulatedDelta = MathHelper.RoundVector3(accumulatedDelta, snapDistance); + + accumulatedDelta = TransformDirection(accumulatedDelta); + } + + newPosition = startPosition + accumulatedDelta; + + Vector3 finalDelta = newPosition - primaryTargetBrushTransform.position; + + TranslateBrushes(finalDelta); + + Event.current.Use(); + } + else + { + startPosition = primaryTargetBrushTransform.position; + } + } + + private void OnWidgetRotation() + { + if (primaryTargetBrushBase == null) + { + return; + } + + Vector3 worldPosition = GetBrushesPivotPoint(); + + if (Event.current.type == EventType.MouseUp) + { + initialRotationOffset = null; + } + + DrawRotationAxis(Color.red, Vector3.right, worldPosition); + DrawRotationAxis(Color.green, Vector3.up, worldPosition); + DrawRotationAxis(Color.blue, Vector3.forward, worldPosition); + } + + // Quaternion compoundRotation = Quaternion.identity; + + private void DrawRotationAxis(Color color, Vector3 axis, Vector3 worldPosition) + { + // EventType source = Event.current.rawType; + // Make the handle respect the Unity Editor's Local/World orientation mode + // Quaternion handleDirection = Quaternion.identity; + // if(Tools.pivotRotation == PivotRotation.Local) + // { + // handleDirection = targetBrush.transform.rotation; + // } + + // Grab a source point and convert from local space to world + Vector3 sourceWorldPosition = worldPosition; + + EditorGUI.BeginChangeCheck(); + // Display a handle and allow the user to determine a new position in world space + + // Vector3 lastEulerAngles = handleDirection.eulerAngles; + + Handles.color = color; + + float snapValue = 0; + if (CurrentSettings.AngleSnappingEnabled) + { + snapValue = CurrentSettings.AngleSnapDistance; + } + + Quaternion sourceRotation = Quaternion.identity;// targetBrushTransform.rotation; + // Quaternion sourceRotation = targetBrushTransform.rotation; + + Quaternion newRotation = Handles.Disc(sourceRotation, + sourceWorldPosition, + axis, + HandleUtility.GetHandleSize(sourceWorldPosition), + true, + snapValue); + + if (EditorGUI.EndChangeCheck()) + { + Quaternion deltaRotation = Quaternion.Inverse(primaryTargetBrushTransform.rotation) * newRotation; + if (!initialRotationOffset.HasValue) + { + initialRotationOffset = deltaRotation; + return; + } + deltaRotation = Quaternion.Inverse(initialRotationOffset.Value) * deltaRotation; + // Quaternion deltaRotation = newRotation; + // Quaternion deltaRotation = newRotation * Quaternion.Inverse(targetBrushTransform.rotation); + + // Debug.Log(deltaRotation.eulerAngles); + if (CurrentSettings.AngleSnappingEnabled) + { + Quaternion plusSnap = Quaternion.AngleAxis(CurrentSettings.AngleSnapDistance, axis);// * baseRotation; + Quaternion zeroSnap = Quaternion.identity;// * baseRotation; + Quaternion negativeSnap = Quaternion.AngleAxis(-CurrentSettings.AngleSnapDistance, axis);// * baseRotation; + + float angleZero = Quaternion.Angle(deltaRotation, zeroSnap); + float anglePlus = Quaternion.Angle(deltaRotation, plusSnap); + float angleNegative = Quaternion.Angle(deltaRotation, negativeSnap); + + // Debug.Log("A0 " + angleZero + ", A+ " + anglePlus + ", A- " + angleNegative); + + if (anglePlus < angleZero) + { + RotateBrushes(plusSnap, sourceWorldPosition); + } + else if (angleNegative < angleZero) + { + RotateBrushes(negativeSnap, sourceWorldPosition); + } + } + else + { + RotateBrushes(deltaRotation, sourceWorldPosition); + } + + Event.current.Use(); + } + } + + private void OnKeyAction(SceneView sceneView, Event e) + { + if (widgetMode == WidgetMode.Bounds) + { + if (primaryTargetBrushBase != null + && KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.CancelCurrentOperation))) // Cancel move + { + if (e.type == EventType.KeyUp) + { + CancelMove(); + } + e.Use(); + } + } + + if (!CameraPanInProgress) + { // check for vertex snapping in translate mode. if (e.keyCode == KeyCode.V) { @@ -376,54 +378,54 @@ void OnKeyAction(SceneView sceneView, Event e) vertexSnapping_Cancel = !vertexSnapping; } - if(KeyMappings.EventsMatch(e, EditorKeyMappings.GetToolViewMapping())) - { + if (KeyMappings.EventsMatch(e, EditorKeyMappings.GetToolViewMapping())) + { if (e.type == EventType.KeyDown && !csgModel.MouseIsHeldOrRecent) - { - widgetMode = WidgetMode.Bounds; - SceneView.RepaintAll(); - } - } - else if(KeyMappings.EventsMatch(e, EditorKeyMappings.GetToolMoveMapping())) - { + { + widgetMode = WidgetMode.Bounds; + SceneView.RepaintAll(); + } + } + else if (KeyMappings.EventsMatch(e, EditorKeyMappings.GetToolMoveMapping())) + { if (e.type == EventType.KeyDown && !csgModel.MouseIsHeldOrRecent) { widgetMode = WidgetMode.Translate; - // Make sure we get rid of any active custom cursor - SabreMouse.ResetCursor(); - SceneView.RepaintAll(); - } - } - else if(KeyMappings.EventsMatch(e, EditorKeyMappings.GetToolRotateMapping())) - { + // Make sure we get rid of any active custom cursor + SabreMouse.ResetCursor(); + SceneView.RepaintAll(); + } + } + else if (KeyMappings.EventsMatch(e, EditorKeyMappings.GetToolRotateMapping())) + { if (e.type == EventType.KeyDown && !csgModel.MouseIsHeldOrRecent) { widgetMode = WidgetMode.Rotate; - // Make sure we get rid of any active custom cursor - SabreMouse.ResetCursor(); - SceneView.RepaintAll(); - } - } - } - } - - void OnMouseMove(SceneView sceneView, Event e) - { - if(CameraPanInProgress || primaryTargetBrushBase == null || widgetMode != WidgetMode.Bounds) - { - return; - } - - bool foundAny = false; - Vector3 worldPos1 = Vector3.zero; - Vector3 worldPos2 = Vector3.zero; - - Vector2 mousePosition = e.mousePosition; - - bool isAxisAlignedCamera = (EditorHelper.GetSceneViewCamera(sceneView) != EditorHelper.SceneViewCamera.Other); - Vector3 cameraDirection = sceneView.camera.transform.forward; - - Bounds bounds = GetBounds(); + // Make sure we get rid of any active custom cursor + SabreMouse.ResetCursor(); + SceneView.RepaintAll(); + } + } + } + } + + private void OnMouseMove(SceneView sceneView, Event e) + { + if (CameraPanInProgress || primaryTargetBrushBase == null || widgetMode != WidgetMode.Bounds) + { + return; + } + + bool foundAny = false; + Vector3 worldPos1 = Vector3.zero; + Vector3 worldPos2 = Vector3.zero; + + Vector2 mousePosition = e.mousePosition; + + bool isAxisAlignedCamera = (EditorHelper.GetSceneViewCamera(sceneView) != EditorHelper.SceneViewCamera.Other); + Vector3 cameraDirection = sceneView.camera.transform.forward; + + Bounds bounds = GetBounds(); // VisualDebug.ClearAll(); @@ -433,318 +435,316 @@ void OnMouseMove(SceneView sceneView, Event e) // Edges if (isAxisAlignedCamera && sceneView.camera.orthographic) // Can only select edges in iso axis aligned - { - for (int i = 0; i < resizeHandlePairs.Length; i++) - { - // Skip any that shouldn't be seen from this camera angle (axis aligned only) - if (isAxisAlignedCamera && Mathf.Abs(Vector3.Dot(TransformDirection(resizeHandlePairs[i].point1), cameraDirection)) > 0.001f) - { - continue; - } - // Skip any corners - if(resizeHandlePairs[i].point1.sqrMagnitude != 1) - { - continue; - } - - Vector3 normalVector3 = Vector3.Cross(InverseTransformDirection(cameraDirection), resizeHandlePairs[i].point1); - - Vector3 worldPosExtent1 = TransformPoint(bounds.center + normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point1.Multiply(bounds.extents)); - Vector3 worldPosExtent2 = TransformPoint(bounds.center - normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point1.Multiply(bounds.extents)); + { + for (int i = 0; i < resizeHandlePairs.Length; i++) + { + // Skip any that shouldn't be seen from this camera angle (axis aligned only) + if (isAxisAlignedCamera && Mathf.Abs(Vector3.Dot(TransformDirection(resizeHandlePairs[i].point1), cameraDirection)) > 0.001f) + { + continue; + } + // Skip any corners + if (resizeHandlePairs[i].point1.sqrMagnitude != 1) + { + continue; + } + + Vector3 normalVector3 = Vector3.Cross(InverseTransformDirection(cameraDirection), resizeHandlePairs[i].point1); + + Vector3 worldPosExtent1 = TransformPoint(bounds.center + normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point1.Multiply(bounds.extents)); + Vector3 worldPosExtent2 = TransformPoint(bounds.center - normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point1.Multiply(bounds.extents)); float range = resizeHandlePairs[i].CalculateScreenRange(TransformPoint, 0, bounds); if (EditorHelper.InClickRect(mousePosition, worldPosExtent1, worldPosExtent2, range)) - { - foundAny = true; - worldPos1 = TransformPoint(bounds.center + resizeHandlePairs[i].point2.Multiply(bounds.extents)); - worldPos2 = TransformPoint(bounds.center + resizeHandlePairs[i].point1.Multiply(bounds.extents)); + { + foundAny = true; + worldPos1 = TransformPoint(bounds.center + resizeHandlePairs[i].point2.Multiply(bounds.extents)); + worldPos2 = TransformPoint(bounds.center + resizeHandlePairs[i].point1.Multiply(bounds.extents)); hoveredResizeHandlePair = resizeHandlePairs[i]; hoveredResizePointIndex = 0; e.Use(); - } + } - worldPosExtent1 = TransformPoint(bounds.center + normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point2.Multiply(bounds.extents)); - worldPosExtent2 = TransformPoint(bounds.center - normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point2.Multiply(bounds.extents)); + worldPosExtent1 = TransformPoint(bounds.center + normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point2.Multiply(bounds.extents)); + worldPosExtent2 = TransformPoint(bounds.center - normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point2.Multiply(bounds.extents)); range = resizeHandlePairs[i].CalculateScreenRange(TransformPoint, 1, bounds); if (EditorHelper.InClickRect(mousePosition, worldPosExtent1, worldPosExtent2, range)) - { - foundAny = true; - worldPos1 = TransformPoint(bounds.center + resizeHandlePairs[i].point1.Multiply(bounds.extents)); - worldPos2 = TransformPoint(bounds.center + resizeHandlePairs[i].point2.Multiply(bounds.extents)); + { + foundAny = true; + worldPos1 = TransformPoint(bounds.center + resizeHandlePairs[i].point1.Multiply(bounds.extents)); + worldPos2 = TransformPoint(bounds.center + resizeHandlePairs[i].point2.Multiply(bounds.extents)); hoveredResizeHandlePair = resizeHandlePairs[i]; hoveredResizePointIndex = 1; e.Use(); - } - } - } - + } + } + } + // Handles - for (int i = 0; i < resizeHandlePairs.Length; i++) - { - // Skip any that shouldn't be seen from this camera angle (axis aligned only) - if (isAxisAlignedCamera && Mathf.Abs(Vector3.Dot(TransformDirection(resizeHandlePairs[i].point1), cameraDirection)) > 0.001f) - { - continue; - } + for (int i = 0; i < resizeHandlePairs.Length; i++) + { + // Skip any that shouldn't be seen from this camera angle (axis aligned only) + if (isAxisAlignedCamera && Mathf.Abs(Vector3.Dot(TransformDirection(resizeHandlePairs[i].point1), cameraDirection)) > 0.001f) + { + continue; + } if (resizeHandlePairs[i].InClickZone(TransformPoint, mousePosition, 0, bounds)) - { - foundAny = true; - worldPos1 = TransformPoint(bounds.center + resizeHandlePairs[i].point2.Multiply(bounds.extents)); - worldPos2 = TransformPoint(bounds.center + resizeHandlePairs[i].point1.Multiply(bounds.extents)); + { + foundAny = true; + worldPos1 = TransformPoint(bounds.center + resizeHandlePairs[i].point2.Multiply(bounds.extents)); + worldPos2 = TransformPoint(bounds.center + resizeHandlePairs[i].point1.Multiply(bounds.extents)); hoveredResizeHandlePair = resizeHandlePairs[i]; hoveredResizePointIndex = 0; e.Use(); - } + } if (resizeHandlePairs[i].InClickZone(TransformPoint, mousePosition, 1, bounds)) { - foundAny = true; - worldPos1 = TransformPoint(bounds.center + resizeHandlePairs[i].point1.Multiply(bounds.extents)); - worldPos2 = TransformPoint(bounds.center + resizeHandlePairs[i].point2.Multiply(bounds.extents)); + foundAny = true; + worldPos1 = TransformPoint(bounds.center + resizeHandlePairs[i].point1.Multiply(bounds.extents)); + worldPos2 = TransformPoint(bounds.center + resizeHandlePairs[i].point2.Multiply(bounds.extents)); hoveredResizeHandlePair = resizeHandlePairs[i]; hoveredResizePointIndex = 1; e.Use(); } - } - - if (foundAny) - { - if(EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control)) - { - SabreMouse.SetCursor(MouseCursor.RotateArrow); - } - else - { - Vector2 screenPoint1 = Camera.current.WorldToScreenPoint(worldPos1); - Vector2 screenPoint2 = Camera.current.WorldToScreenPoint(worldPos2); - - SabreMouse.SetCursorFromVector3(screenPoint2, screenPoint1); - } - - SceneView.RepaintAll(); - } - else - { - SabreMouse.SetCursor(MouseCursor.Arrow); - SceneView.RepaintAll(); - } - } - - void DetermineTranslationPlane (Event e) - { - Bounds bounds = GetBounds(); - - // Determine which face of the bounds the user has clicked - Polygon[] translationBoxCollider = BrushFactory.GenerateCube(); // Generates a unit cube - - // First of all rescale transform the unit cube so that it matches the bounds - for (int i = 0; i < translationBoxCollider.Length; i++) - { - for (int j = 0; j < translationBoxCollider[i].Vertices.Length; j++) - { - Vector3 position = translationBoxCollider[i].Vertices[j].Position; - position = position.Multiply(bounds.extents) + bounds.center; - - position = TransformPoint(position); // Also transform the positions if in local mode - translationBoxCollider[i].Vertices[j].Position = position; - } - translationBoxCollider[i].CalculatePlane(); - } - - // Construct a ray at the mouse position - Vector2 currentPosition = e.mousePosition; - Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); - - // Raycast against the ray against the bounds polygons we just created - float hitDistance; - Polygon hitPolygon = GeometryHelper.RaycastPolygons(translationBoxCollider.ToList(), currentRay, out hitDistance, 0); - - if(hitPolygon != null) // We hit a polygon - { - currentMode = ActiveMode.Translate; - // Use this polygon's plane as the active translation plane - translationPlane = hitPolygon.Plane; - } - else // Didn't hit anything - { - currentMode = ActiveMode.None; - } - } - - void OnMouseDown(SceneView sceneView, Event e) - { - if (primaryTargetBrushBase != null && widgetMode == WidgetMode.Bounds) - { - duplicationOccured = false; - moveCancelled = false; - originalPosition = primaryTargetBrushTransform.position; - fullDeltaAngle = 0; + } - if (CameraPanInProgress) - { - currentMode = ActiveMode.None; - } - else - { - // Resize - dotOffset3 = Vector3.zero; + if (foundAny) + { + if (EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control)) + { + SabreMouse.SetCursor(MouseCursor.RotateArrow); + } + else + { + Vector2 screenPoint1 = Camera.current.WorldToScreenPoint(worldPos1); + Vector2 screenPoint2 = Camera.current.WorldToScreenPoint(worldPos2); - Vector2 mousePosition = e.mousePosition; + SabreMouse.SetCursorFromVector3(screenPoint2, screenPoint1); + } - // Reset which resize pair is being selected - selectedResizeHandlePair = null; + SceneView.RepaintAll(); + } + else + { + SabreMouse.SetCursor(MouseCursor.Arrow); + SceneView.RepaintAll(); + } + } - bool isAxisAlignedCamera = (EditorHelper.GetSceneViewCamera(sceneView) != EditorHelper.SceneViewCamera.Other); - Vector3 cameraDirection = sceneView.camera.transform.forward; + private void DetermineTranslationPlane(Event e) + { + Bounds bounds = GetBounds(); - Bounds bounds = GetBounds(); + // Determine which face of the bounds the user has clicked + Polygon[] translationBoxCollider = BrushFactory.GenerateCube(); // Generates a unit cube - bool handleClicked = false; + // First of all rescale transform the unit cube so that it matches the bounds + for (int i = 0; i < translationBoxCollider.Length; i++) + { + for (int j = 0; j < translationBoxCollider[i].Vertices.Length; j++) + { + Vector3 position = translationBoxCollider[i].Vertices[j].Position; + position = position.Multiply(bounds.extents) + bounds.center; - // Edges - if(isAxisAlignedCamera && sceneView.camera.orthographic) - { - for (int i = 0; i < resizeHandlePairs.Length; i++) - { - // Skip any that shouldn't be seen from this camera angle (axis aligned only) - if (isAxisAlignedCamera && Mathf.Abs(Vector3.Dot(TransformDirection(resizeHandlePairs[i].point1), cameraDirection)) > 0.001f) - { - continue; - } - // Skip any corners - if(resizeHandlePairs[i].point1.sqrMagnitude != 1) - { - continue; - } + position = TransformPoint(position); // Also transform the positions if in local mode + translationBoxCollider[i].Vertices[j].Position = position; + } + translationBoxCollider[i].CalculatePlane(); + } + // Construct a ray at the mouse position + Vector2 currentPosition = e.mousePosition; + Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); + // Raycast against the ray against the bounds polygons we just created + float hitDistance; + Polygon hitPolygon = GeometryHelper.RaycastPolygons(translationBoxCollider.ToList(), currentRay, out hitDistance, 0); - Vector3 normalVector3 = Vector3.Cross(InverseTransformDirection(cameraDirection), resizeHandlePairs[i].point1); + if (hitPolygon != null) // We hit a polygon + { + currentMode = ActiveMode.Translate; + // Use this polygon's plane as the active translation plane + translationPlane = hitPolygon.Plane; + } + else // Didn't hit anything + { + currentMode = ActiveMode.None; + } + } - Vector3 worldPosExtent1 = TransformPoint(bounds.center + normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point1.Multiply(bounds.extents)); - Vector3 worldPosExtent2 = TransformPoint(bounds.center - normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point1.Multiply(bounds.extents)); + private void OnMouseDown(SceneView sceneView, Event e) + { + if (primaryTargetBrushBase != null && widgetMode == WidgetMode.Bounds) + { + duplicationOccured = false; + moveCancelled = false; + originalPosition = primaryTargetBrushTransform.position; + fullDeltaAngle = 0; + + if (CameraPanInProgress) + { + currentMode = ActiveMode.None; + } + else + { + // Resize + dotOffset3 = Vector3.zero; + + Vector2 mousePosition = e.mousePosition; + + // Reset which resize pair is being selected + selectedResizeHandlePair = null; + + bool isAxisAlignedCamera = (EditorHelper.GetSceneViewCamera(sceneView) != EditorHelper.SceneViewCamera.Other); + Vector3 cameraDirection = sceneView.camera.transform.forward; + + Bounds bounds = GetBounds(); + + bool handleClicked = false; + + // Edges + if (isAxisAlignedCamera && sceneView.camera.orthographic) + { + for (int i = 0; i < resizeHandlePairs.Length; i++) + { + // Skip any that shouldn't be seen from this camera angle (axis aligned only) + if (isAxisAlignedCamera && Mathf.Abs(Vector3.Dot(TransformDirection(resizeHandlePairs[i].point1), cameraDirection)) > 0.001f) + { + continue; + } + // Skip any corners + if (resizeHandlePairs[i].point1.sqrMagnitude != 1) + { + continue; + } + + Vector3 normalVector3 = Vector3.Cross(InverseTransformDirection(cameraDirection), resizeHandlePairs[i].point1); + + Vector3 worldPosExtent1 = TransformPoint(bounds.center + normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point1.Multiply(bounds.extents)); + Vector3 worldPosExtent2 = TransformPoint(bounds.center - normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point1.Multiply(bounds.extents)); float range = resizeHandlePairs[i].CalculateScreenRange(TransformPoint, 0, bounds); if (EditorHelper.InClickRect(mousePosition, worldPosExtent1, worldPosExtent2, range)) - { - selectedResizeHandlePair = resizeHandlePairs[i]; - selectedResizePointIndex = 0; + { + selectedResizeHandlePair = resizeHandlePairs[i]; + selectedResizePointIndex = 0; - handleClicked = true; - e.Use(); - } + handleClicked = true; + e.Use(); + } - worldPosExtent1 = TransformPoint(bounds.center + normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point2.Multiply(bounds.extents)); - worldPosExtent2 = TransformPoint(bounds.center - normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point2.Multiply(bounds.extents)); + worldPosExtent1 = TransformPoint(bounds.center + normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point2.Multiply(bounds.extents)); + worldPosExtent2 = TransformPoint(bounds.center - normalVector3.Multiply(bounds.extents) + resizeHandlePairs[i].point2.Multiply(bounds.extents)); range = resizeHandlePairs[i].CalculateScreenRange(TransformPoint, 0, bounds); if (EditorHelper.InClickRect(mousePosition, worldPosExtent1, worldPosExtent2, range)) - { - selectedResizeHandlePair = resizeHandlePairs[i]; - selectedResizePointIndex = 1; - - handleClicked = true; - e.Use(); - } - } - } - - for (int i = 0; i < resizeHandlePairs.Length; i++) - { - // Skip any that shouldn't be seen from this camera angle (axis aligned only) - if (isAxisAlignedCamera && Mathf.Abs(Vector3.Dot(TransformDirection(resizeHandlePairs[i].point1), cameraDirection)) > 0.001f) - { - continue; - } + { + selectedResizeHandlePair = resizeHandlePairs[i]; + selectedResizePointIndex = 1; + + handleClicked = true; + e.Use(); + } + } + } + + for (int i = 0; i < resizeHandlePairs.Length; i++) + { + // Skip any that shouldn't be seen from this camera angle (axis aligned only) + if (isAxisAlignedCamera && Mathf.Abs(Vector3.Dot(TransformDirection(resizeHandlePairs[i].point1), cameraDirection)) > 0.001f) + { + continue; + } if (resizeHandlePairs[i].InClickZone(TransformPoint, mousePosition, 0, bounds)) - { - selectedResizeHandlePair = resizeHandlePairs[i]; - selectedResizePointIndex = 0; + { + selectedResizeHandlePair = resizeHandlePairs[i]; + selectedResizePointIndex = 0; - handleClicked = true; - e.Use(); - } + handleClicked = true; + e.Use(); + } if (resizeHandlePairs[i].InClickZone(TransformPoint, mousePosition, 1, bounds)) { selectedResizeHandlePair = resizeHandlePairs[i]; - selectedResizePointIndex = 1; - - handleClicked = true; - e.Use(); - } - } - - if (handleClicked && selectedResizeHandlePair.HasValue) - { - Vector3 worldPosition1; - Vector3 worldPosition2; - - if (selectedResizePointIndex == 1) - { - worldPosition1 = TransformPoint(bounds.center + selectedResizeHandlePair.Value.point1.Multiply(bounds.extents)); - worldPosition2 = TransformPoint(bounds.center + selectedResizeHandlePair.Value.point2.Multiply(bounds.extents)); - } - else - { - worldPosition1 = TransformPoint(bounds.center + selectedResizeHandlePair.Value.point2.Multiply(bounds.extents)); - worldPosition2 = TransformPoint(bounds.center + selectedResizeHandlePair.Value.point1.Multiply(bounds.extents)); - } - Vector2 screenPoint1 = Camera.current.WorldToScreenPoint(worldPosition1); - Vector2 screenPoint2 = Camera.current.WorldToScreenPoint(worldPosition2); - - SabreMouse.SetCursorFromVector3(screenPoint2, screenPoint1); - - if(EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control) - && selectedResizeHandlePair.Value.ResizeType == ResizeType.EdgeMid) - { - currentMode = ActiveMode.Rotate; - Vector3 activeDirection; - if (selectedResizePointIndex == 0) - { - activeDirection = selectedResizeHandlePair.Value.point1; - } - else - { - activeDirection = selectedResizeHandlePair.Value.point2; - } - - message = "0"; - - initialRotationDirection = TransformDirection(activeDirection.Multiply(GetBounds().extents)); - } - else - { - currentMode = ActiveMode.Resize; - } - - SceneView.RepaintAll(); - } - else - { - DetermineTranslationPlane(e); - } - } - } - - isMarqueeSelection = false; - - marqueeStart = e.mousePosition; - - if(EditorHelper.IsMousePositionInInvalidRects(e.mousePosition)) + selectedResizePointIndex = 1; + + handleClicked = true; + e.Use(); + } + } + + if (handleClicked && selectedResizeHandlePair.HasValue) + { + Vector3 worldPosition1; + Vector3 worldPosition2; + + if (selectedResizePointIndex == 1) + { + worldPosition1 = TransformPoint(bounds.center + selectedResizeHandlePair.Value.point1.Multiply(bounds.extents)); + worldPosition2 = TransformPoint(bounds.center + selectedResizeHandlePair.Value.point2.Multiply(bounds.extents)); + } + else + { + worldPosition1 = TransformPoint(bounds.center + selectedResizeHandlePair.Value.point2.Multiply(bounds.extents)); + worldPosition2 = TransformPoint(bounds.center + selectedResizeHandlePair.Value.point1.Multiply(bounds.extents)); + } + Vector2 screenPoint1 = Camera.current.WorldToScreenPoint(worldPosition1); + Vector2 screenPoint2 = Camera.current.WorldToScreenPoint(worldPosition2); + + SabreMouse.SetCursorFromVector3(screenPoint2, screenPoint1); + + if (EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control) + && selectedResizeHandlePair.Value.ResizeType == ResizeType.EdgeMid) + { + currentMode = ActiveMode.Rotate; + Vector3 activeDirection; + if (selectedResizePointIndex == 0) + { + activeDirection = selectedResizeHandlePair.Value.point1; + } + else + { + activeDirection = selectedResizeHandlePair.Value.point2; + } + + message = "0"; + + initialRotationDirection = TransformDirection(activeDirection.Multiply(GetBounds().extents)); + } + else + { + currentMode = ActiveMode.Resize; + } + + SceneView.RepaintAll(); + } + else + { + DetermineTranslationPlane(e); + } + } + } + + isMarqueeSelection = false; + + marqueeStart = e.mousePosition; + + if (EditorHelper.IsMousePositionInInvalidRects(e.mousePosition)) { marqueeCancelled = true; } @@ -754,28 +754,28 @@ void OnMouseDown(SceneView sceneView, Event e) } } - void OnMouseDrag(SceneView sceneView, Event e) - { - if(e.button != 0 || CameraPanInProgress) // Must be LMB - { - return; - } + private void OnMouseDrag(SceneView sceneView, Event e) + { + if (e.button != 0 || CameraPanInProgress) // Must be LMB + { + return; + } - if (currentMode == ActiveMode.Resize && primaryTargetBrushBase != null && widgetMode == WidgetMode.Bounds) + if (currentMode == ActiveMode.Resize && primaryTargetBrushBase != null && widgetMode == WidgetMode.Bounds) { - OnMouseDragResize(sceneView, e); - } - else if (currentMode == ActiveMode.Rotate && primaryTargetBrushBase != null && widgetMode == WidgetMode.Bounds) - { - OnMouseDragRotate(sceneView, e); + OnMouseDragResize(sceneView, e); } - else if (currentMode == ActiveMode.Translate && !moveCancelled && Tools.current == UnityEditor.Tool.None && primaryTargetBrushBase != null && widgetMode == WidgetMode.Bounds) + else if (currentMode == ActiveMode.Rotate && primaryTargetBrushBase != null && widgetMode == WidgetMode.Bounds) { - OnMouseDragTranslate(sceneView, e); + OnMouseDragRotate(sceneView, e); } - else - { - if(!marqueeCancelled) + else if (currentMode == ActiveMode.Translate && !moveCancelled && Tools.current == UnityEditor.Tool.None && primaryTargetBrushBase != null && widgetMode == WidgetMode.Bounds) + { + OnMouseDragTranslate(sceneView, e); + } + else + { + if (!marqueeCancelled) { marqueeEnd = e.mousePosition; isMarqueeSelection = true; @@ -783,205 +783,204 @@ void OnMouseDrag(SceneView sceneView, Event e) } } - e.Use(); + e.Use(); } - void OnMouseDragResize(SceneView sceneView, Event e) - { - Rect pixelRect = sceneView.camera.pixelRect; - - // Resize a handle - Vector2 currentPosition = e.mousePosition; - - // Clamp the current position to the screen rect. Otherwise we get some odd problems if you carry on - // resizing off screen. - currentPosition.x = Mathf.Clamp(currentPosition.x, pixelRect.xMin, pixelRect.xMax); - currentPosition.y = Mathf.Clamp(currentPosition.y, pixelRect.yMin, pixelRect.yMax); - - Vector2 lastPosition = currentPosition - e.delta; - - Ray lastRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(lastPosition)); - - Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); - -// Bounds bounds = GetBounds(); - - Vector3 offset = primaryTargetBrushTransform.position; -// if(Tools.pivotMode == PivotMode.Center && Tools.pivotRotation == PivotRotation.Global) -// { -// offset = GetBounds().center; -// } - - Vector3 lineStart = offset + TransformDirection(selectedResizeHandlePair.Value.point1); - Vector3 lineEnd = offset + TransformDirection(selectedResizeHandlePair.Value.point2); - - Vector3 lastPositionWorld = MathHelper.ClosestPointOnLine(lastRay, lineStart, lineEnd); - Vector3 currentPositionWorld = MathHelper.ClosestPointOnLine(currentRay, lineStart, lineEnd); - - Vector3 direction; - if (selectedResizePointIndex == 0) - { - direction = selectedResizeHandlePair.Value.point1; - } - else - { - direction = selectedResizeHandlePair.Value.point2; - } - - // If shift is held, flip the direction so they're resizing the opposite side - if(EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Shift)) - { - direction = -direction; - } - - Vector3 deltaWorld = (currentPositionWorld - lastPositionWorld); - // Rescaling logic deals with local space changes, convert to that space - Vector3 deltaLocal = InverseTransformDirection(deltaWorld); - - Vector3 dot3 = Vector3.zero; - if (direction.x != 0) - { - dot3.x = Vector3.Dot(deltaLocal, new Vector3(Mathf.Sign(direction.x), 0, 0)); - } - if (direction.y != 0) - { - dot3.y = Vector3.Dot(deltaLocal, new Vector3(0, Mathf.Sign(direction.y), 0)); - } - if (direction.z != 0) - { - dot3.z = Vector3.Dot(deltaLocal, new Vector3(0, 0, Mathf.Sign(direction.z))); - } - - float snapDistance = CurrentSettings.PositionSnapDistance; - - if (CurrentSettings.PositionSnappingEnabled) - { - // Snapping's dot uses an offset to track deltas that would be lost otherwise due to snapping - dot3 += dotOffset3; - - Vector3 roundedDot3 = MathHelper.RoundVector3(dot3, snapDistance); - dotOffset3 = dot3 - roundedDot3; - dot3 = roundedDot3; - } - - if(EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control)) - { - Undo.RecordObjects(targetBrushTransforms, "Move brush(es)"); - dot3 = TransformDirection(dot3); - if(selectedResizePointIndex == 1) - { - dot3 = -dot3; - } - - TranslateBrushes(dot3); - } - else - { - if(GetIsValidToResize()) - { - RescaleBrush(direction, dot3); - } - } - } - - void OnMouseDragTranslate(SceneView sceneView, Event e) - { - if(!duplicationOccured && EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control)) - { -// Vector3 newPosition = targetBrushTransform.position; - primaryTargetBrushTransform.position = originalPosition; - - duplicationOccured = true; + private void OnMouseDragResize(SceneView sceneView, Event e) + { + Rect pixelRect = sceneView.camera.pixelRect; + + // Resize a handle + Vector2 currentPosition = e.mousePosition; + + // Clamp the current position to the screen rect. Otherwise we get some odd problems if you carry on + // resizing off screen. + currentPosition.x = Mathf.Clamp(currentPosition.x, pixelRect.xMin, pixelRect.xMax); + currentPosition.y = Mathf.Clamp(currentPosition.y, pixelRect.yMin, pixelRect.yMax); + + Vector2 lastPosition = currentPosition - e.delta; + + Ray lastRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(lastPosition)); + + Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); + + // Bounds bounds = GetBounds(); + + Vector3 offset = primaryTargetBrushTransform.position; + // if(Tools.pivotMode == PivotMode.Center && Tools.pivotRotation == PivotRotation.Global) + // { + // offset = GetBounds().center; + // } + + Vector3 lineStart = offset + TransformDirection(selectedResizeHandlePair.Value.point1); + Vector3 lineEnd = offset + TransformDirection(selectedResizeHandlePair.Value.point2); + + Vector3 lastPositionWorld = MathHelper.ClosestPointOnLine(lastRay, lineStart, lineEnd); + Vector3 currentPositionWorld = MathHelper.ClosestPointOnLine(currentRay, lineStart, lineEnd); + + Vector3 direction; + if (selectedResizePointIndex == 0) + { + direction = selectedResizeHandlePair.Value.point1; + } + else + { + direction = selectedResizeHandlePair.Value.point2; + } + + // If shift is held, flip the direction so they're resizing the opposite side + if (EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Shift)) + { + direction = -direction; + } + + Vector3 deltaWorld = (currentPositionWorld - lastPositionWorld); + // Rescaling logic deals with local space changes, convert to that space + Vector3 deltaLocal = InverseTransformDirection(deltaWorld); + + Vector3 dot3 = Vector3.zero; + if (direction.x != 0) + { + dot3.x = Vector3.Dot(deltaLocal, new Vector3(Mathf.Sign(direction.x), 0, 0)); + } + if (direction.y != 0) + { + dot3.y = Vector3.Dot(deltaLocal, new Vector3(0, Mathf.Sign(direction.y), 0)); + } + if (direction.z != 0) + { + dot3.z = Vector3.Dot(deltaLocal, new Vector3(0, 0, Mathf.Sign(direction.z))); + } + + float snapDistance = CurrentSettings.PositionSnapDistance; + + if (CurrentSettings.PositionSnappingEnabled) + { + // Snapping's dot uses an offset to track deltas that would be lost otherwise due to snapping + dot3 += dotOffset3; + + Vector3 roundedDot3 = MathHelper.RoundVector3(dot3, snapDistance); + dotOffset3 = dot3 - roundedDot3; + dot3 = roundedDot3; + } + + if (EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control)) + { + Undo.RecordObjects(targetBrushTransforms, "Move brush(es)"); + dot3 = TransformDirection(dot3); + if (selectedResizePointIndex == 1) + { + dot3 = -dot3; + } + + TranslateBrushes(dot3); + } + else + { + if (GetIsValidToResize()) + { + RescaleBrush(direction, dot3); + } + } + } + + private void OnMouseDragTranslate(SceneView sceneView, Event e) + { + if (!duplicationOccured && EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control)) + { + // Vector3 newPosition = targetBrushTransform.position; + primaryTargetBrushTransform.position = originalPosition; + + duplicationOccured = true; // Duplicate selection, the selection is set automatically EditorHelper.DuplicateSelection(); - } - else - { - SabreMouse.SetCursor(MouseCursor.MoveArrow); - - // Drag brush position - Vector2 lastPosition = e.mousePosition - e.delta; - Vector2 currentPosition = e.mousePosition; - - Ray lastRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(lastPosition)); - Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); - - float lastRayHit; - float currentRayHit; - if(translationPlane.Raycast(lastRay, out lastRayHit)) - { - if(translationPlane.Raycast(currentRay, out currentRayHit)) - { - // Find the world points where the rays hit the rotation plane - Vector3 lastPositionWorld = lastRay.GetPoint(lastRayHit); - Vector3 currentPositionWorld = currentRay.GetPoint(currentRayHit); - - Vector3 delta = (currentPositionWorld - lastPositionWorld); - - float snapDistance = CurrentSettings.PositionSnapDistance; - - Vector3 finalDelta; - - if (CurrentSettings.PositionSnappingEnabled) - { - delta += translationUnrounded; - - // Round the delta according to the pivot rotation mode - Vector3 roundedDelta = TransformDirection(MathHelper.RoundVector3(InverseTransformDirection(delta), snapDistance)); - - translationUnrounded = delta - roundedDelta; - finalDelta = roundedDelta; - } - else - { - finalDelta = delta; - } - - - TranslateBrushes(finalDelta); -// for (int i = 0; i < Selection.transforms.Length; i++) -// { -// Undo.RecordObjects(Selection.transforms, "Move brush(es)"); -// Selection.transforms[i].position += finalDelta; -// -// } - } - } - } - } - - Vector3 GetRotationAxis() - { - Vector3 rotationAxis; - - if(selectedResizeHandlePair.Value.point1.x == 0) - { - rotationAxis = new Vector3(1,0,0); - } - else if(selectedResizeHandlePair.Value.point1.y == 0) - { - rotationAxis = new Vector3(0,1,0); - } - else - { - rotationAxis = new Vector3(0,0,1); - } - - return rotationAxis; - } - - Vector3 GetRotationAxisTransformed() - { - return TransformDirection(GetRotationAxis()); - } - - Vector3 GetBrushesPivotPoint() - { - if(primaryTargetBrushTransform != null) - { - if(Tools.pivotMode == PivotMode.Center) - { + } + else + { + SabreMouse.SetCursor(MouseCursor.MoveArrow); + + // Drag brush position + Vector2 lastPosition = e.mousePosition - e.delta; + Vector2 currentPosition = e.mousePosition; + + Ray lastRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(lastPosition)); + Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); + + float lastRayHit; + float currentRayHit; + if (translationPlane.Raycast(lastRay, out lastRayHit)) + { + if (translationPlane.Raycast(currentRay, out currentRayHit)) + { + // Find the world points where the rays hit the rotation plane + Vector3 lastPositionWorld = lastRay.GetPoint(lastRayHit); + Vector3 currentPositionWorld = currentRay.GetPoint(currentRayHit); + + Vector3 delta = (currentPositionWorld - lastPositionWorld); + + float snapDistance = CurrentSettings.PositionSnapDistance; + + Vector3 finalDelta; + + if (CurrentSettings.PositionSnappingEnabled) + { + delta += translationUnrounded; + + // Round the delta according to the pivot rotation mode + Vector3 roundedDelta = TransformDirection(MathHelper.RoundVector3(InverseTransformDirection(delta), snapDistance)); + + translationUnrounded = delta - roundedDelta; + finalDelta = roundedDelta; + } + else + { + finalDelta = delta; + } + + TranslateBrushes(finalDelta); + // for (int i = 0; i < Selection.transforms.Length; i++) + // { + // Undo.RecordObjects(Selection.transforms, "Move brush(es)"); + // Selection.transforms[i].position += finalDelta; + // + // } + } + } + } + } + + private Vector3 GetRotationAxis() + { + Vector3 rotationAxis; + + if (selectedResizeHandlePair.Value.point1.x == 0) + { + rotationAxis = new Vector3(1, 0, 0); + } + else if (selectedResizeHandlePair.Value.point1.y == 0) + { + rotationAxis = new Vector3(0, 1, 0); + } + else + { + rotationAxis = new Vector3(0, 0, 1); + } + + return rotationAxis; + } + + private Vector3 GetRotationAxisTransformed() + { + return TransformDirection(GetRotationAxis()); + } + + private Vector3 GetBrushesPivotPoint() + { + if (primaryTargetBrushTransform != null) + { + if (Tools.pivotMode == PivotMode.Center) + { Bounds bounds = GetBounds(); if (Tools.pivotRotation == PivotRotation.Global) { @@ -989,318 +988,323 @@ Vector3 GetBrushesPivotPoint() } else { - return primaryTargetBrushTransform.TransformPoint(bounds.center); + return primaryTargetBrushTransform.TransformPoint(bounds.center); + } + } + else // Local mode + { + // Just return the position of the primary selected brush + return primaryTargetBrushTransform.position; + } + } + else + { + return Vector3.zero; + } + } + + private void OnMouseDragRotate(SceneView sceneView, Event e) + { + Bounds bounds = GetBounds(); + // Rotation + Vector3 rotationAxis = GetRotationAxisTransformed(); + // Brush center point + Vector3 centerWorld = TransformPoint(bounds.center); + + Vector2 lastPosition = e.mousePosition - e.delta; + Vector2 currentPosition = e.mousePosition; + + Ray lastRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(lastPosition)); + Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); + + // Calculate the plane rotation is occuring on (this plane shares the rotation axis normal and is coplanar + // with the center point of the brush) + Plane plane = new Plane(rotationAxis, centerWorld); + + float lastRayHit; + float currentRayHit; + if (plane.Raycast(lastRay, out lastRayHit)) + { + if (plane.Raycast(currentRay, out currentRayHit)) + { + // Find the world points where the rays hit the rotation plane + Vector3 lastRayWorld = lastRay.GetPoint(lastRayHit); + Vector3 currentRayWorld = currentRay.GetPoint(currentRayHit); + + // Find the rotation needed to transform the points on the plane into XY aligned plane + Quaternion cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(rotationAxis)); + + // Subtract the brush's center point so the points are relative to the center of the brush + currentRayWorld -= centerWorld; + lastRayWorld -= centerWorld; + + // Rotate the world points by the cancelling rotation to put them on XY plane + currentRayWorld = cancellingRotation * currentRayWorld; + lastRayWorld = cancellingRotation * lastRayWorld; + + // Because the points have been transformed into XY plane, we can just use atan2 to find the angles + float angle1 = Mathf.Rad2Deg * Mathf.Atan2(currentRayWorld.x, currentRayWorld.y); + float angle2 = Mathf.Rad2Deg * Mathf.Atan2(lastRayWorld.x, lastRayWorld.y); + // Change in angle is simply the new angle minus the last + float deltaAngle = angle2 - angle1; + + if (CurrentSettings.AngleSnappingEnabled) + { + deltaAngle += unroundedDeltaAngle; + + float roundedAngle = MathHelper.RoundFloat(deltaAngle, CurrentSettings.AngleSnapDistance); + unroundedDeltaAngle = deltaAngle - roundedAngle; + deltaAngle = roundedAngle; + } + fullDeltaAngle += deltaAngle; + message = fullDeltaAngle.ToString(); + + Undo.RecordObjects(targetBrushTransforms, "Rotate brush(es)"); + + for (int i = 0; i < targetBrushTransforms.Length; i++) + { + targetBrushTransforms[i].RotateAround(centerWorld, rotationAxis, deltaAngle); + } + + for (int brushIndex = 0; brushIndex < targetBrushBases.Length; brushIndex++) + { + EditorHelper.SetDirty(targetBrushBases[brushIndex]); + EditorHelper.SetDirty(targetBrushBases[brushIndex].transform); + targetBrushBases[brushIndex].Invalidate(true); + } + } + } + + SabreMouse.SetCursor(MouseCursor.RotateArrow); + } + + private void OnMouseUp(SceneView sceneView, Event e) + { + duplicationOccured = false; + moveCancelled = false; + + // Just let go of the mouse button, the resize operation has finished + if (currentMode != ActiveMode.None && primaryTargetBrushBase != null && widgetMode == WidgetMode.Bounds) + { + selectedResizeHandlePair = null; + currentMode = ActiveMode.None; + + if (csgModel.MouseIsDragging) + { + e.Use(); + } + + Undo.RecordObjects(targetBrushTransforms, "Rescale Brush"); + Undo.RecordObjects(targetBrushBases, "Rescale Brush"); + } + else + { + if (isMarqueeSelection) // Marquee vertex selection + { + isMarqueeSelection = false; + + marqueeEnd = e.mousePosition; + + List brushes = csgModel.GetBrushes(); + List highlightedBrushObjects = new List(); + for (int brushIndex = 0; brushIndex < brushes.Count; brushIndex++) + { + if (brushes[brushIndex] != null) + { + Vector3 brushWorldPivot = brushes[brushIndex].transform.position; + Vector3 screenPoint = sceneView.camera.WorldToScreenPoint(brushWorldPivot); + + if (SabreMouse.MarqueeContainsPoint(marqueeStart, marqueeEnd, screenPoint)) + { + bool brushInsideMarquee = true; + + // Determine if all the brush's vertices are inside the maquee + Polygon[] transformedPolygons = brushes[brushIndex].GenerateTransformedPolygons(); + for (int polygonIndex = 0; polygonIndex < transformedPolygons.Length && brushInsideMarquee; polygonIndex++) + { + Vertex[] vertices = transformedPolygons[polygonIndex].Vertices; + for (int vertexIndex = 0; vertexIndex < vertices.Length && brushInsideMarquee; vertexIndex++) + { + screenPoint = sceneView.camera.WorldToScreenPoint(vertices[vertexIndex].Position); + if (!SabreMouse.MarqueeContainsPoint(marqueeStart, marqueeEnd, screenPoint)) + { + brushInsideMarquee = false; + } + } + } + + if (brushInsideMarquee) + { + highlightedBrushObjects.Add(brushes[brushIndex].gameObject); + } + } + } + } + + if (!e.shift && !e.control) + { + Selection.objects = new Object[0]; + } + + List tempSelection = new List(Selection.objects); + + for (int i = 0; i < highlightedBrushObjects.Count; i++) + { + if (e.control) + { + tempSelection.Remove(highlightedBrushObjects[i]); + } + else + { + if (!tempSelection.Contains(highlightedBrushObjects[i])) + { + tempSelection.Add(highlightedBrushObjects[i]); + } + } + } + + Selection.objects = tempSelection.ToArray(); + } + } + + if (primaryTargetBrushBase != null) + { + for (int i = 0; i < targetBrushes.Length; i++) + { + if (targetBrushes[i] != null) + { + targetBrushes[i].ResetPivot(); + } + } + } + + SabreMouse.ResetCursor(); + SceneView.RepaintAll(); + } + + private void CancelMove() + { + moveCancelled = true; + primaryTargetBrushTransform.position = originalPosition; + SabreMouse.ResetCursor(); + } + + public void OnRepaint(SceneView sceneView, Event e) + { + if (isMarqueeSelection && sceneView == SceneView.lastActiveSceneView) + { + SabreGraphics.DrawMarquee(marqueeStart, marqueeEnd); + } + + if (primaryTargetBrushBase != null) + { + Bounds bounds = GetBounds(); + + // Selected brush white outline + SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); + + // Selection + GL.Begin(GL.LINES); + + if (Tools.pivotRotation == PivotRotation.Global) + { + GL.Color(Color.white); + SabreGraphics.DrawBox(bounds); + if (CurrentSettings.ShowBrushBoundsGuideLines) + SabreGraphics.DrawBoxGuideLines(bounds, 8.0f); + } + else + { + GL.Color(Color.white); + SabreGraphics.DrawBox(bounds, primaryTargetBrushTransform); + if (CurrentSettings.ShowBrushBoundsGuideLines) + SabreGraphics.DrawBoxGuideLines(bounds, 8.0f, primaryTargetBrushTransform); + } + + GL.End(); + + if (widgetMode == WidgetMode.Bounds) + { + if (currentMode == ActiveMode.Rotate && selectedResizeHandlePair.HasValue) + { + SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); + + Vector3 extents = bounds.extents; + + // If rotation axis is (0,1,0) or (0,1,0), this produces (1,0,1) + Vector3 mask = Vector3.one - MathHelper.VectorAbs(GetRotationAxis()); + + // Discount any extents in the rotation axis and find the magnitude + float largestExtent = extents.Multiply(mask).magnitude;// bounds.GetLargestExtent(); + Vector3 worldCenter = TransformPoint(bounds.center); + SabreGraphics.DrawRotationCircle(worldCenter, GetRotationAxisTransformed(), largestExtent, initialRotationDirection); } - } - else // Local mode - { - // Just return the position of the primary selected brush - return primaryTargetBrushTransform.position; - } - } - else - { - return Vector3.zero; - } - } - - void OnMouseDragRotate(SceneView sceneView, Event e) - { - Bounds bounds = GetBounds(); - // Rotation - Vector3 rotationAxis = GetRotationAxisTransformed(); - // Brush center point - Vector3 centerWorld = TransformPoint(bounds.center); - - Vector2 lastPosition = e.mousePosition - e.delta; - Vector2 currentPosition = e.mousePosition; - - Ray lastRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(lastPosition)); - Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); - - // Calculate the plane rotation is occuring on (this plane shares the rotation axis normal and is coplanar - // with the center point of the brush) - Plane plane = new Plane(rotationAxis, centerWorld); - - float lastRayHit; - float currentRayHit; - if(plane.Raycast(lastRay, out lastRayHit)) - { - if(plane.Raycast(currentRay, out currentRayHit)) - { - // Find the world points where the rays hit the rotation plane - Vector3 lastRayWorld = lastRay.GetPoint(lastRayHit); - Vector3 currentRayWorld = currentRay.GetPoint(currentRayHit); - - // Find the rotation needed to transform the points on the plane into XY aligned plane - Quaternion cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(rotationAxis)); - - // Subtract the brush's center point so the points are relative to the center of the brush - currentRayWorld -= centerWorld; - lastRayWorld -= centerWorld; - - // Rotate the world points by the cancelling rotation to put them on XY plane - currentRayWorld = cancellingRotation * currentRayWorld; - lastRayWorld = cancellingRotation * lastRayWorld; - - // Because the points have been transformed into XY plane, we can just use atan2 to find the angles - float angle1 = Mathf.Rad2Deg * Mathf.Atan2(currentRayWorld.x, currentRayWorld.y); - float angle2 = Mathf.Rad2Deg * Mathf.Atan2(lastRayWorld.x, lastRayWorld.y); - // Change in angle is simply the new angle minus the last - float deltaAngle = angle2 - angle1; - - - if(CurrentSettings.AngleSnappingEnabled) - { - deltaAngle += unroundedDeltaAngle; - - float roundedAngle = MathHelper.RoundFloat(deltaAngle, CurrentSettings.AngleSnapDistance); - unroundedDeltaAngle = deltaAngle - roundedAngle; - deltaAngle = roundedAngle; - } - fullDeltaAngle += deltaAngle; - message = fullDeltaAngle.ToString(); + DrawResizeHandles(sceneView, e); + } + } - Undo.RecordObjects(targetBrushTransforms, "Rotate brush(es)"); - - for (int i = 0; i < targetBrushTransforms.Length; i++) - { - targetBrushTransforms[i].RotateAround(centerWorld, rotationAxis, deltaAngle); - } - - for (int brushIndex = 0; brushIndex < targetBrushBases.Length; brushIndex++) - { - EditorHelper.SetDirty(targetBrushBases[brushIndex]); - EditorHelper.SetDirty(targetBrushBases[brushIndex].transform); - targetBrushBases[brushIndex].Invalidate(true); - } - } - } - - SabreMouse.SetCursor(MouseCursor.RotateArrow); - } - - void OnMouseUp(SceneView sceneView, Event e) - { - duplicationOccured = false; - moveCancelled = false; - - // Just let go of the mouse button, the resize operation has finished - if (currentMode != ActiveMode.None && primaryTargetBrushBase != null && widgetMode == WidgetMode.Bounds) - { - selectedResizeHandlePair = null; - currentMode = ActiveMode.None; - - if(csgModel.MouseIsDragging) - { - e.Use(); - } - - Undo.RecordObjects(targetBrushTransforms, "Rescale Brush"); - Undo.RecordObjects(targetBrushBases, "Rescale Brush"); - } - else - { - if(isMarqueeSelection) // Marquee vertex selection - { - isMarqueeSelection = false; - - marqueeEnd = e.mousePosition; - - List brushes = csgModel.GetBrushes(); - List highlightedBrushObjects = new List(); - for (int brushIndex = 0; brushIndex < brushes.Count; brushIndex++) - { - if(brushes[brushIndex] != null) - { - Vector3 brushWorldPivot = brushes[brushIndex].transform.position; - Vector3 screenPoint = sceneView.camera.WorldToScreenPoint(brushWorldPivot); - - if(SabreMouse.MarqueeContainsPoint(marqueeStart, marqueeEnd, screenPoint)) - { - bool brushInsideMarquee = true; - - // Determine if all the brush's vertices are inside the maquee - Polygon[] transformedPolygons = brushes[brushIndex].GenerateTransformedPolygons(); - for (int polygonIndex = 0; polygonIndex < transformedPolygons.Length && brushInsideMarquee; polygonIndex++) - { - Vertex[] vertices = transformedPolygons[polygonIndex].Vertices; - for (int vertexIndex = 0; vertexIndex < vertices.Length && brushInsideMarquee; vertexIndex++) - { - screenPoint = sceneView.camera.WorldToScreenPoint(vertices[vertexIndex].Position); - if(!SabreMouse.MarqueeContainsPoint(marqueeStart, marqueeEnd, screenPoint)) - { - brushInsideMarquee = false; - } - } - } - - if(brushInsideMarquee) - { - highlightedBrushObjects.Add(brushes[brushIndex].gameObject); - } - } - } - } - - if(!e.shift && !e.control) - { - Selection.objects = new Object[0]; - } - - List tempSelection = new List(Selection.objects); - - for (int i = 0; i < highlightedBrushObjects.Count; i++) - { - if(e.control) - { - tempSelection.Remove(highlightedBrushObjects[i]); - } - else - { - if(!tempSelection.Contains(highlightedBrushObjects[i])) - { - tempSelection.Add(highlightedBrushObjects[i]); - } - } - } - - Selection.objects = tempSelection.ToArray(); - } - } - - if(primaryTargetBrushBase != null) - { - for (int i = 0; i < targetBrushes.Length; i++) - { - if(targetBrushes[i] != null) - { - targetBrushes[i].ResetPivot(); - } - } - } - - SabreMouse.ResetCursor(); - SceneView.RepaintAll(); + GUIStyle style = new GUIStyle(EditorStyles.toolbar); + style.normal.background = SabreCSGResources.ClearTexture; + Rect rectangle = new Rect(0, 50, 300, 50); + style.fixedHeight = rectangle.height; + GUILayout.Window(140007, rectangle, OnTopToolbarGUI, "", style); } - void CancelMove() - { - moveCancelled = true; - primaryTargetBrushTransform.position = originalPosition; - SabreMouse.ResetCursor(); - } - - public void OnRepaint(SceneView sceneView, Event e) - { - if(isMarqueeSelection && sceneView == SceneView.lastActiveSceneView) - { - SabreGraphics.DrawMarquee(marqueeStart, marqueeEnd); - } - - if(primaryTargetBrushBase != null && widgetMode == WidgetMode.Bounds) - { - Bounds bounds = GetBounds(); - - // Selected brush green outline - SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); - - // Selection - GL.Begin(GL.LINES); - GL.Color(Color.white); - - if(Tools.pivotRotation == PivotRotation.Global) - { - SabreGraphics.DrawBox(bounds); - } - else - { - SabreGraphics.DrawBox(bounds, primaryTargetBrushTransform); - } - - GL.End(); - - - if(currentMode == ActiveMode.Rotate && selectedResizeHandlePair.HasValue) - { - SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); - - - Vector3 extents = bounds.extents; - - // If rotation axis is (0,1,0) or (0,1,0), this produces (1,0,1) - Vector3 mask = Vector3.one - MathHelper.VectorAbs(GetRotationAxis()); - - // Discount any extents in the rotation axis and find the magnitude - float largestExtent = extents.Multiply(mask).magnitude;// bounds.GetLargestExtent(); - Vector3 worldCenter = TransformPoint(bounds.center); - SabreGraphics.DrawRotationCircle(worldCenter, GetRotationAxisTransformed(), largestExtent, initialRotationDirection); - } - DrawResizeHandles(sceneView, e); - } - - GUIStyle style = new GUIStyle(EditorStyles.toolbar); - style.normal.background = SabreCSGResources.ClearTexture; - Rect rectangle = new Rect(0, 50, 300, 50); - style.fixedHeight = rectangle.height; - GUILayout.Window(140007, rectangle, OnTopToolbarGUI, "", style); - } - - private void OnTopToolbarGUI(int windowID) - { - widgetMode = SabreGUILayout.DrawEnumGrid(widgetMode, GUILayout.Width(67)); - - GUILayout.BeginHorizontal(GUILayout.Width(200)); - - if (GUILayout.Button("Snap Center", EditorStyles.miniButton)) - { - for (int i = 0; i < targetBrushBases.Length; i++) - { - Undo.RecordObject(targetBrushBases[i].transform, "Snap Center"); - Undo.RecordObject(targetBrushBases[i], "Snap Center"); - - Vector3 newPosition = targetBrushBases[i].transform.position; - - float snapDistance = CurrentSettings.PositionSnapDistance; - newPosition = MathHelper.RoundVector3(newPosition, snapDistance); - targetBrushBases[i].transform.position = newPosition; - targetBrushBases[i].Invalidate(true); - } - } - - if (GUILayout.Button("Flip X", EditorStyles.miniButton)) - { - Undo.RecordObjects(targetBrushes, "Flip Polygons"); + private void OnTopToolbarGUI(int windowID) + { + widgetMode = SabreGUILayout.DrawEnumGrid(widgetMode, GUILayout.Width(67)); + + GUILayout.BeginHorizontal(GUILayout.Width(200)); + + if (GUILayout.Button("Snap Center", EditorStyles.miniButton)) + { + for (int i = 0; i < targetBrushBases.Length; i++) + { + Undo.RecordObject(targetBrushBases[i].transform, "Snap Center"); + Undo.RecordObject(targetBrushBases[i], "Snap Center"); + + Vector3 newPosition = targetBrushBases[i].transform.position; + + float snapDistance = CurrentSettings.PositionSnapDistance; + newPosition = MathHelper.RoundVector3(newPosition, snapDistance); + targetBrushBases[i].transform.position = newPosition; + targetBrushBases[i].Invalidate(true); + } + } + + if (GUILayout.Button("Flip X", EditorStyles.miniButton)) + { + Undo.RecordObjects(targetBrushes, "Flip Polygons"); bool localToPrimaryBrush = (Tools.pivotRotation == PivotRotation.Local); BrushUtility.Flip(primaryTargetBrush, targetBrushes, 0, localToPrimaryBrush, GetBrushesPivotPoint()); - } + } - if (GUILayout.Button("Flip Y", EditorStyles.miniButton)) - { - Undo.RecordObjects(targetBrushes, "Flip Polygons"); + if (GUILayout.Button("Flip Y", EditorStyles.miniButton)) + { + Undo.RecordObjects(targetBrushes, "Flip Polygons"); bool localToPrimaryBrush = (Tools.pivotRotation == PivotRotation.Local); BrushUtility.Flip(primaryTargetBrush, targetBrushes, 1, localToPrimaryBrush, GetBrushesPivotPoint()); } if (GUILayout.Button("Flip Z", EditorStyles.miniButton)) - { - Undo.RecordObjects(targetBrushes, "Flip Polygons"); + { + Undo.RecordObjects(targetBrushes, "Flip Polygons"); bool localToPrimaryBrush = (Tools.pivotRotation == PivotRotation.Local); BrushUtility.Flip(primaryTargetBrush, targetBrushes, 2, localToPrimaryBrush, GetBrushesPivotPoint()); } GUILayout.EndHorizontal(); - } + } - public void RescaleBrush(Vector3 direction, Vector3 translation) - { - if(translation == Vector3.zero) - { - return; - } + public void RescaleBrush(Vector3 direction, Vector3 translation) + { + if (translation == Vector3.zero) + { + return; + } //VisualDebug.ClearAll(); @@ -1310,31 +1314,31 @@ public void RescaleBrush(Vector3 direction, Vector3 translation) Bounds bounds = GetBounds(); - Vector3 negativeDirection = -1 * direction; - Vector3 localPivotPoint = bounds.extents.Multiply(negativeDirection) + bounds.center; + Vector3 negativeDirection = -1 * direction; + Vector3 localPivotPoint = bounds.extents.Multiply(negativeDirection) + bounds.center; - Vector3 size = bounds.size; + Vector3 size = bounds.size; Vector3 scaleFactor = new Vector3(1 + translation.x / size.x, 1 + translation.y / size.y, 1 + translation.z / size.z); - Vector3 newDirection = direction.Multiply(scaleFactor); + Vector3 newDirection = direction.Multiply(scaleFactor); - Vector3 scaleVector3 = MathHelper.VectorAbs(newDirection); + Vector3 scaleVector3 = MathHelper.VectorAbs(newDirection); - if (Mathf.Abs(scaleVector3.x) <= 0.01f) - { - scaleVector3.x = 1; - } + if (Mathf.Abs(scaleVector3.x) <= 0.01f) + { + scaleVector3.x = 1; + } if (Mathf.Abs(scaleVector3.y) <= 0.01f) { - scaleVector3.y = 1; - } + scaleVector3.y = 1; + } if (Mathf.Abs(scaleVector3.z) <= 0.01f) { - scaleVector3.z = 1; - } + scaleVector3.z = 1; + } - if(scaleVector3 == Vector3.one) + if (scaleVector3 == Vector3.one) { // No scale to apply, so early out return; @@ -1342,242 +1346,236 @@ public void RescaleBrush(Vector3 direction, Vector3 translation) Vector3 primaryPivot = primaryTargetBrushTransform.TransformPoint(bounds.center); - for (int brushIndex = 0; brushIndex < targetBrushBases.Length; brushIndex++) - { - Undo.RecordObject(targetBrushBases[brushIndex].transform, "Rescale Brush"); - Undo.RecordObject(targetBrushBases[brushIndex], "Rescale Brush"); + for (int brushIndex = 0; brushIndex < targetBrushBases.Length; brushIndex++) + { + Undo.RecordObject(targetBrushBases[brushIndex].transform, "Rescale Brush"); + Undo.RecordObject(targetBrushBases[brushIndex], "Rescale Brush"); + + if (targetBrushes[brushIndex] != null) // PrimitiveBrush + { + Polygon[] polygons = targetBrushes[brushIndex].GetPolygons(); + + for (int i = 0; i < polygons.Length; i++) + { + Polygon polygon = polygons[i]; + + polygon.CalculatePlane(); + Vector3 previousPlaneNormal = polygons[i].Plane.normal; + + int vertexCount = polygon.Vertices.Length; + + Vector3[] newPositions = new Vector3[vertexCount]; + Vector2[] newUV = new Vector2[vertexCount]; + + for (int j = 0; j < vertexCount; j++) + { + newPositions[j] = polygon.Vertices[j].Position; + newUV[j] = polygon.Vertices[j].UV; + } + + for (int j = 0; j < vertexCount; j++) + { + Vertex vertex = polygon.Vertices[j]; + + Vector3 newPosition = vertex.Position; + + // Start transform + newPosition = targetBrushes[brushIndex].transform.TransformPoint(newPosition); + + if (Tools.pivotRotation == PivotRotation.Local) + { + newPosition = primaryTargetBrushTransform.InverseTransformPoint(newPosition); + } + + newPosition -= localPivotPoint; + + // Scale in that direction + newPosition = newPosition.Multiply(scaleVector3); + + newPosition += localPivotPoint; + + if (Tools.pivotRotation == PivotRotation.Local) + { + newPosition = primaryTargetBrushTransform.TransformPoint(newPosition); + } + + newPosition = targetBrushes[brushIndex].transform.InverseTransformPoint(newPosition); + + newPositions[j] = newPosition; + + // Update UVs + Vector3 p1 = polygon.Vertices[0].Position; + Vector3 p2 = polygon.Vertices[1].Position; + Vector3 p3 = polygon.Vertices[2].Position; + + UnityEngine.Plane plane = new UnityEngine.Plane(p1, p2, p3); + Vector3 f = MathHelper.ClosestPointOnPlane(newPosition, plane); + + Vector2 uv1 = polygon.Vertices[0].UV; + Vector2 uv2 = polygon.Vertices[1].UV; + Vector2 uv3 = polygon.Vertices[2].UV; + + // calculate vectors from point f to vertices p1, p2 and p3: + Vector3 f1 = p1 - f; + Vector3 f2 = p2 - f; + Vector3 f3 = p3 - f; + + // calculate the areas (parameters order is essential in this case): + Vector3 va = Vector3.Cross(p1 - p2, p1 - p3); // main triangle cross product + Vector3 va1 = Vector3.Cross(f2, f3); // p1's triangle cross product + Vector3 va2 = Vector3.Cross(f3, f1); // p2's triangle cross product + Vector3 va3 = Vector3.Cross(f1, f2); // p3's triangle cross product + + float a = va.magnitude; // main triangle area + + // calculate barycentric coordinates with sign: + float a1 = va1.magnitude / a * Mathf.Sign(Vector3.Dot(va, va1)); + float a2 = va2.magnitude / a * Mathf.Sign(Vector3.Dot(va, va2)); + float a3 = va3.magnitude / a * Mathf.Sign(Vector3.Dot(va, va3)); + + // find the uv corresponding to point f (uv1/uv2/uv3 are associated to p1/p2/p3): + Vector2 uv = uv1 * a1 + uv2 * a2 + uv3 * a3; + + newUV[j] = uv; + } + + // Apply all the changes to the polygon + for (int j = 0; j < vertexCount; j++) + { + Vertex vertex = polygon.Vertices[j]; + vertex.Position = newPositions[j]; + vertex.UV = newUV[j]; + } + + // Polygon geometry has changed, inform the polygon that it needs to recalculate its cached plane + polygons[i].CalculatePlane(); + + Vector3 newPlaneNormal = polygons[i].Plane.normal; + + // Find the rotation from the original polygon plane to the new polygon plane + Quaternion normalRotation = Quaternion.FromToRotation(previousPlaneNormal, newPlaneNormal); + + // Rotate all the vertex normals by the new rotation + for (int j = 0; j < vertexCount; j++) + { + Vertex vertex = polygon.Vertices[j]; + vertex.Normal = normalRotation * vertex.Normal; + } + } + } + else // Compound brush + { + if (Tools.pivotRotation == PivotRotation.Global) + { + if (targetBrushTransforms[brushIndex].forward.GetSetAxisCount() != 1 + || targetBrushTransforms[brushIndex].up.GetSetAxisCount() != 1) + { + // Skip any brushes that are not axis aligned + continue; + } + + int found = 0; + + int globalAxis1 = 0; + int globalAxis2 = 0; + + bool flipped1 = false; + bool flipped2 = false; + + for (int i = 0; i < 3; i++) + { + if (!direction[i].EqualsWithEpsilon(0)) + { + if (found == 0) + { + globalAxis1 = i; + if (direction[i] < 0) + { + flipped1 = true; + } + } + else if (found == 1) + { + globalAxis2 = i; + if (direction[i] < 0) + { + flipped2 = true; + } + } + found++; + } + } + + if (found < 1 || found > 2) // Unexpected scenario, skip this brush + { + continue; + } + + for (int axisIndex = 0; axisIndex < found; axisIndex++) + { + bool flipped; + int flippedSign; + int globalAxis; + + if (axisIndex == 0) + { + globalAxis = globalAxis1; + flipped = flipped1; + flippedSign = flipped1 ? -1 : 1; + } + else + { + globalAxis = globalAxis2; + flipped = flipped2; + flippedSign = flipped2 ? -1 : 1; + } + + Vector3 globalTempDirection = Vector3.zero.SetAxis(globalAxis, 1); + Vector3 transformedDirection = targetBrushTransforms[brushIndex].TransformDirection(globalTempDirection); + + int localAxis = 0; + for (int i = 0; i < 3; i++) + { + if (!transformedDirection[i].EqualsWithEpsilon(0)) + { + localAxis = i; + break; + } + } + + Bounds newBounds = targetBrushBases[brushIndex].GetBounds(); - if(targetBrushes[brushIndex] != null) // PrimitiveBrush - { - Polygon[] polygons = targetBrushes[brushIndex].GetPolygons(); - - for (int i = 0; i < polygons.Length; i++) - { - Polygon polygon = polygons[i]; + float offset = 0.5f * translation[globalAxis] * (newBounds.extents[localAxis] / bounds.extents[globalAxis]); + if (flipped) + { + offset = -offset; + } - polygon.CalculatePlane(); - Vector3 previousPlaneNormal = polygons[i].Plane.normal; + Vector3 globalPivot = bounds.center; + Vector3 globalPivotOffset = Vector3.zero.SetAxis(globalAxis, -flippedSign * bounds.extents[globalAxis]); + globalPivot += globalPivotOffset; + // VisualDebug.AddPoint(globalPivot, Color.red); - int vertexCount = polygon.Vertices.Length; + Vector3 localPivot = newBounds.center + targetBrushTransforms[brushIndex].position; + Vector3 localPivotOffset = Vector3.zero.SetAxis(globalAxis, -flippedSign * newBounds.extents[localAxis]); + localPivot += localPivotOffset; + // VisualDebug.AddPoint(localPivot); - Vector3[] newPositions = new Vector3[vertexCount]; - Vector2[] newUV = new Vector2[vertexCount]; + offset += 0.5f * translation[globalAxis] * (localPivot[globalAxis] - globalPivot[globalAxis]) / bounds.extents[globalAxis]; - for (int j = 0; j < vertexCount; j++) - { - newPositions[j] = polygon.Vertices[j].Position; - newUV[j] = polygon.Vertices[j].UV; - } - - for (int j = 0; j < vertexCount; j++) - { - Vertex vertex = polygon.Vertices[j]; - - Vector3 newPosition = vertex.Position; + Vector3 offset3 = Vector3.zero.SetAxis(globalAxis, offset); + targetBrushTransforms[brushIndex].position += offset3; - // Start transform - newPosition = targetBrushes[brushIndex].transform.TransformPoint(newPosition); + // Apply new bounds size + Vector3 extents = newBounds.extents; + extents[localAxis] *= scaleVector3[globalAxis]; + newBounds.extents = extents; - if(Tools.pivotRotation == PivotRotation.Local) - { - newPosition = primaryTargetBrushTransform.InverseTransformPoint(newPosition); - } - - newPosition -= localPivotPoint; - - // Scale in that direction - newPosition = newPosition.Multiply(scaleVector3); - - newPosition += localPivotPoint; - - if(Tools.pivotRotation == PivotRotation.Local) - { - newPosition = primaryTargetBrushTransform.TransformPoint(newPosition); - } - - newPosition = targetBrushes[brushIndex].transform.InverseTransformPoint(newPosition); - - newPositions[j] = newPosition; - - // Update UVs - Vector3 p1 = polygon.Vertices[0].Position; - Vector3 p2 = polygon.Vertices[1].Position; - Vector3 p3 = polygon.Vertices[2].Position; - - UnityEngine.Plane plane = new UnityEngine.Plane(p1, p2, p3); - Vector3 f = MathHelper.ClosestPointOnPlane(newPosition, plane); - - Vector2 uv1 = polygon.Vertices[0].UV; - Vector2 uv2 = polygon.Vertices[1].UV; - Vector2 uv3 = polygon.Vertices[2].UV; - - // calculate vectors from point f to vertices p1, p2 and p3: - Vector3 f1 = p1 - f; - Vector3 f2 = p2 - f; - Vector3 f3 = p3 - f; - - // calculate the areas (parameters order is essential in this case): - Vector3 va = Vector3.Cross(p1 - p2, p1 - p3); // main triangle cross product - Vector3 va1 = Vector3.Cross(f2, f3); // p1's triangle cross product - Vector3 va2 = Vector3.Cross(f3, f1); // p2's triangle cross product - Vector3 va3 = Vector3.Cross(f1, f2); // p3's triangle cross product - - float a = va.magnitude; // main triangle area - - // calculate barycentric coordinates with sign: - float a1 = va1.magnitude / a * Mathf.Sign(Vector3.Dot(va, va1)); - float a2 = va2.magnitude / a * Mathf.Sign(Vector3.Dot(va, va2)); - float a3 = va3.magnitude / a * Mathf.Sign(Vector3.Dot(va, va3)); - - // find the uv corresponding to point f (uv1/uv2/uv3 are associated to p1/p2/p3): - Vector2 uv = uv1 * a1 + uv2 * a2 + uv3 * a3; - - newUV[j] = uv; - } - - // Apply all the changes to the polygon - for (int j = 0; j < vertexCount; j++) - { - Vertex vertex = polygon.Vertices[j]; - vertex.Position = newPositions[j]; - vertex.UV = newUV[j]; - } - - // Polygon geometry has changed, inform the polygon that it needs to recalculate its cached plane - polygons[i].CalculatePlane(); - - Vector3 newPlaneNormal = polygons[i].Plane.normal; - - // Find the rotation from the original polygon plane to the new polygon plane - Quaternion normalRotation = Quaternion.FromToRotation(previousPlaneNormal, newPlaneNormal); - - // Rotate all the vertex normals by the new rotation - for (int j = 0; j < vertexCount; j++) - { - Vertex vertex = polygon.Vertices[j]; - vertex.Normal = normalRotation * vertex.Normal; - } - } - } - else // Compound brush - { - if(Tools.pivotRotation == PivotRotation.Global) - { - if(targetBrushTransforms[brushIndex].forward.GetSetAxisCount() != 1 - || targetBrushTransforms[brushIndex].up.GetSetAxisCount() != 1) - { - // Skip any brushes that are not axis aligned - continue; - } - - int found = 0; - - int globalAxis1 = 0; - int globalAxis2 = 0; - - bool flipped1 = false; - bool flipped2 = false; - - for (int i = 0; i < 3; i++) - { - if(!direction[i].EqualsWithEpsilon(0)) - { - if(found == 0) - { - globalAxis1 = i; - if(direction[i] < 0) - { - flipped1 = true; - } - } - else if(found == 1) - { - globalAxis2 = i; - if(direction[i] < 0) - { - flipped2 = true; - } - } - found++; - } - } - - if(found < 1 || found > 2) // Unexpected scenario, skip this brush - { - continue; - } - - for (int axisIndex = 0; axisIndex < found; axisIndex++) - { - bool flipped; - int flippedSign; - int globalAxis; - - if(axisIndex == 0) - { - globalAxis = globalAxis1; - flipped = flipped1; - flippedSign = flipped1 ? -1 : 1; - } - else - { - globalAxis = globalAxis2; - flipped = flipped2; - flippedSign = flipped2 ? -1 : 1; - } - - Vector3 globalTempDirection = Vector3.zero.SetAxis(globalAxis, 1); - Vector3 transformedDirection = targetBrushTransforms[brushIndex].TransformDirection(globalTempDirection); - - int localAxis = 0; - for (int i = 0; i < 3; i++) - { - if(!transformedDirection[i].EqualsWithEpsilon(0)) - { - localAxis = i; - break; - } - } - - Bounds newBounds = targetBrushBases[brushIndex].GetBounds(); - - float offset = 0.5f * translation[globalAxis] * (newBounds.extents[localAxis] / bounds.extents[globalAxis]); - if(flipped) - { - offset = -offset; - } - - - - Vector3 globalPivot = bounds.center; - Vector3 globalPivotOffset = Vector3.zero.SetAxis(globalAxis, -flippedSign * bounds.extents[globalAxis]); - globalPivot += globalPivotOffset; - // VisualDebug.AddPoint(globalPivot, Color.red); - - Vector3 localPivot = newBounds.center + targetBrushTransforms[brushIndex].position; - Vector3 localPivotOffset = Vector3.zero.SetAxis(globalAxis, -flippedSign * newBounds.extents[localAxis]); - localPivot += localPivotOffset; - // VisualDebug.AddPoint(localPivot); - - offset += 0.5f * translation[globalAxis] * (localPivot[globalAxis] - globalPivot[globalAxis]) / bounds.extents[globalAxis]; - - - - Vector3 offset3 = Vector3.zero.SetAxis(globalAxis, offset); - targetBrushTransforms[brushIndex].position += offset3; - - // Apply new bounds size - Vector3 extents = newBounds.extents; - extents[localAxis] *= scaleVector3[globalAxis]; - newBounds.extents = extents; - - targetBrushBases[brushIndex].SetBounds(newBounds); - } - - - } - else - { + targetBrushBases[brushIndex].SetBounds(newBounds); + } + } + else + { int found = 0; int primaryAxis1 = 0; @@ -1633,9 +1631,9 @@ public void RescaleBrush(Vector3 direction, Vector3 translation) for (int i = 0; i < 3; i++) { - if(!primaryAxis1Local[i].EqualsWithEpsilon(0)) + if (!primaryAxis1Local[i].EqualsWithEpsilon(0)) { - if(primaryAxis1Local[i] < 0) + if (primaryAxis1Local[i] < 0) { flippedB1 = true; } @@ -1644,7 +1642,7 @@ public void RescaleBrush(Vector3 direction, Vector3 translation) } } - if(found > 1) + if (found > 1) { Vector3 primaryAxis2World = primaryTargetBrushTransform.TransformDirection(Vector3.zero.SetAxis(primaryAxis2, 1)); Vector3 primaryAxis2Local = targetBrushTransforms[brushIndex].InverseTransformDirection(primaryAxis2World); @@ -1688,7 +1686,6 @@ public void RescaleBrush(Vector3 direction, Vector3 translation) flippedB = flippedB2; } - Bounds newBounds = targetBrushBases[brushIndex].GetBounds(); // Offset from resizing @@ -1698,7 +1695,7 @@ public void RescaleBrush(Vector3 direction, Vector3 translation) //Debug.Log(sizeInBounds); Vector3 positionOffset; - if(flipped) + if (flipped) { positionOffset = -sizeInBounds * 0.5f * worldOffset; } @@ -1706,7 +1703,6 @@ public void RescaleBrush(Vector3 direction, Vector3 translation) { positionOffset = sizeInBounds * 0.5f * worldOffset; } - // Second offset Vector3 primaryPivotCopy = primaryPivot; @@ -1725,14 +1721,10 @@ public void RescaleBrush(Vector3 direction, Vector3 translation) //VisualDebug.AddPoint(primaryPivotCopy, new Color(0,1,0,0.5f)); - - - Vector3 localPivot = targetBrushTransforms[brushIndex].TransformPoint(newBounds.center); //VisualDebug.AddPoint(localPivot, Color.yellow, 0.1f); - Vector3 localPivotOffset = Vector3.zero.SetAxis(localAxis, newBounds.extents[localAxis]); localPivotOffset = targetBrushTransforms[brushIndex].TransformDirection(localPivotOffset); if (flipped ^ flippedB) @@ -1746,14 +1738,13 @@ public void RescaleBrush(Vector3 direction, Vector3 translation) //VisualDebug.AddPoint(localPivot, Color.blue, 0.3f); - if(!localPivot.EqualsWithEpsilonLower(primaryPivotCopy)) + if (!localPivot.EqualsWithEpsilonLower(primaryPivotCopy)) { Vector3 directionInAxis = Vector3.zero.SetAxis(primaryAxis, direction[primaryAxis]); Vector3 worldDirection = primaryTargetBrushTransform.TransformDirection(directionInAxis); Vector3 worldPositionOffset = scaleVector3[primaryAxis] * (localPivot - primaryPivotCopy) - (localPivot - primaryPivotCopy); worldPositionOffset = worldDirection * Vector3.Dot(worldDirection, worldPositionOffset); positionOffset += worldPositionOffset; - } // Apply the position offsets after they've been calculated @@ -1767,50 +1758,50 @@ public void RescaleBrush(Vector3 direction, Vector3 translation) targetBrushBases[brushIndex].SetBounds(newBounds); } } - } - EditorHelper.SetDirty(targetBrushBases[brushIndex]); - EditorHelper.SetDirty(targetBrushBases[brushIndex].transform); - targetBrushBases[brushIndex].Invalidate(true); - } + } + EditorHelper.SetDirty(targetBrushBases[brushIndex]); + EditorHelper.SetDirty(targetBrushBases[brushIndex].transform); + targetBrushBases[brushIndex].Invalidate(true); + } } - bool GetIsValidToResize() - { + private bool GetIsValidToResize() + { // Check if any of the selected compound brushes are in invalid states - for (int brushIndex = 0; brushIndex < targetBrushBases.Length; brushIndex++) - { - if(targetBrushes[brushIndex] == null) // CompoundBrush - { + for (int brushIndex = 0; brushIndex < targetBrushBases.Length; brushIndex++) + { + if (targetBrushes[brushIndex] == null) // CompoundBrush + { Vector3 forward = targetBrushTransforms[brushIndex].forward; Vector3 up = targetBrushTransforms[brushIndex].up; - + // Transform to local to the primary brush if necessary (local pivot mode) forward = InverseTransformDirection(forward); up = InverseTransformDirection(up); if (forward.GetSetAxisCount() != 1 - || up.GetSetAxisCount() != 1) - { - // Skip any brushes that are not axis aligned - return false; + || up.GetSetAxisCount() != 1) + { + // Skip any brushes that are not axis aligned + return false; } - } - } + } + } - return true; - } + return true; + } - void DrawResizeHandles(SceneView sceneView, Event e) - { - bool isValidToResize = GetIsValidToResize(); + private void DrawResizeHandles(SceneView sceneView, Event e) + { + bool isValidToResize = GetIsValidToResize(); Camera sceneViewCamera = sceneView.camera; Bounds bounds = GetBounds(); - SabreCSGResources.GetGizmoMaterial().SetPass(0); + SabreCSGResources.GetGizmoMaterial().SetPass(0); GL.PushMatrix(); - GL.LoadPixelMatrix(); + GL.LoadPixelMatrix(); GL.Begin(GL.QUADS); @@ -1841,95 +1832,94 @@ void DrawResizeHandles(SceneView sceneView, Event e) } Color color; - if(!isValidToResize) - { - color = Color.grey; - } - else - { - if (resizeHandlePairs[i].ResizeType == ResizeType.EdgeMid) - { - color = Color.white; - } - else - { - color = Color.yellow; - } - } - - // If this point faces away from the camera, then it should reduce the alpha - color.a = 0.5f; - - Vector3 direction; - Vector3 target; - - direction = TransformDirection(resizeHandlePairs[i].point1); - - int handleSize = 8; - if(isAxisAlignedCamera || Vector3.Dot(sceneViewCamera.transform.forward, direction) < 0) - { - color.a = 1f; - handleSize = 8; - } - else - { - color.a = 0.5f; - handleSize = 6; - } - GL.Color(color); - - target = sceneViewCamera.WorldToScreenPoint(TransformPoint(bounds.center + resizeHandlePairs[i].point1.Multiply(bounds.extents))); - - if (target.z > 0) + if (!isValidToResize) + { + color = Color.grey; + } + else + { + if (resizeHandlePairs[i].ResizeType == ResizeType.EdgeMid) + { + color = Color.white; + } + else + { + color = Color.yellow; + } + } + + // If this point faces away from the camera, then it should reduce the alpha + color.a = 0.5f; + + Vector3 direction; + Vector3 target; + + direction = TransformDirection(resizeHandlePairs[i].point1); + + int handleSize = 8; + if (isAxisAlignedCamera || Vector3.Dot(sceneViewCamera.transform.forward, direction) < 0) + { + color.a = 1f; + handleSize = 8; + } + else + { + color.a = 0.5f; + handleSize = 6; + } + GL.Color(color); + + target = sceneViewCamera.WorldToScreenPoint(TransformPoint(bounds.center + resizeHandlePairs[i].point1.Multiply(bounds.extents))); + + if (target.z > 0) { // Make it pixel perfect target = MathHelper.RoundVector3(target); - SabreGraphics.DrawBillboardQuad(target, handleSize, handleSize); - } + SabreGraphics.DrawBillboardQuad(target, handleSize, handleSize); + } - direction = TransformDirection(resizeHandlePairs[i].point2); + direction = TransformDirection(resizeHandlePairs[i].point2); - if(isAxisAlignedCamera || Vector3.Dot(sceneViewCamera.transform.forward, direction) < 0) - { - color.a = 1f; - handleSize = 8; - } - else - { - color.a = 0.5f; - handleSize = 6; - } - GL.Color(color); + if (isAxisAlignedCamera || Vector3.Dot(sceneViewCamera.transform.forward, direction) < 0) + { + color.a = 1f; + handleSize = 8; + } + else + { + color.a = 0.5f; + handleSize = 6; + } + GL.Color(color); - target = sceneViewCamera.WorldToScreenPoint(TransformPoint(bounds.center + resizeHandlePairs[i].point2.Multiply(bounds.extents))); + target = sceneViewCamera.WorldToScreenPoint(TransformPoint(bounds.center + resizeHandlePairs[i].point2.Multiply(bounds.extents))); if (target.z > 0) { // Make it pixel perfect target = MathHelper.RoundVector3(target); - SabreGraphics.DrawBillboardQuad(target, handleSize, handleSize); - } - } + SabreGraphics.DrawBillboardQuad(target, handleSize, handleSize); + } + } GL.End(); Vector2 screenPosition = new Vector2(Screen.width / 2, Screen.height / 2); - // Draw the selected in green if (selectedResizeHandlePair.HasValue) { - SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); + SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); GL.Begin(GL.LINES); GL.Color(Color.green); Vector3 screenPosition1 = sceneViewCamera.WorldToScreenPoint(TransformPoint(bounds.center + selectedResizeHandlePair.Value.point1.Multiply(bounds.extents))); Vector3 screenPosition2 = sceneViewCamera.WorldToScreenPoint(TransformPoint(bounds.center + selectedResizeHandlePair.Value.point2.Multiply(bounds.extents))); - SabreGraphics.DrawScreenLine(screenPosition1, screenPosition2); + SabreGraphics.DrawScreenLine(screenPosition1, screenPosition2); GL.End(); - SabreCSGResources.GetGizmoMaterial().SetPass(0); + SabreCSGResources.GetGizmoMaterial().SetPass(0); GL.Begin(GL.QUADS); GL.Color(Color.green); @@ -1940,13 +1930,12 @@ void DrawResizeHandles(SceneView sceneView, Event e) target = MathHelper.RoundVector3(target); SabreGraphics.DrawBillboardQuad(target, size, size); - size = (selectedResizePointIndex == 1) ? 8 : 6; target = screenPosition2; // Make it pixel perfect target = MathHelper.RoundVector3(target); SabreGraphics.DrawBillboardQuad(target, size, size); - + GL.End(); screenPosition = Vector3.Lerp(screenPosition1, screenPosition2, 0.5f); @@ -1954,8 +1943,7 @@ void DrawResizeHandles(SceneView sceneView, Event e) else if (hoveredResizeHandlePair.HasValue) { Color color = Color.green; - - + SabreCSGResources.GetSelectedBrushDashedAlphaMaterial().SetPass(0); GL.Begin(GL.LINES); @@ -1990,7 +1978,6 @@ void DrawResizeHandles(SceneView sceneView, Event e) target = MathHelper.RoundVector3(target); SabreGraphics.DrawBillboardQuad(target, size, size); - size = (hoveredResizePointIndex == 1) ? 8 : 6; target = screenPosition2; // Make it pixel perfect @@ -2004,12 +1991,12 @@ void DrawResizeHandles(SceneView sceneView, Event e) GL.PopMatrix(); -// GUI.backgroundColor = Color.red; + // GUI.backgroundColor = Color.red; - if (selectedResizeHandlePair.HasValue) - { + if (selectedResizeHandlePair.HasValue) + { // Draw the angle or bounds to let the user know about the current edit operation - GUIStyle style = new GUIStyle(EditorStyles.toolbar); + GUIStyle style = new GUIStyle(EditorStyles.toolbar); if (currentMode != ActiveMode.Rotate) { style.fixedHeight = 28 * 3; @@ -2022,16 +2009,16 @@ void DrawResizeHandles(SceneView sceneView, Event e) style.fontSize = 16; string messageToMeasure; // Construct a separate message that doesn't include rich text markup to accurately measure - if(currentMode != ActiveMode.Rotate) - { + if (currentMode != ActiveMode.Rotate) + { messageToMeasure = ""; - + Vector3 resizeDirection = selectedResizeHandlePair.Value.point1; message = ""; // Construct the rich text message, tagging axes that are being edited as bold for (int i = 0; i < 3; i++) { - if(i > 0) + if (i > 0) { message += "\n"; messageToMeasure += "\n"; @@ -2053,8 +2040,8 @@ void DrawResizeHandles(SceneView sceneView, Event e) } } } - else - { + else + { // Rotation mode populates the message elsewhere messageToMeasure = message; } @@ -2081,45 +2068,55 @@ void DrawResizeHandles(SceneView sceneView, Event e) } } - void TranslateBrushes(Vector3 worldDelta) - { - List rootTransforms = TransformHelper.GetRootSelectionOnly(targetBrushTransforms); - Undo.RecordObjects(rootTransforms.ToArray(), "Move brush(es)"); - - for (int i = 0; i < rootTransforms.Count; i++) - { - targetBrushTransforms[i].position += worldDelta; - } - - for (int brushIndex = 0; brushIndex < targetBrushBases.Length; brushIndex++) - { - EditorHelper.SetDirty(targetBrushBases[brushIndex]); - EditorHelper.SetDirty(targetBrushBases[brushIndex].transform); - targetBrushBases[brushIndex].Invalidate(true); - } - } - - void RotateBrushes(Quaternion rotationDelta, Vector3 sourceWorldPosition) - { - List rootTransforms = TransformHelper.GetRootSelectionOnly(targetBrushTransforms); - Undo.RecordObjects(rootTransforms.ToArray(), "Rotate brush(es)"); - - for (int i = 0; i < rootTransforms.Count; i++) - { - targetBrushTransforms[i].rotation = rotationDelta * rootTransforms[i].rotation; - - Vector3 localPosition = rootTransforms[i].position - sourceWorldPosition; - localPosition = rotationDelta * localPosition; - targetBrushTransforms[i].position = localPosition + sourceWorldPosition; - } - - for (int brushIndex = 0; brushIndex < targetBrushes.Length; brushIndex++) - { - EditorHelper.SetDirty(targetBrushBases[brushIndex]); - EditorHelper.SetDirty(targetBrushBases[brushIndex].transform); - targetBrushBases[brushIndex].Invalidate(true); - } - } + private void TranslateBrushes(Vector3 worldDelta) + { + List rootTransforms = TransformHelper.GetRootSelectionOnly(targetBrushTransforms); + Undo.RecordObjects(rootTransforms.ToArray(), "Move brush(es)"); + + bool didAnyPositionChange = false; + + for (int i = 0; i < rootTransforms.Count; i++) + { + if (worldDelta != Vector3.zero) + { + targetBrushTransforms[i].position += worldDelta; + didAnyPositionChange = true; + } + } + + // the user translated brushes but the grid snapping caused no movement in the scene. + // we return here to prevent rebuilding a bunch of brushes. + if (!didAnyPositionChange) return; + + for (int brushIndex = 0; brushIndex < targetBrushBases.Length; brushIndex++) + { + EditorHelper.SetDirty(targetBrushBases[brushIndex]); + EditorHelper.SetDirty(targetBrushBases[brushIndex].transform); + targetBrushBases[brushIndex].Invalidate(true); + } + } + + private void RotateBrushes(Quaternion rotationDelta, Vector3 sourceWorldPosition) + { + List rootTransforms = TransformHelper.GetRootSelectionOnly(targetBrushTransforms); + Undo.RecordObjects(rootTransforms.ToArray(), "Rotate brush(es)"); + + for (int i = 0; i < rootTransforms.Count; i++) + { + targetBrushTransforms[i].rotation = rotationDelta * rootTransforms[i].rotation; + + Vector3 localPosition = rootTransforms[i].position - sourceWorldPosition; + localPosition = rotationDelta * localPosition; + targetBrushTransforms[i].position = localPosition + sourceWorldPosition; + } + + for (int brushIndex = 0; brushIndex < targetBrushes.Length; brushIndex++) + { + EditorHelper.SetDirty(targetBrushBases[brushIndex]); + EditorHelper.SetDirty(targetBrushBases[brushIndex].transform); + targetBrushBases[brushIndex].Invalidate(true); + } + } /// Finds a vertex at the current mouse position. /// The closest vertex world position. @@ -2136,9 +2133,19 @@ private bool FindClosestVertexAtMousePosition(out Vector3 closestVertexWorldPosi closestVertexWorldPosition = Vector3.zero; float closestDistanceSquare = float.PositiveInfinity; - foreach (PrimitiveBrush brush in targetBrushes) + foreach (BrushBase brush in targetBrushBases) { - Polygon[] polygons = brush.GetPolygons(); + Polygon[] polygons; + + // try getting the polygons depending on the brush type. + if (brush is PrimitiveBrush) + polygons = ((PrimitiveBrush)brush).GetPolygons(); + else if (brush is CompoundBrush) + polygons = ((CompoundBrush)brush).GetPolygons(); + else if (brush is GroupBrush) + polygons = ((GroupBrush)brush).GetPolygons(); + else continue; + for (int i = 0; i < polygons.Length; i++) { Polygon polygon = polygons[i]; @@ -2169,9 +2176,19 @@ private bool FindClosestVertexAtMousePosition(out Vector3 closestVertexWorldPosi closestVertexWorldPosition = Vector3.zero; closestDistanceSquare = float.PositiveInfinity; - foreach (PrimitiveBrush brush in targetBrushes) + foreach (BrushBase brush in targetBrushBases) { - Polygon[] polygons = brush.GetPolygons(); + Polygon[] polygons; + + // try getting the polygons depending on the brush type. + if (brush is PrimitiveBrush) + polygons = ((PrimitiveBrush)brush).GetPolygons(); + else if (brush is CompoundBrush) + polygons = ((CompoundBrush)brush).GetPolygons(); + else if (brush is GroupBrush) + polygons = ((GroupBrush)brush).GetPolygons(); + else continue; + for (int i = 0; i < polygons.Length; i++) { Polygon polygon = polygons[i]; @@ -2231,7 +2248,7 @@ private void OnMessageWindow(int id) // Draw the background GUI.Box(rect, new GUIContent(), EditorStyles.helpBox); - if(isResizeMessage) + if (isResizeMessage) { rect.xMin += 10; } @@ -2247,21 +2264,22 @@ private void OnMessageWindow(int id) } } - public override void ResetTool () - { - SabreMouse.ResetCursor(); - - if(primaryTargetBrushTransform != null) - { - startPosition = primaryTargetBrushTransform.position; - } - } - - public override void Deactivated () - { - // Make sure we get rid of any active custom cursor - SabreMouse.ResetCursor(); - } + public override void ResetTool() + { + SabreMouse.ResetCursor(); + + if (primaryTargetBrushTransform != null) + { + startPosition = primaryTargetBrushTransform.position; + } + } + + public override void Deactivated() + { + // Make sure we get rid of any active custom cursor + SabreMouse.ResetCursor(); + } } } + #endif \ No newline at end of file diff --git a/Scripts/Tools/SurfaceEditor.cs b/Scripts/Tools/SurfaceEditor.cs index 813dc4a7..b8a77170 100755 --- a/Scripts/Tools/SurfaceEditor.cs +++ b/Scripts/Tools/SurfaceEditor.cs @@ -1,4 +1,5 @@ #if UNITY_EDITOR + using System.Collections; using System.Collections.Generic; using System.Linq; @@ -10,171 +11,180 @@ namespace Sabresaurus.SabreCSG { public class SurfaceEditor : Tool { - bool selectHelpersVisible = false; - enum Mode { None, Translate, Rotate, QuickSelect }; - enum AlignDirection { Top, Bottom, Left, Right, Center }; + private bool selectHelpersVisible = false; + + private enum Mode + { None, Translate, Rotate, QuickSelect, FollowLastFace }; + + private enum AlignDirection + { Top, Bottom, Left, Right, Center }; + + private Mode currentMode = Mode.None; + private bool undoRecorded = false; // Used so that when translating or rotating undo is only recorded at the start, not per frame - Mode currentMode = Mode.None; - bool undoRecorded = false; // Used so that when translating or rotating undo is only recorded at the start, not per frame + private List selectedSourcePolygons = new List(); + private Dictionary matchedBrushes = new Dictionary(); - List selectedSourcePolygons = new List(); - Dictionary matchedBrushes = new Dictionary(); + private Polygon lastSelectedPolygon = null; - Polygon lastSelectedPolygon = null; - // The primary polygon being interacted with, this is the polygon that the drag started on - Polygon currentPolygon = null; - float rotationDiameter = 0; + // The primary polygon being interacted with, this is the polygon that the drag started on + private Polygon currentPolygon = null; - // Used so that the MouseUp event knows that it was the end of a drag not the end of a click - bool dragging = false; + private float rotationDiameter = 0; - bool limitToSameMaterial = false; + // Used so that the MouseUp event knows that it was the end of a drag not the end of a click + private bool dragging = false; - Vector3 lastWorldPoint; - Vector3 currentWorldPoint; - bool pointSet = false; + private bool limitToSameMaterial = false; - // Used to preserve movement while snapping - Vector2 totalDelta; - Vector2 appliedDelta; + private Vector3 lastWorldPoint; + private Vector3 currentWorldPoint; + private bool pointSet = false; - // Scale - string scaleAmount = "1"; + // Used to preserve movement while snapping + private Vector2 totalDelta; - string uScaleString = null; - string vScaleString = null; + private Vector2 appliedDelta; - string uOffsetString = null; - string vOffsetString = null; + // Scale + private string scaleAmount = "1"; - // Rotation on UI - float rotationAmount = 0; + private string uScaleString = null; + private string vScaleString = null; - // Used to preserve movement while snapping - float fullDeltaAngle = 0; - float unroundedDeltaAngle = 0; + private string uOffsetString = null; + private string vOffsetString = null; - // Main UI rectangle for this tool's UI - readonly Rect toolbarRect = new Rect(6, 40, 200, 226); + // Rotation on UI + private float rotationAmount = 0; + + // Used to preserve movement while snapping + private float fullDeltaAngle = 0; + + private float unroundedDeltaAngle = 0; + + // Main UI rectangle for this tool's UI + private readonly Rect toolbarRect = new Rect(6, 40, 200, 226); // Used to track what polygons have been previously clicked on, so that the user can cycle click through objects // on the same (or similar) ray cast - List previousHits = new List(); - List lastHitSet = new List(); + private List previousHits = new List(); + + private List lastHitSet = new List(); - Rect alignButtonRect = new Rect(118,110,80,45); + private Rect alignButtonRect = new Rect(118, 110, 80, 45); - Material lastMaterial = null; - Color lastColor = Color.white; + private Material lastMaterial = null; + private Color lastColor = Color.white; - bool copyMaterialHeld = false; + private bool copyMaterialHeld = false; - VertexColorWindow vertexColorWindow = null; + private VertexColorWindow vertexColorWindow = null; // Whether we are actively searching for hidden faces. - bool findingHiddenFaces = false; + private bool findingHiddenFaces = false; // Whether quick select is selecting or deselecting polygons. - enum QuickSelectModes { Additive, Subtractive}; - QuickSelectModes QuickSelectMode = QuickSelectModes.Additive; - - Rect ToolbarRect - { - get - { - Rect rect = new Rect(toolbarRect); - if(selectHelpersVisible) - { - rect.height += 136; - } - return rect; - } - } - - public override void OnSceneGUI(SceneView sceneView, Event e) + private enum QuickSelectModes + { Additive, Subtractive }; + + private QuickSelectModes QuickSelectMode = QuickSelectModes.Additive; + + private Rect ToolbarRect + { + get + { + Rect rect = new Rect(toolbarRect); + if (selectHelpersVisible) + { + rect.height += 152; + } + return rect; + } + } + + public override void OnSceneGUI(SceneView sceneView, Event e) { - base.OnSceneGUI(sceneView, e); // Allow the base logic to calculate first - - // GUI events - OnRepaintGUI(sceneView, e); - - if (e.type == EventType.KeyDown || e.type == EventType.KeyUp) - { - OnKeyAction(sceneView, e); - } - else if (e.type == EventType.Repaint) - { - OnRepaint(sceneView, e); - } - else if(e.type == EventType.MouseMove) - { - SceneView.RepaintAll(); - } - else if(e.type == EventType.MouseDrag) - { - OnMouseDrag(sceneView, e); - } - else if(e.type == EventType.MouseDown - && !EditorHelper.IsMousePositionInInvalidRects(e.mousePosition)) - { - OnMouseDown(sceneView, e); - } - else if(e.type == EventType.MouseUp - && !EditorHelper.IsMousePositionInInvalidRects(e.mousePosition)) - { - OnMouseUp(sceneView, e); - } - else if(e.type == EventType.DragPerform) - { - OnDragPerform(sceneView, e); - } - else if(e.type == EventType.DragUpdated) - { - e.Use(); - } + base.OnSceneGUI(sceneView, e); // Allow the base logic to calculate first + + // GUI events + OnRepaintGUI(sceneView, e); + + if (e.type == EventType.KeyDown || e.type == EventType.KeyUp) + { + OnKeyAction(sceneView, e); + } + else if (e.type == EventType.Repaint) + { + OnRepaint(sceneView, e); + } + else if (e.type == EventType.MouseMove) + { + SceneView.RepaintAll(); + } + else if (e.type == EventType.MouseDrag) + { + OnMouseDrag(sceneView, e); + } + else if (e.type == EventType.MouseDown + && !EditorHelper.IsMousePositionInInvalidRects(e.mousePosition)) + { + OnMouseDown(sceneView, e); + } + else if (e.type == EventType.MouseUp + && !EditorHelper.IsMousePositionInInvalidRects(e.mousePosition)) + { + OnMouseUp(sceneView, e); + } + else if (e.type == EventType.DragPerform) + { + OnDragPerform(sceneView, e); + } + else if (e.type == EventType.DragUpdated) + { + e.Use(); + } } - - void OnMouseDown (SceneView sceneView, Event e) - { - if(e.button != 0 - || (SabreInput.AnyModifiersSet(e) && !(SabreInput.IsModifier(e, EventModifiers.Control) || SabreInput.IsModifier(e, EventModifiers.Shift))) - || CameraPanInProgress - || EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect)) - { - return; - } - - - if(copyMaterialHeld) // Copy material - { - if(!EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect)) - { - Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); - Polygon polygon = csgModel.RaycastBuiltPolygons(ray); - - if(polygon != null) - { - Polygon sourcePolygon = csgModel.GetSourcePolygon(polygon.UniqueIndex); - - if(sourcePolygon != null) - { - if(!matchedBrushes.ContainsKey(sourcePolygon)) - { - matchedBrushes.Add(sourcePolygon, csgModel.FindBrushFromPolygon(sourcePolygon)); - } - - if(sourcePolygon.Material != lastMaterial) - { - ChangePolygonMaterial(sourcePolygon, lastMaterial); - } - ChangePolygonColor(sourcePolygon, lastColor); - } - } - } - } - else // Set currentPolygon for drag operations - { - Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); + + private void OnMouseDown(SceneView sceneView, Event e) + { + if (e.button != 0 + || CameraPanInProgress + || EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect)) + { + return; + } + + if (copyMaterialHeld) // Copy material + { + if (!EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect)) + { + Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); + Polygon polygon = csgModel.RaycastBuiltPolygons(ray); + + if (polygon != null) + { + Polygon sourcePolygon = csgModel.GetSourcePolygon(polygon.UniqueIndex); + + if (sourcePolygon != null) + { + if (!matchedBrushes.ContainsKey(sourcePolygon)) + { + matchedBrushes.Add(sourcePolygon, csgModel.FindBrushFromPolygon(sourcePolygon)); + } + + if (sourcePolygon.Material != lastMaterial) + { + ChangePolygonMaterial(sourcePolygon, lastMaterial); + } + ChangePolygonColor(sourcePolygon, lastColor); + } + } + } + } + else // Set currentPolygon for drag operations + { + Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); // Get all the polygons the ray hits List raycastHits = csgModel.RaycastBuiltPolygonsAll(ray).Select(hit => csgModel.GetSourcePolygon(hit.Polygon.UniqueIndex)).Where(item => item != null).ToList(); @@ -308,6 +318,11 @@ void OnMouseDown (SceneView sceneView, Event e) currentMode = Mode.QuickSelect; } + else if (e.control && e.shift) + { + currentMode = Mode.FollowLastFace; + OnMouseDragFollowLastFace(sceneView, e); + } else { currentMode = Mode.None; @@ -319,243 +334,247 @@ void OnMouseDown (SceneView sceneView, Event e) e.Use(); } } - } - - void OnMouseDrag(SceneView sceneView, Event e) - { - if(e.button != 0 || CameraPanInProgress) - { - return; - } - - // Used so that the MouseUp event knows that it was the end of a drag not the end of a click - dragging = true; - - if (currentMode == Mode.Rotate) - { - OnMouseDragRotate(sceneView, e); - } - else if (currentMode == Mode.Translate) - { - OnMouseDragTranslate(sceneView, e); - } - else if(copyMaterialHeld) // Copy material - { - if(!EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect)) - { - Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); - Polygon polygon = csgModel.RaycastBuiltPolygons(ray); - - if(polygon != null) - { - Polygon sourcePolygon = csgModel.GetSourcePolygon(polygon.UniqueIndex); - - if(sourcePolygon != null) - { - if(!matchedBrushes.ContainsKey(sourcePolygon)) - { - matchedBrushes.Add(sourcePolygon, csgModel.FindBrushFromPolygon(sourcePolygon)); - } - - if(sourcePolygon.Material != lastMaterial) - { - ChangePolygonMaterial(sourcePolygon, lastMaterial); - } - ChangePolygonColor(sourcePolygon, lastColor); - } - } - } - } - else if(currentMode == Mode.QuickSelect) + } + + private void OnMouseDrag(SceneView sceneView, Event e) + { + if (e.button != 0 || CameraPanInProgress) + { + return; + } + + // Used so that the MouseUp event knows that it was the end of a drag not the end of a click + dragging = true; + + if (currentMode == Mode.Rotate) + { + OnMouseDragRotate(sceneView, e); + } + else if (currentMode == Mode.Translate) + { + OnMouseDragTranslate(sceneView, e); + } + else if (copyMaterialHeld) // Copy material + { + if (!EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect)) + { + Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); + Polygon polygon = csgModel.RaycastBuiltPolygons(ray); + + if (polygon != null) + { + Polygon sourcePolygon = csgModel.GetSourcePolygon(polygon.UniqueIndex); + + if (sourcePolygon != null) + { + if (!matchedBrushes.ContainsKey(sourcePolygon)) + { + matchedBrushes.Add(sourcePolygon, csgModel.FindBrushFromPolygon(sourcePolygon)); + } + + if (sourcePolygon.Material != lastMaterial) + { + ChangePolygonMaterial(sourcePolygon, lastMaterial); + } + ChangePolygonColor(sourcePolygon, lastColor); + } + } + } + } + else if (currentMode == Mode.QuickSelect) { OnMouseDragQuickSelect(sceneView, e); } - } + else if (currentMode == Mode.FollowLastFace) + { + OnMouseDragFollowLastFace(sceneView, e); + } + } - void EnsureCurrentPolygonSelected() + private void EnsureCurrentPolygonSelected() { Event e = Event.current; if (currentPolygon != null && !selectedSourcePolygons.Contains(currentPolygon)) { - if(!e.shift && !e.control) + if (!e.shift && !e.control) { ResetSelection(); } selectedSourcePolygons.Add(currentPolygon); - matchedBrushes.Add(currentPolygon, csgModel.FindBrushFromPolygon(currentPolygon)); + if (!matchedBrushes.ContainsKey(currentPolygon)) + matchedBrushes.Add(currentPolygon, csgModel.FindBrushFromPolygon(currentPolygon)); lastSelectedPolygon = currentPolygon; } } - void OnMouseDragTranslate (SceneView sceneView, Event e) - { + private void OnMouseDragTranslate(SceneView sceneView, Event e) + { EnsureCurrentPolygonSelected(); if (currentPolygon != null && matchedBrushes.ContainsKey(currentPolygon)) - { - Transform brushTransform = matchedBrushes[currentPolygon].transform; + { + Transform brushTransform = matchedBrushes[currentPolygon].transform; - Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); + Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); + + Vertex vertex1; + Vertex vertex2; + Vertex vertex3; + // Get the three non-colinear vertices which will give us a valid plane + SurfaceUtility.GetPrimaryPolygonDescribers(currentPolygon, out vertex1, out vertex2, out vertex3); + Plane plane = new Plane(brushTransform.TransformPoint(vertex1.Position), + brushTransform.TransformPoint(vertex2.Position), + brushTransform.TransformPoint(vertex3.Position)); - Vertex vertex1; - Vertex vertex2; - Vertex vertex3; - // Get the three non-colinear vertices which will give us a valid plane - SurfaceUtility.GetPrimaryPolygonDescribers(currentPolygon, out vertex1, out vertex2, out vertex3); - Plane plane = new Plane(brushTransform.TransformPoint(vertex1.Position), - brushTransform.TransformPoint(vertex2.Position), - brushTransform.TransformPoint(vertex3.Position)); + float distance; - float distance; + if (plane.Raycast(ray, out distance)) + { + Vector3 worldPoint = ray.GetPoint(distance); - if(plane.Raycast(ray, out distance)) - { - Vector3 worldPoint = ray.GetPoint(distance); + currentWorldPoint = worldPoint; + Vector3 worldDelta = currentWorldPoint - lastWorldPoint; + pointSet = true; - currentWorldPoint = worldPoint; - Vector3 worldDelta = currentWorldPoint - lastWorldPoint; - pointSet = true; + UVOrientation worldOrientation = SurfaceUtility.GetNorthEastVectors(currentPolygon, brushTransform); - UVOrientation worldOrientation = SurfaceUtility.GetNorthEastVectors(currentPolygon, brushTransform); + Vector3 worldVectorNorth = worldOrientation.NorthVector; + Vector3 worldVectorEast = worldOrientation.EastVector; - Vector3 worldVectorNorth = worldOrientation.NorthVector; - Vector3 worldVectorEast = worldOrientation.EastVector; + // Calculate the change in UV from the world delta + float uvNorthDelta = Vector3.Dot(worldVectorNorth, -worldDelta); + float uvEastDelta = Vector3.Dot(worldVectorEast, -worldDelta); - // Calculate the change in UV from the world delta - float uvNorthDelta = Vector3.Dot(worldVectorNorth, -worldDelta); - float uvEastDelta = Vector3.Dot(worldVectorEast, -worldDelta); + // Discount scale from the translation + float uvNorthScale = 1f / worldOrientation.NorthScale; + float uvEastScale = 1f / worldOrientation.EastScale; - // Discount scale from the translation - float uvNorthScale = 1f / worldOrientation.NorthScale; - float uvEastScale = 1f / worldOrientation.EastScale; + Vector2 uvDelta = new Vector2(uvEastDelta * uvEastScale, uvNorthDelta * uvNorthScale); - Vector2 uvDelta = new Vector2(uvEastDelta * uvEastScale, uvNorthDelta * uvNorthScale); + if (CurrentSettings.PositionSnappingEnabled) + { + totalDelta += uvDelta; - if(CurrentSettings.PositionSnappingEnabled) - { - totalDelta += uvDelta; - - float snapDistance = CurrentSettings.PositionSnapDistance; - - Vector2 roundedTotal = new Vector2(MathHelper.RoundFloat(totalDelta.x, uvEastScale * snapDistance), - MathHelper.RoundFloat(totalDelta.y, uvNorthScale * snapDistance)); - uvDelta = roundedTotal - appliedDelta; - appliedDelta += uvDelta;// - totalDelta; - } + float snapDistance = CurrentSettings.PositionSnapDistance; - bool recordUndo = false; - if(!undoRecorded && uvDelta != Vector2.zero) - { - recordUndo = true; - undoRecorded = true; - } + Vector2 roundedTotal = new Vector2(MathHelper.RoundFloat(totalDelta.x, uvEastScale * snapDistance), + MathHelper.RoundFloat(totalDelta.y, uvNorthScale * snapDistance)); + uvDelta = roundedTotal - appliedDelta; + appliedDelta += uvDelta;// - totalDelta; + } - TransformUVs(UVUtility.TranslateUV, new UVUtility.TransformData(uvDelta,0), recordUndo); + bool recordUndo = false; + if (!undoRecorded && uvDelta != Vector2.zero) + { + recordUndo = true; + undoRecorded = true; + } - lastWorldPoint = currentWorldPoint; + TransformUVs(UVUtility.TranslateUV, new UVUtility.TransformData(uvDelta, 0), recordUndo); - e.Use (); - } - } - } + lastWorldPoint = currentWorldPoint; + e.Use(); + } + } + } - void OnMouseDragRotate(SceneView sceneView, Event e) - { + private void OnMouseDragRotate(SceneView sceneView, Event e) + { EnsureCurrentPolygonSelected(); if (currentPolygon != null && matchedBrushes.ContainsKey(currentPolygon)) - { - Transform brushTransform = matchedBrushes[currentPolygon].transform; - - Vertex vertex1; - Vertex vertex2; - Vertex vertex3; - // Get the three non-colinear vertices which will give us a valid plane - SurfaceUtility.GetPrimaryPolygonDescribers(currentPolygon, out vertex1, out vertex2, out vertex3); - Plane plane = new Plane(brushTransform.TransformPoint(vertex1.Position), - brushTransform.TransformPoint(vertex2.Position), - brushTransform.TransformPoint(vertex3.Position)); - - // Rotation will be around this axis - Vector3 rotationAxis = plane.normal; - // Brush center point - Vector3 centerWorld = brushTransform.TransformPoint(currentPolygon.GetCenterPoint()); - - // Where the mouse was last frame - Vector2 lastPosition = e.mousePosition - e.delta; - // Where the mouse is this frame - Vector2 currentPosition = e.mousePosition; - - Ray lastRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(lastPosition)); - Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); - - float lastRayHit; - float currentRayHit; - - // Find where in the last frame the mouse ray intersected with this polygon's plane - if(plane.Raycast(lastRay, out lastRayHit)) - { - // Find where in the current frame the mouse ray intersected with this polygon's plane - if(plane.Raycast(currentRay, out currentRayHit)) - { - // Find the world points where the rays hit the rotation plane - Vector3 lastRayWorld = lastRay.GetPoint(lastRayHit); - Vector3 currentRayWorld = currentRay.GetPoint(currentRayHit); - - // Find the rotation needed to transform the points on the plane into XY aligned plane - Quaternion cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(rotationAxis)); - - // Subtract the brush's center point so the points are relative to the center of the brush - currentRayWorld -= centerWorld; - lastRayWorld -= centerWorld; - - // Rotate the world points by the cancelling rotation to put them on XY plane - currentRayWorld = cancellingRotation * currentRayWorld; - lastRayWorld = cancellingRotation * lastRayWorld; - - // Because the points have been transformed into XY plane, we can just use atan2 to find the angles - float angle1 = Mathf.Rad2Deg * Mathf.Atan2(currentRayWorld.x, currentRayWorld.y); - float angle2 = Mathf.Rad2Deg * Mathf.Atan2(lastRayWorld.x, lastRayWorld.y); - // Change in angle is simply the new angle minus the last - float deltaAngle = angle2 - angle1; - - // If snapping is enabled, apply snapping to the delta angle - if(CurrentSettings.AngleSnappingEnabled) - { - deltaAngle += unroundedDeltaAngle; - - float roundedAngle = MathHelper.RoundFloat(deltaAngle, CurrentSettings.AngleSnapDistance); - // Store the change in angle that hasn't been applied due to snapping - unroundedDeltaAngle = deltaAngle - roundedAngle; - // Snap out delta angle for the snapped delta - deltaAngle = roundedAngle; - } - fullDeltaAngle += deltaAngle; - - // Undo.RecordObject(targetBrushTransform, "Rotated brush(es)"); - - bool recordUndo = false; - if(!undoRecorded) - { - recordUndo = true; - undoRecorded = true; - } - - // Rotate the UV using the supplied angle - RotateAroundCenter(deltaAngle, recordUndo); - - e.Use(); - } - } - - SabreMouse.SetCursor(MouseCursor.RotateArrow); - } - } - - void OnMouseDragQuickSelect(SceneView sceneView, Event e) + { + Transform brushTransform = matchedBrushes[currentPolygon].transform; + + Vertex vertex1; + Vertex vertex2; + Vertex vertex3; + // Get the three non-colinear vertices which will give us a valid plane + SurfaceUtility.GetPrimaryPolygonDescribers(currentPolygon, out vertex1, out vertex2, out vertex3); + Plane plane = new Plane(brushTransform.TransformPoint(vertex1.Position), + brushTransform.TransformPoint(vertex2.Position), + brushTransform.TransformPoint(vertex3.Position)); + + // Rotation will be around this axis + Vector3 rotationAxis = plane.normal; + // Brush center point + Vector3 centerWorld = brushTransform.TransformPoint(currentPolygon.GetCenterPoint()); + + // Where the mouse was last frame + Vector2 lastPosition = e.mousePosition - e.delta; + // Where the mouse is this frame + Vector2 currentPosition = e.mousePosition; + + Ray lastRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(lastPosition)); + Ray currentRay = Camera.current.ScreenPointToRay(EditorHelper.ConvertMousePointPosition(currentPosition)); + + float lastRayHit; + float currentRayHit; + + // Find where in the last frame the mouse ray intersected with this polygon's plane + if (plane.Raycast(lastRay, out lastRayHit)) + { + // Find where in the current frame the mouse ray intersected with this polygon's plane + if (plane.Raycast(currentRay, out currentRayHit)) + { + // Find the world points where the rays hit the rotation plane + Vector3 lastRayWorld = lastRay.GetPoint(lastRayHit); + Vector3 currentRayWorld = currentRay.GetPoint(currentRayHit); + + // Find the rotation needed to transform the points on the plane into XY aligned plane + Quaternion cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(rotationAxis)); + + // Subtract the brush's center point so the points are relative to the center of the brush + currentRayWorld -= centerWorld; + lastRayWorld -= centerWorld; + + // Rotate the world points by the cancelling rotation to put them on XY plane + currentRayWorld = cancellingRotation * currentRayWorld; + lastRayWorld = cancellingRotation * lastRayWorld; + + // Because the points have been transformed into XY plane, we can just use atan2 to find the angles + float angle1 = Mathf.Rad2Deg * Mathf.Atan2(currentRayWorld.x, currentRayWorld.y); + float angle2 = Mathf.Rad2Deg * Mathf.Atan2(lastRayWorld.x, lastRayWorld.y); + // Change in angle is simply the new angle minus the last + float deltaAngle = angle2 - angle1; + + // If snapping is enabled, apply snapping to the delta angle + if (CurrentSettings.AngleSnappingEnabled) + { + deltaAngle += unroundedDeltaAngle; + + float roundedAngle = MathHelper.RoundFloat(deltaAngle, CurrentSettings.AngleSnapDistance); + // Store the change in angle that hasn't been applied due to snapping + unroundedDeltaAngle = deltaAngle - roundedAngle; + // Snap out delta angle for the snapped delta + deltaAngle = roundedAngle; + } + fullDeltaAngle += deltaAngle; + + // Undo.RecordObject(targetBrushTransform, "Rotated brush(es)"); + + bool recordUndo = false; + if (!undoRecorded) + { + recordUndo = true; + undoRecorded = true; + } + + // Rotate the UV using the supplied angle + RotateAroundCenter(deltaAngle, recordUndo); + + e.Use(); + } + } + + SabreMouse.SetCursor(MouseCursor.RotateArrow); + } + } + + private void OnMouseDragQuickSelect(SceneView sceneView, Event e) { if (!EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect)) { @@ -599,32 +618,56 @@ void OnMouseDragQuickSelect(SceneView sceneView, Event e) e.Use(); } - void OnMouseUp (SceneView sceneView, Event e) - { + private void OnMouseDragFollowLastFace(SceneView sceneView, Event e) + { + if (!EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect)) + { + Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); + Polygon polygon = csgModel.RaycastBuiltPolygons(ray); + + if (polygon != null) + { + Polygon targetPolygon = csgModel.GetSourcePolygon(polygon.UniqueIndex); + + if (targetPolygon != null && targetPolygon != lastSelectedPolygon) + { + if (!matchedBrushes.ContainsKey(targetPolygon)) + matchedBrushes.Add(targetPolygon, csgModel.FindBrushFromPolygon(targetPolygon)); + + FollowLastFace(targetPolygon); + } + } + } + + e.Use(); + } + + private void OnMouseUp(SceneView sceneView, Event e) + { // Normal selection mode - if (e.button == 0 && !CameraPanInProgress - && (!SabreInput.AnyModifiersSet(e) || SabreInput.IsModifier(e, EventModifiers.Control) || SabreInput.IsModifier(e, EventModifiers.Shift)) - && !copyMaterialHeld) - { - currentMode = Mode.None; - undoRecorded = false; - pointSet = false; - SabreMouse.ResetCursor(); - - if(!dragging && !EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect)) - { - Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); + if (e.button == 0 && !CameraPanInProgress + && (!SabreInput.AnyModifiersSet(e) || SabreInput.IsModifier(e, EventModifiers.Control) || SabreInput.IsModifier(e, EventModifiers.Shift) || SabreInput.IsModifier(e, EventModifiers.Control | EventModifiers.Shift)) + && !copyMaterialHeld) + { + currentMode = Mode.None; + undoRecorded = false; + pointSet = false; + SabreMouse.ResetCursor(); + + if (!dragging && !EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect)) + { + Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); // Get all the polygons that the ray hits, sorted from front to back List raycastHits = csgModel.RaycastBuiltPolygonsAll(ray).Select(hit => csgModel.GetSourcePolygon(hit.Polygon.UniqueIndex)).Where(item => item != null).ToList(); // If no modifiers are held, reset selection if (!e.shift && !e.control) - { - currentPolygon = null; - ResetSelection(); - e.Use(); - } + { + currentPolygon = null; + ResetSelection(); + e.Use(); + } // Find the hit polygon Polygon selectedPolygon = null; @@ -680,16 +723,19 @@ void OnMouseUp (SceneView sceneView, Event e) } } - if (selectedPolygon != null) { // If a valid polygon has been selected, make sure it's the most recent in the history previousHits.Remove(selectedPolygon); // Most recent hit previousHits.Insert(0, selectedPolygon); - + + // If holding control and shift, follow last face is used and we don't change anything + if (EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control | EventModifiers.Shift)) + { + } // If holding control, the action counts as selection toggle (if already selected it's removed) - if (EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control)) + else if (EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Control)) { if (selectedSourcePolygons.Contains(selectedPolygon)) { @@ -700,2202 +746,2214 @@ void OnMouseUp (SceneView sceneView, Event e) { selectedSourcePolygons.Add(selectedPolygon); lastSelectedPolygon = selectedPolygon; - matchedBrushes.Add(selectedPolygon, csgModel.FindBrushFromPolygon(selectedPolygon)); + if (!matchedBrushes.ContainsKey(selectedPolygon)) + matchedBrushes.Add(selectedPolygon, csgModel.FindBrushFromPolygon(selectedPolygon)); } } // If holding shift, quick select is used and we don't change anything else if (EnumHelper.IsFlagSet(e.modifiers, EventModifiers.Shift)) { - } else // No modifier pressed, add the polygon to selection { selectedSourcePolygons.Add(selectedPolygon); lastSelectedPolygon = selectedPolygon; - matchedBrushes.Add(selectedPolygon, csgModel.FindBrushFromPolygon(selectedPolygon)); + if (!matchedBrushes.ContainsKey(selectedPolygon)) + matchedBrushes.Add(selectedPolygon, csgModel.FindBrushFromPolygon(selectedPolygon)); } } - // No faces selected, so make sure no objects are selected too - if(selectedSourcePolygons.Count == 0) - { - Selection.activeGameObject = null; - } - } - - dragging = false; - } - else if(e.button == 0 && SabreInput.IsModifier(e, EventModifiers.Shift | EventModifiers.Control)) // Follow last face - { - if(!EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect)) - { - Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); - Polygon polygon = csgModel.RaycastBuiltPolygons(ray); - - if(polygon != null) - { - Polygon targetPolygon = csgModel.GetSourcePolygon(polygon.UniqueIndex); - - if(targetPolygon != null && targetPolygon != lastSelectedPolygon) - { - matchedBrushes.Add(targetPolygon, csgModel.FindBrushFromPolygon(targetPolygon)); - - FollowLastFace(targetPolygon); - } - } - } - } - - } - - void FollowLastFace(Polygon sourceTargetPolygon) - { - // Use UVs on lastSelectedPolygon as a template for targetPolygon - Polygon[] sourceBuiltPolygons = csgModel.BuiltPolygonsByIndex(lastSelectedPolygon.UniqueIndex); - Polygon[] targetBuiltPolygons = csgModel.BuiltPolygonsByIndex(sourceTargetPolygon.UniqueIndex); - - // Walk through all the built polygons from the last face and the newly selected face - for (int sourceIndex = 0; sourceIndex < sourceBuiltPolygons.Length; sourceIndex++) - { - for (int targetIndex = 0; targetIndex < targetBuiltPolygons.Length; targetIndex++) - { - Edge matchedEdge1; - Edge matchedEdge2; - - // Find if any of the two sets of built polygons match - if(EdgeUtility.FindSharedEdge(sourceBuiltPolygons[sourceIndex], targetBuiltPolygons[targetIndex], out matchedEdge1, out matchedEdge2)) - { - Polygon chosenTemplatePolygon = sourceBuiltPolygons[sourceIndex]; - Polygon chosenTargetPolygon = targetBuiltPolygons[targetIndex]; - - Brush brush = csgModel.FindBrushFromPolygon(sourceTargetPolygon); - - Vector3 edge1Vector = (matchedEdge1.Vertex2.Position - matchedEdge1.Vertex1.Position).normalized; - Vector3 sourcePosition = matchedEdge1.Vertex1.Position - Vector3.Cross(edge1Vector, chosenTemplatePolygon.Plane.normal); -// VisualDebug.AddPoint(sourcePosition); - Vector2 sourceUV = GeometryHelper.GetUVForPosition(chosenTemplatePolygon, sourcePosition); - - Vector3 targetPosition1; - Vector3 targetPosition2; - Vector3 targetPosition3; - Vector2 targetUV1; - Vector2 targetUV2; - Vector2 targetUV3; - - if(chosenTemplatePolygon.Vertices.Length == 3 && chosenTargetPolygon.Vertices.Length == 3 - && MathHelper.PlaneEqualsLooser(chosenTemplatePolygon.Plane, chosenTargetPolygon.Plane)) - { - // Special logic for handling two coplanar triangles - targetPosition1 = chosenTargetPolygon.Vertices[0].Position; - targetPosition2 = chosenTargetPolygon.Vertices[1].Position; - targetPosition3 = chosenTargetPolygon.Vertices[2].Position; - - - targetUV1 = chosenTemplatePolygon.Vertices[0].UV; - targetUV2 = chosenTemplatePolygon.Vertices[1].UV; - targetUV3 = chosenTemplatePolygon.Vertices[2].UV; - - Vector2 uvDelta = targetUV1-targetUV2; - targetUV1 += uvDelta; - targetUV2 += uvDelta; - targetUV3 += uvDelta; - } - else - { - targetPosition1 = matchedEdge1.Vertex1.Position; - targetPosition2 = matchedEdge1.Vertex1.Position + (matchedEdge1.Vertex2.Position-matchedEdge1.Vertex1.Position); - targetPosition3 = matchedEdge1.Vertex1.Position - Vector3.Cross(edge1Vector, chosenTargetPolygon.Plane.normal); - - - targetUV1 = matchedEdge1.Vertex1.UV; - targetUV2 = matchedEdge1.Vertex2.UV; - targetUV3 = sourceUV; - } - bool flipY = false; - - float angleBetweenFaces = Vector3.Angle(chosenTemplatePolygon.Plane.normal, chosenTargetPolygon.Plane.normal); - - // Flip Y if there's been a 90 degree angle change - if(angleBetweenFaces >= 89.99f) - { - if(matchedEdge1.Vertex1.UV.y.EqualsWithEpsilon(1) - && matchedEdge1.Vertex2.UV.y.EqualsWithEpsilon(1)) - { - flipY = true; - } - } - - // Update the source polygons - for (int i = 0; i < sourceTargetPolygon.Vertices.Length; i++) - { - Vector3 inputPosition = sourceTargetPolygon.Vertices[i].Position; - inputPosition = brush.transform.TransformPoint(inputPosition); - Vector2 newUV = GeometryHelper.GetUVForPosition(targetPosition1, - targetPosition2, - targetPosition3, - targetUV1, - targetUV2, - targetUV3, - inputPosition); - if(flipY) - { - newUV.y = 1 - newUV.y; - } - sourceTargetPolygon.Vertices[i].UV = newUV; - } - - // Update the cached built polygons, so other operations like Align still work - for (int builtPolygonIndex = 0; builtPolygonIndex < targetBuiltPolygons.Length; builtPolygonIndex++) - { - Polygon builtPolygon = targetBuiltPolygons[builtPolygonIndex]; - for (int vertexIndex = 0; vertexIndex < builtPolygon.Vertices.Length; vertexIndex++) - { - Vector3 position = builtPolygon.Vertices[vertexIndex].Position; - - Vector2 newUV = GeometryHelper.GetUVForPosition(targetPosition1, - targetPosition2, - targetPosition3, - targetUV1, - targetUV2, - targetUV3, - position); - if(flipY) - { - newUV.y = 1 - newUV.y; - } - builtPolygon.Vertices[vertexIndex].UV = newUV; - } - } - - // Update the actual built mesh - PolygonEntry entry = csgModel.GetVisualPolygonEntry(sourceTargetPolygon.UniqueIndex); - - if(PolygonEntry.IsValidAndBuilt(entry)) - { - Vector3[] vertices = entry.BuiltMesh.vertices; - Vector2[] meshUVs = entry.BuiltMesh.uv; - Vector2[] uvs = entry.UV; - - for (int i = 0; i < entry.Positions.Length; i++) - { - Vector3 position = vertices[entry.BuiltVertexOffset + i]; - - Vector2 newUV = GeometryHelper.GetUVForPosition(targetPosition1, - targetPosition2, - targetPosition3, - targetUV1, - targetUV2, - targetUV3, - position); - if(flipY) - { - newUV.y = 1 - newUV.y; - } - - uvs[i] = newUV; - meshUVs[entry.BuiltVertexOffset + i] = newUV; - } - entry.UV = uvs; - entry.BuiltMesh.uv = meshUVs; - EditorHelper.SetDirty(entry.BuiltMesh); - } - - ChangePolygonMaterial(sourceTargetPolygon, lastMaterial); - ChangePolygonColor(sourceTargetPolygon, lastColor); - // Set the last selected polygon to the one we just processed - lastSelectedPolygon = sourceTargetPolygon; - // Update the selection to this polygon - selectedSourcePolygons.Clear(); - selectedSourcePolygons.Add(sourceTargetPolygon); - matchedBrushes.Clear(); - matchedBrushes.Add(sourceTargetPolygon, brush); - - // Inform the brush cache that the polygons have changed, but that a rebuild isn't necessary - brush.RecachePolygons(false); - - // All done, no need to test any more polygons, just return out - return; - } - } - } - } - - float FindAngle(Vertex vertex1, Vertex vertex2, Vertex vertex3, Plane polygonPlane) - { - Vector3 vector1 = vertex1.Position - vertex2.Position; - Vector3 vector2 = vertex1.Position - vertex3.Position; - Quaternion cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(polygonPlane.normal)); - vector1 = cancellingRotation * vector1; - vector2 = cancellingRotation * vector2; - - float angle1 = -Mathf.Atan2(vector1.x, vector1.y) * Mathf.Rad2Deg; - float angle2 = -Mathf.Atan2(vector2.x, vector2.y) * Mathf.Rad2Deg; - return angle1 - angle2; - } - - void OnRepaint (SceneView sceneView, Event e) - { - if(vertexColorWindow != null) - { - vertexColorWindow.Repaint(); - } - - // Start drawing using the relevant material - SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); - - Polygon[] allPolygons; - - // Highlight the polygon the mouse is over unless they are moving the camera, or hovering over UI - if(currentMode == Mode.None - && !CameraPanInProgress - && !EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect) - && (!SabreInput.AnyModifiersSet(e) || SabreInput.IsModifier(e, EventModifiers.Control) || SabreInput.IsModifier(e, EventModifiers.Shift) || SabreInput.IsModifier(e, EventModifiers.Control | EventModifiers.Shift))) - { - Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); - Polygon polygon = csgModel.RaycastBuiltPolygons(ray); - - // Hovered polygon - if(polygon != null) - { - allPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); - SabreGraphics.DrawPolygons(new Color(0,1,0,0.15f), new Color(0,1,0,0.5f), allPolygons); - } - } - - - SabreCSGResources.GetSelectedBrushDashedMaterial().SetPass(0); - // Draw each of the selected polygons - for (int i = 0; i < selectedSourcePolygons.Count; i++) - { - if(selectedSourcePolygons[i] != null) - { - allPolygons = csgModel.BuiltPolygonsByIndex(selectedSourcePolygons[i].UniqueIndex); - SabreGraphics.DrawPolygonsNoOutline(new Color(0,1,0,0.2f), allPolygons); - SabreGraphics.DrawPolygonsOutlineDashed(Color.green, allPolygons); - } - } - - // Draw the rotation gizmo - if(currentMode == Mode.Rotate - && currentPolygon != null - && matchedBrushes.ContainsKey(currentPolygon)) - { - SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); - - Brush brush = matchedBrushes[currentPolygon]; - Transform brushTransform = brush.transform; - - // Polygons are stored in local space, transform the polygon normal into world space - Vector3 normal = brushTransform.TransformDirection(currentPolygon.Plane.normal); - - Vector3 worldCenterPoint = brushTransform.TransformPoint(currentPolygon.GetCenterPoint()); - // Offset the gizmo so it's very slightly above the polygon, to avoid depth fighting - if(brush.Mode == CSGMode.Add) - { - worldCenterPoint += normal * 0.02f; - } - else - { - worldCenterPoint -= normal * 0.02f; - } - - float radius = rotationDiameter * .5f; - - Vector3 initialRotationDirection = 5 * (brushTransform.TransformPoint(currentPolygon.Vertices[1].Position) - brushTransform.TransformPoint(currentPolygon.Vertices[1].Position)).normalized; - - // Draw the actual rotation gizmo - SabreGraphics.DrawRotationCircle(worldCenterPoint, normal, radius, initialRotationDirection); - } - - // If the mouse is down draw a point where the mouse is interacting in world space - if(e.button == 0 && pointSet) - { - Camera sceneViewCamera = sceneView.camera; - - SabreCSGResources.GetVertexMaterial().SetPass (0); - GL.PushMatrix(); - GL.LoadPixelMatrix(); - - GL.Begin(GL.QUADS); - Vector3 target = sceneViewCamera.WorldToScreenPoint(currentWorldPoint); - if(target.z > 0) - { - // Make it pixel perfect - target = MathHelper.RoundVector3(target); - SabreGraphics.DrawBillboardQuad(target, 8, 8); - } - GL.End(); - GL.PopMatrix(); - } + // No faces selected, so make sure no objects are selected too + if (selectedSourcePolygons.Count == 0) + { + Selection.activeGameObject = null; + } + } - // Deselect surfaces that are not hidden during "find hidden surfaces" - if (findingHiddenFaces) + dragging = false; + } + } + + private void FollowLastFace(Polygon sourceTargetPolygon) + { + // Must have selected a polygon. + if (lastSelectedPolygon == null) return; + + // Use UVs on lastSelectedPolygon as a template for targetPolygon + Polygon[] sourceBuiltPolygons = csgModel.BuiltPolygonsByIndex(lastSelectedPolygon.UniqueIndex); + Polygon[] targetBuiltPolygons = csgModel.BuiltPolygonsByIndex(sourceTargetPolygon.UniqueIndex); + + // Walk through all the built polygons from the last face and the newly selected face + for (int sourceIndex = 0; sourceIndex < sourceBuiltPolygons.Length; sourceIndex++) { - List toDeselect = new List(); - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + for (int targetIndex = 0; targetIndex < targetBuiltPolygons.Length; targetIndex++) { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - Brush brush = csgModel.FindBrushFromPolygon(polygon); + Edge matchedEdge1; + Edge matchedEdge2; - if (brush.Mode == CSGMode.Add) + // Find if any of the two sets of built polygons match + if (EdgeUtility.FindSharedEdge(sourceBuiltPolygons[sourceIndex], targetBuiltPolygons[targetIndex], out matchedEdge1, out matchedEdge2)) { - // is the camera on the positive side of the plane? - if (Vector3.Dot(brush.transform.TransformDirection(polygon.Plane.normal), Camera.current.transform.position - brush.transform.TransformPoint(polygon.GetCenterPoint())) > 0) + Polygon chosenTemplatePolygon = sourceBuiltPolygons[sourceIndex]; + Polygon chosenTargetPolygon = targetBuiltPolygons[targetIndex]; + + Brush brush = csgModel.FindBrushFromPolygon(sourceTargetPolygon); + + Vector3 edge1Vector = (matchedEdge1.Vertex2.Position - matchedEdge1.Vertex1.Position).normalized; + Vector3 sourcePosition = matchedEdge1.Vertex1.Position - Vector3.Cross(edge1Vector, chosenTemplatePolygon.Plane.normal); + // VisualDebug.AddPoint(sourcePosition); + Vector2 sourceUV = GeometryHelper.GetUVForPosition(chosenTemplatePolygon, sourcePosition); + + Vector3 targetPosition1; + Vector3 targetPosition2; + Vector3 targetPosition3; + Vector2 targetUV1; + Vector2 targetUV2; + Vector2 targetUV3; + + if (chosenTemplatePolygon.Vertices.Length == 3 && chosenTargetPolygon.Vertices.Length == 3 + && MathHelper.PlaneEqualsLooser(chosenTemplatePolygon.Plane, chosenTargetPolygon.Plane)) { - // deselect polygon. - toDeselect.Add(polygon); + // Special logic for handling two coplanar triangles + targetPosition1 = chosenTargetPolygon.Vertices[0].Position; + targetPosition2 = chosenTargetPolygon.Vertices[1].Position; + targetPosition3 = chosenTargetPolygon.Vertices[2].Position; + + targetUV1 = chosenTemplatePolygon.Vertices[0].UV; + targetUV2 = chosenTemplatePolygon.Vertices[1].UV; + targetUV3 = chosenTemplatePolygon.Vertices[2].UV; + + Vector2 uvDelta = targetUV1 - targetUV2; + targetUV1 += uvDelta; + targetUV2 += uvDelta; + targetUV3 += uvDelta; } - } - else - { - // is the camera on the positive side of the plane? - if (Vector3.Dot(brush.transform.TransformDirection(polygon.Plane.normal), Camera.current.transform.position - brush.transform.TransformPoint(polygon.GetCenterPoint())) < 0) + else { - // deselect polygon. - toDeselect.Add(polygon); + targetPosition1 = matchedEdge1.Vertex1.Position; + targetPosition2 = matchedEdge1.Vertex1.Position + (matchedEdge1.Vertex2.Position - matchedEdge1.Vertex1.Position); + targetPosition3 = matchedEdge1.Vertex1.Position - Vector3.Cross(edge1Vector, chosenTargetPolygon.Plane.normal); + + targetUV1 = matchedEdge1.Vertex1.UV; + targetUV2 = matchedEdge1.Vertex2.UV; + targetUV3 = sourceUV; } - } - } + bool flipY = false; - foreach (Polygon polygon in toDeselect) - { - selectedSourcePolygons.Remove(polygon); - } + float angleBetweenFaces = Vector3.Angle(chosenTemplatePolygon.Plane.normal, chosenTargetPolygon.Plane.normal); - // Recalculate the matched brushes - matchedBrushes.Clear(); + // Flip Y if there's been a 90 degree angle change + if (angleBetweenFaces >= 89.99f) + { + if (matchedEdge1.Vertex1.UV.y.EqualsWithEpsilon(1) + && matchedEdge1.Vertex2.UV.y.EqualsWithEpsilon(1)) + { + flipY = true; + } + } - for (int i = 0; i < selectedSourcePolygons.Count; i++) - { - matchedBrushes.Add(selectedSourcePolygons[i], csgModel.FindBrushFromPolygon(selectedSourcePolygons[i])); - } - } - } + // Update the source polygons + for (int i = 0; i < sourceTargetPolygon.Vertices.Length; i++) + { + Vector3 inputPosition = sourceTargetPolygon.Vertices[i].Position; + inputPosition = brush.transform.TransformPoint(inputPosition); + Vector2 newUV = GeometryHelper.GetUVForPosition(targetPosition1, + targetPosition2, + targetPosition3, + targetUV1, + targetUV2, + targetUV3, + inputPosition); + if (flipY) + { + newUV.y = 1 - newUV.y; + } + sourceTargetPolygon.Vertices[i].UV = newUV; + } + + // Update the cached built polygons, so other operations like Align still work + for (int builtPolygonIndex = 0; builtPolygonIndex < targetBuiltPolygons.Length; builtPolygonIndex++) + { + Polygon builtPolygon = targetBuiltPolygons[builtPolygonIndex]; + for (int vertexIndex = 0; vertexIndex < builtPolygon.Vertices.Length; vertexIndex++) + { + Vector3 position = builtPolygon.Vertices[vertexIndex].Position; + + Vector2 newUV = GeometryHelper.GetUVForPosition(targetPosition1, + targetPosition2, + targetPosition3, + targetUV1, + targetUV2, + targetUV3, + position); + if (flipY) + { + newUV.y = 1 - newUV.y; + } + builtPolygon.Vertices[vertexIndex].UV = newUV; + } + } + + // Update the actual built mesh + PolygonEntry entry = csgModel.GetVisualPolygonEntry(sourceTargetPolygon.UniqueIndex); + + if (PolygonEntry.IsValidAndBuilt(entry)) + { + Vector3[] vertices = entry.BuiltMesh.vertices; + Vector2[] meshUVs = entry.BuiltMesh.uv; + Vector2[] uvs = entry.UV; - void OnDragPerform (SceneView sceneView, Event e) - { - if(DragAndDrop.objectReferences.Length == 1 && DragAndDrop.objectReferences[0] is Material) - { -// if(selectedSourcePolygons.Count > 0) - { - Material material = (Material)DragAndDrop.objectReferences[0]; + for (int i = 0; i < entry.Positions.Length; i++) + { + Vector3 position = vertices[entry.BuiltVertexOffset + i]; + + Vector2 newUV = GeometryHelper.GetUVForPosition(targetPosition1, + targetPosition2, + targetPosition3, + targetUV1, + targetUV2, + targetUV3, + position); + if (flipY) + { + newUV.y = 1 - newUV.y; + } - for (int i = 0; i < selectedSourcePolygons.Count; i++) - { - if(selectedSourcePolygons[i] != null) - { - ChangePolygonMaterial(selectedSourcePolygons[i], material); - } - } - DragAndDrop.AcceptDrag(); - } + uvs[i] = newUV; + meshUVs[entry.BuiltVertexOffset + i] = newUV; + } + entry.UV = uvs; + entry.BuiltMesh.uv = meshUVs; + EditorHelper.SetDirty(entry.BuiltMesh); + } - e.Use(); - } - } + ChangePolygonMaterial(sourceTargetPolygon, lastMaterial); + ChangePolygonColor(sourceTargetPolygon, lastColor); + // Set the last selected polygon to the one we just processed + lastSelectedPolygon = sourceTargetPolygon; + // Update the selection to this polygon + selectedSourcePolygons.Clear(); + selectedSourcePolygons.Add(sourceTargetPolygon); + matchedBrushes.Clear(); + matchedBrushes.Add(sourceTargetPolygon, brush); + + // Inform the brush cache that the polygons have changed, but that a rebuild isn't necessary + brush.RecachePolygons(false); + + // All done, no need to test any more polygons, just return out + return; + } + } + } + } - void OnRepaintGUI(SceneView sceneView, Event e) + private float FindAngle(Vertex vertex1, Vertex vertex2, Vertex vertex3, Plane polygonPlane) { - // Draw UI specific to this editor - GUIStyle toolbar = new GUIStyle(EditorStyles.toolbar); - - // Set the background tint - if(EditorGUIUtility.isProSkin) - { - toolbar.normal.background = SabreCSGResources.HalfBlackTexture; - } - else - { - toolbar.normal.background = SabreCSGResources.HalfWhiteTexture; - } - // Set the style height to match the rectangle (so it stretches instead of tiling) - toolbar.fixedHeight = ToolbarRect.height; - // Draw the actual GUI via a Window - GUILayout.Window(140009, ToolbarRect, OnToolbarGUI, "", toolbar); + Vector3 vector1 = vertex1.Position - vertex2.Position; + Vector3 vector2 = vertex1.Position - vertex3.Position; + Quaternion cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(polygonPlane.normal)); + vector1 = cancellingRotation * vector1; + vector2 = cancellingRotation * vector2; + + float angle1 = -Mathf.Atan2(vector1.x, vector1.y) * Mathf.Rad2Deg; + float angle2 = -Mathf.Atan2(vector2.x, vector2.y) * Mathf.Rad2Deg; + return angle1 - angle2; } - void OnKeyAction(SceneView sceneView, Event e) - { - if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.CopyMaterial))) - { - if(e.type == EventType.KeyDown) - { - copyMaterialHeld = true; - e.Use(); - } - else if (e.type == EventType.KeyUp) - { - copyMaterialHeld = false; - e.Use(); - } - } - } - - void TransformUVs (UVUtility.UVTransformation transformationMethod, UVUtility.TransformData transformData, bool recordUndo) - { - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - - TransformUVs(polygon, transformationMethod, transformData, recordUndo); - } - } - - void TransformUVs (Polygon polygon, - UVUtility.UVTransformation transformationMethod, - UVUtility.TransformData transformData, - bool recordUndo) - { - Brush brush = matchedBrushes[polygon]; - if(recordUndo) - { - Undo.RecordObject(brush, "Transform UVs"); - csgModel.UndoRecordContext("Transform UVs"); - } - - // Update the source polygon, so rebuilding is correct - for (int vertexIndex = 0; vertexIndex < polygon.Vertices.Length; vertexIndex++) - { - Vertex vertex = polygon.Vertices[vertexIndex]; - vertex.UV = transformationMethod(vertex.UV, transformData); -// polygon.Vertices[vertexIndex].UV = transformationMethod(polygon.Vertices[vertexIndex].UV, transformData); - } - - // Update the built polygons in case we need to use them for something else - Polygon[] builtPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); - for (int polygonIndex = 0; polygonIndex < builtPolygons.Length; polygonIndex++) - { - Polygon builtPolygon = builtPolygons[polygonIndex]; - for (int vertexIndex = 0; vertexIndex < builtPolygon.Vertices.Length; vertexIndex++) - { - builtPolygon.Vertices[vertexIndex].UV = transformationMethod(builtPolygon.Vertices[vertexIndex].UV, transformData); - } - } - - - // Update the actual built mesh - PolygonEntry entry = csgModel.GetVisualPolygonEntry(polygon.UniqueIndex); - if(PolygonEntry.IsValidAndBuilt(entry)) - { - if(recordUndo) - { - Undo.RecordObject(entry.BuiltMesh, "Transform UVs"); - } - - - Vector2[] meshUVs = entry.BuiltMesh.uv; - Vector2[] uvs = entry.UV; - for (int vertexIndex = 0; vertexIndex < entry.Positions.Length; vertexIndex++) - { - Vector2 newUV = transformationMethod(uvs[vertexIndex], transformData); - uvs[vertexIndex] = newUV; - meshUVs[entry.BuiltVertexOffset + vertexIndex] = newUV; - } - entry.UV = uvs; - entry.BuiltMesh.uv = meshUVs; - EditorHelper.SetDirty(entry.BuiltMesh); - } - - // Inform the brush cache that the polygons have changed, but that a rebuild isn't necessary - brush.RecachePolygons(false); - EditorHelper.SetDirty(brush as PrimitiveBrush); - } - - void RotateAroundCenter (float rotationAmount, bool recordUndo) - { - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - - Vector2 centerUV = polygon.GetCenterUV(); - - Vector2 uvDelta1 = (polygon.Vertices[2].UV - polygon.Vertices[1].UV).normalized; - // Find the UV delta along an adjacent edge too (so we can detect flipping) - Vector2 uvDelta2 = (polygon.Vertices[0].UV - polygon.Vertices[1].UV).normalized; - - Vector3 uvNormal = Vector3.Cross(uvDelta1,uvDelta2).normalized; - - if(uvNormal.z < 0) - { - TransformUVs(polygon, UVUtility.RotateUV, new UVUtility.TransformData(centerUV,rotationAmount), recordUndo); - } - else // Flip the delta angle for flipped UVs - { - TransformUVs(polygon, UVUtility.RotateUV, new UVUtility.TransformData(centerUV,-rotationAmount), recordUndo); - } - } - } - - public override void OnUndoRedoPerformed () - { - base.OnUndoRedoPerformed (); - - List visualPolygons = csgModel.VisualPolygons; - for (int i = 0; i < visualPolygons.Count; i++) - { - PolygonEntry entry = csgModel.GetVisualPolygonEntry(visualPolygons[i].UniqueIndex); - if(PolygonEntry.IsValidAndBuilt(entry)) - { - Vector2[] meshUVs = entry.BuiltMesh.uv; - Vector2[] uvs = entry.UV; - for (int vertexIndex = 0; vertexIndex < entry.Positions.Length; vertexIndex++) - { - meshUVs[entry.BuiltVertexOffset + vertexIndex] = uvs[vertexIndex]; - } - entry.BuiltMesh.uv = meshUVs; - EditorHelper.SetDirty(entry.BuiltMesh); - } - } - } - - void DrawMaterialBox() - { - bool materialConflict = false; - Material material = null; - - selectedSourcePolygons.RemoveAll(item => item == null); - - if(selectedSourcePolygons.Count > 0) - { - // Set the material to the first polygon's - material = selectedSourcePolygons[0].Material; - // Continue through the rest of the polygons determining if there is a conflict - - for (int i = 1; i < selectedSourcePolygons.Count; i++) - { - // Different materials found - if(selectedSourcePolygons[i].Material != material) - { - materialConflict = true; - } - } - lastMaterial = material; - lastColor = selectedSourcePolygons[0].Vertices[0].Color; - } - - if(material == null) - { - material = CSGModel.GetDefaultMaterial(); - } - -// GUILayout.Label("Mat", SabreGUILayout.GetForeStyle()); - GUILayout.Space(2); - GUILayout.BeginHorizontal(); - Texture2D texture = AssetPreview.GetAssetPreview(material); - if(AssetPreview.IsLoadingAssetPreview(material.GetInstanceID())) - { - // Not loaded yet, so tell the scene view it needs to attempt to paint again - SceneView.RepaintAll(); - } - - Texture secondaryTexture = null; - if(material.HasProperty("_MainTex")) - { - secondaryTexture = material.GetTexture("_MainTex"); // equivalent to .mainTexture - } - - if(secondaryTexture == null) - { - // Couldn't find a main texture, so use the first found texture instead - int propertyCount = ShaderUtil.GetPropertyCount(material.shader); - for (int i = 0; i < propertyCount; i++) - { - if(ShaderUtil.GetPropertyType(material.shader, i) == ShaderUtil.ShaderPropertyType.TexEnv) - { - Texture newTexture = material.GetTexture(ShaderUtil.GetPropertyName(material.shader, i)); - if(newTexture != null) - { - // Ignore normal maps - string assetPath = AssetDatabase.GetAssetPath(newTexture); - TextureImporter importer = TextureImporter.GetAtPath(assetPath) as TextureImporter; + private void OnRepaint(SceneView sceneView, Event e) + { + if (vertexColorWindow != null) + { + vertexColorWindow.Repaint(); + } -#if UNITY_5_5_OR_NEWER - // Unity 5.5 refactored the TextureImporter, requiring slightly different logic - TextureImporterSettings importerSettings = new TextureImporterSettings(); - importer.ReadTextureSettings(importerSettings); - bool isNormalMap = importerSettings.textureType == TextureImporterType.NormalMap; -#else - // Pre Unity 5.5 way of checking if a texture is a normal map - bool isNormalMap = importer.normalmap; -#endif + // Start drawing using the relevant material + SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); - if(!isNormalMap) - { - secondaryTexture = newTexture; - break; - } - } - } - } - } - int width = 64; - GUIStyle style = new GUIStyle(GUI.skin.box); - style.padding = new RectOffset(0,0,0,0); - style.margin = new RectOffset(0,0,0,0); - GUILayout.Box(texture, style, GUILayout.Width(width), GUILayout.Height(width)); - -// GUILayout.Box(secondaryTexture, style, GUILayout.Width(width), GUILayout.Height(width)); - - // Draw again using GL and a custom shader that ignores alpha, only draws texture RGB - if (Event.current.type == EventType.Repaint) - { - Rect rect = GUILayoutUtility.GetLastRect(); - rect.position += new Vector2(rect.width, 0); - Material drawMaterial = SabreCSGResources.GetPreviewMaterial(); - drawMaterial.mainTexture = secondaryTexture; - - if(PlayerSettings.colorSpace == ColorSpace.Linear) - { - drawMaterial.SetFloat("_IsLinear", 1); - } - else - { - drawMaterial.SetFloat("_IsLinear", 0); - } - drawMaterial.SetPass(0); - - GL.PushMatrix(); - - GL.LoadIdentity(); - GL.MultMatrix(GUI.matrix); - GL.Begin(GL.QUADS); - GL.Color(Color.white); - Vector2 position = rect.center; - SabreGraphics.DrawBillboardQuad(position, (int)rect.width, (int)rect.height, false); - GL.End(); - GL.PopMatrix(); - } - - - GUILayout.EndHorizontal(); - - GUILayout.Space(1); - Material newMaterial = null; - - if(materialConflict) - { - material = null; - - EditorGUI.showMixedValue = true; - newMaterial = EditorGUILayout.ObjectField(material, typeof(Material), false, GUILayout.Width(105)) as Material; - EditorGUI.showMixedValue = false; - } - else - { - newMaterial = EditorGUILayout.ObjectField(material, typeof(Material), false, GUILayout.Width(105)) as Material; - } - - - Rect materialFieldRect = GUILayoutUtility.GetLastRect(); - Rect buttonRect = new Rect(materialFieldRect); - buttonRect.xMin = buttonRect.xMax - 15; - buttonRect.xMax += 25; - - if(GUI.Button(buttonRect, "Set", EditorStyles.miniButton)) - { - int controlID = GUIUtility.GetControlID(FocusType.Passive); -// int controlID = GUIUtility.hotControl; - EditorGUIUtility.ShowObjectPicker(material, false, string.Empty, controlID); - } - - if(Event.current.type == EventType.ExecuteCommand) - { - if(Event.current.commandName == "ObjectSelectorUpdated") - { - newMaterial = EditorGUIUtility.GetObjectPickerObject() as Material; - } -// Debug.Log("ExecuteCommand: " + Event.current.commandName); - } - - materialFieldRect.center += ToolbarRect.min; - materialFieldRect.center -= new Vector2(0,EditorStyles.toolbar.fixedHeight); - - if(newMaterial != material) - { - for (int i = 0; i < selectedSourcePolygons.Count; i++) - { - ChangePolygonMaterial(selectedSourcePolygons[i], newMaterial); - } - } - } - - void DrawExcludeBox() - { - bool excludeConflict = false; - bool excludeState = false; - - if(selectedSourcePolygons.Count > 0) - { - // Set the state to the first polygon's - excludeState = selectedSourcePolygons[0].UserExcludeFromFinal; - - // Continue through the rest of the polygons determining if there is a conflict - for (int i = 1; i < selectedSourcePolygons.Count; i++) - { - // Different materials found - if(selectedSourcePolygons[i].UserExcludeFromFinal != excludeState) - { - excludeConflict = true; - excludeState = false; - } - } - } - - GUILayout.BeginHorizontal(GUILayout.Width(50)); - Rect rect = new Rect(72, 48, 60, 15); - bool newExcludeState = SabreGUILayout.ToggleMixed(rect, excludeState, excludeConflict, "Exclude"); - - EditorGUI.showMixedValue = false; // Reset mixed state - GUILayout.EndHorizontal(); - - // Changed exclude state - if(newExcludeState != excludeState) - { - // Loop through all the selected polygons and apply - for (int i = 0; i < selectedSourcePolygons.Count; i++) - { - selectedSourcePolygons[i].UserExcludeFromFinal = newExcludeState; - - if(newExcludeState) - { - UserExcludePolygon(selectedSourcePolygons[i]); - } - else - { - UserIncludePolygon(selectedSourcePolygons[i]); - } - - EditorHelper.SetDirty(matchedBrushes[selectedSourcePolygons[i]]); - // Tell the brush that the polygons have changed but that there's no need to rebuild - matchedBrushes[selectedSourcePolygons[i]].RecachePolygons(false); - } - } - } - - void DrawManualTextBoxes() - { - float? northScale = 1; - float? eastScale = 1; - - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - - Transform brushTransform = matchedBrushes[polygon].transform; - - UVOrientation worldOrientation = SurfaceUtility.GetNorthEastVectors(polygon, brushTransform); - - if(polygonIndex == 0) - { - northScale = worldOrientation.NorthScale; - eastScale = worldOrientation.EastScale; - } - else - { - if(!northScale.HasValue || !northScale.Value.EqualsWithEpsilon(worldOrientation.NorthScale)) - { - northScale = null; - } - - if(!eastScale.HasValue || !eastScale.Value.EqualsWithEpsilon(worldOrientation.EastScale)) - { - eastScale = null; - } - } - } - - Pair uvOffset = SurfaceUtility.GetUVOffset(selectedSourcePolygons); - - float? eastOffset = uvOffset.First; - float? northOffset = uvOffset.Second; - - GUIStyle textFieldStyle1 = SabreGUILayout.GetTextFieldStyle1(); - GUIStyle textFieldStyle2 = SabreGUILayout.GetTextFieldStyle2(); - - - // East Scale (u scale) - Rect rect = new Rect(138, 2, 60, 16); - if(SabreGUILayout.DrawUVField(rect, eastScale, ref uScaleString, "uScaleField", textFieldStyle1)) - { - float newEastScale; - if(float.TryParse(uScaleString, out newEastScale) && newEastScale != 0) - { - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - - float originalEastScale = SurfaceUtility.GetNorthEastVectors(polygon, matchedBrushes[polygon].transform).EastScale; - - TransformUVs(polygon, UVUtility.ScaleUV, new UVUtility.TransformData(new Vector2(newEastScale/originalEastScale,1),0), false); - } - } - } - - // North scale (v scale) - rect = new Rect(138, 17, 60, 16); - if(SabreGUILayout.DrawUVField(rect, northScale, ref vScaleString, "vScaleField", textFieldStyle1)) - { - float newNorthScale; - if(float.TryParse(vScaleString, out newNorthScale) && newNorthScale != 0) - { - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - - float originalNorthScale = SurfaceUtility.GetNorthEastVectors(polygon, matchedBrushes[polygon].transform).NorthScale; - - TransformUVs(polygon, UVUtility.ScaleUV, new UVUtility.TransformData(new Vector2(1, newNorthScale/originalNorthScale),0), true); - } - } - } - - - // North scale (v scale) - rect = new Rect(138, 35, 60, 16); - if(SabreGUILayout.DrawUVField(rect, eastOffset, ref uOffsetString, "uOffsetField", textFieldStyle2)) - { - float newEastOffset; - if(float.TryParse(uOffsetString, out newEastOffset)) - { - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - - float originalEastOffset = SurfaceUtility.GetUVOffset(polygon).x; - - TransformUVs(polygon, UVUtility.TranslateUV, new UVUtility.TransformData(new Vector2(newEastOffset-originalEastOffset,0),0), true); - } - } - } - - rect = new Rect(138, 50, 60, 16); - if(SabreGUILayout.DrawUVField(rect, northOffset, ref vOffsetString, "vOffsetField", textFieldStyle2)) - { - float newNorthOffset; - if(float.TryParse(vOffsetString, out newNorthOffset)) - { - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - - float originalNorthOffset = SurfaceUtility.GetUVOffset(polygon).y; - - TransformUVs(polygon, UVUtility.TranslateUV, new UVUtility.TransformData(new Vector2(0, newNorthOffset-originalNorthOffset),0), true); - } - } - } - } - - public Color GetColor() - { - if(selectedSourcePolygons.Count > 0) - { - return selectedSourcePolygons[0].Vertices[0].Color; - } - else - { - return Color.white; - } - } - - void OnToolbarGUI(int windowID) - { - // Allow the user to change the material on the selected polygons - DrawMaterialBox(); - - // Allow the user to change whether the selected polygons will be excluded from the final mesh - DrawExcludeBox(); - - GUISkin inspectorSkin = SabreGUILayout.GetInspectorSkin(); - - Rect rect = new Rect(138, 68, 60, 18); - - if(GUI.Button(rect, "Color", inspectorSkin.button)) - { - vertexColorWindow = VertexColorWindow.CreateAndShow(csgModel, this); - } - - GUIStyle newStyle = new GUIStyle(EditorStyles.miniButton); - newStyle.padding = new RectOffset(0,0,0,0); - - if(GUI.Button(new Rect(alignButtonRect.xMin,alignButtonRect.yMin,alignButtonRect.width,alignButtonRect.height/3), "▲", newStyle)) - { - Align(AlignDirection.Top); - } - if(GUI.Button(new Rect(alignButtonRect.xMin,alignButtonRect.yMin+alignButtonRect.height/3,alignButtonRect.width/3,alignButtonRect.height/3), "◄", EditorStyles.miniButtonLeft)) - { - Align(AlignDirection.Left); - } - if(GUI.Button(new Rect(alignButtonRect.xMin+alignButtonRect.width/3,alignButtonRect.yMin+alignButtonRect.height/3,alignButtonRect.width/3,alignButtonRect.height/3), "C", EditorStyles.miniButtonMid)) - { - Align(AlignDirection.Center); - } - if(GUI.Button(new Rect(alignButtonRect.xMin+2*alignButtonRect.width/3,alignButtonRect.yMin+alignButtonRect.height/3,alignButtonRect.width/3,alignButtonRect.height/3), "►", EditorStyles.miniButtonRight)) - { - Align(AlignDirection.Right); - } - if(GUI.Button(new Rect(alignButtonRect.xMin,alignButtonRect.yMin+2*alignButtonRect.height/3,alignButtonRect.width,alignButtonRect.height/3), "▼", newStyle)) - { - Align(AlignDirection.Bottom); - } - -// if(GUILayout.Button("Auto UV Local", EditorStyles.miniButton, GUILayout.Width(70))) -// { -// AutoUV(false); -// } - - GUILayout.BeginHorizontal(GUILayout.Width(180)); - - if(GUILayout.Button("Auto UV", EditorStyles.miniButton)) - { - AutoUV(true); - } - - if(GUILayout.Button("Auto Fit", EditorStyles.miniButton)) - { - AutoFit(); - } - - if(GUILayout.Button("Extrude Brush", EditorStyles.miniButton)) - { - if(selectedSourcePolygons.Count > 0) - { - ExtrudeBrushesFromSelection(); - } - } - - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.Width(110)); - - GUILayout.Label("Flip", SabreGUILayout.GetTitleStyle(), GUILayout.Width(25)); - if (GUILayout.Button("X", EditorStyles.miniButtonLeft)) - { - TransformUVs(UVUtility.FlipUVX, new UVUtility.TransformData(Vector2.zero,0), true); - } - if (GUILayout.Button("Y", EditorStyles.miniButtonMid)) - { - TransformUVs(UVUtility.FlipUVY, new UVUtility.TransformData(Vector2.zero,0), true); - } - if (GUILayout.Button("XY", EditorStyles.miniButtonRight)) - { - TransformUVs(UVUtility.FlipUVXY, new UVUtility.TransformData(Vector2.zero,0), true); - } - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.Width(110)); - - GUILayout.Label("Planar", SabreGUILayout.GetTitleStyle(), GUILayout.Width(39)); - - if(GUILayout.Button("X", EditorStyles.miniButtonLeft)) - { - PlanarMap(Vector3.right); - } - - if(GUILayout.Button("Y", EditorStyles.miniButtonMid)) - { - PlanarMap(Vector3.up); - } - - if(GUILayout.Button("Z", EditorStyles.miniButtonRight)) - { - PlanarMap(Vector3.forward); - } - - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.Width(110)); - - if(GUILayout.Button("Flatten", EditorStyles.miniButton)) - { - List brushesToNotify = new List(); - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - Brush brush = matchedBrushes[polygon]; - SurfaceUtility.FacetPolygon(polygon); - - if(!brushesToNotify.Contains(brush)) - { - brushesToNotify.Add(brush); - } - } - - for (int i = 0; i < brushesToNotify.Count; i++) - { - brushesToNotify[i].Invalidate(true); - } - } - if(GUILayout.Button("Smooth", EditorStyles.miniButton)) - { - List brushesToNotify = new List(); - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - Brush brush = matchedBrushes[polygon]; - SurfaceUtility.SmoothPolygon(polygon, brush.GetPolygons()); - - if(!brushesToNotify.Contains(brush)) - { - brushesToNotify.Add(brush); - } - } - - for (int i = 0; i < brushesToNotify.Count; i++) - { - brushesToNotify[i].Invalidate(true); - } - } - GUILayout.EndHorizontal(); -// GUILayout.Space(8); - - GUILayout.BeginHorizontal(GUILayout.Width(180)); - - GUI.SetNextControlName("faceRotateField"); - rotationAmount = EditorGUILayout.FloatField(rotationAmount, GUILayout.Width(40)); - - bool keyboardEnter = Event.current.isKey - && Event.current.keyCode == KeyCode.Return - && Event.current.type == EventType.KeyUp - && GUI.GetNameOfFocusedControl() == "faceRotateField"; - - if(GUILayout.Button("Rotate", EditorStyles.miniButton) || keyboardEnter) - { - RotateAroundCenter(rotationAmount, true); - } - - if (SabreGUILayout.Button("-90", EditorStyles.miniButtonLeft)) - { - RotateAroundCenter(-90, true); - } - if (SabreGUILayout.Button("+90", EditorStyles.miniButtonRight)) - { - RotateAroundCenter(90, true); - } - - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.Width(180)); - - GUI.SetNextControlName("faceScaleField"); - scaleAmount = EditorGUILayout.TextField(scaleAmount, GUILayout.Width(50)); - - keyboardEnter = Event.current.isKey - && Event.current.keyCode == KeyCode.Return - && Event.current.type == EventType.KeyUp - && GUI.GetNameOfFocusedControl() == "faceScaleField"; - - if(GUILayout.Button("Scale", EditorStyles.miniButton) || keyboardEnter) - { - // Try to parse a Vector3 scale from the input string - Vector2 rescaleVector2; - if(StringHelper.TryParseScale(scaleAmount, out rescaleVector2)) - { - // None of the scale components can be zero - if(rescaleVector2.x != 0 && rescaleVector2.y != 0) - { - TransformUVs(UVUtility.ScaleUV, new UVUtility.TransformData(rescaleVector2,0), true); - } - } - } - - if (SabreGUILayout.Button("/ 2", EditorStyles.miniButtonLeft)) - { - TransformUVs(UVUtility.ScaleUV, new UVUtility.TransformData(new Vector2(.5f,.5f),0), true); - } - if (SabreGUILayout.Button("x 2", EditorStyles.miniButtonRight)) - { - TransformUVs(UVUtility.ScaleUV, new UVUtility.TransformData(new Vector2(2f,2f),0), true); - } - - GUILayout.EndHorizontal(); - - DrawManualTextBoxes(); - - - selectHelpersVisible = EditorGUILayout.Foldout(selectHelpersVisible, "Selection Helpers"); - - if(selectHelpersVisible) - { - GUILayout.BeginHorizontal(GUILayout.Width(180)); - - if(GUILayout.Button("All", EditorStyles.miniButton)) - { - SelectAll(); - } - - if(GUILayout.Button("None", EditorStyles.miniButton)) - { - ResetSelection(); - } - - if(GUILayout.Button("Invert", EditorStyles.miniButton)) - { - InvertSelection(); - } - - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.Width(180)); - - if(GUILayout.Button("Excluded", EditorStyles.miniButton)) - { - SelectExcluded(); - } - - if(GUILayout.Button("Same Material", EditorStyles.miniButton)) - { - SelectSameMaterial(); - } - - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(GUILayout.Width(180)); + Polygon[] allPolygons; - if (!findingHiddenFaces) + // Highlight the polygon the mouse is over unless they are moving the camera, or hovering over UI + if (currentMode == Mode.None + && !CameraPanInProgress + && !EditorHelper.IsMousePositionInIMGUIRect(e.mousePosition, ToolbarRect) + && (!SabreInput.AnyModifiersSet(e) || SabreInput.IsModifier(e, EventModifiers.Control) || SabreInput.IsModifier(e, EventModifiers.Shift) || SabreInput.IsModifier(e, EventModifiers.Control | EventModifiers.Shift))) + { + Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); + Polygon polygon = csgModel.RaycastBuiltPolygons(ray); + + // Hovered polygon + if (polygon != null) { - if (GUILayout.Button("Start Finding Hidden Faces", EditorStyles.miniButton)) - { + allPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); + SabreGraphics.DrawPolygons(new Color(0, 1, 0, 0.15f), new Color(0, 1, 0, 0.5f), allPolygons); + } + } + + SabreCSGResources.GetSelectedBrushDashedMaterial().SetPass(0); + // Draw each of the selected polygons + for (int i = 0; i < selectedSourcePolygons.Count; i++) + { + if (selectedSourcePolygons[i] != null) + { + allPolygons = csgModel.BuiltPolygonsByIndex(selectedSourcePolygons[i].UniqueIndex); + SabreGraphics.DrawPolygonsNoOutline(new Color(0, 1, 0, 0.2f), allPolygons); + SabreGraphics.DrawPolygonsOutlineDashed(Color.green, allPolygons); + } + } + + // Draw the rotation gizmo + if (currentMode == Mode.Rotate + && currentPolygon != null + && matchedBrushes.ContainsKey(currentPolygon)) + { + SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); + + Brush brush = matchedBrushes[currentPolygon]; + Transform brushTransform = brush.transform; + + // Polygons are stored in local space, transform the polygon normal into world space + Vector3 normal = brushTransform.TransformDirection(currentPolygon.Plane.normal); + + Vector3 worldCenterPoint = brushTransform.TransformPoint(currentPolygon.GetCenterPoint()); + // Offset the gizmo so it's very slightly above the polygon, to avoid depth fighting + if (brush.Mode == CSGMode.Add) + { + worldCenterPoint += normal * 0.02f; + } + else + { + worldCenterPoint -= normal * 0.02f; + } + + float radius = rotationDiameter * .5f; + + Vector3 initialRotationDirection = 5 * (brushTransform.TransformPoint(currentPolygon.Vertices[1].Position) - brushTransform.TransformPoint(currentPolygon.Vertices[1].Position)).normalized; + + // Draw the actual rotation gizmo + SabreGraphics.DrawRotationCircle(worldCenterPoint, normal, radius, initialRotationDirection); + } + + // If the mouse is down draw a point where the mouse is interacting in world space + if (e.button == 0 && pointSet) + { + Camera sceneViewCamera = sceneView.camera; + + SabreCSGResources.GetVertexMaterial().SetPass(0); + GL.PushMatrix(); + GL.LoadPixelMatrix(); + + GL.Begin(GL.QUADS); + Vector3 target = sceneViewCamera.WorldToScreenPoint(currentWorldPoint); + if (target.z > 0) + { + // Make it pixel perfect + target = MathHelper.RoundVector3(target); + SabreGraphics.DrawBillboardQuad(target, 8, 8); + } + GL.End(); + GL.PopMatrix(); + } + + // Deselect surfaces that are not hidden during "find hidden surfaces" + if (findingHiddenFaces) + { + List toDeselect = new List(); + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + Brush brush = csgModel.FindBrushFromPolygon(polygon); + + if (brush.Mode == CSGMode.Add) + { + // is the camera on the positive side of the plane? + if (Vector3.Dot(brush.transform.TransformDirection(polygon.Plane.normal), Camera.current.transform.position - brush.transform.TransformPoint(polygon.GetCenterPoint())) > 0) + { + // deselect polygon. + toDeselect.Add(polygon); + } + } + else + { + // is the camera on the positive side of the plane? + if (Vector3.Dot(brush.transform.TransformDirection(polygon.Plane.normal), Camera.current.transform.position - brush.transform.TransformPoint(polygon.GetCenterPoint())) < 0) + { + // deselect polygon. + toDeselect.Add(polygon); + } + } + } + + foreach (Polygon polygon in toDeselect) + { + selectedSourcePolygons.Remove(polygon); + } + + // Recalculate the matched brushes + matchedBrushes.Clear(); + + for (int i = 0; i < selectedSourcePolygons.Count; i++) + { + matchedBrushes.Add(selectedSourcePolygons[i], csgModel.FindBrushFromPolygon(selectedSourcePolygons[i])); + } + } + } + + private void OnDragPerform(SceneView sceneView, Event e) + { + if (DragAndDrop.objectReferences.Length == 1 && DragAndDrop.objectReferences[0] is Material) + { + // if(selectedSourcePolygons.Count > 0) + { + Material material = (Material)DragAndDrop.objectReferences[0]; + + for (int i = 0; i < selectedSourcePolygons.Count; i++) + { + if (selectedSourcePolygons[i] != null) + { + ChangePolygonMaterial(selectedSourcePolygons[i], material); + } + } + DragAndDrop.AcceptDrag(); + } + + e.Use(); + } + } + + private void OnRepaintGUI(SceneView sceneView, Event e) + { + // Draw UI specific to this editor + GUIStyle toolbar = new GUIStyle(EditorStyles.toolbar); + + // Set the background tint + if (EditorGUIUtility.isProSkin) + { + toolbar.normal.background = SabreCSGResources.HalfBlackTexture; + } + else + { + toolbar.normal.background = SabreCSGResources.HalfWhiteTexture; + } + // Set the style height to match the rectangle (so it stretches instead of tiling) + toolbar.fixedHeight = ToolbarRect.height; + // Draw the actual GUI via a Window + GUILayout.Window(140009, ToolbarRect, OnToolbarGUI, "", toolbar); + } + + private void OnKeyAction(SceneView sceneView, Event e) + { + if (KeyMappings.EventsMatch(e, Event.KeyboardEvent(KeyMappings.Instance.CopyMaterial))) + { + if (e.type == EventType.KeyDown) + { + copyMaterialHeld = true; + e.Use(); + } + else if (e.type == EventType.KeyUp) + { + copyMaterialHeld = false; + e.Use(); + } + } + } + + private void TransformUVs(UVUtility.UVTransformation transformationMethod, UVUtility.TransformData transformData, bool recordUndo) + { + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + + TransformUVs(polygon, transformationMethod, transformData, recordUndo); + } + } + + private void TransformUVs(Polygon polygon, + UVUtility.UVTransformation transformationMethod, + UVUtility.TransformData transformData, + bool recordUndo) + { + Brush brush = matchedBrushes[polygon]; + if (recordUndo) + { + Undo.RecordObject(brush, "Transform UVs"); + csgModel.UndoRecordContext("Transform UVs"); + } + + // Update the source polygon, so rebuilding is correct + for (int vertexIndex = 0; vertexIndex < polygon.Vertices.Length; vertexIndex++) + { + Vertex vertex = polygon.Vertices[vertexIndex]; + vertex.UV = transformationMethod(vertex.UV, transformData); + // polygon.Vertices[vertexIndex].UV = transformationMethod(polygon.Vertices[vertexIndex].UV, transformData); + } + + // Update the built polygons in case we need to use them for something else + Polygon[] builtPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); + for (int polygonIndex = 0; polygonIndex < builtPolygons.Length; polygonIndex++) + { + Polygon builtPolygon = builtPolygons[polygonIndex]; + for (int vertexIndex = 0; vertexIndex < builtPolygon.Vertices.Length; vertexIndex++) + { + builtPolygon.Vertices[vertexIndex].UV = transformationMethod(builtPolygon.Vertices[vertexIndex].UV, transformData); + } + } + + // Update the actual built mesh + PolygonEntry entry = csgModel.GetVisualPolygonEntry(polygon.UniqueIndex); + if (PolygonEntry.IsValidAndBuilt(entry)) + { + if (recordUndo) + { + Undo.RecordObject(entry.BuiltMesh, "Transform UVs"); + } + + Vector2[] meshUVs = entry.BuiltMesh.uv; + Vector2[] uvs = entry.UV; + for (int vertexIndex = 0; vertexIndex < entry.Positions.Length; vertexIndex++) + { + Vector2 newUV = transformationMethod(uvs[vertexIndex], transformData); + uvs[vertexIndex] = newUV; + meshUVs[entry.BuiltVertexOffset + vertexIndex] = newUV; + } + entry.UV = uvs; + entry.BuiltMesh.uv = meshUVs; + EditorHelper.SetDirty(entry.BuiltMesh); + } + + // Inform the brush cache that the polygons have changed, but that a rebuild isn't necessary + brush.RecachePolygons(false); + EditorHelper.SetDirty(brush as PrimitiveBrush); + } + + private void RotateAroundCenter(float rotationAmount, bool recordUndo) + { + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + + Vector2 centerUV = polygon.GetCenterUV(); + + Vector2 uvDelta1 = (polygon.Vertices[2].UV - polygon.Vertices[1].UV).normalized; + // Find the UV delta along an adjacent edge too (so we can detect flipping) + Vector2 uvDelta2 = (polygon.Vertices[0].UV - polygon.Vertices[1].UV).normalized; + + Vector3 uvNormal = Vector3.Cross(uvDelta1, uvDelta2).normalized; + + if (uvNormal.z < 0) + { + TransformUVs(polygon, UVUtility.RotateUV, new UVUtility.TransformData(centerUV, rotationAmount), recordUndo); + } + else // Flip the delta angle for flipped UVs + { + TransformUVs(polygon, UVUtility.RotateUV, new UVUtility.TransformData(centerUV, -rotationAmount), recordUndo); + } + } + } + + public override void OnUndoRedoPerformed() + { + base.OnUndoRedoPerformed(); + + List visualPolygons = csgModel.VisualPolygons; + for (int i = 0; i < visualPolygons.Count; i++) + { + PolygonEntry entry = csgModel.GetVisualPolygonEntry(visualPolygons[i].UniqueIndex); + if (PolygonEntry.IsValidAndBuilt(entry)) + { + Vector2[] meshUVs = entry.BuiltMesh.uv; + Vector2[] uvs = entry.UV; + for (int vertexIndex = 0; vertexIndex < entry.Positions.Length; vertexIndex++) + { + meshUVs[entry.BuiltVertexOffset + vertexIndex] = uvs[vertexIndex]; + } + entry.BuiltMesh.uv = meshUVs; + EditorHelper.SetDirty(entry.BuiltMesh); + } + } + } + + private void DrawMaterialBox() + { + bool materialConflict = false; + Material material = null; + + selectedSourcePolygons.RemoveAll(item => item == null); + + if (selectedSourcePolygons.Count > 0) + { + // Set the material to the first polygon's + material = selectedSourcePolygons[0].Material; + // Continue through the rest of the polygons determining if there is a conflict + + for (int i = 1; i < selectedSourcePolygons.Count; i++) + { + // Different materials found + if (selectedSourcePolygons[i].Material != material) + { + materialConflict = true; + } + } + lastMaterial = material; + lastColor = selectedSourcePolygons[0].Vertices[0].Color; + } + + if (material == null) + { + material = CSGModel.GetDefaultMaterial(); + } + + // GUILayout.Label("Mat", SabreGUILayout.GetForeStyle()); + GUILayout.Space(2); + GUILayout.BeginHorizontal(); + Texture2D texture = AssetPreview.GetAssetPreview(material); + if (AssetPreview.IsLoadingAssetPreview(material.GetInstanceID())) + { + // Not loaded yet, so tell the scene view it needs to attempt to paint again + SceneView.RepaintAll(); + } + + Texture secondaryTexture = null; + if (material.HasProperty("_MainTex")) + { + secondaryTexture = material.GetTexture("_MainTex"); // equivalent to .mainTexture + } + + if (secondaryTexture == null) + { + // Couldn't find a main texture, so use the first found texture instead + int propertyCount = ShaderUtil.GetPropertyCount(material.shader); + for (int i = 0; i < propertyCount; i++) + { + if (ShaderUtil.GetPropertyType(material.shader, i) == ShaderUtil.ShaderPropertyType.TexEnv) + { + Texture newTexture = material.GetTexture(ShaderUtil.GetPropertyName(material.shader, i)); + if (newTexture != null) + { + // Ignore normal maps + string assetPath = AssetDatabase.GetAssetPath(newTexture); + TextureImporter importer = TextureImporter.GetAtPath(assetPath) as TextureImporter; + +#if UNITY_5_5_OR_NEWER + // Unity 5.5 refactored the TextureImporter, requiring slightly different logic + TextureImporterSettings importerSettings = new TextureImporterSettings(); + importer.ReadTextureSettings(importerSettings); + bool isNormalMap = importerSettings.textureType == TextureImporterType.NormalMap; +#else + // Pre Unity 5.5 way of checking if a texture is a normal map + bool isNormalMap = importer.normalmap; +#endif + + if (!isNormalMap) + { + secondaryTexture = newTexture; + break; + } + } + } + } + } + int width = 64; + GUIStyle style = new GUIStyle(GUI.skin.box); + style.padding = new RectOffset(0, 0, 0, 0); + style.margin = new RectOffset(0, 0, 0, 0); + GUILayout.Box(texture, style, GUILayout.Width(width), GUILayout.Height(width)); + + // GUILayout.Box(secondaryTexture, style, GUILayout.Width(width), GUILayout.Height(width)); + + // Draw again using GL and a custom shader that ignores alpha, only draws texture RGB + if (Event.current.type == EventType.Repaint) + { + Rect rect = GUILayoutUtility.GetLastRect(); + rect.position += new Vector2(rect.width, 0); + Material drawMaterial = SabreCSGResources.GetPreviewMaterial(); + drawMaterial.mainTexture = secondaryTexture; + + if (PlayerSettings.colorSpace == ColorSpace.Linear) + { + drawMaterial.SetFloat("_IsLinear", 1); + } + else + { + drawMaterial.SetFloat("_IsLinear", 0); + } + drawMaterial.SetPass(0); + + GL.PushMatrix(); + + GL.LoadIdentity(); + GL.MultMatrix(GUI.matrix); + GL.Begin(GL.QUADS); + GL.Color(Color.white); + Vector2 position = rect.center; + SabreGraphics.DrawBillboardQuad(position, (int)rect.width, (int)rect.height, false); + GL.End(); + GL.PopMatrix(); + } + + GUILayout.EndHorizontal(); + + GUILayout.Space(1); + Material newMaterial = null; + + if (materialConflict) + { + material = null; + + EditorGUI.showMixedValue = true; + newMaterial = EditorGUILayout.ObjectField(material, typeof(Material), false, GUILayout.Width(105)) as Material; + EditorGUI.showMixedValue = false; + } + else + { + newMaterial = EditorGUILayout.ObjectField(material, typeof(Material), false, GUILayout.Width(105)) as Material; + } + + Rect materialFieldRect = GUILayoutUtility.GetLastRect(); + Rect buttonRect = new Rect(materialFieldRect); + buttonRect.xMin = buttonRect.xMax - 15; + buttonRect.xMax += 25; + + if (GUI.Button(buttonRect, "Set", EditorStyles.miniButton)) + { + int controlID = GUIUtility.GetControlID(FocusType.Passive); + // int controlID = GUIUtility.hotControl; + EditorGUIUtility.ShowObjectPicker(material, false, string.Empty, controlID); + } + + if (Event.current.type == EventType.ExecuteCommand) + { + if (Event.current.commandName == "ObjectSelectorUpdated") + { + newMaterial = EditorGUIUtility.GetObjectPickerObject() as Material; + } + // Debug.Log("ExecuteCommand: " + Event.current.commandName); + } + + materialFieldRect.center += ToolbarRect.min; + materialFieldRect.center -= new Vector2(0, EditorStyles.toolbar.fixedHeight); + + if (newMaterial != material) + { + for (int i = 0; i < selectedSourcePolygons.Count; i++) + { + ChangePolygonMaterial(selectedSourcePolygons[i], newMaterial); + } + } + } + + private void DrawExcludeBox() + { + bool excludeConflict = false; + bool excludeState = false; + + if (selectedSourcePolygons.Count > 0) + { + // Set the state to the first polygon's + excludeState = selectedSourcePolygons[0].UserExcludeFromFinal; + + // Continue through the rest of the polygons determining if there is a conflict + for (int i = 1; i < selectedSourcePolygons.Count; i++) + { + // Different materials found + if (selectedSourcePolygons[i].UserExcludeFromFinal != excludeState) + { + excludeConflict = true; + excludeState = false; + } + } + } + + GUILayout.BeginHorizontal(GUILayout.Width(50)); + Rect rect = new Rect(72, 48, 60, 15); + bool newExcludeState = SabreGUILayout.ToggleMixed(rect, excludeState, excludeConflict, "Exclude"); + + EditorGUI.showMixedValue = false; // Reset mixed state + GUILayout.EndHorizontal(); + + // Changed exclude state + if (newExcludeState != excludeState) + { + // Loop through all the selected polygons and apply + for (int i = 0; i < selectedSourcePolygons.Count; i++) + { + selectedSourcePolygons[i].UserExcludeFromFinal = newExcludeState; + + if (newExcludeState) + { + UserExcludePolygon(selectedSourcePolygons[i]); + } + else + { + UserIncludePolygon(selectedSourcePolygons[i]); + } + + EditorHelper.SetDirty(matchedBrushes[selectedSourcePolygons[i]]); + // Tell the brush that the polygons have changed but that there's no need to rebuild + matchedBrushes[selectedSourcePolygons[i]].RecachePolygons(false); + } + } + } + + private void DrawManualTextBoxes() + { + float? northScale = 1; + float? eastScale = 1; + + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + + Transform brushTransform = matchedBrushes[polygon].transform; + + UVOrientation worldOrientation = SurfaceUtility.GetNorthEastVectors(polygon, brushTransform); + + if (polygonIndex == 0) + { + northScale = worldOrientation.NorthScale; + eastScale = worldOrientation.EastScale; + } + else + { + if (!northScale.HasValue || !northScale.Value.EqualsWithEpsilon(worldOrientation.NorthScale)) + { + northScale = null; + } + + if (!eastScale.HasValue || !eastScale.Value.EqualsWithEpsilon(worldOrientation.EastScale)) + { + eastScale = null; + } + } + } + + Pair uvOffset = SurfaceUtility.GetUVOffset(selectedSourcePolygons); + + float? eastOffset = uvOffset.First; + float? northOffset = uvOffset.Second; + + GUIStyle textFieldStyle1 = SabreGUILayout.GetTextFieldStyle1(); + GUIStyle textFieldStyle2 = SabreGUILayout.GetTextFieldStyle2(); + + // East Scale (u scale) + Rect rect = new Rect(138, 2, 60, 16); + if (SabreGUILayout.DrawUVField(rect, eastScale, ref uScaleString, "uScaleField", textFieldStyle1)) + { + float newEastScale; + if (float.TryParse(uScaleString, out newEastScale) && newEastScale != 0) + { + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + + float originalEastScale = SurfaceUtility.GetNorthEastVectors(polygon, matchedBrushes[polygon].transform).EastScale; + + TransformUVs(polygon, UVUtility.ScaleUV, new UVUtility.TransformData(new Vector2(newEastScale / originalEastScale, 1), 0), false); + } + } + } + + // North scale (v scale) + rect = new Rect(138, 17, 60, 16); + if (SabreGUILayout.DrawUVField(rect, northScale, ref vScaleString, "vScaleField", textFieldStyle1)) + { + float newNorthScale; + if (float.TryParse(vScaleString, out newNorthScale) && newNorthScale != 0) + { + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + + float originalNorthScale = SurfaceUtility.GetNorthEastVectors(polygon, matchedBrushes[polygon].transform).NorthScale; + + TransformUVs(polygon, UVUtility.ScaleUV, new UVUtility.TransformData(new Vector2(1, newNorthScale / originalNorthScale), 0), true); + } + } + } + + // North scale (v scale) + rect = new Rect(138, 35, 60, 16); + if (SabreGUILayout.DrawUVField(rect, eastOffset, ref uOffsetString, "uOffsetField", textFieldStyle2)) + { + float newEastOffset; + if (float.TryParse(uOffsetString, out newEastOffset)) + { + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + + float originalEastOffset = SurfaceUtility.GetUVOffset(polygon).x; + + TransformUVs(polygon, UVUtility.TranslateUV, new UVUtility.TransformData(new Vector2(newEastOffset - originalEastOffset, 0), 0), true); + } + } + } + + rect = new Rect(138, 50, 60, 16); + if (SabreGUILayout.DrawUVField(rect, northOffset, ref vOffsetString, "vOffsetField", textFieldStyle2)) + { + float newNorthOffset; + if (float.TryParse(vOffsetString, out newNorthOffset)) + { + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + + float originalNorthOffset = SurfaceUtility.GetUVOffset(polygon).y; + + TransformUVs(polygon, UVUtility.TranslateUV, new UVUtility.TransformData(new Vector2(0, newNorthOffset - originalNorthOffset), 0), true); + } + } + } + } + + public Color GetColor() + { + if (selectedSourcePolygons.Count > 0) + { + return selectedSourcePolygons[0].Vertices[0].Color; + } + else + { + return Color.white; + } + } + + private void OnToolbarGUI(int windowID) + { + // Allow the user to change the material on the selected polygons + DrawMaterialBox(); + + // Allow the user to change whether the selected polygons will be excluded from the final mesh + DrawExcludeBox(); + + GUISkin inspectorSkin = SabreGUILayout.GetInspectorSkin(); + + Rect rect = new Rect(138, 68, 60, 18); + + if (GUI.Button(rect, "Color", inspectorSkin.button)) + { + vertexColorWindow = VertexColorWindow.CreateAndShow(csgModel, this); + } + + GUIStyle newStyle = new GUIStyle(EditorStyles.miniButton); + newStyle.padding = new RectOffset(0, 0, 0, 0); + + if (GUI.Button(new Rect(alignButtonRect.xMin, alignButtonRect.yMin, alignButtonRect.width, alignButtonRect.height / 3), "▲", newStyle)) + { + Align(AlignDirection.Top); + } + if (GUI.Button(new Rect(alignButtonRect.xMin, alignButtonRect.yMin + alignButtonRect.height / 3, alignButtonRect.width / 3, alignButtonRect.height / 3), "◄", EditorStyles.miniButtonLeft)) + { + Align(AlignDirection.Left); + } + if (GUI.Button(new Rect(alignButtonRect.xMin + alignButtonRect.width / 3, alignButtonRect.yMin + alignButtonRect.height / 3, alignButtonRect.width / 3, alignButtonRect.height / 3), "C", EditorStyles.miniButtonMid)) + { + Align(AlignDirection.Center); + } + if (GUI.Button(new Rect(alignButtonRect.xMin + 2 * alignButtonRect.width / 3, alignButtonRect.yMin + alignButtonRect.height / 3, alignButtonRect.width / 3, alignButtonRect.height / 3), "►", EditorStyles.miniButtonRight)) + { + Align(AlignDirection.Right); + } + if (GUI.Button(new Rect(alignButtonRect.xMin, alignButtonRect.yMin + 2 * alignButtonRect.height / 3, alignButtonRect.width, alignButtonRect.height / 3), "▼", newStyle)) + { + Align(AlignDirection.Bottom); + } + + // if(GUILayout.Button("Auto UV Local", EditorStyles.miniButton, GUILayout.Width(70))) + // { + // AutoUV(false); + // } + + GUILayout.BeginHorizontal(GUILayout.Width(180)); + + if (GUILayout.Button("Auto UV", EditorStyles.miniButton)) + { + AutoUV(true); + } + + if (GUILayout.Button("Auto Fit", EditorStyles.miniButton)) + { + AutoFit(); + } + + if (GUILayout.Button("Extrude Brush", EditorStyles.miniButton)) + { + if (selectedSourcePolygons.Count > 0) + { + ExtrudeBrushesFromSelection(); + } + } + + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.Width(110)); + + GUILayout.Label("Flip", SabreGUILayout.GetTitleStyle(), GUILayout.Width(25)); + if (GUILayout.Button("X", EditorStyles.miniButtonLeft)) + { + TransformUVs(UVUtility.FlipUVX, new UVUtility.TransformData(Vector2.zero, 0), true); + } + if (GUILayout.Button("Y", EditorStyles.miniButtonMid)) + { + TransformUVs(UVUtility.FlipUVY, new UVUtility.TransformData(Vector2.zero, 0), true); + } + if (GUILayout.Button("XY", EditorStyles.miniButtonRight)) + { + TransformUVs(UVUtility.FlipUVXY, new UVUtility.TransformData(Vector2.zero, 0), true); + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.Width(110)); + + GUILayout.Label("Planar", SabreGUILayout.GetTitleStyle(), GUILayout.Width(39)); + + if (GUILayout.Button("X", EditorStyles.miniButtonLeft)) + { + PlanarMap(Vector3.right); + } + + if (GUILayout.Button("Y", EditorStyles.miniButtonMid)) + { + PlanarMap(Vector3.up); + } + + if (GUILayout.Button("Z", EditorStyles.miniButtonRight)) + { + PlanarMap(Vector3.forward); + } + + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.Width(110)); + + if (GUILayout.Button("Flatten", EditorStyles.miniButton)) + { + List brushesToNotify = new List(); + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + Brush brush = matchedBrushes[polygon]; + SurfaceUtility.FacetPolygon(polygon); + + if (!brushesToNotify.Contains(brush)) + { + brushesToNotify.Add(brush); + } + } + + for (int i = 0; i < brushesToNotify.Count; i++) + { + brushesToNotify[i].Invalidate(true); + } + } + if (GUILayout.Button("Smooth", EditorStyles.miniButton)) + { + List brushesToNotify = new List(); + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + Brush brush = matchedBrushes[polygon]; + SurfaceUtility.SmoothPolygon(polygon, brush.GetPolygons()); + + if (!brushesToNotify.Contains(brush)) + { + brushesToNotify.Add(brush); + } + } + + for (int i = 0; i < brushesToNotify.Count; i++) + { + brushesToNotify[i].Invalidate(true); + } + } + GUILayout.EndHorizontal(); + // GUILayout.Space(8); + + GUILayout.BeginHorizontal(GUILayout.Width(180)); + + GUI.SetNextControlName("faceRotateField"); + rotationAmount = EditorGUILayout.FloatField(rotationAmount, GUILayout.Width(40)); + + bool keyboardEnter = Event.current.isKey + && Event.current.keyCode == KeyCode.Return + && Event.current.type == EventType.KeyUp + && GUI.GetNameOfFocusedControl() == "faceRotateField"; + + if (GUILayout.Button("Rotate", EditorStyles.miniButton) || keyboardEnter) + { + RotateAroundCenter(rotationAmount, true); + } + + if (SabreGUILayout.Button("-90", EditorStyles.miniButtonLeft)) + { + RotateAroundCenter(-90, true); + } + if (SabreGUILayout.Button("+90", EditorStyles.miniButtonRight)) + { + RotateAroundCenter(90, true); + } + + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.Width(180)); + + GUI.SetNextControlName("faceScaleField"); + scaleAmount = EditorGUILayout.TextField(scaleAmount, GUILayout.Width(50)); + + keyboardEnter = Event.current.isKey + && Event.current.keyCode == KeyCode.Return + && Event.current.type == EventType.KeyUp + && GUI.GetNameOfFocusedControl() == "faceScaleField"; + + if (GUILayout.Button("Scale", EditorStyles.miniButton) || keyboardEnter) + { + // Try to parse a Vector3 scale from the input string + Vector2 rescaleVector2; + if (StringHelper.TryParseScale(scaleAmount, out rescaleVector2)) + { + // None of the scale components can be zero + if (rescaleVector2.x != 0 && rescaleVector2.y != 0) + { + TransformUVs(UVUtility.ScaleUV, new UVUtility.TransformData(rescaleVector2, 0), true); + } + } + } + + if (SabreGUILayout.Button("/ 2", EditorStyles.miniButtonLeft)) + { + TransformUVs(UVUtility.ScaleUV, new UVUtility.TransformData(new Vector2(.5f, .5f), 0), true); + } + if (SabreGUILayout.Button("x 2", EditorStyles.miniButtonRight)) + { + TransformUVs(UVUtility.ScaleUV, new UVUtility.TransformData(new Vector2(2f, 2f), 0), true); + } + + GUILayout.EndHorizontal(); + + DrawManualTextBoxes(); + + selectHelpersVisible = EditorGUILayout.Foldout(selectHelpersVisible, "Selection Helpers"); + + if (selectHelpersVisible) + { + GUILayout.BeginHorizontal(GUILayout.Width(180)); + + if (GUILayout.Button("All", EditorStyles.miniButton)) + { + SelectAll(); + } + + if (GUILayout.Button("None", EditorStyles.miniButton)) + { + ResetSelection(); + } + + if (GUILayout.Button("Invert", EditorStyles.miniButton)) + { + InvertSelection(); + } + + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.Width(180)); + + if (GUILayout.Button("Excluded", EditorStyles.miniButton)) + { + SelectExcluded(); + } + + if (GUILayout.Button("Same Material", EditorStyles.miniButton)) + { + SelectSameMaterial(); + } + + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.Width(180)); + + if (GUILayout.Button("Same Brush", EditorStyles.miniButton)) + { + SelectSameBrush(); + } + + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(GUILayout.Width(180)); + + if (!findingHiddenFaces) + { + if (GUILayout.Button("Start Finding Hidden Faces", EditorStyles.miniButton)) + { findingHiddenFaces = true; SelectAll(); } } - else + else + { + if (GUILayout.Button("Stop Finding Hidden Faces", EditorStyles.miniButton)) + { + findingHiddenFaces = false; + } + } + + GUILayout.EndHorizontal(); + + GUILayout.Label("Adjacent", SabreGUILayout.GetTitleStyle()); + + GUILayout.BeginHorizontal(GUILayout.Width(180)); + + if (GUILayout.Button("Walls", EditorStyles.miniButtonLeft)) + { + SelectAdjacentWalls(); + } + + if (GUILayout.Button("Floors", EditorStyles.miniButtonMid)) + { + SelectAdjacentFloors(); + } + + if (GUILayout.Button("Ceilings", EditorStyles.miniButtonMid)) + { + SelectAdjacentCeilings(); + } + + if (GUILayout.Button("Coplanar", EditorStyles.miniButtonRight)) + { + SelectAdjacentCoplanar(); + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button("All", EditorStyles.miniButton)) + { + SelectAdjacentAll(); + } + + GUIStyle style = EditorStyles.toggle; + limitToSameMaterial = GUILayout.Toggle(limitToSameMaterial, "Limit to same material", style); + + GUILayout.EndHorizontal(); + + string label = selectedSourcePolygons.Count.ToStringWithSuffix(" selected face", " selected faces"); + GUILayout.Label(label, SabreGUILayout.GetForeStyle()); + } + } + + public override void ResetTool() + { + findingHiddenFaces = false; + } + + public override void OnSelectionChanged() + { + base.OnSelectionChanged(); + + ResetSelection(); + + // Walk through all the selection brushes and select their faces + for (int i = 0; i < Selection.gameObjects.Length; i++) + { + Brush brush = Selection.gameObjects[i].GetComponent(); + if (brush != null) + { + Polygon[] polygons = brush.GetPolygons(); + + for (int j = 0; j < polygons.Length; j++) + { + bool built = (csgModel.BuiltPolygonsByIndex(polygons[j].UniqueIndex).Length > 0); + if (built) + { + selectedSourcePolygons.Add(polygons[j]); + + matchedBrushes.Add(polygons[j], brush); + } + } + } + } + } + + public override void Deactivated() + { + } + + public override bool BrushesHandleDrawing + { + get + { + return false; + } + } + + public override bool PreventBrushSelection + { + get + { + // Can't select brushes in the scene view in the Face tool + return true; + } + } + + private void SelectAll() + { + // Set the selection to all the possible selectable polygons + selectedSourcePolygons = csgModel.GetAllSourcePolygons(); + + // Recalculate the matched brushes + matchedBrushes.Clear(); + + for (int i = 0; i < selectedSourcePolygons.Count; i++) + { + matchedBrushes.Add(selectedSourcePolygons[i], csgModel.FindBrushFromPolygon(selectedSourcePolygons[i])); + } + } + + private void ResetSelection() + { + // Set the selection and matches brushes to empty + selectedSourcePolygons.Clear(); + matchedBrushes.Clear(); + } + + private void InvertSelection() + { + // Construct a list of all polygons that are possible to select + List newList = csgModel.GetAllSourcePolygons(); + + // Remove from that list polygons that are already selected + for (int i = 0; i < selectedSourcePolygons.Count; i++) + { + newList.Remove(selectedSourcePolygons[i]); + } + + // Update the selected list with the new inverted selection + selectedSourcePolygons = newList; + + // Recalculate the matched brushes + matchedBrushes.Clear(); + + for (int i = 0; i < selectedSourcePolygons.Count; i++) + { + matchedBrushes.Add(selectedSourcePolygons[i], csgModel.FindBrushFromPolygon(selectedSourcePolygons[i])); + } + } + + private void SelectExcluded() + { + // Set the selection to all the possible selectable polygons + List allPolygons = csgModel.GetAllSourcePolygons(); + + ResetSelection(); + + for (int i = 0; i < allPolygons.Count; i++) + { + if (allPolygons[i].UserExcludeFromFinal) + { + selectedSourcePolygons.Add(allPolygons[i]); + matchedBrushes.Add(allPolygons[i], csgModel.FindBrushFromPolygon(allPolygons[i])); + } + } + } + + private void SelectSameMaterial() + { + List searchMaterials = selectedSourcePolygons.Select(polygon => polygon.Material).Distinct().ToList(); + + // Set the selection to all the possible selectable polygons + List allPolygons = csgModel.GetAllSourcePolygons(); + + ResetSelection(); + + for (int i = 0; i < allPolygons.Count; i++) + { + if (searchMaterials.Contains(allPolygons[i].Material)) + { + selectedSourcePolygons.Add(allPolygons[i]); + matchedBrushes.Add(allPolygons[i], csgModel.FindBrushFromPolygon(allPolygons[i])); + } + } + } + + private void SelectSameBrush() + { + Dictionary newSelection = new Dictionary(); + + foreach (Polygon selectedPolygon in selectedSourcePolygons) + { + Brush brush = csgModel.FindBrushFromPolygon(selectedPolygon); + if (newSelection.ContainsValue(brush)) continue; + foreach (Polygon brushPolygon in brush.GetPolygons()) + { + bool built = (csgModel.BuiltPolygonsByIndex(brushPolygon.UniqueIndex).Length > 0); + if (!built) continue; + newSelection.Add(brushPolygon, brush); + } + } + + ResetSelection(); + + foreach (var item in newSelection) + { + selectedSourcePolygons.Add(item.Key); + matchedBrushes.Add(item.Key, item.Value); + } + } + + private void SelectAdjacentWalls() + { + AdjacencyFilters.MatchMaterial filter = null; + if (limitToSameMaterial) + { + // Distinct set of materials used by selected polygons + Material[] sourceMaterials = selectedSourcePolygons.Select(polygon => polygon.Material).Distinct().ToArray(); + filter = new AdjacencyFilters.MatchMaterial(sourceMaterials); + } + + List polygonIDs = AdjacencyHelper.FindAdjacentWalls(csgModel.VisualPolygons, selectedSourcePolygons, filter); + + SetSelectionFromPolygonIDs(polygonIDs); + } + + private void SelectAdjacentFloors() + { + AdjacencyFilters.MatchMaterial filter = null; + if (limitToSameMaterial) + { + // Distinct set of materials used by selected polygons + Material[] sourceMaterials = selectedSourcePolygons.Select(polygon => polygon.Material).Distinct().ToArray(); + filter = new AdjacencyFilters.MatchMaterial(sourceMaterials); + } + + List polygonIDs = AdjacencyHelper.FindAdjacentFloors(csgModel.VisualPolygons, selectedSourcePolygons, filter); + + SetSelectionFromPolygonIDs(polygonIDs); + } + + private void SelectAdjacentCeilings() + { + AdjacencyFilters.MatchMaterial filter = null; + if (limitToSameMaterial) + { + // Distinct set of materials used by selected polygons + Material[] sourceMaterials = selectedSourcePolygons.Select(polygon => polygon.Material).Distinct().ToArray(); + filter = new AdjacencyFilters.MatchMaterial(sourceMaterials); + } + + List polygonIDs = AdjacencyHelper.FindAdjacentCeilings(csgModel.VisualPolygons, selectedSourcePolygons, filter); + + SetSelectionFromPolygonIDs(polygonIDs); + } + + private void SelectAdjacentCoplanar() + { + AdjacencyFilters.MatchMaterial filter = null; + if (limitToSameMaterial) + { + // Distinct set of materials used by selected polygons + Material[] sourceMaterials = selectedSourcePolygons.Select(polygon => polygon.Material).Distinct().ToArray(); + filter = new AdjacencyFilters.MatchMaterial(sourceMaterials); + } + + List polygonIDs = AdjacencyHelper.FindAdjacentCoplanar(csgModel.VisualPolygons, selectedSourcePolygons, filter); + + SetSelectionFromPolygonIDs(polygonIDs); + } + + private void SelectAdjacentAll() + { + AdjacencyFilters.MatchMaterial filter = null; + if (limitToSameMaterial) + { + // Distinct set of materials used by selected polygons + Material[] sourceMaterials = selectedSourcePolygons.Select(polygon => polygon.Material).Distinct().ToArray(); + filter = new AdjacencyFilters.MatchMaterial(sourceMaterials); + } + + List polygonIDs = AdjacencyHelper.FindAdjacentAll(csgModel.VisualPolygons, selectedSourcePolygons, filter); + + SetSelectionFromPolygonIDs(polygonIDs); + } + + private void SetSelectionFromPolygonIDs(List polygonIDs) + { + ResetSelection(); + + for (int i = 0; i < polygonIDs.Count; i++) + { + Polygon sourcePolygon = csgModel.GetSourcePolygon(polygonIDs[i]); + selectedSourcePolygons.Add(sourcePolygon); + matchedBrushes.Add(sourcePolygon, csgModel.FindBrushFromPolygon(sourcePolygon)); + } + } + + /// + /// Creates new brushes by extruding the currently selected faces. This method will then + /// select the new brushes. + /// + private void ExtrudeBrushesFromSelection() + { + GameObject[] newObjects = new GameObject[selectedSourcePolygons.Count]; + for (int i = 0; i < selectedSourcePolygons.Count; i++) + { + Quaternion rotation; + Polygon[] polygons; + SurfaceUtility.ExtrudePolygon(selectedSourcePolygons[i], 1, out polygons, out rotation); + + Brush sourceBrush = matchedBrushes[selectedSourcePolygons[i]]; + GameObject newObject = ((PrimitiveBrush)sourceBrush).Duplicate(); + + // if the current brush is part of a compound brush: + if (sourceBrush.transform.parent.GetComponent()) + { + // we can't parent it under the compound brush as that makes no sense to the user (can't be selected individually). + newObject.transform.parent = sourceBrush.transform.parent.parent; + // break the relationship between the brush and the compound brush. + newObject.GetComponent().SetBrushController(null); + } + + newObject.transform.rotation = sourceBrush.transform.rotation * rotation; + // finally give the new brush the other set of polygons. + newObject.GetComponent().SetPolygons(polygons, true); + // give the brush an appropriate auto-generated name. + newObject.name = ""; + newObject.GetComponent().UpdateGeneratedHierarchyName(); + + Undo.RegisterCreatedObjectUndo(newObject, "Extrude Brush"); + + newObjects[i] = newObject; + } + + csgModel.SetCurrentMode(MainMode.Resize); + Selection.objects = newObjects; + } + + private void AutoFit() + { + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + + PolygonEntry entry = csgModel.GetVisualPolygonEntry(polygon.UniqueIndex); + if (PolygonEntry.IsValidAndBuilt(entry)) + { + Brush brush = matchedBrushes[polygon]; + Undo.RecordObject(brush, "Auto Fit"); + csgModel.UndoRecordContext("Auto Fit"); + Undo.RecordObject(entry.BuiltMesh, "Auto Fit"); + Transform brushTransform = brush.transform; + + UVOrientation worldOrientation = SurfaceUtility.GetNorthEastVectors(polygon, brushTransform); + + Vector3 worldVectorNorth = worldOrientation.NorthVector; + Vector3 worldVectorEast = worldOrientation.EastVector; + + Vector3 polygonCenterLocal = polygon.GetCenterPoint(); + Vector3 polygonCenterWorld = brushTransform.TransformPoint(polygonCenterLocal); + + // World vertices + Polygon[] builtPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); + Vertex northernVertex = builtPolygons[0].Vertices[0]; + Vertex southernVertex = builtPolygons[0].Vertices[0]; + Vertex easternVertex = builtPolygons[0].Vertices[0]; + Vertex westernVertex = builtPolygons[0].Vertices[0]; + + for (int builtIndex = 0; builtIndex < builtPolygons.Length; builtIndex++) + { + for (int i = 0; i < builtPolygons[builtIndex].Vertices.Length; i++) + { + Vertex testVertex = builtPolygons[builtIndex].Vertices[i]; + + float dotCurrent = Vector3.Dot(northernVertex.Position - polygonCenterWorld, worldVectorNorth); + float dotTest = Vector3.Dot(testVertex.Position - polygonCenterWorld, worldVectorNorth); + if (dotTest > dotCurrent) + { + northernVertex = testVertex; + } + + dotCurrent = Vector3.Dot(southernVertex.Position - polygonCenterWorld, -worldVectorNorth); + dotTest = Vector3.Dot(testVertex.Position - polygonCenterWorld, -worldVectorNorth); + if (dotTest > dotCurrent) + { + southernVertex = testVertex; + } + + dotCurrent = Vector3.Dot(easternVertex.Position - polygonCenterWorld, worldVectorEast); + dotTest = Vector3.Dot(testVertex.Position - polygonCenterWorld, worldVectorEast); + if (dotTest > dotCurrent) + { + easternVertex = testVertex; + } + + dotCurrent = Vector3.Dot(westernVertex.Position - polygonCenterWorld, -worldVectorEast); + dotTest = Vector3.Dot(testVertex.Position - polygonCenterWorld, -worldVectorEast); + if (dotTest > dotCurrent) + { + westernVertex = testVertex; + } + } + } + + float northernDistance = Vector3.Dot(northernVertex.Position - polygonCenterWorld, worldVectorNorth); + float southernDistance = Vector3.Dot(southernVertex.Position - polygonCenterWorld, worldVectorNorth); + + float easternDistance = Vector3.Dot(easternVertex.Position - polygonCenterWorld, worldVectorEast); + float westernDistance = Vector3.Dot(westernVertex.Position - polygonCenterWorld, worldVectorEast); + + // Update the source polygons + for (int i = 0; i < polygon.Vertices.Length; i++) + { + Vector3 localPosition = polygon.Vertices[i].Position; + Vector3 worldPosition = brushTransform.TransformPoint(localPosition); + + float thisNorthDistance = Vector3.Dot(worldPosition - polygonCenterWorld, worldVectorNorth); + float thisEastDistance = Vector3.Dot(worldPosition - polygonCenterWorld, worldVectorEast); + + Vector2 uv = new Vector2(MathHelper.InverseLerpNoClamp(westernDistance, easternDistance, thisEastDistance), + MathHelper.InverseLerpNoClamp(southernDistance, northernDistance, thisNorthDistance)); + + polygon.Vertices[i].UV = uv; + } + + // Update the built polygons in case we need to use them for something else + for (int builtPolygonIndex = 0; builtPolygonIndex < builtPolygons.Length; builtPolygonIndex++) + { + Polygon builtPolygon = builtPolygons[builtPolygonIndex]; + for (int vertexIndex = 0; vertexIndex < builtPolygon.Vertices.Length; vertexIndex++) + { + Vector3 worldPosition = builtPolygon.Vertices[vertexIndex].Position; + + float thisNorthDistance = Vector3.Dot(worldPosition - polygonCenterWorld, worldVectorNorth); + float thisEastDistance = Vector3.Dot(worldPosition - polygonCenterWorld, worldVectorEast); + + Vector2 uv = new Vector2(MathHelper.InverseLerpNoClamp(westernDistance, easternDistance, thisEastDistance), + MathHelper.InverseLerpNoClamp(southernDistance, northernDistance, thisNorthDistance)); + + builtPolygon.Vertices[vertexIndex].UV = uv; + } + } + + Vector3[] vertices = entry.BuiltMesh.vertices; + + Vector2[] meshUVs = entry.BuiltMesh.uv; + Vector2[] uvs = entry.UV; + + for (int vertexIndex = 0; vertexIndex < entry.Positions.Length; vertexIndex++) + { + Vector3 worldPosition = vertices[entry.BuiltVertexOffset + vertexIndex]; + + float thisNorthDistance = Vector3.Dot(worldPosition - polygonCenterWorld, worldVectorNorth); + float thisEastDistance = Vector3.Dot(worldPosition - polygonCenterWorld, worldVectorEast); + + Vector2 uv = new Vector2(MathHelper.InverseLerpNoClamp(westernDistance, easternDistance, thisEastDistance), + MathHelper.InverseLerpNoClamp(southernDistance, northernDistance, thisNorthDistance)); + + uvs[vertexIndex] = uv; + meshUVs[entry.BuiltVertexOffset + vertexIndex] = uv; + } + entry.UV = uvs; + entry.BuiltMesh.uv = meshUVs; + + EditorHelper.SetDirty(entry.BuiltMesh); + + // Inform the brush cache that the polygons have changed, but that a rebuild isn't necessary + brush.RecachePolygons(false); + } + } + } + + private void AutoUV(bool useWorldSpace) + { + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + + Brush brush = matchedBrushes[polygon]; + Undo.RecordObject(brush, "Auto UV"); + csgModel.UndoRecordContext("Auto UV"); + Transform brushTransform = brush.transform; + + Vector3 planeNormal = polygon.Plane.normal; + if (useWorldSpace) + { + planeNormal = brushTransform.TransformDirection(planeNormal); + } + + Quaternion cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(-planeNormal)); + + // Sets the UV at each point to the position on the plane + for (int i = 0; i < polygon.Vertices.Length; i++) + { + Vector3 position = polygon.Vertices[i].Position; + if (useWorldSpace) + { + position = brushTransform.TransformPoint(position); + } + + Vector2 uv = (cancellingRotation * position) * 0.5f; + polygon.Vertices[i].UV = uv; + } + + Polygon[] builtPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); + + for (int builtPolygonIndex = 0; builtPolygonIndex < builtPolygons.Length; builtPolygonIndex++) { - if (GUILayout.Button("Stop Finding Hidden Faces", EditorStyles.miniButton)) + Polygon builtPolygon = builtPolygons[builtPolygonIndex]; + for (int vertexIndex = 0; vertexIndex < builtPolygon.Vertices.Length; vertexIndex++) { - findingHiddenFaces = false; + Vector3 position = builtPolygon.Vertices[vertexIndex].Position; + + if (!useWorldSpace) + { + position = brushTransform.InverseTransformPoint(position); + } + + Vector2 uv = (cancellingRotation * position) * 0.5f; + builtPolygon.Vertices[vertexIndex].UV = uv; } } - GUILayout.EndHorizontal(); + // Update the actual built mesh - GUILayout.Label("Adjacent", SabreGUILayout.GetTitleStyle()); + PolygonEntry entry = csgModel.GetVisualPolygonEntry(polygon.UniqueIndex); + if (PolygonEntry.IsValidAndBuilt(entry)) + { + Undo.RecordObject(entry.BuiltMesh, "Auto UV"); + Vector3[] vertices = entry.BuiltMesh.vertices; + + Vector2[] meshUVs = entry.BuiltMesh.uv; + Vector2[] uvs = entry.UV; + + for (int vertexIndex = 0; vertexIndex < entry.Positions.Length; vertexIndex++) + { + Vector3 position = vertices[entry.BuiltVertexOffset + vertexIndex]; + if (!useWorldSpace) + { + position = brushTransform.InverseTransformPoint(position); + } - GUILayout.BeginHorizontal(GUILayout.Width(180)); + Vector2 uv = (cancellingRotation * position) * 0.5f; - if(GUILayout.Button("Walls", EditorStyles.miniButtonLeft)) - { - SelectAdjacentWalls(); - } + uvs[vertexIndex] = uv; + meshUVs[entry.BuiltVertexOffset + vertexIndex] = uv; + } + entry.UV = uvs; + entry.BuiltMesh.uv = meshUVs; - if(GUILayout.Button("Floors", EditorStyles.miniButtonMid)) - { - SelectAdjacentFloors(); - } + EditorHelper.SetDirty(entry.BuiltMesh); + } - if(GUILayout.Button("Ceilings", EditorStyles.miniButtonMid)) - { - SelectAdjacentCeilings(); - } + // Inform the brush cache that the polygons have changed, but that a rebuild isn't necessary + brush.RecachePolygons(false); + } + } - if (GUILayout.Button("Coplanar", EditorStyles.miniButtonRight)) + private void PlanarMap(Vector3 planarDirection) + { + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) + { + Polygon polygon = selectedSourcePolygons[polygonIndex]; + + Brush brush = matchedBrushes[polygon]; + Undo.RecordObject(brush, "Planar Map"); + csgModel.UndoRecordContext("Planar Map"); + Transform brushTransform = brush.transform; + + Quaternion cancellingRotation; + if (planarDirection == Vector3.up) { - SelectAdjacentCoplanar(); + cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(-planarDirection, Vector3.right)); + } + else + { + cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(planarDirection)); } - GUILayout.EndHorizontal(); - GUILayout.BeginHorizontal(); + Vector3 planeNormal = polygon.Plane.normal; + planeNormal = brushTransform.TransformDirection(planeNormal); - if (GUILayout.Button("All", EditorStyles.miniButton)) - { - SelectAdjacentAll(); - } + // Skip if the polygon and planar directorions are perpendicular + if (Mathf.Abs(Vector3.Dot(planeNormal, planarDirection)) <= 0.01f) + { + return; + } - GUIStyle style = EditorStyles.toggle; - limitToSameMaterial = GUILayout.Toggle(limitToSameMaterial, "Limit to same material", style); + // Sets the UV at each point to the position on the plane + for (int i = 0; i < polygon.Vertices.Length; i++) + { + Vector3 position = polygon.Vertices[i].Position; + position = brushTransform.TransformPoint(position); - GUILayout.EndHorizontal(); + Vector2 uv = (cancellingRotation * position) * 0.5f; + polygon.Vertices[i].UV = uv; + } - + Polygon[] builtPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); - string label = selectedSourcePolygons.Count.ToStringWithSuffix(" selected face", " selected faces"); - GUILayout.Label(label, SabreGUILayout.GetForeStyle()); - } - } + for (int builtPolygonIndex = 0; builtPolygonIndex < builtPolygons.Length; builtPolygonIndex++) + { + Polygon builtPolygon = builtPolygons[builtPolygonIndex]; + for (int vertexIndex = 0; vertexIndex < builtPolygon.Vertices.Length; vertexIndex++) + { + Vector3 position = builtPolygon.Vertices[vertexIndex].Position; - public override void ResetTool() - { - findingHiddenFaces = false; + Vector2 uv = (cancellingRotation * position) * 0.5f; + builtPolygon.Vertices[vertexIndex].UV = uv; + } + } + + // Update the actual built mesh + + PolygonEntry entry = csgModel.GetVisualPolygonEntry(polygon.UniqueIndex); + if (PolygonEntry.IsValidAndBuilt(entry)) + { + Undo.RecordObject(entry.BuiltMesh, "Planar Map"); + Vector3[] vertices = entry.BuiltMesh.vertices; + + Vector2[] meshUVs = entry.BuiltMesh.uv; + Vector2[] uvs = entry.UV; + + for (int vertexIndex = 0; vertexIndex < entry.Positions.Length; vertexIndex++) + { + Vector3 position = vertices[entry.BuiltVertexOffset + vertexIndex]; + + Vector2 uv = (cancellingRotation * position) * 0.5f; + + uvs[vertexIndex] = uv; + meshUVs[entry.BuiltVertexOffset + vertexIndex] = uv; + } + entry.UV = uvs; + entry.BuiltMesh.uv = meshUVs; + + EditorHelper.SetDirty(entry.BuiltMesh); + } + + // Inform the brush cache that the polygons have changed, but that a rebuild isn't necessary + brush.RecachePolygons(false); + } } - public override void OnSelectionChanged () - { - base.OnSelectionChanged (); - - ResetSelection(); - - // Walk through all the selection brushes and select their faces - for (int i = 0; i < Selection.gameObjects.Length; i++) - { - Brush brush = Selection.gameObjects[i].GetComponent(); - if(brush != null) - { - Polygon[] polygons = brush.GetPolygons(); - - for (int j = 0; j < polygons.Length; j++) - { - bool built = (csgModel.BuiltPolygonsByIndex(polygons[j].UniqueIndex).Length > 0); - if(built) - { - selectedSourcePolygons.Add(polygons[j]); - - matchedBrushes.Add(polygons[j], brush); - } - } - } - } - } - - public override void Deactivated () - { - } - - public override bool BrushesHandleDrawing - { - get - { - return false; - } - } - - public override bool PreventBrushSelection - { - get - { - // Can't select brushes in the scene view in the Face tool - return true; - } - } - - void SelectAll() - { - // Set the selection to all the possible selectable polygons - selectedSourcePolygons = csgModel.GetAllSourcePolygons(); - - // Recalculate the matched brushes - matchedBrushes.Clear(); - - for (int i = 0; i < selectedSourcePolygons.Count; i++) - { - matchedBrushes.Add(selectedSourcePolygons[i], csgModel.FindBrushFromPolygon(selectedSourcePolygons[i])); - } - } - - void ResetSelection() - { - // Set the selection and matches brushes to empty - selectedSourcePolygons.Clear(); - matchedBrushes.Clear(); - } - - void InvertSelection() - { - // Construct a list of all polygons that are possible to select - List newList = csgModel.GetAllSourcePolygons(); - - // Remove from that list polygons that are already selected - for (int i = 0; i < selectedSourcePolygons.Count; i++) - { - newList.Remove(selectedSourcePolygons[i]); - } - - // Update the selected list with the new inverted selection - selectedSourcePolygons = newList; - - // Recalculate the matched brushes - matchedBrushes.Clear(); - - for (int i = 0; i < selectedSourcePolygons.Count; i++) - { - matchedBrushes.Add(selectedSourcePolygons[i], csgModel.FindBrushFromPolygon(selectedSourcePolygons[i])); - } - } - - void SelectExcluded() - { - // Set the selection to all the possible selectable polygons - List allPolygons = csgModel.GetAllSourcePolygons(); - - ResetSelection(); - - for (int i = 0; i < allPolygons.Count; i++) - { - if(allPolygons[i].UserExcludeFromFinal) - { - selectedSourcePolygons.Add(allPolygons[i]); - matchedBrushes.Add(allPolygons[i], csgModel.FindBrushFromPolygon(allPolygons[i])); - } - } - } - - void SelectSameMaterial() - { - List searchMaterials = selectedSourcePolygons.Select(polygon => polygon.Material).Distinct().ToList(); - - // Set the selection to all the possible selectable polygons - List allPolygons = csgModel.GetAllSourcePolygons(); - - ResetSelection(); - - for (int i = 0; i < allPolygons.Count; i++) - { - if(searchMaterials.Contains(allPolygons[i].Material)) - { - selectedSourcePolygons.Add(allPolygons[i]); - matchedBrushes.Add(allPolygons[i], csgModel.FindBrushFromPolygon(allPolygons[i])); - } - } - } - - void SelectAdjacentWalls() - { - AdjacencyFilters.MatchMaterial filter = null; - if (limitToSameMaterial) + private void Align(AlignDirection direction) + { + for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) { - // Distinct set of materials used by selected polygons - Material[] sourceMaterials = selectedSourcePolygons.Select(polygon => polygon.Material).Distinct().ToArray(); - filter = new AdjacencyFilters.MatchMaterial(sourceMaterials); - } + Polygon polygon = selectedSourcePolygons[polygonIndex]; - List polygonIDs = AdjacencyHelper.FindAdjacentWalls(csgModel.VisualPolygons, selectedSourcePolygons, filter); + Transform brushTransform = matchedBrushes[polygon].transform; - SetSelectionFromPolygonIDs(polygonIDs); - } + UVOrientation worldOrientation = SurfaceUtility.GetNorthEastVectors(polygon, brushTransform); - void SelectAdjacentFloors() - { - AdjacencyFilters.MatchMaterial filter = null; - if (limitToSameMaterial) - { - // Distinct set of materials used by selected polygons - Material[] sourceMaterials = selectedSourcePolygons.Select(polygon => polygon.Material).Distinct().ToArray(); - filter = new AdjacencyFilters.MatchMaterial(sourceMaterials); - } + Vector3 worldVectorNorth = worldOrientation.NorthVector; + Vector3 worldVectorEast = worldOrientation.EastVector; - List polygonIDs = AdjacencyHelper.FindAdjacentFloors(csgModel.VisualPolygons, selectedSourcePolygons, filter); + Vector3 polygonCenterLocal = polygon.GetCenterPoint(); + Vector3 polygonCenterWorld = brushTransform.TransformPoint(polygonCenterLocal); - SetSelectionFromPolygonIDs(polygonIDs); - } + // World vertices + Polygon[] builtPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); + Vertex northernVertex = builtPolygons[0].Vertices[0]; + Vertex southernVertex = builtPolygons[0].Vertices[0]; + Vertex easternVertex = builtPolygons[0].Vertices[0]; + Vertex westernVertex = builtPolygons[0].Vertices[0]; - void SelectAdjacentCeilings() - { - AdjacencyFilters.MatchMaterial filter = null; - if (limitToSameMaterial) + for (int builtIndex = 0; builtIndex < builtPolygons.Length; builtIndex++) + { + for (int i = 0; i < builtPolygons[builtIndex].Vertices.Length; i++) + { + Vertex testVertex = builtPolygons[builtIndex].Vertices[i]; + + float dotCurrent = Vector3.Dot(northernVertex.Position - polygonCenterWorld, worldVectorNorth); + float dotTest = Vector3.Dot(testVertex.Position - polygonCenterWorld, worldVectorNorth); + if (dotTest > dotCurrent) + { + northernVertex = testVertex; + } + + dotCurrent = Vector3.Dot(southernVertex.Position - polygonCenterWorld, -worldVectorNorth); + dotTest = Vector3.Dot(testVertex.Position - polygonCenterWorld, -worldVectorNorth); + if (dotTest > dotCurrent) + { + southernVertex = testVertex; + } + + dotCurrent = Vector3.Dot(easternVertex.Position - polygonCenterWorld, worldVectorEast); + dotTest = Vector3.Dot(testVertex.Position - polygonCenterWorld, worldVectorEast); + if (dotTest > dotCurrent) + { + easternVertex = testVertex; + } + + dotCurrent = Vector3.Dot(westernVertex.Position - polygonCenterWorld, -worldVectorEast); + dotTest = Vector3.Dot(testVertex.Position - polygonCenterWorld, -worldVectorEast); + if (dotTest > dotCurrent) + { + westernVertex = testVertex; + } + } + } + + Vector2 offset = new Vector2(0, 0); + + if (direction == AlignDirection.Top) + { + offset.y = 1 - northernVertex.UV.y; + } + else if (direction == AlignDirection.Bottom) + { + offset.y = 0 - southernVertex.UV.y; + } + else if (direction == AlignDirection.Left) + { + offset.x = 0 - westernVertex.UV.x; + } + else if (direction == AlignDirection.Right) + { + offset.x = 1 - easternVertex.UV.x; + } + else if (direction == AlignDirection.Center) + { + offset.x = (0 - westernVertex.UV.x + 1 - easternVertex.UV.x) * .5f; + offset.y = (1 - northernVertex.UV.y + 0 - southernVertex.UV.y) * .5f; + } + + TransformUVs(polygon, UVUtility.TranslateUV, new UVUtility.TransformData(offset, 0), true); + } + } + + private void UserExcludePolygon(Polygon sourcePolygon) + { + Polygon[] builtRenderPolygons = csgModel.BuiltPolygonsByIndex(sourcePolygon.UniqueIndex); + + foreach (Polygon polygon in builtRenderPolygons) { - // Distinct set of materials used by selected polygons - Material[] sourceMaterials = selectedSourcePolygons.Select(polygon => polygon.Material).Distinct().ToArray(); - filter = new AdjacencyFilters.MatchMaterial(sourceMaterials); + polygon.UserExcludeFromFinal = true; } - List polygonIDs = AdjacencyHelper.FindAdjacentCeilings(csgModel.VisualPolygons, selectedSourcePolygons, filter); + // Polygon[] builtCollisionPolygons = csgModel.BuiltCollisionPolygonsByIndex(sourcePolygon.UniqueIndex); + // + // foreach (Polygon polygon in builtCollisionPolygons) + // { + // polygon.UserExcludeFromFinal = true; + // } - SetSelectionFromPolygonIDs(polygonIDs); - } + RemoveAndUpdateMesh(csgModel.GetVisualPolygonEntry(sourcePolygon.UniqueIndex), sourcePolygon); + RemoveAndUpdateMesh(csgModel.GetCollisionPolygonEntry(sourcePolygon.UniqueIndex), sourcePolygon); - void SelectAdjacentCoplanar() + // Mesh colliders need to be refreshed now that their collision meshes have changed + csgModel.RefreshMeshGroup(); + + csgModel.SetContextDirty(); + } + + private void UserIncludePolygon(Polygon sourcePolygon) { - AdjacencyFilters.MatchMaterial filter = null; - if (limitToSameMaterial) + Polygon[] builtRenderPolygons = csgModel.BuiltPolygonsByIndex(sourcePolygon.UniqueIndex); + + foreach (Polygon polygon in builtRenderPolygons) { - // Distinct set of materials used by selected polygons - Material[] sourceMaterials = selectedSourcePolygons.Select(polygon => polygon.Material).Distinct().ToArray(); - filter = new AdjacencyFilters.MatchMaterial(sourceMaterials); + polygon.UserExcludeFromFinal = false; } - List polygonIDs = AdjacencyHelper.FindAdjacentCoplanar(csgModel.VisualPolygons, selectedSourcePolygons, filter); + AddAndUpdateMesh(csgModel.GetVisualPolygonEntry(sourcePolygon.UniqueIndex), sourcePolygon, true); + AddAndUpdateMesh(csgModel.GetCollisionPolygonEntry(sourcePolygon.UniqueIndex), sourcePolygon, false); - SetSelectionFromPolygonIDs(polygonIDs); + // Mesh colliders need to be refreshed now that their collision meshes have changed + csgModel.RefreshMeshGroup(); + + csgModel.SetContextDirty(); } - void SelectAdjacentAll() - { - AdjacencyFilters.MatchMaterial filter = null; - if (limitToSameMaterial) + public void AddAndUpdateMesh(PolygonEntry entry, Polygon sourcePolygon, bool isVisual) + { + if (PolygonEntry.IsValid(entry)) { - // Distinct set of materials used by selected polygons - Material[] sourceMaterials = selectedSourcePolygons.Select(polygon => polygon.Material).Distinct().ToArray(); - filter = new AdjacencyFilters.MatchMaterial(sourceMaterials); + int verticesToAdd = entry.Positions.Length; + int trianglesToAdd = entry.Triangles.Length; + Mesh newMesh; + + if (isVisual) + { + Material material = entry.Material; + if (material == null) + { + material = csgModel.GetDefaultMaterial(); + } + newMesh = csgModel.GetMeshForMaterial(material, verticesToAdd); + } + else + { + newMesh = csgModel.GetMeshForCollision(verticesToAdd); + } + + // Unfortunately in Unity 5.1 accessing .triangles on an empty mesh throws an error + int[] destTriangles = newMesh.GetTrianglesSafe(); + + Vector3[] destVertices = newMesh.vertices; + Vector2[] destUV = newMesh.uv; + Vector3[] destNormals = newMesh.normals; + Color[] destColors = newMesh.colors; + + int destVertexCount = destVertices.Length; + int destTriangleCount = destTriangles.Length; + + Array.Resize(ref destVertices, destVertexCount + verticesToAdd); + Array.Resize(ref destUV, destVertexCount + verticesToAdd); + Array.Resize(ref destNormals, destVertexCount + verticesToAdd); + Array.Resize(ref destColors, destVertexCount + verticesToAdd); + + for (int i = 0; i < entry.Positions.Length; i++) + { + destVertices[destVertexCount + i] = entry.Positions[i]; + destUV[destVertexCount + i] = entry.UV[i]; + destNormals[destVertexCount + i] = entry.Normals[i]; + destColors[destVertexCount + i] = entry.Colors[i]; + } + + Array.Resize(ref destTriangles, destTriangleCount + trianglesToAdd); + + for (int i = 0; i < entry.Triangles.Length; i++) + { + destTriangles[destTriangleCount + i] = entry.Triangles[i] + destVertexCount; + } + + newMesh.vertices = destVertices; + newMesh.uv = destUV; + newMesh.normals = destNormals; + newMesh.triangles = destTriangles; + newMesh.colors = destColors; + + // If the mesh already has tangents + if (csgModel.LastBuildHadTangents) + { + newMesh.GenerateTangents(); + } + + entry.BuiltMesh = newMesh; + entry.BuiltVertexOffset = destVertexCount; + entry.BuiltTriangleOffset = destTriangleCount; } + } - List polygonIDs = AdjacencyHelper.FindAdjacentAll(csgModel.VisualPolygons, selectedSourcePolygons, filter); + public void RemoveAndUpdateMesh(PolygonEntry entry, Polygon sourcePolygon) + { + if (!PolygonEntry.IsValidAndBuilt(entry)) + { + // This polygon hasn't actually been built + return; + } - SetSelectionFromPolygonIDs(polygonIDs); - } - - void SetSelectionFromPolygonIDs(List polygonIDs) - { - ResetSelection(); - - for (int i = 0; i < polygonIDs.Count; i++) - { - Polygon sourcePolygon = csgModel.GetSourcePolygon(polygonIDs[i]); - selectedSourcePolygons.Add(sourcePolygon); - matchedBrushes.Add(sourcePolygon, csgModel.FindBrushFromPolygon(sourcePolygon)); - } - } - - void ExtrudeBrushesFromSelection() - { - GameObject[] newObjects = new GameObject[selectedSourcePolygons.Count]; - for (int i = 0; i < selectedSourcePolygons.Count; i++) - { - Quaternion rotation; - Polygon[] polygons; - SurfaceUtility.ExtrudePolygon(selectedSourcePolygons[i], 1, out polygons, out rotation); - - Brush sourceBrush = matchedBrushes[selectedSourcePolygons[i]]; - GameObject newObject = ((PrimitiveBrush)sourceBrush).Duplicate(); - - newObject.transform.rotation = sourceBrush.transform.rotation * rotation; - // Finally give the new brush the other set of polygons - newObject.GetComponent().SetPolygons(polygons, true); - - Undo.RegisterCreatedObjectUndo(newObject, "Extrude Brush"); - - newObjects[i] = newObject; - } - - csgModel.SetCurrentMode(MainMode.Resize); - Selection.objects = newObjects; - } - - void AutoFit() - { - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - - - PolygonEntry entry = csgModel.GetVisualPolygonEntry(polygon.UniqueIndex); - if(PolygonEntry.IsValidAndBuilt(entry)) - { - Brush brush = matchedBrushes[polygon]; - Undo.RecordObject(brush, "Auto Fit"); - csgModel.UndoRecordContext("Auto Fit"); - Undo.RecordObject(entry.BuiltMesh, "Auto Fit"); - Transform brushTransform = brush.transform; - - UVOrientation worldOrientation = SurfaceUtility.GetNorthEastVectors(polygon, brushTransform); - - Vector3 worldVectorNorth = worldOrientation.NorthVector; - Vector3 worldVectorEast = worldOrientation.EastVector; - - Vector3 polygonCenterLocal = polygon.GetCenterPoint(); - Vector3 polygonCenterWorld = brushTransform.TransformPoint(polygonCenterLocal); - - // World vertices - Polygon[] builtPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); - Vertex northernVertex = builtPolygons[0].Vertices[0]; - Vertex southernVertex = builtPolygons[0].Vertices[0]; - Vertex easternVertex = builtPolygons[0].Vertices[0]; - Vertex westernVertex = builtPolygons[0].Vertices[0]; - - - for (int builtIndex = 0; builtIndex < builtPolygons.Length; builtIndex++) - { - for (int i = 0; i < builtPolygons[builtIndex].Vertices.Length; i++) - { - Vertex testVertex = builtPolygons[builtIndex].Vertices[i]; - - float dotCurrent = Vector3.Dot(northernVertex.Position-polygonCenterWorld, worldVectorNorth); - float dotTest = Vector3.Dot(testVertex.Position-polygonCenterWorld, worldVectorNorth); - if(dotTest > dotCurrent) - { - northernVertex = testVertex; - } - - dotCurrent = Vector3.Dot(southernVertex.Position-polygonCenterWorld, -worldVectorNorth); - dotTest = Vector3.Dot(testVertex.Position-polygonCenterWorld, -worldVectorNorth); - if(dotTest > dotCurrent) - { - southernVertex = testVertex; - } - - dotCurrent = Vector3.Dot(easternVertex.Position-polygonCenterWorld, worldVectorEast); - dotTest = Vector3.Dot(testVertex.Position-polygonCenterWorld, worldVectorEast); - if(dotTest > dotCurrent) - { - easternVertex = testVertex; - } - - dotCurrent = Vector3.Dot(westernVertex.Position-polygonCenterWorld, -worldVectorEast); - dotTest = Vector3.Dot(testVertex.Position-polygonCenterWorld, -worldVectorEast); - if(dotTest > dotCurrent) - { - westernVertex = testVertex; - } - } - } - - float northernDistance = Vector3.Dot(northernVertex.Position - polygonCenterWorld, worldVectorNorth); - float southernDistance = Vector3.Dot(southernVertex.Position - polygonCenterWorld, worldVectorNorth); - - float easternDistance = Vector3.Dot(easternVertex.Position - polygonCenterWorld, worldVectorEast); - float westernDistance = Vector3.Dot(westernVertex.Position - polygonCenterWorld, worldVectorEast); - - // Update the source polygons - for (int i = 0; i < polygon.Vertices.Length; i++) - { - Vector3 localPosition = polygon.Vertices[i].Position; - Vector3 worldPosition = brushTransform.TransformPoint(localPosition); - - float thisNorthDistance = Vector3.Dot(worldPosition - polygonCenterWorld, worldVectorNorth); - float thisEastDistance = Vector3.Dot(worldPosition - polygonCenterWorld, worldVectorEast); - - Vector2 uv = new Vector2(MathHelper.InverseLerpNoClamp(westernDistance, easternDistance, thisEastDistance), - MathHelper.InverseLerpNoClamp(southernDistance, northernDistance, thisNorthDistance)); - - polygon.Vertices[i].UV = uv; - } - - // Update the built polygons in case we need to use them for something else - for (int builtPolygonIndex = 0; builtPolygonIndex < builtPolygons.Length; builtPolygonIndex++) - { - Polygon builtPolygon = builtPolygons[builtPolygonIndex]; - for (int vertexIndex = 0; vertexIndex < builtPolygon.Vertices.Length; vertexIndex++) - { - Vector3 worldPosition = builtPolygon.Vertices[vertexIndex].Position; - - float thisNorthDistance = Vector3.Dot(worldPosition - polygonCenterWorld, worldVectorNorth); - float thisEastDistance = Vector3.Dot(worldPosition - polygonCenterWorld, worldVectorEast); - - Vector2 uv = new Vector2(MathHelper.InverseLerpNoClamp(westernDistance, easternDistance, thisEastDistance), - MathHelper.InverseLerpNoClamp(southernDistance, northernDistance, thisNorthDistance)); - - builtPolygon.Vertices[vertexIndex].UV = uv; - } - } - - - Vector3[] vertices = entry.BuiltMesh.vertices; - - Vector2[] meshUVs = entry.BuiltMesh.uv; - Vector2[] uvs = entry.UV; - - for (int vertexIndex = 0; vertexIndex < entry.Positions.Length; vertexIndex++) - { - Vector3 worldPosition = vertices[entry.BuiltVertexOffset + vertexIndex]; - - float thisNorthDistance = Vector3.Dot(worldPosition - polygonCenterWorld, worldVectorNorth); - float thisEastDistance = Vector3.Dot(worldPosition - polygonCenterWorld, worldVectorEast); - - Vector2 uv = new Vector2(MathHelper.InverseLerpNoClamp(westernDistance, easternDistance, thisEastDistance), - MathHelper.InverseLerpNoClamp(southernDistance, northernDistance, thisNorthDistance)); - - uvs[vertexIndex] = uv; - meshUVs[entry.BuiltVertexOffset + vertexIndex] = uv; - } - entry.UV = uvs; - entry.BuiltMesh.uv = meshUVs; - - EditorHelper.SetDirty(entry.BuiltMesh); - - - // Inform the brush cache that the polygons have changed, but that a rebuild isn't necessary - brush.RecachePolygons(false); - } - } - } - - void AutoUV(bool useWorldSpace) - { - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - - Brush brush = matchedBrushes[polygon]; - Undo.RecordObject(brush, "Auto UV"); - csgModel.UndoRecordContext("Auto UV"); - Transform brushTransform = brush.transform; - - Vector3 planeNormal = polygon.Plane.normal; - if(useWorldSpace) - { - planeNormal = brushTransform.TransformDirection(planeNormal); - } - - Quaternion cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(-planeNormal)); - - // Sets the UV at each point to the position on the plane - for (int i = 0; i < polygon.Vertices.Length; i++) - { - Vector3 position = polygon.Vertices[i].Position; - if(useWorldSpace) - { - position = brushTransform.TransformPoint(position); - } - - Vector2 uv = (cancellingRotation * position) * 0.5f; - polygon.Vertices[i].UV = uv; - } - - - Polygon[] builtPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); - - for (int builtPolygonIndex = 0; builtPolygonIndex < builtPolygons.Length; builtPolygonIndex++) - { - Polygon builtPolygon = builtPolygons[builtPolygonIndex]; - for (int vertexIndex = 0; vertexIndex < builtPolygon.Vertices.Length; vertexIndex++) - { - Vector3 position = builtPolygon.Vertices[vertexIndex].Position; - - if(!useWorldSpace) - { - position = brushTransform.InverseTransformPoint(position); - } - - Vector2 uv = (cancellingRotation * position) * 0.5f; - builtPolygon.Vertices[vertexIndex].UV = uv; - } - } - - // Update the actual built mesh - - PolygonEntry entry = csgModel.GetVisualPolygonEntry(polygon.UniqueIndex); - if(PolygonEntry.IsValidAndBuilt(entry)) - { - Undo.RecordObject(entry.BuiltMesh, "Auto UV"); - Vector3[] vertices = entry.BuiltMesh.vertices; - - Vector2[] meshUVs = entry.BuiltMesh.uv; - Vector2[] uvs = entry.UV; - - for (int vertexIndex = 0; vertexIndex < entry.Positions.Length; vertexIndex++) - { - Vector3 position = vertices[entry.BuiltVertexOffset + vertexIndex]; - if(!useWorldSpace) - { - position = brushTransform.InverseTransformPoint(position); - } - - Vector2 uv = (cancellingRotation * position) * 0.5f; - - uvs[vertexIndex] = uv; - meshUVs[entry.BuiltVertexOffset + vertexIndex] = uv; - } - entry.UV = uvs; - entry.BuiltMesh.uv = meshUVs; - - EditorHelper.SetDirty(entry.BuiltMesh); - } - - // Inform the brush cache that the polygons have changed, but that a rebuild isn't necessary - brush.RecachePolygons(false); - } - } - - void PlanarMap(Vector3 planarDirection) - { - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - - Brush brush = matchedBrushes[polygon]; - Undo.RecordObject(brush, "Planar Map"); - csgModel.UndoRecordContext("Planar Map"); - Transform brushTransform = brush.transform; - - Quaternion cancellingRotation; - if(planarDirection == Vector3.up) - { - cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(-planarDirection, Vector3.right)); - } - else - { - cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(planarDirection)); - } - - Vector3 planeNormal = polygon.Plane.normal; - planeNormal = brushTransform.TransformDirection(planeNormal); - - // Skip if the polygon and planar directorions are perpendicular - if(Mathf.Abs(Vector3.Dot(planeNormal, planarDirection)) <= 0.01f) - { - return; - } - - // Sets the UV at each point to the position on the plane - for (int i = 0; i < polygon.Vertices.Length; i++) - { - Vector3 position = polygon.Vertices[i].Position; - position = brushTransform.TransformPoint(position); - - Vector2 uv = (cancellingRotation * position) * 0.5f; - polygon.Vertices[i].UV = uv; - } - - - Polygon[] builtPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); - - for (int builtPolygonIndex = 0; builtPolygonIndex < builtPolygons.Length; builtPolygonIndex++) - { - Polygon builtPolygon = builtPolygons[builtPolygonIndex]; - for (int vertexIndex = 0; vertexIndex < builtPolygon.Vertices.Length; vertexIndex++) - { - Vector3 position = builtPolygon.Vertices[vertexIndex].Position; - - Vector2 uv = (cancellingRotation * position) * 0.5f; - builtPolygon.Vertices[vertexIndex].UV = uv; - } - } - - // Update the actual built mesh - - PolygonEntry entry = csgModel.GetVisualPolygonEntry(polygon.UniqueIndex); - if(PolygonEntry.IsValidAndBuilt(entry)) - { - Undo.RecordObject(entry.BuiltMesh, "Planar Map"); - Vector3[] vertices = entry.BuiltMesh.vertices; - - Vector2[] meshUVs = entry.BuiltMesh.uv; - Vector2[] uvs = entry.UV; - - for (int vertexIndex = 0; vertexIndex < entry.Positions.Length; vertexIndex++) - { - Vector3 position = vertices[entry.BuiltVertexOffset + vertexIndex]; - - Vector2 uv = (cancellingRotation * position) * 0.5f; - - uvs[vertexIndex] = uv; - meshUVs[entry.BuiltVertexOffset + vertexIndex] = uv; - } - entry.UV = uvs; - entry.BuiltMesh.uv = meshUVs; - - EditorHelper.SetDirty(entry.BuiltMesh); - } - - // Inform the brush cache that the polygons have changed, but that a rebuild isn't necessary - brush.RecachePolygons(false); - } - } - - - void Align(AlignDirection direction) - { - for (int polygonIndex = 0; polygonIndex < selectedSourcePolygons.Count; polygonIndex++) - { - Polygon polygon = selectedSourcePolygons[polygonIndex]; - - Transform brushTransform = matchedBrushes[polygon].transform; - - UVOrientation worldOrientation = SurfaceUtility.GetNorthEastVectors(polygon, brushTransform); - - Vector3 worldVectorNorth = worldOrientation.NorthVector; - Vector3 worldVectorEast = worldOrientation.EastVector; - - Vector3 polygonCenterLocal = polygon.GetCenterPoint(); - Vector3 polygonCenterWorld = brushTransform.TransformPoint(polygonCenterLocal); - - // World vertices - Polygon[] builtPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); - Vertex northernVertex = builtPolygons[0].Vertices[0]; - Vertex southernVertex = builtPolygons[0].Vertices[0]; - Vertex easternVertex = builtPolygons[0].Vertices[0]; - Vertex westernVertex = builtPolygons[0].Vertices[0]; - - - for (int builtIndex = 0; builtIndex < builtPolygons.Length; builtIndex++) - { - for (int i = 0; i < builtPolygons[builtIndex].Vertices.Length; i++) - { - Vertex testVertex = builtPolygons[builtIndex].Vertices[i]; - - float dotCurrent = Vector3.Dot(northernVertex.Position-polygonCenterWorld, worldVectorNorth); - float dotTest = Vector3.Dot(testVertex.Position-polygonCenterWorld, worldVectorNorth); - if(dotTest > dotCurrent) - { - northernVertex = testVertex; - } - - dotCurrent = Vector3.Dot(southernVertex.Position-polygonCenterWorld, -worldVectorNorth); - dotTest = Vector3.Dot(testVertex.Position-polygonCenterWorld, -worldVectorNorth); - if(dotTest > dotCurrent) - { - southernVertex = testVertex; - } - - dotCurrent = Vector3.Dot(easternVertex.Position-polygonCenterWorld, worldVectorEast); - dotTest = Vector3.Dot(testVertex.Position-polygonCenterWorld, worldVectorEast); - if(dotTest > dotCurrent) - { - easternVertex = testVertex; - } - - dotCurrent = Vector3.Dot(westernVertex.Position-polygonCenterWorld, -worldVectorEast); - dotTest = Vector3.Dot(testVertex.Position-polygonCenterWorld, -worldVectorEast); - if(dotTest > dotCurrent) - { - westernVertex = testVertex; - } - } - } - - Vector2 offset = new Vector2(0,0); - - if(direction == AlignDirection.Top) - { - offset.y = 1-northernVertex.UV.y; - } - else if(direction == AlignDirection.Bottom) - { - offset.y = 0-southernVertex.UV.y; - } - else if(direction == AlignDirection.Left) - { - offset.x = 0-westernVertex.UV.x; - } - else if(direction == AlignDirection.Right) - { - offset.x = 1-easternVertex.UV.x; - } - else if(direction == AlignDirection.Center) - { - offset.x = (0-westernVertex.UV.x + 1-easternVertex.UV.x) * .5f; - offset.y = (1-northernVertex.UV.y + 0-southernVertex.UV.y) * .5f; - } - - TransformUVs(polygon, UVUtility.TranslateUV, new UVUtility.TransformData(offset,0), true); - } - } - - void UserExcludePolygon(Polygon sourcePolygon) - { - Polygon[] builtRenderPolygons = csgModel.BuiltPolygonsByIndex(sourcePolygon.UniqueIndex); - - foreach (Polygon polygon in builtRenderPolygons) - { - polygon.UserExcludeFromFinal = true; - } - -// Polygon[] builtCollisionPolygons = csgModel.BuiltCollisionPolygonsByIndex(sourcePolygon.UniqueIndex); -// -// foreach (Polygon polygon in builtCollisionPolygons) -// { -// polygon.UserExcludeFromFinal = true; -// } - - RemoveAndUpdateMesh(csgModel.GetVisualPolygonEntry(sourcePolygon.UniqueIndex), sourcePolygon); - RemoveAndUpdateMesh(csgModel.GetCollisionPolygonEntry(sourcePolygon.UniqueIndex), sourcePolygon); - - // Mesh colliders need to be refreshed now that their collision meshes have changed - csgModel.RefreshMeshGroup(); - - csgModel.SetContextDirty(); - } - - - void UserIncludePolygon(Polygon sourcePolygon) - { - Polygon[] builtRenderPolygons = csgModel.BuiltPolygonsByIndex(sourcePolygon.UniqueIndex); - - foreach (Polygon polygon in builtRenderPolygons) - { - polygon.UserExcludeFromFinal = false; - } - - AddAndUpdateMesh(csgModel.GetVisualPolygonEntry(sourcePolygon.UniqueIndex), sourcePolygon, true); - AddAndUpdateMesh(csgModel.GetCollisionPolygonEntry(sourcePolygon.UniqueIndex), sourcePolygon, false); - - // Mesh colliders need to be refreshed now that their collision meshes have changed - csgModel.RefreshMeshGroup(); - - csgModel.SetContextDirty(); - } - - public void AddAndUpdateMesh(PolygonEntry entry, Polygon sourcePolygon, bool isVisual) - { - if(PolygonEntry.IsValid(entry)) - { - int verticesToAdd = entry.Positions.Length; - int trianglesToAdd = entry.Triangles.Length; - Mesh newMesh; - - if(isVisual) - { - Material material = entry.Material; - if(material == null) - { - material = csgModel.GetDefaultMaterial(); - } - newMesh = csgModel.GetMeshForMaterial(material, verticesToAdd); - } - else - { - newMesh = csgModel.GetMeshForCollision(verticesToAdd); - } - - // Unfortunately in Unity 5.1 accessing .triangles on an empty mesh throws an error - int[] destTriangles = newMesh.GetTrianglesSafe(); - - Vector3[] destVertices = newMesh.vertices; - Vector2[] destUV = newMesh.uv; - Vector3[] destNormals = newMesh.normals; - Color[] destColors = newMesh.colors; - - int destVertexCount = destVertices.Length; - int destTriangleCount = destTriangles.Length; - - Array.Resize(ref destVertices, destVertexCount + verticesToAdd); - Array.Resize(ref destUV, destVertexCount + verticesToAdd); - Array.Resize(ref destNormals, destVertexCount + verticesToAdd); - Array.Resize(ref destColors, destVertexCount + verticesToAdd); - - for (int i = 0; i < entry.Positions.Length; i++) - { - destVertices[destVertexCount + i] = entry.Positions[i]; - destUV[destVertexCount + i] = entry.UV[i]; - destNormals[destVertexCount + i] = entry.Normals[i]; - destColors[destVertexCount + i] = entry.Colors[i]; - } - - Array.Resize(ref destTriangles, destTriangleCount + trianglesToAdd); - - for (int i = 0; i < entry.Triangles.Length; i++) - { - destTriangles[destTriangleCount + i] = entry.Triangles[i] + destVertexCount; - } - - newMesh.vertices = destVertices; - newMesh.uv = destUV; - newMesh.normals = destNormals; - newMesh.triangles = destTriangles; - newMesh.colors = destColors; - - // If the mesh already has tangents - if(csgModel.LastBuildHadTangents) - { - newMesh.GenerateTangents(); - } - - entry.BuiltMesh = newMesh; - entry.BuiltVertexOffset = destVertexCount; - entry.BuiltTriangleOffset = destTriangleCount; - } - } - - public void RemoveAndUpdateMesh(PolygonEntry entry, Polygon sourcePolygon) - { - if(!PolygonEntry.IsValidAndBuilt(entry)) - { - // This polygon hasn't actually been built - return; - } - - int[] triangles = entry.BuiltMesh.triangles; + int[] triangles = entry.BuiltMesh.triangles; // Turn the triangles into degenerates - for (int i = 0; i < entry.Triangles.Length; i++) - { - triangles[entry.BuiltTriangleOffset + i] = 0; - } + for (int i = 0; i < entry.Triangles.Length; i++) + { + triangles[entry.BuiltTriangleOffset + i] = 0; + } bool areAllDegenerate = true; for (int i = 0; i < triangles.Length; i++) { - if(triangles[i] != 0) + if (triangles[i] != 0) { areAllDegenerate = false; } } // PhysX will throw an error if we make all the polygons degenerate, so in that case simply change the triangles array to empty - if(areAllDegenerate) + if (areAllDegenerate) { triangles = new int[0]; } - entry.BuiltMesh.triangles = triangles; - } - - private void ChangePolygonMaterial(Polygon polygon, Material destinationMaterial) - { - Material defaultMaterial = CSGModel.GetDefaultMaterial(); - - // Only attempt to transfer the polygon if it's to a different material! - if(polygon.Material == destinationMaterial - || (polygon.Material == null && destinationMaterial == defaultMaterial) - || (polygon.Material == defaultMaterial && destinationMaterial == null)) - { - return; - } - PolygonEntry entry = csgModel.GetVisualPolygonEntry(polygon.UniqueIndex); - - // Repoint the polygon's material, so it will change with rebuilds - polygon.Material = destinationMaterial; - - if(!PolygonEntry.IsValidAndBuilt(entry)) - { - // This polygon hasn't actually been built - return; - } - - Mesh originalMesh = entry.BuiltMesh; - - int verticesToAdd = entry.Positions.Length; - int trianglesToAdd = entry.Triangles.Length; - - int[] sourceTriangles = originalMesh.triangles; - Vector3[] sourceVertices = originalMesh.vertices; - Vector2[] sourceUV = originalMesh.uv; - Vector2[] sourceUV2 = originalMesh.uv2; - Color[] sourceColors = originalMesh.colors; - Vector3[] sourceNormals = originalMesh.normals; - Vector4[] sourceTangents = originalMesh.tangents; - - Mesh newMesh = csgModel.GetMeshForMaterial(destinationMaterial, verticesToAdd); - - // Unfortunately in Unity 5.1 accessing .triangles on an empty mesh throws an error - int[] destTriangles = newMesh.GetTrianglesSafe(); - - Vector3[] destVertices = newMesh.vertices; - Vector2[] destUV = newMesh.uv; - Vector2[] destUV2 = newMesh.uv2; - Color[] destColors = newMesh.colors; - Vector3[] destNormals = newMesh.normals; - Vector4[] destTangents = newMesh.tangents; - - int destVertexCount = destVertices.Length; - int destTriangleCount = destTriangles.Length; - - - Array.Resize(ref destVertices, destVertexCount + verticesToAdd); - Array.Resize(ref destUV, destVertexCount + verticesToAdd); - Array.Resize(ref destUV2, destVertexCount + verticesToAdd); - Array.Resize(ref destColors, destVertexCount + verticesToAdd); - Array.Resize(ref destNormals, destVertexCount + verticesToAdd); - Array.Resize(ref destTangents, destVertexCount + verticesToAdd); - - for (int i = 0; i < entry.Positions.Length; i++) - { - destVertices[destVertexCount + i] = sourceVertices[entry.BuiltVertexOffset + i]; - destUV[destVertexCount + i] = sourceUV[entry.BuiltVertexOffset + i]; - destNormals[destVertexCount + i] = sourceNormals[entry.BuiltVertexOffset + i]; - } - - // If the source mesh had lightmap UVs to copy - if(sourceUV2.Length > 0) - { - for (int i = 0; i < entry.Positions.Length; i++) - { - destUV2[destVertexCount + i] = sourceUV2[entry.BuiltVertexOffset + i]; - } - } - - // If the source mesh had tangents to copy - if(sourceTangents.Length > 0) - { - for (int i = 0; i < entry.Positions.Length; i++) - { - destTangents[destVertexCount + i] = sourceTangents[entry.BuiltVertexOffset + i]; - } - } - - // If the source mesh had colors to copy - if(sourceColors.Length > 0) - { - for (int i = 0; i < entry.Positions.Length; i++) - { - destColors[destVertexCount + i] = sourceColors[entry.BuiltVertexOffset + i]; - } - } - - Array.Resize(ref destTriangles, destTriangleCount + trianglesToAdd); - - for (int i = 0; i < entry.Triangles.Length; i++) - { - destTriangles[destTriangleCount + i] = sourceTriangles[entry.BuiltTriangleOffset + i] - entry.BuiltVertexOffset + destVertexCount; - } - - for (int i = 0; i < entry.Triangles.Length; i++) - { - sourceTriangles[entry.BuiltTriangleOffset + i] = 0; - } - - newMesh.vertices = destVertices; - newMesh.uv = destUV; - newMesh.uv2 = destUV2; - newMesh.colors = destColors; - newMesh.normals = destNormals; - newMesh.tangents = destTangents; - newMesh.triangles = destTriangles; - - originalMesh.triangles = sourceTriangles; - - entry.Material = destinationMaterial; - entry.BuiltMesh = newMesh; - entry.BuiltTriangleOffset = destTriangleCount; - entry.BuiltVertexOffset = destVertexCount; - - matchedBrushes[polygon].RecachePolygons(false); - - for (int i = 0; i < matchedBrushes[polygon].BrushCache.BuiltVisualPolygons.Count; i++) - { - if(matchedBrushes[polygon].BrushCache.BuiltVisualPolygons[i].UniqueIndex == polygon.UniqueIndex) - { - matchedBrushes[polygon].BrushCache.BuiltVisualPolygons[i].Material = destinationMaterial; - } - } - - Polygon[] builtPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); - for (int i = 0; i < builtPolygons.Length; i++) - { - builtPolygons[i].Material = destinationMaterial; - } - csgModel.SetContextDirty(); - } - - private void ChangePolygonColor(Polygon polygon, Color color) - { - for (int j = 0; j < polygon.Vertices.Length; j++) - { - polygon.Vertices[j].Color = color; - - PolygonEntry entry = csgModel.GetVisualPolygonEntry(polygon.UniqueIndex); - if(entry != null) - { - if(entry.BuiltMesh != null) - { - Undo.RecordObject(entry.BuiltMesh, "Change Vertex Color"); - - Color[] meshColors = entry.BuiltMesh.colors; - Color[] colors = entry.Colors; - - for (int vertexIndex = 0; vertexIndex < entry.Positions.Length; vertexIndex++) - { - colors[vertexIndex] = color; - meshColors[entry.BuiltVertexOffset + vertexIndex] = color; - } - entry.Colors = colors; - entry.BuiltMesh.colors = meshColors; - - EditorHelper.SetDirty(entry.BuiltMesh); - } - } - - // Inform the brush cache that the polygons have changed, but that a rebuild isn't necessary - matchedBrushes[polygon].RecachePolygons(false); - } - } - - public void SetSelectionColor(Color color) - { - for (int i = 0; i < selectedSourcePolygons.Count; i++) - { - Polygon polygon = selectedSourcePolygons[i]; - ChangePolygonColor(polygon, color); - } - } - - public void SetSelectionMaterial(Material material) - { - for (int i = 0; i < selectedSourcePolygons.Count; i++) - { - Polygon polygon = selectedSourcePolygons[i]; - ChangePolygonMaterial(polygon, material); - } - } + entry.BuiltMesh.triangles = triangles; + } + + private void ChangePolygonMaterial(Polygon polygon, Material destinationMaterial) + { + Material defaultMaterial = CSGModel.GetDefaultMaterial(); + + // Only attempt to transfer the polygon if it's to a different material! + if (polygon.Material == destinationMaterial + || (polygon.Material == null && destinationMaterial == defaultMaterial) + || (polygon.Material == defaultMaterial && destinationMaterial == null)) + { + return; + } + PolygonEntry entry = csgModel.GetVisualPolygonEntry(polygon.UniqueIndex); + + // Repoint the polygon's material, so it will change with rebuilds + polygon.Material = destinationMaterial; + + if (!PolygonEntry.IsValidAndBuilt(entry)) + { + // This polygon hasn't actually been built + return; + } + + Mesh originalMesh = entry.BuiltMesh; + + int verticesToAdd = entry.Positions.Length; + int trianglesToAdd = entry.Triangles.Length; + + int[] sourceTriangles = originalMesh.triangles; + Vector3[] sourceVertices = originalMesh.vertices; + Vector2[] sourceUV = originalMesh.uv; + Vector2[] sourceUV2 = originalMesh.uv2; + Color[] sourceColors = originalMesh.colors; + Vector3[] sourceNormals = originalMesh.normals; + Vector4[] sourceTangents = originalMesh.tangents; + + Mesh newMesh = csgModel.GetMeshForMaterial(destinationMaterial, verticesToAdd); + + // Unfortunately in Unity 5.1 accessing .triangles on an empty mesh throws an error + int[] destTriangles = newMesh.GetTrianglesSafe(); + + Vector3[] destVertices = newMesh.vertices; + Vector2[] destUV = newMesh.uv; + Vector2[] destUV2 = newMesh.uv2; + Color[] destColors = newMesh.colors; + Vector3[] destNormals = newMesh.normals; + Vector4[] destTangents = newMesh.tangents; + + int destVertexCount = destVertices.Length; + int destTriangleCount = destTriangles.Length; + + Array.Resize(ref destVertices, destVertexCount + verticesToAdd); + Array.Resize(ref destUV, destVertexCount + verticesToAdd); + Array.Resize(ref destUV2, destVertexCount + verticesToAdd); + Array.Resize(ref destColors, destVertexCount + verticesToAdd); + Array.Resize(ref destNormals, destVertexCount + verticesToAdd); + Array.Resize(ref destTangents, destVertexCount + verticesToAdd); + + for (int i = 0; i < entry.Positions.Length; i++) + { + destVertices[destVertexCount + i] = sourceVertices[entry.BuiltVertexOffset + i]; + destUV[destVertexCount + i] = sourceUV[entry.BuiltVertexOffset + i]; + destNormals[destVertexCount + i] = sourceNormals[entry.BuiltVertexOffset + i]; + } + + // If the source mesh had lightmap UVs to copy + if (sourceUV2.Length > 0) + { + for (int i = 0; i < entry.Positions.Length; i++) + { + destUV2[destVertexCount + i] = sourceUV2[entry.BuiltVertexOffset + i]; + } + } + + // If the source mesh had tangents to copy + if (sourceTangents.Length > 0) + { + for (int i = 0; i < entry.Positions.Length; i++) + { + destTangents[destVertexCount + i] = sourceTangents[entry.BuiltVertexOffset + i]; + } + } + + // If the source mesh had colors to copy + if (sourceColors.Length > 0) + { + for (int i = 0; i < entry.Positions.Length; i++) + { + destColors[destVertexCount + i] = sourceColors[entry.BuiltVertexOffset + i]; + } + } + + Array.Resize(ref destTriangles, destTriangleCount + trianglesToAdd); + + for (int i = 0; i < entry.Triangles.Length; i++) + { + destTriangles[destTriangleCount + i] = sourceTriangles[entry.BuiltTriangleOffset + i] - entry.BuiltVertexOffset + destVertexCount; + } + + for (int i = 0; i < entry.Triangles.Length; i++) + { + sourceTriangles[entry.BuiltTriangleOffset + i] = 0; + } + + newMesh.vertices = destVertices; + newMesh.uv = destUV; + newMesh.uv2 = destUV2; + newMesh.colors = destColors; + newMesh.normals = destNormals; + newMesh.tangents = destTangents; + newMesh.triangles = destTriangles; + + originalMesh.triangles = sourceTriangles; + + entry.Material = destinationMaterial; + entry.BuiltMesh = newMesh; + entry.BuiltTriangleOffset = destTriangleCount; + entry.BuiltVertexOffset = destVertexCount; + + matchedBrushes[polygon].RecachePolygons(false); + + for (int i = 0; i < matchedBrushes[polygon].BrushCache.BuiltVisualPolygons.Count; i++) + { + if (matchedBrushes[polygon].BrushCache.BuiltVisualPolygons[i].UniqueIndex == polygon.UniqueIndex) + { + matchedBrushes[polygon].BrushCache.BuiltVisualPolygons[i].Material = destinationMaterial; + } + } + + Polygon[] builtPolygons = csgModel.BuiltPolygonsByIndex(polygon.UniqueIndex); + for (int i = 0; i < builtPolygons.Length; i++) + { + builtPolygons[i].Material = destinationMaterial; + } + csgModel.SetContextDirty(); + } + + private void ChangePolygonColor(Polygon polygon, Color color) + { + for (int j = 0; j < polygon.Vertices.Length; j++) + { + polygon.Vertices[j].Color = color; + + PolygonEntry entry = csgModel.GetVisualPolygonEntry(polygon.UniqueIndex); + if (entry != null) + { + if (entry.BuiltMesh != null) + { + Undo.RecordObject(entry.BuiltMesh, "Change Vertex Color"); + + Color[] meshColors = entry.BuiltMesh.colors; + Color[] colors = entry.Colors; + + for (int vertexIndex = 0; vertexIndex < entry.Positions.Length; vertexIndex++) + { + colors[vertexIndex] = color; + meshColors[entry.BuiltVertexOffset + vertexIndex] = color; + } + entry.Colors = colors; + entry.BuiltMesh.colors = meshColors; + + EditorHelper.SetDirty(entry.BuiltMesh); + } + } + + // Inform the brush cache that the polygons have changed, but that a rebuild isn't necessary + matchedBrushes[polygon].RecachePolygons(false); + } + } + + public void SetSelectionColor(Color color) + { + for (int i = 0; i < selectedSourcePolygons.Count; i++) + { + Polygon polygon = selectedSourcePolygons[i]; + ChangePolygonColor(polygon, color); + } + } + + public void SetSelectionMaterial(Material material) + { + for (int i = 0; i < selectedSourcePolygons.Count; i++) + { + Polygon polygon = selectedSourcePolygons[i]; + ChangePolygonMaterial(polygon, material); + } + } } } + #endif \ No newline at end of file diff --git a/Scripts/Tools/VertexEditor.cs b/Scripts/Tools/VertexEditor.cs index b26c75bd..1f44d4b4 100644 --- a/Scripts/Tools/VertexEditor.cs +++ b/Scripts/Tools/VertexEditor.cs @@ -29,6 +29,8 @@ public class VertexEditor : Tool float weldTolerance = 0.1f; float scale = 1f; + Vertex movingVertex; + void ClearSelection() { selectedEdges.Clear(); @@ -464,7 +466,12 @@ public override void OnSceneGUI (UnityEditor.SceneView sceneView, Event e) { base.OnSceneGUI(sceneView, e); // Allow the base logic to calculate first - if(primaryTargetBrush != null && AnySelected) + if (e.type == EventType.MouseUp || e.rawType == EventType.MouseUp) + { + moveInProgress = false; + } + + if (primaryTargetBrush != null && AnySelected) { if(startPositions.Count == 0) { @@ -481,7 +488,8 @@ public override void OnSceneGUI (UnityEditor.SceneView sceneView, Event e) handleDirection = primaryTargetBrush.transform.rotation; } - // Grab a source point and convert from local space to world + // Grab a source point and convert from local space to world. + // This is the emergency fall-back solution when no vertex is found. Vector3 sourceWorldPosition = GetSelectedCenter(); @@ -502,10 +510,28 @@ public override void OnSceneGUI (UnityEditor.SceneView sceneView, Event e) } EditorGUI.BeginChangeCheck(); + + // If not moving a vertex yet: + if (!moveInProgress) + { + // Find a selected vertex close to the mouse cursor. + Vector3 vpos; + Brush currentBrush; + if (FindClosestSelectedVertexAtMousePosition(out vpos, out movingVertex)) + if (selectedVertices.TryGetValue(movingVertex, out currentBrush)) + sourceWorldPosition = currentBrush.transform.TransformPoint(movingVertex.Position); + } + else + { + // Move the last selected vertex. + Brush currentBrush; + if (selectedVertices.TryGetValue(movingVertex, out currentBrush)) + sourceWorldPosition = currentBrush.transform.TransformPoint(movingVertex.Position); + } + // Display a handle and allow the user to determine a new position in world space Vector3 newWorldPosition = Handles.PositionHandle(sourceWorldPosition, handleDirection); - if(EditorGUI.EndChangeCheck()) { Undo.RecordObjects(targetBrushTransforms, "Moved Vertices"); @@ -564,8 +590,8 @@ public override void OnSceneGUI (UnityEditor.SceneView sceneView, Event e) } } -// if(e.type == EventType.Repaint) - { + // if(e.type == EventType.Repaint) + { OnRepaint(sceneView, e); } } @@ -1268,7 +1294,89 @@ void DrawVertices(SceneView sceneView, Event e) GL.PopMatrix(); } - public override void Deactivated () + /// Finds a selected vertex at the current mouse position. + /// The closest selected vertex world position. + /// True if a vertex was found else false. + private bool FindClosestSelectedVertexAtMousePosition(out Vector3 closestVertexWorldPosition, out Vertex closestVertex) + { + // find a vertex close to the mouse cursor. + Transform sceneViewTransform = SceneView.currentDrawingSceneView.camera.transform; + Vector3 sceneViewPosition = sceneViewTransform.position; + Vector2 mousePosition = Event.current.mousePosition; + + bool foundAnyPoints = false; + closestVertex = null; + closestVertexWorldPosition = Vector3.zero; + float closestDistanceSquare = float.PositiveInfinity; + + foreach (PrimitiveBrush brush in selectedVertices.Values) + { + Polygon[] polygons = brush.GetPolygons(); + for (int i = 0; i < polygons.Length; i++) + { + Polygon polygon = polygons[i]; + + for (int j = 0; j < polygon.Vertices.Length; j++) + { + Vertex vertex = polygon.Vertices[j]; + if (!selectedVertices.ContainsKey(vertex)) continue; + + Vector3 worldPosition = brush.transform.TransformPoint(vertex.Position); + + float vertexDistanceSquare = (sceneViewPosition - worldPosition).sqrMagnitude; + + if (EditorHelper.InClickZone(mousePosition, worldPosition) && vertexDistanceSquare < closestDistanceSquare) + { + closestVertex = vertex; + closestVertexWorldPosition = worldPosition; + foundAnyPoints = true; + closestDistanceSquare = vertexDistanceSquare; + } + } + } + } + + if (foundAnyPoints == false) + { + // None matched, next try finding the closest by distance + Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); + closestVertexWorldPosition = Vector3.zero; + closestDistanceSquare = float.PositiveInfinity; + + foreach (PrimitiveBrush brush in selectedVertices.Values) + { + Polygon[] polygons = brush.GetPolygons(); + for (int i = 0; i < polygons.Length; i++) + { + Polygon polygon = polygons[i]; + + for (int j = 0; j < polygon.Vertices.Length; j++) + { + Vertex vertex = polygon.Vertices[j]; + if (!selectedVertices.ContainsKey(vertex)) continue; + + Vector3 vertexWorldPosition = brush.transform.TransformPoint(vertex.Position); + + Vector3 closestPoint = MathHelper.ProjectPointOnLine(ray.origin, ray.direction, vertexWorldPosition); + + float vertexDistanceSquare = (closestPoint - vertexWorldPosition).sqrMagnitude; + + if (vertexDistanceSquare < closestDistanceSquare) + { + closestVertex = vertex; + closestVertexWorldPosition = vertexWorldPosition; + foundAnyPoints = true; + closestDistanceSquare = vertexDistanceSquare; + } + } + } + } + } + + return foundAnyPoints; + } + + public override void Deactivated () { } diff --git a/Scripts/UI/SabreCSGPreferences.cs b/Scripts/UI/SabreCSGPreferences.cs index 8b082c4e..c1b78473 100644 --- a/Scripts/UI/SabreCSGPreferences.cs +++ b/Scripts/UI/SabreCSGPreferences.cs @@ -1,4 +1,5 @@ #if UNITY_EDITOR + using UnityEngine; using UnityEditor; using System.Collections; @@ -8,78 +9,72 @@ namespace Sabresaurus.SabreCSG { - public class SabreCSGPreferences : EditorWindow - { - const string RUNTIME_CSG_DEFINE = "RUNTIME_CSG"; - static readonly Vector2 WINDOW_SIZE = new Vector2(370,360); - - static Event cachedEvent; - - public static void CreateAndShow() - { - // Unity API doens't allow us to bring up the preferences, so just create a window that will display it - SabreCSGPreferences window = EditorWindow.GetWindow(true, "SabreCSG Preferences", true); - - // By setting both sizes to the same, even the resize cursor hover is automatically disabled - window.minSize = WINDOW_SIZE; - window.maxSize = WINDOW_SIZE; - - window.Show(); - } - - void OnGUI() - { - GUILayout.Label("SabreCSG Preferences", SabreGUILayout.GetTitleStyle(20)); - PreferencesGUI(); - - } - - [PreferenceItem("SabreCSG")] - public static void PreferencesGUI() - { - - -// Event.current.GetTypeForControl -// -// if(Event.current.type == EventType.KeyDown) -// { -// cachedEvent = new Event(Event.current); -//// this.Repaint(); -// } -// -// GUILayout.TextField(""); -// -// if(cachedEvent != null) -// { -// GUILayout.Label(cachedEvent.ToString()); -// } -// else -// { -// GUILayout.Label("No event"); -// } - - - - GUILayout.Space(10); - - bool newHideGridInPerspective = GUILayout.Toggle(CurrentSettings.HideGridInPerspective, "Hide grid in perspective scene views"); - - if(newHideGridInPerspective != CurrentSettings.HideGridInPerspective) - { - SceneView.RepaintAll(); - CurrentSettings.HideGridInPerspective = newHideGridInPerspective; - } - - - CurrentSettings.OverrideFlyCamera = GUILayout.Toggle(CurrentSettings.OverrideFlyCamera, "Linear fly camera"); - - EditorGUI.BeginChangeCheck(); - CurrentSettings.ShowExcludedPolygons = GUILayout.Toggle(CurrentSettings.ShowExcludedPolygons, "Show excluded polygons"); - if(EditorGUI.EndChangeCheck()) - { - // What's shown in the SceneView has potentially changed, so force it to repaint - SceneView.RepaintAll(); - } + public class SabreCSGPreferences : EditorWindow + { + private const string RUNTIME_CSG_DEFINE = "RUNTIME_CSG"; + private static readonly Vector2 WINDOW_SIZE = new Vector2(370, 360); + + private static Event cachedEvent; + + public static void CreateAndShow() + { + // Unity API doens't allow us to bring up the preferences, so just create a window that will display it + SabreCSGPreferences window = EditorWindow.GetWindow(true, "SabreCSG Preferences", true); + + // By setting both sizes to the same, even the resize cursor hover is automatically disabled + window.minSize = WINDOW_SIZE; + window.maxSize = WINDOW_SIZE; + + window.Show(); + } + + private void OnGUI() + { + GUILayout.Label("SabreCSG Preferences", SabreGUILayout.GetTitleStyle(20)); + PreferencesGUI(); + } + + [PreferenceItem("SabreCSG")] + public static void PreferencesGUI() + { + // Event.current.GetTypeForControl + // + // if(Event.current.type == EventType.KeyDown) + // { + // cachedEvent = new Event(Event.current); + //// this.Repaint(); + // } + // + // GUILayout.TextField(""); + // + // if(cachedEvent != null) + // { + // GUILayout.Label(cachedEvent.ToString()); + // } + // else + // { + // GUILayout.Label("No event"); + // } + + GUILayout.Space(10); + + bool newHideGridInPerspective = GUILayout.Toggle(CurrentSettings.HideGridInPerspective, "Hide grid in perspective scene views"); + + if (newHideGridInPerspective != CurrentSettings.HideGridInPerspective) + { + SceneView.RepaintAll(); + CurrentSettings.HideGridInPerspective = newHideGridInPerspective; + } + + CurrentSettings.OverrideFlyCamera = GUILayout.Toggle(CurrentSettings.OverrideFlyCamera, "Linear fly camera"); + + EditorGUI.BeginChangeCheck(); + CurrentSettings.ShowExcludedPolygons = GUILayout.Toggle(CurrentSettings.ShowExcludedPolygons, "Show excluded polygons"); + if (EditorGUI.EndChangeCheck()) + { + // What's shown in the SceneView has potentially changed, so force it to repaint + SceneView.RepaintAll(); + } EditorGUI.BeginChangeCheck(); CurrentSettings.ShowBrushesAsWireframes = GUILayout.Toggle(CurrentSettings.ShowBrushesAsWireframes, "Show brushes as wireframes"); @@ -90,53 +85,62 @@ public static void PreferencesGUI() SceneView.RepaintAll(); } + EditorGUI.BeginChangeCheck(); + CurrentSettings.ShowBrushBoundsGuideLines = GUILayout.Toggle(CurrentSettings.ShowBrushBoundsGuideLines, "Show brush bounds guide lines"); + if (EditorGUI.EndChangeCheck()) + { + // What's shown in the SceneView has potentially changed, so force it to repaint + CSGModel.UpdateAllBrushesVisibility(); + SceneView.RepaintAll(); + } + GUILayout.Space(10); - if(GUILayout.Button("Change key mappings")) - { - Selection.activeObject = KeyMappings.Instance; - // Show inspector - EditorApplication.ExecuteMenuItem("Window/Inspector"); - } -// CurrentSettings.ReducedHandleThreshold = GUILayout.Toggle(CurrentSettings.ReducedHandleThreshold, "Reduced handle threshold"); - - GUILayout.Space(20); - - GUIStyle style = SabreGUILayout.GetForeStyle(); - style.wordWrap = true; - GUILayout.Label("Runtime CSG is a new experimental feature which allows you to create, alter and build brushes at runtime in your built applications.", style); - BuildTargetGroup buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup; - string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup); - List definesSplit = defines.Split(';').ToList(); - bool enabled = definesSplit.Contains(RUNTIME_CSG_DEFINE); - - if(enabled) - { - if(GUILayout.Button("Disable Runtime CSG (Experimental)")) - { - definesSplit.Remove(RUNTIME_CSG_DEFINE); - defines = string.Join(";", definesSplit.ToArray()); - PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, defines); - } - } - else - { - if(GUILayout.Button("Enable Runtime CSG (Experimental)")) - { - if(!definesSplit.Contains(RUNTIME_CSG_DEFINE)) - { - definesSplit.Add(RUNTIME_CSG_DEFINE); - } - defines = string.Join(";", definesSplit.ToArray()); - PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, defines); - } - } - - - GUILayout.FlexibleSpace(); - - GUILayout.Label("SabreCSG Version " + CSGModel.VERSION_STRING, SabreGUILayout.GetForeStyle()); - } - } + if (GUILayout.Button("Change key mappings")) + { + Selection.activeObject = KeyMappings.Instance; + // Show inspector + EditorApplication.ExecuteMenuItem("Window/Inspector"); + } + // CurrentSettings.ReducedHandleThreshold = GUILayout.Toggle(CurrentSettings.ReducedHandleThreshold, "Reduced handle threshold"); + + GUILayout.Space(20); + + GUIStyle style = SabreGUILayout.GetForeStyle(); + style.wordWrap = true; + GUILayout.Label("Runtime CSG is a new experimental feature which allows you to create, alter and build brushes at runtime in your built applications.", style); + BuildTargetGroup buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup; + string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup); + List definesSplit = defines.Split(';').ToList(); + bool enabled = definesSplit.Contains(RUNTIME_CSG_DEFINE); + + if (enabled) + { + if (GUILayout.Button("Disable Runtime CSG (Experimental)")) + { + definesSplit.Remove(RUNTIME_CSG_DEFINE); + defines = string.Join(";", definesSplit.ToArray()); + PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, defines); + } + } + else + { + if (GUILayout.Button("Enable Runtime CSG (Experimental)")) + { + if (!definesSplit.Contains(RUNTIME_CSG_DEFINE)) + { + definesSplit.Add(RUNTIME_CSG_DEFINE); + } + defines = string.Join(";", definesSplit.ToArray()); + PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, defines); + } + } + + GUILayout.FlexibleSpace(); + + GUILayout.Label("SabreCSG Version " + CSGModel.VERSION_STRING, SabreGUILayout.GetForeStyle()); + } + } } + #endif \ No newline at end of file diff --git a/Scripts/UI/SabreCSGResources.cs b/Scripts/UI/SabreCSGResources.cs index 10e69200..23b4f138 100644 --- a/Scripts/UI/SabreCSGResources.cs +++ b/Scripts/UI/SabreCSGResources.cs @@ -1,4 +1,5 @@ #if UNITY_EDITOR + using UnityEngine; using UnityEditor; using System.Collections.Generic; @@ -6,84 +7,84 @@ namespace Sabresaurus.SabreCSG { - public static class SabreCSGResources - { -#region Fields + public static class SabreCSGResources + { + #region Fields + + // Cached objects keyed by AssetDatabase path relative to SabreCSG folder + private static Dictionary loadedObjects = new Dictionary(); - // Cached objects keyed by AssetDatabase path relative to SabreCSG folder - static Dictionary loadedObjects = new Dictionary(); + // Textures generated rather than loaded + private static Texture2D clearTexture = null; // 0 alpha texture - // Textures generated rather than loaded - private static Texture2D clearTexture = null; // 0 alpha texture - private static Texture2D halfWhiteTexture = null; // white with 0.5 alpha - private static Texture2D halfBlackTexture = null; // black with 0.5 alpha + private static Texture2D halfWhiteTexture = null; // white with 0.5 alpha + private static Texture2D halfBlackTexture = null; // black with 0.5 alpha - // --------------------- + // --------------------- - private static Material selectedBrushMaterial = null; - private static Material selectedBrushDashedMaterial = null; - private static Material selectedBrushDashedAlphaMaterial = null; + private static Material selectedBrushMaterial = null; + private static Material selectedBrushDashedMaterial = null; + private static Material selectedBrushDashedAlphaMaterial = null; private static Material gizmoMaterial = null; - private static Material vertexMaterial = null; - private static Material circleMaterial = null; - private static Material circleOutlineMaterial = null; - private static Material planeMaterial = null; - private static Material previewMaterial = null; - private static Material excludedMaterial = null; - private static Material greyscaleUIMaterial = null; - -#endregion - - - /// - /// Loads an object from a path, or if the object is already loaded returns it - /// - /// Path local to the SabreCSG folder - /// - private static Object LoadObject(string sabrePath) - { - bool found = false; - - Object loadedObject = null; - - // First of all see if there's a cached record - if (loadedObjects.ContainsKey(sabrePath)) - { - found = true; - loadedObject = loadedObjects[sabrePath]; - - // Now make sure the cached record actually points to something - if (loadedObject != null) - { - return loadedObject; - } - } - - // Failed to load from cache, so load it from the Asset Database - loadedObject = AssetDatabase.LoadMainAssetAtPath(Path.Combine(CSGModel.GetSabreCSGPath(), sabrePath)); - if(loadedObject != null) - { - if (found) - { - // A cache record was found but empty, so set the existing record to the newly loaded object - loadedObjects[sabrePath] = loadedObject; - } - else - { - // We know that it's not already in the cache, so add it to the end - loadedObjects.Add(sabrePath, loadedObject); - } - } - return loadedObject; - } - - /// - /// Gets an icon for a primitive brush to be displayed on a button - /// - /// The icon texture. - /// Primitive Brush type. - public static Texture2D GetButtonTexture(PrimitiveBrushType brushType) - { + private static Material vertexMaterial = null; + private static Material circleMaterial = null; + private static Material circleOutlineMaterial = null; + private static Material planeMaterial = null; + private static Material previewMaterial = null; + private static Material excludedMaterial = null; + private static Material greyscaleUIMaterial = null; + + #endregion Fields + + /// + /// Loads an object from a path, or if the object is already loaded returns it + /// + /// Path local to the SabreCSG folder + /// + private static Object LoadObject(string sabrePath) + { + bool found = false; + + Object loadedObject = null; + + // First of all see if there's a cached record + if (loadedObjects.ContainsKey(sabrePath)) + { + found = true; + loadedObject = loadedObjects[sabrePath]; + + // Now make sure the cached record actually points to something + if (loadedObject != null) + { + return loadedObject; + } + } + + // Failed to load from cache, so load it from the Asset Database + loadedObject = AssetDatabase.LoadMainAssetAtPath(Path.Combine(CSGModel.GetSabreCSGPath(), sabrePath)); + if (loadedObject != null) + { + if (found) + { + // A cache record was found but empty, so set the existing record to the newly loaded object + loadedObjects[sabrePath] = loadedObject; + } + else + { + // We know that it's not already in the cache, so add it to the end + loadedObjects.Add(sabrePath, loadedObject); + } + } + return loadedObject; + } + + /// + /// Gets an icon for a primitive brush to be displayed on a button + /// + /// The icon texture. + /// Primitive Brush type. + public static Texture2D GetButtonTexture(PrimitiveBrushType brushType) + { if (brushType == PrimitiveBrushType.Prism) return ButtonPrismTexture; else if (brushType == PrimitiveBrushType.Cylinder) @@ -94,140 +95,149 @@ public static Texture2D GetButtonTexture(PrimitiveBrushType brushType) return ButtonConeTexture; else return ButtonCubeTexture; - } - -#region Accessors - public static Texture2D ClearTexture - { - get - { - if(clearTexture == null) - { - clearTexture = new Texture2D(2,2, TextureFormat.RGBA32, false); - for (int x = 0; x < clearTexture.width; x++) - { - for (int y = 0; y < clearTexture.height; y++) - { - clearTexture.SetPixel(x,y,Color.clear); - } - } - clearTexture.Apply(); - } - return clearTexture; - } - } - - public static Texture2D HalfWhiteTexture - { - get - { - if(halfWhiteTexture == null) - { - halfWhiteTexture = new Texture2D(2,2, TextureFormat.RGBA32, false); - for (int x = 0; x < halfWhiteTexture.width; x++) - { - for (int y = 0; y < halfWhiteTexture.height; y++) - { - halfWhiteTexture.SetPixel(x,y,new Color(1,1,1,0.5f)); - } - } - halfWhiteTexture.Apply(); - } - return halfWhiteTexture; - } - } - - public static Texture2D HalfBlackTexture - { - get - { - if(halfBlackTexture == null) - { - halfBlackTexture = new Texture2D(2,2, TextureFormat.RGBA32, false); - for (int x = 0; x < halfBlackTexture.width; x++) - { - for (int y = 0; y < halfBlackTexture.height; y++) - { - halfBlackTexture.SetPixel(x,y,new Color(0,0,0,0.5f)); - } - } - halfBlackTexture.Apply(); - } - return halfBlackTexture; - } - } - - public static Texture2D AddIconTexture - { - get - { + } + + #region Accessors + + public static Texture2D ClearTexture + { + get + { + if (clearTexture == null) + { + clearTexture = new Texture2D(2, 2, TextureFormat.RGBA32, false); + for (int x = 0; x < clearTexture.width; x++) + { + for (int y = 0; y < clearTexture.height; y++) + { + clearTexture.SetPixel(x, y, Color.clear); + } + } + clearTexture.Apply(); + } + return clearTexture; + } + } + + public static Texture2D HalfWhiteTexture + { + get + { + if (halfWhiteTexture == null) + { + halfWhiteTexture = new Texture2D(2, 2, TextureFormat.RGBA32, false); + for (int x = 0; x < halfWhiteTexture.width; x++) + { + for (int y = 0; y < halfWhiteTexture.height; y++) + { + halfWhiteTexture.SetPixel(x, y, new Color(1, 1, 1, 0.5f)); + } + } + halfWhiteTexture.Apply(); + } + return halfWhiteTexture; + } + } + + public static Texture2D HalfBlackTexture + { + get + { + if (halfBlackTexture == null) + { + halfBlackTexture = new Texture2D(2, 2, TextureFormat.RGBA32, false); + for (int x = 0; x < halfBlackTexture.width; x++) + { + for (int y = 0; y < halfBlackTexture.height; y++) + { + halfBlackTexture.SetPixel(x, y, new Color(0, 0, 0, 0.5f)); + } + } + halfBlackTexture.Apply(); + } + return halfBlackTexture; + } + } + + public static Texture2D AddIconTexture + { + get + { return (Texture2D)LoadObject("Gizmos/Add.png"); - } - } - - public static Texture2D SubtractIconTexture - { - get - { - return (Texture2D)LoadObject("Gizmos/Subtract.png"); - } - } - - public static Texture2D NoCSGIconTexture - { - get - { - return (Texture2D)LoadObject("Gizmos/NoCSG.png"); - } - } - - public static Texture2D DialogOverlayTexture - { - get - { - return (Texture2D)LoadObject("Gizmos/DialogOverlay75.png"); - } - } - - public static Texture2D DialogOverlayRetinaTexture - { - get - { - return (Texture2D)LoadObject("Gizmos/DialogOverlay75@2x.png"); - } - } - - public static Texture2D ButtonCubeTexture - { - get - { - return (Texture2D)LoadObject("Gizmos/ButtonCube.png"); - } - } - - public static Texture2D ButtonPrismTexture - { - get - { - return (Texture2D)LoadObject("Gizmos/ButtonPrism.png"); - } - } - - public static Texture2D ButtonCylinderTexture - { - get - { - return (Texture2D)LoadObject("Gizmos/ButtonCylinder.png"); - } - } - - public static Texture2D ButtonSphereTexture - { - get - { - return (Texture2D)LoadObject("Gizmos/ButtonSphere.png"); - } - } + } + } + + public static Texture2D SubtractIconTexture + { + get + { + return (Texture2D)LoadObject("Gizmos/Subtract.png"); + } + } + + public static Texture2D NoCSGIconTexture + { + get + { + return (Texture2D)LoadObject("Gizmos/NoCSG.png"); + } + } + + public static Texture2D GroupIconTexture + { + get + { + return (Texture2D)LoadObject("Gizmos/Group.png"); + } + } + + public static Texture2D DialogOverlayTexture + { + get + { + return (Texture2D)LoadObject("Gizmos/DialogOverlay75.png"); + } + } + + public static Texture2D DialogOverlayRetinaTexture + { + get + { + return (Texture2D)LoadObject("Gizmos/DialogOverlay75@2x.png"); + } + } + + public static Texture2D ButtonCubeTexture + { + get + { + return (Texture2D)LoadObject("Gizmos/ButtonCube.png"); + } + } + + public static Texture2D ButtonPrismTexture + { + get + { + return (Texture2D)LoadObject("Gizmos/ButtonPrism.png"); + } + } + + public static Texture2D ButtonCylinderTexture + { + get + { + return (Texture2D)LoadObject("Gizmos/ButtonCylinder.png"); + } + } + + public static Texture2D ButtonSphereTexture + { + get + { + return (Texture2D)LoadObject("Gizmos/ButtonSphere.png"); + } + } public static Texture2D ButtonIcoSphereTexture { @@ -237,13 +247,13 @@ public static Texture2D ButtonIcoSphereTexture } } - public static Texture2D ButtonStairsTexture - { - get - { - return (Texture2D)LoadObject("Gizmos/ButtonStairs.png"); - } - } + public static Texture2D ButtonStairsTexture + { + get + { + return (Texture2D)LoadObject("Gizmos/ButtonStairs.png"); + } + } public static Texture2D ButtonConeTexture { @@ -252,7 +262,7 @@ public static Texture2D ButtonConeTexture return (Texture2D)LoadObject("Gizmos/ButtonCone.png"); } } - + public static Texture2D ButtonCurvedStairsTexture { get @@ -281,7 +291,7 @@ public static Texture2D GroupHeaderRetinaTexture { get { - return (Texture2D)LoadObject("Gizmos/GroupHeader@2x.png"); + return (Texture2D)LoadObject("Gizmos/GroupHeader@2x.png"); } } @@ -461,50 +471,74 @@ public static Texture2D ShapeEditorHomeTexture } } + public static Texture2D ImporterUnrealGoldTexture + { + get + { + return (Texture2D)LoadObject("Gizmos/ImporterUnrealGold.png"); + } + } + + public static Texture2D ImporterImporterValveMapFormat2006Texture + { + get + { + return (Texture2D)LoadObject("Gizmos/ImporterValveMapFormat2006.png"); + } + } + + public static Texture2D ImporterBackgroundTexture + { + get + { + return (Texture2D)LoadObject("Gizmos/ImporterBackground.png"); + } + } + public static Material GetExcludedMaterial() - { - if (excludedMaterial == null) - { - excludedMaterial = new Material(Shader.Find("SabreCSG/SeeExcluded")); - excludedMaterial.hideFlags = HideFlags.HideAndDontSave; - excludedMaterial.shader.hideFlags = HideFlags.HideAndDontSave; - excludedMaterial.mainTexture = (Texture2D)LoadObject("Internal/Excluded.png"); - } - return excludedMaterial; - } - - public static Material GetGreyscaleUIMaterial() - { - if (greyscaleUIMaterial == null) - { - greyscaleUIMaterial = new Material(Shader.Find("Hidden/Grayscale-GUITexture")); - greyscaleUIMaterial.hideFlags = HideFlags.HideAndDontSave; - greyscaleUIMaterial.shader.hideFlags = HideFlags.HideAndDontSave; - } - return greyscaleUIMaterial; - } - - public static Material GetSelectedBrushMaterial() - { - if (selectedBrushMaterial == null) - { - selectedBrushMaterial = new Material(Shader.Find("SabreCSG/Line")); - selectedBrushMaterial.hideFlags = HideFlags.HideAndDontSave; - selectedBrushMaterial.shader.hideFlags = HideFlags.HideAndDontSave; - } - return selectedBrushMaterial; - } - - public static Material GetSelectedBrushDashedMaterial() - { - if (selectedBrushDashedMaterial == null) - { - selectedBrushDashedMaterial = new Material(Shader.Find("SabreCSG/Line Dashed")); - selectedBrushDashedMaterial.hideFlags = HideFlags.HideAndDontSave; - selectedBrushDashedMaterial.shader.hideFlags = HideFlags.HideAndDontSave; - } - return selectedBrushDashedMaterial; - } + { + if (excludedMaterial == null) + { + excludedMaterial = new Material(Shader.Find("SabreCSG/SeeExcluded")); + excludedMaterial.hideFlags = HideFlags.HideAndDontSave; + excludedMaterial.shader.hideFlags = HideFlags.HideAndDontSave; + excludedMaterial.mainTexture = (Texture2D)LoadObject("Internal/Excluded.png"); + } + return excludedMaterial; + } + + public static Material GetGreyscaleUIMaterial() + { + if (greyscaleUIMaterial == null) + { + greyscaleUIMaterial = new Material(Shader.Find("Hidden/Grayscale-GUITexture")); + greyscaleUIMaterial.hideFlags = HideFlags.HideAndDontSave; + greyscaleUIMaterial.shader.hideFlags = HideFlags.HideAndDontSave; + } + return greyscaleUIMaterial; + } + + public static Material GetSelectedBrushMaterial() + { + if (selectedBrushMaterial == null) + { + selectedBrushMaterial = new Material(Shader.Find("SabreCSG/Line")); + selectedBrushMaterial.hideFlags = HideFlags.HideAndDontSave; + selectedBrushMaterial.shader.hideFlags = HideFlags.HideAndDontSave; + } + return selectedBrushMaterial; + } + + public static Material GetSelectedBrushDashedMaterial() + { + if (selectedBrushDashedMaterial == null) + { + selectedBrushDashedMaterial = new Material(Shader.Find("SabreCSG/Line Dashed")); + selectedBrushDashedMaterial.hideFlags = HideFlags.HideAndDontSave; + selectedBrushDashedMaterial.shader.hideFlags = HideFlags.HideAndDontSave; + } + return selectedBrushDashedMaterial; + } public static Material GetSelectedBrushDashedAlphaMaterial() { @@ -518,97 +552,99 @@ public static Material GetSelectedBrushDashedAlphaMaterial() } public static Material GetGizmoMaterial() - { - if (gizmoMaterial == null) - { - Shader shader = Shader.Find("SabreCSG/Handle"); - gizmoMaterial = new Material(shader); - gizmoMaterial.hideFlags = HideFlags.HideAndDontSave; - gizmoMaterial.shader.hideFlags = HideFlags.HideAndDontSave; - gizmoMaterial.mainTexture = (Texture2D)LoadObject("Gizmos/SquareGizmo8x8.png"); - } - return gizmoMaterial; - } - - public static Material GetVertexMaterial() - { - if (vertexMaterial == null) - { - Shader shader = Shader.Find("SabreCSG/Handle"); - vertexMaterial = new Material(shader); - vertexMaterial.hideFlags = HideFlags.HideAndDontSave; - vertexMaterial.shader.hideFlags = HideFlags.HideAndDontSave; - vertexMaterial.mainTexture = (Texture2D)LoadObject("Gizmos/CircleGizmo8x8.png"); - } - return vertexMaterial; - } - - public static Material GetCircleMaterial() - { - if (circleMaterial == null) - { - Shader shader = Shader.Find("SabreCSG/Handle"); - circleMaterial = new Material(shader); - circleMaterial.hideFlags = HideFlags.HideAndDontSave; - circleMaterial.shader.hideFlags = HideFlags.HideAndDontSave; - circleMaterial.mainTexture = (Texture2D)LoadObject("Gizmos/Circle.png"); - } - return circleMaterial; - } - - public static Material GetCircleOutlineMaterial() - { - if (circleOutlineMaterial == null) - { - Shader shader = Shader.Find("SabreCSG/Handle"); - circleOutlineMaterial = new Material(shader); - circleOutlineMaterial.hideFlags = HideFlags.HideAndDontSave; - circleOutlineMaterial.shader.hideFlags = HideFlags.HideAndDontSave; - circleOutlineMaterial.mainTexture = (Texture2D)LoadObject("Gizmos/CircleOutline.png"); - } - return circleOutlineMaterial; - } - - public static Material GetPreviewMaterial() - { - if(previewMaterial == null) - { - Shader shader = Shader.Find("SabreCSG/Preview"); - - previewMaterial = new Material(shader); - previewMaterial.hideFlags = HideFlags.HideAndDontSave; - previewMaterial.shader.hideFlags = HideFlags.HideAndDontSave; - } - - return previewMaterial; - } - - public static Material GetNoCSGMaterial() - { - return (Material)LoadObject("Materials/NoCSG.mat"); - } - - public static Material GetAddMaterial() - { - return (Material)LoadObject("Materials/Add.mat"); - } - - public static Material GetSubtractMaterial() - { - return (Material)LoadObject("Materials/Subtract.mat"); - } - - public static Material GetPlaneMaterial() - { - if (planeMaterial == null) - { - planeMaterial = new Material(Shader.Find("SabreCSG/Plane")); - planeMaterial.hideFlags = HideFlags.HideAndDontSave; - planeMaterial.shader.hideFlags = HideFlags.HideAndDontSave; - } - return planeMaterial; - } -#endregion - } + { + if (gizmoMaterial == null) + { + Shader shader = Shader.Find("SabreCSG/Handle"); + gizmoMaterial = new Material(shader); + gizmoMaterial.hideFlags = HideFlags.HideAndDontSave; + gizmoMaterial.shader.hideFlags = HideFlags.HideAndDontSave; + gizmoMaterial.mainTexture = (Texture2D)LoadObject("Gizmos/SquareGizmo8x8.png"); + } + return gizmoMaterial; + } + + public static Material GetVertexMaterial() + { + if (vertexMaterial == null) + { + Shader shader = Shader.Find("SabreCSG/Handle"); + vertexMaterial = new Material(shader); + vertexMaterial.hideFlags = HideFlags.HideAndDontSave; + vertexMaterial.shader.hideFlags = HideFlags.HideAndDontSave; + vertexMaterial.mainTexture = (Texture2D)LoadObject("Gizmos/CircleGizmo8x8.png"); + } + return vertexMaterial; + } + + public static Material GetCircleMaterial() + { + if (circleMaterial == null) + { + Shader shader = Shader.Find("SabreCSG/Handle"); + circleMaterial = new Material(shader); + circleMaterial.hideFlags = HideFlags.HideAndDontSave; + circleMaterial.shader.hideFlags = HideFlags.HideAndDontSave; + circleMaterial.mainTexture = (Texture2D)LoadObject("Gizmos/Circle.png"); + } + return circleMaterial; + } + + public static Material GetCircleOutlineMaterial() + { + if (circleOutlineMaterial == null) + { + Shader shader = Shader.Find("SabreCSG/Handle"); + circleOutlineMaterial = new Material(shader); + circleOutlineMaterial.hideFlags = HideFlags.HideAndDontSave; + circleOutlineMaterial.shader.hideFlags = HideFlags.HideAndDontSave; + circleOutlineMaterial.mainTexture = (Texture2D)LoadObject("Gizmos/CircleOutline.png"); + } + return circleOutlineMaterial; + } + + public static Material GetPreviewMaterial() + { + if (previewMaterial == null) + { + Shader shader = Shader.Find("SabreCSG/Preview"); + + previewMaterial = new Material(shader); + previewMaterial.hideFlags = HideFlags.HideAndDontSave; + previewMaterial.shader.hideFlags = HideFlags.HideAndDontSave; + } + + return previewMaterial; + } + + public static Material GetNoCSGMaterial() + { + return (Material)LoadObject("Materials/NoCSG.mat"); + } + + public static Material GetAddMaterial() + { + return (Material)LoadObject("Materials/Add.mat"); + } + + public static Material GetSubtractMaterial() + { + return (Material)LoadObject("Materials/Subtract.mat"); + } + + public static Material GetPlaneMaterial() + { + if (planeMaterial == null) + { + planeMaterial = new Material(Shader.Find("SabreCSG/Plane")); + planeMaterial.hideFlags = HideFlags.HideAndDontSave; + planeMaterial.shader.hideFlags = HideFlags.HideAndDontSave; + } + return planeMaterial; + } + + #endregion Accessors + } } + #endif \ No newline at end of file diff --git a/Scripts/UI/SabreGraphics.cs b/Scripts/UI/SabreGraphics.cs index d5878c3e..a23b4a47 100644 --- a/Scripts/UI/SabreGraphics.cs +++ b/Scripts/UI/SabreGraphics.cs @@ -1,47 +1,48 @@ #if UNITY_EDITOR + using UnityEngine; using System.Collections; using UnityEditor; namespace Sabresaurus.SabreCSG { - public static class SabreGraphics - { - // Screen position right at the front (note can't use 1, because even though OSX accepts it Windows doesn't) - public const float FRONT_Z_DEPTH = 0.99f; + public static class SabreGraphics + { + // Screen position right at the front (note can't use 1, because even though OSX accepts it Windows doesn't) + public const float FRONT_Z_DEPTH = 0.99f; - public static void DrawBillboardQuad(Vector3 screenPosition, int width, int height, bool specifiedPoints = true) - { + public static void DrawBillboardQuad(Vector3 screenPosition, int width, int height, bool specifiedPoints = true) + { #if UNITY_5_4_OR_NEWER - if(specifiedPoints) - { - // Convert from points to pixels - float scale = EditorGUIUtility.pixelsPerPoint; - width = Mathf.RoundToInt(scale * width); - height = Mathf.RoundToInt(scale * height); - } + if (specifiedPoints) + { + // Convert from points to pixels + float scale = EditorGUIUtility.pixelsPerPoint; + width = Mathf.RoundToInt(scale * width); + height = Mathf.RoundToInt(scale * height); + } #endif - - screenPosition.z = FRONT_Z_DEPTH; - - GL.TexCoord2(0, 1); // TL - GL.Vertex(screenPosition + new Vector3(-width / 2, -height / 2, 0)); - GL.TexCoord2(1, 1); // TR - GL.Vertex(screenPosition + new Vector3(width / 2, -height / 2, 0)); - GL.TexCoord2(1, 0); // BR - GL.Vertex(screenPosition + new Vector3(width / 2, height / 2, 0)); - GL.TexCoord2(0, 0); // BL - GL.Vertex(screenPosition + new Vector3(-width / 2, height / 2, 0)); - } - - public static void DrawScreenLine (Vector3 screenPosition1, Vector3 screenPosition2) - { - screenPosition1.z = FRONT_Z_DEPTH; - GL.Vertex(screenPosition1); - - screenPosition2.z = FRONT_Z_DEPTH; - GL.Vertex(screenPosition2); - } + + screenPosition.z = FRONT_Z_DEPTH; + + GL.TexCoord2(0, 1); // TL + GL.Vertex(screenPosition + new Vector3(-width / 2, -height / 2, 0)); + GL.TexCoord2(1, 1); // TR + GL.Vertex(screenPosition + new Vector3(width / 2, -height / 2, 0)); + GL.TexCoord2(1, 0); // BR + GL.Vertex(screenPosition + new Vector3(width / 2, height / 2, 0)); + GL.TexCoord2(0, 0); // BL + GL.Vertex(screenPosition + new Vector3(-width / 2, height / 2, 0)); + } + + public static void DrawScreenLine(Vector3 screenPosition1, Vector3 screenPosition2) + { + screenPosition1.z = FRONT_Z_DEPTH; + GL.Vertex(screenPosition1); + + screenPosition2.z = FRONT_Z_DEPTH; + GL.Vertex(screenPosition2); + } public static void DrawScreenLineDashed(Vector3 screenPosition1, Vector3 screenPosition2) { @@ -54,492 +55,551 @@ public static void DrawScreenLineDashed(Vector3 screenPosition1, Vector3 screenP GL.Vertex(screenPosition2); } - public static void DrawScreenRectFill (Rect rect) - { - Vector3 topLeft = new Vector3(rect.xMin,rect.yMin, FRONT_Z_DEPTH); - Vector3 topRight = new Vector3(rect.xMax, rect.yMin, FRONT_Z_DEPTH); - Vector3 bottomLeft = new Vector3(rect.xMin, rect.yMax, FRONT_Z_DEPTH); - Vector3 bottomRight = new Vector3(rect.xMax, rect.yMax, FRONT_Z_DEPTH); - - GL.Vertex(topLeft); - GL.Vertex(topRight); - GL.Vertex(bottomRight); - GL.Vertex(bottomLeft); - - GL.Vertex(bottomLeft); - GL.Vertex(bottomRight); - GL.Vertex(topRight); - GL.Vertex(topLeft); - } - - public static void DrawScreenRectOuter (Rect rect) - { - Vector3 topLeft = new Vector3(rect.xMin,rect.yMin, FRONT_Z_DEPTH); - Vector3 topRight = new Vector3(rect.xMax, rect.yMin, FRONT_Z_DEPTH); - Vector3 bottomLeft = new Vector3(rect.xMin, rect.yMax, FRONT_Z_DEPTH); - Vector3 bottomRight = new Vector3(rect.xMax, rect.yMax, FRONT_Z_DEPTH); - - GL.Vertex(topLeft); - GL.Vertex(topRight); - - GL.Vertex(bottomLeft); - GL.Vertex(bottomRight); - - GL.Vertex(topLeft); - GL.Vertex(bottomLeft); - - GL.Vertex(bottomRight); - GL.Vertex(topRight); - } - - public static void DrawBox(Bounds bounds, Transform transform = null) - { - Vector3 center = bounds.center; - - // Calculate each of the transformed axis with their corresponding length - Vector3 up = Vector3.up * bounds.extents.y; - Vector3 right = Vector3.right * bounds.extents.x; - Vector3 forward = Vector3.forward * bounds.extents.z; - - if(transform != null) - { - center = transform.TransformPoint(bounds.center); - - // Calculate each of the transformed axis with their corresponding length - up = transform.TransformVector(Vector3.up) * bounds.extents.y; - right = transform.TransformVector(Vector3.right) * bounds.extents.x; - forward = transform.TransformVector(Vector3.forward) * bounds.extents.z; - } - - // Verticals - GL.Vertex(center - right - forward + up); - GL.Vertex(center - right - forward - up); - GL.Vertex(center - right + forward + up); - GL.Vertex(center - right + forward - up); - GL.Vertex(center + right - forward + up); - GL.Vertex(center + right - forward - up); - GL.Vertex(center + right + forward + up); - GL.Vertex(center + right + forward - up); - - // Horizontal - forward/back - GL.Vertex(center - right + forward - up); - GL.Vertex(center - right - forward - up); - GL.Vertex(center + right + forward - up); - GL.Vertex(center + right - forward - up); - GL.Vertex(center - right + forward + up); - GL.Vertex(center - right - forward + up); - GL.Vertex(center + right + forward + up); - GL.Vertex(center + right - forward + up); - - // Horizontal - right/left - GL.Vertex(center + right - forward - up); - GL.Vertex(center - right - forward - up); - GL.Vertex(center + right + forward - up); - GL.Vertex(center - right + forward - up); - GL.Vertex(center + right - forward + up); - GL.Vertex(center - right - forward + up); - GL.Vertex(center + right + forward + up); - GL.Vertex(center - right + forward + up); - } - - public static void DrawPlane(UnityEngine.Plane plane, Vector3 center, Color colorFront, Color colorBack, float size) - { - SabreCSGResources.GetPlaneMaterial().SetPass(0); - - GL.Begin(GL.QUADS); - - Vector3 normal = plane.normal.normalized; - Vector3 tangent; - - if (normal == Vector3.up || normal == Vector3.down) - { - tangent = Vector3.Cross(normal, Vector3.forward).normalized; - } - else - { - tangent = Vector3.Cross(normal, Vector3.up).normalized; - } - - Vector3 binormal = Quaternion.AngleAxis(90, normal) * tangent; - - // GL.Color(colorFront); - // GL.Vertex(center + (normal * -plane.distance) - tangent * size - binormal * size); - // GL.Vertex(center + (normal * -plane.distance) + tangent * size - binormal * size); - // GL.Vertex(center + (normal * -plane.distance) + tangent * size + binormal * size); - // GL.Vertex(center + (normal * -plane.distance) - tangent * size + binormal * size); - // - // GL.Color(colorBack); - // GL.Vertex(center + (normal * -plane.distance) - tangent * size + binormal * size); - // GL.Vertex(center + (normal * -plane.distance) + tangent * size + binormal * size); - // GL.Vertex(center + (normal * -plane.distance) + tangent * size - binormal * size); - // GL.Vertex(center + (normal * -plane.distance) - tangent * size - binormal * size); - - GL.Color(colorFront); - GL.Vertex(center - tangent * size - binormal * size); - GL.Vertex(center + tangent * size - binormal * size); - GL.Vertex(center + tangent * size + binormal * size); - GL.Vertex(center - tangent * size + binormal * size); - - GL.Color(colorBack); - GL.Vertex(center - tangent * size + binormal * size); - GL.Vertex(center + tangent * size + binormal * size); - GL.Vertex(center + tangent * size - binormal * size); - GL.Vertex(center - tangent * size - binormal * size); - - GL.End(); - - - GL.Begin(GL.LINES); - - GL.Color(Color.white); - - GL.Vertex(center - tangent * size + binormal * size); - GL.Vertex(center + tangent * size + binormal * size); - - GL.Vertex(center + tangent * size + binormal * size); - GL.Vertex(center + tangent * size - binormal * size); - - GL.Vertex(center + tangent * size - binormal * size); - GL.Vertex(center - tangent * size - binormal * size); - - GL.Vertex(center - tangent * size - binormal * size); - GL.Vertex(center - tangent * size + binormal * size); - - GL.Color(Color.green); - - Vector3 normalOffset = -normal * 0.01f; - - GL.Vertex(center + normalOffset - tangent * size + binormal * size); - GL.Vertex(center + normalOffset + tangent * size + binormal * size); - - GL.Vertex(center + normalOffset + tangent * size + binormal * size); - GL.Vertex(center + normalOffset + tangent * size - binormal * size); - - GL.Vertex(center + normalOffset + tangent * size - binormal * size); - GL.Vertex(center + normalOffset - tangent * size - binormal * size); - - GL.Vertex(center + normalOffset - tangent * size - binormal * size); - GL.Vertex(center + normalOffset - tangent * size + binormal * size); - - GL.Color(Color.red); - - normalOffset = normal * 0.01f; - - GL.Vertex(center + normalOffset - tangent * size + binormal * size); - GL.Vertex(center + normalOffset + tangent * size + binormal * size); - - GL.Vertex(center + normalOffset + tangent * size + binormal * size); - GL.Vertex(center + normalOffset + tangent * size - binormal * size); - - GL.Vertex(center + normalOffset + tangent * size - binormal * size); - GL.Vertex(center + normalOffset - tangent * size - binormal * size); - - GL.Vertex(center + normalOffset - tangent * size - binormal * size); - GL.Vertex(center + normalOffset - tangent * size + binormal * size); - - GL.End(); - } - - public static void DrawRotationCircle(Vector3 worldCenter, Vector3 normal, float radius, Vector3 initialRotationDirection) - { - Vector3 tangent; - - if (normal == Vector3.up || normal == Vector3.down) - { - tangent = Vector3.Cross(normal, Vector3.forward).normalized; - } - else - { - tangent = Vector3.Cross(normal, Vector3.up).normalized; - } - - Vector3 binormal = Quaternion.AngleAxis(90, normal) * tangent; - - // Scale the tangent and binormal by the radius - binormal *= radius; - tangent *= radius; - - int count = 30; - float deltaAngle = (2f * Mathf.PI) / count; - - GL.Begin(GL.TRIANGLES); - GL.Color(new Color(1,0,1,0.3f)); - - for (int i = 0; i < count; i++) - { - GL.Vertex(worldCenter); - GL.Vertex(worldCenter + tangent * Mathf.Sin(i * deltaAngle) + binormal * Mathf.Cos(i * deltaAngle)); - GL.Vertex(worldCenter + tangent * Mathf.Sin((i+1) * deltaAngle) + binormal * Mathf.Cos((i+1) * deltaAngle)); - } - GL.End(); - - - GL.Begin(GL.LINES); - GL.Color(Color.magenta); - - for (int i = 0; i < count; i++) - { - GL.Vertex(worldCenter + tangent * Mathf.Sin(i * deltaAngle) + binormal * Mathf.Cos(i * deltaAngle)); - GL.Vertex(worldCenter + tangent * Mathf.Sin((i+1) * deltaAngle) + binormal * Mathf.Cos((i+1) * deltaAngle)); - } - GL.End(); - - if(CurrentSettings.AngleSnappingEnabled) - { - Quaternion cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(normal)); - Vector3 planarInitialDirection = cancellingRotation * initialRotationDirection; - float angleOffset = Mathf.Atan2(planarInitialDirection.x,planarInitialDirection.y); - - float angleSnapDistance = CurrentSettings.AngleSnapDistance; - - count = (int)(360f / angleSnapDistance); - deltaAngle = (2f * Mathf.PI) / count; - - bool divisorOf90 = ((90 % angleSnapDistance) == 0); - - GL.Begin(GL.LINES); - GL.Color(Color.white); - - for (int i = 0; i < count; i++) - { - float totalDeltaAngleDeg = i * angleSnapDistance; - GL.Vertex(worldCenter + tangent * Mathf.Sin(angleOffset + i * deltaAngle) + binormal * Mathf.Cos(angleOffset + i * deltaAngle)); - if(divisorOf90 && (totalDeltaAngleDeg % 90) == 0) - { - GL.Vertex(worldCenter + 0.7f * tangent * Mathf.Sin(angleOffset + i * deltaAngle) + 0.7f * binormal * Mathf.Cos(angleOffset + i * deltaAngle)); - } - else - { - GL.Vertex(worldCenter + 0.9f * tangent * Mathf.Sin(angleOffset + i * deltaAngle) + 0.9f * binormal * Mathf.Cos(angleOffset + i * deltaAngle)); - } - } - GL.End(); - - // Draw a line showing the initial rotation angle, so the user can compare their current angle to it - GL.Begin(GL.LINES); - GL.Color(Color.yellow); - - GL.Vertex(worldCenter); - GL.Vertex(worldCenter + initialRotationDirection); - - GL.End(); - } - } - - public static void DrawPolygons(Color color, Transform transform, params Polygon[] polygons) - { - GL.Begin(GL.LINES); - GL.Color(color); - - for (int j = 0; j < polygons.Length; j++) - { - Polygon polygon = polygons[j]; - for (int i = 0; i < polygon.Vertices.Length - 1; i++) - { - GL.Vertex(transform.TransformPoint(polygon.Vertices[i].Position)); - GL.Vertex(transform.TransformPoint(polygon.Vertices[i + 1].Position)); - } - GL.Vertex(transform.TransformPoint(polygon.Vertices[polygon.Vertices.Length - 1].Position)); - GL.Vertex(transform.TransformPoint(polygon.Vertices[0].Position)); - } - - GL.End(); - - GL.Begin(GL.TRIANGLES); - color.a = 0.3f; - GL.Color(color); - - for (int j = 0; j < polygons.Length; j++) - { - Polygon polygon = polygons[j]; - Vector3 position1 = polygon.Vertices[0].Position; - - for (int i = 1; i < polygon.Vertices.Length - 1; i++) - { - GL.Vertex(transform.TransformPoint(position1)); - GL.Vertex(transform.TransformPoint(polygon.Vertices[i].Position)); - GL.Vertex(transform.TransformPoint(polygon.Vertices[i + 1].Position)); - } - } - GL.End(); - } - - public static void DrawPolygons(Color faceColor, Color outlineColor, params Polygon[] polygons) - { - GL.Begin(GL.LINES); - GL.Color(outlineColor); - - for (int j = 0; j < polygons.Length; j++) - { + public static void DrawScreenRectFill(Rect rect) + { + Vector3 topLeft = new Vector3(rect.xMin, rect.yMin, FRONT_Z_DEPTH); + Vector3 topRight = new Vector3(rect.xMax, rect.yMin, FRONT_Z_DEPTH); + Vector3 bottomLeft = new Vector3(rect.xMin, rect.yMax, FRONT_Z_DEPTH); + Vector3 bottomRight = new Vector3(rect.xMax, rect.yMax, FRONT_Z_DEPTH); + + GL.Vertex(topLeft); + GL.Vertex(topRight); + GL.Vertex(bottomRight); + GL.Vertex(bottomLeft); + + GL.Vertex(bottomLeft); + GL.Vertex(bottomRight); + GL.Vertex(topRight); + GL.Vertex(topLeft); + } + + public static void DrawScreenRectOuter(Rect rect) + { + Vector3 topLeft = new Vector3(rect.xMin, rect.yMin, FRONT_Z_DEPTH); + Vector3 topRight = new Vector3(rect.xMax, rect.yMin, FRONT_Z_DEPTH); + Vector3 bottomLeft = new Vector3(rect.xMin, rect.yMax, FRONT_Z_DEPTH); + Vector3 bottomRight = new Vector3(rect.xMax, rect.yMax, FRONT_Z_DEPTH); + + GL.Vertex(topLeft); + GL.Vertex(topRight); + + GL.Vertex(bottomLeft); + GL.Vertex(bottomRight); + + GL.Vertex(topLeft); + GL.Vertex(bottomLeft); + + GL.Vertex(bottomRight); + GL.Vertex(topRight); + } + + public static void DrawBox(Bounds bounds, Transform transform = null) + { + Vector3 center = bounds.center; + + // Calculate each of the transformed axis with their corresponding length + Vector3 up = Vector3.up * bounds.extents.y; + Vector3 right = Vector3.right * bounds.extents.x; + Vector3 forward = Vector3.forward * bounds.extents.z; + + if (transform != null) + { + center = transform.TransformPoint(bounds.center); + + // Calculate each of the transformed axis with their corresponding length + up = transform.TransformVector(Vector3.up) * bounds.extents.y; + right = transform.TransformVector(Vector3.right) * bounds.extents.x; + forward = transform.TransformVector(Vector3.forward) * bounds.extents.z; + } + + // Verticals + GL.Vertex(center - right - forward + up); + GL.Vertex(center - right - forward - up); + GL.Vertex(center - right + forward + up); + GL.Vertex(center - right + forward - up); + GL.Vertex(center + right - forward + up); + GL.Vertex(center + right - forward - up); + GL.Vertex(center + right + forward + up); + GL.Vertex(center + right + forward - up); + + // Horizontal - forward/back + GL.Vertex(center - right + forward - up); + GL.Vertex(center - right - forward - up); + GL.Vertex(center + right + forward - up); + GL.Vertex(center + right - forward - up); + GL.Vertex(center - right + forward + up); + GL.Vertex(center - right - forward + up); + GL.Vertex(center + right + forward + up); + GL.Vertex(center + right - forward + up); + + // Horizontal - right/left + GL.Vertex(center + right - forward - up); + GL.Vertex(center - right - forward - up); + GL.Vertex(center + right + forward - up); + GL.Vertex(center - right + forward - up); + GL.Vertex(center + right - forward + up); + GL.Vertex(center - right - forward + up); + GL.Vertex(center + right + forward + up); + GL.Vertex(center - right + forward + up); + } + + public static void DrawBoxGuideLines(Bounds bounds, float length, Transform transform = null) + { + Vector3 center = bounds.center; + + // Calculate each of the transformed axis with their corresponding length + Vector3 up = Vector3.up * bounds.extents.y; + Vector3 right = Vector3.right * bounds.extents.x; + Vector3 forward = Vector3.forward * bounds.extents.z; + + Vector3 gup = Vector3.up * length; + Vector3 gright = Vector3.right * length; + Vector3 gforward = Vector3.forward * length; + + Color transparentr = new Color(1.0f, 0.0f, 0.0f, 0.35f); + Color transparentg = new Color(0.0f, 1.0f, 0.0f, 0.35f); + Color transparentb = new Color(0.0f, 0.0f, 1.0f, 0.35f); + + if (transform != null) + { + center = transform.TransformPoint(bounds.center); + + // Calculate each of the transformed axis with their corresponding length + up = transform.TransformVector(Vector3.up) * bounds.extents.y; + right = transform.TransformVector(Vector3.right) * bounds.extents.x; + forward = transform.TransformVector(Vector3.forward) * bounds.extents.z; + + gup = transform.TransformVector(Vector3.up) * length; + gright = transform.TransformVector(Vector3.right) * length; + gforward = transform.TransformVector(Vector3.forward) * length; + } + + // Vertical Guide Lines + GL.Color(Color.green); GL.Vertex(center - right - forward + up); GL.Color(transparentg); GL.Vertex(center - right - forward + up + gup); + GL.Color(Color.green); GL.Vertex(center - right - forward - up); GL.Color(transparentg); GL.Vertex(center - right - forward - up - gup); + GL.Color(Color.green); GL.Vertex(center - right + forward + up); GL.Color(transparentg); GL.Vertex(center - right + forward + up + gup); + GL.Color(Color.green); GL.Vertex(center - right + forward - up); GL.Color(transparentg); GL.Vertex(center - right + forward - up - gup); + GL.Color(Color.green); GL.Vertex(center + right - forward + up); GL.Color(transparentg); GL.Vertex(center + right - forward + up + gup); + GL.Color(Color.green); GL.Vertex(center + right - forward - up); GL.Color(transparentg); GL.Vertex(center + right - forward - up - gup); + GL.Color(Color.green); GL.Vertex(center + right + forward + up); GL.Color(transparentg); GL.Vertex(center + right + forward + up + gup); + GL.Color(Color.green); GL.Vertex(center + right + forward - up); GL.Color(transparentg); GL.Vertex(center + right + forward - up - gup); + + // Horizontal Guide Lines - forward/back + GL.Color(Color.blue); GL.Vertex(center - right + forward - up); GL.Color(transparentb); GL.Vertex(center - right + forward - up + gforward); + GL.Color(Color.blue); GL.Vertex(center - right - forward - up); GL.Color(transparentb); GL.Vertex(center - right - forward - up - gforward); + GL.Color(Color.blue); GL.Vertex(center + right + forward - up); GL.Color(transparentb); GL.Vertex(center + right + forward - up + gforward); + GL.Color(Color.blue); GL.Vertex(center + right - forward - up); GL.Color(transparentb); GL.Vertex(center + right - forward - up - gforward); + GL.Color(Color.blue); GL.Vertex(center - right + forward + up); GL.Color(transparentb); GL.Vertex(center - right + forward + up + gforward); + GL.Color(Color.blue); GL.Vertex(center - right - forward + up); GL.Color(transparentb); GL.Vertex(center - right - forward + up - gforward); + GL.Color(Color.blue); GL.Vertex(center + right + forward + up); GL.Color(transparentb); GL.Vertex(center + right + forward + up + gforward); + GL.Color(Color.blue); GL.Vertex(center + right - forward + up); GL.Color(transparentb); GL.Vertex(center + right - forward + up - gforward); + + // Horizontal Guide Lines - right/left + GL.Color(Color.red); GL.Vertex(center + right - forward - up); GL.Color(transparentr); GL.Vertex(center + right - forward - up + gright); + GL.Color(Color.red); GL.Vertex(center - right - forward - up); GL.Color(transparentr); GL.Vertex(center - right - forward - up - gright); + GL.Color(Color.red); GL.Vertex(center + right + forward - up); GL.Color(transparentr); GL.Vertex(center + right + forward - up + gright); + GL.Color(Color.red); GL.Vertex(center - right + forward - up); GL.Color(transparentr); GL.Vertex(center - right + forward - up - gright); + GL.Color(Color.red); GL.Vertex(center + right - forward + up); GL.Color(transparentr); GL.Vertex(center + right - forward + up + gright); + GL.Color(Color.red); GL.Vertex(center - right - forward + up); GL.Color(transparentr); GL.Vertex(center - right - forward + up - gright); + GL.Color(Color.red); GL.Vertex(center + right + forward + up); GL.Color(transparentr); GL.Vertex(center + right + forward + up + gright); + GL.Color(Color.red); GL.Vertex(center - right + forward + up); GL.Color(transparentr); GL.Vertex(center - right + forward + up - gright); + } + + public static void DrawPlane(UnityEngine.Plane plane, Vector3 center, Color colorFront, Color colorBack, float size) + { + SabreCSGResources.GetPlaneMaterial().SetPass(0); + + GL.Begin(GL.QUADS); + + Vector3 normal = plane.normal.normalized; + Vector3 tangent; + + if (normal == Vector3.up || normal == Vector3.down) + { + tangent = Vector3.Cross(normal, Vector3.forward).normalized; + } + else + { + tangent = Vector3.Cross(normal, Vector3.up).normalized; + } + + Vector3 binormal = Quaternion.AngleAxis(90, normal) * tangent; + + // GL.Color(colorFront); + // GL.Vertex(center + (normal * -plane.distance) - tangent * size - binormal * size); + // GL.Vertex(center + (normal * -plane.distance) + tangent * size - binormal * size); + // GL.Vertex(center + (normal * -plane.distance) + tangent * size + binormal * size); + // GL.Vertex(center + (normal * -plane.distance) - tangent * size + binormal * size); + // + // GL.Color(colorBack); + // GL.Vertex(center + (normal * -plane.distance) - tangent * size + binormal * size); + // GL.Vertex(center + (normal * -plane.distance) + tangent * size + binormal * size); + // GL.Vertex(center + (normal * -plane.distance) + tangent * size - binormal * size); + // GL.Vertex(center + (normal * -plane.distance) - tangent * size - binormal * size); + + GL.Color(colorFront); + GL.Vertex(center - tangent * size - binormal * size); + GL.Vertex(center + tangent * size - binormal * size); + GL.Vertex(center + tangent * size + binormal * size); + GL.Vertex(center - tangent * size + binormal * size); + + GL.Color(colorBack); + GL.Vertex(center - tangent * size + binormal * size); + GL.Vertex(center + tangent * size + binormal * size); + GL.Vertex(center + tangent * size - binormal * size); + GL.Vertex(center - tangent * size - binormal * size); + + GL.End(); + + GL.Begin(GL.LINES); + + GL.Color(Color.white); + + GL.Vertex(center - tangent * size + binormal * size); + GL.Vertex(center + tangent * size + binormal * size); + + GL.Vertex(center + tangent * size + binormal * size); + GL.Vertex(center + tangent * size - binormal * size); + + GL.Vertex(center + tangent * size - binormal * size); + GL.Vertex(center - tangent * size - binormal * size); + + GL.Vertex(center - tangent * size - binormal * size); + GL.Vertex(center - tangent * size + binormal * size); + + GL.Color(Color.green); + + Vector3 normalOffset = -normal * 0.01f; + + GL.Vertex(center + normalOffset - tangent * size + binormal * size); + GL.Vertex(center + normalOffset + tangent * size + binormal * size); + + GL.Vertex(center + normalOffset + tangent * size + binormal * size); + GL.Vertex(center + normalOffset + tangent * size - binormal * size); + + GL.Vertex(center + normalOffset + tangent * size - binormal * size); + GL.Vertex(center + normalOffset - tangent * size - binormal * size); + + GL.Vertex(center + normalOffset - tangent * size - binormal * size); + GL.Vertex(center + normalOffset - tangent * size + binormal * size); + + GL.Color(Color.red); + + normalOffset = normal * 0.01f; + + GL.Vertex(center + normalOffset - tangent * size + binormal * size); + GL.Vertex(center + normalOffset + tangent * size + binormal * size); + + GL.Vertex(center + normalOffset + tangent * size + binormal * size); + GL.Vertex(center + normalOffset + tangent * size - binormal * size); + + GL.Vertex(center + normalOffset + tangent * size - binormal * size); + GL.Vertex(center + normalOffset - tangent * size - binormal * size); + + GL.Vertex(center + normalOffset - tangent * size - binormal * size); + GL.Vertex(center + normalOffset - tangent * size + binormal * size); + + GL.End(); + } + + public static void DrawRotationCircle(Vector3 worldCenter, Vector3 normal, float radius, Vector3 initialRotationDirection) + { + Vector3 tangent; + + if (normal == Vector3.up || normal == Vector3.down) + { + tangent = Vector3.Cross(normal, Vector3.forward).normalized; + } + else + { + tangent = Vector3.Cross(normal, Vector3.up).normalized; + } + + Vector3 binormal = Quaternion.AngleAxis(90, normal) * tangent; + + // Scale the tangent and binormal by the radius + binormal *= radius; + tangent *= radius; + + int count = 30; + float deltaAngle = (2f * Mathf.PI) / count; + + GL.Begin(GL.TRIANGLES); + GL.Color(new Color(1, 0, 1, 0.3f)); + + for (int i = 0; i < count; i++) + { + GL.Vertex(worldCenter); + GL.Vertex(worldCenter + tangent * Mathf.Sin(i * deltaAngle) + binormal * Mathf.Cos(i * deltaAngle)); + GL.Vertex(worldCenter + tangent * Mathf.Sin((i + 1) * deltaAngle) + binormal * Mathf.Cos((i + 1) * deltaAngle)); + } + GL.End(); + + GL.Begin(GL.LINES); + GL.Color(Color.magenta); + + for (int i = 0; i < count; i++) + { + GL.Vertex(worldCenter + tangent * Mathf.Sin(i * deltaAngle) + binormal * Mathf.Cos(i * deltaAngle)); + GL.Vertex(worldCenter + tangent * Mathf.Sin((i + 1) * deltaAngle) + binormal * Mathf.Cos((i + 1) * deltaAngle)); + } + GL.End(); + + if (CurrentSettings.AngleSnappingEnabled) + { + Quaternion cancellingRotation = Quaternion.Inverse(Quaternion.LookRotation(normal)); + Vector3 planarInitialDirection = cancellingRotation * initialRotationDirection; + float angleOffset = Mathf.Atan2(planarInitialDirection.x, planarInitialDirection.y); + + float angleSnapDistance = CurrentSettings.AngleSnapDistance; + + count = (int)(360f / angleSnapDistance); + deltaAngle = (2f * Mathf.PI) / count; + + bool divisorOf90 = ((90 % angleSnapDistance) == 0); + + GL.Begin(GL.LINES); + GL.Color(Color.white); + + for (int i = 0; i < count; i++) + { + float totalDeltaAngleDeg = i * angleSnapDistance; + GL.Vertex(worldCenter + tangent * Mathf.Sin(angleOffset + i * deltaAngle) + binormal * Mathf.Cos(angleOffset + i * deltaAngle)); + if (divisorOf90 && (totalDeltaAngleDeg % 90) == 0) + { + GL.Vertex(worldCenter + 0.7f * tangent * Mathf.Sin(angleOffset + i * deltaAngle) + 0.7f * binormal * Mathf.Cos(angleOffset + i * deltaAngle)); + } + else + { + GL.Vertex(worldCenter + 0.9f * tangent * Mathf.Sin(angleOffset + i * deltaAngle) + 0.9f * binormal * Mathf.Cos(angleOffset + i * deltaAngle)); + } + } + GL.End(); + + // Draw a line showing the initial rotation angle, so the user can compare their current angle to it + GL.Begin(GL.LINES); + GL.Color(Color.yellow); + + GL.Vertex(worldCenter); + GL.Vertex(worldCenter + initialRotationDirection); + + GL.End(); + } + } + + public static void DrawPolygons(Color color, Transform transform, params Polygon[] polygons) + { + GL.Begin(GL.LINES); + GL.Color(color); + + for (int j = 0; j < polygons.Length; j++) + { + Polygon polygon = polygons[j]; + for (int i = 0; i < polygon.Vertices.Length - 1; i++) + { + GL.Vertex(transform.TransformPoint(polygon.Vertices[i].Position)); + GL.Vertex(transform.TransformPoint(polygon.Vertices[i + 1].Position)); + } + GL.Vertex(transform.TransformPoint(polygon.Vertices[polygon.Vertices.Length - 1].Position)); + GL.Vertex(transform.TransformPoint(polygon.Vertices[0].Position)); + } + + GL.End(); + + GL.Begin(GL.TRIANGLES); + color.a = 0.3f; + GL.Color(color); + + for (int j = 0; j < polygons.Length; j++) + { + Polygon polygon = polygons[j]; + Vector3 position1 = polygon.Vertices[0].Position; + + for (int i = 1; i < polygon.Vertices.Length - 1; i++) + { + GL.Vertex(transform.TransformPoint(position1)); + GL.Vertex(transform.TransformPoint(polygon.Vertices[i].Position)); + GL.Vertex(transform.TransformPoint(polygon.Vertices[i + 1].Position)); + } + } + GL.End(); + } + + public static void DrawPolygons(Color faceColor, Color outlineColor, params Polygon[] polygons) + { + GL.Begin(GL.LINES); + GL.Color(outlineColor); + + for (int j = 0; j < polygons.Length; j++) + { Vector3 offset = polygons[j].Plane.normal * 0.001f; Polygon polygon = polygons[j]; - for (int i = 0; i < polygon.Vertices.Length - 1; i++) - { - GL.Vertex(polygon.Vertices[i].Position + offset); - GL.Vertex(polygon.Vertices[i + 1].Position + offset); - } - GL.Vertex(polygon.Vertices[polygon.Vertices.Length - 1].Position + offset); - GL.Vertex(polygon.Vertices[0].Position + offset); - } - - GL.End(); - - GL.Begin(GL.TRIANGLES); - GL.Color(faceColor); - - - - for (int j = 0; j < polygons.Length; j++) - { + for (int i = 0; i < polygon.Vertices.Length - 1; i++) + { + GL.Vertex(polygon.Vertices[i].Position + offset); + GL.Vertex(polygon.Vertices[i + 1].Position + offset); + } + GL.Vertex(polygon.Vertices[polygon.Vertices.Length - 1].Position + offset); + GL.Vertex(polygon.Vertices[0].Position + offset); + } + + GL.End(); + + GL.Begin(GL.TRIANGLES); + GL.Color(faceColor); + + for (int j = 0; j < polygons.Length; j++) + { Vector3 offset = polygons[j].Plane.normal * 0.001f; Polygon polygon = polygons[j]; - Vector3 position1 = polygon.Vertices[0].Position; - - for (int i = 1; i < polygon.Vertices.Length - 1; i++) - { - GL.Vertex(position1 + offset); - GL.Vertex(polygon.Vertices[i].Position + offset); - GL.Vertex(polygon.Vertices[i + 1].Position + offset); - } - } - GL.End(); - } - - public static void DrawPolygonsNoOutline(Color color, params Polygon[] polygons) - { - GL.Begin(GL.TRIANGLES); - - GL.Color(color); - - for (int j = 0; j < polygons.Length; j++) - { - Polygon polygon = polygons[j]; - Vector3 position1 = polygon.Vertices[0].Position; - - for (int i = 1; i < polygon.Vertices.Length - 1; i++) - { - GL.Vertex(position1); - GL.Vertex(polygon.Vertices[i].Position); - GL.Vertex(polygon.Vertices[i + 1].Position); - } - } - GL.End(); - } - - public static void DrawPolygonsOutline(Color color, params Polygon[] polygons) - { - Vector3 depthAdjust = -0.01f * SceneView.currentDrawingSceneView.camera.transform.forward; - GL.Begin(GL.LINES); - - for (int j = 0; j < polygons.Length; j++) - { - Polygon polygon = polygons[j]; - - GL.Color(color); - - for (int i = 0; i < polygon.Vertices.Length; i++) - { - Vector3 currentPosition = polygon.Vertices[i].Position + depthAdjust; - Vector3 nextPosition = polygon.Vertices[(i + 1)%polygon.Vertices.Length].Position + depthAdjust; - - GL.Vertex(currentPosition); - GL.Vertex(nextPosition); - } - } - - GL.End(); - } - - public static void DrawPolygonsOutlineDashed(Color color, params Polygon[] polygons) - { - Vector3 depthAdjust = -0.01f * SceneView.currentDrawingSceneView.camera.transform.forward; - GL.Begin(GL.LINES); - - for (int j = 0; j < polygons.Length; j++) - { - Polygon polygon = polygons[j]; - - GL.Color(color); - - for (int i = 0; i < polygon.Vertices.Length; i++) - { - Vector3 currentPosition = polygon.Vertices[i].Position + depthAdjust; - Vector3 nextPosition = polygon.Vertices[(i + 1)%polygon.Vertices.Length].Position + depthAdjust; - - GL.TexCoord2(0,0); - GL.Vertex(currentPosition); - GL.TexCoord2(Vector3.Distance(nextPosition,currentPosition),0); - GL.Vertex(nextPosition); - } - } - - GL.End(); - } - - public static void DrawMarquee(Vector2 marqueeStart, Vector2 marqueeEnd) - { - Vector2 point1 = EditorHelper.ConvertMousePointPosition(marqueeStart); - Vector2 point2 = EditorHelper.ConvertMousePointPosition(marqueeEnd); - - Rect rect = new Rect(point1.x, point1.y, point2.x - point1.x, point2.y - point1.y); - - SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); - - GL.PushMatrix(); - GL.LoadPixelMatrix(); - - GL.Begin(GL.QUADS); - GL.Color(new Color(0.2f, 0.3f, 0.8f, 0.3f)); - - // Marquee fill (draw double sided) - SabreGraphics.DrawScreenRectFill(rect); - - GL.End(); - - // Marquee border - GL.Begin(GL.LINES); - GL.Color(Color.white); - - // Draw marquee box edges - SabreGraphics.DrawScreenRectOuter(rect); - - GL.End(); - GL.PopMatrix(); - } - -// public static void DrawThickLineTest(Vector3 testPoint1, Vector3 testPoint2, float width) -// { -// Camera sceneViewCamera = UnityEditor.SceneView.currentDrawingSceneView.camera; -// -//// Vector3 screenPoint1 = sceneViewCamera.WorldToScreenPoint(testPoint1); -//// Vector3 screenPoint2 = sceneViewCamera.WorldToScreenPoint(testPoint2); -// -//// Vector3 perpendicular = new Vector3(screenPoint2.x - screenPoint1.x, screenPoint1.y - screenPoint2.y, screenPoint1.z).normalized; -// -//// Vector3 up = sceneViewCamera.transform.up; -// Vector3 forward = sceneViewCamera.transform.forward * 0.01f; -// -// Vector3 cameraVector = sceneViewCamera.transform.position - (testPoint1 + testPoint2)/2f; -// Vector3 lineVector = testPoint2 - testPoint1; -// -// Vector3 up = Vector3.Cross(cameraVector.normalized, lineVector.normalized); -// -//// Vector3 up = Quaternion.LookRotation(sceneViewCamera.transform.forward, sceneViewCamera.transform.up) * Vector3.up; -// -// GL.Color(Color.black); -// GL.Vertex(testPoint1 + up * width - forward); -// GL.Vertex(testPoint1 - up * width - forward); -// GL.Vertex(testPoint2 - up * width - forward); -// GL.Vertex(testPoint2 + up * width - forward); -// -// GL.Color(Color.green); -// GL.Vertex(testPoint1 + up * width/2 - forward); -// GL.Vertex(testPoint1 - up * width/2 - forward); -// GL.Vertex(testPoint2 - up * width/2 - forward); -// GL.Vertex(testPoint2 + up * width/2 - forward); -// } - } + Vector3 position1 = polygon.Vertices[0].Position; + + for (int i = 1; i < polygon.Vertices.Length - 1; i++) + { + GL.Vertex(position1 + offset); + GL.Vertex(polygon.Vertices[i].Position + offset); + GL.Vertex(polygon.Vertices[i + 1].Position + offset); + } + } + GL.End(); + } + + public static void DrawPolygonsNoOutline(Color color, params Polygon[] polygons) + { + GL.Begin(GL.TRIANGLES); + + GL.Color(color); + + for (int j = 0; j < polygons.Length; j++) + { + Polygon polygon = polygons[j]; + Vector3 position1 = polygon.Vertices[0].Position; + + for (int i = 1; i < polygon.Vertices.Length - 1; i++) + { + GL.Vertex(position1); + GL.Vertex(polygon.Vertices[i].Position); + GL.Vertex(polygon.Vertices[i + 1].Position); + } + } + GL.End(); + } + + public static void DrawPolygonsOutline(Color color, params Polygon[] polygons) + { + Vector3 depthAdjust = -0.01f * SceneView.currentDrawingSceneView.camera.transform.forward; + GL.Begin(GL.LINES); + + for (int j = 0; j < polygons.Length; j++) + { + Polygon polygon = polygons[j]; + + GL.Color(color); + + for (int i = 0; i < polygon.Vertices.Length; i++) + { + Vector3 currentPosition = polygon.Vertices[i].Position + depthAdjust; + Vector3 nextPosition = polygon.Vertices[(i + 1) % polygon.Vertices.Length].Position + depthAdjust; + + GL.Vertex(currentPosition); + GL.Vertex(nextPosition); + } + } + + GL.End(); + } + + public static void DrawPolygonsOutlineDashed(Color color, params Polygon[] polygons) + { + Vector3 depthAdjust = -0.01f * SceneView.currentDrawingSceneView.camera.transform.forward; + GL.Begin(GL.LINES); + + for (int j = 0; j < polygons.Length; j++) + { + Polygon polygon = polygons[j]; + + GL.Color(color); + + for (int i = 0; i < polygon.Vertices.Length; i++) + { + Vector3 currentPosition = polygon.Vertices[i].Position + depthAdjust; + Vector3 nextPosition = polygon.Vertices[(i + 1) % polygon.Vertices.Length].Position + depthAdjust; + + GL.TexCoord2(0, 0); + GL.Vertex(currentPosition); + GL.TexCoord2(Vector3.Distance(nextPosition, currentPosition), 0); + GL.Vertex(nextPosition); + } + } + + GL.End(); + } + + public static void DrawMarquee(Vector2 marqueeStart, Vector2 marqueeEnd) + { + Vector2 point1 = EditorHelper.ConvertMousePointPosition(marqueeStart); + Vector2 point2 = EditorHelper.ConvertMousePointPosition(marqueeEnd); + + Rect rect = new Rect(point1.x, point1.y, point2.x - point1.x, point2.y - point1.y); + + SabreCSGResources.GetSelectedBrushMaterial().SetPass(0); + + GL.PushMatrix(); + GL.LoadPixelMatrix(); + + GL.Begin(GL.QUADS); + GL.Color(new Color(0.2f, 0.3f, 0.8f, 0.3f)); + + // Marquee fill (draw double sided) + SabreGraphics.DrawScreenRectFill(rect); + + GL.End(); + + // Marquee border + GL.Begin(GL.LINES); + GL.Color(Color.white); + + // Draw marquee box edges + SabreGraphics.DrawScreenRectOuter(rect); + + GL.End(); + GL.PopMatrix(); + } + + // public static void DrawThickLineTest(Vector3 testPoint1, Vector3 testPoint2, float width) + // { + // Camera sceneViewCamera = UnityEditor.SceneView.currentDrawingSceneView.camera; + // + //// Vector3 screenPoint1 = sceneViewCamera.WorldToScreenPoint(testPoint1); + //// Vector3 screenPoint2 = sceneViewCamera.WorldToScreenPoint(testPoint2); + // + //// Vector3 perpendicular = new Vector3(screenPoint2.x - screenPoint1.x, screenPoint1.y - screenPoint2.y, screenPoint1.z).normalized; + // + //// Vector3 up = sceneViewCamera.transform.up; + // Vector3 forward = sceneViewCamera.transform.forward * 0.01f; + // + // Vector3 cameraVector = sceneViewCamera.transform.position - (testPoint1 + testPoint2)/2f; + // Vector3 lineVector = testPoint2 - testPoint1; + // + // Vector3 up = Vector3.Cross(cameraVector.normalized, lineVector.normalized); + // + //// Vector3 up = Quaternion.LookRotation(sceneViewCamera.transform.forward, sceneViewCamera.transform.up) * Vector3.up; + // + // GL.Color(Color.black); + // GL.Vertex(testPoint1 + up * width - forward); + // GL.Vertex(testPoint1 - up * width - forward); + // GL.Vertex(testPoint2 - up * width - forward); + // GL.Vertex(testPoint2 + up * width - forward); + // + // GL.Color(Color.green); + // GL.Vertex(testPoint1 + up * width/2 - forward); + // GL.Vertex(testPoint1 - up * width/2 - forward); + // GL.Vertex(testPoint2 - up * width/2 - forward); + // GL.Vertex(testPoint2 + up * width/2 - forward); + // } + } } + #endif \ No newline at end of file diff --git a/Scripts/UI/Toolbar.cs b/Scripts/UI/Toolbar.cs index cfd4bfd5..4a636d8d 100644 --- a/Scripts/UI/Toolbar.cs +++ b/Scripts/UI/Toolbar.cs @@ -430,7 +430,7 @@ private static void OnBottomToolbarGUI(int windowID) brushes.Add(brush); } } - if (primaryBrush != null) + if (primaryBrush != null && primaryBrush.SupportsCsgOperations) { CSGMode brushMode = (CSGMode)EditorGUILayout.EnumPopup(primaryBrush.Mode, EditorStyles.toolbarPopup, GUILayout.Width(80)); if(brushMode != primaryBrush.Mode) diff --git a/Shaders/Diffuse-VertexColored.shader b/Shaders/Diffuse-VertexColored.shader index 70df7d35..2e3dbce7 100644 --- a/Shaders/Diffuse-VertexColored.shader +++ b/Shaders/Diffuse-VertexColored.shader @@ -1,50 +1,54 @@ -Shader "SabreCSG/Diffuse (vertex colored) " { -Properties { -} -SubShader { - Tags { "RenderType"="Opaque" } - LOD 200 +Shader "SabreCSG/Diffuse (vertex colored) " +{ + Properties + { + } + SubShader + { + Tags { "RenderType"="Opaque" } + LOD 200 -Pass { -CGPROGRAM -#pragma vertex vert -#pragma fragment frag -#include "UnityShaderVariables.cginc" + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityShaderVariables.cginc" - // vertex shader input data - struct appdata - { - float3 pos : POSITION; - half4 color : COLOR; - }; + // vertex shader input data + struct appdata + { + float3 pos : POSITION; + half4 color : COLOR; + }; - // vertex-to-fragment interpolators - struct v2f - { - fixed4 color : COLOR0; - float4 pos : SV_POSITION; - }; + // vertex-to-fragment interpolators + struct v2f + { + fixed4 color : COLOR0; + float4 pos : SV_POSITION; + }; - // vertex shader - v2f vert(appdata IN) - { - v2f o; - half4 color = IN.color; - o.color = color; - // transform position - o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); - return o; - } + // vertex shader + v2f vert(appdata IN) + { + v2f o; + half4 color = IN.color; + o.color = color; + // transform position + o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); + return o; + } - // fragment shader - fixed4 frag(v2f IN) : SV_Target - { - fixed4 col; - col = IN.color; - return col; + // fragment shader + fixed4 frag(v2f IN) : SV_Target + { + fixed4 col; + col = IN.color; + return col; + } + ENDCG + } } -ENDCG -} -} -Fallback "VertexLit" -} + Fallback "VertexLit" +} \ No newline at end of file diff --git a/Shaders/Diffuse-VertexColoredLit.shader b/Shaders/Diffuse-VertexColoredLit.shader index 074e8b63..432dd904 100644 --- a/Shaders/Diffuse-VertexColoredLit.shader +++ b/Shaders/Diffuse-VertexColoredLit.shader @@ -1,40 +1,45 @@ -Shader "SabreCSG/Diffuse (vertex colored, lit) " { - Properties { +Shader "SabreCSG/Diffuse (vertex colored, lit) " +{ + Properties + { _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 } - SubShader { + SubShader + { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM - // Physically based Standard lighting model, and enable shadows on all light types - #pragma surface surf Standard fullforwardshadows + // Physically based Standard lighting model, and enable shadows on all light types + #pragma surface surf Standard fullforwardshadows - // Use shader model 3.0 target, to get nicer looking lighting - #pragma target 3.0 + // Use shader model 3.0 target, to get nicer looking lighting + #pragma target 3.0 - sampler2D _MainTex; + sampler2D _MainTex; - struct Input { - float2 uv_MainTex; - fixed4 color : COLOR; - }; + struct Input + { + float2 uv_MainTex; + fixed4 color : COLOR; + }; - half _Glossiness; - half _Metallic; + half _Glossiness; + half _Metallic; - void surf (Input IN, inout SurfaceOutputStandard o) { - // Albedo comes from a texture tinted by color - fixed4 c = tex2D (_MainTex, IN.uv_MainTex); - o.Albedo = IN.color; - // Metallic and smoothness come from slider variables - o.Metallic = _Metallic; - o.Smoothness = _Glossiness; - o.Alpha = c.a; - } + void surf (Input IN, inout SurfaceOutputStandard o) + { + // Albedo comes from a texture tinted by color + fixed4 c = tex2D (_MainTex, IN.uv_MainTex); + o.Albedo = IN.color; + // Metallic and smoothness come from slider variables + o.Metallic = _Metallic; + o.Smoothness = _Glossiness; + o.Alpha = c.a; + } ENDCG } FallBack "Diffuse" -} +} \ No newline at end of file diff --git a/Shaders/Handle.shader b/Shaders/Handle.shader index e3599d22..79b74030 100644 --- a/Shaders/Handle.shader +++ b/Shaders/Handle.shader @@ -1,63 +1,68 @@ -Shader "SabreCSG/Handle" { -Properties{ +Shader "SabreCSG/Handle" +{ + Properties + { _MainTex("Base (RGB)", 2D) = "white" { } } - SubShader{ - Pass{ - ZTest Always - ZWrite Off - Cull Off - Blend SrcAlpha OneMinusSrcAlpha - CGPROGRAM -#pragma vertex vert -#pragma fragment frag -#include "UnityShaderVariables.cginc" - - // uniforms - float4 _MainTex_ST; + SubShader + { + Pass + { + ZTest Always + ZWrite Off + Cull Off + Blend SrcAlpha OneMinusSrcAlpha + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityShaderVariables.cginc" - // vertex shader input data - struct appdata { - float3 pos : POSITION; - half4 color : COLOR; - float3 uv0 : TEXCOORD0; - }; + // uniforms + float4 _MainTex_ST; - // vertex-to-fragment interpolators - struct v2f { - fixed4 color : COLOR0; - float2 uv0 : TEXCOORD0; - float4 pos : SV_POSITION; - }; + // vertex shader input data + struct appdata + { + float3 pos : POSITION; + half4 color : COLOR; + float3 uv0 : TEXCOORD0; + }; - // vertex shader - v2f vert(appdata IN) { - v2f o; - half4 color = IN.color; - half3 viewDir = 0.0; - o.color = saturate(color); - // compute texture coordinates - o.uv0 = IN.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - // transform position - o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); - return o; - } + // vertex-to-fragment interpolators + struct v2f + { + fixed4 color : COLOR0; + float2 uv0 : TEXCOORD0; + float4 pos : SV_POSITION; + }; - // textures - sampler2D _MainTex; + // vertex shader + v2f vert(appdata IN) + { + v2f o; + half4 color = IN.color; + half3 viewDir = 0.0; + o.color = saturate(color); + // compute texture coordinates + o.uv0 = IN.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; + // transform position + o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); + return o; + } + // textures + sampler2D _MainTex; - fixed4 frag(v2f IN) : SV_Target - { - fixed4 col; - fixed4 tex, tmp0, tmp1, tmp2; - // SetTexture #0 - tex = tex2D(_MainTex, IN.uv0.xy); - col = IN.color * tex; -// col.a = 1; - return col; - } - ENDCG - } + fixed4 frag(v2f IN) : SV_Target + { + fixed4 col; + fixed4 tex, tmp0, tmp1, tmp2; + // SetTexture #0 + tex = tex2D(_MainTex, IN.uv0.xy); + col = IN.color * tex; + return col; + } + ENDCG + } } } \ No newline at end of file diff --git a/Shaders/Line.shader b/Shaders/Line.shader index af5e4b68..8862a5cd 100644 --- a/Shaders/Line.shader +++ b/Shaders/Line.shader @@ -1,47 +1,54 @@ -Shader "SabreCSG/Line" { - SubShader{ - Pass{ - ZWrite Off - Cull Off - Blend SrcAlpha OneMinusSrcAlpha - CGPROGRAM -#pragma vertex vert -#pragma fragment frag -#include "UnityShaderVariables.cginc" +Shader "SabreCSG/Line" +{ + SubShader + { + Pass + { + ZWrite Off + Cull Off + Blend SrcAlpha OneMinusSrcAlpha + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityShaderVariables.cginc" - // uniforms + // uniforms - // vertex shader input data - struct appdata { - float3 pos : POSITION; - half4 color : COLOR; - }; + // vertex shader input data + struct appdata + { + float3 pos : POSITION; + half4 color : COLOR; + }; - // vertex-to-fragment interpolators - struct v2f { - fixed4 color : COLOR0; - float4 pos : SV_POSITION; - }; + // vertex-to-fragment interpolators + struct v2f + { + fixed4 color : COLOR0; + float4 pos : SV_POSITION; + }; - // vertex shader - v2f vert(appdata IN) { - v2f o; - half4 color = IN.color; - half3 viewDir = 0.0; - o.color = saturate(color); - // compute texture coordinates - // transform position - o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); - return o; - } + // vertex shader + v2f vert(appdata IN) + { + v2f o; + half4 color = IN.color; + half3 viewDir = 0.0; + o.color = saturate(color); + // compute texture coordinates + // transform position + o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); + return o; + } - // fragment shader - fixed4 frag(v2f IN) : SV_Target{ - fixed4 col; - col = IN.color; - return col; - } - ENDCG - } + // fragment shader + fixed4 frag(v2f IN) : SV_Target + { + fixed4 col; + col = IN.color; + return col; + } + ENDCG + } } } \ No newline at end of file diff --git a/Shaders/LineDashed.shader b/Shaders/LineDashed.shader index 22cc5045..4bfc384c 100644 --- a/Shaders/LineDashed.shader +++ b/Shaders/LineDashed.shader @@ -1,57 +1,63 @@ -Shader "SabreCSG/Line Dashed" { - SubShader{ - Pass{ - ZWrite Off - Cull Off - Blend SrcAlpha OneMinusSrcAlpha - CGPROGRAM -#pragma vertex vert -#pragma fragment frag -#include "UnityShaderVariables.cginc" +Shader "SabreCSG/Line Dashed" +{ + SubShader + { + Pass + { + ZWrite Off + Cull Off + Blend SrcAlpha OneMinusSrcAlpha + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityShaderVariables.cginc" - // uniforms + // uniforms - // vertex shader input data - struct appdata { - float3 pos : POSITION; - float2 uv : TEXCOORD0; - half4 color : COLOR; - }; + // vertex shader input data + struct appdata + { + float3 pos : POSITION; + float2 uv : TEXCOORD0; + half4 color : COLOR; + }; - // vertex-to-fragment interpolators - struct v2f { - fixed4 color : COLOR0; - float2 uv : TEXCOORD0; - float4 pos : SV_POSITION; - }; + // vertex-to-fragment interpolators + struct v2f + { + fixed4 color : COLOR0; + float2 uv : TEXCOORD0; + float4 pos : SV_POSITION; + }; - // vertex shader - v2f vert(appdata IN) { - v2f o; - half4 color = IN.color; - half3 viewDir = 0.0; - o.color = saturate(color); - // compute texture coordinates - // transform position - o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); - o.uv = IN.uv; - return o; - } + // vertex shader + v2f vert(appdata IN) + { + v2f o; + half4 color = IN.color; + half3 viewDir = 0.0; + o.color = saturate(color); + // compute texture coordinates + // transform position + o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); + o.uv = IN.uv; + return o; + } - // fragment shader - fixed4 frag(v2f IN) : SV_Target - { - fixed4 col; - col = IN.color; - // This should flip between 0 and 1 values 4 times a UV unit - float interpolant = floor(2 * frac((IN.uv.x) * 2)); + // fragment shader + fixed4 frag(v2f IN) : SV_Target + { + fixed4 col; + col = IN.color; + // This should flip between 0 and 1 values 4 times a UV unit + float interpolant = floor(2 * frac((IN.uv.x) * 2)); - // Set the target color as the supplied color or black based on the interpolant - col = lerp(col, fixed4(0,0,0,1), interpolant); + // Set the target color as the supplied color or black based on the interpolant + col = lerp(col, fixed4(0,0,0,1), interpolant); - return col; - } - ENDCG - } + return col; + } + ENDCG + } } } \ No newline at end of file diff --git a/Shaders/LineDashedAlpha.shader b/Shaders/LineDashedAlpha.shader index 5dccc139..2a47c410 100644 --- a/Shaders/LineDashedAlpha.shader +++ b/Shaders/LineDashedAlpha.shader @@ -1,57 +1,63 @@ -Shader "SabreCSG/Line Dashed Alpha" { - SubShader{ - Pass{ - ZWrite Off - Cull Off - Blend SrcAlpha OneMinusSrcAlpha - CGPROGRAM -#pragma vertex vert -#pragma fragment frag -#include "UnityShaderVariables.cginc" +Shader "SabreCSG/Line Dashed Alpha" +{ + SubShader + { + Pass + { + ZWrite Off + Cull Off + Blend SrcAlpha OneMinusSrcAlpha + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityShaderVariables.cginc" - // uniforms + // uniforms - // vertex shader input data - struct appdata { - float3 pos : POSITION; - float2 uv : TEXCOORD0; - half4 color : COLOR; - }; + // vertex shader input data + struct appdata + { + float3 pos : POSITION; + float2 uv : TEXCOORD0; + half4 color : COLOR; + }; - // vertex-to-fragment interpolators - struct v2f { - fixed4 color : COLOR0; - float2 uv : TEXCOORD0; - float4 pos : SV_POSITION; - }; + // vertex-to-fragment interpolators + struct v2f + { + fixed4 color : COLOR0; + float2 uv : TEXCOORD0; + float4 pos : SV_POSITION; + }; - // vertex shader - v2f vert(appdata IN) { - v2f o; - half4 color = IN.color; - half3 viewDir = 0.0; - o.color = saturate(color); - // compute texture coordinates - // transform position - o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); - o.uv = IN.uv; - return o; - } + // vertex shader + v2f vert(appdata IN) + { + v2f o; + half4 color = IN.color; + half3 viewDir = 0.0; + o.color = saturate(color); + // compute texture coordinates + // transform position + o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); + o.uv = IN.uv; + return o; + } - // fragment shader - fixed4 frag(v2f IN) : SV_Target - { - fixed4 col; - col = IN.color; - // This should flip between 0 and 1 values 4 times a UV unit - float interpolant = floor(2 * frac((IN.uv.x) * 2)); + // fragment shader + fixed4 frag(v2f IN) : SV_Target + { + fixed4 col; + col = IN.color; + // This should flip between 0 and 1 values 4 times a UV unit + float interpolant = floor(2 * frac((IN.uv.x) * 2)); - // Set the target color as the supplied color or black based on the interpolant - col.a *= interpolant; + // Set the target color as the supplied color or black based on the interpolant + col.a *= interpolant; - return col; - } - ENDCG - } + return col; + } + ENDCG + } } } \ No newline at end of file diff --git a/Shaders/Plane.shader b/Shaders/Plane.shader index a3fa2901..378eee8f 100644 --- a/Shaders/Plane.shader +++ b/Shaders/Plane.shader @@ -1,62 +1,70 @@ -Shader "SabreCSG/Plane" { - Properties{ +Shader "SabreCSG/Plane" +{ + Properties + { _MainTex("Base (RGB)", 2D) = "white" { } } - SubShader{ - Pass{ - ZWrite Off - Blend SrcAlpha OneMinusSrcAlpha - CGPROGRAM -#pragma vertex vert -#pragma fragment frag -#include "UnityShaderVariables.cginc" + SubShader + { + Pass + { + ZWrite Off + Blend SrcAlpha OneMinusSrcAlpha + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityShaderVariables.cginc" - // uniforms - float4 _MainTex_ST; + // uniforms + float4 _MainTex_ST; - // vertex shader input data - struct appdata { - float3 pos : POSITION; - half4 color : COLOR; - float3 uv0 : TEXCOORD0; - }; + // vertex shader input data + struct appdata + { + float3 pos : POSITION; + half4 color : COLOR; + float3 uv0 : TEXCOORD0; + }; - // vertex-to-fragment interpolators - struct v2f { - fixed4 color : COLOR0; - float2 uv0 : TEXCOORD0; - float4 pos : SV_POSITION; - }; + // vertex-to-fragment interpolators + struct v2f + { + fixed4 color : COLOR0; + float2 uv0 : TEXCOORD0; + float4 pos : SV_POSITION; + }; - // vertex shader - v2f vert(appdata IN) { - v2f o; - half4 color = IN.color; - half3 viewDir = 0.0; - o.color = saturate(color); - // compute texture coordinates - o.uv0 = IN.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - // transform position - o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); - return o; - } + // vertex shader + v2f vert(appdata IN) + { + v2f o; + half4 color = IN.color; + half3 viewDir = 0.0; + o.color = saturate(color); + // compute texture coordinates + o.uv0 = IN.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; + // transform position + o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); + return o; + } - // textures - sampler2D _MainTex; + // textures + sampler2D _MainTex; - // fragment shader - fixed4 frag(v2f IN) : SV_Target{ - fixed4 col; - fixed4 tex, tmp0, tmp1, tmp2; - // SetTexture #0 - tex = tex2D(_MainTex, IN.uv0.xy); - col = IN.color * tex; - return col; - } + // fragment shader + fixed4 frag(v2f IN) : SV_Target + { + fixed4 col; + fixed4 tex, tmp0, tmp1, tmp2; + // SetTexture #0 + tex = tex2D(_MainTex, IN.uv0.xy); + col = IN.color * tex; + return col; + } - // texenvs - //! TexEnv0: 01000101 01000101 [_MainTex] - ENDCG - } + // texenvs + //! TexEnv0: 01000101 01000101 [_MainTex] + ENDCG + } } } \ No newline at end of file diff --git a/Shaders/Preview.shader b/Shaders/Preview.shader index e0f8377d..c0395349 100644 --- a/Shaders/Preview.shader +++ b/Shaders/Preview.shader @@ -1,74 +1,77 @@ -Shader "SabreCSG/Preview" { -Properties{ +Shader "SabreCSG/Preview" +{ + Properties + { _MainTex("Base (RGB)", 2D) = "white" { } _IsLinear ("Is Linear (1 = true)", Float) = 0 } - SubShader{ - Pass{ - ZWrite Off - ZTest Always - Cull Off - //Blend SrcAlpha OneMinusSrcAlpha -// Blend One One - CGPROGRAM -#pragma vertex vert -#pragma fragment frag -#include "UnityShaderVariables.cginc" + SubShader + { + Pass + { + ZWrite Off + ZTest Always + Cull Off + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityShaderVariables.cginc" - // uniforms - float4 _MainTex_ST; + // uniforms + float4 _MainTex_ST; + // vertex shader input data + struct appdata + { + float3 pos : POSITION; + half4 color : COLOR; + float3 uv0 : TEXCOORD0; + }; - // vertex shader input data - struct appdata { - float3 pos : POSITION; - half4 color : COLOR; - float3 uv0 : TEXCOORD0; - }; + // vertex-to-fragment interpolators + struct v2f + { + fixed4 color : COLOR0; + float2 uv0 : TEXCOORD0; + float4 pos : SV_POSITION; + }; - // vertex-to-fragment interpolators - struct v2f { - fixed4 color : COLOR0; - float2 uv0 : TEXCOORD0; - float4 pos : SV_POSITION; - }; + // vertex shader + v2f vert(appdata IN) + { + v2f o; + half4 color = IN.color; + half3 viewDir = 0.0; + o.color = saturate(color); + // compute texture coordinates + o.uv0 = IN.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; + // transform position + o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); + return o; + } - // vertex shader - v2f vert(appdata IN) { - v2f o; - half4 color = IN.color; - half3 viewDir = 0.0; - o.color = saturate(color); - // compute texture coordinates - o.uv0 = IN.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - // transform position - o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); - return o; - } + // textures + sampler2D _MainTex; + float _IsLinear; - // textures - sampler2D _MainTex; - float _IsLinear; + fixed4 frag(v2f IN) : SV_Target + { + fixed4 col; + fixed4 tex, tmp0, tmp1, tmp2; + // SetTexture #0 + tex = tex2D(_MainTex, IN.uv0.xy); + col = IN.color * tex; - fixed4 frag(v2f IN) : SV_Target - { - fixed4 col; - fixed4 tex, tmp0, tmp1, tmp2; - // SetTexture #0 - tex = tex2D(_MainTex, IN.uv0.xy); - col = IN.color * tex; + if(_IsLinear > 0) + { + // col = pow(col, 0.47); + col = pow(col, 0.454545); + } + col.a = 1; - if(_IsLinear > 0) - { -// col = pow(col, 0.47); - col = pow(col, 0.454545); - + return col; + } + ENDCG } - col.a = 1; - - return col; - } - ENDCG - } } } \ No newline at end of file diff --git a/Shaders/SeeExcluded.shader b/Shaders/SeeExcluded.shader index 5461f71a..3111a4b4 100644 --- a/Shaders/SeeExcluded.shader +++ b/Shaders/SeeExcluded.shader @@ -1,115 +1,75 @@ // Derived from an original shader by Robert Yang, used with permission -Shader "SabreCSG/SeeExcluded" { - Properties { +Shader "SabreCSG/SeeExcluded" +{ + Properties + { _MainTex("Side", 2D) = "white" {} } - SubShader{ - Pass{ - ZWrite Off -// Cull Off - Blend SrcAlpha OneMinusSrcAlpha - CGPROGRAM -#pragma vertex vert -#pragma fragment frag -#include "UnityShaderVariables.cginc" - - // uniforms - sampler2D _MainTex; - - // vertex shader input data - struct appdata { - float3 pos : POSITION; - float3 normal : NORMAL; - }; - - // vertex-to-fragment interpolators - struct v2f { - float4 pos : SV_POSITION; - float3 worldPos : TEXCOORD0; - float3 worldNormal : TEXCOORD1; - }; - - // vertex shader - v2f vert(appdata IN) { - v2f o; - o.worldPos = IN.pos; - o.worldNormal = IN.normal; - // transform position - o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); - return o; - } - - // fragment shader - fixed4 frag(v2f IN) : SV_Target{ - - float3 result; - - - float3 projNormal = saturate(pow(IN.worldNormal * 1.4, 4)); - - float scale = 1;//0.5f; - // SIDE X - float3 x = tex2D(_MainTex, IN.worldPos.zy * scale) * abs(IN.worldNormal.x); - - // TOP / BOTTOM - float3 y = tex2D(_MainTex, IN.worldPos.zx * scale) * abs(IN.worldNormal.y); - - // SIDE Z - float3 z = tex2D(_MainTex, IN.worldPos.xy * scale) * abs(IN.worldNormal.z); - - result = z; - result = lerp(result, x, projNormal.x); - result = lerp(result, y, projNormal.y); - - - - return fixed4(result, 0.5); - - - - - - - + SubShader + { + Pass + { + ZWrite Off + Blend SrcAlpha OneMinusSrcAlpha + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityShaderVariables.cginc" + + // uniforms + sampler2D _MainTex; + + // vertex shader input data + struct appdata + { + float3 pos : POSITION; + float3 normal : NORMAL; + }; + + // vertex-to-fragment interpolators + struct v2f + { + float4 pos : SV_POSITION; + float3 worldPos : TEXCOORD0; + float3 worldNormal : TEXCOORD1; + }; + + // vertex shader + v2f vert(appdata IN) + { + v2f o; + o.worldPos = IN.pos; + o.worldNormal = IN.normal; + // transform position + o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); + return o; + } + + // fragment shader + fixed4 frag(v2f IN) : SV_Target + { + float3 result; + + float3 projNormal = saturate(pow(IN.worldNormal * 1.4, 4)); + + float scale = 1;//0.5f; + // SIDE X + float3 x = tex2D(_MainTex, IN.worldPos.zy * scale) * abs(IN.worldNormal.x); + + // TOP / BOTTOM + float3 y = tex2D(_MainTex, IN.worldPos.zx * scale) * abs(IN.worldNormal.y); + + // SIDE Z + float3 z = tex2D(_MainTex, IN.worldPos.xy * scale) * abs(IN.worldNormal.z); + + result = z; + result = lerp(result, x, projNormal.x); + result = lerp(result, y, projNormal.y); + + return fixed4(result, 0.5); + } + ENDCG + } } - ENDCG - } - } -} - -// -// -// -//Shader "SabreCSG/SeeExcluded" { -// -// -// SubShader { -// Tags { -// "Queue"="Geometry" -// "IgnoreProjector"="False" -// "RenderType"="Opaque" -// } -// -// Cull Back -// ZWrite On -// -// CGPROGRAM -// #pragma surface surf Lambert -// #pragma exclude_renderers flash -// -// sampler2D _MainTex; -// float _Scale; -// -// struct Input { -// float3 worldPos; -// float3 worldNormal; -// }; -// -// void surf (Input IN, inout SurfaceOutput o) { -// -// } -// ENDCG -// } -// Fallback "Diffuse" -//} \ No newline at end of file +} \ No newline at end of file diff --git a/Shaders/ShapeEditorGrid.shader b/Shaders/ShapeEditorGrid.shader index 23d6ad11..6b5db1eb 100644 --- a/Shaders/ShapeEditorGrid.shader +++ b/Shaders/ShapeEditorGrid.shader @@ -41,7 +41,7 @@ v2f vert(appdata IN) { v2f o; - o.pos = UnityObjectToClipPos(float4(IN.pos,1)); + o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); return o; } diff --git a/Shaders/ShapeEditorLine.shader b/Shaders/ShapeEditorLine.shader index a5df3088..2535a68d 100644 --- a/Shaders/ShapeEditorLine.shader +++ b/Shaders/ShapeEditorLine.shader @@ -1,52 +1,57 @@ -// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' +Shader "SabreCSG/ShapeEditorLine" +{ + SubShader + { + Pass + { + ZWrite Off + Cull Off + Blend SrcAlpha OneMinusSrcAlpha + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityCG.cginc" + #include "UnityShaderVariables.cginc" -Shader "SabreCSG/ShapeEditorLine" { - SubShader{ - Pass{ - ZWrite Off - Cull Off - Blend SrcAlpha OneMinusSrcAlpha - CGPROGRAM -#pragma vertex vert -#pragma fragment frag -#include "UnityCG.cginc" -#include "UnityShaderVariables.cginc" + // uniforms - // uniforms + // vertex shader input data + struct appdata + { + float3 pos : POSITION; + half4 color : COLOR; + }; - // vertex shader input data - struct appdata { - float3 pos : POSITION; - half4 color : COLOR; - }; + // vertex-to-fragment interpolators + struct v2f + { + fixed4 color : COLOR0; + float4 pos : SV_POSITION; + }; - // vertex-to-fragment interpolators - struct v2f { - fixed4 color : COLOR0; - float4 pos : SV_POSITION; - }; + // vertex shader + v2f vert(appdata IN) + { + v2f o; + half4 color = IN.color; + half3 viewDir = 0.0; + o.color = saturate(color); + // compute texture coordinates + // transform position + o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); + return o; + } - // vertex shader - v2f vert(appdata IN) { - v2f o; - half4 color = IN.color; - half3 viewDir = 0.0; - o.color = saturate(color); - // compute texture coordinates - // transform position - o.pos = UnityObjectToClipPos(float4(IN.pos,1)); - return o; - } - - // fragment shader - fixed4 frag(v2f IN) : SV_Target { - fixed4 col; - col = IN.color; - if (IN.pos.y < 35) - discard; - return col; - } - ENDCG - } + // fragment shader + fixed4 frag(v2f IN) : SV_Target + { + fixed4 col; + col = IN.color; + if (IN.pos.y < 35) + discard; + return col; + } + ENDCG + } } } \ No newline at end of file diff --git a/Shaders/Tri-Planar.shader b/Shaders/Tri-Planar.shader index a76e5ed7..5a2cec96 100644 --- a/Shaders/Tri-Planar.shader +++ b/Shaders/Tri-Planar.shader @@ -1,6 +1,8 @@ // Original shader by Robert Yang -Shader "SabreCSG/Tri-Planar World" { - Properties { +Shader "SabreCSG/Tri-Planar World" +{ + Properties + { _Side("Side", 2D) = "white" {} _Top("Top", 2D) = "white" {} _Bottom("Bottom", 2D) = "white" {} @@ -9,49 +11,47 @@ Shader "SabreCSG/Tri-Planar World" { _BottomScale ("Bottom Scale", Float) = 2 } - SubShader { - Tags { - "Queue"="Geometry" - "IgnoreProjector"="False" - "RenderType"="Opaque" - } + SubShader + { + Tags { "Queue"="Geometry" "IgnoreProjector"="False" "RenderType"="Opaque" } Cull Back ZWrite On CGPROGRAM - #pragma surface surf Lambert - #pragma exclude_renderers flash + #pragma surface surf Lambert + #pragma exclude_renderers flash - sampler2D _Side, _Top, _Bottom; - float _SideScale, _TopScale, _BottomScale; + sampler2D _Side, _Top, _Bottom; + float _SideScale, _TopScale, _BottomScale; - struct Input { - float3 worldPos; - float3 worldNormal; - }; + struct Input + { + float3 worldPos; + float3 worldNormal; + }; - void surf (Input IN, inout SurfaceOutput o) { - float3 projNormal = saturate(pow(IN.worldNormal * 1.4, 4)); + void surf (Input IN, inout SurfaceOutput o) + { + float3 projNormal = saturate(pow(IN.worldNormal * 1.4, 4)); - // SIDE X - float3 x = tex2D(_Side, frac(IN.worldPos.zy * _SideScale)) * abs(IN.worldNormal.x); + // SIDE X + float3 x = tex2D(_Side, frac(IN.worldPos.zy * _SideScale)) * abs(IN.worldNormal.x); - // TOP / BOTTOM - float3 y = 0; - if (IN.worldNormal.y > 0) { - y = tex2D(_Top, frac(IN.worldPos.zx * _TopScale)) * abs(IN.worldNormal.y); - } else { - y = tex2D(_Bottom, frac(IN.worldPos.zx * _BottomScale)) * abs(IN.worldNormal.y); - } + // TOP / BOTTOM + float3 y = 0; + if (IN.worldNormal.y > 0) + y = tex2D(_Top, frac(IN.worldPos.zx * _TopScale)) * abs(IN.worldNormal.y); + else + y = tex2D(_Bottom, frac(IN.worldPos.zx * _BottomScale)) * abs(IN.worldNormal.y); - // SIDE Z - float3 z = tex2D(_Side, frac(IN.worldPos.xy * _SideScale)) * abs(IN.worldNormal.z); + // SIDE Z + float3 z = tex2D(_Side, frac(IN.worldPos.xy * _SideScale)) * abs(IN.worldNormal.z); - o.Albedo = z; - o.Albedo = lerp(o.Albedo, x, projNormal.x); - o.Albedo = lerp(o.Albedo, y, projNormal.y); - } + o.Albedo = z; + o.Albedo = lerp(o.Albedo, x, projNormal.x); + o.Albedo = lerp(o.Albedo, y, projNormal.y); + } ENDCG } Fallback "Diffuse" diff --git a/Shaders/UINoAlpha.shader b/Shaders/UINoAlpha.shader index 29129951..63a2d114 100644 --- a/Shaders/UINoAlpha.shader +++ b/Shaders/UINoAlpha.shader @@ -1,62 +1,68 @@ -Shader "SabreCSG/UI No Alpha" { -Properties{ +Shader "SabreCSG/UI No Alpha" +{ + Properties + { _MainTex("Base (RGB)", 2D) = "white" { } } - SubShader{ - Pass{ - ZWrite Off - Cull Off - Blend SrcAlpha OneMinusSrcAlpha - CGPROGRAM -#pragma vertex vert -#pragma fragment frag -#include "UnityShaderVariables.cginc" - - // uniforms - float4 _MainTex_ST; + SubShader + { + Pass + { + ZWrite Off + Cull Off + Blend SrcAlpha OneMinusSrcAlpha + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityShaderVariables.cginc" - // vertex shader input data - struct appdata { - float3 pos : POSITION; - half4 color : COLOR; - float3 uv0 : TEXCOORD0; - }; + // uniforms + float4 _MainTex_ST; - // vertex-to-fragment interpolators - struct v2f { - fixed4 color : COLOR0; - float2 uv0 : TEXCOORD0; - float4 pos : SV_POSITION; - }; + // vertex shader input data + struct appdata + { + float3 pos : POSITION; + half4 color : COLOR; + float3 uv0 : TEXCOORD0; + }; - // vertex shader - v2f vert(appdata IN) { - v2f o; - half4 color = IN.color; - half3 viewDir = 0.0; - o.color = saturate(color); - // compute texture coordinates - o.uv0 = IN.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; - // transform position - o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); - return o; - } + // vertex-to-fragment interpolators + struct v2f + { + fixed4 color : COLOR0; + float2 uv0 : TEXCOORD0; + float4 pos : SV_POSITION; + }; - // textures - sampler2D _MainTex; + // vertex shader + v2f vert(appdata IN) + { + v2f o; + half4 color = IN.color; + half3 viewDir = 0.0; + o.color = saturate(color); + // compute texture coordinates + o.uv0 = IN.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; + // transform position + o.pos = mul(UNITY_MATRIX_MVP, float4(IN.pos,1)); + return o; + } + // textures + sampler2D _MainTex; - fixed4 frag(v2f IN) : SV_Target - { - fixed4 col; - fixed4 tex, tmp0, tmp1, tmp2; - // SetTexture #0 - tex = tex2D(_MainTex, IN.uv0.xy); - col = IN.color * tex; -// col.a = 1; - return col; - } - ENDCG - } + fixed4 frag(v2f IN) : SV_Target + { + fixed4 col; + fixed4 tex, tmp0, tmp1, tmp2; + // SetTexture #0 + tex = tex2D(_MainTex, IN.uv0.xy); + col = IN.color * tex; + // col.a = 1; + return col; + } + ENDCG + } } } \ No newline at end of file diff --git a/Shaders/VertexTinted.shader b/Shaders/VertexTinted.shader index 94ee69f1..7d71a70a 100644 --- a/Shaders/VertexTinted.shader +++ b/Shaders/VertexTinted.shader @@ -1,40 +1,45 @@ -Shader "SabreCSG/Vertex Tinted" { - Properties { +Shader "SabreCSG/Vertex Tinted" +{ + Properties + { _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 } - SubShader { + SubShader + { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM - // Physically based Standard lighting model, and enable shadows on all light types - #pragma surface surf Standard fullforwardshadows + // Physically based Standard lighting model, and enable shadows on all light types + #pragma surface surf Standard fullforwardshadows - // Use shader model 3.0 target, to get nicer looking lighting - #pragma target 3.0 + // Use shader model 3.0 target, to get nicer looking lighting + #pragma target 3.0 - sampler2D _MainTex; + sampler2D _MainTex; - struct Input { - float2 uv_MainTex; - fixed4 color : COLOR; - }; + struct Input + { + float2 uv_MainTex; + fixed4 color : COLOR; + }; - half _Glossiness; - half _Metallic; + half _Glossiness; + half _Metallic; - void surf (Input IN, inout SurfaceOutputStandard o) { - // Albedo comes from a texture tinted by color - fixed4 c = tex2D (_MainTex, IN.uv_MainTex); - o.Albedo = lerp(fixed3(1,1,1), IN.color, saturate((1-c.rgb)*2)); - // Metallic and smoothness come from slider variables - o.Metallic = _Metallic; - o.Smoothness = _Glossiness; - o.Alpha = c.a; - } + void surf (Input IN, inout SurfaceOutputStandard o) + { + // Albedo comes from a texture tinted by color + fixed4 c = tex2D (_MainTex, IN.uv_MainTex); + o.Albedo = lerp(fixed3(1,1,1), IN.color, saturate((1-c.rgb)*2)); + // Metallic and smoothness come from slider variables + o.Metallic = _Metallic; + o.Smoothness = _Glossiness; + o.Alpha = c.a; + } ENDCG } FallBack "Diffuse" -} +} \ No newline at end of file