CodeWalker/CodeWalker/WorldForm.cs

8006 lines
278 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using System.Linq;
using SharpDX;
using SharpDX.XInput;
using Device = SharpDX.Direct3D11.Device;
using DeviceContext = SharpDX.Direct3D11.DeviceContext;
using CodeWalker.World;
using CodeWalker.Project;
using CodeWalker.Rendering;
using CodeWalker.GameFiles;
using CodeWalker.Properties;
using CodeWalker.Tools;
namespace CodeWalker
{
public partial class WorldForm : Form, DXForm
{
public Form Form { get { return this; } } //for DXForm/DXManager use
public Renderer Renderer = null;
public object RenderSyncRoot { get { return Renderer.RenderSyncRoot; } }
volatile bool formopen = false;
volatile bool running = false;
volatile bool pauserendering = false;
volatile bool initialised = false;
Stopwatch frametimer = new Stopwatch();
Space space = new Space();
Camera camera;
Timecycle timecycle;
Weather weather;
Clouds clouds;
Water water = new Water();
Trains trains = new Trains();
Scenarios scenarios = new Scenarios();
PopZones popzones = new PopZones();
Heightmaps heightmaps = new Heightmaps();
Watermaps watermaps = new Watermaps();
AudioZones audiozones = new AudioZones();
public Space Space { get { return space; } }
bool MouseLButtonDown = false;
bool MouseRButtonDown = false;
int MouseX;
int MouseY;
System.Drawing.Point MouseDownPoint;
System.Drawing.Point MouseLastPoint;
bool rendermaps = false;
bool renderworld = false;
int startupviewmode = 0; //0=world, 1=ymap, 2=model
string modelname = "dt1_tc_dufo_core";//"dt1_11_fount_decal";//"v_22_overlays";//
string[] ymaplist;
Vector3 prevworldpos = new Vector3(0, 0, 100); //also the start pos
public GameFileCache GameFileCache { get { return gameFileCache; } }
GameFileCache gameFileCache = GameFileCacheFactory.Create();
WorldControlMode ControlMode = WorldControlMode.Free;
object MouseControlSyncRoot = new object();
int MouseControlX = 0;
int MouseControlY = 0;
int MouseControlWheel = 0;
MouseButtons MouseControlButtons = MouseButtons.None;
MouseButtons MouseControlButtonsPrev = MouseButtons.None;
bool MouseInvert = Settings.Default.MouseInvert;
bool ControlFireToggle = false;
int ControlBrushTimer = 0;
bool ControlBrushEnabled;
//float ControlBrushRadius;
Entity camEntity = new Entity();
PedEntity pedEntity = new PedEntity();
bool iseditmode = false;
List<MapIcon> Icons;
MapIcon MarkerIcon = null;
MapIcon LocatorIcon = null;
MapMarker LocatorMarker = null;
MapMarker GrabbedMarker = null;
MapMarker SelectedMarker = null;
MapMarker MousedMarker = null;
List<MapMarker> Markers = new List<MapMarker>();
List<MapMarker> SortedMarkers = new List<MapMarker>();
List<MapMarker> MarkerBatch = new List<MapMarker>();
bool RenderLocator = false;
object markersyncroot = new object();
object markersortedsyncroot = new object();
bool rendercollisionmeshes = Settings.Default.ShowCollisionMeshes;
List<BoundsStoreItem> collisionitems = new List<BoundsStoreItem>();
List<YbnFile> collisionybns = new List<YbnFile>();
Dictionary<YmapEntityDef, YbnFile> collisioninteriors = new Dictionary<YmapEntityDef, YbnFile>();
int collisionmeshrange = Settings.Default.CollisionMeshRange;
bool[] collisionmeshlayers = { true, true, true };
Dictionary<MetaHash, YmapFile> renderworldVisibleYmapDict = new Dictionary<MetaHash, YmapFile>();
bool worldymaptimefilter = true;
bool worldymapweatherfilter = true;
bool renderpathbounds = true;
bool renderpaths = false;
List<YndFile> renderpathynds = new List<YndFile>();
bool renderwaterquads = true;
bool rendertraintracks = false;
List<TrainTrack> rendertraintracklist = new List<TrainTrack>();
bool rendernavmeshes = false;
List<YnvFile> rendernavmeshynvs = new List<YnvFile>();
bool renderscenariobounds = false;
bool renderscenarios = false;
List<YmtFile> renderscenariolist = new List<YmtFile>();
bool renderpopzones = false;
bool renderheightmaps = false;
bool renderwatermaps = false;
bool renderaudiozones = false;
bool renderaudioouterbounds = true;
List<RelFile> renderaudfilelist = new List<RelFile>();
List<AudioPlacement> renderaudplacementslist = new List<AudioPlacement>();
bool MapViewEnabled = false;
int MapViewDragX = 0;
int MapViewDragY = 0;
bool MouseSelectEnabled = false;
bool ShowSelectionBounds = true;
bool SelectByGeometry = false; //select by geometry needs more work
MapSelection CurMouseHit = new MapSelection();
MapSelection LastMouseHit = new MapSelection();
MapSelection PrevMouseHit = new MapSelection();
bool MouseRayCollisionEnabled = true;
bool MouseRayCollisionVisible = false;
SpaceRayIntersectResult MouseRayCollision = new SpaceRayIntersectResult();
string SelectionModeStr = "Entity";
MapSelectionMode SelectionMode = MapSelectionMode.Entity;
MapSelection SelectedItem;
MapSelection CopiedItem;
WorldInfoForm InfoForm = null;
public MapSelection CurrentMapSelection { get { return SelectedItem; } }
TransformWidget Widget = new TransformWidget();
TransformWidget GrabbedWidget = null;
bool ShowWidget = true;
ProjectForm ProjectForm = null;
Stack<UndoStep> UndoSteps = new Stack<UndoStep>();
Stack<UndoStep> RedoSteps = new Stack<UndoStep>();
Vector3 UndoStartPosition;
Quaternion UndoStartRotation;
Vector3 UndoStartScale;
WorldSnapMode SnapMode = WorldSnapMode.None;
WorldSnapMode SnapModePrev = WorldSnapMode.Ground;//also the default snap mode
float SnapGridSize = 1.0f;
public bool EditEntityPivot { get; set; } = false;
SettingsForm SettingsForm = null;
WorldSearchForm SearchForm = null;
CutsceneForm CutsceneForm = null;
InputManager Input = new InputManager();
bool toolspanelexpanded = false;
int toolspanellastwidth;
bool toolsPanelResizing = false;
int toolsPanelResizeStartX = 0;
int toolsPanelResizeStartLeft = 0;
int toolsPanelResizeStartRight = 0;
bool initedOk = false;
public WorldForm()
{
InitializeComponent();
Renderer = new Renderer(this, gameFileCache);
camera = Renderer.camera;
timecycle = Renderer.timecycle;
weather = Renderer.weather;
clouds = Renderer.clouds;
CurMouseHit.WorldForm = this;
LastMouseHit.WorldForm = this;
PrevMouseHit.WorldForm = this;
initedOk = Renderer.Init();
}
private void Init()
{
//called from WorldForm_Load
if (!initedOk)
{
Close();
return;
}
MouseWheel += WorldForm_MouseWheel;
if (!GTAFolder.UpdateGTAFolder(true))
{
Close();
return;
}
Widget.Position = new Vector3(1.0f, 10.0f, 100.0f);
Widget.Rotation = Quaternion.Identity;
Widget.Scale = Vector3.One;
Widget.Visible = false;
Widget.OnPositionChange += Widget_OnPositionChange;
Widget.OnRotationChange += Widget_OnRotationChange;
Widget.OnScaleChange += Widget_OnScaleChange;
ymaplist = YmapsTextBox.Text.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
ViewModeComboBox.SelectedIndex = startupviewmode;
BoundsStyleComboBox.SelectedIndex = 0; //LoadSettings will handle this
SelectionModeComboBox.SelectedIndex = 0; //Entity mode
ShowSelectedExtensionTab(false);
toolspanellastwidth = ToolsPanel.Width * 2; //default expanded size
Icons = new List<MapIcon>();
AddIcon("Google Marker", "icon_google_marker_64x64.png", 64, 64, 11.0f, 40.0f, 1.0f);
AddIcon("Glokon Marker", "icon_glokon_normal_32x32.png", 32, 32, 11.0f, 32.0f, 1.0f);
AddIcon("Glokon Debug", "icon_glokon_debug_32x32.png", 32, 32, 11.5f, 32.0f, 1.0f);
MarkerIcon = Icons[1];
LocatorIcon = Icons[2];
foreach (MapIcon icon in Icons)
{
MarkerStyleComboBox.Items.Add(icon);
LocatorStyleComboBox.Items.Add(icon);
}
MarkerStyleComboBox.SelectedItem = MarkerIcon; //LoadSettings will handle this
LocatorStyleComboBox.SelectedItem = LocatorIcon;
LocatorMarker = new MapMarker();
LocatorMarker.Icon = LocatorIcon;
LocatorMarker.IsMovable = true;
//AddDefaultMarkers(); //some POI to start with
ShaderParamNames[] texsamplers = RenderableGeometry.GetTextureSamplerList();
foreach (var texsampler in texsamplers)
{
TextureSamplerComboBox.Items.Add(texsampler);
}
//TextureSamplerComboBox.SelectedIndex = 0; //LoadSettings will handle this
//RenderModeComboBox.SelectedIndex = 0; //Default
WorldMaxLodComboBox.SelectedIndex = 0;//should this be a setting?
WeatherComboBox.SelectedIndex = 0;//show "<Loading...>" until weather types are loaded
CameraModeComboBox.SelectedIndex = 0; //"Perspective"
DlcLevelComboBox.SelectedIndex = 0; //show "<Loading...>" until DLC list is loaded
UpdateToolbarShortcutsText();
Input.Init();
Renderer.Start();
}
private MapIcon AddIcon(string name, string filename, int texw, int texh, float centerx, float centery, float scale)
{
string filepath = PathUtil.GetFilePath("icons\\" + filename);
try
{
MapIcon mi = new MapIcon(name, filepath, texw, texh, centerx, centery, scale);
Icons.Add(mi);
return mi;
}
catch (Exception ex)
{
MessageBox.Show("Could not load map icon " + filepath + " for " + name + "!\n\n" + ex.ToString());
}
return null;
}
public void InitScene(Device device)
{
int width = ClientSize.Width;
int height = ClientSize.Height;
try
{
Renderer.DeviceCreated(device, width, height);
}
catch (Exception ex)
{
MessageBox.Show("Error loading shaders!\n" + ex.ToString());
return;
}
if (Icons != null)
{
foreach (MapIcon icon in Icons)
{
icon.LoadTexture(device, LogError);
}
}
camera.FollowEntity = camEntity;
camEntity.Position = (startupviewmode!=2) ? prevworldpos : Vector3.Zero;
camEntity.Orientation = Quaternion.LookAtLH(Vector3.Zero, Vector3.Up, Vector3.ForwardLH);
space.AddPersistentEntity(pedEntity);
LoadSettings();
formopen = true;
new Thread(new ThreadStart(ContentThread)).Start();
frametimer.Start();
}
public void CleanupScene()
{
formopen = false;
Renderer.DeviceDestroyed();
if (Icons != null)
{
foreach (MapIcon icon in Icons)
{
icon.UnloadTexture();
}
}
int count = 0;
while (running && (count < 5000)) //wait for the content thread to exit gracefully
{
Thread.Sleep(1);
count++;
}
}
public void BuffersResized(int w, int h)
{
Renderer.BuffersResized(w, h);
}
public void RenderScene(DeviceContext context)
{
float elapsed = (float)frametimer.Elapsed.TotalSeconds;
frametimer.Restart();
if (pauserendering) return;
GameFileCache.BeginFrame();
if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50))
{ return; } //couldn't get a lock, try again next time
UpdateControlInputs(elapsed);
space.Update(elapsed);
if (CutsceneForm != null)
{
CutsceneForm.UpdateAnimation(elapsed);
}
Renderer.Update(elapsed, MouseLastPoint.X, MouseLastPoint.Y);
UpdateWidgets();
BeginMouseHitTest();
Renderer.BeginRender(context);
Renderer.RenderSkyAndClouds();
Renderer.SelectedDrawable = SelectedItem.Drawable;
if (renderworld)
{
RenderWorld();
}
else if (rendermaps)
{
RenderYmaps();
}
else
{
RenderSingleItem();
}
UpdateMouseHits();
RenderSelection();
RenderMoused();
Renderer.RenderQueued();
Renderer.RenderBounds(SelectionMode);
Renderer.RenderSelectionGeometry(SelectionMode);
Renderer.RenderFinalPass();
RenderMarkers();
RenderWidgets();
Renderer.EndRender();
Monitor.Exit(Renderer.RenderSyncRoot);
UpdateMarkerSelectionPanelInvoke();
}
public bool ConfirmQuit()
{
if ((ProjectForm != null) && (ProjectForm.CurrentProjectFile != null))
{
if (MessageBox.Show("Are you sure you want to quit CodeWalker?", "Confirm quit", MessageBoxButtons.YesNo) != DialogResult.Yes)
{
return false;
}
}
return true;
}
private void UpdateTimeOfDayLabel()
{
int v = TimeOfDayTrackBar.Value;
float fh = v / 60.0f;
int ih = (int)fh;
int im = v - (ih * 60);
if (ih == 24) ih = 0;
TimeOfDayLabel.Text = string.Format("{0:00}:{1:00}", ih, im);
}
private void UpdateControlInputs(float elapsed)
{
if (elapsed > 0.1f) elapsed = 0.1f;
var s = Settings.Default;
float moveSpeed = 50.0f;
Input.Update();
if (Input.xbenable)
{
if (Input.ControllerButtonJustPressed(GamepadButtonFlags.Start))
{
SetControlMode(ControlMode == WorldControlMode.Free ? WorldControlMode.Ped : WorldControlMode.Free);
}
}
if (ControlMode == WorldControlMode.Free || ControlBrushEnabled)
{
if (Input.ShiftPressed)
{
moveSpeed *= 5.0f;
}
if (Input.CtrlPressed)
{
moveSpeed *= 0.2f;
}
Vector3 movevec = Input.KeyboardMoveVec(MapViewEnabled);
if (Input.xbenable)
{
movevec.X += Input.xblx;
if (MapViewEnabled) movevec.Y += Input.xbly;
else movevec.Z -= Input.xbly;
moveSpeed *= (1.0f + (Math.Min(Math.Max(Input.xblt, 0.0f), 1.0f) * 15.0f)); //boost with left trigger
if (Input.ControllerButtonPressed(GamepadButtonFlags.A | GamepadButtonFlags.RightShoulder | GamepadButtonFlags.LeftShoulder))
{
moveSpeed *= 5.0f;
}
}
if (MapViewEnabled)
{
movevec *= elapsed * moveSpeed * Math.Min(camera.OrthographicTargetSize * 0.01f, 50.0f);
float mapviewscale = 1.0f / camera.Height;
float fdx = MapViewDragX * mapviewscale;
float fdy = MapViewDragY * mapviewscale;
movevec.X -= fdx * camera.OrthographicSize;
movevec.Y += fdy * camera.OrthographicSize;
}
else
{
//normal movement
movevec *= elapsed * moveSpeed * Math.Min(camera.TargetDistance, 20.0f);
}
Vector3 movewvec = camera.ViewInvQuaternion.Multiply(movevec);
camEntity.Position += movewvec;
MapViewDragX = 0;
MapViewDragY = 0;
if (Input.xbenable)
{
camera.ControllerRotate(Input.xbrx, Input.xbry, elapsed);
float zoom = 0.0f;
float zoomspd = s.XInputZoomSpeed;
float zoomamt = zoomspd * elapsed;
if (Input.ControllerButtonPressed(GamepadButtonFlags.DPadUp)) zoom += zoomamt;
if (Input.ControllerButtonPressed(GamepadButtonFlags.DPadDown)) zoom -= zoomamt;
if (MapViewEnabled) zoom -= zoomamt * Input.xbry;
camera.ControllerZoom(zoom);
bool fire = (Input.xbtrigs.Y > 0);
if (fire && !ControlFireToggle)
{
SpawnTestEntity(true);
}
ControlFireToggle = fire;
}
}
else
{
//"play" mode
int mcx, mcy, mcw;
MouseButtons mcb, mcbp;
bool mlb = false, mrb = false;
bool mlbjustpressed = false, mrbjustpressed = false;
lock (MouseControlSyncRoot)
{
mcx = MouseControlX;
mcy = MouseControlY;
mcw = MouseControlWheel;
mcb = MouseControlButtons;
mcbp = MouseControlButtonsPrev;
mlb = ((mcb & MouseButtons.Left) > 0);
mrb = ((mcb & MouseButtons.Right) > 0);
mlbjustpressed = mlb && ((mcbp & MouseButtons.Left) == 0);
mrbjustpressed = mrb && ((mcbp & MouseButtons.Right) == 0);
MouseControlX = 0;
MouseControlY = 0;
MouseControlWheel = 0;
MouseControlButtonsPrev = MouseControlButtons;
//MouseControlButtons = MouseButtons.None;
}
camera.MouseRotate(mcx, mcy);
if (Input.xbenable)
{
camera.ControllerRotate(Input.xbrx, Input.xbry, elapsed);
}
Vector2 movecontrol = new Vector2(Input.xbmainaxes.X, Input.xbmainaxes.Y); //(L stick)
if (Input.kbmovelft) movecontrol.X -= 1.0f;
if (Input.kbmovergt) movecontrol.X += 1.0f;
if (Input.kbmovefwd) movecontrol.Y += 1.0f;
if (Input.kbmovebck) movecontrol.Y -= 1.0f;
movecontrol.X = Math.Min(movecontrol.X, 1.0f);
movecontrol.X = Math.Max(movecontrol.X, -1.0f);
movecontrol.Y = Math.Min(movecontrol.Y, 1.0f);
movecontrol.Y = Math.Max(movecontrol.Y, -1.0f);
Vector3 fwd = camera.ViewDirection;
Vector3 fwdxy = Vector3.Normalize(new Vector3(fwd.X, fwd.Y, 0));
Vector3 lftxy = Vector3.Normalize(Vector3.Cross(fwd, Vector3.UnitZ));
Vector3 move = lftxy * movecontrol.X + fwdxy * movecontrol.Y;
Vector2 movexy = new Vector2(move.X, move.Y);
movexy *= (1.0f + (Math.Min(Math.Max(Input.xblt, 0.0f), 1.0f) * 15.0f)); //boost with left trigger
pedEntity.ControlMovement = movexy;
pedEntity.ControlJump = Input.kbjump || Input.ControllerButtonPressed(GamepadButtonFlags.X);
pedEntity.ControlBoost = Input.ShiftPressed || Input.ControllerButtonPressed(GamepadButtonFlags.A | GamepadButtonFlags.RightShoulder | GamepadButtonFlags.LeftShoulder);
//Vector3 pedfwd = pedEntity.Orientation.Multiply(Vector3.UnitZ);
bool fire = mlb || (Input.xbtrigs.Y > 0);
if (fire && !ControlFireToggle)
{
SpawnTestEntity(true);
}
ControlFireToggle = fire;
}
}
private void RenderWorld()
{
//start point for world view mode rendering.
//also used for the water, paths, collisions, nav mesh, and the project window items.
renderworldVisibleYmapDict.Clear();
int hour = worldymaptimefilter ? (int)Renderer.timeofday : -1;
MetaHash weathertype = worldymapweatherfilter ? ((weather.CurrentWeatherType != null) ? weather.CurrentWeatherType.NameHash : new MetaHash(0)) : new MetaHash(0);
IEnumerable<Entity> spaceEnts = null;
if (renderworld)
{
space.GetVisibleYmaps(camera, hour, weathertype, renderworldVisibleYmapDict);
spaceEnts = space.TemporaryEntities;
}
if (ProjectForm != null)
{
ProjectForm.GetVisibleYmaps(camera, renderworldVisibleYmapDict);
}
if (CutsceneForm != null)
{
CutsceneForm.GetVisibleYmaps(camera, renderworldVisibleYmapDict);
}
Renderer.RenderWorld(renderworldVisibleYmapDict, spaceEnts);
foreach (var ymap in Renderer.VisibleYmaps)
{
UpdateMouseHits(ymap);
}
if (renderwaterquads || (SelectionMode == MapSelectionMode.WaterQuad))
{
RenderWorldWaterQuads();
}
if (SelectionMode == MapSelectionMode.WaveQuad)
{
RenderWorldWaterWaveQuads();
}
if (SelectionMode == MapSelectionMode.CalmingQuad)
{
RenderWorldWaterCalmingQuads();
}
if (rendercollisionmeshes || (SelectionMode == MapSelectionMode.Collision))
{
RenderWorldCollisionMeshes();
}
if (renderpaths || (SelectionMode == MapSelectionMode.Path))
{
RenderWorldPaths();
}
if (rendertraintracks || (SelectionMode == MapSelectionMode.TrainTrack))
{
RenderWorldTrainTracks();
}
if (rendernavmeshes || (SelectionMode == MapSelectionMode.NavMesh))
{
RenderWorldNavMeshes();
}
if (renderscenarios || (SelectionMode == MapSelectionMode.Scenario))
{
RenderWorldScenarios();
}
if (renderpopzones || (SelectionMode == MapSelectionMode.PopZone))
{
RenderWorldPopZones();
}
if (renderheightmaps || (SelectionMode == MapSelectionMode.Heightmap))
{
RenderWorldHeightmaps();
}
if (renderwatermaps || (SelectionMode == MapSelectionMode.Watermap))
{
RenderWorldWatermaps();
}
if (renderaudiozones || (SelectionMode == MapSelectionMode.Audio))
{
RenderWorldAudioZones();
}
}
private void RenderWorldCollisionMeshes()
{
//enqueue collision meshes for rendering - from the world grid
collisionitems.Clear();
space.GetVisibleBounds(camera, collisionmeshrange, collisionmeshlayers, collisionitems);
collisionybns.Clear();
foreach (var item in collisionitems)
{
YbnFile ybn = gameFileCache.GetYbn(item.Name);
if ((ybn != null) && (ybn.Loaded))
{
collisionybns.Add(ybn);
}
}
collisioninteriors.Clear();
foreach (var mlo in Renderer.VisibleMlos)
{
if (mlo.Archetype == null) return;
var hash = mlo.Archetype.Hash;
YbnFile ybn = gameFileCache.GetYbn(hash);
if ((ybn != null) && (ybn.Loaded))
{
collisioninteriors[mlo] = ybn;
}
}
if (ProjectForm != null)
{
ProjectForm.GetVisibleYbns(camera, collisionybns, collisioninteriors);
}
foreach (var ybn in collisionybns)
{
if ((ybn != null) && (ybn.Loaded))
{
Renderer.RenderCollisionMesh(ybn.Bounds, null);
}
}
foreach (var kvp in collisioninteriors)
{
if ((kvp.Value != null) && (kvp.Value.Loaded))
{
Renderer.RenderCollisionMesh(kvp.Value.Bounds, kvp.Key);
}
}
}
private void RenderWorldWaterQuads()
{
var quads = RenderWorldBaseWaterQuads(water.WaterQuads, MapSelectionMode.WaterQuad);
Renderer.RenderWaterQuads(quads);
}
private void RenderWorldWaterCalmingQuads() => RenderWorldBaseWaterQuads(water.CalmingQuads, MapSelectionMode.CalmingQuad);
private void RenderWorldWaterWaveQuads() => RenderWorldBaseWaterQuads(water.WaveQuads, MapSelectionMode.WaveQuad);
private List<T> RenderWorldBaseWaterQuads<T>(IEnumerable<T> quads, MapSelectionMode requiredMode) where T : BaseWaterQuad
{
List<T> renderwaterquadlist = water.GetVisibleQuads<T>(camera, quads);
ProjectForm?.GetVisibleWaterQuads<T>(camera, renderwaterquadlist);
if(SelectionMode == requiredMode) UpdateMouseHits(renderwaterquadlist);
return renderwaterquadlist;
}
private void RenderWorldPaths()
{
renderpathynds.Clear();
space.GetVisibleYnds(camera, renderpathynds);
if (ProjectForm != null)
{
ProjectForm.GetVisibleYnds(camera, renderpathynds);
}
Renderer.RenderPaths(renderpathynds);
UpdateMouseHits(renderpathynds);
}
private void RenderWorldTrainTracks()
{
if (!trains.Inited) return;
rendertraintracklist.Clear();
rendertraintracklist.AddRange(trains.TrainTracks);
if (ProjectForm != null)
{
ProjectForm.GetVisibleTrainTracks(camera, rendertraintracklist);
}
Renderer.RenderTrainTracks(rendertraintracklist);
UpdateMouseHits(rendertraintracklist);
}
private void RenderWorldNavMeshes()
{
rendernavmeshynvs.Clear();
space.GetVisibleYnvs(camera, collisionmeshrange, rendernavmeshynvs);
if (ProjectForm != null)
{
ProjectForm.GetVisibleYnvs(camera, rendernavmeshynvs);
}
Renderer.RenderNavMeshes(rendernavmeshynvs);
UpdateMouseHits(rendernavmeshynvs);
}
private void RenderWorldScenarios()
{
if (!scenarios.Inited) return;
renderscenariolist.Clear();
renderscenariolist.AddRange(scenarios.ScenarioRegions);
if (ProjectForm != null)
{
ProjectForm.GetVisibleScenarios(camera, renderscenariolist);
}
Renderer.RenderScenarios(renderscenariolist);
UpdateMouseHits(renderscenariolist);
}
private void RenderWorldPopZones()
{
if (!popzones.Inited) return;
//renderpopzonelist.Clear();
//renderpopzonelist.AddRange(popzones.Groups.Values);
if (ProjectForm != null)
{
//ProjectForm.GetVisiblePopZones(camera, renderpopzonelist);
}
Renderer.RenderPopZones(popzones);
}
private void RenderWorldHeightmaps()
{
if (!heightmaps.Inited) return;
//renderheightmaplist.Clear();
//renderheightmaplist.AddRange(heightmaps.Heightmaps);
if (ProjectForm != null)
{
//ProjectForm.GetVisibleHeightmaps(camera, renderheightmaplist);
}
Renderer.RenderBasePath(heightmaps);
}
private void RenderWorldWatermaps()
{
if (!watermaps.Inited) return;
//renderwatermaplist.Clear();
//renderwatermaplist.AddRange(watermaps.Watermaps);
if (ProjectForm != null)
{
//ProjectForm.GetVisibleWatermaps(camera, renderwatermaplist);
}
Renderer.RenderBasePath(watermaps);
}
private void RenderWorldAudioZones()
{
if (!audiozones.Inited) return;
renderaudfilelist.Clear();
renderaudfilelist.AddRange(GameFileCache.AudioDatRelFiles);
if (ProjectForm != null)
{
ProjectForm.GetVisibleAudioFiles(camera, renderaudfilelist);
}
renderaudplacementslist.Clear();
audiozones.GetPlacements(renderaudfilelist, renderaudplacementslist);
BoundingBox bbox = new BoundingBox();
BoundingSphere bsph = new BoundingSphere();
Ray mray = new Ray();
mray.Position = camera.MouseRay.Position + camera.Position;
mray.Direction = camera.MouseRay.Direction;
float hitdist = float.MaxValue;
MapBox lastHitOuterBox = new MapBox();
MapSphere lastHitOuterSphere = new MapSphere();
MapBox mb = new MapBox();
MapSphere ms = new MapSphere();
for (int i = 0; i < renderaudplacementslist.Count; i++)
{
var placement = renderaudplacementslist[i];
switch (placement.Shape)
{
case Dat151ZoneShape.Box:
case Dat151ZoneShape.Line:
mb.CamRelPos = placement.InnerPos - camera.Position;
mb.BBMin = placement.InnerMin;
mb.BBMax = placement.InnerMax;
mb.Orientation = placement.InnerOri;
mb.Scale = Vector3.One;
Renderer.HilightBoxes.Add(mb);
if (renderaudioouterbounds)
{
mb.CamRelPos = placement.OuterPos - camera.Position;
mb.BBMin = placement.OuterMin;
mb.BBMax = placement.OuterMax;
mb.Orientation = placement.OuterOri;
mb.Scale = Vector3.One;
Renderer.BoundingBoxes.Add(mb);
}
Vector3 hbcamrel = (placement.Position - camera.Position);
Ray mraytrn = new Ray();
mraytrn.Position = placement.OrientationInv.Multiply(camera.MouseRay.Position - hbcamrel);
mraytrn.Direction = placement.OrientationInv.Multiply(mray.Direction);
bbox.Minimum = placement.HitboxMin;
bbox.Maximum = placement.HitboxMax;
if (mraytrn.Intersects(ref bbox, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0))
{
CurMouseHit.Audio = placement;
CurMouseHit.HitDist = hitdist;
CurMouseHit.CamRel = hbcamrel;
CurMouseHit.AABB = bbox;
lastHitOuterBox = mb; //highlight the outer box
}
break;
case Dat151ZoneShape.Sphere:
if ((placement.InnerPos != Vector3.Zero) && (placement.OuterPos != Vector3.Zero))
{
ms.CamRelPos = placement.InnerPos - camera.Position;
ms.Radius = placement.InnerRadius;
Renderer.HilightSpheres.Add(ms);
if (renderaudioouterbounds)
{
ms.CamRelPos = placement.OuterPos - camera.Position;
ms.Radius = placement.OuterRadius;
Renderer.BoundingSpheres.Add(ms);
}
bsph.Center = placement.Position;
bsph.Radius = placement.HitSphereRad;
if (mray.Intersects(ref bsph, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0))
{
CurMouseHit.Audio = placement;
CurMouseHit.HitDist = hitdist;
CurMouseHit.CamRel = placement.Position - camera.Position;
CurMouseHit.AABB = new BoundingBox(); //no box here
CurMouseHit.BSphere = bsph;
lastHitOuterSphere = ms; //highlight the outer sphere
}
}
else
{ }
break;
default:
break;//shouldn't get here
}
}
if (CurMouseHit.Audio != null)
{
//hilight the outer bounds of moused item
switch (CurMouseHit.Audio.Shape)
{
case Dat151ZoneShape.Box:
case Dat151ZoneShape.Line:
Renderer.HilightBoxes.Add(lastHitOuterBox);
break;
case Dat151ZoneShape.Sphere:
Renderer.HilightSpheres.Add(lastHitOuterSphere);
break;
}
}
}
private void RenderSingleItem()
{
//start point for model view mode rendering
uint hash = 0;// JenkHash.GenHash(modelname);
if (!uint.TryParse(modelname, out hash)) //try use a hash directly
{
hash = JenkHash.GenHash(modelname);
}
Archetype arche = gameFileCache.GetArchetype(hash);
Archetype selarch = null;
DrawableBase seldrwbl = null;
YmapEntityDef selent = null;
if (arche != null)
{
Renderer.RenderArchetype(arche, null);
selarch = arche;
}
else
{
YmapFile ymap = gameFileCache.GetYmap(hash);
if (ymap != null)
{
Renderer.RenderYmap(ymap);
}
else
{
//not a ymap... see if it's a ydr or yft
YdrFile ydr = gameFileCache.GetYdr(hash);
if (ydr != null)
{
if (ydr.Loaded)
{
Renderer.RenderDrawable(ydr.Drawable, null, null, hash);
seldrwbl = ydr.Drawable;
}
}
else
{
YftFile yft = gameFileCache.GetYft(hash);
if (yft != null)
{
if (yft.Loaded)
{
if (yft.Fragment != null)
{
var f = yft.Fragment;
Renderer.RenderFragment(null, null, f, hash);
seldrwbl = f.Drawable;
}
}
}
else
{
//TODO: collision bounds single model...
//YbnFile ybn = gameFileCache.GetYbn(hash);
}
}
}
}
if ((selarch != null) && (seldrwbl == null))
{
seldrwbl = gameFileCache.TryGetDrawable(selarch);
}
//select this item for viewing by the UI...
if ((SelectedItem.Archetype != selarch) || (SelectedItem.Drawable != seldrwbl) || (SelectedItem.EntityDef != selent))
{
SelectedItem.Clear();
SelectedItem.Archetype = selarch;
SelectedItem.Drawable = seldrwbl;
SelectedItem.EntityDef = selent;
UpdateSelectionUI(false);
}
}
private void RenderYmaps()
{
//start point for ymap view mode rendering
foreach (string lod in ymaplist)
{
uint hash = JenkHash.GenHash(lod);
YmapFile ymap = gameFileCache.GetYmap(hash);
Renderer.RenderYmap(ymap);
UpdateMouseHits(ymap);
}
}
private void RenderMoused()
{
//immediately render the bounding box of the currently moused entity.
if (!MouseSelectEnabled)
{ return; }
PrevMouseHit = LastMouseHit;
LastMouseHit = CurMouseHit;
bool change = LastMouseHit.CheckForChanges(PrevMouseHit); //(LastMouseHit.EntityDef != PrevMouseHit.EntityDef);
if (SelectByGeometry)
{
change = change || (LastMouseHit.Geometry != PrevMouseHit.Geometry);
}
if (change)
{
string text = LastMouseHit.GetFullNameString(string.Empty);
UpdateMousedLabel(text);
}
if(!CurMouseHit.HasHit)
{ return; }
BoundsShaderMode mode = BoundsShaderMode.Box;
float bsphrad = CurMouseHit.BSphere.Radius;
Vector3 bbmin = CurMouseHit.AABB.Minimum;
Vector3 bbmax = CurMouseHit.AABB.Maximum;
Vector3 camrel = CurMouseHit.CamRel;
Vector3 scale = Vector3.One;
Quaternion ori = Quaternion.Identity;
bool ext = (CurMouseHit.ArchetypeExtension != null) || (CurMouseHit.EntityExtension != null) || (CurMouseHit.CollisionBounds != null);
if (CurMouseHit.EntityDef != null)
{
scale = ext ? Vector3.One : CurMouseHit.EntityDef.Scale;
ori = CurMouseHit.EntityDef.Orientation;
}
if (CurMouseHit.Archetype != null)
{
bbmin = CurMouseHit.Archetype.BBMin;
bbmax = CurMouseHit.Archetype.BBMax;
}
if ((CurMouseHit.Geometry != null) || ext)
{
bbmin = CurMouseHit.AABB.Minimum; //override archetype AABB..
bbmax = CurMouseHit.AABB.Maximum;
}
if (CurMouseHit.CarGenerator != null)
{
ori = CurMouseHit.CarGenerator.Orientation;
}
if (CurMouseHit.BoxOccluder != null)
{
ori = CurMouseHit.BoxOccluder.Orientation;
}
if (CurMouseHit.OccludeModelTri != null)
{
var otri = CurMouseHit.OccludeModelTri;
Renderer.RenderSelectionTriangleOutline(otri.Corner1, otri.Corner2, otri.Corner3, 0xFFFFFFFF);
return;
}
if (CurMouseHit.MloEntityDef != null)
{
scale = Vector3.One;
}
if (CurMouseHit.WaterQuad != null)
{
}
if (CurMouseHit.ScenarioNode != null)
{
var sp = CurMouseHit.ScenarioNode.MyPoint;
if (sp == null) sp = CurMouseHit.ScenarioNode.ClusterMyPoint;
if (sp != null) //orientate the moused box for the correct scenario point direction...
{
ori = sp.Orientation;
}
}
if (CurMouseHit.NavPoint != null)
{
ori = CurMouseHit.NavPoint.Orientation;
}
if (CurMouseHit.NavPortal != null)
{
ori = CurMouseHit.NavPortal.Orientation;
}
if (CurMouseHit.NavPoly != null)
{
Renderer.RenderSelectionNavPolyOutline(CurMouseHit.NavPoly, 0xFFFFFFFF);
return;
}
if (CurMouseHit.Audio != null)
{
ori = CurMouseHit.Audio.Orientation;
if (CurMouseHit.Audio.Shape == Dat151ZoneShape.Sphere)
{
mode = BoundsShaderMode.Sphere;
}
}
if (CurMouseHit.CollisionVertex != null)
{
var vpos = CurMouseHit.CollisionVertex.Position;
var crpos = camrel + ori.Multiply(vpos);
var vertexSize = 0.1f;
Renderer.RenderSelectionCircle(vpos, vertexSize, 0xFFFFFFFF);
}
if (CurMouseHit.CollisionPoly != null)
{
Renderer.RenderSelectionCollisionPolyOutline(CurMouseHit.CollisionPoly, 0xFFFFFFFF, CurMouseHit.EntityDef);
}
if (CurMouseHit.CollisionBounds != null)
{
ori = ori * CurMouseHit.BBOrientation;
}
Renderer.RenderMouseHit(mode, ref camrel, ref bbmin, ref bbmax, ref scale, ref ori, bsphrad);
}
private void RenderSelection()
{
if (SelectedItem.MultipleSelectionItems != null)
{
for (int i = 0; i < SelectedItem.MultipleSelectionItems.Length; i++)
{
var item = SelectedItem.MultipleSelectionItems[i];
RenderSelection(ref item);
}
}
else
{
RenderSelection(ref SelectedItem);
}
}
private void RenderSelection(ref MapSelection selectionItem)
{
//immediately render the bounding box of the current selection. also, arrows.
const uint cred = 0xFF0000FF;
const uint cgrn = 0xFF00FF00;
const uint cblu = 0xFFFF0000;
const uint caqu = 0xFFFFFF00;
//const uint cyel = 0xFF00FFFF;
if (ControlBrushEnabled && MouseRayCollision.Hit)
{
var arup = MouseRayCollision.Normal.GetPerpVec();
Renderer.RenderBrushRadiusOutline(MouseRayCollision.Position, MouseRayCollision.Normal, arup, ProjectForm.GetInstanceBrushRadius(), cgrn);
}
if (MouseRayCollisionVisible && MouseRayCollision.Hit)
{
var arup = MouseRayCollision.Normal.GetPerpVec();
Renderer.RenderSelectionArrowOutline(MouseRayCollision.Position, MouseRayCollision.Normal, arup, Quaternion.Identity, 1.0f, 0.05f, cgrn);
}
if (!ShowSelectionBounds)
{ return; }
if (!selectionItem.HasValue)
{ return; }
BoundsShaderMode mode = BoundsShaderMode.Box;
float bsphrad = selectionItem.BSphere.Radius;
Vector3 bbmin = selectionItem.AABB.Minimum;
Vector3 bbmax = selectionItem.AABB.Maximum;
Vector3 camrel = -camera.Position;
Vector3 scale = Vector3.One;
Quaternion ori = Quaternion.Identity;
var arch = selectionItem.Archetype;
var ent = selectionItem.EntityDef;
if (selectionItem.Archetype != null)
{
bbmin = selectionItem.Archetype.BBMin;
bbmax = selectionItem.Archetype.BBMax;
}
if (selectionItem.EntityDef != null)
{
camrel = ent.Position - camera.Position;
scale = ent.Scale;
ori = ent.Orientation;
if (EditEntityPivot)
{
Renderer.RenderSelectionEntityPivot(ent);
}
}
if (selectionItem.CarGenerator != null)
{
var cg = selectionItem.CarGenerator;
camrel = cg.Position - camera.Position;
ori = cg.Orientation;
bbmin = cg.BBMin;
bbmax = cg.BBMax;
float arrowlen = cg._CCarGen.perpendicularLength;
float arrowrad = arrowlen * 0.066f;
Renderer.RenderSelectionArrowOutline(cg.Position, Vector3.UnitX, Vector3.UnitY, ori, arrowlen, arrowrad, cgrn);
if (!Renderer.rendercars)//only render selected car if not already rendering cars..
{
Quaternion cgtrn = Quaternion.RotationAxis(Vector3.UnitZ, (float)Math.PI * -0.5f); //car fragments currently need to be rotated 90 deg right...
Quaternion cgori = Quaternion.Multiply(ori, cgtrn);
Renderer.RenderCar(cg.Position, cgori, cg._CCarGen.carModel, cg._CCarGen.popGroup);
}
}
if (selectionItem.WaveQuad != null)
{
var quad = selectionItem.WaveQuad;
Vector3 quadArrowPos = new Vector3(quad.minX + (quad.maxX - quad.minX) * 0.5f, quad.minY + (quad.maxY - quad.minY) * 0.5f, 5);
Quaternion waveOri = quad.WaveOrientation;
float arrowlen = quad.Amplitude * 50;
float arrowrad = arrowlen * 0.066f;
Renderer.RenderSelectionArrowOutline(quadArrowPos, Vector3.UnitX, Vector3.UnitY, waveOri, arrowlen, arrowrad, cgrn);
}
if (selectionItem.LodLight != null)
{
Renderer.RenderSelectionLodLight(selectionItem.LodLight);
if (selectionItem.LodLight.LodLights != null)
{
bbmin = selectionItem.LodLight.LodLights.BBMin;
bbmax = selectionItem.LodLight.LodLights.BBMax;
}
}
if (selectionItem.PathNode != null)
{
camrel = selectionItem.PathNode.Position - camera.Position;
}
if (selectionItem.TrainTrackNode != null)
{
camrel = selectionItem.TrainTrackNode.Position - camera.Position;
}
if (selectionItem.ScenarioNode != null)
{
camrel = selectionItem.ScenarioNode.Position - camera.Position;
var sn = selectionItem.ScenarioNode;
//render direction arrow for ScenarioPoint
ori = sn.Orientation;
float arrowlen = 2.0f;
float arrowrad = 0.25f;
Renderer.RenderSelectionArrowOutline(sn.Position, Vector3.UnitY, Vector3.UnitZ, ori, arrowlen, arrowrad, cgrn);
MCScenarioPoint vpoint = sn.MyPoint ?? sn.ClusterMyPoint;
if ((vpoint != null) && (vpoint?.Type?.IsVehicle ?? false))
{
var vhash = vpoint.ModelSet?.NameHash ?? 493038497;//"none"
if ((vhash == 0) || (vhash == 493038497))
{
vhash = vpoint.Type?.VehicleModelSetHash ?? 0;
}
if ((vhash == 0) && (sn.ChainingNode?.Chain?.Edges != null) && (sn.ChainingNode.Chain.Edges.Length > 0))
{
var fedge = sn.ChainingNode.Chain.Edges[0]; //for chain nodes, show the first node's model...
var fnode = fedge?.NodeFrom?.ScenarioNode;
if (fnode != null)
{
vpoint = fnode.MyPoint ?? fnode.ClusterMyPoint;
vhash = vpoint.ModelSet?.NameHash ?? 493038497;//"none"
if ((vhash == 0) || (vhash == 493038497))
{
vhash = vpoint.Type?.VehicleModelSetHash ?? 0;
}
}
}
Renderer.RenderCar(sn.Position, sn.Orientation, 0, vhash, true);
}
}
if (selectionItem.ScenarioEdge != null)
{
//render scenario edge arrow
var se = selectionItem.ScenarioEdge;
var sn1 = se.NodeFrom;
var sn2 = se.NodeTo;
if ((sn1 != null) && (sn2 != null))
{
var dirp = sn2.Position - sn1.Position;
float dl = dirp.Length();
Vector3 dir = dirp * (1.0f / dl);
Vector3 dup = Vector3.UnitZ;
var aori = Quaternion.Invert(Quaternion.RotationLookAtRH(dir, dup));
float arrowrad = 0.25f;
float arrowlen = Math.Max(dl - arrowrad*5.0f, 0);
Renderer.RenderSelectionArrowOutline(sn1.Position, -Vector3.UnitZ, Vector3.UnitY, aori, arrowlen, arrowrad, cblu);
}
}
if (selectionItem.MloEntityDef != null)
{
bbmin = selectionItem.AABB.Minimum;
bbmax = selectionItem.AABB.Maximum;
var mlo = selectionItem.MloEntityDef;
var mlop = mlo.Position;
var mloa = mlo.Archetype as MloArchetype;
if (mloa != null)
{
VertexTypePC p1 = new VertexTypePC();
VertexTypePC p2 = new VertexTypePC();
if (mloa.portals != null)
{
for (int ip = 0; ip < mloa.portals.Length; ip++)
{
var portal = mloa.portals[ip];
if (portal.Corners == null) continue;
p2.Colour = caqu;
if ((portal._Data.flags & 4) > 0)
{
p2.Colour = cblu;
}
var pcl = portal.Corners.Length;
for (int ic = 0; ic < pcl; ic++)
{
var icn = ic + 1; if (icn >= pcl) icn = 0;
p1.Colour = (ic == 0) ? cred : p2.Colour;//highlight index 0 and winding direction
p1.Position = mlop + mlo.Orientation.Multiply(portal.Corners[ic].XYZ());
p2.Position = mlop + mlo.Orientation.Multiply(portal.Corners[icn].XYZ());
Renderer.SelectionLineVerts.Add(p1);
Renderer.SelectionLineVerts.Add(p2);
}
}
}
if (mloa.rooms != null)
{
MapBox wbox = new MapBox();
wbox.Scale = Vector3.One;
for (int ir = 0; ir < mloa.rooms.Length; ir++)
{
var room = mloa.rooms[ir];
wbox.CamRelPos = mlop - camera.Position;
wbox.BBMin = room._Data.bbMin;// + offset;
wbox.BBMax = room._Data.bbMax;// + offset;
wbox.Orientation = mlo.Orientation;
if ((ir == 0) || (room.RoomName == "limbo"))
{
bbmin = room._Data.bbMin;
bbmax = room._Data.bbMax;
//////Renderer.BoundingBoxes.Add(wbox);
}
else
{
wbox.BBMin = room.BBMin_CW; //hack method to use CW calculated room AABBs,
wbox.BBMax = room.BBMax_CW; //R* ones are right size, but wrong position??
Renderer.WhiteBoxes.Add(wbox);
}
}
}
}
}
if (selectionItem.MloRoomDef != null)
{
camrel += ori.Multiply(selectionItem.BBOffset);
ori = ori * selectionItem.BBOrientation;
}
if ((selectionItem.ArchetypeExtension != null) || (selectionItem.EntityExtension != null) || (selectionItem.CollisionBounds != null))
{
bbmin = selectionItem.AABB.Minimum;
bbmax = selectionItem.AABB.Maximum;
scale = Vector3.One;
}
if (selectionItem.GrassBatch != null)
{
bbmin = selectionItem.GrassBatch.AABBMin;
bbmax = selectionItem.GrassBatch.AABBMax;
scale = Vector3.One;
}
if (selectionItem.BoxOccluder != null)
{
var bo = selectionItem.BoxOccluder;
camrel = bo.Position - camera.Position;
ori = bo.Orientation;
bbmin = bo.BBMin;
bbmax = bo.BBMax;
}
if (selectionItem.OccludeModelTri != null)
{
var ot = selectionItem.OccludeModelTri;
var om = ot.Model;
bbmin = om._OccludeModel.bmin;
bbmax = om._OccludeModel.bmax;
Renderer.RenderSelectionTriangleOutline(ot.Corner1, ot.Corner2, ot.Corner3, cgrn);
}
if (selectionItem.NavPoly != null)
{
Renderer.RenderSelectionNavPoly(selectionItem.NavPoly);
Renderer.RenderSelectionNavPolyOutline(selectionItem.NavPoly, cgrn);
return;//don't render a selection box for nav poly
}
if (selectionItem.NavPoint != null)
{
var navp = selectionItem.NavPoint;
camrel = navp.Position - camera.Position;
//render direction arrow for NavPoint
ori = navp.Orientation;
float arrowlen = 2.0f;
float arrowrad = 0.25f;
Renderer.RenderSelectionArrowOutline(navp.Position, -Vector3.UnitY, Vector3.UnitZ, ori, arrowlen, arrowrad, cgrn);
}
if (selectionItem.NavPortal != null)
{
var navp = selectionItem.NavPortal;
camrel = navp.Position - camera.Position;
//render direction arrow for NavPortal
ori = navp.Orientation;
float arrowlen = 2.0f;
float arrowrad = 0.25f;
Renderer.RenderSelectionArrowOutline(navp.Position, Vector3.UnitY, Vector3.UnitZ, ori, arrowlen, arrowrad, cgrn);
}
if (selectionItem.Audio != null)
{
var au = selectionItem.Audio;
camrel = au.Position - camera.Position;
ori = au.Orientation;
bbmin = au.HitboxMin;
bbmax = au.HitboxMax;
if (selectionItem.Audio.Shape == Dat151ZoneShape.Sphere)
{
mode = BoundsShaderMode.Sphere;
MapSphere wsph = new MapSphere();
wsph.CamRelPos = au.OuterPos - camera.Position;
wsph.Radius = au.OuterRadius;
Renderer.WhiteSpheres.Add(wsph);
}
else
{
MapBox wbox = new MapBox();
wbox.CamRelPos = au.OuterPos - camera.Position;
wbox.BBMin = au.OuterMin;
wbox.BBMax = au.OuterMax;
wbox.Orientation = au.OuterOri;
wbox.Scale = scale;
Renderer.WhiteBoxes.Add(wbox);
}
}
if (selectionItem.CollisionVertex != null)
{
var vpos = selectionItem.CollisionVertex.Position;
var crpos = camrel + ori.Multiply(vpos);
var vertexSize = 0.1f;
Renderer.RenderSelectionCircle(vpos, vertexSize, cgrn);
}
else if (selectionItem.CollisionPoly != null)
{
Renderer.RenderSelectionCollisionPolyOutline(selectionItem.CollisionPoly, cgrn, selectionItem.EntityDef);
}
if (selectionItem.CollisionBounds != null)
{
camrel += ori.Multiply(selectionItem.BBOffset);
ori = ori * selectionItem.BBOrientation;
}
if (mode == BoundsShaderMode.Box)
{
MapBox box = new MapBox();
box.CamRelPos = camrel;
box.BBMin = bbmin;
box.BBMax = bbmax;
box.Orientation = ori;
box.Scale = scale;
Renderer.SelectionBoxes.Add(box);
}
else if (mode == BoundsShaderMode.Sphere)
{
MapSphere sph = new MapSphere();
sph.CamRelPos = camrel;
sph.Radius = bsphrad;
Renderer.SelectionSpheres.Add(sph);
}
}
private void RenderMarkers()
{
//immediately render all the current markers.
lock (markersyncroot) //should only cause delays if markers moved/updated
{
foreach (var marker in Markers)
{
marker.CamRelPos = marker.WorldPos - camera.Position;
marker.Distance = marker.CamRelPos.Length();
marker.ScreenPos = camera.ViewProjMatrix.MultiplyW(marker.CamRelPos);
}
lock (markersortedsyncroot) //stop collisions with mouse testing
{
SortedMarkers.Clear();
SortedMarkers.AddRange(Markers);
if (RenderLocator)
{
LocatorMarker.CamRelPos = LocatorMarker.WorldPos - camera.Position;
LocatorMarker.Distance = LocatorMarker.CamRelPos.Length();
LocatorMarker.ScreenPos = camera.ViewProjMatrix.MultiplyW(LocatorMarker.CamRelPos);
SortedMarkers.Add(LocatorMarker);
}
SortedMarkers.Sort((m1, m2) => m2.Distance.CompareTo(m1.Distance));
}
MarkerBatch.Clear();
MarkerBatch.AddRange(SortedMarkers);
}
Renderer.RenderMarkers(MarkerBatch);
}
private void RenderWidgets()
{
if (!ShowWidget) return;
Renderer.RenderTransformWidget(Widget);
}
private void UpdateWidgets()
{
if (!ShowWidget) return;
Widget.Update(camera);
}
private Vector3 GetGroundPoint(Vector3 p)
{
float uplimit = 3.0f;
float downlimit = 20.0f;
Ray ray = new Ray(p, new Vector3(0, 0, -1.0f));
ray.Position.Z += 0.1f;
SpaceRayIntersectResult hit = space.RayIntersect(ray, downlimit);
if (hit.Hit)
{
return hit.Position;
}
ray.Position.Z += uplimit;
hit = space.RayIntersect(ray, downlimit);
if (hit.Hit)
{
return hit.Position;
}
return p;
}
private Vector3 SnapPosition(Vector3 p)
{
Vector3 gpos = (p / SnapGridSize).Round() * SnapGridSize;
switch (SnapMode)
{
case WorldSnapMode.Grid:
p = gpos;
break;
case WorldSnapMode.Ground:
p = GetGroundPoint(p);
break;
case WorldSnapMode.Hybrid:
p = GetGroundPoint(gpos);
break;
}
return p;
}
private void Widget_OnPositionChange(Vector3 newpos, Vector3 oldpos)
{
//called during UpdateWidgets()
newpos = SnapPosition(newpos);
if (newpos == oldpos) return;
SelectedItem.SetPosition(newpos, EditEntityPivot);
SelectedItem.UpdateGraphics(this);
if (ProjectForm != null)
{
ProjectForm.OnWorldSelectionModified(SelectedItem);
}
}
private void Widget_OnRotationChange(Quaternion newrot, Quaternion oldrot)
{
//called during UpdateWidgets()
if (newrot == oldrot) return;
SelectedItem.SetRotation(newrot, EditEntityPivot);
SelectedItem.UpdateGraphics(this);
if (ProjectForm != null)
{
ProjectForm.OnWorldSelectionModified(SelectedItem);
}
}
private void Widget_OnScaleChange(Vector3 newscale, Vector3 oldscale)
{
//called during UpdateWidgets()
if (newscale == oldscale) return;
SelectedItem.SetScale(newscale, EditEntityPivot);
SelectedItem.UpdateGraphics(this);
if (ProjectForm != null)
{
ProjectForm.OnWorldSelectionModified(SelectedItem);
}
}
public void SetWidgetPosition(Vector3 pos, bool enableUndo = false)
{
if (enableUndo)
{
SetWidgetMode("Position");
MarkUndoStart(Widget);
}
Widget.Position = pos;
if (enableUndo)
{
MarkUndoEnd(Widget);
}
}
public void SetWidgetRotation(Quaternion q, bool enableUndo = false)
{
if (enableUndo)
{
SetWidgetMode("Rotation");
MarkUndoStart(Widget);
}
Widget.Rotation = q;
if (enableUndo)
{
MarkUndoEnd(Widget);
}
}
public void SetWidgetScale(Vector3 s, bool enableUndo = false)
{
if (enableUndo)
{
SetWidgetMode("Scale");
MarkUndoStart(Widget);
}
Widget.Scale = s;
if (enableUndo)
{
MarkUndoEnd(Widget);
}
}
public void ChangeMultiPosition(MapSelection[] items, Vector3 pos, bool editPivot = false)
{
if (items == SelectedItem.MultipleSelectionItems)
{
SelectedItem.SetPosition(pos, editPivot);
SetWidgetPosition(pos, true);
}
}
public void ChangeMultiRotation(MapSelection[] items, Quaternion rot, bool editPivot = false)
{
if (items == SelectedItem.MultipleSelectionItems)
{
SelectedItem.SetRotation(rot, editPivot);
SetWidgetRotation(rot, true);
}
}
public void ChangeMultiScale(MapSelection[] items, Vector3 scale, bool editPivot = false)
{
if (items == SelectedItem.MultipleSelectionItems)
{
SelectedItem.SetScale(scale, editPivot);
SetWidgetScale(scale, true);
}
}
public void UpdatePathYndGraphics(YndFile ynd, bool fullupdate)
{
if (ynd == null)
{
return;
}
var selection = SelectedItem.PathNode != null
? new[] { SelectedItem.PathNode }
: null;
if (fullupdate)
{
ynd.UpdateAllNodePositions();
ynd.BuildBVH();
space.BuildYndData(ynd);
}
else
{
ynd.UpdateAllNodePositions();
space.BuildYndVerts(ynd, selection);
}
//lock (Renderer.RenderSyncRoot)
{
Renderer.Invalidate(ynd);
}
}
public void UpdatePathNodeGraphics(YndNode pathnode, bool fullupdate)
{
if (pathnode == null) return;
pathnode.Ynd.UpdateBvhForNode(pathnode);
UpdatePathYndGraphics(pathnode.Ynd, fullupdate);
}
public YndNode GetPathNodeFromSpace(ushort areaid, ushort nodeid)
{
return space.NodeGrid.GetYndNode(areaid, nodeid);
}
public void UpdateCollisionBoundsGraphics(Bounds b)
{
lock (Renderer.RenderSyncRoot)
{
if (b is BoundBVH bvh)
{
bvh.BuildBVH();
}
else if (b is BoundComposite bc)
{
bc.BuildBVH();
}
var ib = b;
while (ib.Parent != null)
{
ib = ib.Parent;
}
Renderer.Invalidate(ib);
}
}
public void UpdateNavYnvGraphics(YnvFile ynv, bool fullupdate)
{
ynv.UpdateAllNodePositions();
ynv.UpdateTriangleVertices();
ynv.BuildBVH();
//lock (Renderer.RenderSyncRoot)
{
Renderer.Invalidate(ynv);
}
}
public void UpdateNavPolyGraphics(YnvPoly poly, bool fullupdate)
{
if (poly == null) return;
//poly.Ynv.UpdateBvhForPoly(poly);//TODO!
UpdateNavYnvGraphics(poly.Ynv, fullupdate);
}
public void UpdateNavPointGraphics(YnvPoint point, bool fullupdate)
{
if (point == null) return;
//poly.Ynv.UpdateBvhForPoint(point);//TODO!
UpdateNavYnvGraphics(point.Ynv, fullupdate);
}
public void UpdateNavPortalGraphics(YnvPortal portal, bool fullupdate)
{
if (portal == null) return;
//poly.Ynv.UpdateBvhForPortal(portal);//TODO!
UpdateNavYnvGraphics(portal.Ynv, fullupdate);
}
public void UpdateTrainTrackGraphics(TrainTrack tt, bool fullupdate)
{
tt.BuildVertices();
tt.BuildBVH();
//if (fullupdate)
//{
// //space.BuildYndData(ynd);
//}
//else
//{
// //space.BuildYndVerts(ynd);
//}
//lock (Renderer.RenderSyncRoot)
{
Renderer.Invalidate(tt);
}
}
public void UpdateTrainTrackNodeGraphics(TrainTrackNode node, bool fullupdate)
{
if (node == null) return;
node.Track.UpdateBvhForNode(node);
UpdateTrainTrackGraphics(node.Track, fullupdate);
}
public void UpdateScenarioGraphics(YmtFile ymt, bool fullupdate)
{
var scenario = ymt.ScenarioRegion;
if (scenario == null) return;
scenario.BuildBVH();
scenario.BuildVertices();
//lock (Renderer.RenderSyncRoot)
{
Renderer.Invalidate(scenario);
}
}
public void UpdateLodLightGraphics(YmapLODLight lodlight)
{
lodlight.LodLights?.BuildBVH();
//lock (Renderer.RenderSyncRoot)
{
Renderer.Invalidate(lodlight);
}
}
public void UpdateBoxOccluderGraphics(YmapBoxOccluder box)
{
//lock (Renderer.RenderSyncRoot)
{
Renderer.Invalidate(box);
}
}
public void UpdateOccludeModelGraphics(YmapOccludeModel model)
{
model.BuildBVH();
model.BuildVertices();
//lock (Renderer.RenderSyncRoot)
{
Renderer.Invalidate(model);
}
}
public void UpdateGrassBatchGraphics(YmapGrassInstanceBatch grassBatch)
{
//lock (Renderer.RenderSyncRoot)
{
Renderer.Invalidate(grassBatch);
}
}
public void UpdateAudioPlacementGraphics(RelFile rel)
{
audiozones.PlacementsDict.Remove(rel); //should cause a rebuild to add/remove items
}
public AudioPlacement GetAudioPlacement(RelFile rel, Dat151RelData reldata)
{
var placement = audiozones.FindPlacement(rel, reldata);
if (placement == null)
{
if (reldata is Dat151AmbientZone az) placement = new AudioPlacement(rel, az);
if (reldata is Dat151AmbientRule ar) placement = new AudioPlacement(rel, ar);
if (reldata is Dat151StaticEmitter se) placement = new AudioPlacement(rel, se);
}
return placement;
}
public void SetCameraTransform(Vector3 pos, Quaternion rot)
{
camera.FollowEntity.Position = pos;
camera.FollowEntity.Orientation = rot;
camera.FollowEntity.OrientationInv = Quaternion.Invert(rot);
camera.TargetRotation = Vector3.Zero;
camera.TargetDistance = 0.01f;
}
public void SetCameraClipPlanes(float znear, float zfar)
{
//sets the camera clip planes to the specified values, for use in eg cutscenes
camera.ZNear = znear;
camera.ZFar = zfar;
camera.UpdateProj = true;
}
public void ResetCameraClipPlanes()
{
//resets the camera clip planes to the values in the UI controls.
camera.ZNear = (float)NearClipUpDown.Value;
camera.ZFar = (float)FarClipUpDown.Value;
camera.UpdateProj = true;
}
public Vector3 GetCameraPosition()
{
//currently used by ProjectForm when creating entities
lock (Renderer.RenderSyncRoot)
{
return camera.Position;
}
}
public Vector3 GetCameraViewDir()
{
//currently used by ProjectForm when creating entities
lock (Renderer.RenderSyncRoot)
{
return camera.ViewDirection;
}
}
public void SetCameraSensitivity(float sensitivity, float smoothing)
{
camera.Sensitivity = sensitivity;
camera.Smoothness = smoothing;
}
public void SetMouseInverted(bool invert)
{
MouseInvert = invert;
}
public void SetKeyBindings(KeyBindings kb)
{
Input.keyBindings = kb.Copy();
UpdateToolbarShortcutsText();
}
private void UpdateToolbarShortcutsText()
{
var kb = Input.keyBindings;
ToolbarSelectButton.ToolTipText = string.Format("Select objects / Exit edit mode ({0}, {1})", kb.ToggleMouseSelect, kb.ExitEditMode);
ToolbarMoveButton.ToolTipText = string.Format("Move ({0})", kb.EditPosition);
ToolbarRotateButton.ToolTipText = string.Format("Rotate ({0})", kb.EditRotation);
ToolbarScaleButton.ToolTipText = string.Format("Scale ({0})", kb.EditScale);
ShowToolbarCheckBox.Text = string.Format("Show Toolbar ({0})", kb.ToggleToolbar);
}
private MapBox GetExtensionBox(Vector3 camrel, MetaWrapper ext)
{
MapBox b = new MapBox();
Vector3 pos = Vector3.Zero;
float size = 0.5f;
if (ext is MCExtensionDefLightEffect)
{
var le = ext as MCExtensionDefLightEffect;
pos = le.Data.offsetPosition;
}
else if (ext is MCExtensionDefSpawnPointOverride)
{
var spo = ext as MCExtensionDefSpawnPointOverride;
pos = spo.Data.offsetPosition;
size = spo.Data.Radius;
}
else if (ext is MCExtensionDefDoor)
{
var door = ext as MCExtensionDefDoor;
pos = door.Data.offsetPosition;
}
else if (ext is Mrage__phVerletClothCustomBounds)
{
var cb = ext as Mrage__phVerletClothCustomBounds;
if ((cb.CollisionData != null) && (cb.CollisionData.Length > 0))
{
pos = cb.CollisionData[0].Data.Position;
}
}
else if (ext is MCExtensionDefParticleEffect)
{
var pe = ext as MCExtensionDefParticleEffect;
pos = pe.Data.offsetPosition;
}
else if (ext is MCExtensionDefAudioCollisionSettings)
{
var acs = ext as MCExtensionDefAudioCollisionSettings;
pos = acs.Data.offsetPosition;
}
else if (ext is MCExtensionDefAudioEmitter)
{
var ae = ext as MCExtensionDefAudioEmitter;
pos = ae.Data.offsetPosition;
}
else if (ext is MCExtensionDefSpawnPoint)
{
var sp = ext as MCExtensionDefSpawnPoint;
pos = sp.Data.offsetPosition;
}
else if (ext is MCExtensionDefExplosionEffect)
{
var ee = ext as MCExtensionDefExplosionEffect;
pos = ee.Data.offsetPosition;
}
else if (ext is MCExtensionDefLadder)
{
var ld = ext as MCExtensionDefLadder;
pos = ld.Data.offsetPosition;
}
else if (ext is MCExtensionDefBuoyancy)
{
var bu = ext as MCExtensionDefBuoyancy;
pos = bu.Data.offsetPosition;
}
else if (ext is MCExtensionDefExpression)
{
var exp = ext as MCExtensionDefExpression;
pos = exp.Data.offsetPosition;
}
else if (ext is MCExtensionDefLightShaft)
{
var ls = ext as MCExtensionDefLightShaft;
pos = ls.Data.offsetPosition;
}
else if (ext is MCExtensionDefWindDisturbance)
{
var wd = ext as MCExtensionDefWindDisturbance;
pos = wd.Data.offsetPosition;
}
else if (ext is MCExtensionDefProcObject)
{
var po = ext as MCExtensionDefProcObject;
pos = po.Data.offsetPosition;
}
b.BBMin = pos - size;
b.BBMax = pos + size;
b.CamRelPos = camrel;
return b;
}
private void SpawnTestEntity(bool cameraCenter = false)
{
if (!space.Inited) return;
Vector3 dir = (cameraCenter ? camera.ViewDirection : camera.MouseRay.Direction);
Vector3 ofs = (cameraCenter ? Vector3.Zero : camera.MouseRay.Position);
Vector3 pos = ofs + camera.Position + (dir * 1.5f);
Vector3 vel = dir * 50.0f; //m/s
var hash = JenkHash.GenHash("prop_alien_egg_01");
var arch = GameFileCache.GetArchetype(hash);
if (arch == null) return;
CEntityDef cent = new CEntityDef();
cent.archetypeName = hash;
cent.rotation = new Vector4(0, 0, 0, 1);
cent.scaleXY = 1.0f;
cent.scaleZ = 1.0f;
cent.flags = 1572872;
cent.parentIndex = -1;
cent.lodDist = 200.0f;
cent.lodLevel = rage__eLodType.LODTYPES_DEPTH_ORPHANHD;
cent.priorityLevel = rage__ePriorityLevel.PRI_REQUIRED;
cent.ambientOcclusionMultiplier = 255;
cent.artificialAmbientOcclusion = 255;
cent.position = pos;
YmapEntityDef ent = new YmapEntityDef(null, 0, ref cent);
ent.SetArchetype(arch);
Entity e = new Entity();
e.Position = pos;
e.Velocity = vel;
e.Mass = 10.0f;
e.Momentum = vel * e.Mass;
e.EntityDef = ent;
e.Radius = arch.BSRadius * 0.7f;
e.EnableCollisions = true;
e.Enabled = true;
e.Lifetime = 20.0f;
lock (Renderer.RenderSyncRoot)
{
space.AddTemporaryEntity(e);
}
}
public void SetControlMode(WorldControlMode mode)
{
if (InvokeRequired)
{
try
{
Invoke(new Action(() => { SetControlMode(mode); }));
}
catch
{ }
return;
}
if (mode == ControlMode) return;
bool wasfree = (ControlMode == WorldControlMode.Free || ControlBrushEnabled);
bool isfree = (mode == WorldControlMode.Free || ControlBrushEnabled);
if (isfree && !wasfree)
{
camEntity.Position = pedEntity.Position;
pedEntity.Enabled = false;
Renderer.timerunning = false;
camera.SetFollowEntity(camEntity);
camera.TargetDistance = 1.0f; //default?
camera.Smoothness = Settings.Default.CameraSmoothing;
Cursor.Show();
}
else if (!isfree && wasfree)
{
pedEntity.Position = camEntity.Position;
pedEntity.Velocity = Vector3.Zero;
pedEntity.Enabled = true;
Renderer.timerunning = true;
camera.SetFollowEntity(pedEntity.CameraEntity);
camera.TargetDistance = 0.01f; //1cm
camera.Smoothness = 20.0f;
//center the mouse in the window
System.Drawing.Point centerp = new System.Drawing.Point(ClientSize.Width / 2, ClientSize.Height / 2);
MouseLastPoint = centerp;
MouseX = centerp.X;
MouseY = centerp.Y;
Cursor.Position = PointToScreen(centerp);
Cursor.Hide();
}
ControlMode = mode;
}
private void BeginMouseHitTest()
{
//reset variables for beginning the mouse hit test
CurMouseHit.Clear();
if (Input.CtrlPressed && ProjectForm != null && ProjectForm.CanPaintInstances()) // Get whether or not we can brush from the project form.
{
ControlBrushEnabled = true;
MouseRayCollisionVisible = false;
MouseRayCollision = GetSpaceMouseRay();
}
else
{
ControlBrushEnabled = false;
if (Input.CtrlPressed && MouseRayCollisionEnabled)
{
MouseRayCollisionVisible = true;
MouseRayCollision = GetSpaceMouseRay();
}
else
{
MouseRayCollisionVisible = false;
}
}
Renderer.RenderedDrawablesListEnable =
((SelectionMode == MapSelectionMode.Entity) && MouseSelectEnabled) ||
(SelectionMode == MapSelectionMode.EntityExtension) ||
(SelectionMode == MapSelectionMode.ArchetypeExtension);
Renderer.RenderedBoundCompsListEnable = (SelectionMode == MapSelectionMode.Collision);
}
public SpaceRayIntersectResult GetSpaceMouseRay()
{
SpaceRayIntersectResult ret = new SpaceRayIntersectResult();
if (space.Inited && space.BoundsStore != null)
{
Ray mray = new Ray();
mray.Position = camera.MouseRay.Position + camera.Position;
mray.Direction = camera.MouseRay.Direction;
return space.RayIntersect(mray, float.MaxValue, collisionmeshlayers);
}
return ret;
}
public SpaceRayIntersectResult Raycast(Ray ray)
{
return space.RayIntersect(ray, float.MaxValue, collisionmeshlayers);
}
private void UpdateMouseHits()
{
UpdateMouseHitsFromRenderer();
UpdateMouseHitsFromSpace();
UpdateMouseHitsFromProject();
}
private void UpdateMouseHitsFromRenderer()
{
foreach (var rd in Renderer.RenderedDrawables)
{
UpdateMouseHits(rd.Drawable, rd.Archetype, rd.Entity);
}
}
private void UpdateMouseHitsFromSpace()
{
if (SelectionMode == MapSelectionMode.Collision)
{
MouseRayCollision = GetSpaceMouseRay();
if (MouseRayCollision.Hit)
{
CurMouseHit.UpdateCollisionFromRayHit(ref MouseRayCollision, camera);
}
}
}
private void UpdateMouseHitsFromProject()
{
if (ProjectForm == null) return;
if (SelectionMode == MapSelectionMode.Collision)
{
ProjectForm.GetMouseCollision(camera, ref CurMouseHit);
}
}
private void UpdateMouseHits(DrawableBase drawable, Archetype arche, YmapEntityDef entity)
{
//if ((SelectionMode == MapSelectionMode.Entity) && !MouseSelectEnabled) return; //performance improvement when not selecting entities...
//test the selected entity/archetype for mouse hit.
//first test the bounding sphere for mouse hit..
Quaternion orinv;
Ray mraytrn;
float hitdist = 0.0f;
int geometryIndex = 0;
DrawableGeometry geometry = null;
BoundingBox geometryAABB = new BoundingBox();
BoundingSphere bsph = new BoundingSphere();
BoundingBox bbox = new BoundingBox();
BoundingBox gbbox = new BoundingBox();
Quaternion orientation = Quaternion.Identity;
Vector3 scale = Vector3.One;
Vector3 camrel = -camera.Position;
if (entity != null)
{
orientation = entity.Orientation;
scale = entity.Scale;
camrel += entity.Position;
}
if (arche != null)
{
bsph.Center = camrel + orientation.Multiply(arche.BSCenter);//could use entity.BSCenter
bsph.Radius = arche.BSRadius;
bbox.Minimum = arche.BBMin * scale;
bbox.Maximum = arche.BBMax * scale;
}
else
{
bsph.Center = camrel + drawable.BoundingCenter;
bsph.Radius = drawable.BoundingSphereRadius;
bbox.Minimum = drawable.BoundingBoxMin * scale;
bbox.Maximum = drawable.BoundingBoxMax * scale;
}
bool mousespherehit = camera.MouseRay.Intersects(ref bsph);
if ((SelectionMode == MapSelectionMode.EntityExtension) || (SelectionMode == MapSelectionMode.ArchetypeExtension))
{
//transform the mouse ray into the entity space.
orinv = Quaternion.Invert(orientation);
mraytrn = new Ray();
mraytrn.Position = orinv.Multiply(camera.MouseRay.Position-camrel);
mraytrn.Direction = orinv.Multiply(camera.MouseRay.Direction);
if (SelectionMode == MapSelectionMode.EntityExtension)
{
if ((entity != null) && (entity.Extensions != null))
{
for (int i = 0; i < entity.Extensions.Length; i++)
{
var extension = entity.Extensions[i];
MapBox mb = GetExtensionBox(camrel, extension);
mb.Orientation = orientation;
mb.Scale = Vector3.One;// scale;
mb.BBMin *= scale;
mb.BBMax *= scale;
Renderer.BoundingBoxes.Add(mb);
bbox.Minimum = mb.BBMin; //TODO: refactor this!
bbox.Maximum = mb.BBMax;
if (mraytrn.Intersects(ref bbox, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0))
{
CurMouseHit.EntityDef = entity;
CurMouseHit.Archetype = arche;
CurMouseHit.EntityExtension = extension;
CurMouseHit.HitDist = hitdist;
CurMouseHit.CamRel = mb.CamRelPos;
CurMouseHit.AABB = bbox;
}
}
}
return; //only test extensions when in select extension mode...
}
if (SelectionMode == MapSelectionMode.ArchetypeExtension)
{
if ((arche != null) && (arche.Extensions != null))
{
for (int i = 0; i < arche.Extensions.Length; i++)
{
var extension = arche.Extensions[i];
MapBox mb = GetExtensionBox(camrel, extension);
mb.Orientation = orientation;
mb.Scale = Vector3.One;// scale;
mb.BBMin *= scale;
mb.BBMax *= scale;
Renderer.BoundingBoxes.Add(mb);
bbox.Minimum = mb.BBMin; //TODO: refactor this!
bbox.Maximum = mb.BBMax;
if (mraytrn.Intersects(ref bbox, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0))
{
CurMouseHit.EntityDef = entity;
CurMouseHit.Archetype = arche;
CurMouseHit.ArchetypeExtension = extension;
CurMouseHit.HitDist = hitdist;
CurMouseHit.CamRel = mb.CamRelPos;
CurMouseHit.AABB = bbox;
}
}
}
return; //only test extensions when in select extension mode...
}
}
if (!mousespherehit)
{ return; } //no sphere hit, so no entity hit.
bool usegeomboxes = SelectByGeometry;
var dmodels = drawable.DrawableModels?.High;
if (dmodels == null)
{ usegeomboxes = false; }
if (usegeomboxes)
{
for (int i = 0; i < dmodels.Length; i++)
{
var m = dmodels[i];
if (m.BoundsData == null)
{ usegeomboxes = false; break; }
}
}
//transform the mouse ray into the entity space.
orinv = Quaternion.Invert(orientation);
mraytrn = new Ray();
mraytrn.Position = orinv.Multiply(camera.MouseRay.Position-camrel);
mraytrn.Direction = orinv.Multiply(camera.MouseRay.Direction);
hitdist = 0.0f;
if (usegeomboxes)
{
//geometry bounding boxes version
float ghitdist = float.MaxValue;
for (int i = 0; i < dmodels.Length; i++)
{
var m = dmodels[i];
int gbbcount = m.BoundsData.Length;
for (int j = 0; j < gbbcount; j++) //first box seems to be whole model
{
var gbox = m.BoundsData[j];
gbbox.Minimum = gbox.Min.XYZ();
gbbox.Maximum = gbox.Max.XYZ();
bbox.Minimum = gbbox.Minimum * scale;
bbox.Maximum = gbbox.Maximum * scale;
bool usehit = false;
if (mraytrn.Intersects(ref bbox, out hitdist))
{
if ((j == 0) && (gbbcount > 1)) continue;//ignore a model hit
//bool firsthit = (mousehit.EntityDef == null);
if (hitdist > 0.0f) //firsthit || //ignore when inside the box
{
bool nearer = ((hitdist < CurMouseHit.HitDist) && (hitdist < ghitdist));
bool radsm = true;
if (CurMouseHit.Geometry != null)
{
var b1 = (gbbox.Maximum - gbbox.Minimum) * scale;
var b2 = (CurMouseHit.AABB.Maximum - CurMouseHit.AABB.Minimum) * scale;
float r1 = b1.Length() * 0.5f;
float r2 = b2.Length() * 0.5f;
radsm = (r1 < (r2));// * 0.5f));
}
if ((nearer&&radsm) || radsm) usehit = true;
}
}
else if (j == 0) //no hit on model box
{
break; //don't try this model's geometries
}
if (usehit)
{
int gind = (j > 0) ? j - 1 : 0;
ghitdist = hitdist;
geometry = m.Geometries[gind];
geometryAABB = gbbox;
geometryIndex = gind;
}
}
}
if (geometry == null)
{
return; //no geometry hit.
}
hitdist = ghitdist;
}
else
{
//archetype/drawable bounding boxes version
bool outerhit = false;
if (mraytrn.Intersects(ref bbox, out hitdist)) //test primary box
{
bool firsthit = (CurMouseHit.EntityDef == null);
if (firsthit || (hitdist > 0.0f)) //ignore when inside the box..
{
bool nearer = (hitdist < CurMouseHit.HitDist); //closer than the last..
bool radsm = true;
if ((CurMouseHit.Archetype != null) && (arche != null)) //compare hit archetype sizes...
{
//var b1 = (arche.BBMax - arche.BBMin) * scale;
//var b2 = (mousehit.Archetype.BBMax - mousehit.Archetype.BBMin) * scale;
float r1 = arche.BSRadius;
float r2 = CurMouseHit.Archetype.BSRadius;
radsm = (r1 <= (r2));// * 0.5f)); //prefer selecting smaller things
}
if ((nearer&&radsm) || radsm)
{
outerhit = true;
}
}
}
if (!outerhit)
{ return; } //no hit.
}
CurMouseHit.HitDist = (hitdist > 0.0f) ? hitdist : CurMouseHit.HitDist;
CurMouseHit.EntityDef = entity;
CurMouseHit.Archetype = arche;
CurMouseHit.Drawable = drawable;
CurMouseHit.Geometry = geometry;
CurMouseHit.AABB = geometryAABB;
CurMouseHit.GeometryIndex = geometryIndex;
CurMouseHit.CamRel = camrel;
//go through geometries...? need to use skeleton?
//if (drawable.DrawableModelsHigh == null)
//{ return; }
//if (drawable.DrawableModelsHigh.data_items == null)
//{ return; }
//for (int i = 0; i < drawable.DrawableModelsHigh.data_items.Length; i++)
//{
// var model = drawable.DrawableModelsHigh.data_items[i];
// if ((model.Geometries == null) || (model.Geometries.data_items == null))
// { continue; }
// if ((model.Unknown_18h_Data == null))
// { continue; }
// int boffset = 0;
// if ((model.Unknown_18h_Data.Length > model.Geometries.data_items.Length))
// { boffset = 1; }
// for (int j = 0; j < model.Geometries.data_items.Length; j++)
// {
// var geom = model.Geometries.data_items[j];
// var gbox = model.Unknown_18h_Data[j + boffset];
// bbox.Minimum = gbox.AABB_Max.XYZ();
// bbox.Maximum = gbox.AABB_Min.XYZ();
// if (mraytrn.Intersects(ref bbox, out hitdist)) //test geom box
// {
// bool firsthit = (mousehit.EntityDef == null);
// if (firsthit || (hitdist > 0.0f)) //ignore when inside the box..
// {
// bool nearer = (hitdist < mousehit.HitDist); //closer than the last..
// if (nearer)
// {
// mousehit.HitDist = (hitdist > 0.0f) ? hitdist : mousehit.HitDist;
// mousehit.EntityDef = entity;
// mousehit.Archetype = arche;
// mousehit.Drawable = drawable;
// mousehit.CamRel = camrel;
// }
// }
// }
// }
//}
//Bounds b = null;
//var dd = drawable as Drawable;
//if (dd != null)
//{
// b = dd.Bound;
//}
//else
//{
// var fd = drawable as FragDrawable;
// if (fd != null)
// {
// b = fd.Bound;
// }
//}
//if (b == null)
//{ return; }
//else
//{ }
}
private void UpdateMouseHits(YmapFile ymap)
{
//find mouse hits for things like MLOs, time cycle mods, grass batches, and car generators in ymaps.
BoundingBox bbox = new BoundingBox();
Ray mray = new Ray();
mray.Position = camera.MouseRay.Position + camera.Position;
mray.Direction = camera.MouseRay.Direction;
float hitdist = float.MaxValue;
float dmax = Renderer.renderboundsmaxdist;
if ((SelectionMode == MapSelectionMode.TimeCycleModifier) && (ymap.TimeCycleModifiers != null))
{
for (int i = 0; i < ymap.TimeCycleModifiers.Length; i++)
{
var tcm = ymap.TimeCycleModifiers[i];
if ((((tcm.BBMin + tcm.BBMax) * 0.5f) - camera.Position).Length() > dmax) continue;
MapBox mb = new MapBox();
mb.CamRelPos = -camera.Position;
mb.BBMin = tcm.BBMin;
mb.BBMax = tcm.BBMax;
mb.Orientation = Quaternion.Identity;
mb.Scale = Vector3.One;
Renderer.BoundingBoxes.Add(mb);
bbox.Minimum = mb.BBMin;
bbox.Maximum = mb.BBMax;
if (mray.Intersects(ref bbox, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0))
{
CurMouseHit.TimeCycleModifier = tcm;
CurMouseHit.HitDist = hitdist;
CurMouseHit.CamRel = mb.CamRelPos;
CurMouseHit.AABB = bbox;
}
}
}
if ((SelectionMode == MapSelectionMode.CarGenerator) && (ymap.CarGenerators != null))
{
for (int i = 0; i < ymap.CarGenerators.Length; i++)
{
var cg = ymap.CarGenerators[i];
MapBox mb = new MapBox();
mb.CamRelPos = cg.Position - camera.Position;
mb.BBMin = cg.BBMin;
mb.BBMax = cg.BBMax;
mb.Orientation = cg.Orientation;
mb.Scale = Vector3.One;
Renderer.BoundingBoxes.Add(mb);
Quaternion orinv = Quaternion.Invert(cg.Orientation);
Ray mraytrn = new Ray();
mraytrn.Position = orinv.Multiply(camera.MouseRay.Position - mb.CamRelPos);
mraytrn.Direction = orinv.Multiply(mray.Direction);
bbox.Minimum = mb.BBMin;
bbox.Maximum = mb.BBMax;
if (mraytrn.Intersects(ref bbox, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0))
{
CurMouseHit.CarGenerator = cg;
CurMouseHit.HitDist = hitdist;
CurMouseHit.CamRel = mb.CamRelPos;
CurMouseHit.AABB = bbox;
}
}
if (SelectedItem.CarGenerator != null)
{
}
}
if ((SelectionMode == MapSelectionMode.MloInstance) && (ymap.MloEntities != null))
{
for (int i = 0; i < ymap.MloEntities.Length; i++)
{
var ent = ymap.MloEntities[i];
if (SelectedItem.MloEntityDef == ent) continue;
MapBox mb = new MapBox();
mb.CamRelPos = ent.Position - camera.Position;
mb.BBMin = /*ent?.BBMin ??*/ new Vector3(-1.5f);
mb.BBMax = /*ent?.BBMax ??*/ new Vector3(1.5f);
mb.Orientation = ent?.Orientation ?? Quaternion.Identity;
mb.Scale = /*ent?.Scale ??*/ Vector3.One;
Renderer.BoundingBoxes.Add(mb);
Quaternion orinv = Quaternion.Invert(mb.Orientation);
Ray mraytrn = new Ray();
mraytrn.Position = orinv.Multiply(camera.MouseRay.Position - mb.CamRelPos);
mraytrn.Direction = orinv.Multiply(mray.Direction);
bbox.Minimum = mb.BBMin;
bbox.Maximum = mb.BBMax;
if (mraytrn.Intersects(ref bbox, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0))
{
CurMouseHit.MloEntityDef = ent;
CurMouseHit.EntityDef = ent;
CurMouseHit.HitDist = hitdist;
CurMouseHit.CamRel = mb.CamRelPos;
CurMouseHit.AABB = new BoundingBox(mb.BBMin, mb.BBMax);
}
}
}
if ((SelectionMode == MapSelectionMode.Grass) && (ymap.GrassInstanceBatches != null))
{
for (int i = 0; i < ymap.GrassInstanceBatches.Length; i++)
{
var gb = ymap.GrassInstanceBatches[i];
if ((gb.Position - camera.Position).Length() > dmax) continue;
MapBox mb = new MapBox();
mb.CamRelPos = -camera.Position;
mb.BBMin = gb.AABBMin;
mb.BBMax = gb.AABBMax;
mb.Orientation = Quaternion.Identity;
mb.Scale = Vector3.One;
Renderer.BoundingBoxes.Add(mb);
bbox.Minimum = mb.BBMin;
bbox.Maximum = mb.BBMax;
if (mray.Intersects(ref bbox, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0))
{
CurMouseHit.GrassBatch = gb;
CurMouseHit.HitDist = hitdist;
CurMouseHit.CamRel = mb.CamRelPos;
CurMouseHit.AABB = bbox;
}
}
}
if ((SelectionMode == MapSelectionMode.LodLights) && (ymap.LODLights != null))
{
var ll = ymap.LODLights;
if ((((ll.BBMin + ll.BBMax) * 0.5f) - camera.Position).Length() <= dmax)
{
MapBox mb = new MapBox();
mb.CamRelPos = -camera.Position;
mb.BBMin = ll.BBMin;
mb.BBMax = ll.BBMax;
mb.Orientation = Quaternion.Identity;
mb.Scale = Vector3.One;
Renderer.BoundingBoxes.Add(mb);
if (ll.BVH != null)
{
UpdateMouseHits(ll.BVH, ref mray);
}
}
}
if ((SelectionMode == MapSelectionMode.LodLights) && (ymap.DistantLODLights != null))
{
var dll = ymap.DistantLODLights;
if ((((dll.BBMin + dll.BBMax) * 0.5f) - camera.Position).Length() <= dmax)
{
MapBox mb = new MapBox();
mb.CamRelPos = -camera.Position;
mb.BBMin = dll.BBMin;
mb.BBMax = dll.BBMax;
mb.Orientation = Quaternion.Identity;
mb.Scale = Vector3.One;
Renderer.BoundingBoxes.Add(mb);
}
}
if ((SelectionMode == MapSelectionMode.Occlusion) && (ymap.BoxOccluders != null))
{
for (int i = 0; i < ymap.BoxOccluders.Length; i++)
{
var bo = ymap.BoxOccluders[i];
if ((bo.Position - camera.Position).Length() > dmax) continue;
Renderer.RenderBasePath(bo);
MapBox mb = new MapBox();
mb.CamRelPos = bo.Position - camera.Position;
mb.BBMin = bo.BBMin;
mb.BBMax = bo.BBMax;
mb.Orientation = bo.Orientation;
mb.Scale = Vector3.One;
//Renderer.BoundingBoxes.Add(mb);
Quaternion orinv = Quaternion.Invert(bo.Orientation);
Ray mraytrn = new Ray();
mraytrn.Position = orinv.Multiply(camera.MouseRay.Position - mb.CamRelPos);
mraytrn.Direction = orinv.Multiply(mray.Direction);
bbox.Minimum = mb.BBMin;
bbox.Maximum = mb.BBMax;
if (mraytrn.Intersects(ref bbox, out float hd) && (hd < CurMouseHit.HitDist) && (hd > 0))
{
hitdist = hd;
CurMouseHit.BoxOccluder = bo;
CurMouseHit.OccludeModelTri = null;
CurMouseHit.HitDist = hitdist;
CurMouseHit.CamRel = mb.CamRelPos;
CurMouseHit.AABB = bbox;
}
}
}
if ((SelectionMode == MapSelectionMode.Occlusion) && (ymap.OccludeModels != null))
{
for (int i = 0; i < ymap.OccludeModels.Length; i++)
{
var om = ymap.OccludeModels[i];
Renderer.RenderBasePath(om);
var hittri = om.RayIntersect(ref mray, ref hitdist);
if ((hittri != null) && (hitdist < CurMouseHit.HitDist))
{
CurMouseHit.BoxOccluder = null;
CurMouseHit.OccludeModelTri = hittri;
CurMouseHit.HitDist = hitdist;
CurMouseHit.CamRel = -camera.Position;
CurMouseHit.AABB = hittri.Box;
}
}
}
}
private void UpdateMouseHits<T>(List<T> waterquads) where T : BaseWaterQuad
{
BoundingBox bbox = new BoundingBox();
Ray mray = new Ray();
mray.Position = camera.MouseRay.Position + camera.Position;
mray.Direction = camera.MouseRay.Direction;
float hitdist;
foreach (T quad in waterquads)
{
MapBox mb = new MapBox();
mb.CamRelPos = -camera.Position;
mb.BBMin = new Vector3(quad.minX, quad.minY, quad.z ?? 0);
mb.BBMax = new Vector3(quad.maxX, quad.maxY, quad.z ?? 0);
mb.Orientation = Quaternion.Identity;
mb.Scale = Vector3.One;
Renderer.BoundingBoxes.Add(mb);
bbox.Minimum = mb.BBMin;
bbox.Maximum = mb.BBMax;
if(mray.Intersects(ref bbox, out hitdist) && hitdist > 0 && hitdist <= CurMouseHit.HitDist)
{
float curSize = CurMouseHit.AABB.Size.X * CurMouseHit.AABB.Size.Y;
float newSize = bbox.Size.X * bbox.Size.Y;
if ((curSize == 0) || (newSize < curSize))
{
CurMouseHit.HitDist = hitdist;
CurMouseHit.CamRel = mb.CamRelPos;
CurMouseHit.AABB = bbox;
CurMouseHit.WaterQuad = quad as WaterQuad;
CurMouseHit.WaveQuad = quad as WaterWaveQuad;
CurMouseHit.CalmingQuad = quad as WaterCalmingQuad;
}
}
}
}
private void UpdateMouseHits(List<YnvFile> ynvs)
{
if (SelectionMode != MapSelectionMode.NavMesh) return;
Ray mray = new Ray();
mray.Position = camera.MouseRay.Position + camera.Position;
mray.Direction = camera.MouseRay.Direction;
foreach (var ynv in ynvs)
{
if (renderpathbounds)
{
if (ynv.Nav == null) continue;
if (ynv.Nav.SectorTree == null) continue;
MapBox mb = new MapBox();
mb.CamRelPos = -camera.Position;
mb.BBMin = ynv.Nav.SectorTree.AABBMin.XYZ();
mb.BBMax = ynv.Nav.SectorTree.AABBMax.XYZ();
mb.Orientation = Quaternion.Identity;
mb.Scale = Vector3.One;
Renderer.BoundingBoxes.Add(mb);
}
if (ynv.BVH != null)
{
UpdateMouseHits(ynv.BVH, ref mray);
}
//if ((CurMouseHit.NavPoint != null) || (CurMouseHit.NavPortal != null)) continue;
if ((ynv.Nav != null) && (ynv.Vertices != null) && (ynv.Indices != null) && (ynv.Polys != null))
{
UpdateMouseHits(ynv, ynv.Nav.SectorTree, ynv.Nav.SectorTree, ref mray);
}
}
}
private void UpdateMouseHits(YnvFile ynv, NavMeshSector navsector, NavMeshSector rootsec, ref Ray mray)
{
if (navsector == null) return;
float hitdist = float.MaxValue;
BoundingBox bbox = new BoundingBox();
bbox.Minimum = navsector.AABBMin.XYZ();
bbox.Maximum = navsector.AABBMax.XYZ();
if (rootsec != null) //apparently the Z values are incorrect :(
{
bbox.Minimum.Z = rootsec.AABBMin.Z;
bbox.Maximum.Z = rootsec.AABBMax.Z;
}
float fhd;
if (mray.Intersects(ref bbox, out fhd)) //ray intersects this node... check children for hits!
{
////test vis
//MapBox mb = new MapBox();
//mb.CamRelPos = -camera.Position;
//mb.BBMin = bbox.Minimum;
//mb.BBMax = bbox.Maximum;
//mb.Orientation = Quaternion.Identity;
//mb.Scale = Vector3.One;
//BoundingBoxes.Add(mb);
if (navsector.SubTree1 != null)
{
UpdateMouseHits(ynv, navsector.SubTree1, rootsec, ref mray);
}
if (navsector.SubTree2 != null)
{
UpdateMouseHits(ynv, navsector.SubTree2, rootsec, ref mray);
}
if (navsector.SubTree3 != null)
{
UpdateMouseHits(ynv, navsector.SubTree3, rootsec, ref mray);
}
if (navsector.SubTree4 != null)
{
UpdateMouseHits(ynv, navsector.SubTree4, rootsec, ref mray);
}
if ((navsector.Data != null) && (navsector.Data.PolyIDs != null))
{
BoundingBox cbox = new BoundingBox();
cbox.Minimum = bbox.Minimum - camera.Position;
cbox.Maximum = bbox.Maximum - camera.Position;
var polys = ynv.Polys;
var polyids = navsector.Data.PolyIDs;
for (int i = 0; i < polyids.Length; i++)
{
var polyid = polyids[i];
if (polyid >= polys.Count)
{ continue; }
var poly = polys[polyid];
var ic = poly._RawData.IndexCount;
var startid = poly._RawData.IndexID;
var endid = startid + ic;
if (startid >= ynv.Indices.Count)
{ continue; }
if (endid > ynv.Indices.Count)
{ continue; }
var vc = ynv.Vertices.Count;
var startind = ynv.Indices[startid];
if (startind >= vc)
{ continue; }
Vector3 p0 = ynv.Vertices[startind];
//test triangles for the poly.
int tricount = ic - 2;
for (int t = 0; t < tricount; t++)
{
int tid = startid + t;
int ind1 = ynv.Indices[tid + 1];
int ind2 = ynv.Indices[tid + 2];
if ((ind1 >= vc) || (ind2 >= vc))
{ continue; }
Vector3 p1 = ynv.Vertices[ind1];
Vector3 p2 = ynv.Vertices[ind2];
if (mray.Intersects(ref p0, ref p1, ref p2, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0))
{
var cellaabb = poly._RawData.CellAABB;
CurMouseHit.NavPoly = poly;
CurMouseHit.NavPoint = null;
CurMouseHit.NavPortal = null;
CurMouseHit.HitDist = hitdist;
CurMouseHit.AABB = new BoundingBox(cellaabb.Min, cellaabb.Max);
break;//no need to test further tris in this poly
}
}
}
}
}
}
private void UpdateMouseHits(List<YndFile> ynds)
{
if (SelectionMode != MapSelectionMode.Path) return;
Ray mray = new Ray();
mray.Position = camera.MouseRay.Position + camera.Position;
mray.Direction = camera.MouseRay.Direction;
foreach (var ynd in ynds)
{
if (renderpathbounds)
{
float minz = (ynd.BVH != null) ? ynd.BVH.Box.Minimum.Z : 0.0f;
float maxz = (ynd.BVH != null) ? ynd.BVH.Box.Maximum.Z : 0.0f;
MapBox mb = new MapBox();
mb.CamRelPos = -camera.Position;
mb.BBMin = new Vector3(ynd.BBMin.X, ynd.BBMin.Y, minz);
mb.BBMax = new Vector3(ynd.BBMax.X, ynd.BBMax.Y, maxz);
mb.Orientation = Quaternion.Identity;
mb.Scale = Vector3.One;
Renderer.BoundingBoxes.Add(mb);
}
if (ynd.BVH != null)
{
UpdateMouseHits(ynd.BVH, ref mray);
}
}
if (SelectedItem.PathNode != null)
{
float linkrad = 0.25f;
var n = SelectedItem.PathNode;
if (n.Links != null)
{
foreach (var ln in n.Links)
{
if (ln.Node2 == null) continue;//invalid links can hit here...
Vector3 dv = n.Position - ln.Node2.Position;
float dl = dv.Length();
Vector3 dir = dv * (1.0f / dl);
Vector3 dup = Vector3.UnitZ;
MapBox mb = new MapBox();
int lanestot = ln.LaneCountForward + ln.LaneCountBackward;
float lanewidth = ln.GetLaneWidth();
float inner = ln.LaneOffset * lanewidth;// 0.0f;
float outer = inner + Math.Max(lanewidth * ln.LaneCountForward, 0.5f);
float totwidth = lanestot * lanewidth;
float halfwidth = totwidth * 0.5f;
if (ln.LaneCountBackward == 0)
{
inner -= halfwidth;
outer -= halfwidth;
}
if (ln.LaneCountForward == 0)
{
inner += halfwidth;
outer += halfwidth;
}
mb.CamRelPos = n.Position - camera.Position;
mb.BBMin = new Vector3(-linkrad - outer, -linkrad, 0.0f);
mb.BBMax = new Vector3(linkrad - inner, linkrad, dl);
mb.Orientation = Quaternion.Invert(Quaternion.RotationLookAtRH(dir, dup));
mb.Scale = Vector3.One;
if (ln == SelectedItem.PathLink)
{
Renderer.HilightBoxes.Add(mb);
}
else
{
Renderer.BoundingBoxes.Add(mb);
}
}
}
}
}
private void UpdateMouseHits(List<TrainTrack> tracks)
{
if (SelectionMode != MapSelectionMode.TrainTrack) return;
Ray mray = new Ray();
mray.Position = camera.MouseRay.Position + camera.Position;
mray.Direction = camera.MouseRay.Direction;
foreach (var track in tracks)
{
if (renderpathbounds)
{
//MapBox mb = new MapBox();
//mb.CamRelPos = -camera.Position;
//mb.BBMin = track.BVH?.Box.Minimum ?? Vector3.Zero;
//mb.BBMax = track.BVH?.Box.Maximum ?? Vector3.Zero;
//mb.Orientation = Quaternion.Identity;
//mb.Scale = Vector3.One;
//BoundingBoxes.Add(mb);
}
if (track.BVH != null)
{
UpdateMouseHits(track.BVH, ref mray);
}
}
if (SelectedItem.TrainTrackNode != null)
{
float linkrad = 0.25f;
var n = SelectedItem.TrainTrackNode;
if (n.Links != null)
{
foreach (var ln in n.Links)
{
if (ln == null) continue;
Vector3 dv = n.Position - ln.Position;
float dl = dv.Length();
Vector3 dir = dv * (1.0f / dl);
Vector3 dup = Vector3.UnitZ;
MapBox mb = new MapBox();
mb.CamRelPos = n.Position - camera.Position;
mb.BBMin = new Vector3(-linkrad, -linkrad, 0.0f);
mb.BBMax = new Vector3(linkrad, linkrad, dl);
mb.Orientation = Quaternion.Invert(Quaternion.RotationLookAtRH(dir, dup));
mb.Scale = Vector3.One;
Renderer.BoundingBoxes.Add(mb);
}
}
}
}
private void UpdateMouseHits(List<YmtFile> scenarios)
{
if (SelectionMode != MapSelectionMode.Scenario) return;
Ray mray = new Ray();
mray.Position = camera.MouseRay.Position + camera.Position;
mray.Direction = camera.MouseRay.Direction;
foreach (var scenario in scenarios)
{
var sr = scenario.ScenarioRegion;
if (sr == null) continue;
if (renderscenariobounds)
{
MapBox mb = new MapBox();
mb.CamRelPos = -camera.Position;
mb.BBMin = sr?.BVH?.Box.Minimum ?? Vector3.Zero;
mb.BBMax = sr?.BVH?.Box.Maximum ?? Vector3.Zero;
mb.Orientation = Quaternion.Identity;
mb.Scale = Vector3.One;
Renderer.BoundingBoxes.Add(mb);
}
if (sr.BVH != null)
{
UpdateMouseHits(sr.BVH, ref mray);
}
}
if (SelectedItem.ScenarioNode != null) //move this stuff to renderselection..?
{
var n = SelectedItem.ScenarioNode;
var nc = n.ChainingNode?.Chain;
var ncl = n.Cluster;
//float linkrad = 0.25f;
//if (n.Links != null)
//{
// foreach (var ln in n.Links)
// {
// if (ln == null) continue;
// Vector3 dv = n.Position - ln.Position;
// float dl = dv.Length();
// Vector3 dir = dv * (1.0f / dl);
// Vector3 dup = Vector3.UnitZ;
// MapBox mb = new MapBox();
// mb.CamRelPos = n.Position - camera.Position;
// mb.BBMin = new Vector3(-linkrad, -linkrad, 0.0f);
// mb.BBMax = new Vector3(linkrad, linkrad, dl);
// mb.Orientation = Quaternion.Invert(Quaternion.RotationLookAtRH(dir, dup));
// mb.Scale = Vector3.One;
// BoundingBoxes.Add(mb);
// }
//}
var sr = SelectedItem.ScenarioNode.Ymt.ScenarioRegion;
//if (renderscenariobounds)
{
MapBox mb = new MapBox();
mb.CamRelPos = -camera.Position;
mb.BBMin = sr?.BVH?.Box.Minimum ?? Vector3.Zero;
mb.BBMax = sr?.BVH?.Box.Maximum ?? Vector3.Zero;
mb.Orientation = Quaternion.Identity;
mb.Scale = Vector3.One;
if (renderscenariobounds)
{
Renderer.HilightBoxes.Add(mb);
}
else
{
Renderer.BoundingBoxes.Add(mb);
}
}
if (ncl != null)
{
//hilight the cluster itself
MapBox mb = new MapBox();
mb.Scale = Vector3.One;
mb.BBMin = new Vector3(-0.5f);
mb.BBMax = new Vector3(0.5f);
mb.CamRelPos = ncl.Position - camera.Position;
mb.Orientation = Quaternion.Identity;
Renderer.HilightBoxes.Add(mb);
//show boxes for points in the cluster
if ((ncl.Points != null) && (ncl.Points.MyPoints != null))
{
foreach (var clpoint in ncl.Points.MyPoints)
{
if (clpoint == n.ClusterMyPoint) continue; //don't highlight the selected node...
mb = new MapBox();
mb.Scale = Vector3.One;
mb.BBMin = new Vector3(-0.5f);
mb.BBMax = new Vector3(0.5f);
mb.CamRelPos = clpoint.Position - camera.Position;
mb.Orientation = clpoint.Orientation;
Renderer.BoundingBoxes.Add(mb);
}
}
}
}
}
private void UpdateMouseHits(PathBVHNode pathbvhnode, ref Ray mray)
{
float nrad = 0.5f;
float hitdist = float.MaxValue;
BoundingSphere bsph = new BoundingSphere();
bsph.Radius = nrad;
BoundingBox bbox = new BoundingBox();
bbox.Minimum = pathbvhnode.Box.Minimum - nrad;
bbox.Maximum = pathbvhnode.Box.Maximum + nrad;
BoundingBox nbox = new BoundingBox();
nbox.Minimum = new Vector3(-nrad);
nbox.Maximum = new Vector3(nrad);
float fhd;
if (mray.Intersects(ref bbox, out fhd)) //ray intersects this node... check children for hits!
{
if ((pathbvhnode.Node1 != null) && (pathbvhnode.Node2 != null)) //node is split. recurse
{
UpdateMouseHits(pathbvhnode.Node1, ref mray);
UpdateMouseHits(pathbvhnode.Node2, ref mray);
}
else if (pathbvhnode.Nodes != null) //leaf node. test contaned pathnodes
{
foreach (var n in pathbvhnode.Nodes)
{
bsph.Center = n.Position;
if (mray.Intersects(ref bsph, out hitdist) && (hitdist < CurMouseHit.HitDist) && (hitdist > 0))
{
CurMouseHit.PathNode = n as YndNode;
CurMouseHit.TrainTrackNode = n as TrainTrackNode;
CurMouseHit.ScenarioNode = n as ScenarioNode;
CurMouseHit.LodLight = n as YmapLODLight;
CurMouseHit.NavPoint = n as YnvPoint;
CurMouseHit.NavPortal = n as YnvPortal;
CurMouseHit.NavPoly = null;
CurMouseHit.HitDist = hitdist;
CurMouseHit.CamRel = (n.Position - camera.Position);
CurMouseHit.AABB = nbox;
}
}
}
}
}
public void SelectObject(object obj, object parent = null, bool addSelection = false)
{
if (obj == null)
{
SelectItem(null, addSelection);
return;
}
if (obj is object[] arr)
{
SelectItem(null, addSelection);
foreach (var mobj in arr)
{
SelectObject(mobj, null, true);
}
if (!addSelection)
{
UpdateSelectionUI(true);
}
if ((ProjectForm != null) && !addSelection)
{
ProjectForm.OnWorldSelectionChanged(SelectedItem);
}
}
else
{
var ms = MapSelection.FromProjectObject(this, obj, parent);
if (!ms.HasValue)
{
SelectItem(null, addSelection);
}
else
{
SelectItem(ms, addSelection);
}
}
}
public void SelectItem(MapSelection? mhit = null, bool addSelection = false, bool manualSelection = false, bool notifyProject = true)
{
var mhitv = mhit.HasValue ? mhit.Value : new MapSelection();
if (mhit != null)
{
if ((mhitv.Archetype == null) && (mhitv.EntityDef != null))
{
mhitv.Archetype = mhitv.EntityDef.Archetype; //use the entity archetype if no archetype given
}
if (mhitv.GrassBatch != null)
{
mhitv.Archetype = mhitv.GrassBatch.Archetype;
}
}
if ((mhitv.Archetype != null) && (mhitv.Drawable == null))
{
mhitv.Drawable = gameFileCache.TryGetDrawable(mhitv.Archetype); //no drawable given.. try to get it from the cache.. if it's not there, drawable info won't display...
}
var oldnode = SelectedItem.PathNode;
bool change = false;
if (mhit != null)
{
change = SelectedItem.CheckForChanges(mhitv);
}
else
{
change = SelectedItem.CheckForChanges();
}
if (addSelection)
{
var items = new List<MapSelection>();
if (SelectedItem.MultipleSelectionItems != null)
{
items.AddRange(SelectedItem.MultipleSelectionItems);
if (mhitv.HasValue) //incoming selection isn't empty...
{
//search the list for a match, remove it if already there, otherwise add it.
bool found = false;
foreach (var item in items)
{
if (!item.CheckForChanges(mhitv))
{
items.Remove(item);
found = true;
break;
}
}
if (found)
{
if (items.Count == 1)
{
mhitv = items[0];
items.Clear();
}
else if (items.Count <= 0)
{
mhitv.Clear();
items.Clear();//this shouldn't really happen..
}
mhitv.SetMultipleSelectionItems(items.ToArray());
}
else
{
mhitv.SetMultipleSelectionItems(null);
items.Add(mhitv);
}
change = true;
}
else //empty incoming value... do nothing?
{
return;
}
}
else //current selection is single item, or empty
{
if (change) //incoming selection item is different from the current one
{
if (mhitv.HasValue) //incoming selection isn't empty, add it to the list
{
if (SelectedItem.HasValue) //add the existing item to the selection list, if it's not empty
{
mhitv.SetMultipleSelectionItems(null);
SelectedItem.SetMultipleSelectionItems(null);
items.Add(SelectedItem);
items.Add(mhitv);
SelectedItem.SetMultipleSelectionItems(items.ToArray());
}
}
else //empty incoming value... do nothing?
{
return;
}
}
else //same thing was selected a 2nd time, just clear the selection.
{
SelectedItem.Clear();
mhit = null; //dont's wants to selects it agains!
change = true;
}
}
if (items.Count > 1)
{
//iterate the selected items, and calculate the selection position
mhitv.Clear();
mhitv.SetMultipleSelectionItems(items.ToArray());
}
}
else
{
if (SelectedItem.MultipleSelectionItems != null)
{
change = true;
SelectedItem.Clear();
}
}
if (!change)
{
if (mhit.HasValue)
{
//make sure the path link gets changed (sub-selection!)
//lock (Renderer.RenderSyncRoot)
{
SelectedItem.PathLink = mhitv.PathLink;
SelectedItem.ScenarioEdge = mhitv.ScenarioEdge;
}
}
return;
}
lock (Renderer.RenderSyncRoot) //drawflags is used when rendering.. need that lock
{
if (mhit.HasValue)
{
SelectedItem = mhitv;
}
else
{
SelectedItem.Clear();
}
if (change)
{
if (!addSelection)
{
UpdateSelectionUI(true);
}
Widget.Visible = SelectedItem.CanShowWidget;
if (Widget.Visible)
{
Widget.Position = SelectedItem.WidgetPosition;
Widget.Rotation = SelectedItem.WidgetRotation;
Widget.RotationWidget.EnableAxes = SelectedItem.WidgetRotationAxes;
Widget.ScaleWidget.LockXY = SelectedItem.WidgetScaleLockXY;
Widget.Scale = SelectedItem.WidgetScale;
}
}
}
if (notifyProject && change && (ProjectForm != null) && (!addSelection || manualSelection))
{
ProjectForm.OnWorldSelectionChanged(SelectedItem);
}
var newnode = SelectedItem.PathNode;
if (newnode != oldnode)//this is to allow junction heightmaps to be displayed when selecting a junction node
{
UpdatePathYndGraphics(oldnode?.Ynd, false);
UpdatePathYndGraphics(newnode?.Ynd, false);
}
if (change)
{
// If an item has been selected the user is likely to use a keybind. We need focus!
//Focus();//DISABLED THIS due to causing problems with using arrows to select in project window!
}
}
public void SelectMulti(MapSelection[] items, bool addSelection = false, bool notifyProject = true)
{
SelectItem(null, addSelection, false, notifyProject);
if (items != null)
{
foreach (var item in items)
{
SelectItem(item, true, false, notifyProject);
}
if (!addSelection)
{
UpdateSelectionUI(true);
}
if (notifyProject && (ProjectForm != null) && !addSelection)
{
ProjectForm.OnWorldSelectionChanged(SelectedItem);
}
}
}
private void SelectMousedItem()
{
//when clicked, select the currently moused item and update the selection info UI
if (!MouseSelectEnabled)
{ return; }
SelectItem(LastMouseHit, Input.CtrlPressed, true);
}
private void UpdateSelectionUI(bool wait)
{
try
{
if (InvokeRequired)
{
if (wait)
{
Invoke(new Action(() => { UpdateSelectionUI(wait); }));
}
else
{
BeginInvoke(new Action(() => { UpdateSelectionUI(wait); }));
}
}
else
{
SetSelectionUI(SelectedItem);
if (InfoForm != null)
{
InfoForm.SetSelection(SelectedItem);
}
}
}
catch { }
}
private void SetSelectionUI(MapSelection item)
{
SelectionNameTextBox.Text = item.GetNameString("Nothing selected");
//SelEntityPropertyGrid.SelectedObject = item.EntityDef;
SelArchetypePropertyGrid.SelectedObject = item.Archetype;
SelDrawablePropertyGrid.SelectedObject = item.Drawable;
Renderer.SelectionModelDrawFlags.Clear();
Renderer.SelectionGeometryDrawFlags.Clear();
SelDrawableModelsTreeView.Nodes.Clear();
SelDrawableTexturesTreeView.Nodes.Clear();
if (item.Drawable != null)
{
AddSelectionDrawableModelsTreeNodes(item.Drawable.DrawableModels?.High, "High Detail", true);
AddSelectionDrawableModelsTreeNodes(item.Drawable.DrawableModels?.Med, "Medium Detail", false);
AddSelectionDrawableModelsTreeNodes(item.Drawable.DrawableModels?.Low, "Low Detail", false);
AddSelectionDrawableModelsTreeNodes(item.Drawable.DrawableModels?.VLow, "Very Low Detail", false);
//AddSelectionDrawableModelsTreeNodes(item.Drawable.DrawableModels?.Extra, "X Detail", false);
}
YmapFile ymap = null;
YnvFile ynv = null;
YndFile ynd = null;
TrainTrack traintr = null;
YmtFile scenario = null;
RelFile audiofile = null;
ToolbarCopyButton.Enabled = false;
ToolbarDeleteItemButton.Enabled = false;
ToolbarDeleteItemButton.Text = "Delete";
ToolbarAddItemButton.ToolTipText = "Add";
ToolbarAddItemButton.Enabled = false;
ToolbarPasteButton.Enabled = CopiedItem.CanCopyPaste;
if (item.MultipleSelectionItems != null)
{
SelectionEntityTabPage.Text = "Multiple items";
SelEntityPropertyGrid.SelectedObject = item.MultipleSelectionItems;
ToolbarCopyButton.Enabled = item.CanCopyPaste;
ToolbarDeleteItemButton.Enabled = true;
ToolbarDeleteItemButton.Text = "Delete multiple items";
}
else if (item.TimeCycleModifier != null)
{
SelectionEntityTabPage.Text = "TCMod";
SelEntityPropertyGrid.SelectedObject = item.TimeCycleModifier;
}
else if (item.CarGenerator != null)
{
SelectionEntityTabPage.Text = "CarGen";
SelEntityPropertyGrid.SelectedObject = item.CarGenerator;
ymap = item.CarGenerator.Ymap;
ToolbarCopyButton.Enabled = true;
ToolbarDeleteItemButton.Enabled = true;
ToolbarDeleteItemButton.Text = "Delete car generator";
}
else if (item.LodLight != null)
{
SelectionEntityTabPage.Text = "LodLight";
SelEntityPropertyGrid.SelectedObject = item.LodLight;
ymap = item.LodLight.Ymap;
ToolbarCopyButton.Enabled = true;
ToolbarDeleteItemButton.Enabled = true;
ToolbarDeleteItemButton.Text = "Delete LOD light";
}
else if (item.GrassBatch != null)
{
SelectionEntityTabPage.Text = "Grass";
SelEntityPropertyGrid.SelectedObject = item.GrassBatch;
}
else if (item.BoxOccluder != null)
{
SelectionEntityTabPage.Text = "BoxOccluder";
SelEntityPropertyGrid.SelectedObject = item.BoxOccluder;
ymap = item.BoxOccluder.Ymap;
ToolbarCopyButton.Enabled = true;
ToolbarDeleteItemButton.Enabled = true;
ToolbarDeleteItemButton.Text = "Delete Box Occluder";
}
else if (item.OccludeModelTri != null)
{
SelectionEntityTabPage.Text = "OccludeTriangle";
SelEntityPropertyGrid.SelectedObject = item.OccludeModelTri;
ymap = item.OccludeModelTri.Ymap;
ToolbarCopyButton.Enabled = true;
ToolbarDeleteItemButton.Enabled = true;
ToolbarDeleteItemButton.Text = "Delete Occlude Model Triangle";
}
else if (item.WaterQuad != null)
{
SelectionEntityTabPage.Text = "WaterQuad";
SelEntityPropertyGrid.SelectedObject = item.WaterQuad;
}
else if (item.CalmingQuad != null)
{
SelectionEntityTabPage.Text = "CalmingQuad";
SelEntityPropertyGrid.SelectedObject = item.CalmingQuad;
}
else if (item.WaveQuad != null)
{
SelectionEntityTabPage.Text = "WaveQuad";
SelEntityPropertyGrid.SelectedObject = item.WaveQuad;
}
else if (item.PathNode != null)
{
SelectionEntityTabPage.Text = "PathNode";
SelEntityPropertyGrid.SelectedObject = item.PathNode;
ynd = item.PathNode.Ynd;
ToolbarCopyButton.Enabled = true;
ToolbarDeleteItemButton.Enabled = true;
ToolbarDeleteItemButton.Text = "Delete path node";
}
else if (item.NavPoly != null)
{
SelectionEntityTabPage.Text = "NavPoly";
SelEntityPropertyGrid.SelectedObject = item.NavPoly;
ynv = item.NavPoly.Ynv;
//ToolbarCopyButton.Enabled = true;
//ToolbarDeleteItemButton.Enabled = true;
//ToolbarDeleteItemButton.Text = "Delete nav poly";
}
else if (item.NavPoint != null)
{
SelectionEntityTabPage.Text = "NavPoint";
SelEntityPropertyGrid.SelectedObject = item.NavPoint;
ynv = item.NavPoint.Ynv;
//ToolbarCopyButton.Enabled = true;
//ToolbarDeleteItemButton.Enabled = true;
//ToolbarDeleteItemButton.Text = "Delete nav point";
}
else if (item.NavPortal != null)
{
SelectionEntityTabPage.Text = "NavPortal";
SelEntityPropertyGrid.SelectedObject = item.NavPortal;
ynv = item.NavPortal.Ynv;
//ToolbarCopyButton.Enabled = true;
//ToolbarDeleteItemButton.Enabled = true;
//ToolbarDeleteItemButton.Text = "Delete nav portal";
}
else if (item.TrainTrackNode != null)
{
SelectionEntityTabPage.Text = "TrainNode";
SelEntityPropertyGrid.SelectedObject = item.TrainTrackNode;
traintr = item.TrainTrackNode.Track;
ToolbarCopyButton.Enabled = true;
ToolbarDeleteItemButton.Enabled = true;
ToolbarDeleteItemButton.Text = "Delete train track node";
}
else if (item.ScenarioNode != null)
{
SelectionEntityTabPage.Text = item.ScenarioNode.ShortTypeName;
SelEntityPropertyGrid.SelectedObject = item.ScenarioNode;
scenario = item.ScenarioNode.Ymt;
ToolbarCopyButton.Enabled = true;
ToolbarDeleteItemButton.Enabled = true;
ToolbarDeleteItemButton.Text = "Delete scenario point";
}
else if (item.Audio != null)
{
SelectionEntityTabPage.Text = item.Audio.ShortTypeName;
SelEntityPropertyGrid.SelectedObject = item.Audio;
audiofile = item.Audio.RelFile;
}
else
{
SelectionEntityTabPage.Text = "Entity";
SelEntityPropertyGrid.SelectedObject = item.EntityDef;
if (item.EntityDef != null)
{
ymap = item.EntityDef?.Ymap;
ToolbarCopyButton.Enabled = true;
ToolbarDeleteItemButton.Enabled = true;
ToolbarDeleteItemButton.Text = "Delete entity";
}
}
if (item.EntityExtension != null)
{
SelExtensionPropertyGrid.SelectedObject = item.EntityExtension;
ShowSelectedExtensionTab(true);
}
else if (item.ArchetypeExtension != null)
{
SelExtensionPropertyGrid.SelectedObject = item.ArchetypeExtension;
ShowSelectedExtensionTab(true);
}
else if (item.CollisionVertex != null)
{
SelExtensionPropertyGrid.SelectedObject = item.CollisionVertex;
ShowSelectedExtensionTab(true, "Coll");
ToolbarDeleteItemButton.Enabled = true;
ToolbarDeleteItemButton.Text = "Delete collision vertex";
}
else if (item.CollisionPoly != null)
{
SelExtensionPropertyGrid.SelectedObject = item.CollisionPoly;
ShowSelectedExtensionTab(true, "Coll");
ToolbarDeleteItemButton.Enabled = true;
ToolbarDeleteItemButton.Text = "Delete collision poly";
}
else if (item.CollisionBounds != null)
{
SelExtensionPropertyGrid.SelectedObject = item.CollisionBounds;
ShowSelectedExtensionTab(true, "Coll");
ToolbarDeleteItemButton.Enabled = true;
ToolbarDeleteItemButton.Text = "Delete collision bounds";
}
else
{
SelExtensionPropertyGrid.SelectedObject = null;
ShowSelectedExtensionTab(false);
}
if (ymap != null)
{
EnableYmapUI(true, ymap.Name);
}
if (ynd != null)
{
EnableYndUI(true, ynd.Name);
}
if (ynv != null)
{
EnableYnvUI(true, ynv.Name);
}
if (traintr != null)
{
EnableTrainsUI(true, traintr.Name);
}
if (scenario != null)
{
EnableScenarioUI(true, scenario.Name);
}
if (audiofile != null)
{
EnableAudioUI(true, audiofile.Name);
}
}
private void ShowSelectedExtensionTab(bool show, string text = "Ext")
{
SelectionExtensionTabPage.Text = text;
if (show)
{
if (!SelectionTabControl.TabPages.Contains(SelectionExtensionTabPage))
{
SelectionTabControl.TabPages.Add(SelectionExtensionTabPage);
SelectionTabControl.SelectedTab = SelectionExtensionTabPage;
}
}
else
{
if (SelectionTabControl.TabPages.Contains(SelectionExtensionTabPage))
{
SelectionTabControl.TabPages.Remove(SelectionExtensionTabPage);
}
}
}
private void AddSelectionDrawableModelsTreeNodes(DrawableModel[] models, string prefix, bool check)
{
if (models == null) return;
for (int mi = 0; mi < models.Length; mi++)
{
var model = models[mi];
string mprefix = prefix + " " + (mi + 1).ToString();
var mnode = SelDrawableModelsTreeView.Nodes.Add(mprefix + " " + model.ToString());
mnode.Tag = model;
mnode.Checked = check;
var tmnode = SelDrawableTexturesTreeView.Nodes.Add(mprefix + " " + model.ToString());
tmnode.Tag = model;
if (!check)
{
Renderer.SelectionModelDrawFlags[model] = false;
}
if (model.Geometries == null) continue;
foreach (var geom in model.Geometries)
{
var gname = geom.ToString();
var gnode = mnode.Nodes.Add(gname);
gnode.Tag = geom;
gnode.Checked = true;// check;
var tgnode = tmnode.Nodes.Add(gname);
tgnode.Tag = geom;
if ((geom.Shader != null) && (geom.Shader.ParametersList != null) && (geom.Shader.ParametersList.Hashes != null))
{
var pl = geom.Shader.ParametersList;
var h = pl.Hashes;
var p = pl.Parameters;
for (int ip = 0; ip < h.Length; ip++)
{
var hash = pl.Hashes[ip];
var parm = pl.Parameters[ip];
var tex = parm.Data as TextureBase;
if (tex != null)
{
var t = tex as Texture;
var tstr = tex.Name.Trim();
if (t != null)
{
tstr = string.Format("{0} ({1}x{2}, embedded)", tex.Name, t.Width, t.Height);
}
var tnode = tgnode.Nodes.Add(hash.ToString().Trim() + ": " + tstr);
tnode.Tag = tex;
}
}
tgnode.Expand();
}
}
mnode.Expand();
tmnode.Expand();
}
}
private void UpdateSelectionDrawFlags(TreeNode node)
{
//update the selection draw flags depending on tag and checked/unchecked
var model = node.Tag as DrawableModel;
var geom = node.Tag as DrawableGeometry;
bool rem = node.Checked;
Renderer.UpdateSelectionDrawFlags(model, geom, rem);
}
public void SyncSelDrawableModelsTreeNode(TreeNode node)
{
//called by the info form when a selection treeview node is checked/unchecked.
foreach (TreeNode mnode in SelDrawableModelsTreeView.Nodes)
{
if (mnode.Tag == node.Tag)
{
if (mnode.Checked != node.Checked)
{
mnode.Checked = node.Checked;
}
}
foreach (TreeNode gnode in mnode.Nodes)
{
if (gnode.Tag == node.Tag)
{
if (gnode.Checked != node.Checked)
{
gnode.Checked = node.Checked;
}
}
}
}
}
private void ShowInfoForm()
{
if (InfoForm == null)
{
InfoForm = new WorldInfoForm(this);
InfoForm.SetSelection(SelectedItem);
InfoForm.SetSelectionMode(SelectionModeStr, MouseSelectEnabled);
InfoForm.Show(this);
}
else
{
if (InfoForm.WindowState == FormWindowState.Minimized)
{
InfoForm.WindowState = FormWindowState.Normal;
}
InfoForm.Focus();
}
ToolbarInfoWindowButton.Checked = true;
}
public void OnInfoFormSelectionModeChanged(string mode, bool enableSelect)
{
//called by the WorldInfoForm
SetSelectionMode(mode);
SetMouseSelect(enableSelect);
}
public void OnInfoFormClosed()
{
//called by the WorldInfoForm when it's closed.
InfoForm = null;
ToolbarInfoWindowButton.Checked = false;
}
private void ShowProjectForm()
{
if (ProjectForm == null)
{
ProjectForm = new ProjectForm(this);
ProjectForm.Show(this);
ProjectForm.OnWorldSelectionChanged(SelectedItem); // so that the project form isn't stuck on the welcome window.
}
else
{
if (ProjectForm.WindowState == FormWindowState.Minimized)
{
ProjectForm.WindowState = FormWindowState.Normal;
}
ProjectForm.Focus();
}
ToolbarProjectWindowButton.Checked = true;
}
public void OnProjectFormClosed()
{
ProjectForm = null;
ToolbarProjectWindowButton.Checked = false;
}
private void ShowSearchForm()
{
if (SearchForm == null)
{
SearchForm = new WorldSearchForm(this);
SearchForm.Show(this);
}
else
{
if (SearchForm.WindowState == FormWindowState.Minimized)
{
SearchForm.WindowState = FormWindowState.Normal;
}
SearchForm.Focus();
}
//ToolbarSearchWindowButton.Checked = true;
}
public void OnSearchFormClosed()
{
SearchForm = null;
//ToolbarSearchWindowButton.Checked = false;
}
private void ShowCutsceneForm()
{
if (CutsceneForm == null)
{
CutsceneForm = new CutsceneForm(this);
CutsceneForm.Show(this);
}
else
{
if (CutsceneForm.WindowState == FormWindowState.Minimized)
{
CutsceneForm.WindowState = FormWindowState.Normal;
}
CutsceneForm.Focus();
}
//ToolbarCutsceneWindowButton.Checked = true;
}
public void OnCutsceneFormClosed()
{
CutsceneForm = null;
//ToolbarCutsceneWindowButton.Checked = false;
}
public void ShowModel(string name)
{
ViewModeComboBox.Text = "Model view";
ModelComboBox.Text = name;
modelname = name;
}
public void GoToEntity(YmapEntityDef entity)
{
if (entity == null) return;
ViewModeComboBox.Text = "World view";
GoToPosition(entity.Position);
SelectObject(entity);
}
private void LoadWorld()
{
#if !DEBUG
try
{
#endif
UpdateStatus("Loading timecycles...");
timecycle.Init(gameFileCache, UpdateStatus);
timecycle.SetTime(Renderer.timeofday);
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Error loading timecycles: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
#endif
UpdateStatus("Loading materials...");
BoundsMaterialTypes.Init(gameFileCache);
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Error loading materials: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
#endif
UpdateStatus("Loading weather...");
weather.Init(gameFileCache, UpdateStatus, timecycle);
UpdateWeatherTypesComboBox(weather);
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Error loading weather files, ensure you do not have FiveMods installed or any Redux mod. Game may require reinstall.: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
#endif
UpdateStatus("Loading clouds...");
clouds.Init(gameFileCache, UpdateStatus, weather);
UpdateCloudTypesComboBox(clouds);
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Error loading clouds: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
#endif
UpdateStatus("Loading water...");
water.Init(gameFileCache, UpdateStatus);
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Error loading water: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
#endif
UpdateStatus("Loading trains...");
trains.Init(gameFileCache, UpdateStatus);
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Error loading trains: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
#endif
UpdateStatus("Loading scenarios...");
scenarios.Init(gameFileCache, UpdateStatus, timecycle);
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Error loading scenarios: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
#endif
UpdateStatus("Loading popzones...");
popzones.Init(gameFileCache, UpdateStatus);
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Error loading popzones: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
#endif
UpdateStatus("Loading heightmaps...");
heightmaps.Init(gameFileCache, UpdateStatus);
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Error loading heightmaps: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
#endif
UpdateStatus("Loading watermaps...");
watermaps.Init(gameFileCache, UpdateStatus);
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Error loading watermaps: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
#endif
UpdateStatus("Loading audio zones...");
audiozones.Init(gameFileCache, UpdateStatus);
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Error loading audio zones: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
#endif
UpdateStatus("Loading world...");
space.Init(gameFileCache, UpdateStatus);
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Error loading world: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
#endif
UpdateStatus("World loaded");
}
private void SetDlcLevel(string dlc, bool enable)
{
if (!initialised) return;
Cursor = Cursors.WaitCursor;
Task.Run(() =>
{
lock (Renderer.RenderSyncRoot)
{
if (gameFileCache.SetDlcLevel(dlc, enable))
{
LoadWorld();
}
}
Invoke(new Action(()=> {
Cursor = Cursors.Default;
}));
});
}
private void SetModsEnabled(bool enable)
{
if (!initialised) return;
Cursor = Cursors.WaitCursor;
Task.Run(() =>
{
lock (Renderer.RenderSyncRoot)
{
if (gameFileCache.SetModsEnabled(enable))
{
UpdateDlcListComboBox(gameFileCache.DlcNameList);
LoadWorld();
}
}
Invoke(new Action(() => {
Cursor = Cursors.Default;
}));
});
}
private void ContentThread()
{
//main content loading thread.
running = true;
UpdateStatus("Scanning...");
try
{
GTA5Keys.LoadFromPath(GTAFolder.CurrentGTAFolder, Settings.Default.Key);
//save the key for later if it's not saved already. not really ideal to have this in this thread
if (string.IsNullOrEmpty(Settings.Default.Key) && (GTA5Keys.PC_AES_KEY != null))
{
Settings.Default.Key = Convert.ToBase64String(GTA5Keys.PC_AES_KEY);
Settings.Default.Save();
}
}
catch
{
MessageBox.Show("Keys not found! This shouldn't happen, GTA5.exe outdated? CodeWalker outdated?");
Close();
return;
}
gameFileCache.Init(UpdateStatus, LogError);
UpdateDlcListComboBox(gameFileCache.DlcNameList);
EnableCacheDependentUI();
#if !DEBUG
try
{
#endif
LoadWorld();
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Failed to load world: {ex.Message}");
Close();
return;
}
#endif
initialised = true;
EnableDLCModsUI();
Task.Run(() => {
while (formopen && !IsDisposed) //renderer content loop
{
#if !DEBUG
try
{
#endif
bool rcItemsPending = Renderer.ContentThreadProc();
if (!rcItemsPending)
{
Thread.Sleep(1); //sleep if there's nothing to do
}
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"Renderer Failed: {ex.Message}");
Close();
return;
}
#endif
}
});
while (formopen && !IsDisposed) //main asset loop
{
#if !DEBUG
try
{
#endif
bool fcItemsPending = gameFileCache.ContentThreadProc();
if (!fcItemsPending)
{
Thread.Sleep(1); //sleep if there's nothing to do
}
#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show($"GameFileCache Failed: {ex.Message}");
Close();
return;
}
#endif
}
gameFileCache.Clear();
running = false;
}
private void UpdateStatus(string text)
{
try
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => { UpdateStatus(text); }));
}
else
{
StatusLabel.Text = text;
}
}
catch { }
}
private void UpdateMousedLabel(string text)
{
try
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => { UpdateMousedLabel(text); }));
}
else
{
MousedLabel.Text = text;
}
}
catch { }
}
private void UpdateWeatherTypesComboBox(Weather weather)
{
try
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => { UpdateWeatherTypesComboBox(weather); }));
}
else
{
//MessageBox.Show("sky_hdr: " + weather.GetDynamicValue("sky_hdr").ToString() + "\n" +
// "Timecycle index: " + weather.Timecycle.CurrentSampleIndex + "\n" +
// "Timecycle blend: " + weather.Timecycle.CurrentSampleBlend + "\n");
WeatherComboBox.Items.Clear();
foreach (string wt in weather.WeatherTypes.Keys)
{
WeatherComboBox.Items.Add(wt);
}
WeatherComboBox.SelectedIndex = Math.Max(WeatherComboBox.FindString(Settings.Default.Weather), 0);
WeatherRegionComboBox.SelectedIndex = Math.Max(WeatherRegionComboBox.FindString(Settings.Default.Region), 0);
}
}
catch { }
}
private void UpdateCloudTypesComboBox(Clouds clouds)
{
try
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => { UpdateCloudTypesComboBox(clouds); }));
}
else
{
CloudsComboBox.Items.Clear();
foreach (var frag in clouds.HatManager.CloudHatFrags)
{
CloudsComboBox.Items.Add(frag.Name);
}
CloudsComboBox.SelectedIndex = Math.Max(CloudsComboBox.FindString(Renderer.individualcloudfrag), 0);
CloudParamComboBox.Items.Clear();
foreach (var setting in clouds.AnimSettings.Values)
{
CloudParamComboBox.Items.Add(setting);
}
CloudParamComboBox.SelectedIndex = 0;
}
}
catch { }
}
private void UpdateDlcListComboBox(List<string> dlcnames)
{
try
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => { UpdateDlcListComboBox(dlcnames); }));
}
else
{
DlcLevelComboBox.Items.Clear();
foreach (var dlcname in dlcnames)
{
DlcLevelComboBox.Items.Add(dlcname);
}
if (string.IsNullOrEmpty(gameFileCache.SelectedDlc))
{
DlcLevelComboBox.SelectedIndex = dlcnames.Count - 1;
}
else
{
int idx = DlcLevelComboBox.FindString(gameFileCache.SelectedDlc);
DlcLevelComboBox.SelectedIndex = (idx > 0) ? idx : (dlcnames.Count - 1);
}
}
}
catch { }
}
private void LogError(string text)
{
try
{
if (InvokeRequired)
{
Invoke(new Action(() => { LogError(text); }));
}
else
{
ConsoleTextBox.AppendText(text + "\r\n");
//MessageBox.Show(text);
}
}
catch { }
}
private void UpdateMarkerSelectionPanelInvoke()
{
try
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => { UpdateMarkerSelectionPanel(); }));
}
else
{
UpdateMarkerSelectionPanel();
}
}
catch { }
}
private void UpdateMarkerSelectionPanel()
{
if (!SelectedMarkerPanel.Visible) return;
if (SelectedMarker == null)
{
SelectedMarkerPanel.Visible = false;
return;
}
int ox = -90; //screen offset from actual marker world pos
int oy = -76;
float spx = ((SelectedMarker.ScreenPos.X * 0.5f) + 0.5f) * camera.Width;
float spy = ((SelectedMarker.ScreenPos.Y * -0.5f) + 0.5f) * camera.Height;
int px = (int)Math.Round(spx, MidpointRounding.AwayFromZero) + ox;
int py = (int)Math.Round(spy, MidpointRounding.AwayFromZero) + oy;
int sx = SelectedMarkerPanel.Width;
int sy = SelectedMarkerPanel.Height;
SelectedMarkerPanel.SetBounds(px, py, sx, sy);
}
private void ShowMarkerSelectionInfo(MapMarker marker)
{
SelectedMarkerNameTextBox.Text = SelectedMarker.Name;
SelectedMarkerPositionTextBox.Text = SelectedMarker.Get3DWorldPosString();
UpdateMarkerSelectionPanel();
SelectedMarkerPanel.Visible = true;
}
private void HideMarkerSelectionInfo()
{
SelectedMarkerPanel.Visible = false;
}
private MapMarker FindMousedMarker()
{
lock (markersortedsyncroot)
{
float mx = MouseLastPoint.X;
float my = MouseLastPoint.Y;
if (ShowLocatorCheckBox.Checked)
{
if (IsMarkerUnderPoint(LocatorMarker, mx, my))
{
return LocatorMarker;
}
}
//search backwards through the render markers (front to back)
for (int i = SortedMarkers.Count - 1; i >= 0; i--)
{
MapMarker m = SortedMarkers[i];
if (IsMarkerUnderPoint(m, mx, my))
{
return m;
}
}
}
return null;
}
private bool IsMarkerUnderPoint(MapMarker marker, float x, float y)
{
if (marker.ScreenPos.Z <= 0.0f) return false; //behind the camera...
float dx = x - ((marker.ScreenPos.X * 0.5f) + 0.5f) * camera.Width;
float dy = y - ((marker.ScreenPos.Y * -0.5f) + 0.5f) * camera.Height;
float mcx = marker.Icon.Center.X;
float mcy = marker.Icon.Center.Y;
bool bx = ((dx >= -mcx) && (dx <= mcx));
bool by = ((dy <= 0.0f) && (dy >= -mcy));
return (bx && by);
}
private void GoToMarker(MapMarker m)
{
//////adjust the target to account for the main panel...
////Vector3 view = m.TexturePos;
////view.X += ((float)(MainPanel.Width + 4) * 0.5f) / CurrentZoom;
////TargetViewCenter = view;
camera.FollowEntity.Position = m.WorldPos;
}
public void GoToPosition(Vector3 p)
{
camera.FollowEntity.Position = p;
}
public void GoToPosition(Vector3 p, Vector3 bound)
{
camera.FollowEntity.Position = p;
var bl = bound.Length();
camera.TargetDistance = bl > 1f ? bl : 1f;
}
public MapMarker AddMarker(Vector3 pos, string name, bool addtotxtbox = false)
{
string str = pos.X.ToString() + ", " + pos.Y.ToString() + ", " + pos.Z.ToString();
if (!string.IsNullOrEmpty(name))
{
str += ", " + name;
}
if (addtotxtbox)
{
StringBuilder sb = new StringBuilder();
sb.Append(MultiFindTextBox.Text);
if ((sb.Length > 0) && (!MultiFindTextBox.Text.EndsWith("\n")))
{
sb.AppendLine();
}
sb.AppendLine(str);
MultiFindTextBox.Text = sb.ToString();
}
return AddMarker(str);
}
private MapMarker AddMarker(string markerstr)
{
lock (markersyncroot)
{
MapMarker m = new MapMarker();
m.Parse(markerstr.Trim());
m.Icon = MarkerIcon;
Markers.Add(m);
//ListViewItem lvi = new ListViewItem(new string[] { m.Name, m.WorldPos.X.ToString(), m.WorldPos.Y.ToString(), m.WorldPos.Z.ToString() });
//lvi.Tag = m;
//MarkersListView.Items.Add(lvi);
return m;
}
}
private void AddDefaultMarkers()
{
StringBuilder sb = new StringBuilder();
//sb.AppendLine("1972.606, 3817.044, 0.0, Trevor Bed");
//sb.AppendLine("94.5723, -1290.082, 0.0, Strip Club Bed");
//sb.AppendLine("-1151.746, -1518.136, 0.0, Trevor City Bed");
//sb.AppendLine("-1154.11, -2715.203, 0.0, Flight School");
//sb.AppendLine("-1370.625, 56.1227, 52.82404, Golf");
//sb.AppendLine("-1109.213, 4914.744, 0.0, Altruist Cult");
//sb.AppendLine("-1633.087, 4736.784, 0.0, Deal Gone Wrong");
sb.AppendLine("-2052, 3237, 1449.036, Zancudo UFO");
sb.AppendLine("2490, 3777, 2400, Hippy UFO");
sb.AppendLine("2577.396, 3301.573, 52.52076, Sand glyph");
sb.AppendLine("-804.8452, 176.4936, 75.40561, bh1_48_michaels");
sb.AppendLine("-5.757423, 529.674, 171.1747, ch2_05c_b1");
sb.AppendLine("1971.208, 3818.237, 33.46632, cs4_10_trailer003b");
sb.AppendLine("760.4618, 7392.803, -126.0774, cs1_09_sea_ufo");
sb.AppendLine("501.4398, 5603.96, 795.9738, cs1_10_redeye");
sb.AppendLine("51.3909, 5957.7568, 209.614, cs1_10_clue_moon02");
sb.AppendLine("400.7087, 5714.5645, 605.0978, cs1_10_clue_rain01");
sb.AppendLine("703.442, 6329.8936, 76.4973, cs1_10_clue_rain02");
sb.AppendLine("228.7844, 5370.585, 577.2613, cs1_10_clue_moon01");
sb.AppendLine("366.4871, 5518.0742, 704.3185, cs1_10_clue_mountain01");
sb.AppendLine("41.64376, -779.9391, 832.4024, hw1_22_shipint");
sb.AppendLine("-1255.392, 6795.764, -181.9927, cs1_08_sea_base");
sb.AppendLine("4285.036, 2967.639, -184.1908, cs5_1_sea_hatch");
sb.AppendLine("3041.498, 5584.321, 196.4748, cs2_08_generic02");
sb.AppendLine("3406.483, 5498.655, 23.50577, cs2_08_generic01a");
sb.AppendLine("1507.081, 6565.075, 8.681923, cs1_09_props_elec_spider1");
sb.AppendLine("455.7852, 5586.104, 779.4382, cs1_10_elec_spider_spline052b");
sb.AppendLine("3861.661, -4959.252, 91.49448, plg_01_nico_new");
sb.AppendLine("-1689.308, 2174.457, 107.2592, ch1_09b_vinesleaf_28");
sb.AppendLine("440.8488, 5810.079, 563.4703, Cock face");
sb.AppendLine("-3955.667, -4675.212, -1274.563, Interesting...");
sb.AppendLine("4512.627, 2623.241, 2500, Interesting...");
sb.AppendLine("228.6058, -992.0537, -100, v_garagel");
MultiFindTextBox.Text = sb.ToString();
string[] lines = MultiFindTextBox.Text.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
AddMarker(line);
}
}
private void LoadSettings()
{
var s = Settings.Default;
WindowState = s.WindowMaximized ? FormWindowState.Maximized : WindowState;
FullScreenCheckBox.Checked = s.FullScreen;
WireframeCheckBox.Checked = s.Wireframe;
DeferredShadingCheckBox.Checked = s.Deferred;
HDRRenderingCheckBox.Checked = s.HDR;
ShadowsCheckBox.Checked = s.Shadows;
SkydomeCheckBox.Checked = s.Skydome;
GrassCheckBox.Checked = s.Grass;
TimedEntitiesCheckBox.Checked = s.ShowTimedEntities;
CollisionMeshesCheckBox.Checked = s.ShowCollisionMeshes;
CollisionMeshRangeTrackBar.Value = s.CollisionMeshRange;
DynamicLODCheckBox.Checked = s.DynamicLOD;
DetailTrackBar.Value = s.DetailDist;
WaitForChildrenCheckBox.Checked = s.WaitForChildren;
RenderModeComboBox.SelectedIndex = Math.Max(RenderModeComboBox.FindString(s.RenderMode), 0);
TextureSamplerComboBox.SelectedIndex = Math.Max(TextureSamplerComboBox.FindString(s.RenderTextureSampler), 0);
TextureCoordsComboBox.SelectedIndex = Math.Max(TextureCoordsComboBox.FindString(s.RenderTextureSamplerCoord), 0);
MarkerStyleComboBox.SelectedIndex = Math.Max(MarkerStyleComboBox.FindString(s.MarkerStyle), 0);
LocatorStyleComboBox.SelectedIndex = Math.Max(LocatorStyleComboBox.FindString(s.LocatorStyle), 0);
MarkerDepthClipCheckBox.Checked = s.MarkerDepthClip;
AnisotropicFilteringCheckBox.Checked = s.AnisotropicFiltering;
BoundsStyleComboBox.SelectedIndex = Math.Max(BoundsStyleComboBox.FindString(s.BoundsStyle), 0);
BoundsDepthClipCheckBox.Checked = s.BoundsDepthClip;
BoundsRangeTrackBar.Value = s.BoundsRange;
ErrorConsoleCheckBox.Checked = s.ShowErrorConsole;
StatusBarCheckBox.Checked = s.ShowStatusBar;
SnapGridSizeUpDown.Value = (decimal)s.SnapGridSize;
SetRotationSnapping(s.SnapRotationDegrees);
TimeOfDayTrackBar.Value = s.TimeOfDay;
LODLightsCheckBox.Checked = s.LODLights;
WeatherComboBox.SelectedIndex = Math.Max(WeatherComboBox.FindString(s.Weather), 0);
WeatherRegionComboBox.SelectedIndex = Math.Max(WeatherRegionComboBox.FindString(s.Region), 0);
Renderer.individualcloudfrag = s.Clouds;
NaturalAmbientLightCheckBox.Checked = s.NatrualAmbientLight;
ArtificialAmbientLightCheckBox.Checked = s.ArtificialAmbientLight;
SetTimeOfDay(s.TimeOfDay);
Renderer.SetWeatherType(s.Weather);
EnableModsCheckBox.Checked = s.EnableMods;
DlcLevelComboBox.Text = s.DLC;
gameFileCache.SelectedDlc = s.DLC;
EnableDlcCheckBox.Checked = !string.IsNullOrEmpty(s.DLC);
}
private void SaveSettings()
{
var s = Settings.Default;
s.WindowMaximized = (WindowState == FormWindowState.Maximized);
s.FullScreen = FullScreenCheckBox.Checked;
s.Wireframe = WireframeCheckBox.Checked;
s.Deferred = DeferredShadingCheckBox.Checked;
s.HDR = HDRRenderingCheckBox.Checked;
s.Shadows = ShadowsCheckBox.Checked;
s.Skydome = SkydomeCheckBox.Checked;
s.Grass = GrassCheckBox.Checked;
s.ShowTimedEntities = TimedEntitiesCheckBox.Checked;
s.ShowCollisionMeshes = CollisionMeshesCheckBox.Checked;
s.CollisionMeshRange = CollisionMeshRangeTrackBar.Value;
s.DynamicLOD = DynamicLODCheckBox.Checked;
s.DetailDist = DetailTrackBar.Value;
s.WaitForChildren = WaitForChildrenCheckBox.Checked;
s.RenderMode = RenderModeComboBox.Text;
s.RenderTextureSampler = TextureSamplerComboBox.Text;
s.RenderTextureSamplerCoord = TextureCoordsComboBox.Text;
s.MarkerStyle = MarkerStyleComboBox.Text;
s.LocatorStyle = LocatorStyleComboBox.Text;
s.MarkerDepthClip = MarkerDepthClipCheckBox.Checked;
s.AnisotropicFiltering = AnisotropicFilteringCheckBox.Checked;
s.BoundsStyle = BoundsStyleComboBox.Text;
s.BoundsDepthClip = BoundsDepthClipCheckBox.Checked;
s.BoundsRange = BoundsRangeTrackBar.Value;
s.ShowErrorConsole = ErrorConsoleCheckBox.Checked;
s.ShowStatusBar = StatusBarCheckBox.Checked;
s.SnapRotationDegrees = (float)SnapAngleUpDown.Value;
s.SnapGridSize = (float)SnapGridSizeUpDown.Value;
s.TimeOfDay = TimeOfDayTrackBar.Value;
s.LODLights = LODLightsCheckBox.Checked;
s.Weather = WeatherComboBox.Text;
s.NatrualAmbientLight = NaturalAmbientLightCheckBox.Checked;
s.ArtificialAmbientLight = ArtificialAmbientLightCheckBox.Checked;
s.Region = WeatherRegionComboBox.Text;
s.Clouds = CloudsComboBox.Text;
//additional settings from gamefilecache...
s.EnableMods = gameFileCache.EnableMods;
s.DLC = gameFileCache.EnableDlc ? gameFileCache.SelectedDlc : "";
s.Save();
}
private void ShowSettingsForm(string tab = "")
{
if (SettingsForm == null)
{
SettingsForm = new SettingsForm(this);
SettingsForm.Show(this);
}
else
{
if (SettingsForm.WindowState == FormWindowState.Minimized)
{
SettingsForm.WindowState = FormWindowState.Normal;
}
SettingsForm.Focus();
}
if (!string.IsNullOrEmpty(tab))
{
SettingsForm.SelectTab(tab);
}
}
public void OnSettingsFormClosed()
{
//called by the SettingsForm when it's closed.
SettingsForm = null;
}
private void MarkUndoStart(Widget w)
{
if (!SelectedItem.CanMarkUndo()) return;
if (Widget is TransformWidget)
{
UndoStartPosition = Widget.Position;
UndoStartRotation = Widget.Rotation;
UndoStartScale = Widget.Scale;
}
}
private void MarkUndoEnd(Widget w)
{
if (!SelectedItem.CanMarkUndo()) return;
TransformWidget tw = Widget as TransformWidget;
UndoStep s = null;
if (tw != null)
{
s = SelectedItem.CreateUndoStep(tw.Mode, UndoStartPosition, UndoStartRotation, UndoStartScale, this, EditEntityPivot);
}
if (s != null)
{
RedoSteps.Clear();
UndoSteps.Push(s);
UpdateUndoUI();
}
}
private void Undo()
{
if (UndoSteps.Count == 0) return;
var s = UndoSteps.Pop();
RedoSteps.Push(s);
s.Undo(this, ref SelectedItem);
if (ProjectForm != null)
{
ProjectForm.OnWorldSelectionModified(SelectedItem);
}
UpdateUndoUI();
}
private void Redo()
{
if (RedoSteps.Count == 0) return;
var s = RedoSteps.Pop();
UndoSteps.Push(s);
s.Redo(this, ref SelectedItem);
if (ProjectForm != null)
{
ProjectForm.OnWorldSelectionModified(SelectedItem);
}
UpdateUndoUI();
}
private void UpdateUndoUI()
{
ToolbarUndoButton.DropDownItems.Clear();
ToolbarRedoButton.DropDownItems.Clear();
int i = 0;
foreach (var step in UndoSteps)
{
var button = ToolbarUndoButton.DropDownItems.Add(step.ToString());
button.Tag = step;
button.Click += ToolbarUndoListButton_Click;
i++;
if (i >= 10) break;
}
i = 0;
foreach (var step in RedoSteps)
{
var button = ToolbarRedoButton.DropDownItems.Add(step.ToString());
button.Tag = step;
button.Click += ToolbarRedoListButton_Click;
i++;
if (i >= 10) break;
}
ToolbarUndoButton.Enabled = (UndoSteps.Count > 0);
ToolbarRedoButton.Enabled = (RedoSteps.Count > 0);
}
private void EnableCacheDependentUI()
{
try
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => { EnableCacheDependentUI(); }));
}
else
{
ToolbarNewButton.Enabled = true;
ToolbarOpenButton.Enabled = true;
ToolbarProjectWindowButton.Enabled = true;
ToolsMenuProjectWindow.Enabled = true;
ToolsMenuCutsceneViewer.Enabled = true;
ToolsMenuAudioExplorer.Enabled = true;
ToolsMenuBinarySearch.Enabled = true;
ToolsMenuJenkInd.Enabled = true;
}
}
catch { }
}
private void EnableDLCModsUI()
{
try
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => { EnableDLCModsUI(); }));
}
else
{
EnableDlcCheckBox.Enabled = true;
EnableModsCheckBox.Enabled = true;
DlcLevelComboBox.Enabled = true;
}
}
catch { }
}
public void SetCurrentSaveItem(string filename)
{
bool enable = !string.IsNullOrEmpty(filename);
ToolbarSaveButton.ToolTipText = enable ? ("Save " + filename) : "Save";
ToolbarSaveButton.Enabled = enable;
ToolbarSaveAllButton.Enabled = enable;
}
public void EnableYmapUI(bool enable, string filename)
{
string type = "entity";
switch (SelectionMode)
{
case MapSelectionMode.CarGenerator: type = "car generator"; break;
}
ToolbarAddItemButton.ToolTipText = "Add " + type + (enable ? (" to " + filename) : "");
ToolbarAddItemButton.Enabled = enable;
}
public void EnableYbnUI(bool enable, string filename)
{
if (enable) //only do something if a ybn is selected - EnableYmapUI will handle the no selection case..
{
//ToolbarAddItemButton.ToolTipText = "Add " + type + (enable ? (" to " + filename) : "");
//ToolbarAddItemButton.Enabled = enable;
}
}
public void EnableYndUI(bool enable, string filename)
{
string type = "node";
switch (SelectionMode)
{
case MapSelectionMode.Path: type = "node"; break;
}
if (enable) //only do something if a ynd is selected - EnableYmapUI will handle the no selection case..
{
ToolbarAddItemButton.ToolTipText = "Add " + type + (enable ? (" to " + filename) : "");
ToolbarAddItemButton.Enabled = enable;
}
}
public void EnableYnvUI(bool enable, string filename)
{
string type = "polygon";
switch (SelectionMode)
{
case MapSelectionMode.NavMesh: type = "polygon"; break;
}
if (enable) //only do something if a ynv is selected - EnableYmapUI will handle the no selection case..
{
ToolbarAddItemButton.ToolTipText = "Add " + type + (enable ? (" to " + filename) : "");
ToolbarAddItemButton.Enabled = enable;
}
}
public void EnableTrainsUI(bool enable, string filename)
{
string type = "node";
switch (SelectionMode)
{
case MapSelectionMode.TrainTrack: type = "node"; break;
}
if (enable) //only do something if a track is selected - EnableYmapUI will handle the no selection case..
{
ToolbarAddItemButton.ToolTipText = "Add " + type + (enable ? (" to " + filename) : "");
ToolbarAddItemButton.Enabled = enable;
}
}
public void EnableScenarioUI(bool enable, string filename)
{
string type = "scenario point";
switch (SelectionMode)
{
case MapSelectionMode.Scenario: type = "scenario point"; break;
}
if (enable) //only do something if a scenario is selected - EnableYmapUI will handle the no selection case..
{
ToolbarAddItemButton.ToolTipText = "Add " + type + (enable ? (" to " + filename) : "");
ToolbarAddItemButton.Enabled = enable;
}
}
public void EnableAudioUI(bool enable, string filename) //TODO
{
}
private void New()
{
ShowProjectForm();
if (ProjectForm.IsProjectLoaded)
{
ProjectForm.NewYmap();
}
else
{
ProjectForm.NewProject();
}
}
private void NewProject()
{
ShowProjectForm();
ProjectForm.NewProject();
}
private void NewYmap()
{
ShowProjectForm();
ProjectForm.NewYmap();
}
private void NewYtyp()
{
ShowProjectForm();
ProjectForm.NewYtyp();
}
private void NewYbn()
{
ShowProjectForm();
ProjectForm.NewYbn();
}
private void NewYnd()
{
ShowProjectForm();
ProjectForm.NewYnd();
}
private void NewTrainTrack()
{
ShowProjectForm();
ProjectForm.NewTrainTrack();
}
private void NewScenario()
{
ShowProjectForm();
ProjectForm.NewScenario();
}
private void Open()
{
ShowProjectForm();
if (ProjectForm.IsProjectLoaded)
{
ProjectForm.OpenFiles();
}
else
{
ProjectForm.OpenProject();
}
}
private void OpenProject()
{
ShowProjectForm();
ProjectForm.OpenProject();
}
private void OpenFiles()
{
ShowProjectForm();
ProjectForm.OpenFiles();
}
private void OpenFolder()
{
ShowProjectForm();
ProjectForm.OpenFolder();
}
private void Save()
{
if (ProjectForm == null) return;
ProjectForm.Save();
}
private void SaveAll()
{
if (ProjectForm == null) return;
ProjectForm.SaveAll();
}
private void AddItem()
{
if (ProjectForm == null) return;
switch (SelectionMode)
{
case MapSelectionMode.Entity: ProjectForm.NewEntity(); break;
case MapSelectionMode.CarGenerator: ProjectForm.NewCarGen(); break;
case MapSelectionMode.Path: ProjectForm.NewPathNode(); break;
case MapSelectionMode.NavMesh: ProjectForm.NewNavPoly(); break; //.NewNavPoint/.NewNavPortal//how to add points/portals? project window
case MapSelectionMode.TrainTrack: ProjectForm.NewTrainNode(); break;
case MapSelectionMode.Scenario: ProjectForm.NewScenarioNode(); break; //how to add different node types? project window
case MapSelectionMode.Audio: ProjectForm.NewAudioAmbientZone(); break; //.NewAudioEmitter // how to add emitters as well? project window
}
}
private void CopyItem()
{
CopiedItem = SelectedItem;
ToolbarPasteButton.Enabled = CopiedItem.CanCopyPaste && (ProjectForm != null); //ToolbarAddItemButton.Enabled;
}
private void PasteItem()
{
if ((ProjectForm != null) && CopiedItem.CanCopyPaste)
{
SelectObject(ProjectForm.NewObject(CopiedItem, (CopiedItem.MultipleSelectionItems != null)));
}
}
private void CloneItem()
{
if ((ProjectForm != null) && SelectedItem.CanCopyPaste)
{
SelectObject(ProjectForm.NewObject(SelectedItem, true));
}
}
private void DeleteItem()
{
if (ProjectForm != null)
{
ProjectForm.DeleteObject(SelectedItem);
SelectItem(null);
}
else
{
DeleteItem(SelectedItem);
SelectItem(null);
}
}
private void DeleteItem(MapSelection item)
{
if (item.MultipleSelectionItems != null)
{
for (int i = 0; i < item.MultipleSelectionItems.Length; i++)
{
DeleteItem(item.MultipleSelectionItems[i]);
}
}
else if (item.CollisionVertex != null) DeleteCollisionVertex(item.CollisionVertex);
else if (item.CollisionPoly != null) DeleteCollisionPoly(item.CollisionPoly);
else if (item.CollisionBounds != null) DeleteCollisionBounds(item.CollisionBounds);
else if (item.EntityDef != null) DeleteEntity(item.EntityDef);
else if (item.CarGenerator != null) DeleteCarGen(item.CarGenerator);
else if (item.LodLight != null) DeleteLodLight(item.LodLight);
else if (item.BoxOccluder != null) DeleteBoxOccluder(item.BoxOccluder);
else if (item.OccludeModelTri != null) DeleteOccludeModelTriangle(item.OccludeModelTri);
else if (item.PathNode != null) DeletePathNode(item.PathNode);
else if (item.NavPoly != null) DeleteNavPoly(item.NavPoly);
else if (item.NavPoint != null) DeleteNavPoint(item.NavPoint);
else if (item.NavPortal != null) DeleteNavPortal(item.NavPortal);
else if (item.TrainTrackNode != null) DeleteTrainNode(item.TrainTrackNode);
else if (item.ScenarioNode != null) DeleteScenarioNode(item.ScenarioNode);
else if (item.Audio?.AmbientZone != null) DeleteAudioAmbientZone(item.Audio);
else if (item.Audio?.AmbientRule != null) DeleteAudioAmbientRule(item.Audio);
else if (item.Audio?.StaticEmitter != null) DeleteAudioStaticEmitter(item.Audio);
}
private void DeleteEntity(YmapEntityDef ent)
{
if (ent == null) return;
//project not open, or entity not selected there, just remove the entity from the ymap/mlo...
var ymap = ent.Ymap;
var instance = ent.MloParent?.MloInstance;
if (ymap == null)
{
if (instance != null)
{
try
{
if (!instance.DeleteEntity(ent))
{
SelectItem(null);
}
}
catch (Exception e) // various failures can happen here.
{
MessageBox.Show("Unable to remove entity..." + Environment.NewLine + e.Message);
}
}
}
else if (!ymap.RemoveEntity(ent))
{
MessageBox.Show("Unable to remove entity.");
}
else
{
SelectItem(null);
}
}
private void DeleteCarGen(YmapCarGen cargen)
{
if (cargen == null) return;
//project not open, or cargen not selected there, just remove the cargen from the ymap...
var ymap = cargen.Ymap;
if (!ymap.RemoveCarGen(cargen))
{
MessageBox.Show("Unable to remove car generator.");
}
else
{
SelectItem(null);
}
}
private void DeleteLodLight(YmapLODLight lodlight)
{
if (lodlight == null) return;
//project not open, or lodlight not selected there, just remove the lodlight from the ymap...
var ymap = lodlight.Ymap;
if (!ymap.RemoveLodLight(lodlight))
{
MessageBox.Show("Unable to remove LOD light.");
}
else
{
SelectItem(null);
}
}
private void DeleteBoxOccluder(YmapBoxOccluder box)
{
if (box == null) return;
//project not open, or box not selected there, just remove the box from the ymap...
var ymap = box.Ymap;
if (!ymap.RemoveBoxOccluder(box))
{
MessageBox.Show("Unable to remove box occluder.");
}
else
{
SelectItem(null);
}
}
private void DeleteOccludeModelTriangle(YmapOccludeModelTriangle tri)
{
if (tri == null) return;
//project not open, or tri not selected there, just remove the tri from the ymap...
var ymap = tri.Ymap;
if (!ymap.RemoveOccludeModelTriangle(tri))
{
MessageBox.Show("Unable to remove occlude model triangle.");
}
else
{
UpdateOccludeModelGraphics(tri.Model);
SelectItem(null);
}
}
private void DeletePathNode(YndNode pathnode)
{
if (pathnode == null) return;
if (pathnode.Ynd == null) return;
//project not open, or node not selected there, just remove the node from the ynd...
var ynd = pathnode.Ynd;
if (!ynd.RemoveYndNode(Space, pathnode, true, out var affectedFiles))
{
MessageBox.Show("Unable to remove path node.");
}
else
{
UpdatePathNodeGraphics(pathnode, false);
ProjectForm?.AddYndToProject(ynd);
foreach (var affectedFile in affectedFiles)
{
UpdatePathYndGraphics(affectedFile, false);
ProjectForm?.AddYndToProject(affectedFile);
affectedFile.HasChanged = true;
}
SelectItem(null);
}
}
private void DeleteNavPoly(YnvPoly navpoly)
{
if (navpoly == null) return;
//project not open, or nav poly not selected there, just remove the poly from the ynv...
var ynv = navpoly.Ynv;
if (!ynv.RemovePoly(navpoly))
{
MessageBox.Show("Unable to remove nav poly. NavMesh editing TODO!");
}
else
{
UpdateNavPolyGraphics(navpoly, false);
SelectItem(null);
}
}
private void DeleteNavPoint(YnvPoint navpoint)
{
if (navpoint == null) return;
//project not open, or nav point not selected there, just remove the point from the ynv...
var ynv = navpoint.Ynv;
if (!ynv.RemovePoint(navpoint))
{
MessageBox.Show("Unable to remove nav point. NavMesh editing TODO!");
}
else
{
UpdateNavPointGraphics(navpoint, false);
SelectItem(null);
}
}
private void DeleteNavPortal(YnvPortal navportal)
{
if (navportal == null) return;
//project not open, or nav portal not selected there, just remove the portal from the ynv...
var ynv = navportal.Ynv;
if (!ynv.RemovePortal(navportal))
{
MessageBox.Show("Unable to remove nav portal. NavMesh editing TODO!");
}
else
{
UpdateNavPortalGraphics(navportal, false);
SelectItem(null);
}
}
private void DeleteTrainNode(TrainTrackNode trainnode)
{
if (trainnode == null) return;
//project not open, or train node not selected there, just remove the node from the train track...
var track = trainnode.Track;
if (!track.RemoveNode(trainnode))
{
MessageBox.Show("Unable to remove train track node.");
}
else
{
UpdateTrainTrackNodeGraphics(trainnode, false);
SelectItem(null);
}
}
private void DeleteScenarioNode(ScenarioNode scenariopt)
{
if (scenariopt == null) return;
//project not open, or scenario point not selected there, just remove the point from the region...
var region = scenariopt.Region.Ymt.ScenarioRegion;
if (!region.RemoveNode(scenariopt))
{
MessageBox.Show("Unable to remove scenario point.");
}
else
{
UpdateScenarioGraphics(scenariopt.Ymt, false);
SelectItem(null);
}
}
private void DeleteAudioAmbientZone(AudioPlacement audio)
{
if (audio == null) return;
//project not open, or zone not selected there, just remove the zone from the rel...
var rel = audio.RelFile;
if (!rel.RemoveRelData(audio.AmbientZone))
{
MessageBox.Show("Unable to remove audio ambient zone.");
}
else
{
SelectItem(null);
}
}
private void DeleteAudioAmbientRule(AudioPlacement audio)
{
if (audio == null) return;
//project not open, or rule not selected there, just remove the rule from the rel...
var rel = audio.RelFile;
if (!rel.RemoveRelData(audio.AmbientRule))
{
MessageBox.Show("Unable to remove audio ambient rule.");
}
else
{
SelectItem(null);
}
}
private void DeleteAudioStaticEmitter(AudioPlacement audio)
{
if (audio == null) return;
//project not open, or emitter not selected there, just remove the emitter from the rel...
var rel = audio.RelFile;
if (!rel.RemoveRelData(audio.StaticEmitter))
{
MessageBox.Show("Unable to remove audio static emitter.");
}
else
{
SelectItem(null);
}
}
private void DeleteCollisionVertex(BoundVertex vertex)
{
if (vertex == null) return;
//project not open, or vertex not selected there, just remove the vertex from the geometry...
var bgeom = vertex.Owner;
if ((bgeom == null) || (!bgeom.DeleteVertex(vertex.Index)))
{
MessageBox.Show("Unable to remove vertex.");
}
else
{
UpdateCollisionBoundsGraphics(bgeom);
SelectItem(null);
}
}
private void DeleteCollisionPoly(BoundPolygon poly)
{
if (poly == null) return;
//project not open, or polygon not selected there, just remove the vertex from the geometry...
var bgeom = poly.Owner;
if ((bgeom == null) || (!bgeom.DeletePolygon(poly)))
{
MessageBox.Show("Unable to remove polygon.");
}
else
{
UpdateCollisionBoundsGraphics(bgeom);
SelectItem(null);
}
}
private void DeleteCollisionBounds(Bounds bounds)
{
if (bounds == null) return;
var parent = bounds.Parent;
if (parent != null)
{
parent.DeleteChild(bounds);
UpdateCollisionBoundsGraphics(parent);
}
else
{
var ybn = bounds.GetRootYbn();
ybn.RemoveBounds(bounds);
}
SelectItem(null);
}
private void SetMouseSelect(bool enable)
{
MouseSelectEnabled = enable;
MouseSelectCheckBox.Checked = enable;
ToolbarSelectButton.Checked = enable;
if (InfoForm != null)
{
InfoForm.SetSelectionMode(SelectionModeStr, MouseSelectEnabled);
}
}
private void SetWidgetMode(string mode)
{
ToolbarMoveButton.Checked = false;
ToolbarRotateButton.Checked = false;
ToolbarScaleButton.Checked = false;
lock (Renderer.RenderSyncRoot)
{
switch (mode)
{
case "Default":
Widget.Mode = WidgetMode.Default;
iseditmode = false;
break;
case "Position":
Widget.Mode = WidgetMode.Position;
iseditmode = true;
ToolbarMoveButton.Checked = true;
break;
case "Rotation":
Widget.Mode = WidgetMode.Rotation;
iseditmode = true;
ToolbarRotateButton.Checked = true;
break;
case "Scale":
Widget.Mode = WidgetMode.Scale;
iseditmode = true;
ToolbarScaleButton.Checked = true;
break;
}
}
}
private void SetWidgetSpace(string space)
{
foreach (var child in ToolbarTransformSpaceButton.DropDownItems)
{
var childi = child as ToolStripMenuItem;
if (childi != null)
{
childi.Checked = false;
}
}
lock (Renderer.RenderSyncRoot)
{
switch (space)
{
case "World space":
Widget.ObjectSpace = false;
ToolbarTransformSpaceButton.Image = ToolbarWorldSpaceButton.Image;
ToolbarWorldSpaceButton.Checked = true;
break;
case "Object space":
Widget.ObjectSpace = true;
ToolbarTransformSpaceButton.Image = ToolbarObjectSpaceButton.Image;
ToolbarObjectSpaceButton.Checked = true;
break;
}
}
}
private void ToggleWidgetSpace()
{
SetWidgetSpace(Widget.ObjectSpace ? "World space" : "Object space");
}
private void SetFullscreen(bool fullscreen)
{
if (fullscreen)
{
FormBorderStyle = FormBorderStyle.None;
WindowState = FormWindowState.Maximized;
}
else
{
WindowState = FormWindowState.Normal;
FormBorderStyle = FormBorderStyle.Sizable;
}
}
private void SetBoundsMode(string modestr)
{
BoundsShaderMode mode = BoundsShaderMode.None;
switch (modestr)
{
case "Boxes":
mode = BoundsShaderMode.Box;
break;
case "Spheres":
mode = BoundsShaderMode.Sphere;
break;
}
Renderer.boundsmode = mode;
}
private void SetSelectionMode(string modestr)
{
foreach (var child in ToolbarSelectButton.DropDownItems)
{
var childi = child as ToolStripMenuItem;
if (childi != null)
{
childi.Checked = false;
}
}
MapSelectionMode mode = MapSelectionMode.Entity;
switch (modestr)
{
default:
case "Entity":
mode = MapSelectionMode.Entity;
ToolbarSelectEntityButton.Checked = true;
break;
case "Entity Extension":
mode = MapSelectionMode.EntityExtension;
ToolbarSelectEntityExtensionButton.Checked = true;
break;
case "Archetype Extension":
mode = MapSelectionMode.ArchetypeExtension;
ToolbarSelectArchetypeExtensionButton.Checked = true;
break;
case "Time Cycle Modifier":
mode = MapSelectionMode.TimeCycleModifier;
ToolbarSelectTimeCycleModifierButton.Checked = true;
break;
case "Car Generator":
mode = MapSelectionMode.CarGenerator;
ToolbarSelectCarGeneratorButton.Checked = true;
break;
case "Grass":
mode = MapSelectionMode.Grass;
ToolbarSelectGrassButton.Checked = true;
break;
case "Water Quad":
mode = MapSelectionMode.WaterQuad;
ToolbarSelectWaterQuadButton.Checked = true;
break;
case "Water Calming Quad":
mode = MapSelectionMode.CalmingQuad;
ToolbarSelectCalmingQuadButton.Checked = true;
break;
case "Water Wave Quad":
mode = MapSelectionMode.WaveQuad;
ToolbarSelectWaveQuadButton.Checked = true;
break;
case "Collision":
mode = MapSelectionMode.Collision;
ToolbarSelectCollisionButton.Checked = true;
break;
case "Nav Mesh":
mode = MapSelectionMode.NavMesh;
ToolbarSelectNavMeshButton.Checked = true;
break;
case "Path":
mode = MapSelectionMode.Path;
ToolbarSelectPathButton.Checked = true;
break;
case "Train Track":
mode = MapSelectionMode.TrainTrack;
ToolbarSelectTrainTrackButton.Checked = true;
break;
case "Lod Lights":
mode = MapSelectionMode.LodLights;
ToolbarSelectLodLightsButton.Checked = true;
break;
case "Mlo Instance":
mode = MapSelectionMode.MloInstance;
ToolbarSelectMloInstanceButton.Checked = true;
break;
case "Scenario":
mode = MapSelectionMode.Scenario;
ToolbarSelectScenarioButton.Checked = true;
break;
case "Audio":
mode = MapSelectionMode.Audio;
ToolbarSelectAudioButton.Checked = true;
break;
case "Occlusion":
mode = MapSelectionMode.Occlusion;
ToolbarSelectOcclusionButton.Checked = true;
break;
}
SelectionMode = mode;
SelectionModeStr = modestr;
Renderer.SelectionMode = mode;
if (SelectionModeComboBox.Text != modestr)
{
SelectionModeComboBox.Text = modestr;
}
if (InfoForm != null)
{
InfoForm.SetSelectionMode(modestr, MouseSelectEnabled);
}
}
private void SetSnapMode(WorldSnapMode mode)
{
foreach (var child in ToolbarSnapButton.DropDownItems)
{
var childi = child as ToolStripMenuItem;
if (childi != null)
{
childi.Checked = false;
}
}
ToolbarSnapButton.Checked = (mode != WorldSnapMode.None);
ToolStripMenuItem selItem = null;
switch (mode)
{
case WorldSnapMode.Ground:
selItem = ToolbarSnapToGroundButton;
break;
case WorldSnapMode.Grid:
selItem = ToolbarSnapToGridButton;
break;
case WorldSnapMode.Hybrid:
selItem = ToolbarSnapToGroundGridButton;
break;
}
if (selItem != null)
{
selItem.Checked = true;
ToolbarSnapButton.Image = selItem.Image;
ToolbarSnapButton.Text = selItem.Text;
ToolbarSnapButton.ToolTipText = selItem.ToolTipText;
}
if (mode != WorldSnapMode.None)
{
SnapModePrev = mode;
}
SnapMode = mode;
}
private void SetRotationSnapping(float degrees)
{
Widget.SnapAngleDegrees = degrees;
foreach (var child in ToolbarRotationSnappingButton.DropDownItems)
{
var childi = child as ToolStripMenuItem;
if (childi != null)
{
childi.Checked = false;
}
}
var selItem = ToolbarRotationSnappingCustomButton;
switch (degrees)
{
case 0.0f:
selItem = ToolbarRotationSnappingOffButton;
break;
case 1.0f:
selItem = ToolbarRotationSnapping1Button;
break;
case 2.0f:
selItem = ToolbarRotationSnapping2Button;
break;
case 5.0f:
selItem = ToolbarRotationSnapping5Button;
break;
case 10.0f:
selItem = ToolbarRotationSnapping10Button;
break;
case 45.0f:
selItem = ToolbarRotationSnapping45Button;
break;
case 90.0f:
selItem = ToolbarRotationSnapping90Button;
break;
}
if (selItem != null)
{
selItem.Checked = true;
}
var cval = (float)SnapAngleUpDown.Value;
if (cval != degrees)
{
SnapAngleUpDown.Value = (decimal)degrees;
}
}
private void SetCameraMode(string modestr)
{
foreach (var child in ToolbarCameraModeButton.DropDownItems)
{
var childi = child as ToolStripMenuItem;
if (childi != null)
{
childi.Checked = false;
}
}
Renderer.SetCameraMode(modestr);
switch (modestr)
{
case "Perspective":
MapViewEnabled = false;
ToolbarCameraModeButton.Image = ToolbarCameraPerspectiveButton.Image;
ToolbarCameraPerspectiveButton.Checked = true;
break;
case "Orthographic":
MapViewEnabled = false;
ToolbarCameraModeButton.Image = ToolbarCameraOrthographicButton.Image;
ToolbarCameraOrthographicButton.Checked = true;
break;
case "2D Map":
MapViewEnabled = true;
ToolbarCameraModeButton.Image = ToolbarCameraMapViewButton.Image;
ToolbarCameraMapViewButton.Checked = true;
break;
}
FieldOfViewTrackBar.Enabled = !MapViewEnabled;
MapViewDetailTrackBar.Enabled = MapViewEnabled;
if (CameraModeComboBox.Text != modestr)
{
CameraModeComboBox.Text = modestr;
}
}
private void ToggleCameraMode()
{
SetCameraMode(MapViewEnabled ? "Perspective" : "2D Map");
}
private void ToggleToolbar()
{
ToolbarPanel.Visible = !ToolbarPanel.Visible;
ShowToolbarCheckBox.Checked = ToolbarPanel.Visible;
}
public void ShowSubtitle(string text, float duration)
{
if (InvokeRequired)
{
try
{
BeginInvoke(new Action(() => { ShowSubtitle(text, duration); }));
}
catch { }
return;
}
SubtitleLabel.Text = text;
SubtitleLabel.Visible = true;
SubtitleTimer.Interval = (int)(duration * 1000.0f);
SubtitleTimer.Enabled = true;
}
private void SetTimeOfDay(int minute)
{
float hour = minute / 60.0f;
UpdateTimeOfDayLabel();
lock (Renderer.RenderSyncRoot)
{
Renderer.SetTimeOfDay(hour);
}
}
private void TryCreateNodeLink()//TODO: move this to project window
{
if (SelectionMode != MapSelectionMode.Path)
{
return;
}
var selection = SelectedItem.MultipleSelectionItems;
if (selection?.Length != 2)
{
MessageBox.Show("Please select 2 nodes to perform this action",
"Join Failed.",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var n1 = selection[0].PathNode;
var n2 = selection[1].PathNode;
if (n1 != null && n2 != null)
{
var link = n1.AddLink(n2);
if (link == null)
{
MessageBox.Show("Failed to join nodes. The nodes are likely too far away!", "Join Failed.", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var copy = n1.Links.FirstOrDefault();
link.SetForwardLanesBidirectionally(copy?.LaneCountBackward ?? 1);
link.SetBackwardLanesBidirectionally(copy?.LaneCountForward ?? 1);
UpdatePathYndGraphics(n1.Ynd, false);
UpdatePathYndGraphics(n2.Ynd, false);
}
}
private void TryCreateNodeShortcut()//TODO: move this to project window
{
if (SelectionMode != MapSelectionMode.Path)
{
return;
}
var selection = SelectedItem.MultipleSelectionItems;
if (selection?.Length != 2)
{
MessageBox.Show("Please select 2 nodes to perform this action",
"Join Failed.",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var n1 = selection[0].PathNode;
var n2 = selection[1].PathNode;
if (n1 != null && n2 != null)
{
var link = n1.AddLink(n2);
if (link == null)
{
MessageBox.Show("Failed to join nodes. The nodes are likely too far away!", "Join Failed.", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
link.SetForwardLanesBidirectionally(1);
link.Shortcut = true;
if (n2.TryGetLinkForNode(n1, out var backLink))
{
backLink.Shortcut = true;
}
UpdatePathYndGraphics(n1.Ynd, false);
UpdatePathYndGraphics(n2.Ynd, false);
}
}
private void StatsUpdateTimer_Tick(object sender, EventArgs e)
{
StatsLabel.Text = Renderer.GetStatusText();
if (Renderer.timerunning)
{
float fv = Renderer.timeofday * 60.0f;
TimeOfDayTrackBar.Value = (int)fv;
UpdateTimeOfDayLabel();
}
CameraPositionTextBox.Text = FloatUtil.GetVector3StringFormat(camera.Position, "0.##");
}
private void WorldForm_Load(object sender, EventArgs e)
{
Init();
}
private void WorldForm_FormClosing(object sender, FormClosingEventArgs e)
{
}
private void WorldForm_FormClosed(object sender, FormClosedEventArgs e)
{
SaveSettings();
}
private void WorldForm_MouseDown(object sender, MouseEventArgs e)
{
switch (e.Button)
{
case MouseButtons.Left: MouseLButtonDown = true; break;
case MouseButtons.Right: MouseRButtonDown = true; break;
}
if (!ToolsPanelShowButton.Focused)
{
ToolsPanelShowButton.Focus(); //make sure no textboxes etc are focused!
}
MouseDownPoint = e.Location;
MouseLastPoint = MouseDownPoint;
Input.CtrlPressed = (ModifierKeys & Keys.Control) > 0;
Input.ShiftPressed = (ModifierKeys & Keys.Shift) > 0;
if (ControlMode == WorldControlMode.Free && !ControlBrushEnabled)
{
if (MouseLButtonDown)
{
if (MousedMarker != null)
{
if (MousedMarker.IsMovable)
{
GrabbedMarker = MousedMarker;
}
else
{
SelectedMarker = MousedMarker;
ShowMarkerSelectionInfo(SelectedMarker);
}
if (GrabbedWidget != null)
{
GrabbedWidget.IsDragging = false;
GrabbedWidget = null;
}
}
else
{
if (ShowWidget && Widget.IsUnderMouse && !Input.kbmoving)
{
GrabbedWidget = Widget;
GrabbedWidget.IsDragging = true;
if (Input.ShiftPressed)
{
var ms = CurrentMapSelection.MultipleSelectionItems;
if (ms?.Length > 0 && ms[0].PathNode != null)
{
MessageBox.Show("You cannot clone multiple path nodes at once", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
GrabbedWidget.IsDragging = false;
GrabbedWidget = null;
} else
{
CloneItem();
}
}
MarkUndoStart(GrabbedWidget);
}
else
{
if (GrabbedWidget != null)
{
GrabbedWidget.IsDragging = false;
GrabbedWidget = null;
}
if (Input.CtrlPressed)
{
SpawnTestEntity();
}
}
GrabbedMarker = null;
}
}
if (MouseRButtonDown)
{
SelectMousedItem();
}
}
else
{
lock (MouseControlSyncRoot)
{
MouseControlButtons |= e.Button;
}
}
MouseX = e.X; //to stop jumps happening on mousedown, sometimes the last MouseMove event was somewhere else... (eg after clicked a menu)
MouseY = e.Y;
}
private void WorldForm_MouseUp(object sender, MouseEventArgs e)
{
switch (e.Button)
{
case MouseButtons.Left: MouseLButtonDown = false; break;
case MouseButtons.Right: MouseRButtonDown = false; break;
}
Input.CtrlPressed = (ModifierKeys & Keys.Control) > 0;
Input.ShiftPressed = (ModifierKeys & Keys.Shift) > 0;
lock (MouseControlSyncRoot)
{
MouseControlButtons &= ~e.Button;
}
if (e.Button == MouseButtons.Left)
{
GrabbedMarker = null;
if (GrabbedWidget != null)
{
MarkUndoEnd(GrabbedWidget);
GrabbedWidget.IsDragging = false;
GrabbedWidget.Position = SelectedItem.WidgetPosition;//in case of any snapping, make sure widget is in correct position at the end
GrabbedWidget = null;
}
if ((e.Location == MouseDownPoint) && (MousedMarker == null))
{
//was clicked. but not on a marker... deselect and hide the panel
SelectedMarker = null;
HideMarkerSelectionInfo();
}
ControlBrushTimer = 0;
}
}
private void WorldForm_MouseMove(object sender, MouseEventArgs e)
{
int dx = e.X - MouseX;
int dy = e.Y - MouseY;
Input.CtrlPressed = (ModifierKeys & Keys.Control) > 0;
Input.ShiftPressed = (ModifierKeys & Keys.Shift) > 0;
if (MouseInvert)
{
dy = -dy;
}
if (ControlMode == WorldControlMode.Free && !ControlBrushEnabled)
{
if (MouseLButtonDown)
{
RotateCam(dx, dy);
}
if (MouseRButtonDown)
{
if (Renderer.controllightdir)
{
Renderer.lightdirx += (dx * camera.Sensitivity);
Renderer.lightdiry += (dy * camera.Sensitivity);
}
else if (Renderer.controltimeofday)
{
float tod = Renderer.timeofday;
tod += (dx - dy) / 30.0f;
while (tod >= 24.0f) tod -= 24.0f;
while (tod < 0.0f) tod += 24.0f;
timecycle.SetTime(tod);
Renderer.timeofday = tod;
float fv = tod * 60.0f;
TimeOfDayTrackBar.Value = (int)fv;
UpdateTimeOfDayLabel();
}
}
UpdateMousePosition(e);
}
else if (ControlBrushEnabled)
{
if (MouseRButtonDown)
{
RotateCam(dx, dy);
}
UpdateMousePosition(e);
ControlBrushTimer++;
if (ControlBrushTimer > (Input.ShiftPressed ? 5 : 10))
{
//lock (Renderer.RenderSyncRoot)
{
if (ProjectForm != null && MouseLButtonDown)
{
ProjectForm.PaintGrass(MouseRayCollision, Input);
}
ControlBrushTimer = 0;
}
}
}
else
{
lock (MouseControlSyncRoot)
{
MouseControlX += dx;
MouseControlY += dy;
//MouseControlButtons = e.Button;
}
var newpos = PointToScreen(MouseLastPoint);
if (Cursor.Position != newpos)
{
Cursor.Position = newpos;
return;
}
}
MousedMarker = FindMousedMarker();
if (Cursor != Cursors.WaitCursor)
{
if (MousedMarker != null)
{
if (MousedMarker.IsMovable)
{
Cursor = Cursors.SizeAll;
}
else
{
Cursor = Cursors.Hand;
}
}
else
{
Cursor = Cursors.Default;
}
}
}
private void UpdateMousePosition(MouseEventArgs e)
{
MouseX = e.X;
MouseY = e.Y;
MouseLastPoint = e.Location;
}
private void RotateCam(int dx, int dy)
{
if (GrabbedMarker == null)
{
if (GrabbedWidget == null)
{
if (MapViewEnabled == false)
{
camera.MouseRotate(dx, dy);
}
else
{
//need to move the camera entity XY with mouse in mapview mode...
MapViewDragX += dx;
MapViewDragY += dy;
}
}
else
{
//grabbed widget will move itself in Update() when IsDragging==true
}
}
else
{
//move the grabbed marker...
//float uptx = (CurrentMap != null) ? CurrentMap.UnitsPerTexelX : 1.0f;
//float upty = (CurrentMap != null) ? CurrentMap.UnitsPerTexelY : 1.0f;
//Vector3 wpos = GrabbedMarker.WorldPos;
//wpos.X += dx * uptx;
//wpos.Y += dy * upty;
//GrabbedMarker.WorldPos = wpos;
//UpdateMarkerTexturePos(GrabbedMarker);
//if (GrabbedMarker == LocatorMarker)
//{
// LocateTextBox.Text = LocatorMarker.ToString();
// WorldCoordTextBox.Text = LocatorMarker.Get2DWorldPosString();
// TextureCoordTextBox.Text = LocatorMarker.Get2DTexturePosString();
//}
}
}
private void WorldForm_MouseWheel(object sender, MouseEventArgs e)
{
if (e.Delta != 0)
{
if (ControlMode == WorldControlMode.Free || ControlBrushEnabled)
{
camera.MouseZoom(e.Delta);
}
else
{
lock (MouseControlSyncRoot)
{
MouseControlWheel += e.Delta;
}
}
}
}
private void WorldForm_KeyDown(object sender, KeyEventArgs e)
{
if (ActiveControl is TextBox)
{
var tb = ActiveControl as TextBox;
if (!tb.ReadOnly) return; //don't move the camera when typing!
}
if (ActiveControl is ComboBox)
{
var cb = ActiveControl as ComboBox;
if (cb.DropDownStyle != ComboBoxStyle.DropDownList) return; //nontypable combobox
}
bool enablemove = (!iseditmode) || (MouseLButtonDown && (GrabbedMarker == null) && (GrabbedWidget == null));
Input.KeyDown(e, enablemove);
var k = e.KeyCode;
var kb = Input.keyBindings;
bool ctrl = Input.CtrlPressed;
bool shift = Input.ShiftPressed;
if (!ctrl)
{
if (k == kb.MoveSlowerZoomIn)
{
camera.MouseZoom(1);
}
if (k == kb.MoveFasterZoomOut)
{
camera.MouseZoom(-1);
}
}
if (!Input.kbmoving && !Widget.IsDragging) //don't trigger further actions if camera moving or widget dragging
{
if (!ctrl)
{
//switch widget modes and spaces.
if ((k == kb.ExitEditMode))
{
if (Widget.Mode == WidgetMode.Default) ToggleWidgetSpace();
else SetWidgetMode("Default");
}
if ((k == kb.EditPosition))// && !enablemove)
{
if (Widget.Mode == WidgetMode.Position) ToggleWidgetSpace();
else SetWidgetMode("Position");
}
if ((k == kb.EditRotation))// && !enablemove)
{
if (Widget.Mode == WidgetMode.Rotation) ToggleWidgetSpace();
else SetWidgetMode("Rotation");
}
if ((k == kb.EditScale))// && !enablemove)
{
if (Widget.Mode == WidgetMode.Scale) ToggleWidgetSpace();
else SetWidgetMode("Scale");
}
if (k == kb.ToggleMouseSelect)
{
SetMouseSelect(!MouseSelectEnabled);
}
if (k == kb.ToggleToolbar)
{
ToggleToolbar();
}
if (k == kb.FirstPerson)
{
SetControlMode((ControlMode == WorldControlMode.Free) ? WorldControlMode.Ped : WorldControlMode.Free);
}
if (k == Keys.Delete)
{
DeleteItem();
}
if (SelectionMode == MapSelectionMode.Path)
{
if (k == Keys.J)
{
TryCreateNodeLink();
}
if (k == Keys.K)
{
TryCreateNodeShortcut();
}
}
}
else
{
switch (k)
{
case Keys.N:
New();
break;
case Keys.O:
Open();
break;
case Keys.S:
if (shift) SaveAll();
else Save();
break;
case Keys.Z:
Undo();
break;
case Keys.Y:
Redo();
break;
case Keys.C:
CopyItem();
break;
case Keys.V:
PasteItem();
break;
case Keys.U:
ToolsPanelShowButton.Visible = !ToolsPanelShowButton.Visible;
break;
}
}
}
if (k == Keys.Escape) //temporary? panic get cursor back when in first person mode
{
if (ControlMode != WorldControlMode.Free) SetControlMode(WorldControlMode.Free);
}
if (ControlMode != WorldControlMode.Free || ControlBrushEnabled)
{
e.Handled = true;
}
}
private void WorldForm_KeyUp(object sender, KeyEventArgs e)
{
Input.KeyUp(e);
if (ActiveControl is TextBox)
{
var tb = ActiveControl as TextBox;
if (!tb.ReadOnly) return; //don't move the camera when typing!
}
if (ActiveControl is ComboBox)
{
var cb = ActiveControl as ComboBox;
if (cb.DropDownStyle != ComboBoxStyle.DropDownList) return; //non-typable combobox
}
if (ControlMode != WorldControlMode.Free)
{
e.Handled = true;
}
}
private void WorldForm_Deactivate(object sender, EventArgs e)
{
//try not to lock keyboard movement if the form loses focus.
Input.KeyboardStop();
}
private void ViewModeComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
bool prevmodel = !(rendermaps || renderworld);
string mode = (string)ViewModeComboBox.SelectedItem;
switch (mode)
{
case "World view":
rendermaps = false;
renderworld = true;
ViewTabControl.SelectedTab = ViewWorldTabPage;
break;
case "Ymap view":
rendermaps = true;
renderworld = false;
ViewTabControl.SelectedTab = ViewYmapsTabPage;
break;
case "Model view":
rendermaps = false;
renderworld = false;
ViewTabControl.SelectedTab = ViewModelTabPage;
if (SelectionNameTextBox.Text != "" && SelectionNameTextBox.Text != "Nothing selected")
{
modelname = SelectionNameTextBox.Text;
}
break;
}
if ((camera == null) || (camera.FollowEntity == null)) return;
if (rendermaps || renderworld)
{
if (prevmodel) //only change location if the last mode was model mode
{
camera.FollowEntity.Position = prevworldpos;
}
}
else
{
prevworldpos = camera.FollowEntity.Position;
camera.FollowEntity.Position = new Vector3(0.0f, 0.0f, 0.0f);
}
}
private void ModelComboBox_TextUpdate(object sender, EventArgs e)
{
modelname = ModelComboBox.Text;
}
private void ModelComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
modelname = ModelComboBox.Text;
}
private void YmapsTextBox_TextChanged(object sender, EventArgs e)
{
ymaplist = YmapsTextBox.Text.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
}
private void ToolsPanelHideButton_Click(object sender, EventArgs e)
{
ToolsPanel.Visible = false;
ToolsPanelShowButton.Focus();
}
private void ToolsPanelShowButton_Click(object sender, EventArgs e)
{
ToolsPanel.Visible = true;
ToolsPanelHideButton.Focus();
}
private void WireframeCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.shaders.wireframe = WireframeCheckBox.Checked;
}
private void GrassCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.rendergrass = GrassCheckBox.Checked;
}
private void CarGeneratorsCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.rendercars = CarGeneratorsCheckBox.Checked;
}
private void TimedEntitiesCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.rendertimedents = TimedEntitiesCheckBox.Checked;
}
private void TimedEntitiesAlwaysOnCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.rendertimedentsalways = TimedEntitiesAlwaysOnCheckBox.Checked;
}
private void InteriorsCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.renderinteriors = InteriorsCheckBox.Checked;
}
private void WaterQuadsCheckBox_CheckedChanged(object sender, EventArgs e)
{
renderwaterquads = WaterQuadsCheckBox.Checked;
}
private void ProxiesCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.renderproxies = ProxiesCheckBox.Checked;
}
private void HDTexturesCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.renderhdtextures = HDTexturesCheckBox.Checked;
}
private void NearClipUpDown_ValueChanged(object sender, EventArgs e)
{
camera.ZNear = (float)NearClipUpDown.Value;
camera.UpdateProj = true;
}
private void FarClipUpDown_ValueChanged(object sender, EventArgs e)
{
camera.ZFar = (float)FarClipUpDown.Value;
camera.UpdateProj = true;
}
private void PathsCheckBox_CheckedChanged(object sender, EventArgs e)
{
renderpaths = PathsCheckBox.Checked;
}
private void PathBoundsCheckBox_CheckedChanged(object sender, EventArgs e)
{
renderpathbounds = PathBoundsCheckBox.Checked;
}
private void TrainPathsCheckBox_CheckedChanged(object sender, EventArgs e)
{
rendertraintracks = TrainPathsCheckBox.Checked;
}
private void NavMeshesCheckBox_CheckedChanged(object sender, EventArgs e)
{
rendernavmeshes = NavMeshesCheckBox.Checked;
}
private void PathsDepthClipCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.shaders.PathsDepthClip = PathsDepthClipCheckBox.Checked;
}
private void ErrorConsoleCheckBox_CheckedChanged(object sender, EventArgs e)
{
ConsolePanel.Visible = ErrorConsoleCheckBox.Checked;
}
private void DynamicLODCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.usedynamiclod = DynamicLODCheckBox.Checked;
ShowYmapChildrenCheckBox.Enabled = !Renderer.usedynamiclod;
}
private void DetailTrackBar_Scroll(object sender, EventArgs e)
{
Renderer.lodthreshold = 50.0f / (0.1f + (float)DetailTrackBar.Value);
}
private void WaitForChildrenCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.waitforchildrentoload = WaitForChildrenCheckBox.Checked;
}
private void ReloadShadersButton_Click(object sender, EventArgs e)
{
if (Renderer.Device == null) return; //can't do this with no device
Cursor = Cursors.WaitCursor;
pauserendering = true;
lock (Renderer.RenderSyncRoot)
{
try
{
Renderer.ReloadShaders();
}
catch (Exception ex)
{
MessageBox.Show("Error loading shaders!\n" + ex.ToString());
return;
}
}
pauserendering = false;
Cursor = Cursors.Default;
}
private void MarkerStyleComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
MapIcon icon = MarkerStyleComboBox.SelectedItem as MapIcon;
if (icon != MarkerIcon)
{
MarkerIcon = icon;
foreach (MapMarker m in Markers)
{
m.Icon = icon;
}
}
}
private void LocatorStyleComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
MapIcon icon = LocatorStyleComboBox.SelectedItem as MapIcon;
if (icon != LocatorIcon)
{
LocatorIcon = icon;
LocatorMarker.Icon = icon;
}
}
private void ShowLocatorCheckBox_CheckedChanged(object sender, EventArgs e)
{
RenderLocator = ShowLocatorCheckBox.Checked;
}
private void LocateTextBox_TextChanged(object sender, EventArgs e)
{
if (GrabbedMarker == LocatorMarker) return; //don't try to update the marker if it's being dragged
if (LocatorMarker == null) return; //this shouldn't happen, but anyway
LocatorMarker.Parse(LocateTextBox.Text);
//UpdateMarkerTexturePos(LocatorMarker);
}
private void GoToButton_Click(object sender, EventArgs e)
{
GoToMarker(LocatorMarker);
}
private void AddMarkersButton_Click(object sender, EventArgs e)
{
string[] lines = MultiFindTextBox.Text.Split('\n');
foreach (string line in lines)
{
AddMarker(line);
}
}
private void ClearMarkersButton_Click(object sender, EventArgs e)
{
MultiFindTextBox.Text = string.Empty;
Markers.Clear();
}
private void ResetMarkersButton_Click(object sender, EventArgs e)
{
Markers.Clear();
AddDefaultMarkers();
}
private void AddCurrentPositonMarkerButton_Click(object sender, EventArgs e)
{
AddMarker(camera.Position, "Marker", true);
}
private void AddSelectionMarkerButton_Click(object sender, EventArgs e)
{
if (SelectedItem.EntityDef == null)
{ return; }
Vector3 pos = SelectedItem.EntityDef.Position;
string name = SelectedItem.EntityDef.CEntityDef.archetypeName.ToString();
var marker = AddMarker(pos, name, true);
SelectedMarker = marker;
ShowMarkerSelectionInfo(SelectedMarker);
}
private void MarkerDepthClipCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.markerdepthclip = MarkerDepthClipCheckBox.Checked;
}
private void ShadowsCheckBox_CheckedChanged(object sender, EventArgs e)
{
lock (Renderer.RenderSyncRoot)
{
Renderer.shaders.shadows = ShadowsCheckBox.Checked;
}
}
private void SkydomeCheckbox_CheckedChanged(object sender, EventArgs e)
{
Renderer.renderskydome = SkydomeCheckBox.Checked;
}
private void BoundsStyleComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
var val = BoundsStyleComboBox.SelectedItem;
var strval = val as string;
SetBoundsMode(strval);
}
private void BoundsDepthClipCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.renderboundsclip = BoundsDepthClipCheckBox.Checked;
}
private void BoundsRangeTrackBar_Scroll(object sender, EventArgs e)
{
float fv = BoundsRangeTrackBar.Value;
Renderer.renderboundsmaxdist = fv * fv;
}
private void MouseSelectCheckBox_CheckedChanged(object sender, EventArgs e)
{
SetMouseSelect(MouseSelectCheckBox.Checked);
}
private void SelectionBoundsCheckBox_CheckedChanged(object sender, EventArgs e)
{
ShowSelectionBounds = SelectionBoundsCheckBox.Checked;
}
private void PopZonesCheckBox_CheckedChanged(object sender, EventArgs e)
{
renderpopzones = PopZonesCheckBox.Checked;
}
private void SkeletonsCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.renderskeletons = SkeletonsCheckBox.Checked;
}
private void AudioOuterBoundsCheckBox_CheckedChanged(object sender, EventArgs e)
{
renderaudioouterbounds = AudioOuterBoundsCheckBox.Checked;
}
private void ToolsPanelExpandButton_Click(object sender, EventArgs e)
{
toolspanelexpanded = !toolspanelexpanded;
int oldwidth = ToolsPanel.Width;
if (toolspanelexpanded)
{
ToolsPanelExpandButton.Text = ">>";
}
else
{
ToolsPanelExpandButton.Text = "<<";
}
ToolsPanel.Width = toolspanellastwidth; //or extended width
ToolsPanel.Left -= (toolspanellastwidth - oldwidth);
toolspanellastwidth = oldwidth;
}
private void ToolsDragPanel_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
toolsPanelResizing = true;
toolsPanelResizeStartX = e.X + ToolsPanel.Left;
toolsPanelResizeStartLeft = ToolsPanel.Left;
toolsPanelResizeStartRight = ToolsPanel.Right;
}
}
private void ToolsDragPanel_MouseUp(object sender, MouseEventArgs e)
{
toolsPanelResizing = false;
}
private void ToolsDragPanel_MouseMove(object sender, MouseEventArgs e)
{
if (toolsPanelResizing)
{
int rx = e.X + ToolsPanel.Left;
int dx = rx - toolsPanelResizeStartX;
ToolsPanel.Left = toolsPanelResizeStartLeft + dx;
ToolsPanel.Width = toolsPanelResizeStartRight - toolsPanelResizeStartLeft - dx;
}
}
private void FullScreenCheckBox_CheckedChanged(object sender, EventArgs e)
{
SetFullscreen(FullScreenCheckBox.Checked);
}
private void ControlSettingsButton_Click(object sender, EventArgs e)
{
ShowSettingsForm("Controls");
}
private void AdvancedSettingsButton_Click(object sender, EventArgs e)
{
ShowSettingsForm("Advanced");
}
private void ReloadSettingsButton_Click(object sender, EventArgs e)
{
LoadSettings();
}
private void SaveSettingsButton_Click(object sender, EventArgs e)
{
SaveSettings();
}
private void QuitButton_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Really quit?", "", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
Close();
}
}
private void AboutButton_Click(object sender, EventArgs e)
{
AboutForm f = new AboutForm();
f.Show(this);
}
private void ToolsButton_Click(object sender, EventArgs e)
{
ToolsMenu.Show(ToolsButton, 0, ToolsButton.Height);
}
private void ToolsMenuRPFBrowser_Click(object sender, EventArgs e)
{
BrowseForm f = new BrowseForm();
f.Show(this);
}
private void ToolsMenuRPFExplorer_Click(object sender, EventArgs e)
{
ExploreForm f = new ExploreForm();
f.Show(this);
}
private void ToolsMenuSelectionInfo_Click(object sender, EventArgs e)
{
ShowInfoForm();
}
private void ToolsMenuProjectWindow_Click(object sender, EventArgs e)
{
ShowProjectForm();
}
private void ToolsMenuCutsceneViewer_Click(object sender, EventArgs e)
{
ShowCutsceneForm();
}
private void ToolsMenuAudioExplorer_Click(object sender, EventArgs e)
{
AudioExplorerForm f = new AudioExplorerForm(gameFileCache);
f.Show(this);
}
private void ToolsMenuWorldSearch_Click(object sender, EventArgs e)
{
ShowSearchForm();
}
private void ToolsMenuBinarySearch_Click(object sender, EventArgs e)
{
BinarySearchForm f = new BinarySearchForm(gameFileCache);
f.Show(this);
}
private void ToolsMenuJenkGen_Click(object sender, EventArgs e)
{
JenkGenForm f = new JenkGenForm();
f.Show(this);
}
private void ToolsMenuJenkInd_Click(object sender, EventArgs e)
{
JenkIndForm f = new JenkIndForm(gameFileCache);
f.Show(this);
}
private void ToolsMenuExtractScripts_Click(object sender, EventArgs e)
{
ExtractScriptsForm f = new ExtractScriptsForm();
f.Show(this);
}
private void ToolsMenuExtractTextures_Click(object sender, EventArgs e)
{
ExtractTexForm f = new ExtractTexForm();
f.Show(this);
}
private void ToolsMenuExtractRawFiles_Click(object sender, EventArgs e)
{
ExtractRawForm f = new ExtractRawForm();
f.Show(this);
}
private void ToolsMenuExtractShaders_Click(object sender, EventArgs e)
{
ExtractShadersForm f = new ExtractShadersForm();
f.Show(this);
}
private void ToolsMenuOptions_Click(object sender, EventArgs e)
{
ShowSettingsForm();
}
private void StatusBarCheckBox_CheckedChanged(object sender, EventArgs e)
{
StatusStrip.Visible = StatusBarCheckBox.Checked;
}
private void RenderModeComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
TextureSamplerComboBox.Enabled = false;
TextureCoordsComboBox.Enabled = false;
switch (RenderModeComboBox.Text)
{
default:
case "Default":
Renderer.shaders.RenderMode = WorldRenderMode.Default;
break;
case "Single texture":
Renderer.shaders.RenderMode = WorldRenderMode.SingleTexture;
TextureSamplerComboBox.Enabled = true;
TextureCoordsComboBox.Enabled = true;
break;
case "Vertex normals":
Renderer.shaders.RenderMode = WorldRenderMode.VertexNormals;
break;
case "Vertex tangents":
Renderer.shaders.RenderMode = WorldRenderMode.VertexTangents;
break;
case "Vertex colour 1":
Renderer.shaders.RenderMode = WorldRenderMode.VertexColour;
Renderer.shaders.RenderVertexColourIndex = 1;
break;
case "Vertex colour 2":
Renderer.shaders.RenderMode = WorldRenderMode.VertexColour;
Renderer.shaders.RenderVertexColourIndex = 2;
break;
case "Vertex colour 3":
Renderer.shaders.RenderMode = WorldRenderMode.VertexColour;
Renderer.shaders.RenderVertexColourIndex = 3;
break;
case "Texture coord 1":
Renderer.shaders.RenderMode = WorldRenderMode.TextureCoord;
Renderer.shaders.RenderTextureCoordIndex = 1;
break;
case "Texture coord 2":
Renderer.shaders.RenderMode = WorldRenderMode.TextureCoord;
Renderer.shaders.RenderTextureCoordIndex = 2;
break;
case "Texture coord 3":
Renderer.shaders.RenderMode = WorldRenderMode.TextureCoord;
Renderer.shaders.RenderTextureCoordIndex = 3;
break;
}
}
private void TextureSamplerComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (TextureSamplerComboBox.SelectedItem is ShaderParamNames)
{
Renderer.shaders.RenderTextureSampler = (ShaderParamNames)TextureSamplerComboBox.SelectedItem;
}
}
private void TextureCoordsComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
switch (TextureCoordsComboBox.Text)
{
default:
case "Texture coord 1":
Renderer.shaders.RenderTextureSamplerCoord = 1;
break;
case "Texture coord 2":
Renderer.shaders.RenderTextureSamplerCoord = 2;
break;
case "Texture coord 3":
Renderer.shaders.RenderTextureSamplerCoord = 3;
break;
}
}
private void CollisionMeshesCheckBox_CheckedChanged(object sender, EventArgs e)
{
rendercollisionmeshes = CollisionMeshesCheckBox.Checked;
Renderer.rendercollisionmeshes = rendercollisionmeshes;
}
private void CollisionMeshRangeTrackBar_Scroll(object sender, EventArgs e)
{
collisionmeshrange = CollisionMeshRangeTrackBar.Value;
}
private void CollisionMeshLayer0CheckBox_CheckedChanged(object sender, EventArgs e)
{
collisionmeshlayers[0] = CollisionMeshLayer0CheckBox.Checked;
}
private void CollisionMeshLayer1CheckBox_CheckedChanged(object sender, EventArgs e)
{
collisionmeshlayers[1] = CollisionMeshLayer1CheckBox.Checked;
}
private void CollisionMeshLayer2CheckBox_CheckedChanged(object sender, EventArgs e)
{
collisionmeshlayers[2] = CollisionMeshLayer2CheckBox.Checked;
}
private void CollisionMeshLayerDrawableCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.rendercollisionmeshlayerdrawable = CollisionMeshLayerDrawableCheckBox.Checked;
}
private void ControlLightDirectionCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.controllightdir = ControlLightDirectionCheckBox.Checked;
if (Renderer.controllightdir)
{
ControlTimeOfDayCheckBox.Checked = false;
}
}
private void ControlTimeOfDayCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.controltimeofday = ControlTimeOfDayCheckBox.Checked;
if (Renderer.controltimeofday)
{
ControlLightDirectionCheckBox.Checked = false;
}
}
private void ShowYmapChildrenCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.renderchildents = ShowYmapChildrenCheckBox.Checked;
}
private void DeferredShadingCheckBox_CheckedChanged(object sender, EventArgs e)
{
lock (Renderer.RenderSyncRoot)
{
Renderer.shaders.deferred = DeferredShadingCheckBox.Checked;
}
}
private void HDRRenderingCheckBox_CheckedChanged(object sender, EventArgs e)
{
lock (Renderer.RenderSyncRoot)
{
Renderer.shaders.hdr = HDRRenderingCheckBox.Checked;
}
}
private void AnisotropicFilteringCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.shaders.AnisotropicFiltering = AnisotropicFilteringCheckBox.Checked;
}
private void WorldMaxLodComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
switch (WorldMaxLodComboBox.Text)
{
default:
case "ORPHANHD":
Renderer.renderworldMaxLOD = rage__eLodType.LODTYPES_DEPTH_ORPHANHD;
break;
case "HD":
Renderer.renderworldMaxLOD = rage__eLodType.LODTYPES_DEPTH_HD;
break;
case "LOD":
Renderer.renderworldMaxLOD = rage__eLodType.LODTYPES_DEPTH_LOD;
break;
case "SLOD1":
Renderer.renderworldMaxLOD = rage__eLodType.LODTYPES_DEPTH_SLOD1;
break;
case "SLOD2":
Renderer.renderworldMaxLOD = rage__eLodType.LODTYPES_DEPTH_SLOD2;
break;
case "SLOD3":
Renderer.renderworldMaxLOD = rage__eLodType.LODTYPES_DEPTH_SLOD3;
break;
case "SLOD4":
Renderer.renderworldMaxLOD = rage__eLodType.LODTYPES_DEPTH_SLOD4;
break;
}
}
private void WorldLodDistTrackBar_Scroll(object sender, EventArgs e)
{
float loddist = ((float)WorldLodDistTrackBar.Value) * 0.1f;
Renderer.renderworldLodDistMult = loddist;
WorldLodDistLabel.Text = loddist.ToString("0.0");
}
private void WorldDetailDistTrackBar_Scroll(object sender, EventArgs e)
{
float detdist = ((float)WorldDetailDistTrackBar.Value) * 0.1f;
Renderer.renderworldDetailDistMult = detdist;
WorldDetailDistLabel.Text = detdist.ToString("0.0");
}
private void WorldScriptedYmapsCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.ShowScriptedYmaps = WorldScriptedYmapsCheckBox.Checked;
}
private void WorldYmapTimeFilterCheckBox_CheckedChanged(object sender, EventArgs e)
{
worldymaptimefilter = WorldYmapTimeFilterCheckBox.Checked;
}
private void WorldYmapWeatherFilterCheckBox_CheckedChanged(object sender, EventArgs e)
{
worldymapweatherfilter = WorldYmapWeatherFilterCheckBox.Checked;
}
private void EnableModsCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (!initialised) return;
if (ProjectForm != null)
{
MessageBox.Show("Please close the Project Window before enabling or disabling mods.");
return;
}
SetModsEnabled(EnableModsCheckBox.Checked);
}
private void EnableDlcCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (!initialised) return;
if (ProjectForm != null)
{
MessageBox.Show("Please close the Project Window before enabling or disabling DLC.");
return;
}
SetDlcLevel(DlcLevelComboBox.Text, EnableDlcCheckBox.Checked);
}
private void DlcLevelComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (!initialised) return;
if (ProjectForm != null)
{
MessageBox.Show("Please close the Project Window before changing the DLC level.");
return;
}
SetDlcLevel(DlcLevelComboBox.Text, EnableDlcCheckBox.Checked);
}
private void TimeOfDayTrackBar_Scroll(object sender, EventArgs e)
{
SetTimeOfDay(TimeOfDayTrackBar.Value);
}
private void WeatherComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
Renderer.SetWeatherType(WeatherComboBox.Text);
}
private void WeatherRegionComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
weather.Region = WeatherRegionComboBox.Text;
}
private void CloudsComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
//if (!Monitor.TryEnter(rendersyncroot, 50))
//{ return; } //couldn't get a lock...
Renderer.individualcloudfrag = CloudsComboBox.Text;
//Monitor.Exit(rendersyncroot);
}
private void HDLightsCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.renderlights = HDLightsCheckBox.Checked;
}
private void LODLightsCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.renderdistlodlights = LODLightsCheckBox.Checked;
Renderer.renderlodlights = LODLightsCheckBox.Checked;
}
private void NaturalAmbientLightCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.rendernaturalambientlight = NaturalAmbientLightCheckBox.Checked;
}
private void ArtificialAmbientLightCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.renderartificialambientlight = ArtificialAmbientLightCheckBox.Checked;
}
private void TimeStartStopButton_Click(object sender, EventArgs e)
{
Renderer.timerunning = !Renderer.timerunning;
TimeStartStopButton.Text = Renderer.timerunning ? "Stop" : "Start";
}
private void TimeSpeedTrackBar_Scroll(object sender, EventArgs e)
{
float tv = TimeSpeedTrackBar.Value * 0.01f;
//when tv=0, speed=0 min/sec
//when tv=0.5, speed=0.5 min/sec
//when tv=1, speed=128 min/sec
Renderer.timespeed = 128.0f * tv * tv * tv * tv * tv * tv * tv * tv;
TimeSpeedLabel.Text = Renderer.timespeed.ToString("0.###") + " min/sec";
}
private void CameraModeComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
SetCameraMode(CameraModeComboBox.Text);
}
private void MapViewDetailTrackBar_Scroll(object sender, EventArgs e)
{
float det = ((float)MapViewDetailTrackBar.Value) * 0.1f;
MapViewDetailLabel.Text = det.ToString("0.0#");
lock (Renderer.RenderSyncRoot)
{
Renderer.MapViewDetail = det;
}
}
private void FieldOfViewTrackBar_Scroll(object sender, EventArgs e)
{
float fov = FieldOfViewTrackBar.Value * 0.01f;
FieldOfViewLabel.Text = fov.ToString("0.0#");
lock (Renderer.RenderSyncRoot)
{
camera.FieldOfView = fov;
camera.UpdateProj = true;
}
}
private void CloudParamComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
CloudAnimSetting setting = CloudParamComboBox.SelectedItem as CloudAnimSetting;
if (setting != null)
{
float rng = setting.MaxValue - setting.MinValue;
float cval = (setting.CurrentValue - setting.MinValue) / rng;
int ival = (int)(cval * 200.0f);
ival = Math.Min(Math.Max(ival, 0), 200);
CloudParamTrackBar.Value = ival;
}
}
private void CloudParamTrackBar_Scroll(object sender, EventArgs e)
{
CloudAnimSetting setting = CloudParamComboBox.SelectedItem as CloudAnimSetting;
if (setting != null)
{
float rng = setting.MaxValue - setting.MinValue;
float fval = CloudParamTrackBar.Value / 200.0f;
float cval = (fval * rng) + setting.MinValue;
setting.CurrentValue = cval;
}
}
private void SelDrawableModelsTreeView_AfterCheck(object sender, TreeViewEventArgs e)
{
if (e.Node != null)
{
UpdateSelectionDrawFlags(e.Node);
if (InfoForm != null)
{
InfoForm.SyncSelDrawableModelsTreeNode(e.Node);
}
}
}
private void SelDrawableModelsTreeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Node != null)
{
e.Node.Checked = !e.Node.Checked;
//UpdateSelectionDrawFlags(e.Node);
}
}
private void SelDrawableModelsTreeView_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true; //stops annoying ding sound...
}
private void SelectionWidgetCheckBox_CheckedChanged(object sender, EventArgs e)
{
ShowWidget = SelectionWidgetCheckBox.Checked;
}
private void ShowToolbarCheckBox_CheckedChanged(object sender, EventArgs e)
{
ToolbarPanel.Visible = ShowToolbarCheckBox.Checked;
}
private void ToolbarNewButton_ButtonClick(object sender, EventArgs e)
{
New();
}
private void ToolbarNewProjectButton_Click(object sender, EventArgs e)
{
NewProject();
}
private void ToolbarNewYmapButton_Click(object sender, EventArgs e)
{
NewYmap();
}
private void ToolbarNewYtypButton_Click(object sender, EventArgs e)
{
NewYtyp();
}
private void ToolbarNewYbnButton_Click(object sender, EventArgs e)
{
NewYbn();
}
private void ToolbarNewYndButton_Click(object sender, EventArgs e)
{
NewYnd();
}
private void ToolbarNewTrainsButton_Click(object sender, EventArgs e)
{
NewTrainTrack();
}
private void ToolbarNewScenarioButton_Click(object sender, EventArgs e)
{
NewScenario();
}
private void ToolbarOpenButton_ButtonClick(object sender, EventArgs e)
{
Open();
}
private void ToolbarOpenProjectButton_Click(object sender, EventArgs e)
{
OpenProject();
}
private void ToolbarOpenFilesButton_Click(object sender, EventArgs e)
{
OpenFiles();
}
private void ToolbarOpenFolderButton_Click(object sender, EventArgs e)
{
OpenFolder();
}
private void ToolbarSaveButton_Click(object sender, EventArgs e)
{
Save();
}
private void ToolbarSaveAllButton_Click(object sender, EventArgs e)
{
SaveAll();
}
private void ToolbarSelectButton_ButtonClick(object sender, EventArgs e)
{
SetMouseSelect(!ToolbarSelectButton.Checked);
SetWidgetMode("Default");
}
private void ToolbarSelectEntityButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Entity");
SetMouseSelect(true);
}
private void ToolbarSelectEntityExtensionButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Entity Extension");
SetMouseSelect(true);
}
private void ToolbarSelectArchetypeExtensionButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Archetype Extension");
SetMouseSelect(true);
}
private void ToolbarSelectTimeCycleModifierButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Time Cycle Modifier");
SetMouseSelect(true);
}
private void ToolbarSelectCarGeneratorButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Car Generator");
SetMouseSelect(true);
}
private void ToolbarSelectGrassButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Grass");
SetMouseSelect(true);
}
private void ToolbarSelectWaterQuadButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Water Quad");
SetMouseSelect(true);
}
private void ToolbarSelectCalmingQuadButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Water Calming Quad");
SetMouseSelect(true);
}
private void ToolbarSelectWaveQuadButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Water Wave Quad");
SetMouseSelect(true);
}
private void ToolbarSelectCollisionButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Collision");
SetMouseSelect(true);
}
private void ToolbarSelectNavMeshButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Nav Mesh");
SetMouseSelect(true);
}
private void ToolbarSelectPathButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Path");
SetMouseSelect(true);
}
private void ToolbarSelectTrainTrackButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Train Track");
SetMouseSelect(true);
}
private void ToolbarSelectLodLightsButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Lod Lights");
SetMouseSelect(true);
}
private void ToolbarSelectMloInstanceButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Mlo Instance");
SetMouseSelect(true);
}
private void ToolbarSelectScenarioButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Scenario");
SetMouseSelect(true);
}
private void ToolbarSelectAudioButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Audio");
SetMouseSelect(true);
}
private void ToolbarSelectOcclusionButton_Click(object sender, EventArgs e)
{
SetSelectionMode("Occlusion");
SetMouseSelect(true);
}
private void ToolbarMoveButton_Click(object sender, EventArgs e)
{
SetWidgetMode(ToolbarMoveButton.Checked ? "Default" : "Position");
}
private void ToolbarRotateButton_Click(object sender, EventArgs e)
{
SetWidgetMode(ToolbarRotateButton.Checked ? "Default" : "Rotation");
}
private void ToolbarScaleButton_Click(object sender, EventArgs e)
{
SetWidgetMode(ToolbarScaleButton.Checked ? "Default" : "Scale");
}
private void ToolbarTransformSpaceButton_ButtonClick(object sender, EventArgs e)
{
SetWidgetSpace(Widget.ObjectSpace ? "World space" : "Object space");
}
private void ToolbarObjectSpaceButton_Click(object sender, EventArgs e)
{
SetWidgetSpace("Object space");
}
private void ToolbarWorldSpaceButton_Click(object sender, EventArgs e)
{
SetWidgetSpace("World space");
}
private void ToolbarSnapButton_ButtonClick(object sender, EventArgs e)
{
if (SnapMode == WorldSnapMode.None)
{
SetSnapMode(SnapModePrev);
}
else
{
SetSnapMode(WorldSnapMode.None);
}
}
private void ToolbarSnapToGroundButton_Click(object sender, EventArgs e)
{
SetSnapMode(WorldSnapMode.Ground);
}
private void ToolbarSnapToGridButton_Click(object sender, EventArgs e)
{
SetSnapMode(WorldSnapMode.Grid);
}
private void ToolbarSnapToGroundGridButton_Click(object sender, EventArgs e)
{
SetSnapMode(WorldSnapMode.Hybrid);
}
private void ToolbarRotationSnappingOffButton_Click(object sender, EventArgs e)
{
SetRotationSnapping(0);
}
private void ToolbarRotationSnapping1Button_Click(object sender, EventArgs e)
{
SetRotationSnapping(1);
}
private void ToolbarRotationSnapping2Button_Click(object sender, EventArgs e)
{
SetRotationSnapping(2);
}
private void ToolbarRotationSnapping5Button_Click(object sender, EventArgs e)
{
SetRotationSnapping(5);
}
private void ToolbarRotationSnapping10Button_Click(object sender, EventArgs e)
{
SetRotationSnapping(10);
}
private void ToolbarRotationSnapping45Button_Click(object sender, EventArgs e)
{
SetRotationSnapping(45);
}
private void ToolbarRotationSnapping90Button_Click(object sender, EventArgs e)
{
SetRotationSnapping(90);
}
private void ToolbarRotationSnappingCustomButton_Click(object sender, EventArgs e)
{
ToolsPanel.Visible = true;
ToolsTabControl.SelectedTab = OptionsTabPage;
OptionsTabControl.SelectedTab = OptionsHelpersTabPage;
SnapAngleUpDown.Focus();
}
private void ToolbarSnapGridSizeButton_Click(object sender, EventArgs e)
{
ToolsPanel.Visible = true;
ToolsTabControl.SelectedTab = OptionsTabPage;
OptionsTabControl.SelectedTab = OptionsHelpersTabPage;
SnapGridSizeUpDown.Focus();
}
private void ToolbarUndoButton_ButtonClick(object sender, EventArgs e)
{
Undo();
}
private void ToolbarUndoListButton_Click(object sender, EventArgs e)
{
var tsi = sender as ToolStripItem;
if (tsi == null) return;
var step = tsi.Tag as UndoStep;
if (step == null) return;
if (UndoSteps.Count == 0) return;
var cstep = UndoSteps.Peek();
while (cstep != null)
{
Undo();
if (cstep == step) break;
if (UndoSteps.Count == 0) break;
cstep = UndoSteps.Peek();
}
}
private void ToolbarRedoButton_ButtonClick(object sender, EventArgs e)
{
Redo();
}
private void ToolbarRedoListButton_Click(object sender, EventArgs e)
{
var tsi = sender as ToolStripItem;
if (tsi == null) return;
var step = tsi.Tag as UndoStep;
if (step == null) return;
if (RedoSteps.Count == 0) return;
var cstep = RedoSteps.Peek();
while (cstep != null)
{
Redo();
if (cstep == step) break;
if (RedoSteps.Count == 0) break;
cstep = RedoSteps.Peek();
}
}
private void ToolbarInfoWindowButton_Click(object sender, EventArgs e)
{
ShowInfoForm();
}
private void ToolbarProjectWindowButton_Click(object sender, EventArgs e)
{
ShowProjectForm();
}
private void ToolbarAddItemButton_Click(object sender, EventArgs e)
{
AddItem();
}
private void ToolbarDeleteItemButton_Click(object sender, EventArgs e)
{
DeleteItem();
}
private void ToolbarCopyButton_Click(object sender, EventArgs e)
{
CopyItem();
}
private void ToolbarPasteButton_Click(object sender, EventArgs e)
{
PasteItem();
}
private void ToolbarCameraModeButton_ButtonClick(object sender, EventArgs e)
{
ToggleCameraMode();
}
private void ToolbarCameraPerspectiveButton_Click(object sender, EventArgs e)
{
SetCameraMode("Perspective");
}
private void ToolbarCameraMapViewButton_Click(object sender, EventArgs e)
{
SetCameraMode("2D Map");
}
private void ToolbarCameraOrthographicButton_Click(object sender, EventArgs e)
{
SetCameraMode("Orthographic");
}
private void SelectionModeComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
SetSelectionMode(SelectionModeComboBox.Text);
}
private void SelectionModeComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void ViewModeComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void WorldMaxLodComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void DlcLevelComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void CameraModeComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void RenderModeComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void TextureSamplerComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void TextureCoordsComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void MarkerStyleComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void LocatorStyleComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void BoundsStyleComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void WeatherComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void WeatherRegionComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void CloudsComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void CloudParamComboBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void SnapGridSizeUpDown_ValueChanged(object sender, EventArgs e)
{
SnapGridSize = (float)SnapGridSizeUpDown.Value;
}
private void SnapAngleUpDown_ValueChanged(object sender, EventArgs e)
{
if (Widget != null)
{
SetRotationSnapping((float)SnapAngleUpDown.Value);
}
}
private void RenderEntitiesCheckBox_CheckedChanged(object sender, EventArgs e)
{
Renderer.renderentities = RenderEntitiesCheckBox.Checked;
}
private void StatsLabel_DoubleClick(object sender, EventArgs e)
{
var statsForm = new StatisticsForm(this);
statsForm.Show(this);
}
private void SubtitleLabel_SizeChanged(object sender, EventArgs e)
{
SubtitleLabel.Left = (ClientSize.Width - SubtitleLabel.Size.Width) / 2; //keep subtitle label centered
}
private void SubtitleTimer_Tick(object sender, EventArgs e)
{
SubtitleTimer.Enabled = false;
SubtitleLabel.Visible = false;
}
}
public enum WorldControlMode
{
Free = 0,
Ped = 1,
Car = 2,
Heli = 3,
Plane = 4,
Jetpack = 10,
}
public enum WorldSnapMode
{
None = 0,
Grid = 1,
Ground = 2,
Hybrid = 3,
}
}