Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gimp/plug-ins/lighting/   (Gimp Bildeditor Version 3.2.0©)  Datei vom 14.2.2026 mit Größe 13 kB image not shown  

Quelle  lighting-preview.c   Sprache: C

 

/*************************************************/
/* Compute a preview image and preview wireframe */
/*************************************************/

#include "config.h"

#include <gtk/gtk.h>

#include <libgimp/gimp.h>
#include <libgimpmath/gimpmath.h>

#include "lighting-main.h"
#include "lighting-ui.h"
#include "lighting-image.h"
#include "lighting-apply.h"
#include "lighting-shade.h"

#include "lighting-preview.h"


#define LIGHT_SYMBOL_SIZE 8

static gint handle_xpos = 0, handle_ypos = 0;

/* g_free()'ed on exit */
gdouble *xpostab = NULL;
gdouble *ypostab = NULL;

static gint xpostab_size = -1;  /* if preview size change, do realloc */
static gint ypostab_size = -1;

static gboolean    light_hit           = FALSE;
static gboolean    left_button_pressed = FALSE;
static guint preview_update_timer = 0;


/* Protos */
/* ====== */
static gboolean  interactive_preview_timer_callback  (gpointer data);

void             composite_behind                    (gdouble *color1,
                                                      gdouble *color2);

static void
compute_preview (gint startx,
                 gint starty,
                 gint w,
                 gint h)
{
  gint xcnt, ycnt, f1, f2;
  guchar r, g, b;
  gdouble imagex, imagey;
  gint32 index = 0;
  gdouble color[4];
  gdouble lightcheck[4] = { GIMP_CHECK_LIGHT,  GIMP_CHECK_LIGHT, GIMP_CHECK_LIGHT, 1.0 };
  gdouble darkcheck[4]  = { GIMP_CHECK_DARK,  GIMP_CHECK_DARK, GIMP_CHECK_DARK, 1.0 };
  GimpVector3 pos;
  get_ray_func ray_func;

  if (xpostab_size != w)
    {
      if (xpostab)
        {
          g_free (xpostab);
          xpostab = NULL;
        }
    }

  if (!xpostab)
    {
      xpostab = g_new (gdouble, w);
      xpostab_size = w;
    }

  if (ypostab_size != h)
    {
      if (ypostab)
        {
          g_free (ypostab);
          ypostab = NULL;
        }
    }

  if (!ypostab)
    {
      ypostab = g_new (gdouble, h);
      ypostab_size = h;
    }

  for (xcnt = 0; xcnt < w; xcnt++)
    xpostab[xcnt] = (gdouble) width *((gdouble) xcnt / (gdouble) w);
  for (ycnt = 0; ycnt < h; ycnt++)
    ypostab[ycnt] = (gdouble) height *((gdouble) ycnt / (gdouble) h);

  precompute_init (width, height);

  if (mapvals.bump_mapped == TRUE && mapvals.bumpmap_id != -1)
    {
      bumpmap_setup (gimp_drawable_get_by_id (mapvals.bumpmap_id));
    }

  imagey = 0;

  if (mapvals.previewquality)
    ray_func = get_ray_color;
  else
    ray_func = get_ray_color_no_bilinear;

  if (mapvals.env_mapped == TRUE && mapvals.envmap_id != -1)
    {
      envmap_setup (gimp_drawable_get_by_id (mapvals.envmap_id));

      if (mapvals.previewquality)
        ray_func = get_ray_color_ref;
      else
        ray_func = get_ray_color_no_bilinear_ref;
    }

  cairo_surface_flush (preview_surface);

  for (ycnt = 0; ycnt < PREVIEW_HEIGHT; ycnt++)
    {
      index = ycnt * preview_rgb_stride;
      for (xcnt = 0; xcnt < PREVIEW_WIDTH; xcnt++)
        {
          if ((ycnt >= starty && ycnt < (starty + h)) &&
              (xcnt >= startx && xcnt < (startx + w)))
            {
              imagex = xpostab[xcnt - startx];
              imagey = ypostab[ycnt - starty];
              pos = int_to_posf (imagex, imagey);

              if (mapvals.bump_mapped == TRUE &&
                  mapvals.bumpmap_id != -1 &&
                  xcnt == startx)
                {
                  pos_to_float (pos.x, pos.y, &imagex, &imagey);
                  precompute_normals (0, width, RINT (imagey));
                }

              (*ray_func) (&pos, color);

              if (color[3] < 1.0)
                {
                  f1 = ((xcnt % 32) < 16);
                  f2 = ((ycnt % 32) < 16);
                  f1 = f1 ^ f2;

                  if (f1)
                    {
                      if (color[3] == 0.0)
                        {
                          for (gint i = 0; i < 4; i++)
                            color[i] = lightcheck[i];
                        }
                      else
                        {
                          composite_behind (color, lightcheck);
                        }
                    }
                  else
                    {
                      if (color[3] == 0.0)
                        {
                          for (gint i = 0; i < 4; i++)
                            color[i] = darkcheck[i];
                        }
                      else
                        {
                          composite_behind (color, darkcheck);
                        }
                    }
                }

              r = (guchar) (color[0] * 255);
              g = (guchar) (color[1] * 255);
              b = (guchar) (color[2] * 255);
              GIMP_CAIRO_RGB24_SET_PIXEL((preview_rgb_data + index), r, g, b);
              index += 4;
              imagex++;
            }
          else
            {
              preview_rgb_data[index++] = 200;
              preview_rgb_data[index++] = 200;
              preview_rgb_data[index++] = 200;
              index++;
            }
        }
    }
  cairo_surface_mark_dirty (preview_surface);
}

static void
compute_preview_rectangle (gint * xp, gint * yp, gint * wid, gint * heig)
{
  gdouble x, y, w, h;

  if (width >= height)
    {
      w = (PREVIEW_WIDTH - 50.0);
      h = (gdouble) height *(w / (gdouble) width);

      x = (PREVIEW_WIDTH - w) / 2.0;
      y = (PREVIEW_HEIGHT - h) / 2.0;
    }
  else
    {
      h = (PREVIEW_HEIGHT - 50.0);
      w = (gdouble) width *(h / (gdouble) height);
      x = (PREVIEW_WIDTH - w) / 2.0;
      y = (PREVIEW_HEIGHT - h) / 2.0;
    }
  *xp = RINT (x);
  *yp = RINT (y);
  *wid = RINT (w);
  *heig = RINT (h);
}

/*************************************************/
/* Check if the given position is within the     */
/* light marker. Return TRUE if so, FALSE if not */
/*************************************************/

static gboolean
check_handle_hit (gint xpos, gint ypos)
{
  gint dx,dy,r;
  gint k = mapvals.light_selected;

  dx = handle_xpos - xpos;
  dy = handle_ypos - ypos;


  if (mapvals.lightsource[k].type == POINT_LIGHT ||
      mapvals.lightsource[k].type == DIRECTIONAL_LIGHT)
    {
      r = sqrt (dx * dx + dy * dy) + 0.5;
      if ((gint) r > 7)
        {
          return (FALSE);
        }
      else
        {
          return (TRUE);
        }
    }
  return FALSE;
}

/****************************************/
/* Draw a light symbol                  */
/****************************************/


static void
draw_handles (cairo_t *cr)
{
  gdouble     dxpos, dypos;
  gint        startx, starty, pw, ph;
  GimpVector3 viewpoint;
  GimpVector3 light_position;
  gint        k      = mapvals.light_selected;

  gfloat length;
  gfloat delta_x = 0.0;
  gfloat delta_y = 0.0;

  /* calculate handle position */
  compute_preview_rectangle (&startx, &starty, &pw, &ph);
  switch (mapvals.lightsource[k].type)
    {
    case NO_LIGHT:
      return;
    case POINT_LIGHT:
    case SPOT_LIGHT:
      /* swap z to reverse light position */
      viewpoint = mapvals.viewpoint;
      viewpoint.z = -viewpoint.z;
      light_position = mapvals.lightsource[k].position;
      gimp_vector_3d_to_2d (startx, starty, pw, ph, &dxpos, &dypos,
                            &viewpoint, &light_position);
      handle_xpos = (gint) (dxpos + 0.5);
      handle_ypos = (gint) (dypos + 0.5);
      break;
    case DIRECTIONAL_LIGHT:
      light_position.x = light_position.y = 0.5;
      light_position.z = 0;
      viewpoint.z = -viewpoint.z;
      gimp_vector_3d_to_2d (startx, starty, pw, ph, &dxpos, &dypos,
                            &viewpoint, &light_position);
      length = PREVIEW_HEIGHT / 4;
      delta_x = mapvals.lightsource[k].direction.x * length;
      delta_y = mapvals.lightsource[k].direction.y * length;
      handle_xpos = dxpos + delta_x;
      handle_ypos = dypos + delta_y;
      break;
    }

  if (mapvals.lightsource[k].type != NO_LIGHT)
    {
      GdkRGBA  color;

      cairo_set_line_width (cr, 1.0);

      color.red   = 0.0;
      color.green = 0.2;
      color.blue  = 1.0;
      color.alpha = 1.0;
      gdk_cairo_set_source_rgba (cr, &color);

      /* draw circle at light position */
      switch (mapvals.lightsource[k].type)
        {
        case POINT_LIGHT:
        case SPOT_LIGHT:
          cairo_arc (cr, handle_xpos, handle_ypos,
                     LIGHT_SYMBOL_SIZE/2, 0, 2 * G_PI);
          cairo_fill (cr);
          break;
        case DIRECTIONAL_LIGHT:
          cairo_arc (cr, handle_xpos, handle_ypos,
                     LIGHT_SYMBOL_SIZE/2, 0, 2 * G_PI);
          cairo_fill (cr);
          cairo_move_to (cr, handle_xpos, handle_ypos);
          cairo_line_to (cr, startx + pw/2, starty + ph/2);
          cairo_stroke (cr);
          break;
        case NO_LIGHT:
          break;
        }
    }
}


/*************************************************/
/* Update light position given new screen coords */
/*************************************************/

void
update_light (gint xpos, gint ypos)
{
  gint startx, starty, pw, ph;
  GimpVector3  vp;
  gint         k = mapvals.light_selected;

  compute_preview_rectangle (&startx, &starty, &pw, &ph);

  vp = mapvals.viewpoint;
  vp.z = -vp.z;

  switch (mapvals.lightsource[k].type)
    {
    case        NO_LIGHT:
      break;
    case        POINT_LIGHT:
    case        SPOT_LIGHT:
      gimp_vector_2d_to_3d (startx,
                            starty,
                            pw,
                            ph,
                            xpos, ypos, &vp, &mapvals.lightsource[k].position);
      break;
    case DIRECTIONAL_LIGHT:
      gimp_vector_2d_to_3d (startx,
                            starty,
                            pw,
                            ph,
                            xpos, ypos, &vp, &mapvals.lightsource[k].direction);
      break;
    }
}


/******************************************************************/
/* Draw preview image. if DoCompute is TRUE then recompute image. */
/******************************************************************/

void
preview_compute (void)
{
  GdkDisplay *display = gtk_widget_get_display (previewarea);
  GdkCursor  *cursor;
  gint        startx, starty, pw, ph;

  compute_preview_rectangle (&startx, &starty, &pw, &ph);

  if (GDK_IS_WINDOW (gtk_widget_get_window (previewarea)))
    {
      cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
      gdk_window_set_cursor (gtk_widget_get_window (previewarea), cursor);
      g_object_unref (cursor);

      compute_preview (startx, starty, pw, ph);
      cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
      gdk_window_set_cursor (gtk_widget_get_window (previewarea), cursor);
      g_object_unref (cursor);
      gdk_display_flush (display);
    }
}


/******************************/
/* Preview area event handler */
/******************************/

gboolean
preview_events (GtkWidget *area,
                GdkEvent  *event)
{
  switch (event->type)
    {
    case GDK_ENTER_NOTIFY:
      break;
    case GDK_LEAVE_NOTIFY:
      break;
    case GDK_BUTTON_PRESS:
      light_hit = check_handle_hit (event->button.x, event->button.y);
      left_button_pressed = TRUE;
      break;
    case GDK_BUTTON_RELEASE:
      left_button_pressed = FALSE;
      break;
    case GDK_MOTION_NOTIFY:
      if (left_button_pressed == TRUE &&
          light_hit == TRUE &&
          mapvals.interactive_preview == TRUE )
        {
          gtk_widget_queue_draw (previewarea);
          interactive_preview_callback(NULL);
          update_light (event->motion.x, event->motion.y);
        }
      break;
    default:
      break;
    }

  return FALSE;
}

gboolean
preview_draw (GtkWidget *area,
              cairo_t   *cr)
{
  cairo_set_source_surface (cr, preview_surface, 0.0, 0.0);

  cairo_paint (cr);

  /* draw symbols if enabled in UI */
  if (mapvals.interactive_preview)
    {
      draw_handles (cr);
    }

  return FALSE;
}

void
interactive_preview_callback (GtkWidget *widget)
{
  if (preview_update_timer != 0)
    g_source_remove (preview_update_timer);

  preview_update_timer = g_timeout_add (100,
                                        interactive_preview_timer_callback,
                                        NULL);
}

static gboolean
interactive_preview_timer_callback (gpointer data)
{
  gint   k     = mapvals.light_selected;
  gchar *pos_x = g_strdup_printf (("light-position-x-%d"), k + 1);
  gchar *pos_y = g_strdup_printf (("light-position-y-%d"), k + 1);
  gchar *pos_z = g_strdup_printf (("light-position-z-%d"), k + 1);
  gchar *dir_x = g_strdup_printf (("light-direction-x-%d"), k + 1);
  gchar *dir_y = g_strdup_printf (("light-direction-y-%d"), k + 1);
  gchar *dir_z = g_strdup_printf (("light-direction-z-%d"), k + 1);

  mapvals.update_enabled = FALSE;  /* disable apply_settings() */

  g_object_set (mapvals.config,
                pos_x, mapvals.lightsource[k].position.x,
                pos_y, mapvals.lightsource[k].position.y,
                pos_z, mapvals.lightsource[k].position.z,
                dir_x, mapvals.lightsource[k].direction.x,
                dir_y, mapvals.lightsource[k].direction.y,
                dir_z, mapvals.lightsource[k].direction.z,
                NULL);

  g_free (pos_x);
  g_free (pos_y);
  g_free (pos_z);
  g_free (dir_x);
  g_free (dir_y);
  g_free (dir_z);

  mapvals.update_enabled = TRUE;

  preview_compute ();

  gtk_widget_queue_draw (previewarea);

  preview_update_timer = 0;

  return FALSE;
}

void
composite_behind (gdouble *color1,
                  gdouble *color2)
{
  g_return_if_fail (color1 != NULL);
  g_return_if_fail (color2 != NULL);

  if (color1[3] < 1.0)
    {
      gdouble factor = color2[3] * (1.0 - color1[3]);

      color1[0] = color2[0] * factor + color1[0] * color1[3];
      color1[1] = color2[1] * factor + color1[1] * color1[3];
      color1[2] = color2[2] * factor + color1[2] * color1[3];
      color1[3] = factor + color1[3];
    }
}

Messung
CHZG
829810093

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.