Смекни!
smekni.com

Використання OpenGL. Моделювання вогню (стр. 5 из 6)

При запуску програми в пам'яті комп'ютера створюється масив, що містить поточний стан кожної з часток. У нім також міститься така величина, як "прожите життя" частки. При русі окрім яскравості зменшується і життя частки. Коли спочатку рівна одиниці життя обнуляється, частка відроджується в основі полум'я з новими параметрами. Таким чином кількість задіяних часток постійна (у цій програмі їх 2000), а частки проживають усі нові і нові "життя". Як уже згадувалося, поведінка полум'я цілком залежить від того з якими параметрами відроджуються частки. Ось ці параметри: по-перше, початкове положення часток (x, y, z -координат, де z=const=3, а x і y вибираються згідно з розподілом, згідно з яким вірогідність появи частки в центральній частині (квадраті 1х1) квадрата 2х2 з центром в нулі втричі вище чим по околиці), далі початкові швидкості часток(x, y, z -координати вибираються випадково зі змінюваних інтервалів) і швидкість гасіння частки (також в межах заданого інтервалу). Наступна діаграма ілюструє усе вищесказане.

Рис. 3.2 Циклічна схема переміщення часток

Далі приводиться код самої програми:

#include <windows.h>// Заголовочний файл Windows

#include <math.h>

#include <stdio.h>// Заголовочний файл вводу/виводу

#include <gl&bsol;gl.h>// Заголовочний файл бібліотеки OpenGL32

#include <gl&bsol;glu.h>// Заголовочний файл бібліотеки GLu32

#include <gl&bsol;glaux.h>// Заголовочний файл бібліотеки The Glaux

#defineMAX_PARTICLES1000

#define MAX_COLORS 4// Кількість кольорів полум’я

#define BOTTOM-3.0f

HDChDC=NULL;

HGLRChRC=NULL;

HWNDhWnd=NULL;

HINSTANCEhInstance;

boolkeys[256];

boolactive=TRUE;

boolfullscreen=FALSE;

boolrainbow=TRUE;

floatslowdown=6.0f;// Сповільнення часток

floatxspeed;

floatyspeed;

floatzoom=-20.0f;

GLuintloop;// Параметр циклу

GLuintcol;// Поточний колір

GLuintdelay;// Затримка ефекту веселки

GLuinttexture[1];// Пам’ять для текстури часток

GLfloatr;

typedef struct// Оголошення змінних

{

boolactive;

floatlife;

floatfade;

floatr;

floatg;

floatb;

floatx;

floaty;

floatz;

floatxi;

floatyi;

floatzi;

floatxg;

floatyg;

floatzg;

}

particles;// Структура часток

particles particle[MAX_PARTICLES];// Масив часток

static GLfloat colors[MAX_COLORS][4]=// Кольори веселки

{

{1.0f,0.5f,0.5f},{1.0f,0.5f,0.24f},{1.0f,0.63f,0.4f},{1.0f,0.2f,0.5f}

};

LRESULTCALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

AUX_RGBImageRec *LoadBMP(char *Filename)// Завантаження Bitmap зображення

{

FILE *File=NULL;// Дескриптор файлу

if (!Filename)// Переконатися у наданні імені файлу

{

return NULL;

}

File=fopen(Filename,"r");// Перевірити чи існує файл

if (File)

{

fclose(File);

return auxDIBImageLoad(Filename)

}

return NULL; // Якщо завантаження не вдалося, то повертається NULL

}

int LoadGLTextures()

{

int Status=FALSE;// Індикатор стану

AUX_RGBImageRec *TextureImage[1];// Створити простір пам’яті длятекстур

memset(TextureImage,0,sizeof(void *)*1);// Встановити покажчик на NULL

if (TextureImage[0]=LoadBMP("Data/Particle.bmp"))// Завантажити текстури

{

Status=TRUE;glGenTextures(1, &texture[0]);// Створення однієї текстури

glBindTexture(GL_TEXTURE_2D, texture[0]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

}

if (TextureImage[0])

{

if (TextureImage[0]->data) // Якщо текстури не існує

{

free(TextureImage[0]->data); // Звільнити пам’ять

}

free(TextureImage[0]);

}

return Status;

}

GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Перевизначити розмір вікна

{

if (height==0)

{

height=1;// Висота рівна одиниці

}

glViewport(0,0,width,height);// Перезавантажити поточну область перегляду

glMatrixMode(GL_PROJECTION);// Вибір матриці проекту

glLoadIdentity();// Перезавантаження матриці проекту

// Обчислити коефіцієнт стискування вікна

gluPerspective(20.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

int InitGL(GLvoid)// Налаштування OpenGL

{

if (!LoadGLTextures())

return FALSE;

srand((DWORD)GetTickCount);

glShadeModel(GL_SMOOTH);

glClearColor(0.0f,0.0f,0.0f,0.0f);// Чорний фон

glClearDepth(1.0f);// Буфер глибини

glDisable(GL_DEPTH_TEST);

glEnable(GL_BLEND);// Змішування

glBlendFunc(GL_SRC_ALPHA,GL_ONE);// Тип змішування

glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);

glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);

glEnable(GL_TEXTURE_2D);

glBindTexture(GL_TEXTURE_2D,texture[0]);// Вибір текстури

for (loop=0;loop<MAX_PARTICLES;loop++)// Ініціалізація текстур

{

particle[loop].active=TRUE;// Make All The Particles Active

particle[loop].life=1.0f;// Give All The Particles Full Life

particle[loop].fade=float(rand()%100)/100.0f+0.3f;

particle[loop].r=colors[loop*(MAX_COLORS/MAX_PARTICLES)][0];// Вибір червоного кольору

particle[loop].g=colors[loop*(MAX_COLORS/MAX_PARTICLES)][1];// Вибір червоного кольору

particle[loop].b=colors[loop*(MAX_COLORS/MAX_PARTICLES)][2];// Вибір червоного кольору

particle[loop].xi=float((rand()%50)-26.0f)*10.0f;// Випадкова Швидкість На Осі X

particle[loop].yi=float((rand()%100)-25.0f)*10.0f;// Випадкова Швидкість На Осі Y

particle[loop].zi=float((rand()%50)-25.0f)*10.0f;;// Випадкова Швидкість На Осі Z

particle[loop].xg=0.0f;particle[loop].yg=-0.08f; particle[loop].zg=0.0f;

particle[loop].y=BOTTOM;

}

return TRUE;// Ініціалізація

}

int DrawGLScene(GLvoid)// Малювання

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Очищення екрану і буфера глибини

glLoadIdentity();

for (loop=0;loop<MAX_PARTICLES;loop++)// Цикл через усі частки

{

if (particle[loop].active)// Якщо частки активні

{

float x=particle[loop].x;// Захопити позицію Xfloat y=particle[loop].y;// Захопити позицію Y

float z=particle[loop].z+zoom;// Захопити позицію Z

int coin;

glColor4f(particle[loop].r,particle[loop].g,particle[loop].b,particle[loop].life)

glBegin(GL_TRIANGLE_STRIP);

glTexCoord2d(1,1); glVertex3f(x+0.5f,y+0.5f,z);

glTexCoord2d(0,1); glVertex3f(x-0.5f,y+0.5f,z);

glTexCoord2d(1,0); glVertex3f(x+0.5f,y-0.5f,z);

glTexCoord2d(0,0); glVertex3f(x-0.5f,y-0.5f,z);

glEnd();

particle[loop].x+=particle[loop].xi/(slowdown*1000);

particle[loop].y+=particle[loop].yi/(slowdown*1000);

particle[loop].z+=particle[loop].zi/(slowdown*1000);

particle[loop].xi+=particle[loop].xg;

particle[loop].yi+=particle[loop].yg;

particle[loop].zi+=particle[loop].zg;

particle[loop].life-=particle[loop].fade;// Скорочення терміну життя часток

if (particle[loop].life<0.0f)// Якщо частка перегорає

{

particle[loop].life=1.0f;// Дати нове життя

particle[loop].fade=float(rand()%100)/1000.0f+0.01f; // Випадкове значення

particle[loop].y=BOTTOM;

coin=rand();

if (coin<(RAND_MAX/8)) particle[loop].x=float(rand())/(RAND_MAX)-2.0f;

else

if (coin<(RAND_MAX/4)) particle[loop].x=float(rand())/(RAND_MAX)+1.0f;

else particle[loop].x=2*float(rand())/(RAND_MAX)-1.0f;

coin=rand();

if (coin<(RAND_MAX/8)) particle[loop].z=float(rand())/(RAND_MAX)-2.0f;

else

if (coin<(RAND_MAX/4)) particle[loop].z=float(rand())/(RAND_MAX)+1.0f;

else particle[loop].z=2*float(rand())/(RAND_MAX)-1.0f;

particle[loop].xi=xspeed+float((rand()%60)-32.0f);

particle[loop].yi=yspeed+float((rand()%700)-200.0f);

particle[loop].zi=float((rand()%60)-30.0f);

col=rand()*(MAX_COLORS+1)/RAND_MAX;

if (col>3) col=0;

particle[loop].r=colors[col][0];// Вибір червоного кольору

particle[loop].g=colors[col][1];// Вибір зеленого кольору

particle[loop].b=colors[col][2];// Вибір синього кольору

}

if (keys[VK_NUMPAD8] && (particle[loop].yg<1.5f)) particle[loop].yg+=0.01f;

if (keys[VK_NUMPAD2] && (particle[loop].yg>-1.5f)) particle[loop].yg-=0.01f;

if (keys[VK_NUMPAD6] && (particle[loop].xg<1.5f)) particle[loop].xg+=0.01f;

if (keys[VK_NUMPAD4] && (particle[loop].xg>-1.5f)) particle[loop].xg-=0.01f;

}

}

return TRUE;

}

GLvoid KillGLWindow(GLvoid)

{

if (fullscreen)

{

ChangeDisplaySettings(NULL,0);

ShowCursor(TRUE);// Відображення курсора

}

if (hRC)

{

if (!wglMakeCurrent(NULL,NULL)){

MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);

}

if (!wglDeleteContext(hRC))

{

MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);

}

hRC=NULL;

}

if (hDC && !ReleaseDC(hWnd,hDC))

{

MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);

hDC=NULL;

}

if (hWnd && !DestroyWindow(hWnd))// Ми млжемо знищити вікно?

{

MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);

hWnd=NULL;// Set hWnd To NULL

}

if (!UnregisterClass("OpenGL",hInstance))// Ми можемо не зареєструвати клас

{

MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);

hInstance=NULL;// Set hInstance To NULL

}

}

/*Наступний код створює вікно OpenGL:

*title- заголовок вікна

* width- довжина вікна

*height- висота вікна

*bits- кількість бітів для відображення кольору (8/16/24/32)

*fullscreenflag- використання повноекранного режиму*/

BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)

{

GLuintPixelFormat;// Уртимання результату після пошуку відповідності

WNDCLASSwc;// Клас структури вікна

DWORDdwExStyle;// Розширений Стиль вікна

DWORDdwStyle;// Стиль вікна

RECTWindowRect;

WindowRect.left=(long)0;

WindowRect.right=(long)width;

WindowRect.top=(long)0;

WindowRect.bottom=(long)height;

fullscreen=fullscreenflag;// Повноекранний режим

hInstance= GetModuleHandle(NULL);

wc.style= CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Перемалювання вікна

wc.lpfnWndProc= (WNDPROC) WndProc;

wc.cbClsExtra= 0;// Жодних додаткових вікон

wc.cbWndExtra= 0;// Жодних додаткових вікон

wc.hInstance= hInstance;// Встановтти зразок

wc.hIcon= LoadIcon(NULL, IDI_WINLOGO); // Завантаження стандартного значка

wc.hCursor= LoadCursor(NULL, IDC_ARROW); // Завантаження координит курсора

wc.hbrBackground= NULL;wc.lpszMenuName= NULL;wc.lpszClassName= "OpenGL";// Вказання ім’я класу

if (!RegisterClass(&wc))// Зареєструвати клас вікна

{

MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);

return FALSE;}

if (fullscreen)

{

DEVMODE dmScreenSettings;// Режим пристрою

memset(&dmScreenSettings,0,sizeof(dmScreenSettings));// Перевірка очищення пам’яті

dmScreenSettings.dmSize=sizeof(dmScreenSettings);

dmScreenSettings.dmPelsWidth= width;// Довжина вікна

dmScreenSettings.dmPelsHeight= height;// Висота вікна

dmScreenSettings.dmBitsPerPel= bits;// Кількість бітів

dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)

{

// При збої

if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By&bsol;nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)

{

fullscreen=FALSE;// Присвоїти повноекранному режиму значення = FALSE

}

else

{

// Виштовхнути дані зі стека.

MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);

return FALSE;

}