PDA

View Full Version : Rendering into BitMap using opengl in Win32



him_me2
10-26-2009, 09:27 PM
Hi all,
i'm trying to use the other option in PIXELFORMATDESCRIPTOR i.e PFD_DRAW_TO_BITMAP. i want that my code should render into the DIB created by me so that i can save it as a .bmp file or display it on screen using GDI or i can pass that DIB buffer to some other applications so that they can do the rest of the display part.

1)i want help in rendering part as well as how to display it.

Here is my code:

///////////////////////////////////

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <stdio.h>
#include <stdlib.h>

//#include "dibsect.h"

//global declarations

HWND hWnd;
HDC hDC, memDC, destDC;
HGLRC hRC;
//DIBSection m_dib; // declaring a DIB here
GLvoid *pix;
RECT rect;
int width=500, height=400;
BITMAPINFO * bit_m, *bmi;
HBITMAP hBitmap, oldBitmap;
void *bytes;

// Set up pixel format for graphics initialization
void SetupPixelFormat()
{
PIXELFORMATDESCRIPTOR pfd, *ppfd;
int pixelformat;

ppfd = &pfd;

ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
ppfd->nVersion = 1;
ppfd->dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_SUPPORT_GDI;// PFD_SUPPORT_GDI ;
ppfd->dwLayerMask = PFD_MAIN_PLANE;
ppfd->iPixelType = PFD_TYPE_RGBA;
ppfd->cColorBits = 24;
ppfd->cDepthBits = 16;
ppfd->cAlphaBits = 16;
ppfd->cAccumBits = 0;
ppfd->cStencilBits = 0;

pixelformat = ChoosePixelFormat(hDC, ppfd);
SetPixelFormat(hDC, pixelformat, ppfd);


//creating DIB
bytes=malloc(width*height*3);

bmi = (BITMAPINFO *)malloc(sizeof(BITMAPINFOHEADER)); //allocating memory for bitmap

bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi->bmiHeader.biWidth = width;
bmi->bmiHeader.biHeight = height;
bmi->bmiHeader.biPlanes = 1;
bmi->bmiHeader.biBitCount = 24;
bmi->bmiHeader.biCompression = BI_RGB;
bmi->bmiHeader.biSizeImage = 0;
bmi->bmiHeader.biXPelsPerMeter = 0;
bmi->bmiHeader.biYPelsPerMeter = 0;
bmi->bmiHeader.biClrUsed = 0;
bmi->bmiHeader.biClrImportant = 0;

// create DIB section
hBitmap = CreateDIBSection(hDC, bmi, DIB_RGB_COLORS, &amp;bytes, NULL, 0);
if(SelectObject(memDC, hBitmap)== NULL)
MessageBox(NULL,(LPCWSTR)L"Object not selected!",(LPCWSTR)L"Error",
MB_OK
);



}


// Initialize OpenGL graphics
void InitGraphics()
{

hDC = GetDC(NULL);
memDC=CreateCompatibleDC(hDC); // creating a memory DC

if(memDC==NULL)
MessageBox(NULL,(LPCWSTR)L"memDC not created!",(LPCWSTR)L"Error",
MB_OK
);

SetupPixelFormat();

hRC = wglCreateContext(memDC); // creating a rendering context
wglMakeCurrent(memDC, hRC);



GLfloat values[2];
//glGetFloatv(GL_LINE_WIDTH_GRANULARITY, values);
//printf("GL_LINE_WIDTH_GRANULARITY value is %3.1f\n",values[0]);
//glGetFloatv(GL_LINE_WIDTH_RANGE, values);printf("GL_LINE_WIDTH_RANGE values are %3.1f %3.1f\n",values[0], values[1]);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
glLineWidth(1.0);
glShadeModel(GL_SMOOTH);
glClearColor(0.8F, 1.0F, 1.0F, 1.0F);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);


//glClearColor(0, 0, 0, 0);
//glClearDepth(1.0);
//glEnable(GL_DEPTH_TEST);
}

// Resize graphics to fit window
void ResizeGraphics()
{
// Get new window size


GLfloat aspect;

GetClientRect(hWnd, &amp;rect);
width = rect.right;
height = rect.bottom;
aspect = (GLfloat)width / height;

// Adjust graphics to window size
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//gluPerspective(45, 1.0, 0.1, 100.0);
glFrustum (-1.0, 1.0, -1.0, 1.0,1.5, 20.0);
//gluPerspective(50.0, aspect, 10.0, 100.0);
glMatrixMode(GL_MODELVIEW);

}

// OpenGL drawing section
void DrawGraphics()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Set location in front of camera
glLoadIdentity();
glTranslated(0, 0, -10);
glScalef(1.0,2.0,1.0);

//glRotatef(30.0,0,0,-10);

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

// Draw a square
glBegin(GL_POLYGON);
glColor3d(0, 0, 1);
glVertex3d(-2, 2, 0);
glVertex3d(2, 2, 0);
glVertex3d(2.0, -2, 0);
glVertex3d(-2, -2, 0);

glEnd();

glBegin(GL_POLYGON);
glColor3d(0.0, 0.0, 1);
glVertex3d(-1, 1, 0);
glVertex3d(1, 1, 0);
glVertex3d(1, -1, 0);
glVertex3d(-1, -1, 0);
glEnd();

glBegin(GL_LINES);
glColor3d(0,0,1);
glVertex3d(-2,2,0);
glVertex3d(-1,1,0);
glVertex3d(1,1,0);
glVertex3d(2,2,0);
glVertex3d(1,-1,0);
glVertex3d(2,-2,0);
glVertex3d(-1,-1,0);
glVertex3d(-2,-2,0);
glEnd();

glBegin(GL_LINES);
glColor3d(0,0,1);
glVertex3d(3,3,0);
glVertex3d(8,3,0);
glEnd();

/*wglUseFontBitmaps(hDC, 0, 256, 1000);
glRasterPos2f(30.0F, 300.0F);
glListBase(1000);
glCallLists(12, GL_UNSIGNED_BYTE, "Red Triangle");
glFlush(); */
//glReadPixels(0, 0, (GLsizei)width, (GLsizei)height, GL_RGBA, GL_FLOAT, pix);
// Show the new scene
//SwapBuffers(hDC);
oldBitmap = (HBITMAP)SelectObject(memDC, hBitmap);

BitBlt(destDC,0,0,width, height,memDC,0,0,SRCCOPY);
SelectObject(destDC, oldBitmap);

}



/// Saving a frame buffer in a memory to a .bmp file

int SaveDIBitmap(char *filename, /* I - File to save to */BITMAPINFO *info, /* I - Bitmap information */void *bits) /* I - Bitmap pixel bits */
{
FILE *fp; /* Open file pointer */
long size, /* Size of file */
infosize, /* Size of bitmap info */
bitsize; /* Size of bitmap pixels */
BITMAPFILEHEADER header; /* File header */
/*
* Try opening the file; use "wb" mode to write this *binary* file.
*/
if ((fp = fopen(filename, "wb")) == NULL)
return (-1);
if (info->bmiHeader.biSizeImage == 0)/* Figure out the bitmap size */
bitsize = (info->bmiHeader.biWidth *info->bmiHeader.biBitCount + 7) / 8 *abs(info->bmiHeader.biHeight);
else
bitsize = info->bmiHeader.biSizeImage; infosize = sizeof(BITMAPINFOHEADER);

switch (info->bmiHeader.biCompression)
{
case BI_BITFIELDS :
infosize += 12; /* Add 3 RGB doubleword masks */
if (info->bmiHeader.biClrUsed == 0)
break;

case BI_RGB :

if (info->bmiHeader.biBitCount > 8 &amp;&amp; info->bmiHeader.biClrUsed == 0)
break;

case BI_RLE8 :

case BI_RLE4 :

if (info->bmiHeader.biClrUsed == 0)
infosize += (1 << info ->bmiHeader.biBitCount) * 4;

else
infosize += info->bmiHeader.biClrUsed * 4;
break;
};

size = sizeof(BITMAPFILEHEADER) + infosize + bitsize;
/*
* Write the file header, bitmap information, and bitmap pixel data…
*/
header.bfType = 'MB'; /* Non -portable… sigh */
header.bfSize = size;
header.bfReserved1 = 0;
header.bfReserved2 = 0;
header.bfOffBits = sizeof(BITMAPFILEHEADER) + infosize;

if (fwrite(&amp;header, 1, sizeof(BITMAPFILEHEADER), fp) <sizeof(BITMAPFILEHEADER))
{
/*
* Couldn't write the file header - return…
*/
fclose(fp);
return (-1);
};

if (fwrite(info, 1, infosize, fp) < infosize)
{
/*
* Couldn't write the bitmap header - return…
*/
fclose(fp);
return (-1);
};

if (fwrite(bits, 1, bitsize, fp) < bitsize)
{
/*
* Couldn't write the bitmap - return…
*/
fclose(fp);
return (-1);
};
/*
* OK, everything went fine - return…
*/
fclose(fp);
return (0);
}




// Handle window events and messages
LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
//ResizeGraphics();
break;

case WM_KEYUP:
{
int u = 9;
break;
}

case WM_CLOSE:
DestroyWindow(hWnd);
break;

case WM_DESTROY:
PostQuitMessage(0);
break;

// Default event handler
default:
return DefWindowProc (hWnd, uMsg, wParam, lParam);
break;
}

return 1;
}

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

const LPCWSTR appname = TEXT("OpenGL Sample");

WNDCLASS wndclass;
MSG msg;

// Define the window class
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)MainWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, appname);
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = NULL; //(HBRUSH)(COLOR_WINDOW+1);
wndclass.lpszMenuName = appname;
wndclass.lpszClassName = appname;

// Register the window class
if (!RegisterClass(&amp;wndclass)) return FALSE;

// Create the window
hWnd = CreateWindow(
appname,
appname,
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
CW_USEDEFAULT,
CW_USEDEFAULT,
1024,
800,
NULL,
NULL,
hInstance,
NULL);

// if window not created
if (!hWnd) return FALSE;

// Initialize OpenGL
InitGraphics();

// Display the window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

// Event loop
while (1)
{
if (PeekMessage(&amp;msg, NULL, 0, 0, PM_NOREMOVE) == TRUE)
{
if (!GetMessage(&amp;msg, NULL, 0, 0)) return TRUE;

TranslateMessage(&amp;msg);
DispatchMessage(&amp;msg);
}
DrawGraphics();
SaveDIBitmap("him.bmp",bmi,bytes );
}

wglDeleteContext(hRC);
ReleaseDC(hWnd, hDC);
}

pls help me as i'm stuck in this problem since last week

yooyo
10-27-2009, 06:05 AM
1. What is the exact PROBLEM?
2. Rendering to bitmap is not hw accelerated, and you are limited to OpenGL 1.1

him_me2
10-27-2009, 07:03 AM
Thanks for ur reply. The problem is i want to render on a raw buffer (e.g. void *bits) which has been allocated some memory without using any DC (in windows i'm doing) using openGL. and after that i can save it as bitmap.

is there any way by which we can render a buffer using openGL without using rendering context concept in a window.

I am building a application in which u can say thr are two main modules. 1) one which interacts with DC and windows etc. it also does the bitblt part. so it is transfering a raw memory buffer to the 2nd module taking height and width of the current window and 32 bits perpixel (RGBA).

2) 2nd module is currently setting the pixel values in the buffer using native line draw and polygon draw algorithms. it is just filling that array buffer. Now i want to introduce OpenGL to my second module where it will use openGL to draw line, polygon clipping etc.

this is my original problem. pls help me with this.. if some doubt pls ask i will explain again. thanks in advance.

yooyo
10-27-2009, 07:10 AM
You cant force OpenGL to render to some void* allocated memory buffer.

You can create GL context and then create offscreen buffer and render to it. When you done, just grab pixels back. This might be a slow depending on image size.

him_me2
10-27-2009, 10:08 PM
is creating a openGL context is platform dependent.
can u tell me some points how to begin with it.

I greatly appreciate your help.

yooyo
10-28-2009, 04:30 AM
Yes.. Creating OpenGL context is platform dependent..
http://www.opengl.org/wiki/Creating_an_OpenGL_Context

and most simple example:
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=05

After you create context, you need to create offscreen buffer using FBO:
http://www.songho.ca/opengl/gl_fbo.html

More stuff for reading:
http://www.opengl.org/wiki/GL_EXT_framebuffer_object

and finaly, read pixels to your buffer:


glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, my_fbo);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, my_buffer);


This will work on ATI and NVidia graphics cards with proper drivers installed. For other graphics cards (Intel, S3, ..) you have to check.