Jump to content
  • Advertisement
Sign in to follow this  
ridefast42

Very Slight Problem

This topic is 4324 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Ok, I have started to learn directx(woohoo!). I am using the tutorials over at directtutorials.com which are by far the best tutorials I have come across. I did the very first directx tutorial where it just displays a blue screen and everything worked fine. Then I decided to challenge myself and make it fade from black to blue to black again repeatedly. This works fine except that is flickers to black for a half second before it starts to fade to black again. Here is the source:
#include <windows.h>
#include <d3d9.h>

LPDIRECT3D9 d3d;
LPDIRECT3DDEVICE9 d3ddev;

void initD3D(HWND hWnd);
void render_frame(void);
void cleanD3D(void);
int r,b,g,color_count;
int fade_in;
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void color_change(void);


int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow)
{
    HWND hWnd;
    WNDCLASSEX wc;

    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = (WNDPROC)WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpszClassName = "WindowClass";

    RegisterClassEx(&wc);

    hWnd = CreateWindowEx(NULL,
                          "WindowClass",
                          "Neil is cool!!!",
                          WS_OVERLAPPEDWINDOW,
                          300, 300,
                          640, 480,
                          NULL,
                          NULL,
                          hInstance,
                          NULL);

    ShowWindow(hWnd, nCmdShow);

    initD3D(hWnd);

    MSG msg;

    while(TRUE)
    {
        DWORD starting_point = GetTickCount();

        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                break;

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        render_frame();

        while ((GetTickCount() - starting_point) < 25);
    }

    cleanD3D();
    return msg.wParam;
}


LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
        case WM_DESTROY:
            {
                PostQuitMessage(0);
                return 0;
            } break;
    }

    return DefWindowProc (hWnd, message, wParam, lParam);
}


void initD3D(HWND hWnd)
{
    d3d = Direct3DCreate9(D3D_SDK_VERSION);  

    D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;    
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow = hWnd;

    d3d->CreateDevice(D3DADAPTER_DEFAULT,
                      D3DDEVTYPE_HAL,
                      hWnd,
                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                      &d3dpp,
                      &d3ddev);

    return;
}

void color_change(void)
{
	if(color_count<=255 && fade_in == 0)
	{
		color_count++;
		b--;
		fade_in = 0;
	}
	else
	{
		fade_in = 1;
	}
	if(color_count>=0 && fade_in == 1)
	{
		color_count--;
		b++;
		fade_in = 1;
	}
	else
	{
		fade_in = 0;
	}

}



void render_frame(void)
{
	color_change();
    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(r, g, b), 1.0f, 0);
    d3ddev->BeginScene();
    d3ddev->EndScene();
    d3ddev->Present(NULL, NULL, NULL, NULL);

    return;
}


void cleanD3D(void)
{
    d3ddev->Release();  
    d3d->Release();  

    return;
}

Share this post


Link to post
Share on other sites
Advertisement
I couldn't exactly find the cause of the problem, but I noticed the 'color_change' function can be more efficient. Thus I changed it and I see no more black flicker now.


void color_change(void)
{
if ( fade_in == 1 ) {
b++;
if ( b > 255 ) {
b = 255; fade_in = 0;
}
} if ( fade_in == 0 ) {
b--;
if ( b < 0 ) {
b = 0; fade_in = 1;
}
}
}



Hope this helps you ;)

Share this post


Link to post
Share on other sites
I am still a n00b at directx so the solution will likely turn up in future reading.BTW, thanks for the efficient code ;)

Share this post


Link to post
Share on other sites
Actually, I think I know where your problem was...


if(color_count>=0 && fade_in == 1)
{
color_count--;
b++;
fade_in = 1;
}


This bit of code made the b value 256 before going to the if statements where it would decrease b again. Because 256 lies outside the acceptable range ( 0-255 ) for color components Direct3D renders this as black. Thus you would have one black render in between two blue ones because of this 'tresspass'.

Share this post


Link to post
Share on other sites

// Please excuse the reformatting. Your style is fine; I just want to conserve
// space and not clutter the post with source boxes.
// However, you really shouldn't use (void) for function prototypes:
void color_change() {
if(color_count<=255 && fade_in == 0) {
color_count++;
b--;
fade_in = 0;
} else {
fade_in = 1;
}
if(color_count>=0 && fade_in == 1) {
color_count--;
b++;
fade_in = 1;
} else {
fade_in = 0;
}
}


'b' and 'color_count' aren't initialized, so this can break in release mode. Even in debug mode, they both get initialized to 0, but they're supposed to move in opposite directions. (Also, it seems to me like 'b' would get set to -1 the first time through, since b, color_count and fade_in would all be 0.) That said, they're redundant; get rid of color_count, and simplify your logic, expressing it in terms of 'b'. Meanwhile, there's no point setting fade_in to 0 when we're in an if-case that required it to be 0, and similarly for 1, so we can remove those lines. That gives:


void color_change() {
if (b >= 0 && fade_in == 0) {
b--;
} else {
fade_in = 1;
}
if(b <= 255 && fade_in == 1) {
b++;
} else {
fade_in = 0;
}
}


The *problem* is that the bounds on b are incorrect: while it is true that b is allowed to be 0 or 255, we don't want to include them in our range check, because if for example b is 0 and fade_in is 0, we then set b to -1.

More importantly, though, the *logic* is just plain messy. First off, we're treating the integer fade_in like a boolean in logic, but not then treating it like a boolean in code: it's explicitly compared (something you don't really need to do anyway), but not to TRUE or FALSE. (Note that in C++, there is a real boolean type, called 'bool', which you should use for boolean values. It names the values in lowercase, i.e. 'true' and 'false', and can't validly take on some other value.

But using an actual boolean isn't the solution we want here, because the logic for handling fading in and fading out is basically symmetrical. Instead, we'll use the integer-ness, by letting fade_in represent the amount by which we will change 'b'. That is, either +1 or -1. That calls for a rename...


void color_change() {
if (b >= 0 && delta_b == -1) {
b += delta_b;
} else {
delta_b = 1;
}
if(b <= 255 && delta_b == 1) {
b += delta_b;
} else {
delta_b = -1;
}
}


Now the redundancy starts to show more clearly. Also, we see that there are a couple of things that go on here - b is updated, and delta_b possibly changes sign - and these tasks are intertwined. Instead, let's handle delta_b first, and then b. This shouldn't break the logic (and may help fix anything that was broken), because we were only supposed to change each of them at most once in color_change(), and weren't really depending on the order. In order to extract the delta_b changes, we notice that they're changed in the else-cases. This means we need to negate some and-conditions. By applying deMorgan's rule, and noting that for example "!(x >= y)" is the same as "x < y", we get:


void color_change() {
if (b < 0 || delta_b != -1) {
delta_b = 1;
}
if (b > 255 || delta_b != 1) {
delta_b = -1;
}

if (b >= 0 && delta_b == -1) {
b += delta_b;
}
if(b <= 255 && delta_b == 1) {
b += delta_b;
}
}


Now we fix the problem with our inequalities:


void color_change() {
if (b <= 0 || delta_b != -1) {
delta_b = 1;
}
if (b >= 255 || delta_b != 1) {
delta_b = -1;
}

if (b >= 0 && delta_b == -1) {
b += delta_b;
}
if(b <= 255 && delta_b == 1) {
b += delta_b;
}
}


Next, we can remove some of the b-checking logic, based on the fact that the b value should ALWAYS be >= 0 (that means we can remove that check, and also convert our <= into an ==), and <= 255 (so we can remove that check, and also convert our >= into an ==). After we reach the final code, we can verify that this is the case.


void color_change() {
if (b == 0 || delta_b != -1) {
delta_b = 1;
}
if (b == 255 || delta_b != 1) {
delta_b = -1;
}

if (delta_b == -1) {
b += delta_b;
}
if (delta_b == 1) {
b += delta_b;
}
}


Since delta_b will always be either -1 or 1, we therefore always adjust b in the same way and can remove that logic. This also means that if delta_b != -1, then delta_b == 1. There's no point adding an OR-case for delta_b == 1 for logic that sets delta_b = 1, so we can remove that as well. Similarly for the other case.


void color_change() {
if (b == 0) {
delta_b = 1;
}
if (b == 255) {
delta_b = -1;
}
b += delta_b;
}


Finally, we can link the above two if-cases with a bit of mathematical trickery: if b == 0, then delta_b must have been -1 before, and now we are setting it to 1. (That is, we can only reach the black colour while fading towards black.) Similarly, if b == 255, delta_b must have been 1 before, getting set to -1. Thus in either of these cases, we could multiply delta_b by -1, which takes 1 to -1 and -1 to 1:


void color_change() {
if (b == 0 || b == 255) {
delta_b *= -1;
}
b += delta_b;
}


This also requires us to initialize the variables, as ought to have happened anyway:


int b = 0;
int delta_b = -1; // so that it will change to 1 the first time through


Now we can verify that it works. On the first call, delta_b gets flipped to 1, and then added to b, which becomes 1. On subsequent calls, b increases while delta_b is unchanged (because b is in the 'middle range'). On the call where b == 254 before the function, it is 255 after, and delta_b is still 1. That delta_b value might seem initially wrong, but it's not "externally visible" anyway, and actually is needed for correctness: on the next pass, b == 255, so delta_b gets flipped from 1 to -1 *at that point*, and then the -1 is added to b, which starts heading back towards zero. Working :)

Share this post


Link to post
Share on other sites
Wow, thanks I should of thought of it that way because I have done something like that before in a pong game(to change the balls velocity upon collision). Correct me if I am wrong in saying that it flickered to black for a split second because the function begins and ends multiple times within the program and the in-between time defaults the screen to a black color? Because I did it where it only went to 255 and it still flickered black.

EDIT: BTW your method works like a charm.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!