Results 1 to 23 of 23

Thread: API: what is the best function for draw an image using 4 points?

  1. #1

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    API: what is the best function for draw an image using 4 points?

    the BitlBlt() draw the image using just the position and size(form origin and destination).
    but imagine if the image is rotated... how we can draw it?
    VB6 2D Sprite control

    To live is difficult, but we do it.

  2. #2
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,145

    Re: API: what is the best function for draw an image using 4 points?

    Depends on the language, and the library being used.
    You mentioned API, and if you're talking Windows API, there are a number of APIs functions that can be used.
    If you're restricting yourself to the GDI API, there are two methods I've used.
    If you're using the GDI+ API, there are still essentially the same two methods, but they are easier to implement as the functions are wrapped by .Net managed graphic calls so you can call them using the .Net Graphics object methods if you're using a .Net managed based language, but the GDI+ methods can be called from VB6 as well.

    The two methods I've used with GDI and VB6, are
    1. plgblt (parallelogram blit) where you calculate the three corners of a rotated square and then plgblt an image to that rotated square to do the rotation. You mentioned four points, and while the parallelogram has four points, the symmetry of a parallelogram (like the symmetry of a rectangle or square) means you can calculate the fourth point once you have the first three, so the method saves a little time by not having you pass two extra parameters for the fourth point to the method.

    2. Enable Advanced drawing mode using SetGraphicsMode, then use SetWorldTransform to define a rotation and then just use bitblt.

    I think the second method is actually more flexible, as it can effect all VB6 drawing, not just API drawing, so you can set up the rotation, and draw grid lines, or other figures using VB6's normal line, and circle drawing commands and they will be rotated by the amount specified.

    You can use GDI+ with VB6 as well, although I haven't done much of it myself, so you have the same two capabilities above built into the GDI+ API, but with perhaps easier implementation, I don't know.
    In any case, the plgblt type operation is included as one of the overloads of the DrawImage methods, and the SetWorldTransform type method is included as various TransForm methods calls, in particular, the TransformRotate method to implement a rotation.

    There are other GDI+ Matrix manipulations available as well, which I haven't really used, but if you setup a matrix, you can use a RotateAt method call to essentially combine a couple of things necessary for rotation of an object at a certain location within the drawing, but I haven't used it. I've just relied on the Transform methods of the current matrix of the Graphics object to do those manipulations.

    But as I mentioned above, I didn't use GDI+ with VB6 in those cases. I've been using VB.Net, which wraps those GDI+ calls with methods built into the Graphics Object that .Net uses for WinForm applications.

    I'm sure I've posted some plgblt versions of VB6 code on the forum, and I'm pretty sure dilettante has as well. We've both also probably posted SetWorldTransform versions as well.
    A quick search finds this VB6 example of SetWorldTransform posted back in 2013, one of my earliest posts on this forum.

    Of course there are more performant ways by using other libraries instead of the basic Windows API, but I'll leave that to others to describe as I haven't done a lot of that.
    Last edited by passel; Sep 20th, 2020 at 09:47 AM.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  3. #3

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    Re: API: what is the best function for draw an image using 4 points?

    passel: the plgblt() is:
    Code:
    Private Declare Function PlgBlt Lib "GDI32.dll" (ByVal hDCDest As Long, _
        ByRef lpPoint As PointAPI, ByVal hdcSrc As Long, ByVal nXSrc As Long, _
        ByVal nYSrc As Long, ByVal nWidth As Long, ByVal nHeight As Long, _
        ByVal hbmMask As Long, ByVal xMask As Long, ByVal yMask As Long) As Long
    but i need some corrections: what is the lpPoint? is the rotated rectangle points?
    the hbmMask is for the transparency(hide the image backcolor)?
    VB6 2D Sprite control

    To live is difficult, but we do it.

  4. #4
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,145

    Re: API: what is the best function for draw an image using 4 points?

    The lpPoint array is the array of the first three points of the parallelogram, the fourth is calculated. So they are the rotated rectangle points, when you want a rotated rectangle. But they will create a parallelogram, so the corners aren't restricted to 90 degree corners. You can create isometric looking 3D rectangular faces as well, if you don't calculate your corners correctly. But you might want that on purpose.

    If you provide a monochrome (1-bit per pixel image) bitmap, it will define which pixels are drawn in the blit. So, it could hide the "backcolor", if the mask pixel positions match the backcolor pixel positions, but it will "hide" any color, since it is a mask that defines the parts to be drawn, and is not associated with a color.

    Here is a post that shows the plgblt in action, and if you read the rest of the thread, there are some of the other examples of the methods as well.

    Also, Here is a thread where dilettante was playing around with plgblt.

    Of course, there is an example of using the plgblt, with masking also, in a post of one of your earlier threads.
    This example is not doing 2D rotation, it is using plgblt (if the option is selected) to draw the walls and top and bottom of a number of isometric 3d blocks on a plane, and you can rotate and tip the plane up and down to see the blocks from different view points. There is the option to enable using plgblt do draw the blocks, and another option to turn the masking on or off. When the masking is on, the texture that make up the "walls" of the block have rectangular cutouts, that look like windows in the side of a building, and you can see through them to view other parts of other walls through the openings.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  5. #5

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    Re: API: what is the best function for draw an image using 4 points?

    please i need understand more 1 thing: imagine that i have 1 plane.
    we have the vector's A, B, C and D(the plane have 4 vectors)... every vector have their own X,Y and Z(thing that i know them, so we can use VA, VB, VC and VD to identify the plane vectors....
    now how can i add the vectors on point's array?
    VB6 2D Sprite control

    To live is difficult, but we do it.

  6. #6
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,145

    Re: API: what is the best function for draw an image using 4 points?

    We don't use four vectors to define the plane, we use four points.

    Are the four points VA, VB, VC and VD that define your plane four corners of a rectangle or square?

    Assuming VA is the "upper left" and going clockwise(VB, VC, VD), then VD.X = VA.X and VD.Y = VC.Y.

    So, you just pass VA, VB and VC in the points array, and VD is calculated from VA and VC (the two points it connects to).
    This works for any parallelogram, not just squares and rectangles.

    Z is not involved in 2D graphics, and bitblt and plgblt are 2D functions.
    Last edited by passel; Sep 21st, 2020 at 05:02 PM.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  7. #7

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    Re: API: what is the best function for draw an image using 4 points?

    correct me: Points is 2D and Vectors is 3D, right?
    can i use on these way:
    Code:
    dim VA as POINTAPI
    dim VB as POINTAPI
    dim VC as POINTAPI
    dim VD as POINTAPI
    dim PlgBltpoint(4) as POINTAPI
    
    'here i know their X and Y values(i know convert 3D to 2D)
    'then i can add the points:
    PlgBltpoint(0)=VA
    PlgBltpoint(1)=VB
    PlgBltpoint(2)=VC
    PlgBltpoint(3)=VD
    
    'add it to the function:
    PlgBlt PlgBltpoint.....
    is like:
    (upper-left)VA - VB(upper-right)
    (low-right)VC - VD(low-left)
    ?
    like you see, i don't calculate the 3rd or 4th point...
    but i accept corrections
    VB6 2D Sprite control

    To live is difficult, but we do it.

  8. #8
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,145

    Re: API: what is the best function for draw an image using 4 points?

    plgblt only takes three points.

    You can't force it to take four points.

    You always pass it the first three points, and it creates a parallelogram by computing the fourth point to fit the rules that define what a parallelogram is, i.e. a four sided figure where the opposite sides are the same length, and the opposite sides are parallel.

    Also, 3D doesn't come into it with plgblt.

    You can project 3D rectangles to 2D yourself and then pass these 2D points to plgblt. But that is assuming you don't use perspective, i.e. the height of the deeper end of the rectangle is still the same height as the closer end of the rectangle (so you get a parallelogram, not a trapazoid), then you can fill that parallelogram with plgblt, which is what I do in the third link in post #4 example.

    This can look neat, but there are two issues.
    1. Since there is no shrinking of height in distance, your mind tells you the further away lines are taller than the closer lines, i.e. you loose perspective.
    2. The texture will fill the parallelogram linearly, whereas to have the illusion of depth, the texture should not fill linearly, but be relatively spread at the closer end, and getting more condensed as it retreats into the distance.

    If you're still trying to find a simple API call that will fill a trapezoid shaped figure with an image, especially with perspective calculations, there isn't one. You need to move away from the API and use a graphics library that does support filling 3D surfaces. An in most cases, those won't actually use manually calculated trapezoid areas. Graphic libraries and hardware are designed to break figures up into triangles, primarily because a triangle always has to be in a single plane, so all the points will have the same orthogonal which simplifies other calculations. The hardware is designed to be very efficient at filling these triangles with proper perspective rendered textures.

    If you want to fill trapezoid projections with perspective textures, then you're going to have to fill it yourself, either pixel by pixel, or if you're aligned to certain axis, you can use stretchblt to fill the area by rows of pixels. Its a lot of work, and is why that has been pushed to the graphic cards with their own processors, to do all this calculation and manipulation on their processors and their memory, rather than taxing the computer's processor and memory.

    An aside:
    I realized I oversimplified my calculation of the fourth point in post #6. Since none of the sides have to be parallel with the coordinate axis, the fourth point is not simply the X value of one point, and the Y value of another, it is adding the delta between the second and third points added to the first point.

    x0,y0 first point
    x1,y1 second point, clockwise from first
    x2,y2 third point, clockwise from second.

    Fourth point is x0 + (x2 - x1), y0 + (y2 - y1)
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  9. #9

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    Re: API: what is the best function for draw an image using 4 points?

    i'm sorry passel, but can i rotate the image in X,Y and Z and then draw it?
    maybe it can resolve my problem more easy, i think.
    VB6 2D Sprite control

    To live is difficult, but we do it.

  10. #10
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,145

    Re: API: what is the best function for draw an image using 4 points?

    Do what you want.

    plgblt is a very simple thing. It can only do what it can do. You can only do what you can do.
    Whether plgblt can be useful to what you want to do, is for you to decide.

    The only thing that plgblt can do is essentially a stretchblt of a rectangular bitmap into a parallelogram. And it can have a corresponding 1-bit depth monochrome mask to identify which pixels in the rectangular bitmap will be transferred to the parallelogram.
    That is it.
    It has nothing to do with planes, 3D coordinates, or rotation for that matter. It can only skew a rectangular shape into a parallelogram. But you can calculate the corners of the parallelogram so that the image ends up being rotated in 2D.

    Your original question said you can use bitblt to transfer an area of a rectangular image to a another rectangular area.
    Those transfers have to be aligned with the X and Y axis of the screen or bitmap.
    You asked how you can rotate the image. The implication is that you are asking how can you rotate the rectangular area of the image, so it is still a rectangle, but is rotated so the edges are not aligned with the X,Y axis of the screen or bitmap.
    PlgBlt can be used to do that.

    Parallelogram. Parallelogram. Parallelogram.

    If you don't understand what a Parallelogram is, you should review your basic Geometry Lessons.

    You can do a 3d rotation of 2D rectangle located in 3D space (X, Y, Z) and then draw it with plgblt, only if your 2D rectangle in 3D space ends up being projected to 2D as a parallelogram, i.e. you project it back to 2D, and don't use perspective, and don't care that your resulting image pixels will also not be drawn with perspective when the image is transferred to the parallelogram shape.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  11. #11

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    Re: API: what is the best function for draw an image using 4 points?

    passel: correct me more things:
    - polygon() function is only for triangles or can be for rectangles?
    - the brush, on polygon(), can draw by shaped rotation way(think on pyramid for example)?
    VB6 2D Sprite control

    To live is difficult, but we do it.

  12. #12
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,145

    Re: API: what is the best function for draw an image using 4 points?

    What does the documentation say?

    Its a polygon, so that means many lines.

    You can pass a number of points to the polygon function.
    The function will automatically draw a line from the last point to the first, so you don't have to include the first point again to close the polygon.
    The minimum number of points you can pass is 2.
    The result will be a line, as the function draws a line from the first point to the second, and then automatically draws a line from the second back to the first, which is on top of the line already drawn.

    I don't know what the maximum number of points is, but it certainly isn't limited to 3 or 4. I would assume you could do hundreds of points, but I don't know if there is an established limit.

    You can rotate the points that make up the polygon of course, but that isn't going to rotate the brush that fills it.
    I think GDI+ allows rotating a brush, but it still will be a flat image of the brush filling the polygon, not a 3D type image.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  13. #13

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    Re: API: what is the best function for draw an image using 4 points?

    thinking on GDI or GDIPLUS they use GPU or it's a different thing?
    i need understand these for i choose the right thing for draw the texture
    VB6 2D Sprite control

    To live is difficult, but we do it.

  14. #14
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,145

    Re: API: what is the best function for draw an image using 4 points?

    I'm not sure if GDI or GDI+ take advantage of the GPU for most of their functions. To take advantage of the GPUs on a graphics card you need to use libraries that do. If you were using a WPF form, then it does take advantage of the GPUs for some things. The primary examples, of course would be DirectX or OpenGL. There are other libraries as well, and some of them may use DirectX or OpenGL under the hood.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  15. #15

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    Re: API: what is the best function for draw an image using 4 points?

    passel imagine 1 image for wall. is the texture.
    like you know the wall have several directions... imagine seen a wall in front of you, seems a rectangle... now imagine that the next wall is rotated 90... but using the position and the size, can we calculate the degree(in these case is 90)?
    VB6 2D Sprite control

    To live is difficult, but we do it.

  16. #16
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,145

    Re: API: what is the best function for draw an image using 4 points?

    If you want to restrict your 3D view to a simple view, like you are walking around on a flat plane, and you only rotate around the Y axis, i.e. only your heading changes, then that can simplify things.

    But we've been through that for a long time in one of your previous threads.

    Even if you simplify your case to where you are just running around on a plane and drawing textured walls laid out in a grid pattern, like buildings along streets that run north-south and east-west, or an indoor maze with walls, floor and ceiling, laid out on a grid, to draw those with a 3D perspective, you will need to change the rectangles into trapezoid shape when the walls are not perpendicular to your view.
    If you think of the wall that is in front of you is 0 degrees, so you see it in front of you as a rectangle. If you turn your head to the left or right, then the rectangle moves the opposite direction of your view, and it becomes trapezoid shaped. If you turn your head left, the smaller end of the trapezoid is to the left, as that end of the wall is relatively further away from your eye point.

    The main thing is, there isn't an Win Api call that will fill that trapezoid shape with an image that has been transformed to fill it with perspective. You can use polygon to fill the trapezoid with a brush, but the brush would fill the shaped with the same texture that is used to fill the rectangle. The wall may be at 30 degrees, or 60 degrees, but the texture would still look as it did at 0 degrees.

    The old school way of filling these trapezoid is to calculate the depth that each horizontal pixel represents.
    For instance, say the rectangle was 400 pixels wide, and you had a 400 pixel wide image to fill it.
    Now, if you place a wall that was the same size, but at 90 degrees, and off to one side, then you would end up with a trapezoid. Depending on the position of the wall, the "near" end of the trapezoid could be much taller than the original rectangle, and the "far" end could be much smaller. The horizontal width of the trapezoid on the screen would be much narrower than the 400 pixels of the original width at 0 degrees.

    Lets say it was now 100 pixels wide, on the screen. That means the 400 pixel wide texture needs to be mapped to 100 pixels.
    A simple approach is to simply stretch blit the texture into a 100 pixel wide image.
    Now you can loop through those 100 pixels and stretch each vertical line of the image one by one to fit the vertical height of your trapezoid height at that horizontal point of your trapezoid.
    This would be similar to what the plgblt does for a parallelogram, but now you're doing it manually for the trapezoid shape.

    The main issue is, that for perspective, the texture shouldn't be stretched evenly across the 100 pixels. The pixels closer to your eye should be "wider" then the pixels further from your eye. So, the texture should probably be expanded on the closer end, and compressed on the far end.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  17. #17

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    Re: API: what is the best function for draw an image using 4 points?

    think with me on these way:
    - the Z texture must be the Z of the shape(even the Z Depth).. the original texture is a rectangle shape;
    - now i can rotate the image\shape(converting radians to degrees );
    - the conversion from 3D to 2D give me the draw position.
    until here i can do it.... but now how i can draw the image on shape?
    i think the best is the transparentblt() API function for draw it without backcolor.
    but i need more help on 1 thing: how can i rotate it on picturebox(ok.. i can use a memory HDC), on positive position and right size?
    (yes the rotation can make some pixels outside the picturebox size\position)
    VB6 2D Sprite control

    To live is difficult, but we do it.

  18. #18

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    Re: API: what is the best function for draw an image using 4 points?

    passel finally i get something:
    Code:
    'Get the four vectors
        
        'Floor:
        'Vector1: low-left
        FillPosition3D NewPosition3D(0), Position.X, Position.Y, Position.Z
        NewPosition3D(0) = Rotate(NewPosition3D(0), Rotation, RotatedPosition)
        
        
        'Vector2: upper-left
        FillPosition3D NewPosition3D(1), Position.X, Position.Y, Position.Z + Size.ZDepth
        NewPosition3D(1) = Rotate(NewPosition3D(1), Rotation, RotatedPosition)
        
        'Vector3: upper-right
        FillPosition3D NewPosition3D(2), Position.X + Size.Width, Position.Y, Position.Z + Size.ZDepth
        NewPosition3D(2) = Rotate(NewPosition3D(2), Rotation, RotatedPosition)
        
        
        'Vector4: low-right
        FillPosition3D NewPosition3D(3), Position.X + Size.Width, Position.Y, Position.Z
        NewPosition3D(3) = Rotate(NewPosition3D(3), Rotation, RotatedPosition)
    
    'Convert all 3D vectors to 2D vectors(for screen):
        Dim i As Integer
        For i = 0 To 3
            Points(i) = ConvertPositon3DTo2D(NewPosition3D(i), WorldSize)
        Next i
        
        'change the brush and pen:
        FillStyle = vbFSSolid
        'FillColor = vbRed
        
        
        DrawStyle = DrawStyleConstants.vbInvisible
        Polygon Me.hdc, Points(0), 4
        Dim TexturePoints(3) As POINTAPI
        TexturePoints(0) = Points(1) 'upper-left
        TexturePoints(1) = Points(2) 'upper-right
        TexturePoints(2) = Points(0) 'low-left
        If (PlgBlt(Me.hdc, TexturePoints(0), Picture1.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, &O0, &O0, &O0) = 0) Then MsgBox CStr(GetLastError())
    now i get the some results
    my problem is:
    - why isn't the entire street(there is a color instead the image)?
    - the street is more big than the image, so the image is stretch... how can i avoid these problem?
    results:
    https://imgur.com/a/psX89ZW
    VB6 2D Sprite control

    To live is difficult, but we do it.

  19. #19
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,145

    Re: API: what is the best function for draw an image using 4 points?

    I click on the link https://imgur.com/a/psX89ZW with several browsers and I don't see any image, so I won't bother trying to guess.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  20. #20

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    Re: API: what is the best function for draw an image using 4 points?

    Name:  pgl.jpg
Views: 55
Size:  21.3 KB
    VB6 2D Sprite control

    To live is difficult, but we do it.

  21. #21

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    Re: API: what is the best function for draw an image using 4 points?

    what fails seems to be the shape Width on TexturePoints()
    VB6 2D Sprite control

    To live is difficult, but we do it.

  22. #22
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,145

    Re: API: what is the best function for draw an image using 4 points?

    I guess since we don't have the code, we can't step through the code to examine the values of the points.
    It doesn't look much like a floor to me.

    Also, the points drawing the red don't seem to agree with the points used in the plgblt.
    What are the values of the four points in the Points array?
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  23. #23

    Thread Starter
    PowerPoster joaquim's Avatar
    Join Date
    Apr 2007
    Posts
    3,394

    Re: API: what is the best function for draw an image using 4 points?

    heres the entire code:
    Code:
    Option Explicit
    
    Private Declare Function GetLastError Lib "kernel32" () As Long
    Private Declare Function GetActiveWindow Lib "user32" () As Long
    
    Private Declare Function ArrPtr Lib "msvbvm60" Alias "VarPtr" (Ptr() As Any) As Long
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    
    'Get Key state:
    Const KEY_DOWN As Integer = &H8000
    Private Declare Function GetKeyState Lib "user32.dll" (ByVal nVirtKey As KeyCodeConstants) As Integer
    
    'Draw array Vertices:
    Private Type POINTAPI
        X As Long
        Y As Long
    End Type
    Private Declare Function PlgBlt Lib "gdi32" ( _
    ByVal hdcDest As Long, lpPoint As POINTAPI, ByVal hdcSrc As Long, ByVal nXSrc As Long, ByVal nYSrc As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hbmMask As Long, ByVal xMask As Long, ByVal yMask As Long) As Long
    Private Declare Function Polygon Lib "gdi32" (ByVal hdc As Long, lpPoint As POINTAPI, ByVal nCount As Long) As Long
    
    Private Enum Coordenates
        None
        Z
        X
        Y
    End Enum
    
    Private Type Position3D
        X As Double
        Y As Double
        Z As Double
    End Type
    
    Private Type Angle3D
        X As Double
        Y As Double
        Z As Double
        RotationPosition3D As Position3D
    End Type
    
    Private Type Size3D
        Width As Double
        Height As Double
        ZDepth As Double
        distance As Double
    End Type
    
    Private Type Player
        Position As Position3D
        Movement As Position3D
        Size As Size3D
        angle As Angle3D
        MoveCoordenates As Coordenates
    End Type
    
    Private Type Camera
        Position As Position3D
        Size As Size3D
    End Type
    
    Private Const Pi As Double = 3.14159265358979
    Dim Angletest As Angle3D
    
    Dim Player1 As Player
    Dim camera1 As Camera
    
    Private Function GetDimensionsArray(arrays() As Position3D) As Integer
        Dim lPtr            As Long
        Dim nRetVal         As Integer
        
        Call CopyMemory(lPtr, ByVal ArrPtr(arrays), 4)
        If lPtr <> 0 Then
            Call CopyMemory(nRetVal, ByVal lPtr, 2)
        End If
        GetDimensionsArray = nRetVal
    End Function
    
    
    Private Function IsKeyDown(ByVal nVirtKey As KeyCodeConstants) As Boolean
        If GetKeyState(nVirtKey) And KEY_DOWN Then
            IsKeyDown = True
        Else
            IsKeyDown = False
        End If
    End Function
    
    Private Sub LetPoint3dArray(la() As Position3D, ParamArray va() As Variant)
        ' No error trapping, so use with caution.
        Dim i       As Long
        Dim j       As Long
        Dim k      As Long
    
        k = (UBound(va) + 1) \ 3 - 1
        ReDim la(k)
        For i = 0& To k
            la(i).X = va(j): j = j + 1
            la(i).Y = va(j): j = j + 1
            la(i).Z = va(j): j = j + 1
        Next
    End Sub
    
    Private Sub FillPosition2D(Position As POINTAPI, X As Long, Y As Long)
        Position.X = X
        Position.Y = Y
    End Sub
    
    Private Sub FillPosition3D(Position As Position3D, X As Double, Y As Double, Z As Double)
        Position.X = X
        Position.Y = Y
        Position.Z = Z
    End Sub
    
    Private Sub FillSize3D(Size As Size3D, Width As Double, Height As Double, ZDepth As Double)
        Size.Width = Width
        Size.Height = Height
        Size.ZDepth = ZDepth
    End Sub
    
    Private Function GetLinePosition(Origin As Position3D, Destiny As Position3D, ActualPosition As Double, Optional WhatCoordenate As Coordenates = Z) As Position3D
        
        'Getting the AB vector(B-A or Destiny-Origin):
        Dim AB As Position3D
        AB.X = Destiny.X - Origin.X
        AB.Y = Destiny.Y - Origin.Y
        AB.Z = Destiny.Z - Origin.Z
        
        Dim NewPosition As Position3D
        Dim T As Double
        'depending on player movement(for get 1 coordenate and the T), we get the point coordenate:
        If (WhatCoordenate = X) Then
            'P.x = O.x + t*AB.x
            't = (P.x - O.x) / AB.x
            If (AB.X = 0) Then
                T = 0
            Else
                T = (ActualPosition - Origin.X) / AB.X
            End If
            NewPosition.X = ActualPosition
            NewPosition.Y = Origin.Y + AB.Y * T
            NewPosition.Z = Origin.Z + AB.Z * T
            
        ElseIf (WhatCoordenate = Y) Then
            'P.y = O.y + t*AB.y
            't = (P.y - O.y) / AB.y
            
            If (AB.Y = 0) Then
                T = 0
            Else
                T = (ActualPosition - Origin.Y) / AB.Y
            End If
            NewPosition.Y = ActualPosition
            NewPosition.X = Origin.X + AB.X * T
            NewPosition.Z = Origin.Z + AB.Z * T
        ElseIf (WhatCoordenate = Z) Then
            'P.z = O.z + t*AB.z
            't = (P.z - O.z) / AB.z
            
            If (AB.Z = 0) Then
                T = 0
            Else
                T = (ActualPosition - Origin.Z) / AB.Z
            End If
            NewPosition.Z = ActualPosition
            NewPosition.X = Origin.X + AB.X * T
            NewPosition.Y = Origin.Y + AB.Y * T
        End If
        GetLinePosition = NewPosition
    End Function
    
    
    Private Function ConvertPositon3DTo2D(Position As Position3D, World3DSize As Size3D) As POINTAPI
        
        Dim ConvertedPosition As POINTAPI
        Dim PosZZDepth As Long
        
        Dim Width As Double
        Dim Height As Double
        
        'sum Z position with cam world distance:
        PosZZDepth = Position.Z + World3DSize.distance
        If (PosZZDepth = 0) Then PosZZDepth = 1 'avoiding division by zero
        
        'getting center of the screen center:
        If (World3DSize.Width = 0) Then World3DSize.Width = 1 'avoiding division by zero
        Width = World3DSize.Width / 2
        If (World3DSize.Height = 0) Then World3DSize.Height = 1 'avoiding division by zero
        Height = World3DSize.Height / 2
        
        
        'avoid drawing on back of the camera:
        If (PosZZDepth <= World3DSize.distance) Then
             PosZZDepth = 1
             'World3DSize.distance = 1
        End If
        
        'convert 3D(X, Y, Z) to 2D(X,Y):
        'ConvertedX = (ActualX * CamDistance /(CamDistance + ZPosition)) + HalfCenterOfWidth
        'ConvertedY = (ActualY * CamDistance /(CamDistance + ZPosition)) + HalfCenterOfHeight
        ConvertedPosition.X = (Position.X * World3DSize.distance / PosZZDepth) + Width
        ConvertedPosition.Y = (Position.Y * World3DSize.distance / PosZZDepth) + Height
        
        ConvertPositon3DTo2D = ConvertedPosition
    End Function
    
    Private Function IsOnCamera(VerticePosition As Position3D, CameraPosition As Position3D, CameraSize As Size3D) As Boolean
        If (((VerticePosition.Z) >= CameraPosition.Z) And ((VerticePosition.Z) <= (CameraPosition.Z + CameraSize.ZDepth)) _
        And (((VerticePosition.Y) >= CameraPosition.Y) And ((VerticePosition.Y) <= (CameraPosition.Y + CameraSize.Height))) _
        And (((VerticePosition.X) >= CameraPosition.X) And ((VerticePosition.X) <= (CameraPosition.X + CameraSize.Width)))) Then
            IsOnCamera = True
        Else
            IsOnCamera = False
        End If
    End Function
        
    Private Function IsCollision3D(ObjectPosition1 As Position3D, ObjectSize1 As Size3D, ObjectPosition2 As Position3D, ObjectSize2 As Size3D) As Boolean
      IsCollision3D = ((ObjectPosition1.X <= (ObjectPosition2.X + ObjectSize2.Width)) And ((ObjectPosition1.X + ObjectSize1.Width) >= ObjectPosition2.X)) And ((ObjectPosition1.Y <= (ObjectPosition2.Y + ObjectSize2.Height)) And ((ObjectPosition1.Y + ObjectSize1.Height) >= ObjectPosition2.Y)) And ((ObjectPosition1.Z <= (ObjectPosition2.Z + ObjectSize2.ZDepth)) And ((ObjectPosition1.Z + ObjectSize1.ZDepth) >= ObjectPosition2.Z))
    End Function
    
    Private Function ConvertDegreesToRadians(Rotation As Angle3D) As Angle3D
        Dim deg2Rad As Double
        deg2Rad = Pi / 180
        
        ConvertDegreesToRadians.X = Rotation.X * deg2Rad
        ConvertDegreesToRadians.Y = Rotation.Y * deg2Rad
        ConvertDegreesToRadians.Z = Rotation.Z * deg2Rad
    End Function
    
    Private Function Rotate(Position As Position3D, Rotation As Angle3D, PositionRotated As Position3D) As Position3D
        Dim ConvertedPosition As Position3D
        Dim RotationInRads As Angle3D
        
        RotationInRads = ConvertDegreesToRadians(Rotation)
        ConvertedPosition = Position
        ConvertedPosition.X = Position.X - PositionRotated.X
        ConvertedPosition.Y = Position.Y - PositionRotated.Y  'reversed because Y increments down
        ConvertedPosition.Z = Position.Z - PositionRotated.Z
        Dim T As Position3D
        
        'Z axis  (Roll)
        T = ConvertedPosition
            ConvertedPosition.X = T.X * Cos(RotationInRads.Z) - T.Y * Sin(RotationInRads.Z)
            ConvertedPosition.Y = T.X * Sin(RotationInRads.Z) + T.Y * Cos(RotationInRads.Z)
        
        'X axis  (Pitch)
        T = ConvertedPosition
            ConvertedPosition.Y = T.Y * Cos(RotationInRads.X) - T.Z * Sin(RotationInRads.X)
            ConvertedPosition.Z = T.Y * Sin(RotationInRads.X) + T.Z * Cos(RotationInRads.X)
      
        'Y axis  (Yaw)
        T = ConvertedPosition
            ConvertedPosition.X = T.Z * Sin(RotationInRads.Y) + T.X * Cos(RotationInRads.Y)
            ConvertedPosition.Z = T.Z * Cos(RotationInRads.Y) - T.X * Sin(RotationInRads.Y)
            
            'Go back to the new position:
            ConvertedPosition.X = ConvertedPosition.X + PositionRotated.X
            ConvertedPosition.Y = ConvertedPosition.Y + PositionRotated.Y
            ConvertedPosition.Z = ConvertedPosition.Z + PositionRotated.Z
            
        Rotate = ConvertedPosition
    End Function
    
    
    Private Sub DrawLine(Origin As Position3D, Destiny As Position3D, Rotation As Angle3D, WorldSize As Size3D)
        Dim Points(2) As POINTAPI
        Dim NewPosition3D(2) As Position3D
        Dim RotatedPosition As Position3D
        Dim test(2, 3) As Position3D
        'MsgBox CStr(GetDimensionsArray(test()))
        With Player1.Position
           FillPosition3D RotatedPosition, .X, .Y, .Z  'rotate using camera Position
        End With
        
        'Line:
        'Calculate Vector1:
        FillPosition3D NewPosition3D(0), Origin.X, Origin.Y, Origin.Z
        NewPosition3D(0) = Rotate(NewPosition3D(0), Rotation, RotatedPosition)
        
        'Calculate Vector2:
        FillPosition3D NewPosition3D(1), Destiny.X, Destiny.Y, Destiny.Z
        NewPosition3D(1) = Rotate(NewPosition3D(1), Rotation, RotatedPosition)
        
        'Testing If Vector0 and Vector1 are inside of camera:
        
        
        
        If (IsOnCamera(NewPosition3D(0), camera1.Position, camera1.Size) = False And _
            IsOnCamera(NewPosition3D(1), camera1.Position, camera1.Size) = False) Then
            Exit Sub
        End If
        
        If (IsOnCamera(NewPosition3D(0), camera1.Position, camera1.Size) = False) Then
            NewPosition3D(0) = GetInCamVector(NewPosition3D(0), NewPosition3D(1))
        End If
        
       If (IsOnCamera(NewPosition3D(1), camera1.Position, camera1.Size) = False) Then
            NewPosition3D(1) = GetInCamVector(NewPosition3D(1), NewPosition3D(0))
        End If
        
        'Convert the Vector1 to 2D:
        Points(0) = ConvertPositon3DTo2D(NewPosition3D(0), camera1.Size)
        
        'Convert the Vector2 to 2D:
        Points(1) = ConvertPositon3DTo2D(NewPosition3D(1), camera1.Size)
        Polygon Me.hdc, Points(0), 2
        
    End Sub
    
    Private Sub DrawPlane(Position As Position3D, Size As Size3D, Rotation As Angle3D, WorldSize As Size3D)
        Dim Points(4) As POINTAPI
        Dim NewPoint As POINTAPI
        Dim NewPosition3D(4) As Position3D
        Dim RotatedPosition As Position3D
        
        'Rotate from player position:
        With Player1.Position
           FillPosition3D RotatedPosition, Player1.Position.X + Player1.Size.Width / 2, Player1.Position.Y + Player1.Size.Height / 2, Player1.Position.Z + Player1.Size.ZDepth / 2 'Camera Position
        End With
        
        'Get the four vectors
        
        'Floor:
        'Vector1: low-left
        FillPosition3D NewPosition3D(0), Position.X, Position.Y, Position.Z
        NewPosition3D(0) = Rotate(NewPosition3D(0), Rotation, RotatedPosition)
        
        
        'Vector2: upper-left
        FillPosition3D NewPosition3D(1), Position.X, Position.Y, Position.Z + Size.ZDepth
        NewPosition3D(1) = Rotate(NewPosition3D(1), Rotation, RotatedPosition)
        
        'Vector3: upper-right
        FillPosition3D NewPosition3D(2), Position.X + Size.Width, Position.Y, Position.Z + Size.ZDepth
        NewPosition3D(2) = Rotate(NewPosition3D(2), Rotation, RotatedPosition)
        
        
        'Vector4: low-right
        FillPosition3D NewPosition3D(3), Position.X + Size.Width, Position.Y, Position.Z
        NewPosition3D(3) = Rotate(NewPosition3D(3), Rotation, RotatedPosition)
        
        'Testing if the plane is on screen:
            
        If ((IsOnCamera(NewPosition3D(0), camera1.Position, camera1.Size) = False) _
            And (IsOnCamera(NewPosition3D(1), camera1.Position, camera1.Size) = False) _
            And (IsOnCamera(NewPosition3D(2), camera1.Position, camera1.Size) = False) _
            And (IsOnCamera(NewPosition3D(3), camera1.Position, camera1.Size) = False)) Then
            'Exit Sub
        End If
        
        If (IsOnCamera(NewPosition3D(0), camera1.Position, camera1.Size) = False) Then
           ' NewPosition3D(0) = GetInCamVector(NewPosition3D(0), NewPosition3D(1))
        End If
        
        If (IsOnCamera(NewPosition3D(1), camera1.Position, camera1.Size) = False) Then
            'NewPosition3D(1) = GetInCamVector(NewPosition3D(1), NewPosition3D(0))
        End If
        
        If (IsOnCamera(NewPosition3D(2), camera1.Position, camera1.Size) = False) Then
            'NewPosition3D(2) = GetInCamVector(NewPosition3D(1), NewPosition3D(2))
            'NewPosition3D(2).X = NewPosition3D(3).X
        End If
        
        
        If (IsOnCamera(NewPosition3D(3), camera1.Position, camera1.Size) = False) Then
            'NewPosition3D(3) = NewPosition3D(0)
            'NewPosition3D(3).X = NewPosition3D(2).X
        End If
        
       
        
        'Convert all 3D vectors to 2D vectors(for screen):
        Dim i As Integer
        For i = 0 To 3
            Points(i) = ConvertPositon3DTo2D(NewPosition3D(i), WorldSize)
        Next i
        
        'change the brush and pen:
        FillStyle = vbFSSolid
        'FillColor = vbRed
        
        'Draw the polygn:
        DrawStyle = DrawStyleConstants.vbInvisible
        Polygon Me.hdc, Points(0), 4
        
        'draw the texture:
        Dim TexturePoints(3) As POINTAPI
        TexturePoints(0) = Points(1) 'upper-left
        TexturePoints(1) = Points(2) 'upper-right
        TexturePoints(2) = Points(0) 'low-left
        If (PlgBlt(Me.hdc, TexturePoints(0), Picture1.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, &O0, &O0, &O0) = 0) Then MsgBox CStr(GetLastError())
    End Sub
    
    Private Function Ceil(dInput As Double) As Double
        ' Ceiling, defined as: the smallest integer that is not smaller than x.
        ' Works for both positive and negative.
        Ceil = Int(dInput): If Ceil <> dInput Then Ceil = Ceil + 1#
    End Function
    
    Private Function GetInCamVector(Origin As Position3D, Destiny As Position3D) As Position3D
        Dim Steps As Double
        Steps = Math.Sqr(Math.Abs(Destiny.X - Origin.X) ^ 2 + Math.Abs(Destiny.Y - Origin.Y) ^ 2 + Math.Abs(Destiny.Z - Origin.Z) ^ 2)
        Steps = Ceil(Steps)
        
        Dim increment As Position3D
        increment.X = (Destiny.X - Origin.X) / Steps
        increment.Y = (Destiny.Y - Origin.Y) / Steps
        increment.Z = (Destiny.Z - Origin.Z) / Steps
        
        Dim nextpoint As Position3D
        nextpoint = Origin
        Dim i As Integer
        
        Dim inter As Position3D
        Dim Size As Size3D
        For i = 1 To Steps
            nextpoint.X = nextpoint.X + increment.X
            nextpoint.Y = nextpoint.Y + increment.Y
            nextpoint.Z = nextpoint.Z + increment.Z
            inter.X = Math.Round(nextpoint.X)
            inter.Y = Math.Round(nextpoint.Y)
            inter.Z = Math.Round(nextpoint.Z)
            If (IsOnCamera(inter, camera1.Position, camera1.Size) = True) Then
                GetInCamVector = inter
                Exit For
            End If
        Next i
    End Function
    
    Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
        If (KeyCode = vbKeyEscape) Then End
    End Sub
    
    Private Sub DrawWorld()
        Me.Cls
        'Angletest.X = HScroll1.Value
        'Angletest.Y = VScroll1.Value
        'Angletest.Z = HScroll2.Value
        
        Label1.Caption = Angletest.X & " X, " & Angletest.Y & " Y, " & Angletest.Z & " Z"
        Label1.Caption = Label1.Caption & vbNewLine & "PosX: " & Player1.Position.X & ", PosY: " & Player1.Position.Y & ", PosZ: " & Player1.Position.Z
        
        Dim RecPosition As Position3D
        Dim RecPositiond As Position3D
        Dim RecPosition2 As Position3D
        Dim RecSize As Size3D
        Dim ang As Angle3D
        Dim Angletest2 As Angle3D
        
        'Draw camera dimensions:
        ForeColor = ColorConstants.vbBlue
        Me.DrawWidth = 5
        FillPosition3D RecPosition, camera1.Position.X, camera1.Position.Y, 0
        FillPosition3D RecPosition2, camera1.Position.X + camera1.Size.Width, camera1.Position.Y, 0
        DrawLine RecPosition, RecPosition2, Angletest, camera1.Size
        
        FillPosition3D RecPosition, camera1.Position.X + camera1.Size.Width, camera1.Position.Y, 0
        FillPosition3D RecPosition2, camera1.Position.X + camera1.Size.Width, camera1.Position.Y + camera1.Size.Height, 0
        DrawLine RecPosition, RecPosition2, Angletest, camera1.Size
        
        FillPosition3D RecPosition, camera1.Position.X, camera1.Position.Y + camera1.Size.Height, 0
        FillPosition3D RecPosition2, camera1.Position.X + camera1.Size.Width, camera1.Position.Y + camera1.Size.Height, 0
        DrawLine RecPosition, RecPosition2, Angletest, camera1.Size
        
        FillPosition3D RecPosition, camera1.Position.X, camera1.Position.Y, 0
        FillPosition3D RecPosition2, camera1.Position.X, camera1.Position.Y + camera1.Size.Height, 0
        DrawLine RecPosition, RecPosition2, Angletest, camera1.Size
        
        Me.DrawWidth = 1
        ForeColor = ColorConstants.vbBlack
        FillColor = ColorConstants.vbRed
        FillSize3D RecSize, 2000, 500, 2000
        FillPosition3D RecPosition, Player1.Position.X - 380, Player1.Position.Y + 230, Player1.Position.Z
        DrawPlane RecPosition, RecSize, Angletest, camera1.Size
        
        
        Me.DrawWidth = 1
        FillColor = ColorConstants.vbYellow
        FillSize3D RecSize, 2000, 500, 2000
        FillPosition3D RecPosition, Player1.Position.X - 380, Player1.Position.Y + 230, Player1.Position.Z + 2000
        DrawPlane RecPosition, RecSize, Angletest, camera1.Size
        
        FillColor = ColorConstants.vbBlack
        FillPosition3D RecPosition, 0, -Me.ScaleHeight / 2, 0
        FillPosition3D RecPosition2, 0, Me.ScaleHeight, 0
        DrawLine RecPosition, RecPosition2, Angletest2, camera1.Size
        
        FillPosition3D RecPosition, -Me.ScaleWidth / 2, 0, 0
        FillPosition3D RecPosition2, Me.ScaleWidth, 0, 0
        DrawLine RecPosition, RecPosition2, Angletest2, camera1.Size
        
        
        
        Me.Refresh
    
    End Sub
    
    Private Sub Form_Resize()
        ScaleMode = vbPixels
        AutoRedraw = True
        
        camera1.Size.Height = Me.ScaleHeight
        camera1.Size.Width = Me.ScaleWidth
        camera1.Position.X = -Me.ScaleWidth / 2
        camera1.Position.Y = -Me.ScaleHeight / 2
        camera1.Position.Z = -100
        camera1.Size.ZDepth = 4000
        camera1.Size.distance = 100
        FillPosition3D Player1.Position, camera1.Position.X + Me.ScaleWidth / 2, camera1.Position.Y + Me.ScaleHeight / 2, 0 'Camera Position
        
        DrawWorld 'draw the things
    End Sub
    
    Private Sub Timer1_Timer()
        'yes i use a timer for get the keyboard control
         Dim Speed As Integer
         If (GetActiveWindow() <> Me.hWnd) Then Exit Sub
         Speed = 1
         Player1.MoveCoordenates = None
         If IsKeyDown(vbKeyEscape) = True Then
            End
         End If
         
         If IsKeyDown(vbKeyShift) = True Then
            Speed = 50
        End If
        
         If IsKeyDown(vbKeyA) = True Then
            Angletest.Y = Angletest.Y + 1
            If (Angletest.Y >= 360) Then Angletest.Y = 0
            Player1.MoveCoordenates = Y
            DrawWorld
        End If
        
        If IsKeyDown(vbKeyD) And KEY_DOWN Then
            Angletest.Y = Angletest.Y - 1
            If (Angletest.Y <= -360) Then Angletest.Y = 0
            Player1.MoveCoordenates = Y
            DrawWorld
        End If
        
        If IsKeyDown(vbKeyLeft) And KEY_DOWN Then
            Player1.Position.X = Player1.Position.X + Speed
            Player1.MoveCoordenates = X
            DrawWorld
        End If
        
        If IsKeyDown(vbKeyRight) And KEY_DOWN Then
            Player1.Position.X = Player1.Position.X - Speed
            Player1.MoveCoordenates = X
            DrawWorld
        End If
        
        If IsKeyDown(vbKeyW) And KEY_DOWN Then
            Player1.Position.Y = Player1.Position.Y - Speed
            Player1.MoveCoordenates = Y
            DrawWorld
        End If
        
        If IsKeyDown(vbKeyS) And KEY_DOWN Then
            Player1.Position.Y = Player1.Position.Y + Speed
            Player1.MoveCoordenates = Y
            DrawWorld
        End If
        
        If IsKeyDown(vbKeyUp) And KEY_DOWN Then
            Player1.Position.Z = Player1.Position.Z - Speed
            Player1.Movement.Z = Player1.Movement.Z - Speed
            Player1.MoveCoordenates = Z
            DrawWorld
        End If
        
        If IsKeyDown(vbKeyDown) And KEY_DOWN Then
            Player1.Position.Z = Player1.Position.Z + Speed
            Player1.Movement.Z = Player1.Movement.Z + Speed
            Player1.MoveCoordenates = Z
            DrawWorld
        End If
    End Sub
    if you need the project(tell me if you can see the image on picturebox1(AutoRedraw must be, i belive always, true.. for we get results.. maybe was my last problem)):
    World3D.zip
    VB6 2D Sprite control

    To live is difficult, but we do it.

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