Mam problem z programem w C z użyciem opengl. Nie chciałbym podawać kodu bez ostatecznej konieczności z lenistwa. Chodzi o to że jest to prosty sześcian. i chciwym żeby się poruszał ale robi to tylko po naciśnięciu jakiegoś guzika. Co należny zrobić? Cos ja timer? Ma ktoś jakaś rade? program jest w C.
Wrzuć logikę w główną pętlę.
Trochę zależy od tego jak GL inicjalizujesz (używasz GLUT np.?).
Ogólny pomysł jest taki że (pseudokod):
void on_key_down() {
moving = true; // reakcja na naciśnięcie klawisza, cube zaczyna sie ruszać
}
void on_key_up() {
moving = false; // reakcja na podniesienie klawisza, cube przestaje sie ruszać
}
void main_loop() { // pętla główna, gdzieś ją pewnie już masz w programie, chyba że np. używasz GLUT który robi to za Ciebie
while (true) {
if (moving) {
cube_position += step; // ściśle to bardziej velocity / deltatime
}
draw_cube(); // i rysuje na pozycji cube_position
}
}
Właściwie to trochę źle to napisałem. Do funkcji Wyrysowującej wprowadzam zwiększanie wartości zmiennej globalnej rotacyjnej. Sześcian sie nie porusza, robi to tylko kiedy trzyma się okienko i porusza szczególnie poza krawędziami obrazu monitora. Nie wiem jak temu zaradzić z biblioteka opengl. Nie używam glut , tam chyba jest specjalna funkcja obsługująca funkcje wyświetlającą. Wprowadzane jest odczytywanie klawiszy jak up i jakby czekało albo nie przechodziło do kolejnej linijki w pewnym miejscu i odświeżało aktualny obraz.
Brzmi to trochę tak jakbyś nie wywoływał sam wyrysowowywania w pętli (kiedy porusza się oknem za krawędziami ekranu okno dostaje WM_PAINT). Skoro zmieniasz pozycje co każde wyrysowanie, a pozycja zmienia się tylko kiedy ruszasz oknem, to znaczy że rysowanie nie jest wykonywane bez przerwy.
PS. Jeśli nie to, daj odpowiedzialny fragment kodu, bo tak to można zgadywać.
Musiałbyś pokazać trochę kodu.
Pod Windows komunikat WM_PAINT ma jakby dwa tryby:
- jeśli (pośrednio lub bezpośrednio) wywołujesz ValidateRect(), to Windows będzie odrysowywał okno tylko kiedy mu się zachce.
- jeśli nie ma ValidateRect (ani BeginPaint/EndPaint) to okno będzie odrysowywane w kółko bez przerwy, zabierając 100% czasu procka ;-)
tobie pewnie chodzi o ten drugi wariant. można też robić InvalidateRect w jakimś timerze, by ograniczyć ilość klatek na sekundę.
#include "szescian.h"
LONG WINAPI WndProc( HWND, UINT, WPARAM, LPARAM );
HGLRC SetUpOpenGL( HWND hWnd );
// Wartosci poczatkowe
#define DEFAULT_Z_DIST 25
#define DEFAULT_PIVOT_VERT_ANGLE 0
#define DEFAULT_PIVOT_HORIZ_ANGLE 0
#define DEFAULT_PIVOT_X 0
#define DEFAULT_PIVOT_Y 0
float z_dist=DEFAULT_Z_DIST; // INSERT, PAGE UP
float pivot_vert_angle=DEFAULT_PIVOT_VERT_ANGLE; // UP, DOWN
float pivot_horiz_angle=DEFAULT_PIVOT_HORIZ_ANGLE; // LEFT, RIGHT
float pivot_x=DEFAULT_PIVOT_X; // DELETE, PAGE DOWN
float pivot_y=DEFAULT_PIVOT_Y; // HOME, END
double rot=0;
// ************ Deklaracje funkcji ************************
void DrawOpenGLScene( void ); // glowna funkcja rysujaca
// Skladowe funkcje obiektu graficznego
void szescian(void);
// ..............................
//******** Fukcje skladowe ********************************
void szescian(void)
{
rot++;
glRotatef(rot,1,0,0);
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
{
// Parametry wierzcholkow
GLfloat sa[3]={0.0f,0.0f,0.0f};
GLfloat sb[3]={1.0f,0.0f,0.0f};
GLfloat sc[3]={1.0f,1.0f,0.0f};
GLfloat sd[3]={0.0f,1.0f,0.0f};
GLfloat se[3]={0.0f,0.0f,-1.0f};
GLfloat sf[3]={1.0f,0.0f,-1.0f};
GLfloat sg[3]={1.0f,1.0f,-1.0f};
GLfloat sh[3]={0.0f,1.0f,-1.0f};
// Sciany skladowe
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_POLYGON);
glVertex3fv(sa);
glVertex3fv(sb);
glVertex3fv(sc);
glVertex3fv(sd);
glEnd();
glColor3f(0.0f, 1.0f, 0.0f);
glBegin(GL_POLYGON);
glVertex3fv(sb);
glVertex3fv(sf);
glVertex3fv(sg);
glVertex3fv(sc);
glEnd();
glColor3f(0.0f, 0.0f, 1.0f);
glBegin(GL_POLYGON);
glVertex3fv(sf);
glVertex3fv(se);
glVertex3fv(sh);
glVertex3fv(sg);
glEnd();
glColor3f(1.0f, 1.0f, 0.0f);
glBegin(GL_POLYGON);
glVertex3fv(se);
glVertex3fv(sa);
glVertex3fv(sd);
glVertex3fv(sh);
glEnd();
glColor3f(0.0f, 1.0f, 1.0f);
glBegin(GL_POLYGON);
glVertex3fv(sd);
glVertex3fv(sc);
glVertex3fv(sg);
glVertex3fv(sh);
glEnd();
glColor3f(1.0f, 0.0f, 1.0f);
glBegin(GL_POLYGON);
glVertex3fv(sa);
glVertex3fv(sb);
glVertex3fv(sf);
glVertex3fv(se);
glEnd();
}
}
//********************************************************
// Glowna funkcja WINDOWS
//********************************************************
int WINAPI WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,
int nCmdShow)
{
static char szAppName[] = "OpenGL";
static char szTitle[]= "SZESCIAN"; // Nazwa okna
WNDCLASS wc; // zmienna klasy okna
MSG msg; // zmienna komunikatu
HWND hWnd; // uchwyt okna
// wypelnianie klasy okna
wc.style =
CS_HREDRAW | CS_VREDRAW;// styl okna
wc.lpfnWndProc =
(WNDPROC)WndProc; // procedura okna
wc.cbClsExtra = 0; // dodatkowe dane
wc.cbWndExtra = 0;
wc.hInstance =
hInstance; // instancja
wc.hIcon = NULL; // nazwa ikony
wc.hCursor =
LoadCursor(NULL, IDC_ARROW);// kursor
wc.hbrBackground =
(HBRUSH)(COLOR_WINDOW+1);// domyslny kolor okna
wc.lpszMenuName = NULL;
wc.lpszClassName =
szAppName; // nazwa klasy
// Rejestracja klasy okna
RegisterClass( &wc );
// Konstrukcja glownego okna
hWnd = CreateWindow(
szAppName, // app name
szTitle, // Text for window title bar
WS_OVERLAPPEDWINDOW// Window style
// NEED THESE for OpenGL calls to work!
| WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, // no parent window
NULL, // Use the window class menu.
hInstance,// This instance owns this window
NULL // We don't use any extra data
);
// Jezeli okno nie zostanie utworzone, zwrot 0
if ( !hWnd )
{
return( 0 );
}
ShowWindow( hWnd, nCmdShow );// Wyswietlanie okna
UpdateWindow( hWnd ); // Aktualizacja okna
// Uruchiomienie petli komunikatow
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage( &msg ); // Przetwarzanie wiadomosci
DispatchMessage( &msg ); // Zwolnienie wiadomosci
}
return( msg.wParam );
}
//********************************************************
// Procedura okna
//********************************************************
LONG WINAPI WndProc(HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
HDC hDC;
static HGLRC hRC; // Note this is STATIC!
PAINTSTRUCT ps;
GLdouble gldAspect;
GLsizei glnWidth, glnHeight;
float change;
// Petla komunikatow
switch (msg)
{
case WM_CREATE:
hRC = SetUpOpenGL( hWnd ); // Inicjalizacja OpenGL
return 0;
case WM_SIZE:
hDC = GetDC (hWnd); // Kontekst urzadzenia
wglMakeCurrent (hDC, hRC);
// Usawienie rozmiarow okna graficznego
glnWidth = (GLsizei) LOWORD (lParam);
glnHeight = (GLsizei) HIWORD (lParam);
// Aspekt DC
gldAspect = (GLdouble)glnWidth/(GLdouble)glnHeight;
glMatrixMode( GL_PROJECTION );// Ustawienie macierzy projekcji
glLoadIdentity();
// Rodzaj transformacji ekranowej
gluPerspective(
30.0, // kat
gldAspect, // aspekt
1.0, // polozenie plaszczyzny blizszej
1000.0 ); // polozenie plaszczyzny dalszej
glViewport( 0, 0, glnWidth, glnHeight );
// czyszczenie
glClearColor(0.5f,0.5f,0.5f,1.0f);
glEnable(GL_COLOR_MATERIAL);
wglMakeCurrent( NULL, NULL );
ReleaseDC( hWnd, hDC );
return 0;
case WM_PAINT:
// rysowanie sceny
hDC = BeginPaint( hWnd, &ps );
wglMakeCurrent( hDC, hRC );
DrawOpenGLScene();
SwapBuffers(hDC);
wglMakeCurrent( NULL, NULL );
EndPaint( hWnd, &ps );
return 0;
case WM_DESTROY:
// zamykanie
wglDeleteContext( hRC );
PostQuitMessage( 0 );
return 0;
case WM_KEYDOWN: //************ OBSLUGA KLAWISZY ***********************
if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
change=1.0f;
else
change=0.1f;
switch ((int)wParam)
{
// obrot w pionie
case VK_UP:
pivot_vert_angle+=5;
if (pivot_vert_angle>=360)
pivot_vert_angle-=360;
InvalidateRect(hWnd, NULL, FALSE);
break;
case VK_DOWN:
pivot_vert_angle-=5;
if (pivot_vert_angle<0)
pivot_vert_angle+=360;
InvalidateRect(hWnd, NULL, FALSE);
break;
// obrot w poziomie
case VK_RIGHT:
pivot_horiz_angle+=5;
if (pivot_horiz_angle>=360)
pivot_horiz_angle-=360;
InvalidateRect(hWnd, NULL, FALSE);
break;
case VK_LEFT:
pivot_horiz_angle-=5;
if (pivot_horiz_angle<0)
pivot_horiz_angle+=360;
InvalidateRect(hWnd, NULL, FALSE);
break;
// przesuniecia w poziomie
case VK_NEXT:
if ((pivot_x+change)<400)
pivot_x+=change;
InvalidateRect(hWnd, NULL, FALSE);
break;
case VK_DELETE:
if ((pivot_x-change)>-400)
pivot_x-=change;
InvalidateRect(hWnd, NULL, FALSE);
break;
// przesuniecia w pionie
case VK_HOME:
if ((pivot_y+change)<400)
pivot_y+=change;
InvalidateRect(hWnd, NULL, FALSE);
break;
case VK_END:
if ((pivot_y-change)>-400)
pivot_y-=change;
InvalidateRect(hWnd, NULL, FALSE);
break;
// odleglosc
case VK_INSERT:
if ((z_dist+change)<600)
z_dist+=change;
InvalidateRect(hWnd, NULL, FALSE);
break;
case VK_PRIOR:
if ((z_dist-change)>1)
z_dist-=change;
InvalidateRect(hWnd, NULL, FALSE);
break;
// wyjscie z programu
case VK_ESCAPE:
PostMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
}
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
//*******************************************************
// Uruchomienie OpenGL w srodowisku Windows wymaga
// wlaczenie trybu pikselowego oraz ustawienia
// kontekstu renderowania
//*******************************************************
HGLRC SetUpOpenGL( HWND hWnd )
{
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof (PIXELFORMATDESCRIPTOR), // rozmiar struktury
1, // numer wersji
PFD_DRAW_TO_WINDOW | // flaga rysowania w oknie,
PFD_SUPPORT_OPENGL | // uzycie OpenGL
PFD_DOUBLEBUFFER, // uzycie podwojnego buforowania
PFD_TYPE_RGBA, // model kolorow - RGBA
24, // kolor 24-bitowy
0, 0, 0,
0, 0, 0, // trezerwa
0, 0, // brak bufora alpha
0, 0, 0, 0, 0, // brak bufora akumulacji
32, // bufor glebokosci 32-bitowy
0, // brak bufora szablonu
0, // brak bufora pomocniczego
PFD_MAIN_PLANE, // warstwa
0, // rezerwa - 0
0, // maska
0, // maska widoczna
0 // maska bledow
};
// zmienne
int nMyPixelFormatID;
HDC hDC;
HGLRC hRC;
hDC = GetDC( hWnd );
// Inicjalizacja trybu pikselowego
nMyPixelFormatID = ChoosePixelFormat( hDC, &pfd );
SetPixelFormat( hDC, nMyPixelFormatID, &pfd );
// Inicjalizacja kontekstu renderowania
hRC = wglCreateContext( hDC );
ReleaseDC( hWnd, hDC );
return hRC;
}
//********************************************************
// Glowna funkcja rysujaca.
//********************************************************
void DrawOpenGLScene( )
{
GLfloat position[4]={10.0f, 10.0, 100.0f, 0.0f};
// flagi czynnosci pomocniczych
glEnable( GL_DEPTH_TEST );
// czyszczenie buforow
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
//glEnable(GL_CULL_FACE);
glEnable(GL_COLOR_MATERIAL);
auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);
// wlaczenie oswietlenia
glLightfv(GL_LIGHT0, GL_POSITION, position);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
// transformacja obserwacji
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
// umiejscowienie kamery w odleglym miejscu
glTranslatef( pivot_x, pivot_y, -z_dist );
glRotatef(pivot_vert_angle, 1, 0, 0);
glRotatef(pivot_horiz_angle, 0, 1, 0);
glPushMatrix();
//szescian !!!!!!!!!!!!!!!!!!!!!!!!!!
szescian();
glPopMatrix();
glFlush ();
}
wc.style =
CS_HREDRAW | CS_VREDRAW;// styl okna
Brakuje CS_OWNDC
.
case WM_SIZE:
hDC = GetDC (hWnd); // Kontekst urzadzenia
wglMakeCurrent (hDC, hRC);
...
wglMakeCurrent( NULL, NULL );
ReleaseDC( hWnd, hDC );
return 0;
Wywal GetDC, wglMakeCurrent i ReleaseDC.
case WM_PAINT:
// rysowanie scenyhDC = BeginPaint( hWnd, &ps ); wglMakeCurrent( hDC, hRC ); DrawOpenGLScene(); SwapBuffers(hDC); wglMakeCurrent( NULL, NULL ); EndPaint( hWnd, &ps ); return 0;
Wywal BeginPaint, wglMakeCurrent i EndPaint.
Usunięcie EndPaint spowoduje odrysowywanie okna bez przerwy. Możesz więc wywalić wszystkie InvalidateRect.
// NEED THESE for OpenGL calls to work!
| WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
Nieprawda. Do OpenGL-a potrzebne jest CS_OWNDC, a nie WS_CLIPCHILDREN ani WS_CLIPSIBLINGS.
Wybacz troche sie zgubiłem w twojej wypowiedzi, Starałem się robic zgodnie z nia ale nadal sześcian nie porusza sie i nie odzweza sie obraz na bieżąco ze zmianami. Może jeszcze jakaś pomoc, bylbym wdzieczny. Brakuje CS_OWNDC skad wziac ?
Brakuje CS_OWNDC skad wziac ?
Trzeba, niestety, samodzielnie paluszkami wpisać.
Albo nie, czekaj, napiszę dla ciebie, tylko sobie skopiuj i wklej tam gdzie trzeba.
CS_OWNDC
Gdybym mógł prosić o wklejenie ewentualnie kodu w odp. Byłbym wdzięczny.
wc.style =
CS_HREDRAW | CS_VREDRAW;// styl oknaBrakuje
CS_OWNDC
.
wc.style =
CS_HREDRAW | CS_VREDRAW | CS_OWNDC;// styl okna
Azarien napisał(a):
Wywal BeginPaint, wglMakeCurrent i EndPaint.
Usunięcie EndPaint spowoduje odrysowywanie okna bez przerwy. Możesz więc wywalić wszystkie InvalidateRect.
Tak się tego nie robi.
Animacje, albo jakieś gry, rysują bez przerwy w głównej pętli gdy nie ma komunikatów, albo i zawsze.
if( PeekMessage(... ) ) obsługa;
// else
rysujemy;
A w wm_paint nic nie robimy, czyli tak:
BeginPaint...
// tu można rysować ale po co, skoro to i tak ciągle się rysuje w mainloop.
EndPain();
Azarien napisał(a):
Nieprawda. Do OpenGL-a potrzebne jest CS_OWNDC, a nie WS_CLIPCHILDREN ani WS_CLIPSIBLINGS.
Chyba głupoty.
Rysujesz poprzez ten hglrc, a nie po tym hdc...
Do prostych rysowanek można użyć WM_TIMER,
i tam przesuwać sobie i rysować te obrazki (ewentualnie invalidateRect, a potem rysować normalnie, tj. w wm_paint).
https://www.opengl.org/wiki/Platform_specifics:_Windows "Be sure to use the CS_OWNDC flag.". Miałem przynajmniej jeden komputer, na którym TRZEBA było podać CS_OWNDC. Nie widzę powodu by się upierać przeciwnie. - Azarien dzisiaj, 10:30
To weź examples do C++ w VS i tam jest przykładu użycia opengl z MFC - cube, i znajdź tam CS_OWNDC.
Może błąd polega na czymś innym.
Np. nie musisz używać wglMakeCurrent za każdym razem, gdy rysujemy w wm_paint, bo wystarczy raz to zrobić;
ale to i tak nawali, gdy mamy kilka okien w których rysujemy za pomocą opengl.
Podobno też niektóre dawniejsze drivery opengl były zjeb*** i wtedy to cs_owndc pomagało.
Można sobie oczywiście używać spokojnie owndc - na pewno nie zaszkodzi, a i usuwać tego dc wtedy nie potrzeba.
Kiedyś były ostro limitowane zasoby - w win 98 i starszych, więc sobie tworzyli takie głupoty.
A może dzisiaj jest już stale trzymane to dc dla każdego okna, pomijając te standardowe contros - static, button, ect., bo to byłaby lekka przesada...
Ok działa coś tam wykliniłem, ale mam jeszcze inne pytanie. Nie używam glut a chciałbym stworzyć kule, jednak mam trudności z tym. Próbowałem po sworzniu dysku tak go zmodyfikować aby było ok ale mimo wielu prób wychodzą mi jakieś straszaki. Poradzi ktoś?
Nie używam glut a chciałbym stworzyć kule
użyj gluSphere()
.