Думаю, пора выкладывать. Данный тутор показывает инициализацию OpenGL и рендеринг простой сцены, а именно, пирамиды. Этот туториал основан на предыдущем, и новый код добавлен к уже имеющемуся. В данной теме будет только новый код, в исходнике же новый код помечен в комментариях - начало кода обозначено как New Code, и соответственно окончание нового кода обозначено как End.
Лицензия превыше всего : любая информация которая здесь предоставлена, может содержать те или иные неточности, код может не компилиться при некоторых условиях. Все что здесь есть, предоставлено мною без каких-либо гарантий и ответственности, и я не несу никакой ответственности за любой возможный ущерб, который может быть вызван использованием любой части данного поста, кода или информации в любом виде и при любых обстоятельствах.
Теперь новые данные :
* Подключим библиотеки, если они не подключены в настройках
Code
/* NEW CODE */
// Add required libs on fly, or you can set 'em up in Settings->Link menu
* В функции WinMain добавим новый код, но сперва здесь начало функции для наглядности
Code
// Below functions we need
// Main function int WINAPI WinMain(HINSTANCE inst,HINSTANCE prev_inst,LPSTR line,int show) {
* То что есть в предыдущем туторе пропустим и далее новый код - мы получаем хендл окна и вызываем 2 наших новых функции, то есть сперва настраиваем pixel format, а уже потом делаем настройки OpenGL для рендеринга.
Code
/* NEW CODE */
// Now we need device context
dc = GetDC(w_handle);
// Pass it to our pixel format setup func
_pixel_format(dc);
// After done, we want to setup GL stuff, i.e. perspective and etc.
setup_screen(640,480);
/* END */
* На этом дополнения заканчиваются, все что нужно, уже сделано. Немного старого кода, закрывающего функцию - тоже для наглядности
Code
return _process(w_handle); // return result back to, after it's handled by _process function }
* Дальше в базовом коде была функция LRESULT CALLBACK w_process(HWND w_handle,UINT _msg,WPARAM wparam,LPARAM lparam), но она у нас без изменений, поэтому переходим еще дальше, и соответственно в функцию WPARAM _process(HWND w_handle), поскольку она небольшая, то весь ее код будет приведен ниже, новый и старый.
* Здесь мы добавляем условие else в наш цикл, вызываем нашу функцию для отрисовки сцены и свопируем буферы. Делаем мы это там, где раньше был комментарий по поводу возможности добавления функций для отрисовки т.д. в данном участке программы.
Code
// We will pass window handle to this one in WinMain function (at the end of) WPARAM _process(HWND w_handle) { MSG msg;
// This one is the main application loop, it's infinite.
while(1) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // Dispatch system messages { if(msg.message == WM_QUIT) break; // If got WM_QUIT message then break the loop and exit from application
TranslateMessage(&msg); // Otherwise, let's find out what the message is exactly DispatchMessage(&msg); // And execute it }
/* NEW CODE */
// Below we draw our stuff else { draw();
// Swap buffers SwapBuffers(dc); }
/* END */
}
return(msg.wParam); }
* На этом заканчиваются все модификации имеющихся функций, и идут новые, начнем с int _pixel_format(HDC dc) .
* Сперва мы обьявляем структуру PIXELFORMATDESCRIPTOR и заполняем ее, это настройки для OpenGL, в частности, это глубина Z-буфера, и глубина цвета, также мы установим тип пикселей PFD_TYPE_RGBA;, то есть составной цвет, это - красный, зеленый, синий и альфа канал. Цвета задаются путем смешивания вышеприведенных трех базовых цветов, альфа канал, это значение прозрачности. Также мы настраиваем accumulation и stencil буферы. Другие настройки мы пока не трогаем. Вообще рекомендую посмотреть самую подробную информацию на MSDN.com по этому вопросу.
Потом, нам нужно проверить как наш pixel format подходит к контексту устройства, и для этого мы используем ChoosePixelFormat(dc,&desc). Если проверка прошла успешно, мы назначаем данный pixel format вызывая функцию SetPixelFormat(dc,p_format,&desc).
Если обе эти вещи были успешно завершены, нам нужно создать контекст рендера для OpenGL, делаем это так - _glrc = wglCreateContext(dc); Тем не менее, контекстов рендера может быть несколько, несмотря на то что мы создали только один контекст. Поэтому нам нужно сделать какой-либо из имеющихся контекстов рендера текущим. В нашем случае все просто - wglMakeCurrent(dc,_glrc);. Делать это нужно в любом случае, даже если контекст только один. Ниже код :
/
Code
/ Below func to set up pixel format and GL context
int _pixel_format(HDC dc) { // Our pixel format struct
PIXELFORMATDESCRIPTOR desc = {0};
// Int variable to get ChoosePixelFormat func result
int p_format;
// It's strongly recommended you to advance to MSDN for more info about this one below // Note : not all the existing variables are set up here, but only required ones
desc.nSize = sizeof(PIXELFORMATDESCRIPTOR); // Size of struct shulda be set to sizeof(PIXELFORMATDESCRIPTOR) desc.nVersion = 1; // Version shulda be set to 1
desc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; // Properties of pixel format desc.dwLayerMask = PFD_MAIN_PLANE; // Although this was only used in earlier GL versions, we 'll set it up too desc.iPixelType = PFD_TYPE_RGBA; // Type of pixel data, we need RGBA (Red,Green,Blue, Alpha channel value) desc.cColorBits = 32; // If in RGBA mode, then it's size of color buffer excluding alpha values desc.cDepthBits = 24; // Depth of z-buffer (depth buffer) desc.cAccumBits = 0; // Accumulation buffer desc.cStencilBits = 0; // Stencil buffers
// Check does pixel format match given device context or it ain't
// If results from above are OK, we want to set our pixel format then if (SetPixelFormat(dc,p_format,&desc) == FALSE) { return 0; }
// If we're OK with pixel format, now we need to create GL rendering context for device context _glrc = wglCreateContext(dc);
// We want to make our GL context to be current GL context, although we have no another contexts, we // need to call this func in any case. wglMakeCurrent(dc,_glrc);
return 1; }
* Теперь мы настроим пару вещей в OpenGL, для отрисовки сцены. Это viewport, то есть область видимости в пределах окна, условно говоря. Мы задаем viewport так чтобы он соответствовал размерам окна. Можно сделать его и меньшим, так поступают например при рендеринге в текстуру. Для интереса, можно попробовать изменить ширину и длину на, допустим, 128х128. Также мы устанавливаем режим матриц в GL_PROJECTION и в GL_MODELVIEW. Это матрица проекции и матрица вида. Между этими делами мы также задаем и gluPerspective(......), это угол обзора, то есть FOV (Field Of View) в градусах, у нас это 90 градусов, потом соотношение сторон экрана (Aspect Ratio) и отсекающие плоскости, Z-Near и Z-Far (clipping planes).
// Perspective projection matrix // Variables : FOV (field of view in angles), aspect ratio (x to y), Z near, Z far (both are clipping planes) gluPerspective(90.0f,(float)width/(float)height,1.0f,10000.0f);
// Model view matrix glMatrixMode(GL_MODELVIEW);
// Identity matrix glLoadIdentity(); }
* Пришло время заняться непосредственно сценой, эта функция последняя в туторе. Для начала мы очищаем экран и задаем идентичную матрицу.(Identity matrix). Потом мы трансформируем вид. Это нужно, чтобы навести камеру на пирамиду, которую будем рисовать, делаем это так - gluLookAt(0,0,2.5,0,0,0,0,1,0); Здесь 9 параметров, первые 3 это позиция камеры в мировых координатах., другие 3 это вектор направления взгдяда, то есть, куда камера смотрит (в каком направлении), последние 3 - это up vector, то есть верх у нас это Y (в разных других программах/ играх верх может быть по оси Z).
Далее мы вертим пирамиду по осям Y и Z, используя glRotatef(.....);, также включаем тест глубины, чтобы определить, какие обьекты находятся ближе к камере или дальше, делаем это так - glEnable(GL_DEPTH_TEST);.
Пирамиду мы рисуем не целиком, а только боковые стены, 4 штуки, соответственно. Поскольку это треугольники (причем одна точка общая для всех 4), мы сообщаем об этом OpenGL - glBegin(GL_TRIANGLES);. Далее мы задаем цвет для каждого треугольника отдельно и рисуем каждый из них, то есть, мы задаем все три вершины треугольника, и подаем их на рендер, вызывая функцию glVertex3f(.....); для каждого из треугольников по три раза., то есть по одному разу для каждой из вершин треугольника. Закончив, мы сообщаем об этом в OpenGL - glEnd(); и также отключаем тест глубины - glDisable(GL_DEPTH_TEST);.
Код :
Code
void draw() { // Clear the screen and load identity matrix glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();
// View transform // Variables : eye position (3 vars), view direction (3 vars), up vector (3 vars) // Explanations : eye position is point from we're looking at, view direction is point we are // looking at, and up vector describes our coordinate system, we set Y to be pointed to the up gluLookAt(0,0,2.5,0,0,0,0,1,0);
// Just a variable to change angle value (in degrees) to rotate our pyramid to d = d + 0.5f;
// Rotate the pyramid using Z axis and Y axis, we pass our "d" variable below // Variables : angle, axis (3 vars : x,y and z respectively) glRotatef(d,0,0,1); glRotatef((d*0.2f),0,1,0);
// Depth test to grab info how far objects are located from glEnable(GL_DEPTH_TEST);
// Start to draw triangles glBegin (GL_TRIANGLES);
// Below we set up color for EACH triangle. We draw only 4 sides of pyramid, without drawing it's bottom. // You can draw the bottom using GL_QUADS (you will need 1 quad then), or using GL_TRIANGLES (2 triangles to draw then)
glColor3ub(255,255,0);
// We draw triangle by setting up it's vertices, 3 at all.
// Note the pyramid has 5 vertices, 1 at the top, and 4 at the bottom. the top vertex is shared between all 4 sides (4 triangles as well)
Поймал три бага(с манифестом, с юникодом и с линковкой), связанных с настройками. Наверное, лучше выкладывать весь проект.
Ну это можно настроить в Visual C++, в лицензии сказано что в разных версиях могут быть некие отличия.
Quote (nilrem)
А почему ты коменты в исходниках на русском не пишешь?
Так быстрее, потому что в английском нет conjugation для adjective и noun (в смысле нет форм прилагательных и существительных слов), вобщем из двух иностранных это самый простой язык, там не все есть в грамматике что в других языках. И также он многим понятен в разных странах, больше чем только из тех кто русский знает аудитория.
Quote (nilrem)
А так - нормальный туториал.
Ну основы тут показаны, вроде все должно быть понятно.
Допустим. Но какова в данном случае семантика переменной dc и по каком сообщению её присваивать? Ведь первый то пост писан не в мелкососфте. Откуда там знать, констекст какого девайса понадобился форумчанину и для чего? Не всё так плохо, как оно есть на самом деле.
Сообщение отредактировал Тритон - Вторник, 24 Апреля 2012, 11:58
device context в вин апи используется для работы с графикой через GDI (любая функция рисования там требует первым параметром контекст устройства). Т.е. это что-то вроде холста, на котором происходит рисование. Каждое окно может иметь свой контекст. Получить его можно в любой момент после создания и до удаления окна.
В данном случае контекст устройства используется для инициализации OpenGL.
Сообщение отредактировал Apati - Вторник, 24 Апреля 2012, 12:35
device context в вин апи используется для работы с графикой через GDI (любая функция рисования там требует первым параметром контекст устройства)
Птзолдта прочитать и сам могу. Объясни толком, чей контекст.
Quote (Apati)
В данном случае контекст устройства используется для инициализации OpenGL.
Допустим. А от какого окна?
Quote (Apati)
Получить его можно в любой момент после создания и до удаления окна.
Допустим. Но вот в педзолдтовых примерах его не надо получать в мессаге WM_CREATE. А в каком событии это надо сделать в данном случае? Не всё так плохо, как оно есть на самом деле.
Добавлено (11.05.2012, 06:10) --------------------------------------------- Ни когда не поверю, что у меня какая то сложная гога. Тупейший же глюк. Как с ним бороться?
Добавлено (11.05.2012, 09:16) --------------------------------------------- И
Quote
C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|4|error: fstream.h: No such file or directory| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|5|error: iostream.h: No such file or directory| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|10|warning: ignoring #pragma comment | C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|12|warning: ignoring #pragma comment | C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|13|warning: ignoring #pragma comment | C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|228|warning: "/*" within comment| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|15|error: 'ofstream' in namespace 'std' does not name a type| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp||In function 'int WinMain(HINSTANCE__*, HINSTANCE__*, CHAR*, int)':| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|40|error: 'Log' was not declared in this scope| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|41|error: 'endl' was not declared in this scope| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp||In function 'bool InitApplication(HINSTANCE__*, int)':| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|90|error: 'Log' was not declared in this scope| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|90|error: 'endl' was not declared in this scope| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp||In function 'LRESULT WindowProcedureMainWindow(HWND__*, UINT, WPARAM, LPARAM)':| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|180|error: 'Log' was not declared in this scope| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|180|error: 'endl' was not declared in this scope| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp||In function 'bool SetOpenGLPixelFormat(HDC__*)':| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|195|error: 'Log' was not declared in this scope| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|195|error: 'endl' was not declared in this scope| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp||In function 'void SetupScreen(int, int)':| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|248|error: 'Log' was not declared in this scope| C:\tsserver\Projects\cpp\codeblocks\SeaJackals\SeaJackals.cpp|248|error: 'endl' was not declared in this scope| ||=== Build finished: 13 errors, 4 warnings ===|
Добавлено (11.05.2012, 09:20) --------------------------------------------- Вроде с файлами проекта и головами разобрался. Но