how can i render a 3D shape\polygn using GDI\GDIPLUS?

how can i render a 3D shape\polygon using GDI\GDIPLUS?
You need to do the math yourself or you may use a third party library since gdi[+] has no 3d concept.
yes i know... but i need learn what to do. thanks to a youtube video, i had learned:

1 - we get the 2 vertical lines points;
2 - using that points we get the origin and destiny of the horizontal line.
3 - we get the horizontal line points;
4 - knowing that points we can set the pixel on that point .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
'Get line points:
Public Function Ceil(ByVal Value As Double) As Double
    Ceil = -Int(-Value)
End Function

'if the line don't use Z, the Z value must be zero
Public Function GetLinePoints(ByRef Origin As Position3D, ByRef Destiny As Position3D) As Position3D()
    Dim Steps As Double
    Dim Points() As Position3D
    
    'Get the points line count:
    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)
    If (Steps = 0) Then Steps = 1 'void division by zero
    
    'Get the line increment step:
    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
    ReDim Points(Steps)
    
    'Get all step points:
    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)
        Points(i).X = inter.X
        Points(i).Y = inter.Y
        Points(i).Z = inter.Z
        'Debug.Print "X: " + CStr(inter.X) + vbTab + "Y: " + CStr(inter.Y) + vbTab + "Z: " + CStr(inter.Z)
    Next i
    GetLinePoints = Points
End Function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
'Draw the image:
Friend Sub DrawImageRectanglePoints(DestinationHDC As Long, Points() As Position3D, WorldSize As Size3D)
    'Points(0) is the Upper-Left
    'Points(1) is the Upper-Right
    'Points(2) is the Low-Right
    'Points(3) is the Low-Left
    
    'Get left and right vertical line points:
    Dim PointsUpperDownLeft() As Position3D
    PointsUpperDownLeft = GetLinePoints(Points(0), Points(3))
    Dim PointsUpperDownRight() As Position3D
    PointsUpperDownRight = GetLinePoints(Points(1), Points(2))
    
    Dim X As Long
    Dim Y As Long
    Dim R As Long
    Dim G As Long
    Dim B As Long
    
    'Between the left and right vertical line points we get the horizontal line points:
    Dim DrawPixelPoints() As Position3D
    For Y = 0 To UBound(PointsUpperDownLeft) - 1
        DrawPixelPoints = GetLinePoints(PointsUpperDownRight(Y), PointsUpperDownLeft(Y))
        For X = 0 To UBound(DrawPixelPoints) - 1
            Dim Point As POINTAPI
            Dim color As Long
            Dim PosX As Long
            Dim PosY As Long
            PosX = X
            PosY = Y
            
            'Test the image size for we tiled the image:
            If (PosX > ImageWidth) Then
                While (PosX >= ImageWidth)
                    PosX = PosX - ImageWidth
                Wend
            End If
            
            If (PosY >= ImageHeight) Then
                While (PosY > ImageHeight)
                    PosY = PosY - ImageHeight
                Wend
            End If
            
            'Get the pixel color(ARGB):
            GdipBitmapGetPixel hBitmap, PosX, PosY, color
            
            'Convert ARGB to RGB:
            R = color And &HFF
            G = (color And &HFF00&) \ &H100&
            B = (color And &HFF0000) \ &H10000
            If (color = CLR_INVALID) Then Exit For
            
            'Convert the 3D point to 2D point:
            Point = ConvertPositon3DTo2D(DrawPixelPoints(X), WorldSize)
            
            'Draw the pixel on point:
            SetPixelV DestinationHDC, Point.X, Point.Y, RGB(R, G, B)
        Next X
    Next Y
End Sub

the SetPixelV(), GDI, is slow... but the GDIPLUS have 1 function for set the pixel directly on HDC?
VB code in a C/C++ forum???
i'm so sorry about it.. too much work and been to much faster... i'm using VB6, only for test, but i'm doing it too on C++.
heres the code on C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 // Get line points:
    public double Ceil(double Value) {
        return (Int((Value * -1)) * -1);
    }
    
    // if the line don't use Z, the Z value must be zero
    public Position3D[] GetLinePoints(ref Position3D Origin, ref Position3D Destiny) {
        double Steps;
        Position3D[] Points;
        // Get the points line count:
        Steps = Math.Sqr(pow(Math.Abs(Destiny.X - Origin.X),  2) + pow(Math.Abs(Destiny.Y - Origin.Y) , 2) + pow(Math.Abs(Destiny.Z - Origin.Z) , 2))
        
        Steps = Ceil(Steps);
        if ((Steps == 0)) {
            Steps = 1;
        }
        
        // void division by zero
        // Get the line increment step:
        Position3D increment;
        increment.X = ((Destiny.X - Origin.X) 
                    / Steps);
        increment.Y = ((Destiny.Y - Origin.Y) 
                    / Steps);
        increment.Z = ((Destiny.Z - Origin.Z) 
                    / Steps);
        Position3D nextpoint;
        nextpoint = Origin;
        int i;
        Position3D inter;
        Size3D size;
        object Points;
        for (i = 1; (i <= Steps); i++) {
            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);
            Points[i].X = inter.X;
            Points[i].Y = inter.Y;
            Points[i].Z = inter.Z;
            // Debug.Print "X: " + CStr(inter.X) + vbTab + "Y: " + CStr(inter.Y) + vbTab + "Z: " + CStr(inter.Z)
        }
        
        return Points;
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
template<typename variant> 
int GetLastElementArray(variant &array)
{
    return sizeof array / sizeof *array - 1;
}

// Draw the image:
    internal void DrawImageRectanglePoints(HDC DestinationHDC, Position3D[] Points, Size3D WorldSize) {
        // Points(0) is the Upper-Left
        // Points(1) is the Upper-Right
        // Points(2) is the Low-Right
        // Points(3) is the Low-Left
        // Get left and right vertical line points:
        Position3D[] PointsUpperDownLeft;
        PointsUpperDownLeft = GetLinePoints(Points(0), Points(3));
        Position3D[] PointsUpperDownRight;
        PointsUpperDownRight = GetLinePoints(Points(1), Points(2));
        long X;
        long Y;
        long R;
        long G;
        long B;
        // Between the left and right vertical line points we get the horizontal line points:
        Position3D[] DrawPixelPoints;
//UBound is the last array index:
        for (Y = 0; (Y 
                    <= (GetLastElementArray(PointsUpperDownLeft) - 1)); Y++) {
            DrawPixelPoints = GetLinePoints(PointsUpperDownRight[Y], PointsUpperDownLeft[Y]);
            for (X = 0; (X 
                        <= (GetLastElementArray(DrawPixelPoints) - 1)); X++) {
                POINTAPI Point;
                long color;
                long PosX;
                long PosY;
                PosX = X;
                PosY = Y;
                // Test the image size for we tiled the image:
                if ((PosX > ImageWidth)) {
                    while ((PosX >= ImageWidth)) {
                        PosX = (PosX - ImageWidth);
                    }
                    
                    if ((PosY >= ImageHeight)) {
                        while ((PosY > ImageHeight)) {
                            PosY = (PosY - ImageHeight);
                        }
                        
                        // Get the pixel color(ARGB):
                        GdipBitmapGetPixel( hBitmap, PosX, PosY, color);
                        // Convert ARGB to RGB:
                        R =(color>> 16) & 0xff;
                         G=(color>>  8) & 0xff;
                        B = (color & 0xff);
                   
                        if ((color == CLR_INVALID)) {
                            break;
                        }
                        
                        // Convert the 3D point to 2D point:
                        Point = ConvertPositon3DTo2D(DrawPixelPoints[X], WorldSize);
                        // Draw the pixel on point:
                        SetPixelV( DestinationHDC,  Point.X,  Point.Y,   RGB(R, G, B));
                    }
                    
                }
        
    }

my question is: using GDIPLUS, can i set a pixel just using the HDC destination?
maybe will be more faster
Last edited on
The DestinationHDC should be of course of type HDC not long.

With CreateCompatibleDC(...) and CreateCompatibleBitmap(...) you can create the HDC in memory which is much faster. For an example how to do it see:

https://docs.microsoft.com/en-us/windows/win32/gdi/capturing-an-image

Once you have the memory dc you can BitBlt(...) it to the real dc in the WM_PAINT message. The example is a bit different but you may get the gist...

This is also known as double buffering.
coder777: the CreateCompatibleBitmap() is faster than DIB's?
i must update my image class for use DIB's, for work with pixels, and GDIPLUS for draw\load images files(GIF, JPEG, PNG, BMP and others).
and create a memory HDC for the entire world for draw everything on form...
after i do these update and fix the camera problems, i can create my 3D level ;)
PS: i update the others C++ functions ;)
You need a handle to a bitmap. How it comes into existence doesn't really matter for the speed. Except when it its incompatible and the system needs to recalculate the color scheme. Therefore I would recommend that you load the image and blitbit it to the compatible bitmap so that the recalculations has to be done just once.

For the 3d stuff I would recommend to take a look at thirdparty libraries such as boost:

https://www.boost.org/doc/libs/1_74_0/libs/qvm/doc/html/index.html
thank you so much for all.
i'm some months only for learn how i can render and now i know.
now i need more time to understand how create, correctly the camera and the Convert3Dto2D() hehehehe...
yes they, both, are dependent on shapes\figures\objects position and size ;)
thank you so much
so i did that change:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
void DrawImageRectanglePoints(HDC DestinationHDC, Position3D[] Points, Size3D WorldSize) {
        // Points(0) is the Upper-Left
        // Points(1) is the Upper-Right
        // Points(2) is the Low-Right
        // Points(3) is the Low-Left
        // Get left and right vertical line points:
        Position3D[] PointsUpperDownLeft;
        PointsUpperDownLeft = GetLinePoints(Points(0), Points(3));
        Position3D[] PointsUpperDownRight;
        PointsUpperDownRight = GetLinePoints(Points(1), Points(2));
        long X;
        long Y;
        long R;
        long G;
        long B;
        // Between the left and right vertical line points we get the horizontal line points:
        Position3D[] DrawPixelPoints;
//UBound is the last array index:
        for (Y = 0; (Y 
                    <= (GetLastElementArray(PointsUpperDownLeft) - 1)); Y++) {
            DrawPixelPoints = GetLinePoints(PointsUpperDownRight[Y], PointsUpperDownLeft[Y]);
            for (X = 0; (X 
                        <= (GetLastElementArray(DrawPixelPoints) - 1)); X++) {
                POINTAPI Point;
                long color;
                long PosX;
                long PosY;
                PosX = X;
                PosY = Y;
                // Test the image size for we tiled the image:
                if ((PosX > ImageWidth)) {
                    while ((PosX >= ImageWidth)) {
                        PosX = (PosX - ImageWidth);
                    }
                    
                    if ((PosY >= ImageHeight)) {
                        while ((PosY > ImageHeight)) {
                            PosY = (PosY - ImageHeight);
                        }
                        
                        // Get the pixel color(ARGB):
                        GdipBitmapGetPixel( hBitmap, PosX, PosY, color);
                        // Convert ARGB to RGB:
                        R =(color>> 16) & 0xff;
                         G=(color>>  8) & 0xff;
                        B = (color & 0xff);
                   
                        if ((color == CLR_INVALID)) {
                            break;
                        }
                        
                        // Convert the 3D point to 2D point:
                        Point = ConvertPositon3DTo2D(DrawPixelPoints[X], WorldSize);
                        // Draw the pixel on point:
                        //SetPixelV( DestinationHDC,  Point.X,  Point.Y,   RGB(R, G, B));
GdipBitmapSetPixel (MemhBitmap, Point.X, Point.Y, color);
                    }
                    
                }
        Point = ConvertPositon3DTo2D(PointsUpperDownLeft(0), WorldSize);
GdipDrawImage (DestinationHDC, MemhBitmap, Point.X, Point.Y)
    }

heres when i add the image:
1
2
3
4
5
6
7
8
9
Public void FromImageFile(String FileName)
{
    GdipGraphicsClear(hGraphics, &HFFFF0000)
    GdipLoadImageFromFile(FileName, hBitmap)
    GdipGraphicsClear(MemhGraphics, &HFFFF0000)
    GdipLoadImageFromFile(FileName, MemhBitmap)
    GdipGetImageWidth(hBitmap, ImageWidth)
    GdipGetImageHeight(hBitmap, ImageHeight)
}

the program ask for the image file... but then freezes and turn off.... i'm doing something wrong with MemhBitmap and MemhGraphics?
fixed but stills slow :(
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
void DrawImageRectanglePoints(HDC DestinationHDC, Position3D[] Points, Size3D WorldSize) {
        // Points(0) is the Upper-Left
        // Points(1) is the Upper-Right
        // Points(2) is the Low-Right
        // Points(3) is the Low-Left
        // Get left and right vertical line points:
        Position3D[] PointsUpperDownLeft;
        PointsUpperDownLeft = GetLinePoints(Points(0), Points(3));
        Position3D[] PointsUpperDownRight;
        PointsUpperDownRight = GetLinePoints(Points(1), Points(2));
        long X;
        long Y;
        long R;
        long G;
        long B;
        // Between the left and right vertical line points we get the horizontal line points:
        Position3D[] DrawPixelPoints;
//UBound is the last array index:
        for (Y = 0; (Y 
                    <= (GetLastElementArray(PointsUpperDownLeft) - 1)); Y++) {
            DrawPixelPoints = GetLinePoints(PointsUpperDownRight[Y], PointsUpperDownLeft[Y]);
            for (X = 0; (X 
                        <= (GetLastElementArray(DrawPixelPoints) - 1)); X++) {
                POINTAPI Point;
                long color;
                long PosX;
                long PosY;
                PosX = X;
                PosY = Y;
                // Test the image size for we tiled the image:
                if ((PosX > ImageWidth)) {
                    while ((PosX >= ImageWidth)) {
                        PosX = (PosX - ImageWidth);
                    }
                    
                    if ((PosY >= ImageHeight)) {
                        while ((PosY > ImageHeight)) {
                            PosY = (PosY - ImageHeight);
                        }
                        
                        // Get the pixel color(ARGB):
                        GdipBitmapGetPixel( hBitmap, PosX, PosY, color);
                        // Convert ARGB to RGB:
                        R =(color>> 16) & 0xff;
                         G=(color>>  8) & 0xff;
                        B = (color & 0xff);
                   
                        if ((color == CLR_INVALID)) {
                            break;
                        }
                        
                        // Convert the 3D point to 2D point:
                        Point = ConvertPositon3DTo2D(DrawPixelPoints[X], WorldSize);
                        // Draw the pixel on point:
                        //SetPixelV( DestinationHDC,  Point.X,  Point.Y,   RGB(R, G, B));
GdipBitmapSetPixel (MemhBitmap, Point.X, Point.Y, color);
                    }
                    
                }
        Point = ConvertPositon3DTo2D(PointsUpperDownLeft(0), WorldSize);

GdipDeleteGraphics (hGraphics);
     GdipCreateFromHDC(DestinationHDC, hGraphics);
GdipDrawImage (DestinationHDC, MemhBitmap, Point.X, Point.Y);
    }
It looks like you're trying to transform a whole image. Which is of course slow. Actually you shouldn't use Get/SetPixel at all.

Instead use StretchBlt(...) for transforming a whole image. In that case you just need to calclulate the rectangle once you have a handle to the bitmap. See:

https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-stretchblt
if i create the Graphics from:
GdipCreateFromHDC(GetDC(0), hGraphics)
how i use the source HDC?
What do you mean by 'source HDC'? source for what?

In visual basic/gdi+ you can use a certain version of GdipDrawImage(...) to get effect of transform the image.

Both visual basic and gdi+ are rather slow. So don't expect any wonders.
GdipDrawImage() can i use it like StretchBlt()?
Yes. See the examples:

https://docs.microsoft.com/en-us/dotnet/api/system.drawing.graphics?view=dotnet-plat-ext-5.0

https://docs.microsoft.com/en-us/dotnet/desktop/winforms/advanced/cropping-and-scaling-images-in-gdi?view=netframeworkdesktop-4.8

They are in C# but it shouldn't be too hard to find the visual basic equivalents.

Note that you should draw in a special function that provides PaintEventArgs. I would think that you can create such a function using visual studio.

GetDC(0) is for the entire window not the client region.
i need ask more... but i will create a new topic
Topic archived. No new replies allowed.