why these 'if' seems ignored?

Pages: 123
doing these:
1
2
3
4
5
6
7
8
9
/*
            //Draw the pixel on valid positions:
            if(Z>=0 && PosX<Width && PosX>=0 && PosY<Height && PosY>=0)
            {
                size_t pixelOffset = PosY * scanlineSize + PosX * pixelSize;
                Pixels[pixelOffset+2]=GetRValue(LineColor);
                Pixels[pixelOffset+1]=GetGValue(LineColor);
                Pixels[pixelOffset+0]=GetBValue(LineColor);
            }*/

i win a double speed.
and yes i found a problem here... why using GetXValue() inside the loop, if i can do it outside!?!
i will test these now
> i get 16FPS... so it can be the DrawLine() problem:
Not until you also time it WITHOUT calling RefreshToHDC();

You're measuring 16FPS doing both things.

You need to find out whether it's one or the other.

using these:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
do
    {
        test.Clear();
        string s="Frame Per Second: " + to_string(FramePerSecond);
        DrawText(test,s.c_str(),-1, &rec2, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
        test.RefreshFromHDC();
        int TextureY=0;
        for(int i=0; i<600; i++)
        {
          test.DrawLine(line.OriginX, line.OriginY+i, line.OriginZ, line.DestinationX, line.DestinationY+i, line.DestinationZ,RGB(0,255,0), false);
          test.DrawLine(line.OriginX+900, line.OriginY+i, line.OriginZ, line.DestinationX+900, line.DestinationY+i, line.DestinationZ,RGB(0,255,0), false);
        }
        test.RefreshToHDC();
        BitBlt(HDCConsole,50,0,test.Width, test.Height,test,0,0,SRCCOPY);

i get 16FPS. comment the 'test.RefreshToHDC();' or not.. the FPS is the same.
i change the DrawLine():
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
void DrawLine(float X0, float Y0, float Z0, float X1, float Y1, float Z1, COLORREF LineColor = RGB(255,0,0), bool Refresh=true)
    {
        //Getting Line Distance(float results):
        float DX = abs(X1 - X0);
        float DY = abs(Y1 - Y0);
        float DZ = abs(Z1 - Z0);
        float LineDistance =abs( sqrt(pow(DX,2) + pow(DY,2) + pow(DZ,2)));


        //Getting the Steps incrementation(float results):
        float XSteps = DX/LineDistance;
        float YSteps = DY/LineDistance;
        float ZSteps = DZ/LineDistance;

        //Draw Line using the Steps\ Incrementation:
        float X = X0;
        float Y = Y0;
        float Z = Z0;
        float EyeDistance = 500;// doing these i avoid the black\empty vertical lines

        //Getting RGB from the color:
        BYTE R = GetRValue(LineColor);
        BYTE G = GetGValue(LineColor);
        BYTE B = GetBValue(LineColor);

        for(int i=0; i<LineDistance; i++)
        {
            //For every steps we calculate the perspective:
            //Avoiding division by zero:
            if(Z==0) Z=1;
            float Perspective = EyeDistance/(EyeDistance+Z);

            //The 3D to 2D convertion(i use 300 of eye distance, but we can change it):

            int PosX = trunc(X*Perspective);
            int PosY = trunc(Y*Perspective);


            //Draw the pixel on valid positions:
            if(Z>=0 && PosX<Width && PosX>=0 && PosY<Height && PosY>=0)
            {
                size_t pixelOffset = PosY * scanlineSize + PosX * pixelSize;
                int PosR = pixelOffset+2;
                int PosG = pixelOffset+1;
                int PosB = pixelOffset+0;
                Pixels[PosR]=R;
                Pixels[PosG]=G;
                Pixels[PosB]=B;
            }


            //Increment steps(integer results):
            X+=XSteps;
            Y+=YSteps;
            Z+=ZSteps;
        }
        if(Refresh==true) RefreshToHDC();
    }

what i'm changing is on loop:
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
for(int i=0; i<LineDistance; i++)
        {
            //For every steps we calculate the perspective:
            //Avoiding division by zero:
            if(Z==0) Z=1;
            float Perspective = EyeDistance/(EyeDistance+Z);

            //The 3D to 2D convertion(i use 300 of eye distance, but we can change it):

            int PosX = trunc(X*Perspective);
            int PosY = trunc(Y*Perspective);


            //Draw the pixel on valid positions:
            if(Z>=0 && PosX<Width && PosX>=0 && PosY<Height && PosY>=0)
            {
                size_t pixelOffset = PosY * scanlineSize + PosX * pixelSize;
                int PosR = pixelOffset+2;
                int PosG = pixelOffset+1;
                int PosB = pixelOffset+0;
                Pixels[PosR]=R;
                Pixels[PosG]=G;
                Pixels[PosB]=B;
            }


            //Increment steps(integer results):
            X+=XSteps;
            Y+=YSteps;
            Z+=ZSteps;
        }

if i comment the 'if', i will get the 33FPS.
what is the 'Pixels' is a vector:
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
vector<BYTE> Pixels;

    void GetDIBS()
    {
        memset( &bmp, 0, sizeof(BITMAP) );
        GetObject(HBit, sizeof(BITMAP), &bmp);

        info.bmiHeader.biSize = sizeof(info.bmiHeader);
        info.bmiHeader.biWidth = bmp.bmWidth;
        // pay attention to the sign, you most likely want a
        // top-down pixel array as it's easier to use
        info.bmiHeader.biHeight = -bmp.bmHeight;
        info.bmiHeader.biPlanes = 1;
        info.bmiHeader.biBitCount = 32;
        info.bmiHeader.biCompression = BI_RGB;

        // the following calculations work for 16/24/32 bits bitmaps
        // but assume a byte pixel array
        pixelSize = info.bmiHeader.biBitCount / 8;
        // the + 3 ) & ~3 part is there to ensure that each
        // scan line is 4 byte aligned
        scanlineSize = (pixelSize * info.bmiHeader.biWidth + 3) & ~3;
        bitmapSize = bmp.bmHeight * scanlineSize;

        Pixels.resize (bitmapSize);
        GetDIBits(HDCMemory, HBit, 0, bmp.bmHeight, &Pixels[0], &info, DIB_RGB_COLORS);
    }

i'm doing wrong using a vector instead the 'void*'?
anyone can tell me more? did i miss something?
1
2
3
4
5
6
7
8
9
10
11
void RefreshFromHDC()
    {
        //Update the pixels array\vector from HDC:
        GetDIBits(HDCMemory, HBit, 0, bmp.bmHeight, &Pixels[0], &info, DIB_RGB_COLORS);
    }

    void RefreshToHDC()
    {
        //Update the image from pixels array\vector:
        SetDIBits(HDCMemory, HBit, 0, bmp.bmHeight, &Pixels[0], &info, DIB_RGB_COLORS);
    }
Last edited on
if i comment the 'if', i will get the 33FPS.
Actually I doubt that this small piece of code has that much of an impact. You may surround the loop with GetTickCount() to exactly measure the time.

I recommend the following:
1
2
3
4
5
6
7
8
9
10
11
        BITMAPINFO bmi;
        memset(&bmi, 0, sizeof(bmi));
        bmi.bmiHeader.biSize = sizeof(bmi);
        bmi.bmiHeader.biWidth = cx;
        bmi.bmiHeader.biHeight = cy;
        bmi.bmiHeader.biPlanes = 1;
        bmi.bmiHeader.biBitCount = 32;
        bmi.bmiHeader.biCompression = BI_RGB;

        void *ptr;
        HBITMAP hb = CreateDIBSection(HDC{}, &bmi, DIB_RGB_COLORS, &ptr, 0, 0);
In that case you can modify the memory directly and select the HBITMAP into your memory DC for BitBlt(...) instead of permanently copying all pixels with GetDIBits(...)/SetDIBits(...).

By the way. Line 7 in DrawLine(...):
1
2
        float LineDistance =(DX * DX) + (DY * DY) + (DZ * DZ);
        if(LineDistance < 1) return;
Last edited on
1 - your math ideia don't works :(
2 - using the void*ptr... how i use 'ptr[index]'? or i must allways 'ptr++'? to be honest the 'void*' continues make me confused.
1 - your math ideia don't works :(
The sqrt(...) was missing:
float LineDistance =sqrt((DX * DX) + (DY * DY) + (DZ * DZ));


2 - using the void*ptr... how i use 'ptr[index]'? or i must allways 'ptr++'? to be honest the 'void*' continues make me confused.
Instead of void * you may use uchar8_t (or whatever you prefer). However CreateDIBSection(...) expects a void** to fill. So you need a reinterpret_cast<void *>(ptr):
1
2
        //uchar8_t *Pixels;
        HBITMAP hb = CreateDIBSection(HDC{}, &bmi, DIB_RGB_COLORS, &reinterpret_cast<void *>(Pixels), 0, 0);
unsigned char *Pixels;

my CodeBlocks GNU compiler don't have the 'uchar8_t' only typedif ;)
HBit = CreateDIBSection(HDCMemory, &info, DIB_RGB_COLORS, &reinterpret_cast<void *>(Pixels), 0, 0);
error on 'reinterpret_cast':
"lvalue required as unary '&' operand"
so what is wrong?
Looks like you can't use &reinterpret_cast<void *>(Pixels) like this. So you unfortunately need to do this:

1
2
void* p = reinterpret_cast<void *>(Pixels);
HBit = CreateDIBSection(HDCMemory, &info, DIB_RGB_COLORS, &p, 0, 0);
or i did something wrong, or continues with no correct pointer:
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
68
69
70
71
72
73
74
75
BYTE *Pixels;

    void GetDIBS()
    {
        memset( &bmp, 0, sizeof(BITMAP) );
        GetObject(HBit, sizeof(BITMAP), &bmp);

        info.bmiHeader.biSize = sizeof(info.bmiHeader);
        info.bmiHeader.biWidth = bmp.bmWidth;
        // pay attention to the sign, you most likely want a
        // top-down pixel array as it's easier to use
        info.bmiHeader.biHeight = -bmp.bmHeight;
        info.bmiHeader.biPlanes = 1;
        info.bmiHeader.biBitCount = 32;
        info.bmiHeader.biCompression = BI_RGB;

        // the following calculations work for 16/24/32 bits bitmaps
        // but assume a byte pixel array
        pixelSize = info.bmiHeader.biBitCount / 8;
        // the + 3 ) & ~3 part is there to ensure that each
        // scan line is 4 byte aligned
        scanlineSize = (pixelSize * info.bmiHeader.biWidth + 3) & ~3;
        bitmapSize = bmp.bmHeight * scanlineSize;

        //Pixels.resize (bitmapSize);
        //GetDIBits(HDCMemory, HBit, 0, bmp.bmHeight, &Pixels[0], &info, DIB_RGB_COLORS);
        void* p = reinterpret_cast<void *>(Pixels);
        HBit = CreateDIBSection(HDCMemory, &info, DIB_RGB_COLORS,&p, 0, 0);
    }
image(int SizeWidth, int SizeHeight, COLORREF Backcolor=RGB(0,0,0))
    {
        //Creating HDC and HBITMAP memory:
        HDCMemory = CreateCompatibleDC(NULL);
        //HBit = CreateBitmap(SizeWidth, SizeHeight, 1, 32,NULL);
        //SelectObject(HDCMemory, HBit);

        //Getting image size:
        Width = SizeWidth;
        Height = SizeHeight;



        GetDIBS();
        cout << "hey";
        //Clear image and change the backcolor:
        Clear(Backcolor);
    }

    void RefreshFromHDC()
    {
        //Update the pixels array\vector from HDC:
        GetDIBits(HDCMemory, HBit, 0, bmp.bmHeight, &Pixels[0], &info, DIB_RGB_COLORS);
    }

    void RefreshToHDC()
    {
        //Update the image from pixels array\vector:
        SetDIBits(HDCMemory, HBit, 0, bmp.bmHeight, &Pixels[0], &info, DIB_RGB_COLORS);
    }

    ~image()
    {
        SelectObject(HDCMemory, oldBit);
        DeleteObject(HBit);
        DeleteDC(HDCMemory);
    }

    void Clear(COLORREF backcolor = RGB(0,0,0))
    {
        HBRUSH HBrush = CreateSolidBrush(backcolor);
        RECT rec={0,0,Width, Height};
        FillRect(HDCMemory,&rec,HBrush);
        DeleteObject(HBrush);
        RefreshFromHDC();
    }

for test i use the 'Clear()':
1
2
3
4
do
    {
        test.Clear(RGB(255,0,0));
BitBlt(HDCConsole,50,0,test.Width, test.Height,test,0,0,SRCCOPY);

but nothing happens.. only 'cout', image(), works
Last edited on
You need to select HBit into your HDCMemory otherwise there is no bitmap to fill. So uncomment line 35 and move it after line 43.
Remove line 74.
I'm wondering what your frame rate is for
1
2
3
4
5
6
7
8
do
    {
        test.Clear();
        string s="Frame Per Second: " + to_string(FramePerSecond);
        DrawText(test,s.c_str(),-1, &rec2, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
        test.RefreshFromHDC();
        test.RefreshToHDC();
        BitBlt(HDCConsole,50,0,test.Width, test.Height,test,0,0,SRCCOPY);

This is the best it's going to be, even if you could magically draw the scene in zero time.

1
2
3
4
5
6
7
8
    void Clear(COLORREF backcolor = RGB(0,0,0))
    {
        HBRUSH HBrush = CreateSolidBrush(backcolor);
        RECT rec={0,0,Width, Height};
        FillRect(HDCMemory,&rec,HBrush);
        DeleteObject(HBrush);  // why?
        RefreshFromHDC();  // why!?
    }

Create the background clearing brush just once in the constructor, then delete it in the destructor. You're trying to write performance code, so don't keep creating and destroying things you can easily keep.

Also, what's with all the refreshing to/from HDC for?
Your loop should be
- clear your offscreen buffer
- draw in your offscreen buffer
- refresh offscreen buffer to the screen.



> void* p = reinterpret_cast<void *>(Pixels);
> HBit = CreateDIBSection(HDCMemory, &info, DIB_RGB_COLORS,&p, 0, 0);
Read the spec.
https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createdibsection

[out] ppvBits
A pointer to a variable that receives a pointer to the location of the DIB bit values.

p is updated to point to where the DIB is.

1
2
3
void* p;
HBit = CreateDIBSection(HDCMemory, &info, DIB_RGB_COLORS, &p, 0, 0);
Pixels = reinterpret_cast<BYTE*>(p);


Any chance you could upload this testbench code to say github?
Because we're back to trying to peephole optimise your code again.
@salem c
You are right. void* p = reinterpret_cast<void *>(Pixels); was nonsense. Testing here is somewhat difficult...
1
2
3
4
5
6
7
8
9
10
11
12
image(int SizeWidth, int SizeHeight, COLORREF Backcolor=RGB(0,0,0))
    {
        //Creating HDC:
        HDCMemory = CreateCompatibleDC(NULL);


        //Getting image size:
        Width = SizeWidth;
        Height = SizeHeight;

        GetDIBS();
    }

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
void* p;
    BYTE *Pixels;

    void GetDIBS()
    {

        info.bmiHeader.biSize = sizeof(info.bmiHeader);
        info.bmiHeader.biWidth = bmp.bmWidth;
        // pay attention to the sign, you most likely want a
        // top-down pixel array as it's easier to use
        info.bmiHeader.biHeight = -bmp.bmHeight;
        info.bmiHeader.biPlanes = 1;
        info.bmiHeader.biBitCount = 32;
        info.bmiHeader.biCompression = BI_RGB;

        // the following calculations work for 16/24/32 bits bitmaps
        // but assume a byte pixel array
        pixelSize = info.bmiHeader.biBitCount / 8;
        // the + 3 ) & ~3 part is there to ensure that each
        // scan line is 4 byte aligned
        scanlineSize = (pixelSize * info.bmiHeader.biWidth + 3) & ~3;
        bitmapSize = bmp.bmHeight * scanlineSize;

        HBit = CreateDIBSection(HDCMemory, &info, DIB_RGB_COLORS, &p, 0, 0);
        if(SelectObject(HDCMemory, HBit)==NULL) cout << "error";
        Pixels = reinterpret_cast<BYTE*>(p);
    }

on test, i only draw the text FPS for see the result. but i miss something.
because nothing happens.. i get that 'cout' error
i found my image size error. and fixed... now i'm continue with change ;)
ok now i did a test:
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
int main()
{
    HDC HDCConsole = GetConsoleHDC();

    RECT rec;
    GetClientRect(GetConsoleWindow(),&rec);

    int Speed=1;
    LineSteps line(20,100,100,700,100,700);
    image test(1000,600);

    int FramePerSecond=0;
    int Frames=0;
    RECT rec2 ={0,30,170,50};
    auto Start =GetTickCount();
    do
    {
        test.Clear();
        string s="Frame Per Second: " + to_string(FramePerSecond);
        DrawText(test,s.c_str(),-1, &rec2, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
        test.RefreshFromHDC();
        int TextureY=0;

        for(int i=0; i<600; i++)
        {
          //test.DrawLine(line.OriginX, line.OriginY+i, line.OriginZ, line.DestinationX, line.DestinationY+i, line.DestinationZ,RGB(255,0,0),false);
        }
        //test.RefreshToHDC();
        BitBlt(HDCConsole,50,0,test.Width, test.Height,test,0,0,SRCCOPY);

i 850-900FPS
now uncomment that 2 lines:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
LineSteps line(20,100,100,700,100,700);
    image test(1000,600);

    int FramePerSecond=0;
    int Frames=0;
    RECT rec2 ={0,30,170,50};
    auto Start =GetTickCount();
    do
    {
        test.Clear();
        string s="Frame Per Second: " + to_string(FramePerSecond);
        DrawText(test,s.c_str(),-1, &rec2, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
        test.RefreshFromHDC();
        int TextureY=0;

        for(int i=0; i<600; i++)
        {
          test.DrawLine(line.OriginX, line.OriginY+i, line.OriginZ, line.DestinationX, line.DestinationY+i, line.DestinationZ,RGB(255,0,0),false);
        }
        test.RefreshToHDC();
        BitBlt(HDCConsole,50,0,test.Width, test.Height,test,0,0,SRCCOPY);

now get 56FPS.
seems that using the CreateDIBSection() i don't need update the image on HDC with image array.. thank you...
so only remains the DrawLine():
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
void DrawLine(float X0, float Y0, float Z0, float X1, float Y1, float Z1, COLORREF LineColor = RGB(255,0,0), bool Refresh=true)
    {
        //Getting Line Distance(float results):
        float DX = X1 - X0;
        float DY = Y1 - Y0;
        float DZ = Z1 - Z0;
        float LineDistance =sqrt((DX * DX) + (DY * DY) + (DZ * DZ));


        //Getting the Steps incrementation(float results):
        float XSteps = DX/LineDistance;
        float YSteps = DY/LineDistance;
        float ZSteps = DZ/LineDistance;

        //Draw Line using the Steps\ Incrementation:
        float X = X0;
        float Y = Y0;
        float Z = Z0;
        float EyeDistance = 500;// doing these i avoid the black\empty vertical lines

        //Getting RGB from the color:
        BYTE R = GetRValue(LineColor);
        BYTE G = GetGValue(LineColor);
        BYTE B = GetBValue(LineColor);

        for(int i=0; i<LineDistance; i++)
        {
            //For every steps we calculate the perspective:
            //Avoiding division by zero:
            if(Z==0) Z=1;
            float Perspective = EyeDistance/(EyeDistance+Z);

            //The 3D to 2D convertion(i use 400 of eye distance, but we can change it... seems the better value for avoid the vertical black lines):

            int PosX = trunc(X*Perspective);
            int PosY = trunc(Y*Perspective);


            //Draw the pixel on valid positions:
            if(Z>=0 && PosX<Width && PosX>=0 && PosY<Height && PosY>=0)
            {
                size_t pixelOffset = PosY * scanlineSize + PosX * pixelSize;
                int PosR = pixelOffset+2;
                int PosG = pixelOffset+1;
                int PosB = pixelOffset+0;
                Pixels[PosR]=R;
                Pixels[PosG]=G;
                Pixels[PosB]=B;
            }


            //Increment steps:
            X+=XSteps;
            Y+=YSteps;
            Z+=ZSteps;
        }
    }


so is the entire math on function?
so only remains the DrawLine():
What is the problem?

Some minor:
1
2
3
4
5
        float DX = X1 - X0;
        float DY = Y1 - Y0;
        float DZ = Z1 - Z0;
        float LineDistance =sqrt((DX * DX) + (DY * DY) + (DZ * DZ));
if(LineDistance < 1) return; // otherwise you risk a division by zero on line 11/12/13 


1
2
3
4
5
6
            //For every steps we calculate the perspective:
            //Avoiding division by zero:
//            if(Z==0) Z=1;
//            float Perspective = EyeDistance/(EyeDistance+Z);
const float d = EyeDistance+Z; // Note that Z==0 is irrelevant here
const float Perspective = (d != 0) ? (EyeDistance/d) : 0;
i need to ask: do i need convert float to int?

1
2
3
//The 3D to 2D convertion(i use 300 of eye distance, but we can change it):
            int PosX = trunc(X*Perspective);
            int PosY = trunc(Y*Perspective);

without trunc() i can win ~20 frames.
Truncation happens automatically when you convert a floating-point value to an integer. No need to call std::trunc.
thanks for that.. more 1 that i have learned with these code ;)
even so i have these slow... so i test more and i found that i lose 600FPS here:
these loop have 900 cycles... even so it's slow.. is these normal?

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
for(int i=0; i<LineDistance; i++)
        {
            //For every steps we calculate the perspective:
            //Avoiding division by zero:
            const float d = EyeDistance+Z; // Note that Z==0 is irrelevant here
            const float Perspective = (d != 0) ? (EyeDistance/d) : 0;

            //The 3D to 2D convertion(i use 300 of eye distance, but we can change it):
            int PosX = X*Perspective;
            int PosY = Y*Perspective;


            //Draw the pixel on valid positions:
            if(Z>=0 && PosX<Width && PosX>=0 && PosY<Height && PosY>=0)
            {
                size_t pixelOffset = PosY * scanlineSize + PosX * pixelSize;
                int PosR = pixelOffset+2;
                int PosG = pixelOffset+1;
                int PosB = pixelOffset+0;
                Pixels[PosR]=R;
                Pixels[PosG]=G;
                Pixels[PosB]=B;
            }


            //Increment steps(integer results):
            X+=XSteps;
            Y+=YSteps;
            Z+=ZSteps;
        }

unless: is possible these math give me some igual values?(not tested, just thinking)
1
2
3
X+=XSteps;
            Y+=YSteps;
            Z+=ZSteps;

Pages: 123