Page 2 of 2 FirstFirst 12
Results 41 to 54 of 54

Thread: [RESOLVED] Layer rendering (image program)

  1. #41
    PowerPoster boops boops's Avatar
    Join Date
    Nov 2008
    Location
    Holland/France
    Posts
    3,201

    Re: Layer rendering (image program)

    Quote Originally Posted by NickThissen View Post
    As far as I understand it (I'm not absolutely sure about this), when you call Invalidate the region is indeed placed in some kind of queue, and the actual painting happens only when the Update method is called. This allows you to invalidate multiple regions or rectangles in a row, and only call Update when you invalidated all the regions that need to be painted.

    At first I thought that therefore one must call Update in order to get a repaint at all, but that doesn't seem to be the case. With all the painting I have ever done, calling Update or not does not seem to make a difference. This suggests to me that the control calls its own Update method when at least one region of it is invalidated. This can't happen instantly (otherwise calling Invalidate multiple times and only then calling Update would be nonsense) so I think that the 'control' simply waits a short time, in which you can potentially call Invalidate a few more times with different regions, until calling Update.

    If you are for example moving some shape across the PictureBox, as I am doing in my example project, then you can now Invalidate both the old and the new locations of the shape before calling Update. If Invalidate would immediately repaint the control then the paint code would be run twice (or many many more times in more complicated drawing scenarios), while it is much more efficient to just run it once and then redraw the invalidated regions in one go.

    I think the best option is to always call Update after you have invalidated all regions, but I have never seen anything behave wrong or even strange when not calling Update.
    Thanks for your explanation Nick. I assumed the "queue" concerned was being handled by the OS (along with non-Framework painting tasks) but on further reading it is clear that I was wrong: apparently the application has its own Invalidate queue, although there isn't an implicit Update involved.

    According to the graphics guru Bob Powell
    , the Invalidate queue is cleared when the application is about to enter an idle state. If there are any invalid rectangles to be handled, the application issues a WM_Paint Message. (Refresh and Update, on the other hand, issue an immediate WM_Paint Message.) In either case, the sequel to the WM_Paint message is:

    1. Calculate the union Region of all the Invalid rectangles (Regions are basically collections of rectangles).
    2. Clear the Invalidate queue
    3. Call the OnPaint Sub
    4. MyBase.OnPaint raises the Paint Event
    5. Call any event handler subs for the Paint Event.

    I assume that whatever happens next is handled by the OS and the graphics hardware. I hope I'm getting towards the truth now, because understanding this seems essential for measuring and optimizing GDI+ graphics performance.

    BB

  2. #42
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Layer rendering (image program)

    That seems about right yes. I don't know too much about it myself, and everything I do know is pieced together over the years from various sources. Luckily I never got into the situation where I needed to draw too much. I only usually do some custom control drawing, and even though that can get pretty complicated (many little bits and pieces) the controls are usually quite small so the drawing never slows it down.

  3. #43

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Layer rendering (image program)

    Ok need your help again

    This is the drawing part of a layer:
    Code:
        Private OldTransform As New System.Drawing.Drawing2D.Matrix
        Private OldSize As New Size(0, 0)
        Public Sub Draw(ByRef g As Graphics)
            If Me.Changed = True Then UpdateRegion(OldTransform, OldSize)
            g.TranslateTransform(Me.PictureNode.CenterPoint.X + 400, Me.PictureNode.CenterPoint.Y + 300)
            g.RotateTransform(Val(Me.PictureNode.RotateVariable.Value))
            g.TranslateTransform((Me.PictureNode.Location.X + Val(Me.PosXHandler.Value)) - Me.PictureNode.CenterPoint.X - 400 + Me.PictureNode.Size.Width * 0.5, (Me.PictureNode.Location.Y + Val(Me.PosYHandler.Value)) - Me.PictureNode.CenterPoint.Y - 300 + Me.PictureNode.Size.Height * 0.5)
            g.RotateTransform(Me.PictureNode.Rotation.Value)
            g.TranslateTransform(Me.PictureNode.Size.Width * -0.5, Me.PictureNode.Size.Height * -0.5)
            'drawing and updating
            g.DrawImage(PictureNode.SizedImage, New Rectangle(0, 0, PictureNode.SizedImage.Width, PictureNode.SizedImage.Height), 0, 0, PictureNode.SizedImage.Width, PictureNode.SizedImage.Height, GraphicsUnit.Pixel, Color.ToImageAttribute)
            OldTransform = g.Transform
            OldSize = Me.PictureNode.Size.Value
            If Me.Changed = True Then UpdateRegion(OldTransform, OldSize)
            Me.Changed = False
        End Sub
    UpdateRegion sub:
    Code:
        Public Sub UpdateRegion(ByVal Tdata As System.Drawing.Drawing2D.Matrix, ByVal Size As Size)
            Dim r As New System.Drawing.Region(New Rectangle(New Point(0, 0), Size))
            r.Transform(Tdata)
            Form1.MainScreen.Invalidate(r)
        End Sub
    When I move the image of this layer around, the edges deform/are cut off. As example, I move a square 200 x 200 image to the right and on the left and right part of the image disappears. Moving up/down and the top and lower part deform.
    Why is part of the image being cut-off when I move the image around and how can I stop it from happening?

    Note: it doesn't happens when I invalidate the entire screen, but I can't use that (lag)

    Now I read your posts (that were on a different page I haven't read ), is it because I am invalidating <inside> the onpaint sub?

    EDIT

    Wow that is one mistake I'll never make again.
    it was checking for changed nodes using the onpaint sub, but when it did find something changed it invalidated it, causing a new onpaint. This onpaint gave a different type of region, causing some very weird bugs like this.
    Last edited by bergerkiller; Aug 12th, 2010 at 11:39 AM.

  4. #44
    PowerPoster boops boops's Avatar
    Join Date
    Nov 2008
    Location
    Holland/France
    Posts
    3,201

    Re: Layer rendering (image program)

    Invalidating inside the OnPaint sub is definitely a mistake. I suggest trying the following order:
    1. Define a matrix (mtx)
    2. Apply all the transformations to the matrix (mtx.Rotate, mtx.Translate etc.). Note that there's also a Matrix.RotateAt(angle, point) which may save you having to do separate translations.
    3. Define a Region with the target rectangle for drawing (rect) and apply the matrix: Dim rgn as New Region(rect, mtx).
    4. Invalidate the Region: Me.Invalidate(rgn).
    5. Add Me.Update if you want the app to force drawing immediately instead of waiting for a quiet moment. But that's not always a good idea.
    6. In the OnPaint sub or in a Paint event handler, apply the transformation to the graphics: e.Graphics.Transform=mtx.
    7. Then draw the image to the target rectangle: e.Graphics.DrawImage(image, rect).

    EDIT: Error in Step 3 above: you have to apply the transformation separately from the rectangle:
    Code:
    Dim rgn As New Region(rect)
    rgn.Transform(mtx)
    BB
    Last edited by boops boops; Aug 12th, 2010 at 12:19 PM.

  5. #45

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Layer rendering (image program)

    Note that there's also a Matrix.RotateAt(angle, point) which may save you having to do separate translations.
    Yep I know. But I can't seem to get rotateat working. First to clear stuff up:
    - layers can contain different types
    - current type that is supported: "Picture Node"
    - picture node arguments/paramters are:
    + location (as Watched point, structure I made myself to see if it has changed)
    + size (as Watched size)
    + static rotation (as Watched integer)
    + middle point for dynamic rotation (watched point)
    + dynamic rotation (variablehandler; changes value by setting a variable)
    + sizedimage property (checks for a changes size, generates a new sized image if needed)
    + color (new color class, capable of doing new stuff. Including: to image attributes, from/to ole; decimal text; drawing color; argb and "merge" option to merge it with other colors)

    All key parts are now working, even the coloring.

    As you saw in the draw sub, it takes a lot of stuff to draw the final image.
    (that's why I used bitmaps to store them in the earlier version).

    Now I have a couple of questions:
    - how can I rotate the image around the middle using rotateat?
    - how can I add "subclassing" so the subclasses can access the parent; for example:
    Code:
    public class testclass
       public b as integer
       sub new()
          me.testsubclass.a = 1
       end sub
       public class testsubclass
          public sub SetB()
             b = 2
          end sub
          public a as integer
       end class
    end class
    - How can I add additional effects to the graphics object (as example greyscale/inverted colors) If I need to apply it on every ondraw and not infront/after, how can I merge two effects?
    Last edited by bergerkiller; Aug 12th, 2010 at 01:23 PM.

  6. #46
    PowerPoster boops boops's Avatar
    Join Date
    Nov 2008
    Location
    Holland/France
    Posts
    3,201

    Re: Layer rendering (image program)

    I can give you a quick answer about Matrix.RotateAt. The angle is in degrees, not radians. The rotation point (and all points you deal with) should be relative to the graphics origin. So if you are drawing on PictureBox1 and you use the pe.Graphics from the PictureBox's OnPaint Sub, it will be relative to point(0,0) of the picture box client area. For example, to rotate a rectantle rect 30 degrees about its centre, you could use:

    Code:
    mtx.RotateAt(30, New Point(rect.Left+rect.Width\2, rect.Top+rect.Height\2))
    I don't see anything wrong with storing an intermediate bitmap. For example you could store a colour-modified version of the original image as a bitmap, and do scaling/rotation/translation with a matrix in the (On)Paint sub. That way you would be able to do color transformations using an array (with Lockbits), which in some cases can much faster than using the Drawing2D.ColorMatrix (let alone using Bitmap.SetPixel, which is disastrously slow). On the other hand, I don't have the impression that there is anything to be gained by doing scaling or rotation using Lockbits. I'm being cautious here because I'd like to test these assumptions with real measurements.

    Your question about a "parent" is a bit hard to follow. Defining one class inside another doesn't make them related in any way. You can always set a public variable in an instance of another class. You can also declare a variable Shared, so that it applies to all instances of the class, but I don't think that's what you are looking for. Maybe you should think of a structure in which both classes Inherit from a common base class.

    BB

  7. #47

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Layer rendering (image program)

    Thanks

    About the subclassing; I'll explain the situation.

    I have one layer class. I made my own "PictureNode" class, with all variables for a picture node. The layer class has a "Type" variable, defining the type. Rendering checks the type and based on that it renders.

    But, the layer class has a "changed" boolean variable (for invalidating). The PictureNode class has to access this variable, basically accessing the parent.
    At this point I added the class as a variable instance:
    Code:
    Public PictureNode as PictureNode
    I can't reference back (of course), so all I can do now is calling an updatescreen sub that checks all layers if they are changed. This could be slow eventually, and the sub is called more times a second, so even 50 ms is disastrous. Since I will add 10+ different types in the future, I need a quick way of a "subclass", so when I type layers(0). I don't see a long list of variables, but the subclass "PictureNode" with it's respective variables.

    I can of course give the PictureNode class a "parent" variable, like the layer. But I was wondering if there is a way without adding new variables, to add subclassing. Sort of like small menus in code.

    Is this possible? Code sections using nothing more than a single class/other.

  8. #48
    PowerPoster boops boops's Avatar
    Join Date
    Nov 2008
    Location
    Holland/France
    Posts
    3,201

    Re: Layer rendering (image program)

    I don't see the problem with giving the PictureNode class a Parent field. You could pass its value as a parameter to the PictureNode.New sub:
    Code:
    Dim pictureNode As New PictureNode(Me)
    Another idea that crosses my mind is to give the Layer a Shared Event which passes the instance as an argument, and which is handled in the PictureNode class. I'm a bit hazy about the details though, and maybe it wouldn't be worth the effort.

    BB

  9. #49

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Layer rendering (image program)

    Well now I need it even more.

    Example.

    Some layer image types do contain rotation, location and size, others don't.
    The selection square must access these types, but I don't want to pollute the clean layer code with lots of properties.

    Now I want to add a subclass called "members", with inside all the different properties that can exist. This subclass needs to access the different classes inside the parent, referencing back and then forward. Is it completely impossible to add sub-menus in classes? Instead of saying:
    Code:
    Layers(0).SetLocation(0, 0)
    Say:
    Code:
    Layers(0).Members.Location = new point(0, 0)
    This is one of those things that tricked me for quite a while. As example, the webbrowser control contains a lot of subclasses that actually access the parent's window. It would be really useful if I can add "menus of code" to make it all a lot cleaner.

    In your example you gave the picturenode class a "parent" property, which is then set on the "new" sub. I want to prevent any odd referencing problems; since I sometimes completely replace the picturenode variable of a layer with a new one. Then I would need to add the entire referencing of the node in the code, making it messy.

    I'll formulate the question again; is it possible to add "menus of code" WITHOUT giving the new menu a parent property?
    Last edited by bergerkiller; Aug 13th, 2010 at 12:23 PM.

  10. #50

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Layer rendering (image program)

    Bump.

    When you insert a class inside a class, you can access this "subclass", but only the shared properties inside the "subclass". I want to access normal variables in the "subclass" when the class is declared as a variable. I don't want to hassle with parent variables in the subclass.

    so:
    Dim a as new mainclass()
    a.subclass.value = 5

  11. #51
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Layer rendering (image program)

    In your last piece of code, 'subclass' is a property, which holds an instance of a different class. Often, there will be only one instance ever, and you can create and assign this instance in the constructor of the main class.

    vb.net Code:
    1. Public Class MainClass
    2.  
    3.    Public Sub New()
    4.       _SubClass = New SubClass()
    5.    End Sub
    6.    
    7.    'I'm not sure if this is allowed (name conflict)
    8.    Private _SubClass As SubClass
    9.    Public ReadOnly Property SubClass As SubClass
    10.       Get
    11.          Return _SubClass
    12.       End Get
    13.    End Property
    14.  
    15.  
    16.    Public Sub UseValue()
    17.       MessageBox.Show(Me.SubClass.Value.ToString())
    18.    End Sub
    19.  
    20. End Class
    21.  
    22. Public Class SubClass
    23.  
    24.    Public Property Value As Integer
    25.  
    26. End Class

    This is a really simple example. If you want a more in-depth, real-life example, take a look at my 'Customizable Menu/Tool/StatusStrips' codebank thread, especially the AppearanceControl component. It has a lot of these 'menus' you mention. For example, to get the highlight color of the border of a select button, I use this code:
    Code:
    Return ac.CustomAppearance.ButtonAppearance.SelectedAppearance.BorderHighlight
    ac is the AppearanceControl.
    CustomAppearance is property returning an instance of a class in the AppearanceControl.
    ButtonAppearance is a property returning an instance of a class in the CustomAppearance class.
    SelectedAppearance is a property returning an instance of a class in the ButtonAppearance class.
    And finally, BorderHighlight is a color property.

    I also posted them on 'the code project' with a bit more explanation:
    http://www.codeproject.com/KB/menus/...le_strips.aspx

  12. #52

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Layer rendering (image program)

    I must have been unclear: the subclass must be able to interact with the mainclass. But as I see it now, it is impossible to communicate back from a subclass. This, because "subclass" is not added to something by default, so you can't call a "parent". I'll just stick with the parent system then, since it seems to be the only way of doing it.

    If anyone knows of a way of doing this subclassing in a global way; subclasses and classes can both access the same variables; please post a replay.

  13. #53
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Layer rendering (image program)

    The only way the subclass is able to interact with the parent is by supplying it with the parent. The two classes have no relationship whatsoever (so calling it a subclass is not a very good choice either). It's like an apple in a bag. The apple is the 'subclass' and the bag is the 'mainclass'. But the apple doesn't know anything about the bag, you are free to put the apple in a different bag or even outside of any bags.

    The only way the subclass is going to know about the parent class is by providing the parent class to the subclass, preferably in the constructor. Here is an example from the customizable toolstrips I linked to previously.

    The AppearanceControl has a 'CustomAppearance' property of type 'AppearanceProperties'. In the constructor of the AppearanceControl class, I create a new instance of the AppearanceProperties class and pass "Me", the current AppearanceControl:
    Code:
    Public Class AppearanceControl
       Inherits Component
    
       Public Sub New()
          _CustomAppearance = New AppearanceProperties(Me)
       End Sub
    
       Private _CustomAppearance As AppearanceProperties
       Public Property CustomAppearance() As AppearanceProperties
            Get
                Return _CustomAppearance
            End Get
            Set(ByVal value As AppearanceProperties)
                _CustomAppearance = value
            End Set
        End Property
    
    End Class
    The AppearanceProperties class has more 'subclasses', for example the ButtonAppearance property of type ButtonAppearanceProperties, and these subclasses also require the parent AppearanceControl, so I again I pass it along:
    Code:
    Public Class AppearanceProperties
    
       Public Sub New(ByVal appearanceControl As AppearanceControl)
          _ButtonAppearance = New ButtonAppearanceProperties(appearanceControl)
       End Sub
    
       Private _ButtonAppearance As ButtonAppearanceProperties
       Public Property ButtonAppearance() As ButtonAppearanceProperties
          Get
             Return _ButtonAppearance
           End Get
           Set(ByVal value As ButtonAppearanceProperties)
             _ButtonAppearance = value
          End Set
       End Property
    
    End Class
    The ButtonAppearanceProperties class has yet another few subclasses, namely the SelectedAppearance, CheckedAppearance and PressedAppearance properties (all of their own types)
    Code:
    Public Class ButtonAppearanceProperties
    
    	Public Sub New(ByVal appearanceControl As AppearanceControl)
    		_SelectedAppearance = New SelectedButtonAppearanceProperties(appearanceControl)
    		_CheckedAppearance = New CheckedButtonAppearanceProperties(appearanceControl)
    		_PressedAppearance = New PressedButtonAppearanceProperties(appearanceControl)
    	End Sub
    
    	Private _SelectedAppearance As SelectedButtonAppearanceProperties
    	Public Property SelectedAppearance() As SelectedButtonAppearanceProperties
    		Get
    			Return _SelectedAppearance
    		End Get
    		Set(ByVal value As SelectedButtonAppearanceProperties)
    			_SelectedAppearance = value
    		End Set
    	End Property
    
    	Private _CheckedAppearance As CheckedButtonAppearanceProperties
    	Public Property CheckedAppearance() As CheckedButtonAppearanceProperties
    		Get
    			Return _CheckedAppearance
    		End Get
    		Set(ByVal value As CheckedButtonAppearanceProperties)
    			_CheckedAppearance = value
    		End Set
    	End Property
    
    	Private _PressedAppearance As PressedButtonAppearanceProperties
    	Public Property PressedAppearance() As PressedButtonAppearanceProperties
    		Get
    			Return _PressedAppearance
    		End Get
    		Set(ByVal value As PressedButtonAppearanceProperties)
    			_PressedAppearance = value
    		End Set
    	End Property
    
    End Class
    Finally, these classes use the parent class (AppearanceControl). For example, the SelectedButtonAppearanceProperties class has a GradientBegin color property, and when that is set, a method on the AppearanceControl class must be called:
    Code:
    Public Class SelectedButtonAppearanceProperties
    
    	Private ap As AppearanceControl
    	
    	Public Sub New(ByVal appearanceControl As AppearanceControl)
    		ap = appearanceControl
    	End Sub
    
    	Private _GradientBegin As Color = Color.FromArgb(255, 255, 222)
    	Public Property GradientBegin() As Color
    		Get
    			Return _GradientBegin
    		End Get
    		Set(ByVal value As Color)
    			_GradientBegin = value
    			
    			' AppearanceControl is finally used here:
    			If ap IsNot Nothing Then ap.OnAppearanceChanged(EventArgs.Empty)
    		End Set
    	End Property
    	
    End Class
    As you can see, I pass along the parent class (AppearanceControl) to each subclass, and the subclasses pass this same parent class along to their subclasses, and so on. This is basic object oriented programming: if a class needs to use another class, then you just pass it along. This is the way it can be done and this is the way is should be done.

  14. #54

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Layer rendering (image program)

    Great example!

    And yeah, that is what I had in mind with "parent", was just wondering if it was possible to do without using a "parent".

    Old question comes back to mind now, while I was working on the draw sub:
    - How can I draw images with an inverted color effect (how do I set the imageattribute to do this); and how can I combine this with a changed color imageattribute.

    At this point, the layers pass certain values over to it's children; the color at this point. This color is combined with the children' own color by factorizing. But, in the future layers can get certain render effect, such as grayscale; blackscale; inverted colors and maybe even blur. How can I do all this; and how can I combine two of these imageattribute effects?

    This is the function to get the color image attribute:
    Code:
        Public Shared Function ToImageAttribute(ByVal Color As System.Drawing.Color) As System.Drawing.Imaging.ImageAttributes
            Dim cmxPic As New System.Drawing.Imaging.ColorMatrix
            cmxPic.Matrix00 = Color.R / 255
            cmxPic.Matrix11 = Color.G / 255
            cmxPic.Matrix22 = Color.B / 255
            cmxPic.Matrix33 = Color.A / 255
            ToImageAttribute = New System.Drawing.Imaging.ImageAttributes
            ToImageAttribute.SetColorMatrix(cmxPic, System.Drawing.Imaging.ColorMatrixFlag.Default, System.Drawing.Imaging.ColorAdjustType.Bitmap)
        End Function
    EDIT

    Never mind all, I figured out how to do all this using the colormatrix:
    | Output R | Output G | Output B | Output A | XXXXXXX
    Input R 0 0 0 0 0
    Input G 0 0 0 0 0
    Input B 0 0 0 0 0
    Input A 0 0 0 0 0
    Factor 0 0 0 0 0

    A colormatrix just divides the input color channels over the output channels, you you can swap red with blue color channel.
    Negatives can be made using a negative value. Values are ranging from -1 to 0 for negatives and 0 to 1 for positives.
    To make a negative, give 0x0; 1x1; 2x2 -1 and give 4x0; 4x1; 4x2 1 to prevent the image from turning black.
    Last edited by bergerkiller; Aug 15th, 2010 at 05:37 PM.

Page 2 of 2 FirstFirst 12

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width