برنامه نویسی openGL - هفت خط کد انجمن پرسش و پاسخ برنامه نویسی

وبـــلاگ هــفت خــط کــد


آموزش های برنامه نویسی
۲۶۷ نفر آنلاین
۸۶ عضو و ۱۸۱ مهمان در سایت حاضرند

برنامه نویسی openGL

+2 امتیاز

سلام من تو Qt 5.2 میخوام با openGL برنامه گرافیک بنویسم اما نمیدونم چه طوری باید فایلش رو ایجاد کرد. لطفا بگید چطوری تو C++‎ میتونم یه برنامه openGL رو اجرا کنم؟

سوال شده فروردین 21, 1393  بوسیله ی cyber (امتیاز 38)   4 8 11
دوباره تگ گذاری شد شهریور 11, 1393 بوسیله ی BlueBlade
IDE مهم نیستش .

با OpenGL میخوای چی کارکنی ؟

تو کدوم Platform میخوای ازش استفاده کنی ؟
تازه دارم یاد میگیرمش برای پروژه. و فعلا میخوام یه کد خیلی ساده ی OpenGL رو اجرا کنم. در همین حد که یه پنجره خروجی بده و مثلا یه خط رو رسم کنه. و البته تو لینوکس دارم کار میکنم.
اگه میخوای در همون حد ساده جلو بری از همون Qt استفاده کن و من Qt کار نکردم که بگم چی کار کنی .
ولی اگه میخوای پیشرفته تر کار کنی از Qt برای OpenGL استفاده نکن .
میتونی از GLX یا EGL برای OpenGL توی لینوکس استفاده کنی.
این خیلی مهمه که OpenGL رو میخوای چیطوری باهاش کار کنی باید بگی تا بشه راهنمایی کرد .
بله درسته. شما از چه جهت میگید برای پیشرفته تر Qt خوب نیست و از GLX یا EGL استفاده کنم؟ میشه مزایاش رو بگید؟
و این که خب الان برای کدهای ساده میخوام اما خب جلوتر برم پیشرفته تر میشه. شما با کدومش کار کردید یا میتونید راهنمایی کنید؟ الان اصلا مهم نیست چه محیطی فقط میخوام یه چیزی باشه که کدهام رو توش اجرا کنم. الان هم اکلیپس دارم هم Qt ولی تو هیچ کدوم نمیدونم چطوری باید از openGL استفاده کنم.
OpenGLی که Qt به شما میده همون OpenGL ای هست که بقیه رابط ها میدن .
ولی اینجا موضوع سفارش سازی هست . و اینکه توی OpenGL پیشرفته باید همه چی زیر نظر خودنتون باشه و اینکه خیلی چیزها رو خودتون کنترل کنید .
 ( ساختن Context و انتخاب Profile و .... ) و اینکه برنامتون فقط بخاطر استفاده از OpenGL وابسته به Qt میشه .
واینکه Qt برای ++C نوشته شده . و اگه بخواهید از زبان C یا مثلا ASM ازش استفاده کنید باید با Qt ارتباط برقرار کنید که نمیشه ( نه اینکه نشه ، ولی نشدنش از شدنش بهتره ) . و کلا خودتون رو وابسته میکنید به Qt .و خیلی چیزهای دیگه ...
اگه در نهایت میخوای پیشرفته کار کنی از همین الان پیشرفته شروع کن .
ممنون. خب من الان تو مرحله اول فقط میخوام یه برنامه OpenGL رو اجرا کنم. اگه میشه رو هر محیطی که میشه راهشو بهم بگید. مراحل نوشتن تا کامپایل و اجرا منظورمه.
گفتم که تو لینوکسم و میخوام یه کد ساده رو پیاده سازی کنم.

1 پاسخ

+5 امتیاز
 
بهترین پاسخ

اول اینکه OpenGL چون چند-سکو هست تو سکو های مختلف دسترسی بهش مختلف هست .

توی Windows باید با توابع WGL به OpenGL دسترسی پیدا کنید . که توابع WGL در فایل opengl32.dll پیاده شدند .

توی Linux/Unix درواقع چندجور راه هست .در سیستم عامل های Linux معمولا از X برای مدیریت سیستم پنجره استفاده میشه و برای همین برای سیستم X یک Extension وجود داره به نام GLX .

معمولا وقتی Driver ( البته Driver های مربوط به X ) برای OpenGL نوشته میشه GLX هم داخلش پیاده سازی میکنن .

برای لینوکس شما باید به کتابخونه libGL.so برنامتون رو پیوند بدید .

حتما این فایل ها رو دانلود کن و داخل این مسیر /usr/include/GL/ کپیشون کن :

 

https://www.opengl.org/registry/api/GL/glext.h
https://www.opengl.org/registry/api/GL/glcorearb.h
https://www.opengl.org/registry/api/GL/glxext.h
https://www.opengl.org/registry/api/GL/wglext.h

 

خب حالا این کد یه پنجره خالی با X و یک Context نسخه 3.3 از نوع Core Profile درست میکنه و یه سری اطلاعات رو نمایش میده . البته تو این کد برای رسم تصاویر چیزی ننوشتم و بیشتر هدفش ساختن Context هست .

#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <GL/glx.h>
#include <GL/glcorearb.h>
#include <GL/glxext.h>

/*** Variables ***/

static const int attr [] = {
	GLX_BUFFER_SIZE		, 32 ,
	GLX_DOUBLEBUFFER	, True ,
	GLX_STENCIL_SIZE	, 8 ,
	GLX_DEPTH_SIZE		, 16 ,
	GLX_RENDER_TYPE		, GLX_RGBA_BIT,
	GLX_DRAWABLE_TYPE	, GLX_WINDOW_BIT,
	GLX_X_RENDERABLE	, True ,
	NULL			, NULL ,
};

static const GLint gl_attr[] ={
	GLX_CONTEXT_MAJOR_VERSION_ARB	, 3,
	GLX_CONTEXT_MINOR_VERSION_ARB	, 3,
	GLX_CONTEXT_PROFILE_MASK_ARB	, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
//	GLX_CONTEXT_FLAGS_ARB		, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
	NULL				, NULL ,
};

Display* dsp = NULL;
GLXFBConfig* fb_get_cfg,*fb_choose_cfg;
XVisualInfo* visual_info = NULL;
int maj,min,fb_get_elements,fb_choose_elements,screen;
Window window,root_window;
XSetWindowAttributes window_attr;
Colormap cmap;
GLXContext context;
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
Bool direct;
GLint glmaj,glmin,f1,f2,f3;

static void create_context_default (void);
static void create_context_new     (void);
static void create_context_arb     (void);
static void load_func 		   (void);

int main ()
{

	/*** Initialization ***/

	memset(&window_attr,0,sizeof(window_attr));
	dsp = XOpenDisplay(NULL);
	screen = DefaultScreen(dsp);
	glXQueryVersion (dsp,&maj,&min);
	fb_get_cfg = glXGetFBConfigs(dsp,screen,&fb_get_elements);

	fb_choose_cfg = glXChooseFBConfig (dsp , 0 , attr , &fb_choose_elements);
	visual_info = glXGetVisualFromFBConfig (dsp , fb_choose_cfg[0]);
	root_window = RootWindow (dsp ,screen);
	cmap = XCreateColormap (dsp , root_window ,visual_info->visual,AllocNone);

	window_attr.colormap = cmap;
	window_attr.border_pixel = 0;
	window_attr.event_mask = StructureNotifyMask;

	window = XCreateWindow (dsp , root_window , 0 , 0,640,480, 1 ,
				visual_info->depth ,InputOutput , visual_info->visual ,
				CWBackPixel|CWBorderPixel|CWColormap|CWEventMask ,&window_attr);

	XMapWindow(dsp,window);

	/*** OpenGL Context ***/
	load_func();
//	create_context_default();
	create_context_arb();
//	create_context_new();
	direct = glXIsDirect(dsp,context);
	PFNGLGETINTEGERVPROC _glGetIntegerv;
	_glGetIntegerv = glXGetProcAddressARB ((const GLubyte*) "glGetIntegerv");

        _glGetIntegerv(GL_MAJOR_VERSION,&glmaj);
        _glGetIntegerv(GL_MINOR_VERSION,&glmin);
	_glGetIntegerv(GL_CONTEXT_PROFILE_MASK,&f1);
	_glGetIntegerv(GL_CONTEXT_FLAGS,&f2);

	printf("GLX Server ! 				: %s\n",glXQueryServerString(dsp ,0,GLX_ARB_create_context_profile));
	printf("GLX Client ! 				: %s\n",glXGetClientString(dsp ,GLX_ARB_create_context_profile));
        printf("Direct 					: %s\n",(direct == True ? "True" : "False"));
        printf("Version (GetString) 			: %s\n",glGetString(GL_VERSION));
	printf("Version (GetIntegerv) 			: %d.%d\n",glmaj,glmin);
        printf("Profile/Flags 				: 0x%X.0x%X\n",f1,f2);

	/*** OpenGL Context ARB ***/
	XEvent event;
   	{
		GLboolean cont = GL_TRUE;
		while (cont) {
	    	XNextEvent(dsp, &event);
		}
	}

	return 0;
}


static void create_context_arb (void)
{
	context = glXCreateContextAttribsARB (dsp , fb_choose_cfg[0], 0,True,gl_attr);

	if(context == NULL)
	 	printf ("glXCreateNewContext()			: Failed !\n");
	else
		printf ("glXCreateNewContext()			: Succeeded !\n");

	if(!glXMakeCurrent(dsp,window,context))
		printf("glXMakeCurrent()			: Failed !\n");
	else
		printf("glXMakeCurrent()			: Succeeded !\n");
}

static void create_context_default (void)
{
	context = glXCreateContext(dsp , visual_info , None , True);
	if(context == NULL)
		printf ("glXCreateContext()			: Failed !\n");
	else
		printf ("glXCreateContext()			: Succeeded !\n");

	if(!glXMakeCurrent(dsp,window,context))
		printf ("glXMakeCurrent() 			: Failed !\n");
	else
		printf ("glXMakeCurrent()			: Succeeded !\n");
}

static void create_context_new (void)
{
	context = glXCreateNewContext(dsp , fb_choose_cfg[0],GLX_RGBA_TYPE,NULL,True);
	if(context == NULL)
	 	printf ("glXCreateNewContext()			: Failed !\n");
	else
		printf ("glXCreateNewContext()			: Succeeded !\n");

	if(!glXMakeCurrent(dsp,window,context))
		printf("glXMakeCurrent()			: Failed !\n");
	else
		printf("glXMakeCurrent()			: Succeeded !\n");
}

static void load_func (void)
{
	glXCreateContextAttribsARB = glXGetProcAddress ((const GLubyte*) "glXCreateContextAttribsARB");
	if(glXCreateContextAttribsARB == NULL)
		printf("glXGetProcAddress() 			: Failed !\n");
	else
		printf("glXGetProcAddress()			: Succeeded !\n");

}

یک پوشه درست کن مثلا به نام gltest .

حالا داخل پوشه ۲ تا پوشه دیگه درست کن به نام های bin و src .

این کد بالا رو در داخل پوشه src در فایل main.c ذخیره کن .

و این هم یه Makefile هست بره اینکه کدت رو راحت کامپایل کنی :

 

LIB_PATH		=/lib64/
LIB_FILES		=libGL.so libX11.so

DIR_SRC			=src/
DIR_BIN			=bin/

CC				= gcc
PRINT			= echo
CFLAGS			= -Wall -c -std=c99
LFLAGS			= -Wall

.PHONY: clean
.PHONY: glx
.PHONY: all
default: $(DIR_BIN)main

clean:
	rm -rf bin/*.o

$(DIR_BIN)main.o : $(DIR_SRC)main.c
	$(CC) $(CFLAGS) $(DIR_SRC)main.c -o $(DIR_BIN)main.o

$(DIR_BIN)main : $(DIR_BIN)main.o
	$(CC) $(LFLAGS)  -lGL -lX11 $(DIR_BIN)main.o -o $(DIR_BIN)main

این فایل بالا رو در پوشه gltest در فایل Makefile ذخیره کن .

و آخر هم ترمینال رو باز کن و به پوشه ی gltest برو و دستور make رو وارد کن . اونوقت برنامه کامپایل میشه و فایل اجرایی در پوشه ی bin درست میشه و میتونی اجراش کن .

البته اجباری نیست از Makefile استفاده کنی و میتونی خودت دستور ها رو در ترمینال بنویسی . ولی Makefile خیلی خوبه . باهاش کار کنی متوجه میشی که خیلی کارت رو راحت میکنه .

 

پاسخ داده شده فروردین 21, 1393 بوسیله ی Ali Rahbar (امتیاز 4,240)   6 16 46
انتخاب شد فروردین 27, 1393 بوسیله ی BlueBlade
تمام کارها رو انجام دادم اما در نهایت که تو ترمینال مینویسم make پیغام زیر رو میده:
Makefile:18: *** missing separator.  Stop.
همه کارایی که گفتیدو انجام دادم.

حالا میخواستم ببینم راه دیگه ای سراغ ندارید؟ مثلا طرز اجرا کردن OpenGL تو اکلیپس یا Qt رو اگه بگید خیلی ممنون میشم..
به عنوان مثال من میخوام کد زیر رو با یکی از IDE هایی که گفتم کامپایل و اجرا کنم. اگه میشه روش کار رو بگید.
/*
 * GL01Hello.cpp: Test OpenGL C/C++ Setup
 */
#include <GL/glut.h>  // GLUT, includes glu.h and gl.h
 
/* Handler for window-repaint event. Call back when the window first appears and
   whenever the window needs to be re-painted. */
void display() {
   glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
   glClear(GL_COLOR_BUFFER_BIT);         // Clear the color buffer
 
   // Draw a Red 1x1 Square centered at origin
   glBegin(GL_QUADS);              // Each set of 4 vertices form a quad
      glColor3f(1.0f, 0.0f, 0.0f); // Red
      glVertex2f(-0.5f, -0.5f);    // x, y
      glVertex2f( 0.5f, -0.5f);
      glVertex2f( 0.5f,  0.5f);
      glVertex2f(-0.5f,  0.5f);
   glEnd();
 
   glFlush();  // Render now
}
 
/* Main function: GLUT runs as a console application starting at main()  */
int main(int argc, char** argv) {
   glutInit(&argc, argv);                 // Initialize GLUT
   glutCreateWindow("OpenGL Setup Test"); // Create a window with the given title
   glutInitWindowSize(320, 320);   // Set the window's initial width & height
   glutInitWindowPosition(50, 50); // Position the window's initial top-left corner
   glutDisplayFunc(display); // Register display callback handler for window re-paint
   glutMainLoop();           // Enter the infinitely event-processing loop
   return 0;
}
مشکلی که توی Makefile هست بخاطر ویرایشگر اینجاست که Tab ها رو تبدیل به Space میکنه . در صورتی که در Makefile ها Tab خیلی مهم هست . برای همینه که Makefile درست اجرا نمیشه . تو خط های ۱۸و۲۱و۲۴ در Makefile فاصله های اول دستورها رو پاک کن و به جای هر کدوم یه Tab بزار .
من با IDE هایی که گفتی کار نکردم و درکل IDE مهم نیست .
بهرحال .... این کدی که اینجا گذاشتی از کتابخونه ی کمکی GLUT استفاده  میکنه .
من نمیدونم از کدوم توزیع Linux استفاده میکنی . فقط اینکه بسته glut یا freeglut رو باید نصب بکنی .
بعد این فایل رو ذخیره میکنی مثلا به نام gltest.cpp .
بعد با ترمینال به مسیر فایل میری و این ۲ خط رو وارد میکنی :
g++ -Wall -c gltest.cpp -o gltest.o
g++ -Wall -lGL -lglut gltest.o -o gltest
همین !
من بازم کاری که گفتیدو کردم اما این دفعه برای اجرای make کلی ارور تو ترمینال نمایش میده و توی پوشه ی bin هم فایلو درست نمیکنه. ارورش خیلی خیلی زیاد بود بالای ۲۰۰ خط من یکی از خطاشو میذارم ببینید:
src/main.c:224:1: error: stray ‘\275’ in program
این دوتا دستورم زدم:
g++ -Wall -c gltest.cpp -o gltest.o
g++ -Wall -lGL -lglut gltest.o -o gltest

اما میگه:
No such file or directory
g++: fatal error: no input files
freeglut هم نصبه.
من که با همین Makefile میزنم و make هم میشه . دیگه نمیدونم چی بگم ...
در مورد ۲ تا دستور خب معلومه که شما توی مسیر فایل نیستی که همچین خطایی رو بهت میده . توی هر مسیری که فایل gltest.cpp رو ذخیره کردی . با ترمینال و دستور cd به اون مسیر برو بعد دستورها رو اجرا کن .
(کارهایی رو که میکنی رو با دقت بیشتر انجام بده )
خب بلاخره موفق شدم.. (:
اما روش کار رو که خیلی دنبالش گشتم میزارم تا کسانی هم که بعدا خواستن برنامه ی OpenGL رو کامپایل کنن انجام بدن:
طرز کامپایل در لینوکس و ترجیحا فدورا:

اول اطمینان حاصل کنید که کامپایلر هاتون نصبن. برای کامپایل کدهای c میتونید از کامند gcc --version و برای c++از این کامند استفاده کنید: g++ --version . و همین طور برای gdb این رو: gdb --version
خب اگه نصب بودن که هیچ در غیر این صورت نصبشون کنید.

حالا باید برای کامپایل و اجرای OpenGL برخی از کتابخونه ها و رفرنس هاش رو نصب کنید:(از جمله GL و glut) خب اول باید چک کنید ببینید شاید نصب باشه. برای چک کردن از دو تا کامند زیر به ترتیب برای GL و glut استفاده کنید:

rpm -qa | grep glut
rpm -qa | grep GL

اما اگر نصب نبودن برای نصب کامندهای زیر رو بزنید:

yum install freeglut
yum install freeglut-devel
yum install mesa-libGLU
yum install mesa-libGLU-devel
yum install mesa-libGL
yum install mesa-libGL-devel
yum install mesa-libEGL

ترجیحا همه پکیج های بالا رو نصب می کنیم.
حالا میرسیم به کامپایل کردن برنامه:
یه کد OpenGL رو تو یه فایل .c ذخیره می کنید.مثلا main.c. بعد ترمینال رو باز کنید و به مسیر فایل برید و کامندهای زیر رو بزنید:

gcc -lglut -lGL -lGLU main.c -o main
./main

موفق باشید.
...