Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Code::Blocks ja OpenGL

black cat [01.08.2011 16:57:41]

#

Miten OpenGllän saisi toimimaan kunnolla Code::Blocksissa. Latasin paketin jossa oli tarvittavat tiedostot(luultavasti) ja laitoin ne mielestäni oikeisiin paikkoihin(lib-kansion tiedostot kääntäjän lib-kansioon ja include-kansion tiedostot kääntäjän include-kansioon ja dll-tiedostot projektin kansioon). Sitten menin Markus Ilmolan OpenGL-sivuille, mutta yksikään esimerkeistä ei toiminut. Esimerkiksi seuraava koodi aiheuttaa virheet:

#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <math.h>
//#include <gl\glext.h> // Ei tarvita tässä ohjelmassa
// Määrittele laitekonteksti globaaliksi sitä nimittäin tarvitaan myös pääfunktiossa.
HDC hdcs;
// Valon sijainti
float lightPos[4]={ 0, 5, 0, 1 };
// Viestinkäsittelijä
LRESULT CALLBACK WindowProc(HWND hwnds, UINT uMsg, WPARAM wParams, LPARAM lParams){
    switch (uMsg)
    {
        // Koska piirrämme ikkunan sisällön pääsilmukassa jatkuvasti uudelleen
        // reakoimme WM_PAINT-viestiin vain tyhjentämällä ikkunan mustaksi.
        case WM_PAINT:
        {
            PAINTSTRUCT p;
            BeginPaint(hwnds, &p);
            glClear(GL_COLOR_BUFFER_BIT);
            SwapBuffers(hdcs);
            EndPaint(hwnds, &p);
            return 0;
        }
        // Ikkuna yritetään sulkea kutsu PostQuitMessage()-funktiota.
        case WM_CLOSE:
        {
            PostQuitMessage(0);
            return 0;
        }
        // Käsittele myös WM_SIZE se lähetetään ikkunalle aina kun sen kokoa muutetaan.
        // Tämä on oiva tilaisuus muuttaa viewport
        // oikean kokoiseksi peittämään koko ikkuna.
        case WM_SIZE:
        {
            // Ikkunan uusi koko saadaan lParam parametrista LOWORD ja HIWORD makroilla.
            glViewport(0, 0, LOWORD(lParams), HIWORD(lParams));
            return 0;
        }
    }
    // Viestiä ei käsitelty kutsu DefWindowProc()-funktiota.
    return DefWindowProc(hwnds, uMsg, wParams, lParams);
}

int luoIkkuna(unsigned int leveys, unsigned int korkeus, char *otsikko){
    // Rekisteröi ikkunaluokka
    WNDCLASS wc;
    memset(&wc, 0, sizeof(WNDCLASS));
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.hCursor= LoadCursor(NULL, IDC_ARROW);
    wc.lpfnWndProc = (WNDPROC) WindowProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = "OpenGLtutoriaali";
    if (!RegisterClass(&wc)) return 0;
    // Luo ikkuna
    RECT r;
    r.left=GetSystemMetrics(SM_CXSCREEN)/2-leveys/2;
    r.top=GetSystemMetrics(SM_CYSCREEN)/2-korkeus/2;
    r.right=r.left+leveys;
    r.bottom=r.top+korkeus;
    AdjustWindowRectEx(&r, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW);
    HWND hwnds;
    hwnds=CreateWindowEx(WS_EX_APPWINDOW, "OpenGLtutoriaali", otsikko, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, r.left, r.top, r.right-r.left, r.bottom-r.top, NULL, NULL, GetModuleHandle(NULL), NULL);
    // Luo laitekonteksti
    hdcs=GetDC(hwnds);
    if (!hdcs) return 0;
    // Valitse pikseliformaatti
    PIXELFORMATDESCRIPTOR pfds;
    memset(&pfds, 0, sizeof(PIXELFORMATDESCRIPTOR));
    pfds.nSize=sizeof(PIXELFORMATDESCRIPTOR);
    pfds.nVersion=1;
    pfds.dwFlags=PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
    pfds.iPixelType=PFD_TYPE_RGBA;
    pfds.cRedBits=16;
    pfds.cGreenBits=16;
    pfds.cBlueBits=16;
    pfds.cAlphaBits=16;
    pfds.cStencilBits=16;
    pfds.cDepthBits=32;
    pfds.iLayerType=PFD_MAIN_PLANE;
    int pixelFormat;
    pixelFormat = ChoosePixelFormat(hdcs, &pfds);
    if (!pixelFormat) return 0;
    if (!SetPixelFormat(hdcs, pixelFormat, &pfds)) return 0;
    // Luo renderöintikonteksti
    HGLRC hrc;
    hrc=wglCreateContext(hdcs);
    if (!hrc) return 0;
    if (!wglMakeCurrent(hdcs, hrc)) return 0;
    // Tuo ikkuna näkyviin
    ShowWindow(hwnds, SW_SHOW);
    SetForegroundWindow(hwnds);
    SetFocus(hwnds);
    // Palauta onnistuminen
    return 1;
}
// Laskee kahden vektorin pistetulon
float pistetulo(float v1[3], float v2[3]){
    return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2];
}
// Taso piirretään käyttäen useita pieniä nelikulmioita
// paremman valaistuksen saavuttamiseksi
void piirraTaso(void){
    int x, z;
    glBegin(GL_QUADS);
    glNormal3f(0,1,0);
    for (z=0; z<22; z+=2){
        for (x=0; x<22; x+=2){
            glVertex3f(-10+x, 0, -10+z);
            glVertex3f(-10+x, 0, -10+z+2);
            glVertex3f(-10+x+2, 0, -10+z+2);
            glVertex3f(-10+x+2, 0, -10+z);
        }
    }
    glEnd();
}
// Piirtää kuution tai sen katvetilan, jos katvetila-parametri on TRUE
void piirraKuutio(BOOL katvetila){
    // Data piirrettävää kuutiota varten
    static float vertex[8][3]={{-1,0,-1},{1,0,-1},{-1,2,-1},{1,2,-1},{-1,0,1}, {1,0, 1},{-1,2, 1},{1,2, 1}};
    static int index[6][4]={ {0,2,3,1}, {4,5,7,6}, {5,1,3,7},{4,6,2,0}, {7,3,2,6}, {4,0,1,5} };
    // Tahojen normaalit
    static float normal[6][3]={{0,0,-1},{0,0,1},{1,0,0},{-1,0,0},{0,1,0},{0,-1,0}};
    // Katvetilan muodostusta varten jokaisen tahon on tiedettävä naapurinsa.
    static int naapuri[6][4]={{3,4,2,5},{5,2,4,3},{5,0,4,1},{1,4,0,5},{2,0,3,1},{3,0,2,1}};
    // Jokaiselle verteksille valoa kohti osoittava vektori.
    static float L[8][3];
    if (!katvetila){
        // Piirrä kuutio
        glBegin(GL_QUADS);
        int i, j;
        for (i=0; i<6; i++){
            glNormal3f(normal[i][0], normal[i][1], normal[i][2]);
            for (j=0; j<4; j++){
                glVertex3f(vertex[ index[i][j] ][0], vertex[ index[i][j] ][1], vertex[ index[i][j] ][2]);
            }
        }
        glEnd();
    }
    else{
        int i,j;
        // Laske valoa kohti osoittavat vektorit.
        for (i=0; i<8; i++){
            L[i][0]=lightPos[0]-vertex[i][0];
            L[i][1]=lightPos[1]-vertex[i][1];
            L[i][2]=lightPos[2]-vertex[i][2];
        }
        // Piirrä katvetila.
        // Tässä tulee sairaan paljon indeksointia, joka olisi voitu välttää
        // jonkinlaisen verteksi-structuren ja osoittimien käytöllä.
        glBegin(GL_QUADS);
        // Jokaiselle taholle
        for (i=0; i<6; i++){
            // Jos tämä taho osoittaa kohti valoa
            if (pistetulo( normal[i], L[ index[i][0] ] )>=0){
                // Jokaiselle vierustaholle
                for (j=0; j<4; j++){
                    // Jos tämä vierustaho EI osoita kohti valoa
                    if (pistetulo(normal[ naapuri[i][j] ], L[ index[ naapuri[i][j] ][0] ])<0){
                        // Tahojen välinen särmä kuuluu silhuettiin
                        // venytä se nelikulmioksi poispäin valosta.
                        glVertex3f(vertex[ index[i][j] ][0], vertex[ index[i][j] ][1], vertex[ index[i][j] ][2]);
                        glVertex3f(vertex[ index[i][(j+1)%4] ][0], vertex[ index[i][(j+1)%4] ][1], vertex[ index[i][(j+1)%4] ][2]);
                        glVertex3f(vertex[ index[i][(j+1)%4] ][0]-100*L[ index[i][(j+1)%4] ][0], vertex[ index[i][(j+1)%4] ][1]-100*L[ index[i][(j+1)%4] ][1], vertex[ index[i][(j+1)%4] ][2]-100*L[ index[i][(j+1)%4] ][2]);
                        glVertex3f(vertex[ index[i][j] ][0]-100*L[ index[i][j] ][0], vertex[ index[i][j] ][1]-100*L[ index[i][j] ][1], vertex[ index[i][j] ][2]-100*L[ index[i][j] ][2]);
                    }
                }
            }
        }
        glEnd();
    }
}
// Pääfunktio
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
    float angle=0;
    // Luo ikkuna
    if (!luoIkkuna(800, 600, "OpenGL:n perusteet - Osa 4: Valot ja varjot")) return 0;
    // Määrittele viewport koko ikkunan kokoiseksi
    glViewport(0, 0, 800, 600);
    // Koska koordinaatisto on itseasiassa matriisi täytyy meidän ottaa
    // projektiomatriisi käsiteltäväksi ennen gluPerspective-kutsua.
    glMatrixMode(GL_PROJECTION);
    gluPerspective(60, 800.0/600.0, 1, 100);
    // Kaikki matriisia muuttavat käskyt vaikuttavat tämän jälkeen modelview-matriisiin
    glMatrixMode(GL_MODELVIEW);
    // Laita näkymättömien pintojen poisto ja sysyyspuskurialgoritmi päälle.
    glEnable(GL_CULL_FACE);
    // Valitse syvyystestausfunktio "<=" oletuksena olevan "<" tilalle.
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);
    // Aseta valo nro. 0 päälle
    float Cl[4]={0.8,0.8,0.8,1};
    float A[4]={0.2,0.2,0.2,1};
    float Cd[4]={1,1,1,1};
    glLightfv(GL_LIGHT0, GL_DIFFUSE, Cl); // Väri
    glLightfv(GL_LIGHT0, GL_AMBIENT, A); // Ympätisrövalon määrä
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Cd); // Pinnan väri
    glEnable(GL_LIGHT0);
    // OpenGL lisää valaistukseen vielä yhden valonlähteistä
    // riippumattoman ympäristövalon, josta haluamme päästä eroon.
    float nolla[4]={0,0,0,1};
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, nolla);
    // Viestinkäsittelysilmukka
    MSG msg;
    while(1){
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
            if (msg.message==WM_QUIT) break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else{
            // Tyhjennä väripuskuri, syvyyspuskuri ja sapluunapuskuri
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
            // Aseta modelview-matriisi
            glLoadIdentity(); // "Resetoi" matriisi yksikkömatriisiksi
            glTranslatef(0, -3, -10); // Siirrä hieman kauemmaksi kamerasta
            glRotatef(angle, 0, 1, 0); // Pyöritä hieman Y-akselin ympäri
            // Kasvata pyörityskulmaa hieman
            angle+=0.05;
            // Siirrä valoa
            lightPos[0]=5*sin(angle*-0.2);
            lightPos[1]=5+sin(angle*0.5);
            lightPos[2]=5*cos(angle*-0.2);
            glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
            // Ensimmäinen vaihe.
            // täytetään syvyyspuskuri ja piirretään kuva käyttäen pelkkää ympäristövaloa
            glDisable(GL_LIGHTING);
            glDisable(GL_STENCIL_TEST);
            glColor3f(A[0], A[1], A[2]);
            piirraTaso();
            piirraKuutio(FALSE);
            // Toinen vaihe
            // Piirrä katvetila sapluunapuskuriin
            // Jos haluat päästä eroon varjoista kommentoi tämä toinen vaihe pois
            glDisable(GL_CULL_FACE); // Katvetilasta pitää piirtää kaikki osat
            glEnable(GL_STENCIL_TEST); // Sapluunapuskuri päälle
            glColorMask(0, 0, 0, 0); // Emme halua päivittää väripuskuria
            glDepthMask(0); // Emmekä syvyyspuskuria
            glStencilFunc(GL_ALWAYS, 0, 0);
            glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Käännä bitit piirtäessä
            piirraKuutio(TRUE);
            glEnable(GL_CULL_FACE);
            glColorMask(1, 1, 1, 1);
            glDepthMask(1);
            // Viimeinen vaihe
            // Piirrä lopullinen kuva kohtiin, jossa sapluunapuskurin arvo on 0
            glEnable(GL_LIGHTING);
            glStencilFunc(GL_EQUAL, 0, ~0);
            glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
            piirraTaso();
            piirraKuutio(FALSE);
            // Piirrä vielä valonlähde
            glDisable(GL_LIGHTING);
            glDisable(GL_STENCIL_TEST);
            glPointSize(5);
            glBegin(GL_POINTS);
            glColor3f(1,1,0);
            glVertex3f(lightPos[0], lightPos[1], lightPos[2]);
            glEnd();
            // Vaihda puskuri näytölle.
            SwapBuffers(hdcs);
        }
    }
    return 0;
}

Tiedättekö mikä on ongelma?
Thanks

nomic [01.08.2011 17:00:04]

#

Onko tarvittavat kirjastot linkattu mukaan ohjelmaan?

black cat [01.08.2011 17:03:20]

#

on.

Metabolix [01.08.2011 20:11:16]

#

Ei ole, näkeehän sen noista virheistäkin. Tarvitset gdi32-kirjaston.

Vielä fiksumpaa olisi heivata nuo Windows-riippuvaiset asiat kokonaan pois ja käyttää OpenGL:ää yhdessä vaikka SDL:n kanssa. Siitä on opaskin. Säästyy paljon vaivaa, ja oikein tehdyn ohjelman voi kääntää Linuxille ja Macille ilman muutoksia.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta