Showing posts with label windows. Show all posts
Showing posts with label windows. Show all posts

Thursday, January 28, 2010

OpenGL Introduction

OpenGL Introduction

OpenGL is a software interface to graphics hardware. It is designed as a hardware-independent interface to be used for many different hardware platforms. OpenGL programs can also work across a network (client-server paradigm) even if the client and server are different kinds of computers. The client in OpenGL is a computer on which an OpenGL program actually executes, and the server is a computer that performs the drawings.

OpenGL uses the prefix gl for core OpenGL commands and glu for commands in OpenGL Utility Library. Similarly, OpenGL constants begin with GL_ and use all capital letters. OpenGL also uses suffix to specify the number of arguments and data type passed to a OpenGL call.
glColor3f(1, 0, 0);         // set rendering color to red with 3 floating numbers
glColor4d(0, 1, 0, 0.2);    // set color to green with 20% of opacity (double)
glVertex3fv(vertex);        // set x-y-z coordinates using pointer

State Machine

OpenGL is a state machine. Modes and attributes in OpenGL will be remained in effect until they are changed. Most state variables can be enabled or disabled with glEnable() or glDisable(). You can also check if a state is currently enabled or disabled with glIsEnabled(). You can save or restore a collection of state variables into/from attribute stacks using glPushAttrib() or glPopAttrib(). GL_ALL_ATTRIB_BITS parameter can be used to save/restore all states. The number of stacks must be at least 16 in OpenGL standard.
(Check your maximum stack size with glinfo.)
 
glPushAttrib(GL_LIGHTING_BIT);    // elegant way to change states because
    glDisable(GL_LIGHTING);       // you can restore exact previous states
    glEnable(GL_COLOR_MATERIAL);  // after calling glPopAttrib()
glPushAttrib(GL_COLOR_BUFFER_BIT);
    glDisable(GL_DITHER);
    glEnable(GL_BLEND);



glPopAttrib();                    // restore GL_COLOR_BUFFER_BIT
glPopAttrib();                    // restore GL_LIGHTING_BIT

glBegin() and glEnd()

In order to draw geometric primitives (points, lines, triangles, etc) in OpenGL, you can specify a list of vertex data between glBegin() and glEnd(). This method is called immediate mode. (You may draw geometric primitives using other methods such as vertex array.)
glBegin(GL_TRIANGLES);
    glColor3f(1, 0, 0);     // set vertex color to red
    glVertex3fv(v1);        // draw a triangle with v1, v2, v3
    glVertex3fv(v2);
    glVertex3fv(v3);
glEnd();
There are 10 types of primitives in OpenGL; GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, and GL_POLYGON.

glFlush() & glFinish()

Similar to computer IO buffer, OpenGL commands are not executed immediately. All commands are stored in buffers first, including network buffers and the graphics accelerator itself, and are awaiting execution until buffers are full. For example, if an application runs over the network, it is much more efficient to send a collection of commands in a single packet than to send each command over network one at a time.
glFlush() empties all commands in these buffers and forces all pending commands will to be executed immediately without waiting buffers are full. Therefore glFlush() guarantees that all OpenGL commands made up to that point will complete executions in a finite amount time after calling glFlush(). And glFlush() does not wait until previous executions are complete and may return immediately to your program. So you are free to send more commands even though previously issued commands are not finished.
glFinish() flushes buffers and forces commands to begin execution as glFlush() does, but glFinish() blocks other OpenGL commands and waits for all execution is complete. Consequently, glFinish() does not return to your program until all previously called commands are complete. It might be used to synchronize tasks or to measure exact elapsed time that certain OpenGL commands are executed.

Wednesday, January 27, 2010

Winmain Explained

The WinMain function is the conventional name for the user-provided entry point for a Windows-based application.
 The name WinMain is used by convention by many programming frameworks. Depending on the programming framework, the call to the WinMain function can be preceded and followed by additional activities specific to that framework.
Your WinMain should initialize the application, display its main window, and enter a message retrieval-and-dispatch loop that is the top-level control structure for the remainder of the application's execution. Terminate the message loop when it receives a WM_QUIT message. At that point, your WinMain should exit the application, returning the value passed in the WM_QUIT message's wParam parameter. If WM_QUIT was received as a result of calling PostQuitMessage, the value of wParam is the value of the PostQuitMessage function's nExitCode parameter. For more information, see Creating a Message Loop.

Note:
ANSI applications can use the lpCmdLine parameter of the WinMain function to access the command-line string, excluding the program name. Note that lpCmdLine uses the LPSTR data type instead of the LPTSTR data type. This means that WinMain cannot be used by Unicode programs. The GetCommandLineW function can be used to obtain the command line as a Unicode string. Some programming frameworks might provide an alternative entry point that provides a Unicode command line. For example, the Microsoft Visual Studio C++ complier uses the name wWinMain for the Unicode entry point.


Syntax
int WINAPI WinMain(      
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow
);
Parameters

hInstance
[in] Handle to the current instance of the application.
hPrevInstance
[in] Handle to the previous instance of the application. This parameter is always NULL. If you need to detect whether another instance already exists, create a uniquely named mutex using the CreateMutex function. CreateMutex will succeed even if the mutex already exists, but the function will return ERROR_ALREADY_EXISTS. This indicates that another instance of your application exists, because it created the mutex first. However, a malicious user can create this mutex before you do and prevent your application from starting. To prevent this situation, create a randomly named mutex and store the name so that it can only be obtained by an authorized user. Alternatively, you can use a file for this purpose. To limit your application to one instance per user, create a locked file in the user's profile directory.
lpCmdLine
[in] Pointer to a null-terminated string specifying the command line for the application, excluding the program name. To retrieve the entire command line, use the GetCommandLine function.
nCmdShow
[in] Specifies how the window is to be shown. This parameter can be one of the following values.
SW_HIDE
Hides the window and activates another window.
SW_MAXIMIZE
Maximizes the specified window.
SW_MINIMIZE
Minimizes the specified window and activates the next top-level window in the Z order.
SW_RESTORE
Activates and displays the window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when restoring a minimized window.
SW_SHOW
Activates the window and displays it in its current size and position.
SW_SHOWMAXIMIZED
Activates the window and displays it as a maximized window.
SW_SHOWMINIMIZED
Activates the window and displays it as a minimized window.
SW_SHOWMINNOACTIVE
Displays the window as a minimized window. This value is similar to SW_SHOWMINIMIZED, except the window is not activated.
SW_SHOWNA
Displays the window in its current size and position. This value is similar to SW_SHOW, except the window is not activated.
SW_SHOWNOACTIVATE
Displays a window in its most recent size and position. This value is similar to SW_SHOWNORMAL, except the window is not actived.
SW_SHOWNORMAL
Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
Return Value
If the function succeeds, terminating when it receives a WM_QUIT message, it should return the exit value contained in that message's wParam parameter. If the function terminates before entering the message loop, it should return zero.



Explaination of Win32 Project under VisualStudio

To create a new Win32 project

  1. On the File menu, click New, and then click Project....
  2. In the Project Types pane, select Win32 in the Visual C++ node, and then select Win32 Project in the Templates pane.
    Type a name for the project, such as win32app. You can accept the default location, type a location, or browse to a directory where you want to save the project.
  3. On the Win32 Application Wizard, select Next.
  4. On the Win32 Application Wizard, under Application type select Windows application. Under Additional options select Empty project. Leave the remaining options as they are. Click Finish to create the project.
  5. Add a C++ file to the project by selecting Add New Item... from the Project menu. In the Add New Item dialog box, select C++ File (.cpp). Type a name for the file, such as GT_HelloWorldWin32.cpp, and click Add.

To start a Win32 applications

  1. As you know, every C and C++ application must have a main function. This function is the starting point for the application. Similarly, in a Win32 application, every application must have a WinMain function. The syntax for WinMain is as follows:



    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow);
    
    For an explanation of the parameters and return value of this function, see WinMain Function.


  2. In addition to WinMain, each Win32 application must also have a second function which is usually called WndProc, which stands for window procedure. The syntax for WndProc is as follows:

    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    The purpose of this function is to handle any messages that your application receives from the operating system. When does your application receive messages from the operating system? All the time! For example, imagine that we have created a dialog box that has an OK button. When the user clicks that button, the operating system sends our application a message, which lets us know that a user pressed this button. The WndProc function is responsible for responding to that event. In our example, the appropriate response might be to close the dialog box.
     
    EXTRA READ
      More Information on  Window Procedures

    • Window Procedures Every window has an associated window procedure — a function that processes all messages sent or posted to all windows of the class. All aspects of a window's appearance and behavior depend on the window procedure's response to these messages. 
    • Each window is a member of a particular window class. The window class determines the default window procedure that an individual window uses to process its messages.
       

To add functionality to WinMain

  1. First, create inside the WinMain function a window class structure of type WNDCLASSEX. This structure contains information about your window, such as the application's icon, the background color of the window, the name to display in the title bar, the name of the window procedure function, and so on. A typical WNDCLASSEX structure follows:



    WNDCLASSEX wcex;
    
        wcex.cbSize = sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName   = NULL;
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    
    For an explanation of the fields of this structure, see WNDCLASSEX.



  2. Now that you have created your window class, you must register it. Use the RegisterClassEx function, and pass the window class structure as an argument:



    if (!RegisterClassEx(&wcex))
        {
            MessageBox(NULL,
                _T("Call to RegisterClassEx failed!"),
                _T("Win32 Guided Tour"),
                NULL);
    
            return 1;
        }
    



  3. Now that you have registered your class, it is time to create a window. Use the CreateWindow function as follows:



    static TCHAR szWindowClass[] = _T("win32app");
    static TCHAR szTitle[] = _T("Win32 Guided Tour Application");
    // The parameters to CreateWindow explained:
    // szWindowClass: the name of the application
    // szTitle: the text that appears in the title bar
    // WS_OVERLAPPEDWINDOW: the type of window to create
    // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
    // 500, 100: initial size (width, length)
    // NULL: the parent of this window
    // NULL: this application dows not have a menu bar
    // hInstance: the first parameter from WinMain
    // NULL: not used in this application
    HWND hWnd = CreateWindow(
        szWindowClass,
        szTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        500, 100,
        NULL,
        NULL,
        hInstance,
        NULL
    );
    if (!hWnd)
    {
        MessageBox(NULL,
            _T("Call to CreateWindow failed!"),
            _T("Win32 Guided Tour"),
            NULL);
    
        return 1;
    }
    
    This function returns an HWND, which is a handle to a window. For more information, see Windows Data Types.



  4. Now that we have created the window, we can display it to the screen using the following code:



    // The parameters to ShowWindow explained:
    // hWnd: the value returned from CreateWindow
    // nCmdShow: the fourth parameter from WinMain
    ShowWindow(hWnd,
        nCmdShow);
    UpdateWindow(hWnd);
    
    So far, this window will not display much, because we have not yet implemented the WndProc function.



  5. The final step of WinMain is the message loop. The purpose of this loop is to listen for messages that the operating system sends. When the application receives a message, the message is dispatched to the WndProc function to handle it. The message loop resembles this:



    MSG msg;
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return (int) msg.wParam;
    
    For more information about the structures and functions that is used in the message loop, see MSG, GetMessage, TranslateMessage, and DispatchMessage.
    The steps that you have just completed are common to most Win32 applications. For include directives and global variable declarations required in this application,
    At this point, your WinMain function should resemble this:

    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow)
    {
        WNDCLASSEX wcex;
    
        wcex.cbSize = sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName   = NULL;
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    
        if (!RegisterClassEx(&wcex))
        {
            MessageBox(NULL,
                _T("Call to RegisterClassEx failed!"),
                _T("Win32 Guided Tour"),
                NULL);
    
            return 1;
        }
    
        hInst = hInstance; // Store instance handle in our global variable
    
        // The parameters to CreateWindow explained:
        // szWindowClass: the name of the application
        // szTitle: the text that appears in the title bar
        // WS_OVERLAPPEDWINDOW: the type of window to create
        // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
        // 500, 100: initial size (width, length)
        // NULL: the parent of this window
        // NULL: this application dows not have a menu bar
        // hInstance: the first parameter from WinMain
        // NULL: not used in this application
        HWND hWnd = CreateWindow(
            szWindowClass,
            szTitle,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT,
            500, 100,
            NULL,
            NULL,
            hInstance,
            NULL
        );
    
        if (!hWnd)
        {
            MessageBox(NULL,
                _T("Call to CreateWindow failed!"),
                _T("Win32 Guided Tour"),
                NULL);
    
            return 1;
        }
    
        // The parameters to ShowWindow explained:
        // hWnd: the value returned from CreateWindow
        // nCmdShow: the fourth parameter from WinMain
        ShowWindow(hWnd,
            nCmdShow);
        UpdateWindow(hWnd);
    
        // Main message loop:
        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return (int) msg.wParam;
    }
    


To add functionality to WndProc

  1. The purpose of the WndProc function is to handle messages that your application receives. You usually implement this by using a switch function.
    The first message we will handle is the WM_PAINT message. Your application receives this message when a portion of your application's window must be updated. When a window is first created, the whole window must be updated, and this message is passed to indicate this.
    The first thing that you should do when you handle a WM_PAINT message is call BeginPaint, and the last thing that you should do is call EndPaint. In between these two function calls you handle all the logic to lay out the text, buttons, and other controls for your window. For this application, we display the string "Hello, World!" inside the window. To display text, use the TextOut function, as shown here:

    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR greeting[] = _T("Hello, World!");
    
    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
    
        // Here your application is laid out.
        // For this introduction, we just print out "Hello, World!"
        // in the top left corner.
        TextOut(hdc,
            5, 5,
            greeting, _tcslen(greeting));
        // End application-specific layout section.
    
        EndPaint(hWnd, &ps);
        break;
    }
    



  2. Your application will typically handle many other messages, such as WM_CREATE and WM_DESTROY. A simple but complete WndProc function follows:

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        PAINTSTRUCT ps;
        HDC hdc;
        TCHAR greeting[] = _T("Hello, World!");
    
        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
    
            // Here your application is laid out.
            // For this introduction, we just print out "Hello, World!"
            // in the top left corner.
            TextOut(hdc,
                5, 5,
                greeting, _tcslen(greeting));
            // End application specific layout section.
    
            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
            break;
        }
    
        return 0;
    }