3D C/C++ tutorials -> OpenGL 1.5 -> Multisample antialiasing
Use for personal or educational purposes only. Commercial and other profit uses strictly prohibited. Exploitation of content on a website or in a publication prohibited.
win32_opengl_window.h
#include <windows.h>
#include <math.h>
#include "string.h"
#include <gl/glew.h> // http://glew.sourceforge.net/
#include <gl/wglew.h>
#include <FreeImage.h> // http://freeimage.sourceforge.net/
// ----------------------------------------------------------------------------------------------------------------------------
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glew32.lib")
#pragma comment(lib, "FreeImage.lib")
// ----------------------------------------------------------------------------------------------------------------------------
extern CString ModuleDirectory, ErrorLog;
// ----------------------------------------------------------------------------------------------------------------------------
extern int gl_max_texture_size, gl_max_texture_max_anisotropy_ext;
// ----------------------------------------------------------------------------------------------------------------------------
class CTexture
{
protected:
GLuint Texture;
public:
CTexture();
~CTexture();
operator GLuint ();
bool LoadTexture2D(char *FileName);
void Destroy();
private:
FIBITMAP *GetBitmap(char *FileName, int &Width, int &Height, int &BPP);
};
// ----------------------------------------------------------------------------------------------------------------------------
class COpenGLRenderer
{
protected:
int Width, Height;
protected:
// CTexture Texture;
float *VertexArray;
public:
COpenGLRenderer();
~COpenGLRenderer();
bool Init();
void Render(float FrameTime);
void Resize(int Width, int Height);
void Destroy();
};
// ----------------------------------------------------------------------------------------------------------------------------
class COpenGLView
{
protected:
char *Title;
int Width, Height, Samples;
HWND hWnd;
HGLRC hGLRC;
public:
COpenGLView();
~COpenGLView();
bool Init(HINSTANCE hInstance, char *Title, int Width, int Height, int Samples);
void Show(bool Maximized = false);
void MessageLoop();
void Destroy();
void OnPaint();
void OnSize(int Width, int Height);
};
// ----------------------------------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
// ----------------------------------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR sCmdLine, int iShow);
win32_opengl_window.cpp
#include "win32_opengl_window.h"
// ----------------------------------------------------------------------------------------------------------------------------
int gl_max_texture_size = 0, gl_max_texture_max_anisotropy_ext = 0;
// ----------------------------------------------------------------------------------------------------------------------------
CTexture::CTexture()
{
Texture = 0;
}
CTexture::~CTexture()
{
}
CTexture::operator GLuint ()
{
return Texture;
}
bool CTexture::LoadTexture2D(char *FileName)
{
CString DirectoryFileName = ModuleDirectory + FileName;
int Width, Height, BPP;
FIBITMAP *dib = GetBitmap(DirectoryFileName, Width, Height, BPP);
if(dib == NULL)
{
ErrorLog.Append("Error loading texture " + DirectoryFileName + "!\r\n");
return false;
}
GLenum Format = 0;
if(BPP == 32) Format = GL_BGRA;
if(BPP == 24) Format = GL_BGR;
if(Format == 0)
{
ErrorLog.Append("Unsupported texture format (%s)!\r\n", FileName);
FreeImage_Unload(dib);
return false;
}
BYTE *Data = FreeImage_GetBits(dib);
if(!GLEW_VERSION_1_2)
{
int Pitch = FreeImage_GetPitch(dib);
if(Format == GL_BGRA) Format = GL_RGBA;
if(Format == GL_BGR) Format = GL_RGB;
int bpp = BPP / 8;
BYTE *line = Data;
for(int y = 0; y < Height; y++)
{
BYTE *pixel = line;
for(int x = 0; x < Width; x++)
{
BYTE Temp = pixel[0];
pixel[0] = pixel[2];
pixel[2] = Temp;
pixel += bpp;
}
line += Pitch;
}
}
Destroy();
glGenTextures(1, &Texture);
glBindTexture(GL_TEXTURE_2D, Texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLEW_VERSION_1_4 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if(GLEW_EXT_texture_filter_anisotropic)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_texture_max_anisotropy_ext);
}
if(GLEW_VERSION_1_4)
{
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, Format, GL_UNSIGNED_BYTE, Data);
glBindTexture(GL_TEXTURE_2D, 0);
FreeImage_Unload(dib);
return true;
}
void CTexture::Destroy()
{
glDeleteTextures(1, &Texture);
Texture = 0;
}
FIBITMAP *CTexture::GetBitmap(char *FileName, int &Width, int &Height, int &BPP)
{
FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(FileName);
if(fif == FIF_UNKNOWN)
{
fif = FreeImage_GetFIFFromFilename(FileName);
}
if(fif == FIF_UNKNOWN)
{
return NULL;
}
FIBITMAP *dib = NULL;
if(FreeImage_FIFSupportsReading(fif))
{
dib = FreeImage_Load(fif, FileName);
}
if(dib != NULL)
{
int OriginalWidth = FreeImage_GetWidth(dib);
int OriginalHeight = FreeImage_GetHeight(dib);
Width = OriginalWidth;
Height = OriginalHeight;
if(Width == 0 || Height == 0)
{
FreeImage_Unload(dib);
return NULL;
}
BPP = FreeImage_GetBPP(dib);
if(Width > gl_max_texture_size) Width = gl_max_texture_size;
if(Height > gl_max_texture_size) Height = gl_max_texture_size;
if(!GLEW_ARB_texture_non_power_of_two)
{
Width = 1 << (int)floor((log((float)Width) / log(2.0f)) + 0.5f);
Height = 1 << (int)floor((log((float)Height) / log(2.0f)) + 0.5f);
}
if(Width != OriginalWidth || Height != OriginalHeight)
{
FIBITMAP *rdib = FreeImage_Rescale(dib, Width, Height, FILTER_BICUBIC);
FreeImage_Unload(dib);
dib = rdib;
}
}
return dib;
}
// ----------------------------------------------------------------------------------------------------------------------------
COpenGLRenderer::COpenGLRenderer()
{
}
COpenGLRenderer::~COpenGLRenderer()
{
}
bool COpenGLRenderer::Init()
{
bool Error = false;
// Error |= !Texture.LoadTexture2D("texture.jpg");
if(Error)
{
return false;
}
float Data[] =
{ // s, t, nx, ny, nz, x, y, z
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f,
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f,
1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f,
0.0f, 1.0f, 0.0f, 0.0f, 1.0f, -0.5f, 0.5f, 0.5f,
0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.5f, -0.5f, -0.5f,
1.0f, 0.0f, 0.0f, 0.0f, -1.0f, -0.5f, -0.5f, -0.5f,
1.0f, 1.0f, 0.0f, 0.0f, -1.0f, -0.5f, 0.5f, -0.5f,
0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, 0.5f, -0.5f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f,
1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f,
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, -0.5f,
0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f,
0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f,
1.0f, 0.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f,
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f,
0.0f, 1.0f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f,
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f,
1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f,
0.0f, 1.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f,
0.0f, 0.0f, 0.0f, -1.0f, 0.0f, -0.5f, -0.5f, -0.5f,
1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, -0.5f,
1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, 0.5f,
0.0f, 1.0f, 0.0f, -1.0f, 0.0f, -0.5f, -0.5f, 0.5f
};
VertexArray = new float[192];
memcpy(VertexArray, Data, 768);
GLfloat LightModelAmbient[] = {0.0f, 0.0f, 0.0f, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, LightModelAmbient);
GLfloat LightAmbient[] = {0.25f, 0.25f, 0.25f, 1.0f};
glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);
GLfloat LightDiffuse[] = {0.75f, 0.75f, 0.75f, 1.0f};
glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
GLfloat MaterialAmbient[] = {1.0f, 1.0f, 1.0f, 1.0f};
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, MaterialAmbient);
GLfloat MaterialDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialDiffuse);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
return true;
}
void COpenGLRenderer::Render(float FrameTime)
{
static GLfloat LightPosition[] = {0.0f, 0.0f, 2.5f, 1.0f}, a = 0.0f;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0f, 0.0f, 2.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
glRotatef(a, 0.0f, 1.0f, 0.0f);
glRotatef(a, 1.0f, 0.0f, 0.0f);
glColor3f(1.0f, 1.0f, 1.0f);
// glEnable(GL_TEXTURE_2D);
// glBindTexture(GL_TEXTURE_2D, Texture);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 32, VertexArray);
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 32, VertexArray + 2);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 32, VertexArray + 5);
glDrawArrays(GL_QUADS, 0, 24);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// glBindTexture(GL_TEXTURE_2D, 0);
// glDisable(GL_TEXTURE_2D);
a += 5.625f * FrameTime;
}
void COpenGLRenderer::Resize(int Width, int Height)
{
this->Width = Width;
this->Height = Height;
glViewport(0, 0, Width, Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (float)Width / (Height > 0 ? (float)Height : 1.0f), 0.125f, 512.0f);
}
void COpenGLRenderer::Destroy()
{
// Texture.Destroy();
delete [] VertexArray;
}
// ----------------------------------------------------------------------------------------------------------------------------
COpenGLRenderer OpenGLRenderer;
// ----------------------------------------------------------------------------------------------------------------------------
CString ModuleDirectory, ErrorLog;
// ----------------------------------------------------------------------------------------------------------------------------
void GetModuleDirectory()
{
char *moduledirectory = new char[256];
GetModuleFileName(GetModuleHandle(NULL), moduledirectory, 256);
*(strrchr(moduledirectory, '\\') + 1) = 0;
ModuleDirectory = moduledirectory;
delete [] moduledirectory;
}
// ----------------------------------------------------------------------------------------------------------------------------
COpenGLView::COpenGLView()
{
}
COpenGLView::~COpenGLView()
{
}
bool COpenGLView::Init(HINSTANCE hInstance, char *Title, int Width, int Height, int Samples)
{
this->Title = Title;
this->Width = Width;
this->Height = Height;
WNDCLASSEX WndClassEx;
memset(&WndClassEx, 0, sizeof(WNDCLASSEX));
WndClassEx.cbSize = sizeof(WNDCLASSEX);
WndClassEx.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
WndClassEx.lpfnWndProc = WndProc;
WndClassEx.hInstance = hInstance;
WndClassEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClassEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
WndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClassEx.lpszClassName = "Win32OpenGLWindow";
if(RegisterClassEx(&WndClassEx) == 0)
{
ErrorLog.Set("RegisterClassEx failed!");
return false;
}
DWORD Style = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
hWnd = CreateWindowEx(WS_EX_APPWINDOW, WndClassEx.lpszClassName, Title, Style, 0, 0, Width, Height, NULL, NULL, hInstance, NULL);
if(hWnd == NULL)
{
ErrorLog.Set("CreateWindowEx failed!");
return false;
}
HDC hDC = GetDC(hWnd);
if(hDC == NULL)
{
ErrorLog.Set("GetDC failed!");
return false;
}
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.iLayerType = PFD_MAIN_PLANE;
int PixelFormat = ChoosePixelFormat(hDC, &pfd);
if(PixelFormat == 0)
{
ErrorLog.Set("ChoosePixelFormat failed!");
return false;
}
static int MSAAPixelFormat = 0;
if(SetPixelFormat(hDC, MSAAPixelFormat == 0 ? PixelFormat : MSAAPixelFormat, &pfd) == FALSE)
{
ErrorLog.Set("SetPixelFormat failed!");
return false;
}
hGLRC = wglCreateContext(hDC);
if(hGLRC == NULL)
{
ErrorLog.Set("wglCreateContext failed!");
return false;
}
if(wglMakeCurrent(hDC, hGLRC) == FALSE)
{
ErrorLog.Set("wglMakeCurrent failed!");
return false;
}
if(glewInit() != GLEW_OK)
{
ErrorLog.Set("glewInit failed!");
return false;
}
if(MSAAPixelFormat == 0 && Samples > 0)
{
if(WGLEW_ARB_pixel_format && GLEW_ARB_multisample)
{
while(Samples > 0)
{
UINT NumFormats = 0;
int PFAttribs[] =
{
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
WGL_SAMPLES_ARB, Samples,
0
};
if(wglChoosePixelFormatARB(hDC, PFAttribs, NULL, 1, &MSAAPixelFormat, &NumFormats) == TRUE && NumFormats > 0) break;
Samples--;
}
wglDeleteContext(hGLRC);
DestroyWindow(hWnd);
UnregisterClass(WndClassEx.lpszClassName, hInstance);
return Init(hInstance, Title, Width, Height, Samples);
}
else
{
Samples = 0;
}
}
this->Samples = Samples;
GetModuleDirectory();
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_max_texture_size);
if(GLEW_EXT_texture_filter_anisotropic)
{
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_texture_max_anisotropy_ext);
}
if(WGLEW_EXT_swap_control)
{
wglSwapIntervalEXT(0);
}
return OpenGLRenderer.Init();
}
void COpenGLView::Show(bool Maximized)
{
RECT dRect, wRect, cRect;
GetWindowRect(GetDesktopWindow(), &dRect);
GetWindowRect(hWnd, &wRect);
GetClientRect(hWnd, &cRect);
wRect.right += Width - cRect.right;
wRect.bottom += Height - cRect.bottom;
wRect.right -= wRect.left;
wRect.bottom -= wRect.top;
wRect.left = dRect.right / 2 - wRect.right / 2;
wRect.top = dRect.bottom / 2 - wRect.bottom / 2;
MoveWindow(hWnd, wRect.left, wRect.top, wRect.right, wRect.bottom, FALSE);
ShowWindow(hWnd, Maximized ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL);
}
void COpenGLView::MessageLoop()
{
MSG Msg;
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
void COpenGLView::Destroy()
{
OpenGLRenderer.Destroy();
wglDeleteContext(hGLRC);
DestroyWindow(hWnd);
}
void COpenGLView::OnPaint()
{
static DWORD LastFPSTime = GetTickCount(), LastFrameTime = LastFPSTime, FPS = 0;
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hWnd, &ps);
DWORD Time = GetTickCount();
float FrameTime = (Time - LastFrameTime) * 0.001f;
LastFrameTime = Time;
if(Time - LastFPSTime > 1000)
{
CString Text = Title;
Text.Append(" - %dx%d", Width, Height);
Text.Append(", ATF %dx", gl_max_texture_max_anisotropy_ext);
Text.Append(", MSAA %dx", Samples);
Text.Append(", FPS: %d", FPS);
Text.Append(" - %s", (char*)glGetString(GL_RENDERER));
SetWindowText(hWnd, Text);
LastFPSTime = Time;
FPS = 0;
}
else
{
FPS++;
}
OpenGLRenderer.Render(FrameTime);
SwapBuffers(hDC);
EndPaint(hWnd, &ps);
InvalidateRect(hWnd, NULL, FALSE);
}
void COpenGLView::OnSize(int Width, int Height)
{
this->Width = Width;
this->Height = Height;
OpenGLRenderer.Resize(Width, Height);
}
// ----------------------------------------------------------------------------------------------------------------------------
COpenGLView OpenGLView;
// ----------------------------------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch(uiMsg)
{
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_PAINT:
OpenGLView.OnPaint();
break;
case WM_SIZE:
OpenGLView.OnSize(LOWORD(lParam), HIWORD(lParam));
break;
default:
return DefWindowProc(hWnd, uiMsg, wParam, lParam);
}
return 0;
}
// ----------------------------------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR sCmdLine, int iShow)
{
char *AppName = "Multisample antialiasing";
if(OpenGLView.Init(hInstance, AppName, 800, 600, 4))
{
OpenGLView.Show();
OpenGLView.MessageLoop();
}
else
{
MessageBox(NULL, ErrorLog, AppName, MB_OK | MB_ICONERROR);
}
OpenGLView.Destroy();
return 0;
}
Download
|