#include <math.h>
#include <gtk/gtk.h>
#include <gtkgl/gtkglarea.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#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);
}
}
syntax highlighted by Code2HTML, v. 0.9.1