CodeWalker/Project/Panels/EditYmapGrassPanel.cs

309 lines
12 KiB
C#
Raw Normal View History

2018-06-08 00:42:41 +08:00
using System;
2018-03-03 21:03:08 +08:00
using System.Collections.Generic;
using System.Windows.Forms;
2018-06-08 00:42:41 +08:00
using CodeWalker.GameFiles;
using CodeWalker.World;
using SharpDX;
// TODO
// - COMPLETED -- Optimization feature.
2018-06-08 00:42:41 +08:00
// - COMPLETED -- Remove grass instances using CTRL + SHIFT + LMB
// - Better gizmo for grass brush (like a circle with a little line in the middle sticking upwards)
2018-06-08 00:42:41 +08:00
// - Maybe some kind of auto coloring system? I've noticed that mostly all grass in GTA inherits it's color from the surface it's on.
// - Grass area fill (generate grass on ydr based on colision materials?)
// - Need to have a way to erase instances from other batches in the current batches ymap.
// if we optimize our instances, we'd have to go through each batch to erase, this is very monotonous.
2018-06-08 00:42:41 +08:00
// BUG
// - I've added a "zoom" kind of feature when hitting the goto button, but when the bounds of the
// grass batch are 0, the zoom of the camera is set to 0, which causes the end-user to have to scroll
// out a lot in order to use any movement controls. I will need to clamp that to a minimum value.
2018-03-03 21:03:08 +08:00
namespace CodeWalker.Project.Panels
{
public partial class EditYmapGrassPanel : ProjectPanel
{
public ProjectForm ProjectForm;
2018-03-03 21:03:08 +08:00
public EditYmapGrassPanel(ProjectForm owner)
2018-03-03 21:03:08 +08:00
{
ProjectForm = owner;
InitializeComponent();
}
2018-06-08 00:42:41 +08:00
public YmapGrassInstanceBatch CurrentBatch { get; set; }
#region Form
2018-03-03 21:03:08 +08:00
public void SetBatch(YmapGrassInstanceBatch batch)
{
CurrentBatch = batch;
Tag = batch;
UpdateFormTitle();
2018-06-08 00:42:41 +08:00
UpdateControls();
2020-01-15 14:48:27 +08:00
ProjectForm.WorldForm?.SelectObject(batch);
2018-06-08 00:42:41 +08:00
}
private void UpdateControls()
{
if (ProjectForm?.CurrentProjectFile == null) return;
if (ProjectForm.GrassBatchExistsInProject(CurrentBatch))
{
GrassAddToProjectButton.Enabled = false;
GrassDeleteButton.Enabled = true;
}
else
{
GrassAddToProjectButton.Enabled = true;
GrassDeleteButton.Enabled = false;
}
ArchetypeNameTextBox.Text = CurrentBatch.Batch.archetypeName.ToString();
PositionTextBox.Text = FloatUtil.GetVector3String(CurrentBatch.Position);
LodDistNumericUpDown.Value = CurrentBatch.Batch.lodDist;
LodFadeRangeNumericUpDown.Value = (decimal) CurrentBatch.Batch.LodInstFadeRange;
LodFadeStartDistanceNumericUpDown.Value = (decimal) CurrentBatch.Batch.LodFadeStartDist;
ScaleRangeTextBox.Text = FloatUtil.GetVector3String(CurrentBatch.Batch.ScaleRange);
OrientToTerrainNumericUpDown.Value = (decimal)CurrentBatch.Batch.OrientToTerrain;
OptmizationThresholdNumericUpDown.Value = 15;
BrushModeCheckBox.Checked = CurrentBatch.BrushEnabled;
RadiusNumericUpDown.Value = (decimal)CurrentBatch.BrushRadius;
ExtentsMinTextBox.Text = FloatUtil.GetVector3String(CurrentBatch.AABBMin);
ExtentsMaxTextBox.Text = FloatUtil.GetVector3String(CurrentBatch.AABBMax);
2018-03-03 21:03:08 +08:00
}
private void UpdateFormTitle()
{
Text = CurrentBatch?.Batch.archetypeName.ToString() ?? "Grass Batch";
}
2018-06-08 00:42:41 +08:00
#endregion
#region Events
#region BrushSettings
private void GrassGoToButton_Click(object sender, EventArgs e)
{
if (CurrentBatch == null) return;
ProjectForm.WorldForm?.GoToPosition(CurrentBatch.Position, CurrentBatch.AABBMax - CurrentBatch.AABBMin);
}
private void GrassAddToProjectButton_Click(object sender, EventArgs e)
{
ProjectForm.SetProjectItem(CurrentBatch);
ProjectForm.AddGrassBatchToProject();
}
private void GrassDeleteButton_Click(object sender, EventArgs e)
{
ProjectForm.SetProjectItem(CurrentBatch);
var ymap = CurrentBatch?.Ymap;
if (!ProjectForm.DeleteGrassBatch()) return;
ymap?.CalcExtents(); // Recalculate the extents after deleting the grass batch.
ProjectForm.WorldForm.SelectItem();
}
private void GrassColorLabel_Click(object sender, EventArgs e)
{
var colDiag = new ColorDialog {Color = GrassColorLabel.BackColor};
if (colDiag.ShowDialog(this) == DialogResult.OK)
GrassColorLabel.BackColor = colDiag.Color;
}
private void BrushModeCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (CurrentBatch == null) return;
CurrentBatch.BrushEnabled = BrushModeCheckBox.Checked;
}
private void RadiusNumericUpDown_ValueChanged(object sender, EventArgs e)
{
if (CurrentBatch == null) return;
CurrentBatch.BrushRadius = (float)RadiusNumericUpDown.Value;
}
2018-06-08 00:42:41 +08:00
#endregion
#region Batch Settings
private void ArchetypeNameTextBox_TextChanged(object sender, EventArgs e)
{
var archetypeHash = JenkHash.GenHash(ArchetypeNameTextBox.Text);
var archetype = ProjectForm.GameFileCache.GetArchetype(archetypeHash);
if (archetype == null)
{
HashLabel.Text = $@"Hash: {archetypeHash} (invalid)";
return;
}
CurrentBatch.Archetype = archetype;
var b = CurrentBatch.Batch;
b.archetypeName = archetypeHash;
CurrentBatch.Batch = b;
ProjectForm.WorldForm.UpdateGrassBatchGraphics(CurrentBatch);
HashLabel.Text = $@"Hash: {archetypeHash}";
UpdateFormTitle();
CurrentBatch.HasChanged = true;
ProjectForm.SetGrassBatchHasChanged(false);
ProjectForm.SetYmapHasChanged(true);
}
private void LodDistNumericUpDown_ValueChanged(object sender, EventArgs e)
{
var batch = CurrentBatch.Batch;
batch.lodDist = (uint) LodDistNumericUpDown.Value;
CurrentBatch.Batch = batch;
ProjectForm.WorldForm.UpdateGrassBatchGraphics(CurrentBatch);
ProjectForm.SetYmapHasChanged(true);
}
private void LodFadeStartDistanceNumericUpDown_ValueChanged(object sender, EventArgs e)
{
var batch = CurrentBatch.Batch;
batch.LodFadeStartDist = (float) LodFadeStartDistanceNumericUpDown.Value;
CurrentBatch.Batch = batch;
ProjectForm.WorldForm.UpdateGrassBatchGraphics(CurrentBatch);
ProjectForm.SetYmapHasChanged(true);
}
private void LodFadeRangeNumericUpDown_ValueChanged(object sender, EventArgs e)
{
var batch = CurrentBatch.Batch;
batch.LodInstFadeRange = (float) LodFadeRangeNumericUpDown.Value;
CurrentBatch.Batch = batch;
ProjectForm.WorldForm.UpdateGrassBatchGraphics(CurrentBatch);
ProjectForm.SetYmapHasChanged(true);
}
private void OrientToTerrainNumericUpDown_ValueChanged(object sender, EventArgs e)
{
var batch = CurrentBatch.Batch;
batch.OrientToTerrain = (float) OrientToTerrainNumericUpDown.Value;
CurrentBatch.Batch = batch;
ProjectForm.WorldForm.UpdateGrassBatchGraphics(CurrentBatch);
ProjectForm.SetYmapHasChanged(true);
}
private void ScaleRangeTextBox_TextChanged(object sender, EventArgs e)
{
var batch = CurrentBatch.Batch;
var v = FloatUtil.ParseVector3String(ScaleRangeTextBox.Text);
batch.ScaleRange = v;
CurrentBatch.Batch = batch;
ProjectForm.WorldForm.UpdateGrassBatchGraphics(CurrentBatch);
ProjectForm.SetYmapHasChanged(true);
}
private void OptimizeBatchButton_Click(object sender, EventArgs e)
{
if (CurrentBatch.Instances == null || CurrentBatch.Instances.Length <= 0) return;
Ability to edit YTYP files and MLO Entity Defintions + Revisions to grass brush (#33) * - Add ability to edit/add ytyp files to project. - Add ability to edit/add ytyp archetype files to ytyp. - Add ability to add/remove entities from mlo archetype defs. - Add ability to save ytyp files. - Add dialog popup before optimizing grass batches. - Fix grass batches not being selected when chaning selection in project explorer. - Merged with upstream/master. - Squashed last 4 commits for PR cleanliness. * Fixed windows forms reference error. * - Added error checking to deleting mlo entities. - Fixed various bugs with deleting mlo entities. - Fixed edit archetype panel Asset Type box. - Removed redundant/unnecessary. - Removed backwards references between MCEntityDef and YmapEntityDef. All ymap entity to mcentity references are grabbed using indecies in the MloInstanceData class. - Fixed "YmapMenu" not showing when selecting entities/mlo entities in project form. Current bugs: - Loading a ytyp file -- mlo entities are not editiable, and are created in the world. - entitysets are not editable (properly). - Removing an mloinstancedef from a ymap does not delete the mlo instance's gizmo from the world, and it's still selectable. (Although all references are lost, and I believe collected by the GC?) * - Moved archetype initialization methods YmapFile.InitYmapEntityArchetypes(GameFileCache gfc) and MloInstanceData.InitYmapEntityArchetypes(GameFileCache gfc) - Added ability to load mlo instance defs through ymap files. - Fixed add method for mlo archetypes. * - Removed SetOrientationInv. - Removed unreachable code + updated comment. - Renamed CreateEntity to CreateYmapEntity, and renamed params for consistency. * Split calls to CreateYmapEntity() and MloArchetype.AddEntity(). * Fixed redundant rotation inversions. * - Added ability to select rooms. - Changed tree view grouping for mlo entities. - Fixed projectexplorer selection bugs. - Added ability to toggle mlo entity sets. - Fixed some change events when editing archetypes.
2018-12-03 16:54:04 +08:00
var d = MessageBox.Show(
@"You are about to split the selected batch into multiple parts. Are you sure you want to do this?",
@"Instance Optimizer", MessageBoxButtons.YesNo);
if (d == DialogResult.No)
return;
2018-06-08 00:42:41 +08:00
lock (ProjectForm.WorldForm.RenderSyncRoot)
{
var newBatches = CurrentBatch?.OptimizeInstances(CurrentBatch, (float)OptmizationThresholdNumericUpDown.Value);
if (newBatches == null || newBatches.Length <= 0) return;
// Remove our batch from the ymap
CurrentBatch.Ymap.RemoveGrassBatch(CurrentBatch);
foreach (var batch in newBatches)
{
var b = batch.Batch;
b.lodDist = CurrentBatch.Batch.lodDist;
b.LodInstFadeRange = CurrentBatch.Batch.LodInstFadeRange;
b.LodFadeStartDist = CurrentBatch.Batch.LodFadeStartDist;
b.ScaleRange = CurrentBatch.Batch.ScaleRange;
b.OrientToTerrain = CurrentBatch.Batch.OrientToTerrain;
b.archetypeName = CurrentBatch.Batch.archetypeName;
batch.Batch = b;
batch.Archetype = CurrentBatch.Archetype;
batch.UpdateInstanceCount();
ProjectForm.NewGrassBatch(batch);
}
CurrentBatch.Ymap.CalcExtents();
CurrentBatch.Ymap.Save();
// TODO: Select the last grass batch in the new list on the project explorer.
ProjectForm.ProjectExplorer.TrySelectGrassBatchTreeNode(CurrentBatch.Ymap.GrassInstanceBatches[0]);
}
}
#endregion
#endregion
#region Publics
public void CreateInstancesAtMouse(SpaceRayIntersectResult mouseRay)
{
var wf = ProjectForm.WorldForm;
if (wf == null) return;
2020-01-06 20:21:32 +08:00
lock (wf.RenderSyncRoot)
2018-06-08 00:42:41 +08:00
{
CurrentBatch.CreateInstancesAtMouse(
CurrentBatch,
mouseRay,
(float) RadiusNumericUpDown.Value,
(int) DensityNumericUpDown.Value,
SpawnRayFunc,
new Color(GrassColorLabel.BackColor.R, GrassColorLabel.BackColor.G, GrassColorLabel.BackColor.B),
(int) AoNumericUpDown.Value,
(int) ScaleNumericUpDown.Value,
FloatUtil.ParseVector3String(PadTextBox.Text),
RandomizeScaleCheckBox.Checked
);
wf.UpdateGrassBatchGraphics(CurrentBatch);
}
BatchChanged();
}
public void EraseInstancesAtMouse(SpaceRayIntersectResult mouseRay)
{
var wf = ProjectForm.WorldForm;
if (wf == null) return;
var changed = false;
2020-01-06 20:21:32 +08:00
lock (wf.RenderSyncRoot)
2018-06-08 00:42:41 +08:00
{
if (CurrentBatch.EraseInstancesAtMouse(
CurrentBatch,
mouseRay,
(float) RadiusNumericUpDown.Value
))
{
wf.UpdateGrassBatchGraphics(CurrentBatch);
changed = true;
}
}
if (changed) BatchChanged();
}
2018-03-03 21:03:08 +08:00
2018-06-08 00:42:41 +08:00
#endregion
#region Privates
private SpaceRayIntersectResult SpawnRayFunc(Vector3 spawnPos)
{
var res = ProjectForm.WorldForm.Raycast(new Ray(spawnPos, -Vector3.UnitZ));
return res;
}
2018-03-03 21:03:08 +08:00
2018-06-08 00:42:41 +08:00
private void BatchChanged()
2018-03-03 21:03:08 +08:00
{
2018-06-08 00:42:41 +08:00
UpdateControls();
CurrentBatch.UpdateInstanceCount();
CurrentBatch.HasChanged = true;
ProjectForm.SetGrassBatchHasChanged(false);
2018-03-03 21:03:08 +08:00
}
2018-06-08 00:42:41 +08:00
#endregion
2018-03-03 21:03:08 +08:00
}
2018-06-08 00:42:41 +08:00
}