#include #include #include #include #include #include #include "entity.h" #include "rendgtkgl.h" static void rendgtkgl_area_redraw (ENode *glarea); static gint rendgtkgl_area_realize (GtkWidget *widget, gpointer data) { ENode *node = data; /* OpenGL functions can be called only if make_current returns true */ if (gtk_gl_area_make_current(GTK_GL_AREA(widget))) { glViewport(0,0, widget->allocation.width, widget->allocation.height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0,100, 100,0, -1,1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } EDEBUG (("rendgtkgl", "GTK GL realize called")); rendgtkgl_area_redraw (node); return TRUE; } /* When widget is exposed it's contents are redrawn. */ static gint rendgtkgl_area_expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) { ENode *node = data; if (event->count > 0) { rendgtkgl_area_redraw (node); } return TRUE; } /* When glarea widget size changes, viewport size is set to match the new size */ static gint rendgtkgl_area_configure (GtkWidget *widget, GdkEventConfigure *event) { /* OpenGL functions can be called only if make_current returns true */ if (gtk_gl_area_make_current(GTK_GL_AREA(widget))) { glViewport(0,0, widget->allocation.width, widget->allocation.height); } return TRUE; } static void rendgtkgl_render (ENode * node) { GtkWidget *glarea; EBuf *value; /* Attribute list for gtkglarea widget. Specifies a list of Boolean attributes and enum/integer attribute/value pairs. The last attribute must be GDK_GL_NONE. See glXChooseVisual manpage for further explanation. */ int attrlist[] = { GDK_GL_RGBA, GDK_GL_RED_SIZE,1, GDK_GL_GREEN_SIZE,1, GDK_GL_BLUE_SIZE,1, GDK_GL_DOUBLEBUFFER, GDK_GL_NONE }; /* Check if OpenGL is supported. */ if (gdk_gl_query() == FALSE) { g_warning("OpenGL not known to be supported on this system\n"); return; } #if 0 /* This only works in 1.2.2 and greater, so I'll just leave it out. */ /* vendor dependent version info string */ info_str = gdk_gl_get_info(); g_print(info_str); g_free(info_str); #endif /* Create new OpenGL widget. */ glarea = GTK_WIDGET(gtk_gl_area_new(attrlist)); /* Events for widget must be set before X Window is created */ gtk_widget_set_events(GTK_WIDGET(glarea), GDK_EXPOSURE_MASK| GDK_BUTTON_PRESS_MASK); /* Redraw image when exposed. */ gtk_signal_connect(GTK_OBJECT(glarea), "expose_event", GTK_SIGNAL_FUNC(rendgtkgl_area_expose), node); /* When window is resized viewport needs to be resized also. */ gtk_signal_connect(GTK_OBJECT(glarea), "configure_event", GTK_SIGNAL_FUNC(rendgtkgl_area_configure), node); /* Do initialization when widget has been realized. */ gtk_signal_connect(GTK_OBJECT(glarea), "realize", GTK_SIGNAL_FUNC(rendgtkgl_area_realize), node); /* gtk_widget_set_usize(GTK_WIDGET(glarea), 100,100); */ value = enode_attrib (node, "visible", NULL); if ((ebuf_empty (value)) || erend_value_is_true (value)) gtk_widget_show (glarea); enode_set_kv (node, "top-widget", glarea); EDEBUG (("rendgtkgl", "GTK GL render called")); } static int rendgtkgl_redraw_attr_set (ENode * node, EBuf * attr, EBuf * value) { rendgtkgl_area_redraw (node); return TRUE; } static void rendgtkgl_parent (ENode *parent_node, ENode *child_node) { EDEBUG (("rendgtkgl", "rendgtkgl_parent called, looking for parent")); } static void rendgtkgl_destroy (ENode * node) { GtkWidget *top = enode_get_kv (node, "top-widget"); if (top) gtk_widget_destroy (top); } void rendgtkgl_line_render (ENode *node) { EBuf *val; float x1, y1, x2, y2; float width; EDEBUG (("rendgtkgl", "rendering line")); val = enode_attrib (node, "x1", NULL); x1 = erend_get_float (val); val = enode_attrib (node, "y1", NULL); y1 = erend_get_float (val); val = enode_attrib (node, "x2", NULL); x2 = erend_get_float (val); val = enode_attrib (node, "y2", NULL); y2 = erend_get_float (val); val = enode_attrib (node, "width", NULL); if (ebuf_not_empty (val)) { width = erend_get_float (val); EDEBUG (("rendgtkgl", "setting line width to %f", width)); glLineWidth(width); } else { glLineWidth(1.0); } glBegin(GL_LINES); glVertex2f(x1, y1); glVertex2f(x2, y2); glEnd(); } void rendgtkgl_point_render (ENode *node) { EBuf *val; float x, y; EDEBUG (("rendgtkgl", "rendering point")); val = enode_attrib (node, "x", NULL); x = erend_get_float (val); val = enode_attrib (node, "y", NULL); y = erend_get_float (val); glBegin(GL_POINTS); glVertex2f(x, y); glEnd(); } void rendgtkgl_matrix_render (ENode *node) { EBuf *val; float x, y, z; float angle; EDEBUG (("rendgtkgl", "rendering matrix")); glPushMatrix(); val = enode_attrib (node, "translate-x", NULL); if (ebuf_not_empty (val)) { x = erend_get_float (val); val = enode_attrib (node, "translate-y", NULL); y = erend_get_float (val); val = enode_attrib (node, "translate-z", NULL); z = erend_get_float (val); glTranslatef (x, y, z); } val = enode_attrib (node, "rotate-angle", NULL); if (ebuf_not_empty (val)) { angle = erend_get_float (val); val = enode_attrib (node, "rotate-x", NULL); x = erend_get_float (val); val = enode_attrib (node, "rotate-y", NULL); y = erend_get_float (val); val = enode_attrib (node, "rotate-z", NULL); z = erend_get_float (val); EDEBUG (("rendgtkgl", "doing gl-matrix rotation, %f, %f, %f, %f", angle, x, y, z)); glRotatef (angle, x, y, z); } val = enode_attrib (node, "scale-x", NULL); if (ebuf_not_empty (val)) { x = erend_get_float (val); val = enode_attrib (node, "scale-y", NULL); y = erend_get_float (val); val = enode_attrib (node, "scale-z", NULL); z = erend_get_float (val); glScalef (x, y, z); } } void rendgtkgl_text_render (ENode *node) { EBuf *val; float x, y; char *p, *text = NULL; text = enode_attrib_str (node, "text", NULL); EDEBUG (("rendgtkgl", "rendering text")); val = enode_attrib (node, "x", NULL); x = erend_get_float (val); val = enode_attrib (node, "y", NULL); y = erend_get_float (val); glRasterPos2f(x, y); for ( p = text; *p; p++ ) { glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *p); } } static void rendgtkgl_rectangle_render (ENode *node) { /* change values when you split this up okay? */ EBuf *val; float x1, y1, x2, y2; EDEBUG (("rendgtkgl", "rendering a rectangle" )); val = enode_attrib (node, "x1", NULL); x1 = erend_get_float (val); val = enode_attrib (node, "y1", NULL); y1 = erend_get_float (val); val = enode_attrib (node, "x2", NULL); x2 = erend_get_float (val); val = enode_attrib (node, "y2", NULL); y2 = erend_get_float (val); EDEBUG (("rendgtkgl", "rendering a rectangle %f, %f, %f, %f", x1, y1, x2, y2)); glRectf (x1, y1, x2, y2); } static void rendgtkgl_cube_render (ENode *node) { EBuf *val; float size; EDEBUG (("rendgtkgl", "rendering cube")); val = enode_attrib (node, "size", NULL); size = erend_get_float (val); glutSolidCube(size); } static void rendgtkgl_sphere_render (ENode *node) { EBuf *val; float radius, slices, stacks; val = enode_attrib (node, "radius", NULL); radius = erend_get_float (val); val = enode_attrib (node, "slices", NULL); slices = erend_get_float (val); val = enode_attrib (node, "stacks", NULL); stacks = erend_get_float (val); glutSolidSphere(radius, slices, stacks); } static gint rendgtkgl_object_render (ENodeTreeWalk *walker) { EBufConst *type; EBufConst *val; GdkColor color; ENode *node = walker->curnode; type = enode_type (node); EDEBUG (("rendgtkgl", "rendering %s", walker->curnode->element->str)); /* Common stuff */ val = enode_attrib (node, "color", NULL); if (ebuf_not_empty (val)) { if (gdk_color_parse (val->str, &color) ) { glColor3us (color.red, color.green, color.blue); } else { glColor3us (255, 255, 255); } } if (ebuf_equal_str (type, "gl-point")) { rendgtkgl_point_render (node); } else if (ebuf_equal_str (type, "gl-line")) { rendgtkgl_line_render (node); } else if (ebuf_equal_str (type, "gl-matrix")) { rendgtkgl_matrix_render (node); } else if (ebuf_equal_str (type, "gl-rectangle")) { rendgtkgl_rectangle_render (node); } else if (ebuf_equal_str (type, "glut-cube")) { rendgtkgl_cube_render (node); } else if (ebuf_equal_str (type, "glut-sphere")) { rendgtkgl_sphere_render (node); } else if (ebuf_equal_str (type, "glut-text")) { rendgtkgl_text_render (node); } return (TRUE); } static gint rendgtkgl_object_parent (ENodeTreeWalk *walker) { EBuf *type; EDEBUG (("rendgtkgl", "Parenting %s to parent %s", walker->curnode->element->str, walker->parentnode->element->str)); type = enode_type (walker->curnode); if (ebuf_equal_str(type, "gl-matrix")) { EDEBUG (("rendgtkgl", "Popping matrix")); glPopMatrix(); } return (TRUE); } static void rendgtkgl_area_redraw (ENode *glarea) { GtkWidget *widget; widget = enode_get_kv (glarea, "top-widget"); if (!widget) return; /* OpenGL functions can be called only if make_current returns true */ if (gtk_gl_area_make_current(GTK_GL_AREA(widget))) { ENodeTreeWalk *walker; glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); walker = enode_treewalk_new (glarea); enode_treewalk (walker, rendgtkgl_object_render, rendgtkgl_object_parent); enode_treewalk_free (walker); /* Swap backbuffer to front */ gtk_gl_area_swapbuffers(GTK_GL_AREA(widget)); } } void renderer_init (RendererFlags flags) { Element *element; ElementAttr *e_attr; EDEBUG (("rendgtkgl", "registering rendgtkgl")); if (flags & RENDERER_REGISTER) { EDEBUG (("rendgtkgl", "Registering glarea element")); element = g_new0 (Element, 1); element->render_func = rendgtkgl_render; element->parent_func = rendgtkgl_parent; element->destroy_func = rendgtkgl_destroy; element->description = "Create a gtk GL area for doing GL based graphics."; element->tag = "glarea"; element_register (element); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "redraw"; e_attr->description = "Cause a redraw of the GL Area."; e_attr->value_desc = "*"; e_attr->set_attr_func = rendgtkgl_redraw_attr_set; element_register_attrib (element, e_attr); /* GtkGLArea Point Renderer */ element = g_new0 (Element, 1); element->tag = "gl-point"; element->description = "Create a single point on the gl area."; element_register (element); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "x"; e_attr->description = "Horizontal point location."; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "y"; e_attr->description = "Vertical point location."; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); /* GtkGLArea Rectangle Renderer, change atribs when you split this up please */ element = g_new0 (Element, 1); element->tag = "gl-rectangle"; element->description = "Create a rectangle in the gl area."; element_register (element); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "x1"; e_attr->description = "First horizontal point location."; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "y1"; e_attr->description = "First vertical point location."; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "x2"; e_attr->description = "Second horizontal point location."; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "y2"; e_attr->description = "Second vertical point location."; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); /* GtkGLArea Line Renderer */ element = g_new0 (Element, 1); element->tag = "gl-line"; element->description = "Create a line in the gl area."; element_register (element); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "x1"; e_attr->description = "First horizontal point location."; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "y1"; e_attr->description = "First vertical point location."; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "x2"; e_attr->description = "Second horizontal point location."; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "y2"; e_attr->description = "Second vertical point location."; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); /* GtkGLArea Cube Renderer */ element = g_new0 (Element, 1); element->tag = "glut-cube"; element->description = "Draw a cube in the gl area."; element_register (element); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "size"; e_attr->description = "Size of cube."; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); element = g_new0 (Element, 1); /* GtkGLArea Sphere Renderer */ element->tag = "glut-sphere"; element->description = "Create a sphere in the gl area."; element_register (element); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "radius"; e_attr->description = "radius of sphere"; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "slices"; e_attr->description = "number of subdivisions around X axis"; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "stacks"; e_attr->description = "number of subdivisions along Z axis"; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); /* font text render */ element = g_new0 (Element, 1); element->tag = "glut-text"; element->description = "Draw text in a gl area."; element_register (element); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "text"; e_attr->description = "text in widget"; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "x"; e_attr->description = "x co-ordinate"; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); e_attr = g_new0 (ElementAttr, 1); e_attr->attribute = "y"; e_attr->description = "y coordinate"; e_attr->value_desc = "0,*"; element_register_attrib (element, e_attr); } }