gtk-gl-slider例程分析


gtk_gl_init (&argc, &argv);

初始化gtkglext


surface = cairo_image_surface_create_from_png (IMAGE);

context = cairo_create (surface);

创建cairo的surface,context


g_signal_connect (G_OBJECT (drawing_area), "expose-event", G_CALLBACK (expose), NULL);

注册绘图事件函数


  gl_context = gtk_widget_get_gl_context (widget);
  gl_drawable = gtk_widget_get_gl_drawable (widget);

获取gl_context,gl_drawable


gdk_gl_drawable_gl_begin (gl_drawable, gl_context);

  glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
  glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, surface_data[0]);
  gdk_gl_drawable_gl_end (gl_drawable);
进行控件绘图操作


/* un deslizador de planos OpenGL texturados con Cairo */
/* Juan Manuel Mouriz <jmouriz@gmail.com> */

#include <gtk/gtk.h>
#include <gtk/gtkgl.h>
#include <GL/gl.h>
#include <math.h>

#define IMAGE "covers/1.png"
#define SPEED 1000 / 60

typedef enum
{
  BACK = -1,
  FORWARD = 1,
  LEFT = -1,
  RIGHT = 1
} direction_t;

static GtkWidget *drawing_area;
static gfloat angle;
static gfloat offset;
static GLuint texture;
static direction_t direction;

gint width;
gint height;
guchar *surface_data[1];

/* función de apoyo que reemplaza gluPerspective con glFrustum */
void
perspective (GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far)
{
  GLdouble top;
  GLdouble bottom;
  GLdouble left;
  GLdouble right;

  top = near * tan (M_PI / 180.0f * fovy / 2.0f);
  bottom = -top;
  right = aspect * top;
  left = -right;

  glFrustum (left, right, bottom, top, near, far);
}

/* transformación para la animación de rotación */
void
transform_rotation (void)
{
  glRotatef (angle * direction, 0, 1, 0);
}

/* transformación para la animación de desplazamiento */
void
transform_translation (void)
{
  glTranslatef (offset * direction, 0.0f, 0.0f);
}

/* actualización del área de dibujo */
void
update (void)
{
  gdk_window_invalidate_rect (drawing_area->window, &drawing_area->allocation, FALSE);
  gdk_window_process_updates (drawing_area->window, FALSE);
}

/* función de rotación */
gboolean
rotate (gpointer data)
{
  gboolean stop;

  stop = FALSE;
  angle += 10.0f;
  stop ^= angle > 45.0f;

  update ();

  return !stop;
}

/* función de desplazamiento */
gboolean
translate (gpointer data)
{
  gboolean stop;

  stop = FALSE;
  offset += 0.05f;
  stop ^= offset > 0.5f;

  update ();

  return !stop;
}

/* comienzo de la rotación */
void
start_rotation (void)
{
  angle = 0.0f;

  g_timeout_add (SPEED, rotate, NULL);
}

/* comienzo del desplazamiento */
void
start_translation (void)
{
  offset = 0.0f;

  g_timeout_add (SPEED, translate, NULL);
}

/* manejadores de señales para los botones de control */

void
go_left (GtkWidget *widget, gpointer data)
{
  direction = LEFT;

  start_rotation ();
}

void
go_right (GtkWidget *widget, gpointer data)
{
  direction = RIGHT;

  start_rotation ();
}

void
go_back (GtkWidget *widget, gpointer data)
{
  direction = BACK;

  start_translation ();
}

void
go_forward (GtkWidget *widget, gpointer data)
{
  direction = FORWARD;

  start_translation ();
}

void
go_center (GtkWidget *widget, gpointer data)
{
  angle = 0.0f;
  offset = 0.0f;

  update ();
}

/* dibujar un plano */
void
draw_cover (float offset, float angle, float near, gboolean animate)
{
    glPushMatrix ();
    glTranslatef (offset, 0.0f, near);
    glRotatef (angle, 0, 1, 0);
    if (animate)
      transform_rotation ();
    glBegin (GL_QUADS);
    glTexCoord2i (width, height);
    glVertex2f (0.5f, -0.5f);
    glTexCoord2i (width, -0.5f);
    glVertex2f (0.5f, 0.5f);
    glTexCoord2i (-0.5f, -0.5f);
    glVertex2f (-0.5f, 0.5f);
    glTexCoord2i (-0.5f, height);
    glVertex2f (-0.5f, -0.5f);
    glEnd ();
    glPopMatrix ();
}

/* dibujar una pila de planos */
void
draw_covers_stack (void)
{
  float x;
  int i;

  glPushMatrix ();

  transform_translation ();

  for (x = 1.0f; x > 0.2f; x -= 0.1f)
    draw_cover (x, -45.0f, 0.0f, FALSE);

  for (x = -1.0f; x < -0.2f; x += 0.1f)
    draw_cover (x, 45.0f, 0.0f, FALSE);

  draw_cover (0.0f, 0.0f, 0.25f, TRUE);

  glPopMatrix ();
}

void
draw(void)
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glPushMatrix();
  glTranslatef(0.0f, -0.45f, 0.0f);
  glPushMatrix();
  /* dibujar la reflección */
  glScalef(1.0, -1.0, 1.0);
  glTranslatef(0.0f, 1.05f, 0.0f);
  //glEnable(GL_NORMALIZE);
  //glCullFace(GL_FRONT);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glColor4f(1.0, 1.0, 1.0, 0.40);
  draw_covers_stack ();
  glDisable(GL_BLEND);
  //glDisable(GL_NORMALIZE);
  //glCullFace(GL_BACK);
  glPopMatrix();
  /* dibujar */
  draw_covers_stack ();
  glPopMatrix();
}

/* barra de control de desplazamiento */
GtkWidget *
build_translation_control (void)
{
  GtkWidget *box;
  GtkWidget *button;
  GtkWidget *label;

  box = gtk_hbox_new (TRUE, 0);

  if (!box)
    g_assert_not_reached ();

  label = gtk_label_new ("<b>Desplazamiento</b>");

  if (!label)
    g_assert_not_reached ();

  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
  gtk_container_add (GTK_CONTAINER (box), label);
  gtk_widget_show (label);

  button = gtk_button_new_with_label ("Izquierda");

  if (!button)
    g_assert_not_reached ();

  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (go_back), NULL);

  gtk_container_add (GTK_CONTAINER (box), button);
  gtk_widget_show (button);

  button = gtk_button_new_with_label ("Centro");

  if (!button)
    g_assert_not_reached ();

  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (go_center), NULL);

  gtk_container_add (GTK_CONTAINER (box), button);
  gtk_widget_show (button);

  button = gtk_button_new_with_label ("Derecha");

  if (!button)
    g_assert_not_reached ();

  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (go_forward), NULL);

  gtk_container_add (GTK_CONTAINER (box), button);
  gtk_widget_show (button);

  return box;
}

/* barra de control de rotación */
GtkWidget *
build_rotation_control (void)
{
  GtkWidget *box;
  GtkWidget *button;
  GtkWidget *label;

  box = gtk_hbox_new (TRUE, 0);

  if (!box)
    g_assert_not_reached ();

  label = gtk_label_new ("<b>Rotación</b>");

  if (!label)
    g_assert_not_reached ();

  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
  gtk_container_add (GTK_CONTAINER (box), label);
  gtk_widget_show (label);

  button = gtk_button_new_with_label ("Izquierda");

  if (!button)
    g_assert_not_reached ();

  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (go_left), NULL);

  gtk_container_add (GTK_CONTAINER (box), button);
  gtk_widget_show (button);

  button = gtk_button_new_with_label ("Centro");

  if (!button)
    g_assert_not_reached ();

  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (go_center), NULL);

  gtk_container_add (GTK_CONTAINER (box), button);
  gtk_widget_show (button);

  button = gtk_button_new_with_label ("Derecha");

  if (!button)
    g_assert_not_reached ();

  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (go_right), NULL);

  gtk_container_add (GTK_CONTAINER (box), button);
  gtk_widget_show (button);

  return box;
}

/* barra de control */
GtkWidget *
build_control (void)
{
  GtkWidget *box;
  GtkWidget *control;

  box = gtk_vbox_new (FALSE, 0);

  if (!box)
    g_assert_not_reached ();

  control = build_rotation_control ();

  if (!control)
    g_assert_not_reached ();

  gtk_container_add (GTK_CONTAINER (box), control);
  gtk_widget_show (control);

  control = build_translation_control ();

  if (!control)
    g_assert_not_reached ();

  gtk_container_add (GTK_CONTAINER (box), control);
  gtk_widget_show (control);

  return box;
}

/* manejadores de señales */

gboolean
delete (GtkWidget *widget, GdkEvent *event, gpointer data)
{
  glDeleteTextures (1, &texture);
  gtk_main_quit ();
  return TRUE;
}

void
realize (GtkWidget *widget, gpointer data)
{
  //GLfloat light[4];
  GdkGLContext *gl_context;
  GdkGLDrawable *gl_drawable;
  gboolean can_begin;

  gl_context = gtk_widget_get_gl_context (widget);
  gl_drawable = gtk_widget_get_gl_drawable (widget);
  can_begin = gdk_gl_drawable_gl_begin (gl_drawable, gl_context);

  //light[0] = 1.0f;
  //light[1] = 1.0f;
  //light[2] = 1.0f;
  //light[3] = 1.0f;

  if (!can_begin)
    g_assert_not_reached ();

  glEnable (GL_TEXTURE_RECTANGLE_ARB);
  //glEnable (GL_LIGHTING);
  glEnable (GL_LIGHT0);
  glEnable (GL_LIGHT1);
  //glLightfv (GL_LIGHT0, GL_DIFFUSE, light);

  glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  gdk_gl_drawable_gl_end (gl_drawable);
}

gboolean
configure (GtkWidget *widget, GdkEventConfigure *event, gpointer data)
{
  GdkGLContext *gl_context;
  GdkGLDrawable *gl_drawable;
  GLsizei width;
  GLsizei height;
  gboolean can_begin;

  gl_context = gtk_widget_get_gl_context (widget);
  gl_drawable = gtk_widget_get_gl_drawable (widget);
  width = widget->allocation.width;
  height = widget->allocation.height;
  can_begin = gdk_gl_drawable_gl_begin (gl_drawable, gl_context);

  if (!can_begin)
    g_assert_not_reached ();

  glViewport (0, 0, width, height);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  perspective (60.0f, (GLfloat) width / (GLfloat) height, 1.0f, 5.0f);
  glMatrixMode (GL_MODELVIEW);
  glLoadIdentity ();
  glTranslatef (0.0f, 0.25f, -2.0f);
  glGenTextures (1, &texture);

  /*
  glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
  glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, surface_data[0]);
  */

  gdk_gl_drawable_gl_end (gl_drawable);

  return TRUE;
}

gboolean
expose (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
  GdkGLContext *gl_context;
  GdkGLDrawable *gl_drawable;
  gboolean can_begin;
  gboolean is_double_buffered;

  gl_context = gtk_widget_get_gl_context (widget);
  gl_drawable = gtk_widget_get_gl_drawable (widget);
  is_double_buffered = gdk_gl_drawable_is_double_buffered (gl_drawable);
  can_begin = gdk_gl_drawable_gl_begin (gl_drawable, gl_context);

  if (!can_begin)
    g_assert_not_reached ();

  glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
  glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, surface_data[0]);
  draw ();

  if (is_double_buffered)
    gdk_gl_drawable_swap_buffers (gl_drawable);
  else
    glFlush ();

  gdk_gl_drawable_gl_end (gl_drawable);

  return TRUE;
}

/* inicio */
int
main (int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *box;
  GtkWidget *label;
  GtkWidget *control;
  GdkGLConfig *gl_config;
  cairo_surface_t *surface;
  cairo_t *context;
  gboolean gl_capability;

  gtk_init (&argc, &argv);
  gtk_gl_init (&argc, &argv);

  gl_config = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB | GDK_GL_MODE_ALPHA | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE);

  if (!gl_config)
    g_assert_not_reached ();

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

  if (!window)
    g_assert_not_reached ();

  gtk_window_set_title (GTK_WINDOW (window), "Desplazamiento de planos animado");

  gtk_widget_add_events (window, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);

  g_signal_connect (G_OBJECT (window), "delete-event", G_CALLBACK (delete), NULL);

  box = gtk_vbox_new (FALSE, 0);

  if (!box)
    g_assert_not_reached ();

  gtk_container_add (GTK_CONTAINER (window), box);
  gtk_widget_show (box);

  label = gtk_label_new ("<span size='18000' weight='heavy'>Desplazamiento de planos animado</span>");

  if (!label)
    g_assert_not_reached ();

  gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
  gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
  gtk_widget_show (label);

  drawing_area = gtk_drawing_area_new ();

  if (!drawing_area)
    g_assert_not_reached ();

  gtk_container_add (GTK_CONTAINER (box), drawing_area);
  gtk_widget_show (drawing_area);

  control = build_control ();

  if (!control)
    g_assert_not_reached ();

  gtk_box_pack_start (GTK_BOX (box), control, FALSE, FALSE, 0);
  gtk_widget_show (control);

  /* cargar la imagen en un contexto Cairo y obtener los bytes para usar como textura de los planos */
  surface = cairo_image_surface_create_from_png (IMAGE);

  if (!surface)
    g_assert_not_reached ();

  width = cairo_image_surface_get_width (surface);
  height = cairo_image_surface_get_height (surface);

  gtk_widget_set_size_request (drawing_area, width, height);
  gl_capability = gtk_widget_set_gl_capability (drawing_area, gl_config, NULL, TRUE, GDK_GL_RGBA_TYPE);

  if (!gl_capability)
    g_assert_not_reached ();

  g_signal_connect_after (G_OBJECT (drawing_area), "realize", G_CALLBACK (realize), NULL);
  g_signal_connect (G_OBJECT (drawing_area), "configure-event", G_CALLBACK (configure), NULL);
  g_signal_connect (G_OBJECT (drawing_area), "expose-event", G_CALLBACK (expose), NULL);

  gtk_widget_set_app_paintable (window, TRUE);
  gtk_widget_realize (window);
  gdk_window_set_back_pixmap (window->window, NULL, FALSE);
  gtk_widget_show (window);

  surface_data[0] = g_malloc0 (4 * width * height);

  if (!surface_data[0])
    g_assert_not_reached ();

  context = cairo_create (surface);

  if (!context)
    g_assert_not_reached ();

  surface_data[0] = cairo_image_surface_get_data (surface);

  if (!context)
    g_assert_not_reached ();

  gtk_main ();

  if (surface_data[0])
    g_free (surface_data[0]);

  return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值