Jump to content
Xtreme .Net Talk

snarfblam

Leaders
  • Posts

    2156
  • Joined

  • Last visited

  • Days Won

    2

snarfblam last won the day on November 26 2009

snarfblam had the most liked content!

2 Followers

About snarfblam

  • Birthday 11/19/1984

Personal Information

  • Visual Studio .NET Version
    VB Express 2005, C# Express 2008
  • .NET Preferred Language
    C#, VB

snarfblam's Achievements

Newbie

Newbie (1/14)

4

Reputation

  1. Ever wish the picture box could scale images without using bilinear filtering (for example, when viewing/editing video game graphics)? In the past I had written controls from scratch that emulate the PictureBox but used my desired interpolation. Then I was hit with a stroke of common sense. I've extended the PictureBox class to enhance it with the ability to use various interpolation modes, including the video game creator's best friend, nearest neighbor. using System.Windows.Forms; using System.Drawing.Drawing2D; using System.ComponentModel; using System; namespace iLab { /// /// A PictureBox control extended to allow a variety of interpolations. /// class InterpolatedBox:pictureBox { #region Interpolation Property /// Backing Field private InterpolationMode interpolation = InterpolationMode.Default; /// /// The interpolation used to render the image. /// [DefaultValue(typeof(InterpolationMode), "Default"), Description("The interpolation used to render the image.")] public InterpolationMode Interpolation { get { return interpolation; } set { if(value == InterpolationMode.Invalid) throw new ArgumentException("\"Invalid\" is not a valid value."); // (Duh!) interpolation = value; Invalidate(); // Image should be redrawn when a different interpolation is selected } } #endregion /// /// Overridden to modify rendering behavior. /// /// Painting event args. protected override void OnPaint(PaintEventArgs pe) { // Before the PictureBox renders the image, we modify the // graphics object to change the interpolation. // Set the selected interpolation. pe.Graphics.InterpolationMode = interpolation; // Certain interpolation modes (such as nearest neighbor) need // to be offset by half a pixel to render correctly. pe.Graphics.PixelOffsetMode = PixelOffsetMode.Half; // Allow the PictureBox to draw. base.OnPaint(pe); } } } Since I'm such a swell guy, I translated it to VB too. Imports System.Drawing.Drawing2D Imports System.ComponentModel ''' A PictureBox control extended to allow a variety of interpolations. Public Class InterpolatedBox Inherits PictureBox ''' The backing field for the Interpolation property Dim _interpolation As InterpolationMode = InterpolationMode.Default ''' ''' The interpolation used to render the image. ''' Description("The interpolation used to render the image.")> _ Public Property Interpolation() As InterpolationMode Get Return _interpolation End Get Set(ByVal value As InterpolationMode) If value = InterpolationMode.Invalid Then _ Throw New ArgumentException("""Invalid"" is not a valid value.") '(duh.) _interpolation = value Invalidate() 'Image should be redrawn when a different interpolation is selected End Set End Property ''' ''' Overridden to modify rendering behavior. ''' ''' Painting event args. Protected Overrides Sub OnPaint(ByVal pe As System.Windows.Forms.PaintEventArgs) ' Before the PictureBox renders the image, we modify the ' graphics object to change the interpolation. ' Set the selected interpolation. pe.Graphics.InterpolationMode = _interpolation ' Certain interpolation modes (such as nearest neighbor) need ' to be offset by half a pixel to render correctly. pe.Graphics.PixelOffsetMode = PixelOffsetMode.Half ' Allow the PictureBox to draw. MyBase.OnPaint(pe) End Sub End Class
  2. Presumably this exception would only be thrown on array access, so let's start by identifying which lines the error might be thrown on. Public Class Form1 Dim numberOfFiles As Integer = 0 Dim ds As New DataSet Public TechVan(,) As String = {{"", ""}} Dim NumOfVan As Integer = 0 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim x As Integer = 0 Dim y As Integer = 0 Dim num_rows As Long = 0 Dim num_cols As Long = 0 Dim file_name As String = "TechVan.csv" 'load tech name and van # into an array If File.Exists(file_name) Then Dim tmpstream As StreamReader = File.OpenText(file_name) Dim strlines() As String Dim strline() As String 'Load content of file to strLines array strlines = tmpstream.ReadToEnd().Split(CChar(Environment.NewLine)) 'Redimension the array. num_rows = UBound(strlines) NumOfVan = CInt(num_rows) [color="Red"]strline = strlines(0).Split(CChar(",")) '1[/color] num_cols = UBound(strline) ReDim TechVan(CInt(num_rows), CInt(num_cols)) 'Copy the data into the array. For x = 0 To CInt(num_rows) [color="Red"]strline = strlines(x).Split(CChar(",")) '2[/color] For y = 0 To CInt(num_cols) [color="Red"]TechVan(x, y) = strline(y).Trim() ' 3[/color] Next Next End If End Sub Number 1 shouldn't throw an exception, because String.Split should return an array with at least one element. Number 2 shouldn't throw an exception because your code contains a bounds check. That leaves number 3, in which case you're assuming that each line of the file contains at least as many entries as the first line. Assume the first line has two entries. You re-dim TechVan to have two columns, and y will loop from 0 to 1. Now, if you have a line with only one entry on it, you will attempt to access strline(1), but the array will only contain a single element at strline(0), which would produce an exception. Hopefully, if you add a check to make sure strline contains the correct number of entries (and log or display an error if this is not the case), it will eliminate the unhandled exception. For what it's worth, WinForms providing the user the option to keep running the program after an unhandled exception occurs is a very bad idea. When you click "continue", it means that a function ran half-way through before blowing up, and the program could be in an inconsistent state, creating stability issues, and possibly even security issues.
  3. It took me a minute of scratching my head before I figured this out. Here's what I came up with. First thing I did was get the pixel coordinates relative to the origin of the isometric grid. I'm using the image you posted as an example. The origin of the grid is at pixel coordinate (319, 0). public partial class Form1 : Form { const int origX = 319; const int origy = 0; public Form1() { InitializeComponent(); } private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { int relativeToOriginX = e.X - origX; int relativeToOriginY = e.Y - origy; } } I eventually reasoned that, placing the mouse cursor over the grid, for each pixel you move down, you're moving 1/32 of a tile in both the x- and y-axes of the isometric grid. (If you move the mouse down 32 pixels, you've gone from the corner of tile (0,0) to the corner of tile (1,1).) Up is -1/32 of a tile in each axis. Moving from left to right, it takes 64 pixels to go from the "bottom-left" corner of a tile to the "top-right", thus one pixel right is +1/64 in the x-axis and -1/64 in the y-axis. Likewise, left is -1/64 and + 1/64. So, we can add some more constants to represent those values: const int origX = 319; const int origy = 0; [color="Blue"] const double isoYperPixelY = (1.0 / 32); const double isoXperPixelY = (1.0 / 32); const double isoYperPixelX = -(1.0 / 64); const double isoXperPixelX = (1.0 / 64);[/color] Now, to get grid coordinates, you can take the pixel X (relative to the origin of the grid), and multiply it by isoXperPixelX, then multiply the pixel Y by isoXperPixelY, add the two together, and viola. You've got your grid X-coordinate. Use the same process to get your grid Y-coordinate. public partial class Form1 : Form { const int origX = 319; const int origy = 0; const double isoYperPixelY = (1.0 / 32); const double isoXperPixelY = (1.0 / 32); const double isoYperPixelX = -(1.0 / 64); const double isoXperPixelX = (1.0 / 64); public Form1() { InitializeComponent(); } private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { int relativeToOriginX = e.X - origX; int relativeToOriginY = e.Y - origy; [color="Blue"] double isoX = relativeToOriginX * isoXperPixelX + relativeToOriginY * isoXperPixelY; double isoY = relativeToOriginX * isoYperPixelX + relativeToOriginY * isoYperPixelY; Text = ((int)isoX).ToString() + ", " + ((int)isoY).ToString();[/color] } } Place your grid image in a picturebox, move the mouse around, and watch the form's caption. Fun Fact: I realized after the fact that this is effectively matrix multiplication.
  4. I'm not sure exactly how you want it represented in the property grid, but a tutorial on customizing the property grid (like this) should have all the info you need. It's not simple, but it's doable.
  5. You can have a property appear on the property grid that is not actually part of the class by using a custom TypeDescriptor (check out some tutorials on customizing the property grid), but what is the actual problem you're trying to solve here? There's likely a better solution.
  6. This is an issue of greedy versus lazy quantifiers. Basically, a greedy quantifier, such as *, will try to match as much as possible. Your regex describes a string with brackets on either end, which does match the string "[abc] Bbbb [7]". You want the lazy version, which will find the smallest match possible. Check out http://www.regular-expressions.info/reference.html
  7. Non-VB-specific methods are generally recommended anyways since they're generally the same across all .NET languages. To get the left part of a string: ' Get left two letters Dim start As Integer = 0 Dim length As Integer = 2 Dim Beginning As String = ("Some Text").Substring(start, length) As for the "Like" operator, I've never used it but it seems to me that regular expressions would be a good substitute, if you're willing to learn it (not difficult). Dim regexMatch As Boolean = Regex.IsMatch("Some Text", "^S.*") The dot matches any character, and the asterisk modifies the dot to match zero or more any-characters (i.e. ".*" in regex behaves just like "*" in your code). The ^ matches the start of the string. I also stumbled onto this article taking a different approach.
  8. I googled System.Web.Script.Serialization and it listed all the classes as being part of System.Web.Extensions.dll.
  9. Does the font still scale if you set the AutoScaleMode property to None? I don't mess with the font size in Windows because it breaks the UI of some programs. They don't deal with scaling properly. (This even includes software I've written. :( ) Ideally, though, I would prefer to scale the fonts up. I do scale the fonts up in my browser, though. In earlier versions of FireFox, depending on how a font's size was set, sometimes the text wouldn't scale. It definitely bothered me.
  10. Simply put, your function is calling itself (possibly indirectly) over and over again. Open up the call stack window and look at which functions are calling which to figure out why and how your code is calling itself.
  11. One (or more) of the FileStream constructors accepts a FileMode argument, which allows you to specify FileMode.Append. Once you've created the FileStream, you can create a StreamWriter with the FileStream. Depending on what you're doing, you might also be able to use one of the handy convenience methods of the System.IO.File class. void AppendToLog(string text) { File.AppendAllText(Program.LogPath, text); }
  12. It looks like there might be a couple of problems with your pointer math. I don't play with pointers every day, so I can't promise I'll get it 100% either, but here's what I'm noticing: First, I'm a little confused by this: int offset = dataA.Stride - width; It looks like the value of "offset" is meant to make up the difference between the length of a row's data and the row's stride (i.e. offset specifies the row's padding). That seems like a confusing way to deal with stride. What I would do is have two pointer variables per image. In addition to ptrA and ptrB, I would have what I'll call rowStartA and rowStartB. You would initalize rowStartA to dataA.Scan0, and rowStartB likewise. Then, after you process each row, add dataA.Stride to rowStartA to get the starting address of the next row. Before you loop over the pixels in each row, you would initialize prtA to the current value of rowStartA, and then increment ptrA after each byte is processed. So, something like this... rowStartA = dataA.Scan0 rowStartB = dataB.Scan0 loop over Y ptrA = rowStartA prtB = rowStartB loop over X process byte ptrA ++ ptrB ++ end loop rowStartA += dataA.Stride rowStartB += dataB.Stride end loop Secondly, your pointers walk through bytes. If I understand correctly, you are processing one byte per pixel. With a 24-bit format, it would be three bytes per pixel. With 32-bit, it would be four bytes per pixel, but you would want to skip over the alpha byte. This is what I imagine code would typically look like for an ARGB image, not taking alpha blending into account (hopefully I've got the byte order correct): for (int x = 0; x < width; x++) { // Blue int result = (ptrB[0] * ptrA[0]) / 255; ptrA[0] = (byte)result > (byte)255 ? (byte)255 : (byte)result; prtA++; ptrB++; // Green int result = (ptrB[0] * ptrA[0]) / 255; ptrA[0] = (byte)result > (byte)255 ? (byte)255 : (byte)result; prtA++; ptrB++; // Red int result = (ptrB[0] * ptrA[0]) / 255; ptrA[0] = (byte)result > (byte)255 ? (byte)255 : (byte)result; prtA++; ptrB++; // Alpha (ignored) (or you can just copy the alpha channel from image A to B) prtA++; ptrB++; } For a 24-bit format, just get rid of the last pair of increments. Hopefully that helps.
  13. Well, it looks like I might have been wrong. There seems to be a metro version of VS after all (http://dotnet.dzone.com/articles/visual-studio-11-beta). The real problem is that you apparently need to be a licensed developer (whatever that entails) to distribute apps, and need to distribute apps via the app store (http://techcrunch.com/2012/09/29/windows-store-metro-mode-no-sideloading-psa). I'm not sure what that means for programmers like me who only make free software. I'd be curious to see what you're cooking up, but lately, I've actually been trying to get back on top of an NES homebrew game I've been working on. I just need to muster up the patience and determination needed to finish a game in written completely in assembly.
  14. Windows for ARM devices lacks the traditional desktop. At's all Metro whatever it's called now. So, as I understand it, while you can develop for ARM devices, you won't be able to develop on ARM devices.
  15. Nope! Maybe you should show your code that declares, raises, and subscribes to events. Any object can subscribe to events on any other object it can get its hands on.
×
×
  • Create New...