using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; using System.Text; using allegro; using alleggl; public class exgui : AllegGL { /* This is an example of how to use the Allegro GUI routines along with AllegroGL It demonstrates how to proceed to : - Use the OpenGL double buffer along with the GUI - Use the regular Allegro GUI routines "as is" - Create a GUI viewport which draws some GL stuff (see 'glviewport_proc()') */ const float VIEW_ASPECT = 1.0f; /* information needed to display the mesh */ struct display_info { public int polygon_mode; /* rendering mode of polygons */ public float theta, phi; /* orientation of object */ public uint tex; /* texture */ } static display_info _display_info; /* No need of a 'd_clear_proc' since algl_do_dialog will clear the screen * and Z buffer for us. However note that things like centre_dialog will * benefit from having a clear proc at the start, and for non-fullscreen * dialogs perhaps you'd want the auto-clear to clear to black, then draw * your small dialog in white with a d_clear_proc. It's up to you. */ static DIALOGS my_dialog = new DIALOGS(6); /* This callback function demonstrates how to use the d_algl_viewport_proc * object. */ static int glviewport_callback(IntPtr viewport, int msg, int c) { int focus = TRUE; float prevx = 0, prevy = 0; /* position of mouse */ float zoom = 30; /* field of view in degrees */ int ret = 0; /* Determine if the mouse is on the object */ if (msg == MSG_GOTMOUSE) { focus = TRUE; } if (msg == MSG_LOSTMOUSE) { focus = FALSE; } if (msg == MSG_IDLE) { rest(2); ret = D_O_K; } if (msg == MSG_DRAW) { OpenGL.glMatrixMode(OpenGL.GL_MODELVIEW); OpenGL.glLoadIdentity(); OpenGL.glMatrixMode(OpenGL.GL_PROJECTION); OpenGL.glLoadIdentity(); OpenGLU.gluPerspective(zoom, VIEW_ASPECT, 1, 100); OpenGL.glMatrixMode(OpenGL.GL_MODELVIEW); OpenGL.glTranslatef(0, 0, -30); /* Apply the rotations */ OpenGL.glRotatef(_display_info.phi, 1.0f, 0.0f, 0.0f); OpenGL.glRotatef(_display_info.theta, 0.0f, 1.0f, 0.0f); /* Display the 3D object */ OpenGL.glPolygonMode(OpenGL.GL_FRONT_AND_BACK, (uint)_display_info.polygon_mode); display(); OpenGL.glPolygonMode(OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_FILL); /* Display of 2D objects is also possible */ allegro_gl_set_allegro_mode(); rect(viewport, 5, 5, ((BITMAP)viewport).w - 5, ((BITMAP)viewport).h - 5, focus != 0 ? makecol(255, 0, 0) : makecol(255, 255, 255)); textprintf_ex(viewport, font, 10, 445, makecol(255, 255, 255), -1, "Click & drag"); allegro_gl_unset_allegro_mode(); ret = D_O_K; } /* drag in progress, simulate trackball */ if ((mouse_b & 1) > 0 && focus != 0) { float x, y; x = mouse_x; y = mouse_y; _display_info.theta += x - prevx; _display_info.phi += y - prevy; ret = D_O_K; } /* zooming drag */ if ((mouse_b & 2) > 0 && focus != 0) { zoom += ((mouse_y - prevy) / ((BITMAP)viewport).h) * 40; if (zoom < 5) zoom = 5; if (zoom > 120) zoom = 120; ret = D_O_K; } prevx = mouse_x; prevy = mouse_y; return ret; } public delegate int GLVIEWPORT(IntPtr viewport, int msg, int c); static GLVIEWPORT d_glviewport_callback = new GLVIEWPORT(glviewport_callback); /* This function is an ordinary GUI proc (no GL calls) It manages the 3 radio buttons and determine which rendering type has been selected */ static int my_radio_proc(int msg, IntPtr d, int c) { int ret, i; //ret = d_radio_proc(msg, d, c); DIALOG_PROC _d_radio_proc = (DIALOG_PROC)Marshal.GetDelegateForFunctionPointer(AllegroAPI.GetAddress("d_radio_proc"), typeof(DIALOG_PROC)); ret = _d_radio_proc(msg, d, c); /* Determine which one is selected... */ for (i = 1; i < 3; i++) { if ((my_dialog[i].flags & D_SELECTED) > 0) { break; } } /* ...and change the mode accordingly */ switch (i) { case 1: _display_info.polygon_mode = (int)OpenGL.GL_POINT; break; case 2: _display_info.polygon_mode = (int)OpenGL.GL_LINE; break; case 3: default: _display_info.polygon_mode = (int)OpenGL.GL_FILL; break; } return ret; } static DIALOG_PROC d_my_radio_proc = new DIALOG_PROC(my_radio_proc); /* Displays the 3D object */ static void display() { /* Translate and rotate the object */ OpenGL.glTranslatef(-2.5f, 0.0f, 0.0f); OpenGL.glRotatef(-30, 1.0f, 0.0f, 0.0f); OpenGL.glRotatef(30, 0.0f, 1.0f, 0.0f); OpenGL.glRotatef(30, 0.0f, 0.0f, 1.0f); OpenGL.glColor3f(1.0f, 0.0f, 1.0f); /* Draw the sides of the three-sided pyramid */ OpenGL.glBindTexture(OpenGL.GL_TEXTURE_2D, _display_info.tex); OpenGL.glBegin(OpenGL.GL_TRIANGLE_FAN); OpenGL.glTexCoord2f(0, 0); OpenGL.glVertex3d(0, 4, 0); OpenGL.glTexCoord2f(1, 0); OpenGL.glVertex3d(0, -4, -4); OpenGL.glTexCoord2f(1, 1); OpenGL.glVertex3d(-4, -4, 4); OpenGL.glTexCoord2f(0, 1); OpenGL.glVertex3d(4, -4, 4); OpenGL.glTexCoord2f(1, 0); OpenGL.glVertex3d(0, -4, -4); OpenGL.glEnd(); OpenGL.glColor3f(0.0f, 1.0f, 1.0f); /* Draw the base of the pyramid */ OpenGL.glBegin(OpenGL.GL_TRIANGLES); OpenGL.glTexCoord2f(1, 0); OpenGL.glVertex3d(0, -4, -4); OpenGL.glTexCoord2f(0, 1); OpenGL.glVertex3d(4, -4, 4); OpenGL.glTexCoord2f(1, 1); OpenGL.glVertex3d(-4, -4, 4); OpenGL.glEnd(); OpenGL.glTranslatef(2.5f, 0.0f, 0.0f); OpenGL.glRotatef(45, 1.0f, 0.0f, 0.0f); OpenGL.glRotatef(45, 0.0f, 1.0f, 0.0f); OpenGL.glRotatef(45, 0.0f, 0.0f, 1.0f); OpenGL.glColor3f(0.0f, 1.0f, 0.0f); OpenGL.glBindTexture(OpenGL.GL_TEXTURE_2D, 0); /* Draw the sides of the cube */ OpenGL.glBegin(OpenGL.GL_QUAD_STRIP); OpenGL.glVertex3d(3, 3, -3); OpenGL.glVertex3d(3, -3, -3); OpenGL.glVertex3d(-3, 3, -3); OpenGL.glVertex3d(-3, -3, -3); OpenGL.glVertex3d(-3, 3, 3); OpenGL.glVertex3d(-3, -3, 3); OpenGL.glVertex3d(3, 3, 3); OpenGL.glVertex3d(3, -3, 3); OpenGL.glVertex3d(3, 3, -3); OpenGL.glVertex3d(3, -3, -3); OpenGL.glEnd(); OpenGL.glColor3f(0.0f, 0.0f, 1.0f); /* Draw the top of the cube */ OpenGL.glBegin(OpenGL.GL_QUADS); OpenGL.glVertex3d(-3, -3, -3); OpenGL.glVertex3d(3, -3, -3); OpenGL.glVertex3d(3, -3, 3); OpenGL.glVertex3d(-3, -3, 3); OpenGL.glEnd(); /* Bottom is texture-mapped */ OpenGL.glBindTexture(OpenGL.GL_TEXTURE_2D, _display_info.tex); OpenGL.glBegin(OpenGL.GL_QUADS); OpenGL.glTexCoord2f(0, 0); OpenGL.glVertex3d(-3, 3, -3); OpenGL.glTexCoord2f(1, 0); OpenGL.glVertex3d(-3, 3, 3); OpenGL.glTexCoord2f(1, 1); OpenGL.glVertex3d(3, 3, 3); OpenGL.glTexCoord2f(0, 1); OpenGL.glVertex3d(3, 3, -3); OpenGL.glEnd(); OpenGL.glBindTexture(OpenGL.GL_TEXTURE_2D, 0); } /* Load the texture */ static void setup_texture() { PALETTE pal = new PALETTE(); BITMAP bmp, bmp2; int w = 128, h = 128; bmp = load_bitmap("mysha.pcx", pal); if (!bmp) { allegro_message("Error loading `mysha.pcx'"); return; } bmp2 = create_bitmap(w, h); stretch_blit(bmp, bmp2, 0, 0, bmp.w, bmp.h, 0, 0, w, h); destroy_bitmap(bmp); OpenGL.glTexEnvi(OpenGL.GL_TEXTURE_ENV, OpenGL.GL_TEXTURE_ENV_MODE, (int)OpenGL.GL_DECAL); _display_info.tex = allegro_gl_make_texture(bmp2); destroy_bitmap(bmp2); } static int Main() { //DIALOG my_dialog[] = //{ // /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ // { d_algl_viewport_proc, 10, 10, 460, 460, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, // { my_radio_proc, 500, 10, 120, 20, 0, 0, 0, 0, 1, 0, "Points", NULL, NULL }, // { my_radio_proc, 500, 40, 120, 20, 0, 0, 0, 0, 1, 0, "Lines", NULL, NULL }, // { my_radio_proc, 500, 70, 120, 20, 0, 0, 0, D_SELECTED, 1, 0, "Polygons", NULL, NULL }, // { d_button_proc, 500, 450, 120, 20, 0, 0, 0, D_EXIT, 0, 0, "Exit", NULL, NULL }, // { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } //}; allegro_init(); install_allegro_gl(); allegro_gl_clear_settings(); allegro_gl_set(AGL_Z_DEPTH, 16); allegro_gl_set(AGL_COLOR_DEPTH, 16); allegro_gl_set(AGL_DOUBLEBUFFER, 1); allegro_gl_set(AGL_WINDOWED, TRUE); allegro_gl_set(AGL_SUGGEST, AGL_COLOR_DEPTH | AGL_Z_DEPTH | AGL_DOUBLEBUFFER | AGL_WINDOWED); if (set_gfx_mode(GFX_OPENGL, 640, 480, 0, 0) < 0) { allegro_message(string.Format("Error setting OpenGL graphics mode:\n{0}\n" + "Allegro GL error : {1}\n", allegro_error, allegro_gl_error)); return -1; } install_keyboard(); install_mouse(); /* Set up OpenGL */ /* remove back faces */ OpenGL.glEnable(OpenGL.GL_DEPTH_TEST); OpenGL.glEnable(OpenGL.GL_CULL_FACE); /* speedups */ OpenGL.glShadeModel(OpenGL.GL_FLAT); OpenGL.glPointSize(2.0f); OpenGL.glEnable(OpenGL.GL_TEXTURE_2D); setup_texture(); /* Set colours of dialog components */ set_dialog_color(my_dialog, makecol(0, 0, 0), makecol(255, 255, 255)); /* Set up the callback function for d_algl_viewport_proc */ my_dialog[0].dp = Marshal.GetFunctionPointerForDelegate(d_glviewport_callback); my_dialog[0].bg = makecol(77, 102, 153); /* Set colour for automatic dialog clearing */ OpenGL.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); my_dialog[0] = new DIALOG(d_algl_viewport_proc, 10, 10, 460, 460, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL); my_dialog[1] = new DIALOG(d_my_radio_proc, 500, 10, 120, 20, 0, 0, 0, 0, 1, 0, Marshal.StringToCoTaskMemAnsi("Points"), NULL, NULL); my_dialog[2] = new DIALOG(d_my_radio_proc, 500, 40, 120, 20, 0, 0, 0, 0, 1, 0, Marshal.StringToCoTaskMemAnsi("Lines"), NULL, NULL); my_dialog[3] = new DIALOG(d_my_radio_proc, 500, 70, 120, 20, 0, 0, 0, D_SELECTED, 1, 0, Marshal.StringToCoTaskMemAnsi("Polygons"), NULL, NULL); my_dialog[4] = new DIALOG(d_button_proc, 500, 450, 120, 20, 0, 0, 0, D_EXIT, 0, 0, Marshal.StringToCoTaskMemAnsi("Exit"), NULL, NULL); my_dialog[5] = new DIALOG(NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL); /* Same as Allegro's do_dialog, but works with OpenGL -- the only * caveat is that the whole screen is cleared and the dialog redrawn * once per update (i.e. pretty much all the time). */ algl_do_dialog(my_dialog, -1); return 0; } static int algl_do_dialog(IntPtr dialog, int focus_obj) { DIALOG_PLAYER player; //AGL_LOG(2, "allegro_gl_do_dialog\n"); /* Allegro GUI routines generally use the 2D gfx functions therefore we set default behaviour to allegro_gl_set_allegro_mode so that we can use the GUI functions "as is" */ allegro_gl_set_allegro_mode(); player = init_dialog(dialog, focus_obj); show_mouse(screen); /* Nothing to do here. * Redrawing is done from d_algl_viewport_proc() callback. */ while (update_dialog(player) != 0) { } show_mouse(NULL); /* restore previous projection matrices */ allegro_gl_unset_allegro_mode(); return shutdown_dialog(player); } static int d_algl_viewport_proc(int msg, IntPtr _d, int c) { int ret = D_O_K; DIALOG d = _d; //typedef int (*_callback)(BITMAP*, int, int); //_callback callback = (_callback) d->dp; BITMAP viewport = create_sub_bitmap(screen, d.x, d.y, d.w, d.h); //AGL_LOG(3, "d_algl_viewport_proc\n"); if (msg == MSG_DRAW) { /* Draws the background */ clear_to_color(viewport, d.bg); } /* First we get back into a 3D mode */ allegro_gl_unset_allegro_mode(); /* Save the Viewport and Scissor states */ OpenGL.glPushAttrib(OpenGL.GL_SCISSOR_BIT | OpenGL.GL_VIEWPORT_BIT); /* Adapt the viewport to the object size */ OpenGL.glViewport(d.x, SCREEN_H - d.y - d.h, d.w, d.h); OpenGL.glScissor(d.x, SCREEN_H - d.y - d.h, d.w, d.h); OpenGL.glEnable(OpenGL.GL_SCISSOR_TEST); /* Clear the depth buffer for this scissor region */ if (msg == MSG_DRAW) { OpenGL.glClear(OpenGL.GL_DEPTH_BUFFER_BIT); } /* Call the callback function */ //if (callback) // ret = callback(viewport, msg, c); ret = glviewport_callback(viewport, msg, c); /* Restore the previous state */ OpenGL.glPopAttrib(); allegro_gl_set_allegro_mode(); destroy_bitmap(viewport); /* Redraw the GUI every frame */ if (msg == MSG_IDLE) { OpenGL.glClear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); broadcast_dialog_message(MSG_DRAW, 0); /* Draw the mouse cursor */ algl_draw_mouse(); /* Flip buffers */ allegro_gl_flip(); } return ret; } }