-
Sep 20th, 2020, 08:25 AM
#1
Thread Starter
PowerPoster
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?
-
Sep 20th, 2020, 09:38 AM
#2
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
-
Sep 20th, 2020, 11:40 AM
#3
Thread Starter
PowerPoster
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)?
-
Sep 20th, 2020, 03:59 PM
#4
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
-
Sep 21st, 2020, 03:03 PM
#5
Thread Starter
PowerPoster
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?
-
Sep 21st, 2020, 04:58 PM
#6
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
-
Sep 22nd, 2020, 02:17 PM
#7
Thread Starter
PowerPoster
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
-
Sep 22nd, 2020, 07:10 PM
#8
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
-
Sep 23rd, 2020, 03:41 PM
#9
Thread Starter
PowerPoster
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.
-
Sep 23rd, 2020, 09:12 PM
#10
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
-
Sep 24th, 2020, 03:29 PM
#11
Thread Starter
PowerPoster
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)?
-
Sep 24th, 2020, 08:02 PM
#12
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
-
Sep 25th, 2020, 03:05 PM
#13
Thread Starter
PowerPoster
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
-
Sep 25th, 2020, 06:23 PM
#14
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
-
Sep 26th, 2020, 03:21 PM
#15
Thread Starter
PowerPoster
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º)?
-
Sep 27th, 2020, 02:37 PM
#16
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
-
Sep 29th, 2020, 03:12 PM
#17
Thread Starter
PowerPoster
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)
-
Oct 4th, 2020, 01:38 PM
#18
Thread Starter
PowerPoster
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
-
Oct 4th, 2020, 02:05 PM
#19
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
-
Oct 4th, 2020, 02:15 PM
#20
Thread Starter
PowerPoster
Re: API: what is the best function for draw an image using 4 points?
-
Oct 4th, 2020, 02:21 PM
#21
Thread Starter
PowerPoster
Re: API: what is the best function for draw an image using 4 points?
what fails seems to be the shape Width on TexturePoints()
-
Oct 4th, 2020, 04:22 PM
#22
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
-
Oct 5th, 2020, 02:17 PM
#23
Thread Starter
PowerPoster
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
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|