www.pudn.com > 3dterrain.zip > init.cpp
//////////////////////////////////////////////////////////////////////
// init.cpp - obsahuje funkcie pre vytvorenie okna, ktore bude pracovat
// s OpenGL
// Vazba na ostatne je iba cez init.h a instanciu triedy scene
//////////////////////////////////////////////////////////////////////
#include "scene.h"
HDC hDC=NULL; // privátny GDI Device Context
HGLRC hRC=NULL; // Rendering Context
HWND hWnd=NULL; // Handle na okno
HINSTANCE hInstance; // Inštalacia programu
char MenoApplikacie[]="Teren";
bool keys[256]; // pole - práca s klavesnicou
bool fullscreen=1; // indikátor pre fullscreen
bool active=1; // indikator aktivy (negacia priznaku minimalizacie)
int error=0; // ak je 1 nastala chyba a program sa ma ukoncit
int screen_x=800; // horizontalne rozlisenie
int screen_y=600; // vertikalne rozlisenie
int screen_bit=16; // pocet bitov na 1 pixel
int english=1;
scene *scene_=NULL;
bool edge_clamp_supported=0;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // deklarácia WndProc
void KillGLWindow(void); // deklaracia KillGLWindow
int Nastav_rozlisenia();
//////////////////////////////////////////////////////////////////////
/* Parametry pri tvorbe OpenGL okna *
* title - titulek okna *
* width - sirka okna *
* height - vyska okna *
* bits - pocet bitu na pixel */
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreen_)
{
GLuint PixelFormat;
WNDCLASSEX wc; // miesto pre strukturu pouzitu na registraciu triedy okna
DWORD dwExStyle;
DWORD dwStyle;
RECT WindowRect; // miesto pre velkost okna
WindowRect.left=(long)0;
WindowRect.right=(long)width;
WindowRect.top=(long)0;
WindowRect.bottom=(long)height;
fullscreen=fullscreen_;
wc.cbSize = sizeof(WNDCLASSEX); //velkost struktury WINDOWCLASSEX
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; /*nastavenie stylu okna
CS_HREDRAW - prekreslenie okna pri zmene horizontalne velkosti okna
CS_VREDRAW - -----------""-------------- vertikalnej ------""-----
CS_OWNDC - vyhradi jedinecny kontext zariadenia pre kazde okno */
wc.lpfnWndProc = (WNDPROC) WndProc; //smernika na funkciu na spracovanie sprav
wc.cbClsExtra = 0; //specifikuje pocet extra bytov na konci struktury triedy okien na ukladanie informacii
wc.cbWndExtra = 0; //-------""--------------------, ktore sa maju vyhradit po vyskyte okna
wc.hInstance = hInstance; //handle (ukazovatel) na instalaciu (paremeter z WinMain)
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINLOGO)); //handle ikony ktora sa ma pouzit pre danu truedu okien
wc.hCursor = NULL; // LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR_MAIN)); //handle kurzora ktory ----------------""----------------
wc.hbrBackground = NULL; //handle stetca pouziteho na vyfarbenie pozadia okna
wc.lpszMenuName = NULL; //ukazovatel na sz(StringZero) v ktorom je nazov pre menu (!)triedy
wc.lpszClassName = "OpenGL"; //ukaz na sz, ktory obsahuje nazov triedy. Tento nazov sa pouzie v parametry lpClassName vo funkcii CreateWindowEx
wc.hIconSm = NULL; //LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TITLE)); //handle k ikone, ktora sa ma pouzit v titulkovom pruhu okien, vytvorenych touto triedou. Ak je NULL pouzije sa hIcon
if(!RegisterClassEx(&wc)) //registracia novej tiredy okna, pouzivanych na vytavaranie okien
{ MessageBox(NULL,"Chyba pri registracii triedy okna.","ERROR",MB_OK|MB_ICONEXCLAMATION);return 0;}
if(fullscreen) //ZMENA DO FULLSCREEN
{
DEVMODE dmScreenSettings; //struktura popisujuca graficky mod
memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); //vynuluje dmScreenSettings
dmScreenSettings.dmSize=sizeof(dmScreenSettings); //nastavy velkost
dmScreenSettings.dmPelsWidth = width; //vertikalne roazlisenie
dmScreenSettings.dmPelsHeight = height; //horizontalne rozlisenie
dmScreenSettings.dmBitsPerPel = bits; //pocet bitov na pixel
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; //specifikuje ktore polozky v strukture su menene ??
/**** zmena modu !!! ****/
{ int mod;
mod=ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN);
if(mod!=DISP_CHANGE_SUCCESSFUL)
{
switch(mod)
{
case(DISP_CHANGE_RESTART):MessageBox(NULL,"The computer must be restarted in order for the graphics mode to work.","Chyba pri inicializacii grafickeho rezimu",MB_ICONERROR);break;
case(DISP_CHANGE_BADFLAGS):MessageBox(NULL,"An invalid set of flags was passed in.","Chyba pri inicializacii grafickeho rezimu",MB_ICONERROR);break;
case(DISP_CHANGE_FAILED):MessageBox(NULL,"The display driver failed the specified graphics mode.","Chyba pri inicializacii grafickeho rezimu",MB_ICONERROR);break;
case(DISP_CHANGE_BADMODE):MessageBox(NULL,"The graphics mode is not supported.","Chyba pri inicializacii grafickeho rezimu",MB_ICONERROR);break;
}
if(MessageBox(NULL,"Chyba pri inicializacii grafickeho rezimu. Chcete pokracovat v okne?","Chyba",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{ fullscreen=0;} //pokracovanie v okne
else
{ MessageBox(NULL,"Program se uzavrie.","ERROR",MB_OK|MB_ICONSTOP);return FALSE;}
}
}
}
ShowCursor(0);
if (fullscreen)
{
dwExStyle=WS_EX_APPWINDOW; //Forces a top-level window onto the taskbar when the window is minimized.
dwStyle=WS_POPUP; //vytvara prekryte okno
// ShowCursor(0); //skryje kurzor
}
else
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; //okno ktore ma ohranicenie s vyvysenou hranou (WS_EX_WINDOWEDGE)
dwStyle=WS_OVERLAPPEDWINDOW; //vytvara okno s titulkovym pruhom, ohranicenim, okno je ohraniceny tenkou ciarov
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); //vypocitava velkost okna
/*vytvara okno, generuje: WM_GETMINMAXINFO,WM_NCCREATE,WM_NCCALCSIZE,WM_CREATA,WM_SHOWWINDOW */
hWnd = CreateWindowEx( dwExStyle, //rozsireny styl okna
"OpenGL", //ukazovatel na sz obsahujuci platny nazov triedy pre okno (registrovanej triedy)
title, //ukazovatel na sz obsahujuci meno okna (zobrazuje sa titulkovom pruhu)
dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, //...
0, 0, //pozicia okna na obrazovke (x,y)
WindowRect.right-WindowRect.left, //sirka okna
WindowRect.bottom-WindowRect.top, //vyska okna
NULL, //handle k rodicovskemu oknu
NULL, //handle k menu okna. Ak sa ma pouzit trieda menu pouzite hodnotu NULL
hInstance, //handle vyskytu aplikacie, ktora vytvara okno
NULL); //ukazovatel na data ktora budu odovzdane oko lParam spravy WM_CREATE
if (!hWnd) //ak sa okno nepodarilo vytvorit koniec
{
KillGLWindow();MessageBox(NULL,"Chyba pri tvorbe okna.","ERROR",MB_OK|MB_ICONEXCLAMATION);return FALSE;
}
/*Abychom mohli pracovat s OpenGL musíme premostit vykreslování na rozhraní OpenGL tím,
ze nastavíme tzv. PixelFormatDescriptor, který slouzí jako komunikátor mezi výstupními
rutinami windowsu a výstupními rutinami knihovny OpenGL. Poukazuje na to, jaké rozdíly
jsou v zobrazování barev atd. Toto nastavení najdete ve funkci bSetupPixelFormat.
Pokud vás zajímají jednotlivé polozky ve strukture PIXELFORMATDESCRIPTOR, najdete to v helpu.*/
static PIXELFORMATDESCRIPTOR pfd=
{
sizeof(PIXELFORMATDESCRIPTOR), //velkost PIXELFORMATDESCRIPTOR
1, //verzia tato hodnota ma byt nastavena na 1
PFD_DRAW_TO_WINDOW | //support window -(The buffer can draw to a window or device surface.)
PFD_SUPPORT_OPENGL | //support OpenGL -(The buffer supports OpenGL drawing.)
PFD_DOUBLEBUFFER, //double buffered -(The buffer is double-buffered. This flag and PFD_SUPPORT_GDI are mutually exclusive in the current generic implementation
PFD_TYPE_RGBA, //RGBA type -(RGBA pixels. Each pixel has four components in this order: red, green, blue, and alpha.)
(BYTE)bits, // -bit color depth -(For RGBA pixel types, it is the size of the color buffer, excluding the alpha bitplanes.)
0, 0, 0, 0, 0, 0, //color bits ignored -(cRedBits,cRedShift,cGreenBits,cGreenShift,cBlueBits,cBlueShift)
0, 0, //no alpha buffer, shift bit ignored , -(cAlphaBits,cAlphaShift)
0, //no accumulation buffer -(cAccumBits)
0, 0, 0, 0, //accum bits ignored -(cAccumRedBits,cAccumGreenBits,cAccumBlueBits,cAccumAlphaBits)
16, //16-bit z-buffer, -(cDepthBits - Specifies the depth of the depth (z-axis) buffer.)
0, //no stencil buffer -(cStencilBits - Specifies the depth of the stencil buffer.)
0, //no auxiliary buffer -(cAuxBuffers)
PFD_MAIN_PLANE, //main layer -(iLayerType - Ignored. Earlier implementations of OpenGL used this member, but it is no longer used.)
0, //reserved -(bReserved)
0, 0, 0 //layer masks ignored -(dwLayerMask,dwVisibleMask,dwDamageMask)
};
hDC=GetDC(hWnd); //ziskanie handla obrazoveho kontextu zariadenia (DC) klienskej casti okna (s handlom hWnd)
if (!hDC)
{
KillGLWindow();
MessageBox(NULL,"Nejde vytvorit GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
/*The ChoosePixelFormat function attempts to match an appropriate pixel format supported by a device context to a given pixel format specification.*/
PixelFormat=ChoosePixelFormat(hDC,&pfd); //device context to search for a best pixel format match, pixel format for which a best match is sought
if (!PixelFormat)
{
KillGLWindow();
MessageBox(NULL,"Nejde nájst PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
/*The SetPixelFormat function sets the pixel format of the specified device context to the format specified by the iPixelFormat index.*/
if(!SetPixelFormat(hDC,PixelFormat,&pfd))
{
KillGLWindow();
MessageBox(NULL,"Nejde nastavit PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
/*The wglCreateContext function creates a new OpenGL rendering context,
which is suitable for drawing on the device referenced by hdc.
The rendering context has the same pixel format as the device context.*/
hRC=wglCreateContext(hDC); // create a rendering context
if (!hRC) //return value is a valid handle to an OpenGL rendering context.
{
KillGLWindow();
MessageBox(NULL,"Nejde vytvorit GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
/*The wglMakeCurrent function makes a specified OpenGL rendering context the calling
thread's current rendering context. All subsequent OpenGL calls made by the thread are
drawn on the device identified by hdc. You can also use wglMakeCurrent to change the
calling thread's current rendering context so it's no longer current. */
if(!wglMakeCurrent(hDC,hRC)) // make it the calling thread's current rendering context
{
KillGLWindow();
MessageBox(NULL,"Nejde aktivovat GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
ShowWindow(hWnd,SW_SHOW); //zvyditelnie okna, posiela spravu WM_SHOWWINDOW
SetForegroundWindow(hWnd); //nastavuje okno na to s ktorym pracuje uzivatel
SetFocus(hWnd); //nastavy vstup klavesnice na toto okno
// inicializacia sceny
scene_ = new scene; // vytvarame scenu
if(scene_==NULL || error) // ak sa nevytvorila, alebo pri vytvarani vznikla chyba
{
if(scene_!=NULL)delete scene_; // ak sa vytvorila, uvolnime
KillGLWindow(); // vypneme OpenGL
MessageBox(NULL,"Chyba pri vytvarani sceny.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return 0; // koniec, aplikacia sa ukonci
}
return 1;
}
//////////////////////////////////////////////////////////////////////
void KillGLWindow(void) // rušíme okno
{
ShowCursor(1);
if (fullscreen) // Fullscreen (ano/nie)
{
ChangeDisplaySettings(NULL,0); // zmena grafickeho rezimu na prednastavene rozlisenie
}
if (hRC)
{
if(!wglMakeCurrent(NULL,NULL)) // make the rendering context not current
{ MessageBox(NULL,"DC a RC chyba.","ERROR",MB_OK | MB_ICONINFORMATION);}
if(!wglDeleteContext(hRC)) // delete the rendering context
{ MessageBox(NULL,"Chyba: Delete Rendering Context.","ERROR",MB_OK | MB_ICONINFORMATION);}
hRC=NULL;
}
if (hDC && !ReleaseDC(hWnd,hDC)) // uvolnuje kontext zariadenia
{
MessageBox(NULL,"Chyba: Uvolnenia Device Context.","ERROR",MB_OK | MB_ICONINFORMATION);
hDC=NULL;
}
if (hWnd && !DestroyWindow(hWnd)) // ukoncuje aplikaciu, posiela spravu WM_DESTROY
{
MessageBox(NULL,"Chyba: hWnd.","ERROR",MB_OK | MB_ICONINFORMATION);
hWnd=NULL;
}
if (!UnregisterClass("OpenGL",hInstance)) //removes a window class, freeing the memory required for the class.
{
MessageBox(NULL,"Nejde odregistrovat okno.","ERROR",MB_OK | MB_ICONINFORMATION);
hInstance=NULL;
}
}
/*********************************************************************************************/
/*Funkcia na spracovanie sprav. Spravy su posielane do funkcie pomocou DispatchMessage(&msg);*/
LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch (uMsg)
{
case WM_ACTIVATE: //generovane ak je okno aktivizovane, alebo deaktivizovane
{
if (!HIWORD(wParam)) //HIWORD(wParam) -priznak minimalizovaneho okna
{active=TRUE;} //okno nie je minimalizovane
else active=FALSE; //okno je minimalizovane
return 0;
}
case WM_SYSCOMMAND:{ switch (wParam){ case SC_SCREENSAVE: case SC_MONITORPOWER: return 0;}break;}
case WM_CLOSE:{PostQuitMessage(0);return 0;} //generuje WM_QUIT a wParam=0
case WM_KEYDOWN:{keys[wParam] = 1;return 0;} //stlacenie klavesy
case WM_KEYUP: {keys[wParam] = 0;return 0;} //pustenie klavesy
case WM_LBUTTONDOWN:{keys[VK_LBUTTON] = TRUE;return 0;}
case WM_LBUTTONUP:{keys[VK_LBUTTON] = FALSE;return 0;}
case WM_RBUTTONDOWN:{keys[VK_RBUTTON] = TRUE;return 0;}
case WM_RBUTTONUP:{keys[VK_RBUTTON] = FALSE;return 0;}
case WM_SIZE: {if(scene_!=NULL)scene_->ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));return 0;} //zmena velkosti, funkcia je definovana v tomto subore
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
//////////////////////////////////////////////////////////////////////
/**********VSTUPNA FUNCKIA*****************************************************/
int WINAPI WinMain(HINSTANCE hInstance_,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
MSG msg; //mesto pre strukturu MESSAGE - pre spravy
BOOL koniec=0;
hInstance=hInstance_;
if( Nastav_rozlisenia())
if( ( english ?
MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION) :
MessageBox(NULL,"Cela obrazovka?", "Nastavenie obrazovky (pocas behu pomocou F1)",MB_YESNO|MB_ICONQUESTION)
) ==IDNO )
{ fullscreen=FALSE;}
// vytvarame okno a incializujeme scenu
if (!CreateGLWindow(MenoApplikacie,screen_x,screen_y,screen_bit, fullscreen))return 0;
while(!koniec) //pokial nie je koniec
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) /*ak nie je pristupna sprave vrati 0
ak je prisupna sparava vrati nenulu a zapise ju do struktury msg,
NULL - HWND spracuva spravy z aktualneho vlakna, PM_REMOVE - presuva spravu z radu sprav
na rozdiel od GetMessage, PeekMessage necaka na pijatie dalsiej sprave pred vratenim (hodnoty)*/
{ //sprava je pristupna - treba ju spracovat
if (msg.message==WM_QUIT)koniec=1;
else
{
TranslateMessage(&msg); //preklada virtualne spravy (VK_*) na znakove spravy (WM_CHAR)
DispatchMessage(&msg); //posiela spravy aplikacie prislusnej funkcie (WndProc)na spracovanie
} //- "" - vracia to co vracia WndProc
}
else //ziadna sprava - cinnost ktoru ma vykonavat mimo spracovavania sprav
{
if (active) scene_->DrawGLScene(); //ak je program aktivny vykresluj
if (keys[VK_ESCAPE]) koniec=1; //ak je stlaceny Esc ukonc
else SwapBuffers(hDC); //prehodi buffer
if (keys[VK_F1]) //cez F1 prepinanie z Fullscreen do okna
{
keys[VK_F1]=FALSE;
if(scene_!=NULL)delete scene_;
KillGLWindow();
fullscreen=!fullscreen;
if (!CreateGLWindow(MenoApplikacie,screen_x,screen_y,screen_bit,fullscreen))return 0;
}
}
}
if(scene_!=NULL)delete scene_;
KillGLWindow();
return (msg.wParam); //funkcia WinMain ma vratit hodnotu, ktora bola pouzita z funkciou PostQuitMessage
}
int GetVariable(char *temp, FILE *sub, char* varname, char* varvalue, int size_strings)
{
if(fgets(temp, size_strings, sub) == NULL)
{
temp[0] = NULL;
return 0;
}
varname[0]=NULL;
varvalue[0]=NULL;
char rovnasa=0;
for(int i=0,j=0,k=0; temp[i]!=NULL&&temp[i]!='\n'&&temp[i]!='/'; i++) // prejdeme vsetky znaky
{
if(temp[i]==' ' || temp[i]=='\t')continue;
if(temp[i]=='='){ rovnasa=1;continue;}
if(rovnasa)
{
varvalue[k]=temp[i]; k++;
}
else
{
varname[j]=temp[i]; j++;
}
}
varname[j]=NULL;
varvalue[k]=NULL;
return 1;
}
int Nastav_rozlisenia()
{
FILE* sub=NULL;
char temp[100];
char varname[100],varvalue[100];
int ret=0;
sub = fopen( "data/init.txt", "rb");
if(sub == NULL)return 1;
while(GetVariable( temp, sub, varname, varvalue, 100))
{
float fl=(float)atof(varvalue);
int in=atoi(varvalue);
strlwr(varname); // Convert a string to lowercase
if(!strcmp("width",varname))screen_x=in;
else if(!strcmp("height",varname))screen_y=in;
else if(!strcmp("colorbit",varname))screen_bit=in;
else if(!strcmp("fullscreen",varname))
{
switch(varvalue[0])
{
case 'A': case 'a': case 'Y': case 'y': fullscreen = 1; break;
case 'N': case 'n': fullscreen = 0; break;
case 'M': case 'm': ret=1; break;
}
}
else if(!strcmp("language",varname))
{
if(in==0)english=1;
else if(in==1)english=0;
}
}
fclose(sub);
if(screen_x==0)screen_x=800;
if(screen_y==0)screen_y=600;
if(screen_bit==0)screen_bit=16;
return ret;
}