opengl'i kullanmaya başlama
Windows’ta manuel OpenGL kurulumu
Sonunda tam örnek kod bulunur
OpenGL için Windows bileşenleri
WGL
WGL (wiggle olarak telaffuz edilebilir), “Windows ve OpenGL arasındaki bir arabirim"de olduğu gibi “Windows-GL” anlamına gelir - Windows API’sinden OpenGL ile iletişim kurmak için bir dizi işlev. WGL işlevlerinin bir wgl öneki vardır ve belirteçleri bir WGL_ önekine sahiptir.
Microsoft sistemlerinde desteklenen varsayılan OpenGL sürümü 1.1’dir. Bu çok eski bir versiyondur (en sonuncusu 4.5). En son sürümleri almanın yolu, grafik sürücülerinizi güncellemektir, ancak grafik kartınız bu yeni sürümleri desteklemelidir.
WGL işlevlerinin tam listesi burada bulunabilir.
Grafik cihaz arayüzü (GDI)
GDI (bugün GDI+ olarak güncellendi), Windows’ta bir pencereye çizim yapmanıza olanak sağlayan bir 2B çizim arabirimidir. OpenGL’yi başlatmak ve onunla etkileşime girmesine izin vermek için GDI’ya ihtiyacınız var (ancak aslında GDI’nın kendisini kullanmayacaksınız).
GDI’da, her pencerenin, işlevleri çağırırken çizim hedefini tanımlamak için kullanılan bir cihaz bağlamı (DC) vardır (bunu parametre olarak iletirsiniz). Ancak, OpenGL kendi oluşturma bağlamını (RC) kullanır. Bu nedenle, RC oluşturmak için DC kullanılacaktır.
Temel kurulum
Bir pencere oluşturma
Yani OpenGL’de bir şeyler yapmak için RC’ye ihtiyacımız var ve RC’yi almak için DC’ye ihtiyacımız var ve DC’yi elde etmek için bir pencereye ihtiyacımız var. Windows API kullanarak bir pencere oluşturmak birkaç adım gerektirir. Bu temel bir rutindir, bu nedenle daha ayrıntılı bir açıklama için diğer belgelere başvurmalısınız, çünkü bu Windows API’sini kullanmakla ilgili değildir.
Bu bir Windows kurulumudur, bu nedenle Windows.h
eklenmelidir ve programın giriş noktası parametreleriyle birlikte WinMain
prosedürü olmalıdır. Programın ayrıca opengl32.dll
ve gdi32.dll
ile bağlantılı olması gerekir (64 veya 32 bit sistemde olmanıza bakılmaksızın).
Önce penceremizi WNDCLASS
yapısını kullanarak tanımlamamız gerekiyor. Oluşturmak istediğimiz pencere hakkında bilgiler içerir:
/* REGISTER WINDOW */
WNDCLASS window_class;
// Clear all structure fields to zero first
ZeroMemory(&window_class, sizeof(window_class));
// Define fields we need (others will be zero)
window_class.style = CS_OWNDC;
window_class.lpfnWndProc = window_procedure; // To be introduced later
window_class.hInstance = instance_handle;
window_class.lpszClassName = TEXT("OPENGL_WINDOW");
// Give our class to Windows
RegisterClass(&window_class);
/* *************** */
Her alanın anlamının kesin bir açıklaması (ve alanların tam listesi için) için MSDN belgelerine bakın.
Ardından CreateWindowEx
kullanarak bir pencere oluşturabiliriz. Pencere oluşturulduktan sonra DC’sini alabiliriz:
/* CREATE WINDOW */
HWND window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
TEXT("OPENGL_WINDOW"),
TEXT("OpenGL window"),
WS_OVERLAPPEDWINDOW,
0, 0,
800, 600,
NULL,
NULL,
instance_handle,
NULL);
HDC dc = GetDC(window_handle);
ShowWindow(window_handle, SW_SHOW);
/* ************* */
Son olarak, işletim sisteminden pencere olaylarını alan bir mesaj döngüsü oluşturmamız gerekiyor:
/* EVENT PUMP */
MSG msg;
while (true) {
if (PeekMessage(&msg, window_handle, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// draw(); <- there goes your drawing
SwapBuffers(dc); // To be mentioned later
}
/* ********** */
Piksel biçimi
OpenGL’nin penceremiz hakkında renk bitliği, arabelleğe alma yöntemi vb. gibi bazı bilgileri bilmesi gerekir. Bunun için piksel formatı kullanıyoruz. Ancak, işletim sistemine yalnızca ne tür bir piksel biçimine ihtiyacımız olduğunu önerebiliriz ve işletim sistemi en çok destekleneni sağlar, bunun üzerinde doğrudan kontrolümüz yoktur. Bu nedenle yalnızca tanımlayıcı olarak adlandırılır.
/* PIXEL FORMAT */
PIXELFORMATDESCRIPTOR descriptor;
// Clear all structure fields to zero first
ZeroMemory(&descriptor, sizeof(descriptor));
// Describe our pixel format
descriptor.nSize = sizeof(descriptor);
descriptor.nVersion = 1;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER | PFD_SWAP_LAYER_BUFFERS;
descriptor.iPixelType = PFD_TYPE_RGBA;
descriptor.cColorBits = 32;
descriptor.cRedBits = 8;
descriptor.cGreenBits = 8;
descriptor.cBlueBits = 8;
descriptor.cAlphaBits = 8;
descriptor.cDepthBits = 32;
descriptor.cStencilBits = 8;
// Ask for a similar supported format and set it
int pixel_format = ChoosePixelFormat(dc, &descriptor);
SetPixelFormat(dc, pixel_format, &descriptor);
/* *********************** */
dwFlags
alanında çift arabelleğe almayı etkinleştirdik, bu yüzden çizimden sonra bir şeyler görmek için SwapBuffers
‘ı çağırmalıyız.
Oluşturma bağlamı
Bundan sonra, basitçe render bağlamımızı oluşturabiliriz:
/* RENDERING CONTEXT */
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
/* ***************** */
Bir seferde yalnızca bir iş parçacığının RC’yi kullanabileceğini unutmayın. Daha sonra başka bir iş parçacığından kullanmak isterseniz, yeniden etkinleştirmek için oraya wglMakeCurrent
çağırmalısınız (bu, o anda etkin olduğu iş parçacığında devre dışı bırakacaktır, vb.).
OpenGL işlevlerini alma
OpenGL işlevleri, işlev işaretçileri kullanılarak elde edilir. Genel prosedür:
- Bir şekilde işlev işaretçi türlerini elde edin (esas olarak işlev prototipleri)
- Kullanmak istediğimiz her işlevi bildirin (işlev işaretçi türüyle birlikte)
- Gerçek işlevi elde edin
Örneğin, glBegin’i düşünün:
// We need to somehow find something that contains something like this,
// as we can't know all the OpenGL function prototypes
typedef void (APIENTRY *PFNGLBEGINPROC)(GLenum);
// After that, we need to declare the function in order to use it
PFNGLBEGINPROC glBegin;
// And finally, we need to somehow make it an actual function
(“PFN”, “işlev için işaretçi” anlamına gelir, ardından bir OpenGL işlevinin adını izler ve sonunda “PROC” - bu, olağan OpenGL işlev işaretçi türü adıdır.)
İşte Windows’ta nasıl yapıldığı. Daha önce belirtildiği gibi, Microsoft yalnızca OpenGL 1.1’i sunar. İlk olarak, o sürüm için işlev işaretçi türleri GL/gl.h
dahil edilerek bulunabilir. Bundan sonra, kullanmayı düşündüğümüz tüm fonksiyonları yukarıda gösterildiği gibi bildiririz (bunu bir başlık dosyasında yapmak ve onları “extern” olarak bildirmek, hepsini bir kez yükledikten sonra, sadece dahil ederek kullanmamıza izin verir). Son olarak, OpenGL 1.1 işlevlerinin yüklenmesi DLL dosyasını açarak yapılır:
HMODULE gl_module = LoadLibrary(TEXT("opengl32.dll"));
/* Load all the functions here */
glBegin = (PFNGLBEGINPROC)GetProcAddress("glBegin");
// ...
/* *************************** */
FreeLibrary(gl_module);
Ancak, muhtemelen OpenGL 1.1’den biraz daha fazlasını istiyoruz. Ancak Windows bize bunun üzerindeki herhangi bir şey için işlev prototiplerini veya dışa aktarılan işlevleri vermez. Prototiplerin OpenGL kayıt defterinden alınması gerekir. Bizi ilgilendiren üç dosya var: GL/glext.h
, GL/glcorearb.h
ve GL/wglext.h
.
Windows tarafından sağlanan GL/gl.h
dosyasını tamamlamak için GL/glext.h
‘e ihtiyacımız var. (kayıt defteri tarafından açıklandığı gibi) “OpenGL 1.2 ve üstü uyumluluk profili ve uzantı arabirimleri” içerir (profiller ve uzantılar hakkında daha sonra, burada bu iki dosyayı kullanmanın gerçekten iyi bir fikir olmadığını göreceğiz) .
Gerçek işlevlerin wglGetProcAddress
tarafından elde edilmesi gerekiyor (bu adam için DLL dosyasını açmaya gerek yok, orada değiller, sadece işlevi kullanın). Bununla birlikte, OpenGL 1.2 ve üzeri tüm fonksiyonları getirebiliriz (ancak 1.1 değil). Düzgün çalışması için OpenGL oluşturma bağlamının oluşturulması ve geçerli hale getirilmesi gerektiğini unutmayın. Örneğin, glClear
:
// Include the header from the OpenGL registry for function pointer types
// Declare the functions, just like before
PFNGLCLEARPROC glClear;
// ...
// Get the function
glClear = (PFNGLCLEARPROC)wglGetProcAddress("glClear");
Aslında hem wglGetProcAddress
hem de GetProcAddress
kullanan bir sarmalayıcı get_proc
prosedürü oluşturabiliriz:
// Get function pointer
void* get_proc(const char *proc_name)
{
void *proc = (void*)wglGetProcAddress(proc_name);
if (!proc) proc = (void*)GetProcAddress(gl_module, proc_name); // gl_module must be somewhere in reach
return proc;
}
Özetlemek için, bunun gibi işlev işaretçisi bildirimleriyle dolu bir başlık dosyası oluştururuz:
extern PFNGLCLEARCOLORPROC glClearColor;
extern PFNGLCLEARDEPTHPROC glClearDepth;
extern PFNGLCLEARPROC glClear;
extern PFNGLCLEARBUFFERIVPROC glClearBufferiv;
extern PFNGLCLEARBUFFERFVPROC glClearBufferfv;
// And so on...
Daha sonra sadece bir kez çağırdığımız load_gl_functions
gibi bir prosedür oluşturabiliriz ve şöyle çalışır:
glClearColor = (PFNGLCLEARCOLORPROC)get_proc("glClearColor");
glClearDepth = (PFNGLCLEARDEPTHPROC)get_proc("glClearDepth");
glClear = (PFNGLCLEARPROC)get_proc("glClear");
glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)get_proc("glClearBufferiv");
glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)get_proc("glClearBufferfv");
Ve hazırsın! Sadece işlev işaretçileri ve GL’yi içeren başlığı ekleyin.
Daha iyi kurulum
OpenGL profilleri
OpenGL, 20 yılı aşkın bir süredir geliştirilmektedir ve geliştiriciler her zaman geriye dönük uyumluluk (BC) konusunda katı olmuştur. Bu nedenle yeni bir özellik eklemek çok zor. Böylece 2008 yılında iki “profil"e ayrıldı. Çekirdek ve uyumluluk. Çekirdek profil, performans iyileştirmeleri ve bazı yeni özellikler lehine BC’yi bozar. Hatta bazı eski özellikleri tamamen kaldırır. Uyumluluk profili, BC’yi 1.0’a kadar olan tüm sürümlerle korur ve bazı yeni özellikler üzerinde mevcut değildir. Yalnızca eski, eski sistemler için kullanılacaktır, tüm yeni uygulamalar çekirdek profili kullanmalıdır.
Bu nedenle, temel kurulumumuzda bir sorun var - yalnızca OpenGL 1.0 ile geriye dönük uyumlu bağlamı sağlıyor. Piksel formatı da sınırlıdır. Uzantıları kullanarak daha iyi bir yaklaşım var.
OpenGL uzantıları
OpenGL’nin orijinal işlevselliğine yapılan herhangi bir eklemeye uzantılar denir. Genellikle, daha önce olmayan bazı şeyleri yasal hale getirebilir, parametre değer aralığını genişletebilir, GLSL’yi genişletebilir ve hatta tamamen yeni işlevler ekleyebilirler.
Üç ana uzantı grubu vardır: satıcı, EXT ve ARB. Satıcı uzantıları belirli bir satıcıdan gelir ve AMD veya NV gibi satıcıya özel bir işareti vardır. EXT uzantıları, birlikte çalışan birkaç satıcı tarafından yapılır. Bir süre sonra, tamamı resmi olarak desteklenenler ve ARB tarafından onaylananlar olan ARB uzantıları haline gelebilirler.
Tüm uzantıların ve daha önce de belirtildiği gibi, OpenGL 1.2 ve sonraki tüm işlev işaretçi türlerinin işlev işaretçi türlerini ve işlev prototiplerini elde etmek için, başlık dosyalarının OpenGL kayıt defterinden indirilmesi gerekir. Tartışıldığı gibi, yeni uygulamalar için çekirdek profili kullanmak daha iyidir, bu nedenle GL/gl.h
ve yerine
(GL/glcorearb.h
eklenmesi tercih edilir. GL/glext.hGL/glcorearb.h
kullanıyorsanız, GL/gl.h
eklemeyin).
GL/wglext.h
içinde WGL için uzantılar da vardır. Örneğin, desteklenen tüm uzantıların listesini alma işlevi aslında bir uzantının kendisidir, wglGetExtensionsStringARB
(desteklenen tüm uzantıların boşlukla ayrılmış bir listesini içeren büyük bir dize döndürür).
Uzantıları almak da wglGetProcAddress
aracılığıyla gerçekleştirilir, bu nedenle sarmalayıcımızı daha önce olduğu gibi kullanabiliriz.
Gelişmiş piksel biçimi ve bağlam oluşturma
WGL_ARB_pixel_format
uzantısı, gelişmiş piksel biçimi oluşturmamızı sağlar. Daha önce olduğu gibi, bir yapı kullanmıyoruz. Bunun yerine, aranan niteliklerin listesini geçiyoruz.
int pixel_format_arb;
UINT pixel_formats_found;
int pixel_attributes[] = {
WGL_SUPPORT_OPENGL_ARB, 1,
WGL_DRAW_TO_WINDOW_ARB, 1,
WGL_DRAW_TO_BITMAP_ARB, 1,
WGL_DOUBLE_BUFFER_ARB, 1,
WGL_SWAP_LAYER_BUFFERS_ARB, 1,
WGL_COLOR_BITS_ARB, 32,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 32,
WGL_STENCIL_BITS_ARB, 8,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
0
};
BOOL result = wglChoosePixelFormatARB(dc, pixel_attributes, NULL, 1, &pixel_format_arb, &pixel_formats_found);
Benzer şekilde, WGL_ARB_create_context
uzantısı bize gelişmiş bağlam oluşturma olanağı sağlar:
GLint context_attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
HGLRC new_rc = wglCreateContextAttribsARB(dc, 0, context_attributes);
Parametrelerin ve işlevlerin kesin açıklaması için OpenGL spesifikasyonuna bakın.
Neden onlarla başlamadık? Bunun nedeni, uzantılar bunu yapmamıza izin veriyor ve uzantıları almak için wglGetProcAddress
‘e ihtiyacımız var, ancak bu yalnızca etkin ve geçerli bir bağlamla çalışır. Yani özünde, istediğimiz bağlamı yaratmadan önce, bazı bağlamların halihazırda aktif olması gerekir ve buna genellikle sahte bağlam denir.
Ancak Windows, bir pencerenin piksel biçiminin birden fazla kez ayarlanmasına izin vermez. Bu nedenle, yeni şeyler uygulamak için pencerenin yok edilmesi ve yeniden oluşturulması gerekiyor:
wglMakeCurrent(dc, NULL);
wglDeleteContext(rc);
ReleaseDC(window_handle, dc);
DestroyWindow(window_handle);
// Recreate the window...
Tam örnek kod:
/* We want the core profile, so we include GL/glcorearb.h. When including that, then
GL/gl.h should not be included.
If using compatibility profile, the GL/gl.h and GL/glext.h need to be included.
GL/wglext.h gives WGL extensions.
Note that Windows.h needs to be included before them. */
#include <cstdio>
#include <Windows.h>
#include <GL/glcorearb.h>
#include <GL/wglext.h>
LRESULT CALLBACK window_procedure(HWND, UINT, WPARAM, LPARAM);
void* get_proc(const char*);
/* gl_module is for opening the DLL, and the quit flag is here to prevent
quitting when recreating the window (see the window_procedure function) */
HMODULE gl_module;
bool quit = false;
/* OpenGL function declarations. In practice, we would put these in a
separate header file and add "extern" in front, so that we can use them
anywhere after loading them only once. */
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
PFNGLGETSTRINGPROC glGetString;
int WINAPI WinMain(HINSTANCE instance_handle, HINSTANCE prev_instance_handle, PSTR cmd_line, int cmd_show) {
/* REGISTER WINDOW */
WNDCLASS window_class;
// Clear all structure fields to zero first
ZeroMemory(&window_class, sizeof(window_class));
// Define fields we need (others will be zero)
window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
window_class.lpfnWndProc = window_procedure;
window_class.hInstance = instance_handle;
window_class.lpszClassName = TEXT("OPENGL_WINDOW");
// Give our class to Windows
RegisterClass(&window_class);
/* *************** */
/* CREATE WINDOW */
HWND window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
TEXT("OPENGL_WINDOW"),
TEXT("OpenGL window"),
WS_OVERLAPPEDWINDOW,
0, 0,
800, 600,
NULL,
NULL,
instance_handle,
NULL);
HDC dc = GetDC(window_handle);
ShowWindow(window_handle, SW_SHOW);
/* ************* */
/* PIXEL FORMAT */
PIXELFORMATDESCRIPTOR descriptor;
// Clear all structure fields to zero first
ZeroMemory(&descriptor, sizeof(descriptor));
// Describe our pixel format
descriptor.nSize = sizeof(descriptor);
descriptor.nVersion = 1;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER | PFD_SWAP_LAYER_BUFFERS;
descriptor.iPixelType = PFD_TYPE_RGBA;
descriptor.cColorBits = 32;
descriptor.cRedBits = 8;
descriptor.cGreenBits = 8;
descriptor.cBlueBits = 8;
descriptor.cAlphaBits = 8;
descriptor.cDepthBits = 32;
descriptor.cStencilBits = 8;
// Ask for a similar supported format and set it
int pixel_format = ChoosePixelFormat(dc, &descriptor);
SetPixelFormat(dc, pixel_format, &descriptor);
/* *********************** */
/* RENDERING CONTEXT */
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
/* ***************** */
/* LOAD FUNCTIONS (should probably be put in a separate procedure) */
gl_module = LoadLibrary(TEXT("opengl32.dll"));
wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)get_proc("wglGetExtensionsStringARB");
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)get_proc("wglChoosePixelFormatARB");
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)get_proc("wglCreateContextAttribsARB");
glGetString = (PFNGLGETSTRINGPROC)get_proc("glGetString");
FreeLibrary(gl_module);
/* ************** */
/* PRINT VERSION */
const GLubyte *version = glGetString(GL_VERSION);
printf("%s\n", version);
fflush(stdout);
/* ******* */
/* NEW PIXEL FORMAT*/
int pixel_format_arb;
UINT pixel_formats_found;
int pixel_attributes[] = {
WGL_SUPPORT_OPENGL_ARB, 1,
WGL_DRAW_TO_WINDOW_ARB, 1,
WGL_DRAW_TO_BITMAP_ARB, 1,
WGL_DOUBLE_BUFFER_ARB, 1,
WGL_SWAP_LAYER_BUFFERS_ARB, 1,
WGL_COLOR_BITS_ARB, 32,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 32,
WGL_STENCIL_BITS_ARB, 8,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
0
};
BOOL result = wglChoosePixelFormatARB(dc, pixel_attributes, NULL, 1, &pixel_format_arb, &pixel_formats_found);
if (!result) {
printf("Could not find pixel format\n");
fflush(stdout);
return 0;
}
/* **************** */
/* RECREATE WINDOW */
wglMakeCurrent(dc, NULL);
wglDeleteContext(rc);
ReleaseDC(window_handle, dc);
DestroyWindow(window_handle);
window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
TEXT("OPENGL_WINDOW"),
TEXT("OpenGL window"),
WS_OVERLAPPEDWINDOW,
0, 0,
800, 600,
NULL,
NULL,
instance_handle,
NULL);
dc = GetDC(window_handle);
ShowWindow(window_handle, SW_SHOW);
/* *************** */
/* NEW CONTEXT */
GLint context_attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
rc = wglCreateContextAttribsARB(dc, 0, context_attributes);
wglMakeCurrent(dc, rc);
/* *********** */
/* EVENT PUMP */
MSG msg;
while (true) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// draw(); <- there goes your drawing
SwapBuffers(dc);
}
/* ********** */
return 0;
}
// Procedure that processes window events
LRESULT CALLBACK window_procedure(HWND window_handle, UINT message, WPARAM param_w, LPARAM param_l)
{
/* When destroying the dummy window, WM_DESTROY message is going to be sent,
but we don't want to quit the application then, and that is controlled by
the quit flag. */
switch(message) {
case WM_DESTROY:
if (!quit) quit = true;
else PostQuitMessage(0);
return 0;
}
return DefWindowProc(window_handle, message, param_w, param_l);
}
/* A procedure for getting OpenGL functions and OpenGL or WGL extensions.
When looking for OpenGL 1.2 and above, or extensions, it uses wglGetProcAddress,
otherwise it falls back to GetProcAddress. */
void* get_proc(const char *proc_name)
{
void *proc = (void*)wglGetProcAddress(proc_name);
if (!proc) proc = (void*)GetProcAddress(gl_module, proc_name);
return proc;
}
g++ GLExample.cpp -lopengl32 -lgdi32
ile MinGW/Cygwin veya cl GLExample.cpp opengl32.lib gdi32.lib user32.lib
ile MSVC derleyicisi ile derlenmiştir. Ancak OpenGL kayıt defterindeki başlıkların dahil etme yolunda olduğundan emin olun. Değilse, derleyiciye nerede olduklarını söylemek için g++
için -I
işaretini veya cl
için /I
işaretini kullanın. vardır.
macOS’ta Modern OpenGL 4.1’i kurun (Xcode, GLFW ve GLEW)
1. GLFW’yi yükleyin
İlk adım bir OpenGL penceresi oluşturmaktır. GLFW, OpenGL ile pencereler oluşturmak, GLFW’yi kurmak için önce dosyalarını www.glfw.org adresinden indirmek için Açık Kaynaklı, çok platformlu bir kitaplıktır.
GLFW klasörünü çıkarın, içeriği şöyle görünecektir
GLFW oluşturmak için CMake’i indirin ve yükleyin. www.cmake.org/download/ adresine gidin, CMake’i indirin ve MAC OS X için yükleyin
Xcode kurulu değilse. Mac App Store’dan Xcode’u indirin ve yükleyin.
GLFW klasörünün içinde yeni bir klasör Oluştur oluşturun
CMake’i açın, GLFW klasörünü seçmek için Kaynağa Gözat düğmesine tıklayın (CMakeLists.txt dosyasının bu klasörün içinde olduğundan emin olun). Bundan sonra, Yapıya Gözat düğmesine tıklayın ve önceki adımda yeni oluşturulan Oluştur klasörünü seçin.
Şimdi Yapılandır düğmesine tıklayın ve Varsayılan yerel derleyicileri kullan seçeneği ile üretici olarak Xcode‘u seçin ve Bitti‘ye tıklayın.
BUILD_SHARED_LIBS seçeneğini işaretleyin ve ardından tekrar Yapılandır düğmesine tıklayın ve son olarak Oluştur düğmesine tıklayın.
Nesilden sonra CMake şöyle görünmelidir
Şimdi Finder‘ı açın ve /usr‘a gidin, henüz orada değilse yerel bir klasör adı oluşturun. local klasörünü açın ve henüz orada değilse include ve lib olmak üzere iki klasör oluşturun.
Şimdi GLFW klasörünü açın ve Build’e gidin (CMake’in dosyaları oluşturduğu yer). GLFW.xcodeproj dosyasını Xcode’da açın.
Yükle > Mac’im‘i seçin ve ardından çalıştır‘a tıklayın (Şekilli düğmeyi oynat).
Artık başarıyla yüklenmiştir (uyarıları dikkate almayınız).
Finder’ı açın ve /usr/local/lib klasörüne gidin ve üç GLFW kitaplık dosyasının orada zaten bulunacağından emin olmak için (Eğer değilse, GLFW klasörü içinde Build klasörünü açın ve **src/Debug’a gidin ** tüm dosyaları /usr/local/lib dizinine kopyalayın)
Finder’ı açın ve /usr/local/include‘a gidin ve içinde glfw3.h ve glfw3native.h adında iki başlık dosyası bulunan bir GLFW klasörü zaten mevcut olacaktır.
2. GLEW’yi yükleyin
GLEW, OpenGL uzantılarını sorgulamaya ve yüklemeye yardımcı olan bir çapraz platform kitaplığıdır. Hedef platformda hangi OpenGL uzantılarının desteklendiğini belirlemek için çalışma zamanı mekanizmaları sağlar. Yalnızca modern OpenGL içindir (çalışma zamanında işlevlerin belirlenmesini gerektiren OpenGL sürüm 3.2 ve üstü). Yüklemek için önce dosyalarını glew.sourceforge.net adresinden indirin.
GLFW klasörünü çıkarın, içeriği şöyle görünecektir.
Şimdi Terminal’i açın, GLEW Klasörüne gidin ve aşağıdaki komutları yazın
make
sudo make install
make clean
Şimdi GLEW başarıyla kuruldu. Open Finder’ın kurulu olduğundan emin olmak için /usr/local/include adresine gidin ve içinde glew.h, glxew adında üç başlık dosyası bulunan bir GL klasörü zaten mevcut olacaktır. .h ve wglew.h
Finder’ı açın ve /usr/local/lib adresine gidin, GLEW kitaplık dosyaları orada zaten bulunacaktır
3. Test Et ve Çalıştır
Şimdi GLFW ve GLEW’yi başarıyla kurduk. Kodlama zamanı. Xcode’u açın ve yeni bir Xcode projesi oluşturun. Komut Satırı Aracı’nı seçin, ardından devam edin ve dil olarak C++‘ı seçin.
Xcode, yeni bir komut satırı projesi oluşturacaktır.
Proje adına tıklayın ve Yapı Ayarları sekmesinin altında Temelden Tümüne geçiş yapın, Arama Yolları bölümünün altında, Başlık Arama Yollarına /usr/local/include ekleyin ve ekleyin /usr/local/lib Kitaplık Arama Yollarında
Proje adına tıklayın ve İnşa Etme Aşamaları sekmesi altında ve İkili Kitaplıklarla Bağlantı altında OpenGL.framework ekleyin ve ayrıca yakın zamanda oluşturulan GLFW ve GLEW kitaplıklarını ekleyin. /usr/local/lib
Artık C++ ve Xcode kullanarak macOS üzerinde Modern Open GL 4.1’de kodlamaya hazırız. Aşağıdaki kod, Boş Ekran Çıktısı ile GLFW kullanarak bir OpenGL Penceresi oluşturacaktır.
#include <GL/glew.h>
#include <GLFW/glfw3.h>
// Define main function
int main()
{
// Initialize GLFW
glfwInit();
// Define version and compatibility settings
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
// Create OpenGL window and context
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);
glfwMakeContextCurrent(window);
// Check for window creation failure
if (!window)
{
// Terminate GLFW
glfwTerminate();
return 0;
}
// Initialize GLEW
glewExperimental = GL_TRUE; glewInit();
// Event loop
while(!glfwWindowShouldClose(window))
{
// Clear the screen to black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
// Terminate GLFW
glfwTerminate(); return 0;
}
Çapraz Platform OpenGL bağlam oluşturma (SDL2 kullanarak)
OpenGL bağlamıyla bir Pencere Oluşturma (uzantı GLEW aracılığıyla yükleniyor):
#define GLEW_STATIC
#include <GL/glew.h>
#include <SDL2/SDL.h>
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO); /* Initialises Video Subsystem in SDL */
/* Setting up OpenGL version and profile details for context creation */
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
/* A 800x600 window. Pretty! */
SDL_Window* window = SDL_CreateWindow
(
"SDL Context",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
800, 600,
SDL_WINDOW_OPENGL
);
/* Creating OpenGL Context */
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
/* Loading Extensions */
glewExperimental = GL_TRUE;
glewInit();
/* The following code is for error checking.
* If OpenGL has initialised properly, this should print 1.
* Remove it in production code.
*/
GLuint vertex_buffer;
glGenBuffers(1, &vertex_buffer);
printf("%u\n", vertex_buffer);
/* Error checking ends here */
/* Main Loop */
SDL_Event window_event;
while(1) {
if (SDL_PollEvent(&window_event)) {
if (window_event.type == SDL_QUIT) {
/* If user is exiting the application */
break;
}
}
/* Swap the front and back buffer for flicker-free rendering */
SDL_GL_SwapWindow(window);
}
/* Freeing Memory */
glDeleteBuffers(1, &vertex_buffer);
SDL_GL_DeleteContext(gl_context);
SDL_Quit();
return 0;
}
C++ ve Kakao ile OpenGL 4.1 Oluşturma
OpenGL Alma
OpenGL ile ilgili en yaygın yanılgılardan biri, bunun 3. parti kaynaklardan kurulabilen bir kütüphane olduğudur. Bu yanılgı, “OpenGL’yi nasıl kurarım” veya “OpenGL SDK’yı nereden indiririm” şeklinde birçok soruya yol açar.
OpenGL bilgisayar sistemine bu şekilde girmez. OpenGL tek başına, bir uygulamanın izlemesi gereken komutlara ilişkin yalnızca bir dizi belirtimdir. Yani önemli olan uygulamadır. Ve şimdilik, OpenGL uygulamaları GPU sürücülerinin bir parçasıdır. Gelecekte, yeni GPU programlama arayüzü OpenGL’yi bir kitaplık olarak uygulamaya izin verdiğinde bu * değişebilir*, ancak şimdilik bu, grafik sürücülerine yönelik bir programlama API’sidir.
OpenGL ilk piyasaya sürüldüğünde, API bir şekilde orijinal Sun Irix’e ek olarak Windows, Solaris ve Linux’un (LSB-4 Masaüstü) ABI (Uygulama İkili Arayüzü) sözleşmesine dahil oldu. Apple takip etti ve aslında OpenGL’yi MacOS X’e o kadar derinden entegre etti ki, mevcut OpenGL sürümü yüklü MacOS X sürümüne sıkı sıkıya bağlı. Bunun dikkate değer bir etkisi vardır, bu işletim sistemleri için sistem programlama ortamları (yani, bu sistemleri doğal olarak hedefleyen derleyici ve bağlayıcı araç zinciri) aynı zamanda OpenGL API tanımlarını da gerektirir. Bu nedenle, OpenGL için gerçekten bir SDK kurmak gerekli değildir. Hedeflenen ABI’yi izleyen bir yapı ortamının kurulu olduğu varsayılarak, özel bir SDK kurulmasına gerek kalmadan OpenGL’yi bu işletim sistemlerinde programlamak teknik olarak mümkündür.
Bu katı ABI kurallarının bir yan etkisi, bağlama arabirimi aracılığıyla açığa çıkan OpenGL sürümünün, hedef platformda çalışan programların kullanılabilir olmasını bekleyebileceği en düşük ortak payda olmasıdır. Bu nedenle, modern OpenGL özelliklerine, ayrıntılı olarak ayrı ayrı açıklanan genişletme mekanizması aracılığıyla erişilmelidir.
Linux
Linux’ta geliştirme paketlerini sistemin farklı yönleri için bölümlere ayırmak oldukça yaygındır, böylece bunlar ayrı ayrı güncellenebilir. Çoğu Linux dağıtımında, OpenGL için geliştirme dosyaları, genellikle bir masaüstü uygulama geliştirme meta paketi için bir bağımlılık olan özel bir pakette bulunur. Bu nedenle, Linux için OpenGL geliştirme dosyalarının kurulumu, genellikle masaüstü geliştirme meta paketlerinin/paketlerinin kurulumuyla halledilir.*
Microsoft Windows
API bağlama kitaplığı “opengl32.dll” (Windows’un hem 32 bit hem de 64 bit sürümleri için bu şekilde adlandırılır), Windows NT-4 ve Windows 95B’den (her ikisi de yaklaşık 1997) beri her Windows sürümüyle varsayılan olarak gönderilir. Ancak bu DLL, gerçek bir OpenGL uygulaması sağlamaz (başka bir OpenGL uygulaması kurulu değilse, tek amacı programlar için bir güvenlik ağı olarak hareket etmek olan bir yazılım geri dönüşü dışında). Bu DLL, Windows’a aittir ve değiştirilmemeli veya taşınmamalıdır! Modern OpenGL sürümleri, Yüklenebilir İstemci Sürücüsünün (ICD) bir parçası olarak gönderilir ve her Windows sürümüyle önceden yüklenmiş olarak gelen varsayılan ‘opengl32.dll’ aracılığıyla erişilir. Ancak, Microsoft tarafından dahili olarak Windows Update aracılığıyla yüklenen grafik sürücülerinin bir OpenGL ICD’sini yüklemeyeceğine/güncellemeyeceğine karar verildi. Sürücülerin otomatik olarak yüklendiği bu tür yeni Windows yüklemeleri, modern OpenGL özellikleri için destekten yoksundur. Modern özelliklere sahip bir OpenGL ICD elde etmek için grafik sürücülerinin doğrudan GPU satıcısının web sitesinden indirilmesi ve manuel olarak kurulması gerekir.
Geliştirme ile ilgili olarak, kendi başına hiçbir ekstra adım atılmamalıdır. Windows ABI belirtimlerini izleyen tüm C/C++ derleyicileri, OpenGL’den yararlanan yürütülebilir dosyaları oluşturmak ve bağlamak için gereken başlıklar ve bağlayıcı saplaması (opengl32.lib) ile birlikte gelir.
Java ve LWJGL 3.0 ile Opengl Bağlamı Oluşturun
Bu örnek kodda, LWJGL 3.0+ kullanarak boş bir Opengl Penceresi oluşturacağız, bu, IDE’nizde proje oluşturma adımlarını içermiyor
- Tüm kazanı içerecek bir sınıf adı WindowManager oluşturun plate code for creating a opengl context window on screen
WindowManager.java
import org.lwjgl.glfw.*;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.*;
/**
* Class Containing code related to inflating Opengl Window
*/
public class Displaymanager {
private static long window;
public static void createDisplay(){
// Setup an error callback. The default implementation
// will print the error message in System.err.
GLFWErrorCallback.createPrint(System.err).set();
// Initialize GLFW. Most GLFW functions will not work before doing this.
if ( !glfwInit() )
throw new IllegalStateException("Unable to initialize GLFW");
// Configure our window
glfwDefaultWindowHints(); // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable
int WIDTH = 300;
int HEIGHT = 300;
// Create the window
window = glfwCreateWindow(WIDTH, HEIGHT, "Hello World!", NULL, NULL);
if ( window == NULL )
throw new RuntimeException("Failed to create the GLFW window");
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
glfwSetWindowShouldClose(window, true); // We will detect this in our rendering loop
});
// Get the resolution of the primary monitor
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center our window
glfwSetWindowPos(
window,
(vidmode.width() - WIDTH) / 2,
(vidmode.height() - HEIGHT) / 2
);
// Make the OpenGL context current
glfwMakeContextCurrent(window);
// Enable v-sync
glfwSwapInterval(1);
// Make the window visible
glfwShowWindow(window);
}
public static boolean isCloseRequested(){
return glfwWindowShouldClose(window);
}
public static void updateDisplay(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
glfwSwapBuffers(window); // swap the color buffers
// Poll for window events. The key callback above will only be
// invoked during this call.
glfwPollEvents();
}
public static void destroyDisplay(){
// Terminate GLFW and free the error callback
cleanUp();
glfwTerminate();
glfwSetErrorCallback(null).free();
}
private static void cleanUp() {
// Free the window callbacks and destroy the window
glfwFreeCallbacks(window);
glfwDestroyWindow(window);
}
}
- Ardından, oluşturulan tüm yukarıdaki işlevleri çağıracak ana işleme döngüsünü içeren bir sınıf oluşturun.
OpenGlMain.java
import org.lwjgl.opengl.GL;
import renderEngine.Displaymanager;
import static org.lwjgl.opengl.GL11.glClearColor;
/**
* Class to test the opengl Window
*/
public class OpenGlMain {
public static void main(String[] args) {
Displaymanager.createDisplay();
// This line is critical for LWJGL's interoperation with GLFW's
// OpenGL context, or any context that is managed externally.
// LWJGL detects the context that is current in the current thread,
// creates the GLCapabilities instance and makes the OpenGL
// bindings available for use.
GL.createCapabilities();
while (!Displaymanager.isCloseRequested()){
// Set the clear color
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
Displaymanager.updateDisplay();
}
Displaymanager.destroyDisplay();
}
}
Daha fazla ayrıntı için ödeme resmi LWJGL Guide