zneu = z2 + c0 (xneu+j.yneu) = ( x+j.y)2 + (x0,j.y0) (xneu+j.yneu) = ( x2 - y2 + x0 ) + j.( 2.x.y + y0 ) xneu := ( x2 - y2 + x0 ) yneu := ( 2.x.y + y0 )divergieren. Durch count_mandel_schritte( maxCount, x0, y0 ) wird diese Anzahl der Schritte < maxCount ermittelt.
if((GetAsyncKeyState(VK_ESCAPE)<0))return;verwendet werden.
Hier ist kein komplettes programm! Dies soll mit den Kenntnissen selbst zusammen gestellt werden.
// zum Abbrechen: #define DO_STOP ((GetAsyncKeyState(VK_ESCAPE)<0))
// Weltgrösse GLdouble x_min = -3.0; GLdouble x_max = +1.0; GLdouble y_min = -2.0; GLdouble y_max = +2.0;
// ermittle die Anzahl der Iterationsschritte: int count_mandel_schritte( int maxCount, double x0, double y0 ) { int anz = 0; double h, x = x0, y = y0, r = 0.0; while (( anz < maxCount ) && ( r < 4.0 )) { h = x ; x = h * h - y * y + x0 ; y = h * y; y += y + y0 ; r = x * x + y * y ; anz ++ ; } return anz ; }
Anstelle von void draw_mandel( int di, int dj, int maxCount ) { ... } können auch globale "Paramter" verendet werden (siehe weiter unten ...)
Mit der folgenden Methode kann ein Menu erstellt werden. Zur Schreibvereinfachung werden (wie angegeben) die MACROS verwendet, wie z.B.:
MENU_BEGIN() // kein ; MENU_POPUP("Popup&1") // kein ; MENU_ITEM("Item &1 zu Popup1", show_1) // kein ; MENU_ITEM("Item &2 zu Popup1", show_2) // kein ; MENU_POPUP("&Fraktale ") // kein ; MENU_ITEM("...", draw_...1) // kein ; MENU_ITEM("...", draw_...2) // kein ; MENU_END() // kein ;
Die Menu-Funktionen müssen vom Typ sein (sonst "Abstürze, Stacküberlauf, usw."):
typedef void (CALLBACK* SHOW_FUNC)();
SHOW_FUNC show_func;
Menu-Funktionen sehen dann z.B. so aus:
void CALLBACK draw_mandel1(void) { m_color_index = 1; draw_mandel(); }
void CALLBACK draw_mandel2(void) { m_color_index = 2; draw_mandel(); }
void CALLBACK draw_mandel3(void) { m_color_index = 3; draw_mandel(); }
void CALLBACK draw_mandel4(void) { m_color_index = 4; draw_mandel(); }
void CALLBACK set_org(void) { ...}
Als Menu-Item-Identifizierer (WM_COMMAND, wParam)
wird der Funktionszeiger einer Menu-Funktion verwendet,
was zwar einfach in der Benutzung ist, aber auch "gefährlich".
/* Rahmen-Quelltext: OpenGL mit Windows GLAUX.LIB OPENGL32.LIB GLU32.LIB */ #include <windows.h> #include <gl\glaux.h> #include <gl\gl.h> #include <stdio.h> #include <math.h> #pragma comment(lib, "GLAUX.LIB") #pragma comment(lib, "OPENGL32.LIB") #pragma comment(lib, "GLU32.LIB") #pragma comment(linker,"/defaultlib:kernel32.lib") #pragma comment(linker,"/entry:mainCRTStartup") #pragma comment(linker,"/subsystem:windows") //////////////////////////////////////////////////////// // AB HIER NICHTS ÄNDERN BITTE BIS ... #define err_if(e,errStr) if(e)if(IDOK!=MessageBox(0,TEXT(errStr),0,\ MB_OKCANCEL|MB_DEFBUTTON2|MB_ICONSTOP|MB_SETFOREGROUND))exit(-1); #define DO_STOP ((GetAsyncKeyState(VK_ESCAPE)<0)) void CALLBACK ChangeSize(int w, int h); LONG old_wnd_proc; // vorherige CALLBACK-Funktion //Prototyp der CALLBACK-Funktion: //LRESULT CALLBACK wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); // MENU-Macros: #define MENU_BEGIN() {HMENU hPopup=0;TCHAR *pPopup=TEXT("");HMENU m_hMenu=CreateMenu(); #define MENU_POPUP(text) if(hPopup)AppendMenu(m_hMenu,MF_POPUP,(UINT_PTR)hPopup,pPopup);hPopup=CreatePopupMenu();pPopup=TEXT(text); #define MENU_ITEM(text,func) AppendMenu(hPopup,MF_STRING,(UINT_PTR)(func),TEXT(text)); #define MENU_END() AppendMenu(m_hMenu,MF_POPUP,(UINT_PTR)hPopup,pPopup);SetMenu(auxGetHWND(),m_hMenu);\ SetClassLong(auxGetHWND(),GCL_HICON,(LONG)ExtractIcon(GetModuleHandle(0),"Shell32.dll",43));\ old_wnd_proc = SetWindowLong(auxGetHWND(),GWL_WNDPROC,(LONG)wnd_proc);} typedef void (CALLBACK* SHOW_FUNC)(); SHOW_FUNC show_func; // aktuelle Zeichenfunktion LRESULT CALLBACK wnd_proc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { if(WM_COMMAND == uMsg) { //ist GetClassName(hwnd, buf, 512);//"tkLibWClass" if(!lParam ||(HIWORD(wnd_proc)==HIWORD(wParam))) { show_func = (SHOW_FUNC)(wParam|(0xFFFF0000&(UINT)wnd_proc)); InvalidateRect(hwnd,NULL,TRUE); UpdateWindow(hwnd); } } //SetWindowPos(auxGetHWND(),HWND_TOP,0,0,0,0,(SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_SHOWWINDOW)); return CallWindowProc((WNDPROC)old_wnd_proc,hwnd,uMsg,wParam,lParam); } // ... BIS HIERHER ////////////////////////////////////////////////////////
So ist etwa die main-Funktion aufgebaut:
int main(int argc, char* argv[]) { auxInitDisplayMode(AUX_DOUBLE|AUX_RGBA|AUX_DEPTH); auxInitPosition(200,200, m_width, m_hight); auxInitWindow("GDV-Musterlösung (Fraktale)"); // HIER WERDEN TASTEN EINGEFÜGT auxKeyFunc('1', set_1_aktiv); // Taste 1 auxKeyFunc('2', set_2_aktiv); // Taste 2 auxKeyFunc('3', set_3_aktiv); // Taste 3 // HIER WERDEN MAUS_CALLBACK-Funktionen hinterlegt auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN, mouse_ldown ); auxMouseFunc(AUX_RIGHTBUTTON, AUX_MOUSEDOWN, mouse_rdown ); auxReshapeFunc( ChangeSize ); /* // HIER WIRD DAS MENU EINGEFÜGT MENU_BEGIN() // kein ; MENU_POPUP("Popup&1") // kein ; MENU_ITEM("Item &1 zu Popup1", show_1) // kein ; MENU_ITEM("Item &2 zu Popup1", show_2) // kein ; MENU_POPUP("&Fraktale ") // kein ; MENU_ITEM("draw_mandel (colortyp &1), Maus-Klick-Zoom on", draw_mandel1) // kein ; MENU_ITEM("draw_mandel (Colortyp &2), Maus-Klick-Zoom on", draw_mandel2) // kein ; MENU_ITEM("draw_mandel (Colortyp &3), Maus-Klick-Zoom on", draw_mandel3) // kein ; MENU_ITEM("draw_mandel (Colortyp &4), Maus-Klick-Zoom on", draw_mandel4) // kein ; MENU_ITEM("feine Rasterung und &langsam, Maus-Klick-Zoom on", set_fein) // kein ; MENU_ITEM("mittlere Rasterung und &bunt, Maus-Klick-Zoom on", set_mittel) // kein ; MENU_ITEM("grobe Rasterung und &scnell, Maus-Klick-Zoom on", set_grob) // kein ; MENU_ITEM("&Reset (org. Weltgrösse), Maus-Klick-Zoom on", set_org) // kein ; MENU_POPUP("&Beispiele") // kein ; MENU_ITEM("beispiel &1, Maus-Klick-Zoom off", draw_mandel_a) // kein ; MENU_ITEM("beispiel &2, Maus-Klick-Zoom off", draw_mandel_b) // kein ; MENU_ITEM("beispiel &3, Maus-Klick-Zoom off", draw_mandel_c) // kein ; MENU_ITEM("beispiel &4, Maus-Klick-Zoom off", draw_mandel_d) // kein ; MENU_POPUP("&Help") // kein ; MENU_ITEM("&Info ", help1) // kein ; MENU_ITEM("&About", help2) // kein ; MENU_END() // kein ; */ auxMainLoop( RenderScene ); return 0; }
Es ist oft günstig, wenn die vielen möglichen Arten der Einstellungen und Auswahlmöglichkeiten des Menüs mit Hilfe von globale Konstanten gesteuert wird. Ein Menu-Item setzt dann lediglich diese globale Konstante(n), die oft an dem m_... erkennbar sind und später zu Member-Variablen werden können. Global ist z.B.:
// oben nach den #include ... #define PI 3.14159265 GLdouble x_min = -3.0; GLdouble x_max = +1.0; // x-Weltgrösse GLdouble y_min = -2.0; GLdouble y_max = +2.0; // y-Weltgrösse GLint m_width = 300; GLint m_hight = 300; //Pixel-Breite,-Höhe GLint m_di = 2, m_dj = 2; // Vergröberungsfaktoren GLint m_color_index = 1; // Art der farbgestaltung GLdouble m_dx, m_dy; // Welt-Schrittweite GLint m_maxCount = 40; // maximale Anzahl von Iterationen GLint m_anzCount; // aktuelle Anzahl GLdouble m_rsum; // Quadrat-Summe
Beispiele für Menu-Item-Funktionen sind:
void CALLBACK draw_mandel1(void) { m_color_index = 1; draw_mandel(); } void CALLBACK draw_mandel2(void) { m_color_index = 2; draw_mandel(); } void CALLBACK draw_mandel3(void) { m_color_index = 3; draw_mandel(); } void CALLBACK draw_mandel4(void) { m_color_index = 4; draw_mandel(); } void CALLBACK set_org(void) { x_min = -3.0; x_max = +1.0; // x-Weltgrösse y_min = -2.0; y_max = +2.0; // y-Weltgrösse m_di = 2; m_dj = 2; m_maxCount = 40; ChangeSize(0,0); draw_mandel(); }
count_mandel_schritte(x0,y0) ermittelt an einem bestimmten Punkt (x0,y0) die Anzahl m_anzCount der Iterationen. m_anzCount entspricht (in irgend einer Art) der Farben des Punktes (x0,y0). Die Funktion set_color() benutzt den aktuell-eingestellten Wert m_color_index, um daraus in einer kreativen Art ein glColor3d(r(m_color_index),g(m_color_index),b(m_color_index)) zu machen.
void count_mandel_schritte(double x0,double y0) { GLdouble x,y, h, r = 0.0; m_anzCount = 0; m_rsum = 0.0; x = x0; y = y0; while (( m_anzCount < m_maxCount ) && ( r < 4.0 )) { h = x ; x = h * h - y * y + x0 ; y = h * y; y += y + y0 ; r = x * x + y * y ; m_rsum += r; m_anzCount++; } }
draw_mandel() ist eine Menu-Item-Funktion, die dann etwa wie folgt aussieht:
void CALLBACK draw_mandel(void) { m_dx = (x_max - x_min)/m_width; m_dx *= m_di; m_dy = (y_max - y_min)/m_hight; m_dy *= m_dj; double x,y; for ( x = x_min; x < x_max; x += m_dx ) { for ( y = y_min; y < y_max; y += m_dy ) { if(DO_STOP) return; count_mandel_schritte(x,y); set_color(); if((m_di==1)&&(m_dj==1)){ glBegin(GL_LINES); glVertex3d(x, y, 0 ); glVertex3d(x + m_dx, y + m_dy, 0 ); glEnd(); } else { err_if(1,"es ist noch was zu tun!!!"); } } } }
Um Nachrichten-Rekurisonen zu vermeiden braucht eine MessageBox() das Zurücksetzen von show_func = 0;
void help1(void) { show_func = 0;
MessageBox(auxGetHWND(),
"1. Mit einem linken Mausklick kann in das Farktal hinein-gezoomt werden.\n" \
"2. Mit einem rechten Mausklick kann in das Farktal hinein-gezoomt werden.\n" \
"3. Auc können die Taste '1' oder Alt+1 zum Zeichnen verwendet werden\n"
,"Erklärungen",MB_OK);
}
Wie sieht ChangeSize() aus? Damit eigene Aufrufe von ChangeSize(0,0) den Viewport setzen, holt sich in diesem Fall glGetInteger() die aktuellen Viewport-Werte.
void CALLBACK ChangeSize(int w, int h) { if((w<1)||(h<1)) { int ijwh[4]; glGetIntegerv(GL_VIEWPORT, ijwh); m_width = ijwh[2]; m_hight = ijwh[3]; } else { m_width = w; m_hight = h; } glViewport( 0,0, m_width, m_hight ); glMatrixMode( GL_MODELVIEW );glLoadIdentity(); glOrtho(x_min,x_max,y_min,y_max,-100,100); // = volle Fläche } void CALLBACK RenderScene( void ) { glClear(GL_COLOR_BUFFER_BIT); if(show_func) show_func(); auxSwapBuffers(); }
Wie kann durch einen Maus-Klick an der Maus-Position eine Ausschnittsvergrösserung (und ähnlich eine Ausschnittsverkleinerung) erfolgen?
// void CALLBACK mouse_rdown( AUX_EVENTREC *e ) { double x0,y0, dx,dy; int i0 = e -> data[AUX_MOUSEX]; int j0 = e -> data[AUX_MOUSEY]; int di = m_width; int dj = m_hight; dx = x_max - x_min; x0 = x_min + dx * i0/di; dy = y_max - y_min; y0 = y_max - dy * j0/dj; x_min = x0 - dx*2; x_max = x0 + dx*2; y_min = y0 - dy*2; y_max = y0 + dy*2; //printf("\nx_min=%8.5f, x_max=%8.5f, y_min=%8.5f, y_max=%8.5f",x_min,x_max,y_min,y_max); ChangeSize(0,0); }