//Gradients private void gradientNameBox_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Return) { if (!Document.ContainsGradient(gradientNameBox.Text)) { PhotonGradient pg = new PhotonGradient(PhotonInterpolationMode.Linear); pg.Add(new Photon(0, 0, 0), 0); pg.Add(new Photon(1, 1, 1), 1); GradientDialog gd = new GradientDialog(pg); if (gd.ShowDialog() == DialogResult.OK) { if (Document.SetGradient(gradientNameBox.Text, pg)) { Document.SelectedGradientName = gradientNameBox.Text; } } } else { Document.SelectedGradientName = gradientNameBox.Text; } e.SuppressKeyPress = true; } }
private void Document_GradientRemoved(string name, PhotonGradient gradient) { if (name == gradientName) { Close(); } }
public GradientDialog(PhotonGradient gradient) { CenterToParent(); InitializeComponent(); gradientTypeBox.DataSource = Enum.GetValues(typeof(PhotonInterpolationMode)); Gradient = gradient; }
private void gradientBox_MouseClick(object sender, MouseEventArgs e) { PhotonGradient gradient = gradientBox.Gradient; float u = (float)e.X / gradientBox.Width * gradient.Length + gradient.Start; int i = gradient.ClosestIndex(u); if (e.Button == MouseButtons.Left) { PhotonGradient.PhotonPosition pp = gradient[i]; if (ModifierKeys == Keys.Control) { pp.Photon = gradient[u]; pp.Position = u; gradient.Add(pp); gradientBox.UpdateRender(); } else { PhotonDialog photonDialog = new PhotonDialog(this); photonDialog.Photon = pp.Photon; if (photonDialog.ShowDialog() == DialogResult.OK) { pp.Photon = photonDialog.Photon; gradient[i] = pp; gradientBox.UpdateRender(); } } } else if (e.Button == MouseButtons.Right && i > 0 && i < gradient.PhotonPositionCount - 1) { gradient.Remove(i); gradientBox.UpdateRender(); } }
public void UpdateArea(int x, int y, int width, int height, PhotonGradient gradient, IEnumerable <Effect> effects) { if (gradient == null) { gradient = new PhotonGradient(PhotonInterpolationMode.Linear); gradient.Add(new Photon(0.0f, 0.0f, 0.0f), heightField.ClampMin); gradient.Add(new Photon(1.0f, 1.0f, 1.0f), heightField.ClampMax); } if (x >= 0 && width > 0 && x + width <= Width && y >= 0 && height > 0 && y + height <= Height) { BitmapData data = bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); try { unsafe { byte *start = (byte *)data.Scan0.ToPointer(); for (int _x = x; _x < x + width; _x++) { for (int _y = y; _y < y + height; _y++) { Photon p = gradient[heightField[_x, _y]]; if (effects != null) { foreach (Effect e in effects) { if (e != null) { p = e(_x, _y, p, heightField); } } } byte *pix = start + _y * Width * 4 + _x * 4; * pix = p.b; pix++; *pix = p.g; pix++; *pix = p.r; pix++; *pix = p.a; } } } } catch (Exception e) { throw new Exception(e.Message); } finally { bitmap.UnlockBits(data); } } else { throw new Exception("The supplied region did not lie within the height render."); } }
private void Document_GradientSet(string name, PhotonGradient gradient) { gradientNameBox.Items.Clear(); foreach (string s in Document.GradientNames) { gradientNameBox.Items.Add(s); } }
private void editGradientToolStripMenuItem_Click(object sender, EventArgs e) { if (Document.ContainsGradient(gradientNameBox.Text)) { PhotonGradient copy = Document.GetGradient(gradientNameBox.Text).MakeCopy(); GradientDialog gd = new GradientDialog(gradientNameBox.Text, this); gd.Show(); } }
private void Document_GradientSet(string name, PhotonGradient gradient) { selectedGradientBox.Items.Clear(); foreach (string s in Document.GradientNames) { selectedGradientBox.Items.Add(s); } selectedGradientBox.Text = Document.SelectedGradientName; }
private static void SaveGradient(Stream stream, PhotonGradient gradient) { stream.Write(BitConverter.GetBytes(gradient.PhotonPositionCount), 0, sizeof(int)); stream.Write(BitConverter.GetBytes((int)gradient.Mode), 0, sizeof(int)); for (int i = 0; i < gradient.PhotonPositionCount; i++) { stream.Write(gradient[i].Photon, 0, sizeof(byte) * 4); stream.Write(BitConverter.GetBytes(gradient[i].Position), 0, sizeof(float)); } }
private void Document_GradientRemoved(string name, PhotonGradient gradient) { gradientNameBox.Items.Clear(); selectedGradientBox.Items.Clear(); foreach (string s in Document.GradientNames) { gradientNameBox.Items.Add(s); selectedGradientBox.Items.Add(s); } selectedGradientBox.SelectedItem = Document.SelectedGradient; }
private void Redo() { if (redoQueue.Count > 0) { BrushAction redoAction = redoQueue.Dequeue(); //Set all of the values in the affected area to what they were before the undo action took place. HeightRender render = Document.SelectedRender; BrushAction opposite = new BrushAction(redoAction.Selection, redoAction.Data); for (int x = redoAction.Selection.Left; x < redoAction.Selection.Right; x++) { for (int y = redoAction.Selection.Top; y < redoAction.Selection.Bottom; y++) { float oldSample; if (render.HeightField.TryGetHeight(x, y, out oldSample)) { int i = (y - redoAction.Selection.Top) * redoAction.Selection.Width + (x - redoAction.Selection.Left); render.HeightField[x, y] = redoAction.Data[i]; opposite.Data[i] = oldSample; } } } PhotonGradient gradient = Document.SelectedGradient; IEnumerable <HeightRender.Effect> effects; if (paintEffectsBox.Checked) { effects = Document.SelectedEffects; } else { effects = null; //Don't worry about effects if we're not painting with them. } //Update each section of the selection when wrapping has been accounted for. foreach (FieldSelection fs in redoAction.Selection.SubSelectionsOf(render.HeightField)) { //Omit any parts that have a width or height of zero. if (!fs.IsEmpty) { //Update the corresponding part of the render. render.UpdateArea(fs.Left, fs.Top, fs.Width, fs.Height, gradient, effects); //Invalidate the corresponding part of the image panel so that it redraws itself in realtime. Point start = Numerics.ToPoint(renderArea.ImageToClient(new Vector2(fs.Left, fs.Top))); Point end = Numerics.ToPoint(renderArea.ImageToClient(new Vector2(fs.Right, fs.Bottom))); renderArea.Invalidate(new Rectangle(Numerics.Max(start.X, 0), Numerics.Max(start.Y, 0), Numerics.Max(end.X, 0), Numerics.Max(end.Y, 0))); } } undoQueue.Enqueue(opposite); } }
//Setting public static bool SetGradient(string name, PhotonGradient gradient) { if (name != null && name.Length > 0) { gradients[name] = gradient; if (gradientSet != null) { gradientSet(name, gradient); } return(true); } else { return(false); } }
private void editGradientToolStripMenuItem_Click(object sender, EventArgs e) { if (Document.SelectedGradient != null) { PhotonGradient fallback = Document.SelectedGradient.MakeCopy(); GradientDialog gd = new GradientDialog(Document.SelectedGradientName, this); if (gd.ShowDialog() == DialogResult.OK && Document.SelectedRender != null) { Document.SelectedRender.UpdateAll(Document.SelectedGradient, Document.SelectedEffects); renderArea.Invalidate(); } else { Document.SetGradient(Document.SelectedGradientName, fallback); } } }
private void gradientBox_MouseMove(object sender, MouseEventArgs e) { PhotonGradient gradient = gradientBox.Gradient; float u = (float)e.X / gradientBox.Width * gradient.Length + gradient.Start; int i = gradient.ClosestIndex(u); if (e.Button == MouseButtons.Middle && i > 0 && i < gradient.PhotonPositionCount - 1) { PhotonGradient.PhotonPosition pp = gradient[i]; if (ModifierKeys == Keys.Shift) { pp.Position = (float)(int)(Math.Round(u * gradientRuler.Segments)) / gradientRuler.Segments; } else { pp.Position = u; } gradient[i] = pp; gradientBox.UpdateRender(); } }
private static PhotonGradient LoadGradient(Stream stream) { byte[] buffer = new byte[4]; stream.Read(buffer, 0, sizeof(int)); int count = BitConverter.ToInt32(buffer, 0); stream.Read(buffer, 0, sizeof(int)); PhotonInterpolationMode mode = (PhotonInterpolationMode)BitConverter.ToInt32(buffer, 0); PhotonGradient gradient = new PhotonGradient(mode); for (int i = 0; i < count; i++) { stream.Read(buffer, 0, sizeof(byte) * 4); Photon p = buffer; stream.Read(buffer, 0, sizeof(float)); float f = BitConverter.ToSingle(buffer, 0); gradient.Add(p, f); } return(gradient); }
public GradientDialog(string gradientName, Form owner) { Owner = owner; if (gradientName != null && gradientName.Length > 0) { CenterToParent(); InitializeComponent(); gradientTypeBox.DataSource = Enum.GetValues(typeof(PhotonInterpolationMode)); if (Document.ContainsGradient(this.gradientName = gradientName)) { gradientBox.Gradient = Document.GetGradient(gradientName); } else { PhotonGradient pg = new PhotonGradient(PhotonInterpolationMode.Linear); pg.Add(new Photon(0.0f, 0.0f, 0.0f), 0.0f); pg.Add(new Photon(1.0f, 1.0f, 1.0f), 1.0f); Document.SetGradient(gradientName, gradientBox.Gradient = pg); } copy = gradientBox.Gradient.MakeCopy(); gradientTypeBox.SelectedItem = gradientBox.Gradient.Mode; minBox.Value = (decimal)gradientBox.Gradient.Start; maxBox.Value = (decimal)(gradientBox.Gradient.Length - gradientBox.Gradient.Start); Document.Cleared += Document_Cleared; Document.Loaded += Document_Loaded; Document.GradientRemoved += Document_GradientRemoved; } else { throw new Exception("The supplied name was empty or null."); } }
public void UpdateAll(PhotonGradient gradient, IEnumerable <Effect> effects) { UpdateArea(0, 0, Width, Height, gradient, effects); }
//Loading public static IOEvaluation Load(string path) { Clear(); if (File.Exists(path)) { FileStream stream = null; try { stream = new FileStream(path, FileMode.Open); } catch { return(IOEvaluation.CannotOpenStream); } try { IOBlockIdentifier block; string blockName; byte[] blockBuff = new byte[sizeof(int)]; stream.Read(blockBuff, 0, sizeof(int)); block = (IOBlockIdentifier)BitConverter.ToInt32(blockBuff, 0); if (block == IOBlockIdentifier.FileBegin) { do { if (stream.Position < stream.Length) { stream.Read(blockBuff, 0, sizeof(int)); block = (IOBlockIdentifier)BitConverter.ToInt32(blockBuff, 0); switch (block) { case IOBlockIdentifier.FileEnd: break; case IOBlockIdentifier.Brush: blockName = LoadText(stream); BrushScript bs = LoadBrush(stream); SetBrush(blockName, bs.brush, bs.script); break; case IOBlockIdentifier.Effect: blockName = LoadText(stream); EffectScript es = LoadEffect(stream); SetEffect(blockName, es.effect, es.script); break; case IOBlockIdentifier.Gradient: blockName = LoadText(stream); PhotonGradient gradient = LoadGradient(stream); SetGradient(blockName, gradient); break; case IOBlockIdentifier.Render: blockName = LoadText(stream); HeightRender render = LoadRender(stream); SetRender(blockName, render); break; case IOBlockIdentifier.Generator: blockName = LoadText(stream); GeneratorScript gs = LoadGenerator(stream); SetGenerator(blockName, gs.generator, gs.script); break; default: throw new Exception("Encountered a block that couldn't be identified."); } } else { throw new Exception("The end of the file was reached before the appropriate 'End of File' flag was found."); } }while (block != IOBlockIdentifier.FileEnd); //Path and Callback associatedPath = path; if (loaded != null) { loaded(path); } return(IOEvaluation.Success); } else { return(IOEvaluation.ConversionError); } } catch { Clear(); return(IOEvaluation.ConversionError); } finally { stream.Close(); } } else { associatedPath = path; return(IOEvaluation.FileDoesNotExist); } }
//Loading public static bool Load(string path) { Clear(); if (File.Exists(path)) { FileStream stream = new FileStream(path, FileMode.Open); try { byte[] countBuf = new byte[4]; int count; //Load Renders stream.Read(countBuf, 0, sizeof(int)); count = BitConverter.ToInt32(countBuf, 0); for (int i = 0; i < count; i++) { string name = LoadText(stream); HeightRender render = LoadRender(stream); SetRender(name, render); } //Load Gradients stream.Read(countBuf, 0, sizeof(int)); count = BitConverter.ToInt32(countBuf, 0); for (int i = 0; i < count; i++) { string name = LoadText(stream); PhotonGradient gradient = LoadGradient(stream); SetGradient(name, gradient); } //Load Effects stream.Read(countBuf, 0, sizeof(int)); count = BitConverter.ToInt32(countBuf, 0); for (int i = 0; i < count; i++) { string name = LoadText(stream); EffectScript es = LoadEffect(stream); SetEffect(name, es.effect, es.script); } //Load Brushes stream.Read(countBuf, 0, sizeof(int)); count = BitConverter.ToInt32(countBuf, 0); for (int i = 0; i < count; i++) { string name = LoadText(stream); BrushScript bs = LoadBrush(stream); SetBrush(name, bs.brush, bs.script); } //Path and Callback associatedPath = path; if (loaded != null) { loaded(path); } return(true); } catch { associatedPath = null; return(false); } finally { stream.Close(); } } else { associatedPath = path; return(false); } }
private void Application_Idle(object sender, EventArgs e) { Vector2 pointOnRenderArea = Numerics.ToVector(renderArea.PointToClient(Control.MousePosition)); Vector2 pointOnRender = renderArea.ClientToImage(pointOnRenderArea); if (renderArea.Focused && Document.SelectedRender != null) { #region Undo if (undoing) { Undo(); } #endregion #region Redo if (redoing) { Redo(); } #endregion #region Panning if (MouseButtons == MouseButtons.Middle) { renderArea.ImageOffset += (pointOnRenderArea - lastPointOnRenderArea) / renderArea.ImageScale; } #endregion #region Brush //Select the appropriate brush based on the active mouse buttons. HeightBrush activeBrush = null; if (MouseButtons == MouseButtons.Left) { activeBrush = Document.LeftBrush; } else if (MouseButtons == MouseButtons.Right) { activeBrush = Document.RightBrush; } //If a mouse button was in use; paint. if (activeBrush != null) { HeightRender render = Document.SelectedRender; PhotonGradient gradient = Document.SelectedGradient; IEnumerable <HeightRender.Effect> effects; if (paintEffectsBox.Checked) { effects = Document.SelectedEffects; } else { effects = null; //If we aren't painting with effects then we don't care about supplying them to the update. } #region Process Steps //The brush stroke is broken up into steps that are each a given length (in pixels). The length is denoted by the brush precision. Vector2 brushDelta = lastPointOnRender - pointOnRender; float strokeLength = (float)brushDelta.Length; float steps = strokeLength / activeBrush.Precision + 1; Vector2 brushStep = brushDelta * (1.0f / steps); for (int i = (int)steps - 1; i >= 0; i--) //Work backwards so the undo and redo functionality makes sense. { //Calculate the current brush position, based on the starting point, the step vector and the current step index. Vector2 brushPosition = pointOnRender + brushStep * i; #region Process Brush Paint try { //Perform the actual brush operation and capture the selected area it affects. FieldSelection brushArea; float[] previousData; activeBrush.Paint(render.HeightField, (int)brushPosition.X, (int)brushPosition.Y, strokeLength, out brushArea, out previousData); //Add this paint event to the undo queue. undoQueue.Enqueue(new BrushAction(brushArea, previousData)); redoQueue.Clear(); //Break up the brush area into multiple parts if they intersect the edges of the image. foreach (FieldSelection fs in brushArea.SubSelectionsOf(render.HeightField)) { //Omit any parts that have a width or height of zero. if (!fs.IsEmpty) { //Update the corresponding part of the render. render.UpdateArea(fs.Left, fs.Top, fs.Width, fs.Height, gradient, effects); //Invalidate the corresponding part of the image panel so that it redraws itself in realtime. Point start = Numerics.ToPoint(renderArea.ImageToClient(new Vector2(fs.Left, fs.Top))); Point end = Numerics.ToPoint(renderArea.ImageToClient(new Vector2(fs.Right, fs.Bottom))); renderArea.Invalidate(new Rectangle(Numerics.Max(start.X, 0), Numerics.Max(start.Y, 0), Numerics.Max(end.X, 0), Numerics.Max(end.Y, 0))); } } } catch (Exception ex) { //This usually happens when activeBrush.Paint is called, because it executes the user's brush script. Shows the script error message as a message box. MessageBox.Show(ex.Message, "There was a runtime error with your brush script."); } #endregion } #endregion } #endregion } else { undoing = redoing = false; } lastPointOnRenderArea = pointOnRenderArea; lastPointOnRender = pointOnRender; }
private void Application_Idle(object sender, EventArgs e) { Vector2 pointOnRenderArea = Numerics.ToVector(renderArea.PointToClient(Control.MousePosition)); Vector2 pointOnRender = renderArea.ClientToImage(pointOnRenderArea); if (renderArea.Focused && Document.SelectedRender != null) { #region Panning if (MouseButtons == MouseButtons.Middle) { renderArea.ImageOffset += (pointOnRenderArea - lastPointOnRenderArea) / renderArea.ImageScale; } #endregion #region Brush HeightBrush activeBrush = null; if (MouseButtons == MouseButtons.Left) { activeBrush = Document.LeftBrush; } else if (MouseButtons == MouseButtons.Right) { activeBrush = Document.RightBrush; } if (activeBrush != null) { HeightRender render = Document.SelectedRender; PhotonGradient gradient = Document.SelectedGradient; IEnumerable <HeightRender.Effect> effects; if (paintEffectsBox.Checked) { effects = Document.SelectedEffects; } else { effects = null; } #region Process Steps Vector2 brushDelta = lastPointOnRender - pointOnRender; float strokeLength = (float)brushDelta.Length; float steps = strokeLength / activeBrush.Precision + 1; Vector2 brushStep = brushDelta * (1.0f / steps); for (int i = 0; i < steps; i++) { Vector2 brushPosition = pointOnRender + brushStep * i; #region Process Brush Paint try { FieldSelection brushArea; activeBrush.Paint(render.HeightField, (int)brushPosition.X, (int)brushPosition.Y, strokeLength, out brushArea); foreach (FieldSelection fs in brushArea.SubSelectionsOf(render.HeightField)) { if (!fs.IsEmpty) { render.UpdateArea(fs.Left, fs.Top, fs.Width, fs.Height, gradient, effects); Point start = Numerics.ToPoint(renderArea.ImageToClient(new Vector2(fs.Left, fs.Top))); Point end = Numerics.ToPoint(renderArea.ImageToClient(new Vector2(fs.Right, fs.Bottom))); renderArea.Invalidate(new Rectangle(Numerics.Max(start.X, 0), Numerics.Max(start.Y, 0), Numerics.Max(end.X, 0), Numerics.Max(end.Y, 0))); } } } catch (Exception ex) { MessageBox.Show(ex.Message, "There was a runtime error with your brush script."); } #endregion } #endregion } #endregion } lastPointOnRenderArea = pointOnRenderArea; lastPointOnRender = pointOnRender; }