Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

39
plug-ins/lighting/README Normal file
View File

@ -0,0 +1,39 @@
Lighting Effects 0.2.2 -- image filter plug-in for PIKA
===================================================================
Copyright (C) 1996-98 Tom Bech
Copyright (C) 1996-98 Federico Mena Quintero
You can reach the author(s) via E-mail:
tomb@gimp.org (Tom) or quartic@gimp.org (Federico).
PIKA was developed by Peter Mattis and Spencer Kimball.
You can contact them at pika@xcf.berkeley.edu.
There's more PIKA stuff on our home pages:
http://www.ii.uib.no/~tomb/pika.html (Tom's page)
http://www.nuclecu.unam.mx/~federico/pika/index.html (Quartic's page)
Legal stuff
===========
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
In other words, you can't sue us for whatever happens while using this ;)
Have fun,
Tom

15
plug-ins/lighting/TODO Normal file
View File

@ -0,0 +1,15 @@
The lighting plug-in "todo"-list:
=================================
* Supersampling/antialiasing
* Bilinear filtering of environment map
* Refraction back in?
* Support for any-sized non-gray bump-maps.
* Support for gray or alpha-channeled env-maps.
* Zooming and scrolling in preview window
* Autoconf/automake stuff
* Put spotlight back in
* Nicer interactive UI
* Presets
* Multiple light sources

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/technology.heckin/lighting/icons">
<file preprocess="to-pixdata">lighting-intensity-ambient-high.png</file>
<file preprocess="to-pixdata">lighting-intensity-ambient-low.png</file>
<file preprocess="to-pixdata">lighting-intensity-diffuse-high.png</file>
<file preprocess="to-pixdata">lighting-intensity-diffuse-low.png</file>
<file preprocess="to-pixdata">lighting-reflectivity-diffuse-high.png</file>
<file preprocess="to-pixdata">lighting-reflectivity-diffuse-low.png</file>
<file preprocess="to-pixdata">lighting-reflectivity-specular-high.png</file>
<file preprocess="to-pixdata">lighting-reflectivity-specular-low.png</file>
<file preprocess="to-pixdata">lighting-reflectivity-highlight-high.png</file>
<file preprocess="to-pixdata">lighting-reflectivity-highlight-low.png</file>
</gresource>
</gresources>

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 842 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

View File

@ -0,0 +1,18 @@
stock_icons = [
'lighting-intensity-ambient-high.png',
'lighting-intensity-ambient-low.png',
'lighting-intensity-diffuse-high.png',
'lighting-intensity-diffuse-low.png',
'lighting-reflectivity-diffuse-high.png',
'lighting-reflectivity-diffuse-low.png',
'lighting-reflectivity-highlight-high.png',
'lighting-reflectivity-highlight-low.png',
'lighting-reflectivity-specular-high.png',
'lighting-reflectivity-specular-low.png',
]
lighting_icon_sources = gnome.compile_resources(
'lighting-icon-images',
'lighting-icon-images.gresource.xml',
# source_dir: meson.current_source_directory(),
)

View File

@ -0,0 +1,153 @@
/******************************************************/
/* Apply mapping and shading on the whole input image */
/******************************************************/
#include "config.h"
#include <sys/types.h>
#include <libpika/pika.h>
#include "lighting-main.h"
#include "lighting-image.h"
#include "lighting-shade.h"
#include "lighting-apply.h"
#include "libpika/stdplugins-intl.h"
/*************/
/* Main loop */
/*************/
void
compute_image (void)
{
gint xcount, ycount;
PikaRGB color;
glong progress_counter = 0;
PikaVector3 p;
PikaImage *new_image = NULL;
PikaLayer *new_layer = NULL;
gint32 index;
guchar *row = NULL;
guchar obpp;
gboolean has_alpha;
get_ray_func ray_func;
if (mapvals.create_new_image == TRUE ||
(mapvals.transparent_background == TRUE &&
! pika_drawable_has_alpha (input_drawable)))
{
/* Create a new image */
/* ================== */
new_image = pika_image_new (width, height, PIKA_RGB);
if (mapvals.transparent_background == TRUE)
{
/* Add a layer with an alpha channel */
/* ================================= */
new_layer = pika_layer_new (new_image, "Background",
width, height,
PIKA_RGBA_IMAGE,
100.0,
pika_image_get_default_new_layer_mode (new_image));
}
else
{
/* Create a "normal" layer */
/* ======================= */
new_layer = pika_layer_new (new_image, "Background",
width, height,
PIKA_RGB_IMAGE,
100.0,
pika_image_get_default_new_layer_mode (new_image));
}
pika_image_insert_layer (new_image, new_layer, NULL, 0);
output_drawable = PIKA_DRAWABLE (new_layer);
}
if (mapvals.bump_mapped == TRUE && mapvals.bumpmap_id != -1)
{
bumpmap_setup (pika_drawable_get_by_id (mapvals.bumpmap_id));
}
precompute_init (width, height);
if (! mapvals.env_mapped || mapvals.envmap_id == -1)
{
ray_func = get_ray_color;
}
else
{
envmap_setup (pika_drawable_get_by_id (mapvals.envmap_id));
ray_func = get_ray_color_ref;
}
dest_buffer = pika_drawable_get_shadow_buffer (output_drawable);
has_alpha = pika_drawable_has_alpha (output_drawable);
/* FIXME */
obpp = has_alpha ? 4 : 3; //pika_drawable_get_bpp (output_drawable);
row = g_new (guchar, obpp * width);
pika_progress_init (_("Lighting Effects"));
/* Init the first row */
if (mapvals.bump_mapped == TRUE && mapvals.bumpmap_id != -1 && height >= 2)
interpol_row (0, width, 0);
for (ycount = 0; ycount < height; ycount++)
{
if (mapvals.bump_mapped == TRUE && mapvals.bumpmap_id != -1)
precompute_normals (0, width, ycount);
index = 0;
for (xcount = 0; xcount < width; xcount++)
{
p = int_to_pos (xcount, ycount);
color = (* ray_func) (&p);
row[index++] = (guchar) (color.r * 255.0);
row[index++] = (guchar) (color.g * 255.0);
row[index++] = (guchar) (color.b * 255.0);
if (has_alpha)
row[index++] = (guchar) (color.a * 255.0);
progress_counter++;
}
pika_progress_update ((gdouble) progress_counter /
(gdouble) maxcounter);
gegl_buffer_set (dest_buffer, GEGL_RECTANGLE (0, ycount, width, 1), 0,
has_alpha ?
babl_format ("R'G'B'A u8") : babl_format ("R'G'B' u8"),
row,
GEGL_AUTO_ROWSTRIDE);
}
pika_progress_update (1.0);
g_free (row);
g_object_unref (dest_buffer);
pika_drawable_merge_shadow (output_drawable, TRUE);
pika_drawable_update (output_drawable, 0, 0, width, height);
if (new_image)
{
pika_display_new (new_image);
pika_displays_flush ();
}
}

View File

@ -0,0 +1,7 @@
#ifndef __LIGHTING_APPLY_H__
#define __LIGHTING_APPLY_H__
void init_compute (void);
void compute_image (void);
#endif /* __LIGHTING_APPLY_H__ */

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "lighting-icons.h"
#include "images/lighting-icon-images.h"
void
lighting_icons_init (void)
{
static gboolean initialized = FALSE;
GtkIconTheme *icon_theme;
if (initialized)
return;
initialized = TRUE;
icon_theme = gtk_icon_theme_get_default ();
gtk_icon_theme_add_resource_path (icon_theme, "/technology.heckin/lighting/icons");
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __LIGHTING_ICONS_H__
#define __LIGHTING_ICONS_H__
#define LIGHTING_INTENSITY_AMBIENT_LOW "lighting-intensity-ambient-low"
#define LIGHTING_INTENSITY_AMBIENT_HIGH "lighting-intensity-ambient-high"
#define LIGHTING_INTENSITY_DIFFUSE_LOW "lighting-intensity-diffuse-low"
#define LIGHTING_INTENSITY_DIFFUSE_HIGH "lighting-intensity-diffuse-high"
#define LIGHTING_REFLECTIVITY_DIFFUSE_LOW "lighting-reflectivity-diffuse-low"
#define LIGHTING_REFLECTIVITY_DIFFUSE_HIGH "lighting-reflectivity-diffuse-high"
#define LIGHTING_REFLECTIVITY_SPECULAR_LOW "lighting-reflectivity-specular-low"
#define LIGHTING_REFLECTIVITY_SPECULAR_HIGH "lighting-reflectivity-specular-high"
#define LIGHTING_REFLECTIVITY_HIGHLIGHT_LOW "lighting-reflectivity-highlight-low"
#define LIGHTING_REFLECTIVITY_HIGHLIGHT_HIGH "lighting-reflectivity-highlight-high"
void lighting_icons_init (void);
#endif /* __LIGHTING_ICONs_H__ */

View File

@ -0,0 +1,410 @@
/*************************************/
/* PIKA image manipulation routines. */
/*************************************/
#include "config.h"
#include <gtk/gtk.h>
#include <libpika/pika.h>
#include "lighting-main.h"
#include "lighting-image.h"
#include "lighting-preview.h"
#include "lighting-ui.h"
PikaDrawable *input_drawable;
PikaDrawable *output_drawable;
GeglBuffer *source_buffer;
GeglBuffer *dest_buffer;
PikaDrawable *bump_drawable;
GeglBuffer *bump_buffer;
const Babl *bump_format;
PikaDrawable *env_drawable;
GeglBuffer *env_buffer;
guchar *preview_rgb_data = NULL;
gint preview_rgb_stride;
cairo_surface_t *preview_surface = NULL;
glong maxcounter;
gint width, height;
gint env_width, env_height;
PikaRGB background;
gint border_x1, border_y1, border_x2, border_y2;
guchar sinemap[256], spheremap[256], logmap[256];
/******************/
/* Implementation */
/******************/
guchar
peek_map (GeglBuffer *buffer,
const Babl *format,
gint x,
gint y)
{
guchar data[4];
guchar ret_val;
gegl_buffer_sample (buffer, x, y, NULL, data, format,
GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
if (babl_format_get_bytes_per_pixel (format))
{
ret_val = data[0];
}
else
{
ret_val = (guchar)((float)((data[0] + data[1] + data[2])/3.0));
}
return ret_val;
}
PikaRGB
peek (gint x,
gint y)
{
PikaRGB color;
gegl_buffer_sample (source_buffer, x, y, NULL,
&color, babl_format ("R'G'B'A double"),
GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
if (! babl_format_has_alpha (gegl_buffer_get_format (source_buffer)))
color.a = 1.0;
return color;
}
PikaRGB
peek_env_map (gint x,
gint y)
{
PikaRGB color;
if (x < 0)
x = 0;
else if (x >= env_width)
x = env_width - 1;
if (y < 0)
y = 0;
else if (y >= env_height)
y = env_height - 1;
gegl_buffer_sample (env_buffer, x, y, NULL,
&color, babl_format ("R'G'B'A double"),
GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
color.a = 1.0;
return color;
}
void
poke (gint x,
gint y,
PikaRGB *color)
{
if (x < 0)
x = 0;
else if (x >= width)
x = width - 1;
if (y < 0)
y = 0;
else if (y >= height)
y = height - 1;
gegl_buffer_set (dest_buffer, GEGL_RECTANGLE (x, y, 1, 1), 0,
babl_format ("R'G'B'A double"), color,
GEGL_AUTO_ROWSTRIDE);
}
gint
check_bounds (gint x,
gint y)
{
if (x < border_x1 ||
y < border_y1 ||
x >= border_x2 ||
y >= border_y2)
return FALSE;
else
return TRUE;
}
PikaVector3
int_to_pos (gint x,
gint y)
{
PikaVector3 pos;
if (width >= height)
{
pos.x = (gdouble) x / (gdouble) width;
pos.y = (gdouble) y / (gdouble) width;
pos.y += 0.5 * (1.0 - (gdouble) height / (gdouble) width);
}
else
{
pos.x = (gdouble) x / (gdouble) height;
pos.y = (gdouble) y / (gdouble) height;
pos.x += 0.5 * (1.0 - (gdouble) width / (gdouble) height);
}
pos.z = 0.0;
return pos;
}
PikaVector3
int_to_posf (gdouble x,
gdouble y)
{
PikaVector3 pos;
if (width >= height)
{
pos.x = x / (gdouble) width;
pos.y = y / (gdouble) width;
pos.y += 0.5 * (1.0 - (gdouble) height / (gdouble) width);
}
else
{
pos.x = x / (gdouble) height;
pos.y = y / (gdouble) height;
pos.x += 0.5 * (1.0 - (gdouble) width / (gdouble) height);
}
pos.z = 0.0;
return pos;
}
void
pos_to_int (gdouble x,
gdouble y,
gint *scr_x,
gint *scr_y)
{
if (width >= height)
{
y -= 0.5 * (1.0 - (gdouble) height / (gdouble) width);
*scr_x = RINT ((x * (gdouble) width));
*scr_y = RINT ((y * (gdouble) width));
}
else
{
x -= 0.5 * (1.0 - (gdouble) width / (gdouble) height);
*scr_x = RINT ((x * (gdouble) height));
*scr_y = RINT ((y *(gdouble) height));
}
}
void
pos_to_float (gdouble x,
gdouble y,
gdouble *xf,
gdouble *yf)
{
if (width >= height)
{
y -= 0.5 * (1.0 - (gdouble) height / (gdouble) width);
*xf = x * (gdouble) (width-1);
*yf = y * (gdouble) (width-1);
}
else
{
x -= 0.5 * (1.0 - (gdouble) width / (gdouble) height);
*xf = x * (gdouble) (height-1);
*yf = y * (gdouble) (height-1);
}
}
/**********************************************/
/* Compute the image color at pos (u,v) using */
/* Quartics bilinear interpolation stuff. */
/**********************************************/
PikaRGB
get_image_color (gdouble u,
gdouble v,
gint *inside)
{
gint x1, y1, x2, y2;
PikaRGB p[4];
x1 = RINT (u);
y1 = RINT (v);
if (check_bounds (x1, y1) == FALSE)
{
*inside = FALSE;
return background;
}
x2 = (x1 + 1);
y2 = (y1 + 1);
if (check_bounds (x2, y2) == FALSE)
{
*inside = TRUE;
return peek (x1, y1);
}
*inside = TRUE;
p[0] = peek (x1, y1);
p[1] = peek (x2, y1);
p[2] = peek (x1, y2);
p[3] = peek (x2, y2);
return pika_bilinear_rgba (u, v, p);
}
gdouble
get_map_value (GeglBuffer *buffer,
const Babl *format,
gdouble u,
gdouble v,
gint *inside)
{
gint x1, y1, x2, y2;
gdouble p[4];
x1 = RINT (u);
y1 = RINT (v);
x2 = (x1 + 1);
y2 = (y1 + 1);
if (check_bounds (x2, y2) == FALSE)
{
*inside = TRUE;
return (gdouble) peek_map (buffer, format, x1, y1);
}
*inside = TRUE;
p[0] = (gdouble) peek_map (buffer, format, x1, y1);
p[1] = (gdouble) peek_map (buffer, format, x2, y1);
p[2] = (gdouble) peek_map (buffer, format, x1, y2);
p[3] = (gdouble) peek_map (buffer, format, x2, y2);
return pika_bilinear (u, v, p);
}
static void
compute_maps (void)
{
gint x;
gdouble val, c, d;
/* Compute Sine, Log and Spherical transfer function maps */
/* ====================================================== */
c = 1.0 / 255.0;
d = 1.15 * 255.0;
for (x = 0; x < 256; x++)
{
sinemap[x] = (guchar) (255.0 * (0.5 * (sin ((G_PI * c * (gdouble) x) -
0.5 * G_PI) +
1.0)));
spheremap[x] = (guchar) (255.0 * (sqrt (sin (G_PI * (gdouble) x /
512.0))));
val = (d * exp (-1.0 / (8.0 * c * ((gdouble) x + 5.0))));
if (val > 255.0)
val = 255.0;
logmap[x] = (guchar) val;
}
}
/****************************************/
/* Allocate memory for temporary images */
/****************************************/
gint
image_setup (PikaDrawable *drawable,
gint interactive)
{
gint w, h;
gboolean ret;
compute_maps ();
/* Get some useful info on the input drawable */
/* ========================================== */
input_drawable = drawable;
output_drawable = drawable;
ret = pika_drawable_mask_intersect (drawable,
&border_x1, &border_y1, &w, &h);
border_x2 = border_x1 + w;
border_y2 = border_y1 + h;
if (! ret)
return FALSE;
width = pika_drawable_get_width (input_drawable);
height = pika_drawable_get_height (input_drawable);
source_buffer = pika_drawable_get_buffer (input_drawable);
maxcounter = (glong) width * (glong) height;
if (interactive)
{
preview_rgb_stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24,
PREVIEW_WIDTH);
preview_rgb_data = g_new0 (guchar, preview_rgb_stride * PREVIEW_HEIGHT);
preview_surface = cairo_image_surface_create_for_data (preview_rgb_data,
CAIRO_FORMAT_RGB24,
PREVIEW_WIDTH,
PREVIEW_HEIGHT,
preview_rgb_stride);
}
return TRUE;
}
void
bumpmap_setup (PikaDrawable *bumpmap)
{
if (bumpmap)
{
if (! bump_buffer)
{
bump_buffer = pika_drawable_get_buffer (bumpmap);
}
if (pika_drawable_is_rgb (bumpmap))
bump_format = babl_format ("R'G'B' u8");
else
bump_format = babl_format ("Y' u8"); /* FIXME */
}
}
void
envmap_setup (PikaDrawable *envmap)
{
if (envmap && ! env_buffer)
{
env_width = pika_drawable_get_width (envmap);
env_height = pika_drawable_get_height (envmap);
env_buffer = pika_drawable_get_buffer (envmap);
}
}

View File

@ -0,0 +1,72 @@
#ifndef __LIGHTING_IMAGE_H__
#define __LIGHTING_IMAGE_H__
#include <libpika/pika.h>
#include <libpika/pikaui.h>
extern PikaDrawable *input_drawable;
extern PikaDrawable *output_drawable;
extern GeglBuffer *source_buffer;
extern GeglBuffer *dest_buffer;
extern PikaDrawable *bump_drawable;
extern GeglBuffer *bump_buffer;
extern const Babl *bump_format;
extern PikaDrawable *env_drawable;
extern GeglBuffer *env_buffer;
extern guchar *preview_rgb_data;
extern gint preview_rgb_stride;
extern cairo_surface_t *preview_surface;
extern glong maxcounter;
extern gint width,height,env_width,env_height;
extern PikaRGB background;
extern gint border_x1, border_y1, border_x2, border_y2;
extern guchar sinemap[256], spheremap[256], logmap[256];
guchar peek_map (GeglBuffer *buffer,
const Babl *format,
gint x,
gint y);
PikaRGB peek (gint x,
gint y);
PikaRGB peek_env_map (gint x,
gint y);
void poke (gint x,
gint y,
PikaRGB *color);
gint check_bounds (gint x,
gint y);
PikaVector3 int_to_pos (gint x,
gint y);
PikaVector3 int_to_posf (gdouble x,
gdouble y);
void pos_to_int (gdouble x,
gdouble y,
gint *scr_x,
gint *scr_y);
void pos_to_float (gdouble x,
gdouble y,
gdouble *xf,
gdouble *yf);
PikaRGB get_image_color (gdouble u,
gdouble v,
gint *inside);
gdouble get_map_value (GeglBuffer *buffer,
const Babl *format,
gdouble u,
gdouble v,
gint *inside);
gint image_setup (PikaDrawable *drawable,
gint interactive);
void bumpmap_setup (PikaDrawable *bumpmap);
void envmap_setup (PikaDrawable *envmap);
#endif /* __LIGHTING_IMAGE_H__ */

View File

@ -0,0 +1,491 @@
/* Lighting Effects 0.2.2 -- image filter plug-in for PIKA
*
* Copyright (C) 1996-98 Tom Bech
* Copyright (C) 1996-98 Federico Mena Quintero
*
* E-mail: tomb@gimp.org (Tom) or quartic@gimp.org (Federico)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include <libpika/pika.h>
#include "lighting-apply.h"
#include "lighting-image.h"
#include "lighting-main.h"
#include "lighting-preview.h"
#include "lighting-shade.h"
#include "lighting-ui.h"
#include "libpika/stdplugins-intl.h"
LightingValues mapvals;
typedef struct _Lighting Lighting;
typedef struct _LightingClass LightingClass;
struct _Lighting
{
PikaPlugIn parent_instance;
};
struct _LightingClass
{
PikaPlugInClass parent_class;
};
#define LIGHTING_TYPE (lighting_get_type ())
#define LIGHTING (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LIGHTING_TYPE, Lighting))
GType lighting_get_type (void) G_GNUC_CONST;
static GList * lighting_query_procedures (PikaPlugIn *plug_in);
static PikaProcedure * lighting_create_procedure (PikaPlugIn *plug_in,
const gchar *name);
static PikaValueArray * lighting_run (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *image,
gint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args,
gpointer run_data);
static void set_default_settings (void);
static void check_drawables (void);
G_DEFINE_TYPE (Lighting, lighting, PIKA_TYPE_PLUG_IN)
PIKA_MAIN (LIGHTING_TYPE)
DEFINE_STD_SET_I18N
static void
lighting_class_init (LightingClass *klass)
{
PikaPlugInClass *plug_in_class = PIKA_PLUG_IN_CLASS (klass);
plug_in_class->query_procedures = lighting_query_procedures;
plug_in_class->create_procedure = lighting_create_procedure;
plug_in_class->set_i18n = STD_SET_I18N;
}
static void
lighting_init (Lighting *lighting)
{
}
static GList *
lighting_query_procedures (PikaPlugIn *plug_in)
{
return g_list_append (NULL, g_strdup (PLUG_IN_PROC));
}
static PikaProcedure *
lighting_create_procedure (PikaPlugIn *plug_in,
const gchar *name)
{
PikaProcedure *procedure = NULL;
if (! strcmp (name, PLUG_IN_PROC))
{
PikaRGB white = { 1.0, 1.0, 1.0, 1.0 };
procedure = pika_image_procedure_new (plug_in, name,
PIKA_PDB_PROC_TYPE_PLUGIN,
lighting_run, NULL, NULL);
pika_procedure_set_image_types (procedure, "RGB*");
pika_procedure_set_sensitivity_mask (procedure,
PIKA_PROCEDURE_SENSITIVE_DRAWABLE);
pika_procedure_set_menu_label (procedure, _("_Lighting Effects..."));
pika_procedure_add_menu_path (procedure,
"<Image>/Filters/Light and Shadow/[Light]");
pika_procedure_set_documentation (procedure,
_("Apply various lighting effects "
"to an image"),
"No help yet",
name);
pika_procedure_set_attribution (procedure,
"Tom Bech & Federico Mena Quintero",
"Tom Bech & Federico Mena Quintero",
"Version 0.2.0, March 15 1998");
PIKA_PROC_ARG_DRAWABLE (procedure, "bump-drawable",
"Bump drawable",
"Bumpmap drawable (set to NULL if disabled)",
TRUE,
G_PARAM_READWRITE);
PIKA_PROC_ARG_DRAWABLE (procedure, "env-drawable",
"Env drawable",
"Environmentmap drawable (set to NULL if disabled",
TRUE,
G_PARAM_READWRITE);
PIKA_PROC_ARG_BOOLEAN (procedure, "do-bumpmap",
"Do bumpmap",
"Enable bumpmapping",
TRUE,
G_PARAM_READWRITE);
PIKA_PROC_ARG_BOOLEAN (procedure, "do-envmap",
"Do envmap",
"Enable envmapping",
TRUE,
G_PARAM_READWRITE);
PIKA_PROC_ARG_INT (procedure, "bumpmap-type",
"Bumpmap type",
"Type of mapping (0=linear, 1=log, 2=sinusoidal, "
"3=spherical)",
0, 2, 0,
G_PARAM_READWRITE);
PIKA_PROC_ARG_INT (procedure, "light-type",
"Light type",
"Type of lightsource (0=point, 1=directional, "
"3=spot, 4=none)",
0 ,4, 0,
G_PARAM_READWRITE);
PIKA_PROC_ARG_RGB (procedure, "light-color",
"Light color",
"Light source color",
TRUE, &white,
G_PARAM_READWRITE);
PIKA_PROC_ARG_DOUBLE (procedure, "light-position-x",
"Light position X",
"Light source position (x,y,z)",
-G_MAXDOUBLE, G_MAXDOUBLE, -1,
G_PARAM_READWRITE);
PIKA_PROC_ARG_DOUBLE (procedure, "light-position-y",
"Light position Y",
"Light source position (x,y,z)",
-G_MAXDOUBLE, G_MAXDOUBLE, -1,
G_PARAM_READWRITE);
PIKA_PROC_ARG_DOUBLE (procedure, "light-position-z",
"Light position Z",
"Light source position (x,y,z)",
-G_MAXDOUBLE, G_MAXDOUBLE, -1,
G_PARAM_READWRITE);
PIKA_PROC_ARG_DOUBLE (procedure, "light-direction-x",
"Light direction X",
"Light source direction (x,y,z)",
-G_MAXDOUBLE, G_MAXDOUBLE, -1,
G_PARAM_READWRITE);
PIKA_PROC_ARG_DOUBLE (procedure, "light-direction-y",
"Light direction Y",
"Light source direction (x,y,z)",
-G_MAXDOUBLE, G_MAXDOUBLE, -1,
G_PARAM_READWRITE);
PIKA_PROC_ARG_DOUBLE (procedure, "light-direction-z",
"Light direction Z",
"Light source direction (x,y,z)",
-G_MAXDOUBLE, G_MAXDOUBLE, 1,
G_PARAM_READWRITE);
PIKA_PROC_ARG_DOUBLE (procedure, "ambient-intensity",
"Ambient intensity",
"Material ambient intensity",
0, 1, 0.2,
G_PARAM_READWRITE);
PIKA_PROC_ARG_DOUBLE (procedure, "diffuse-intensity",
"Diffuse intensity",
"Material diffuse intensity",
0, 1, 0.5,
G_PARAM_READWRITE);
PIKA_PROC_ARG_DOUBLE (procedure, "diffuse-reflectivity",
"Diffuse reflectivity",
"Material diffuse reflectivity",
0, 1, 0.4,
G_PARAM_READWRITE);
PIKA_PROC_ARG_DOUBLE (procedure, "specular-reflectivity",
"Specular reflectivity",
"Material specular reflectivity",
0, 1, 0.5,
G_PARAM_READWRITE);
PIKA_PROC_ARG_DOUBLE (procedure, "highlight",
"Highlight",
"Material highlight (note, it's exponential)",
0, G_MAXDOUBLE, 27.0,
G_PARAM_READWRITE);
PIKA_PROC_ARG_BOOLEAN (procedure, "antialiasing",
"Antialiasing",
"Apply antialiasing",
FALSE,
G_PARAM_READWRITE);
PIKA_PROC_ARG_BOOLEAN (procedure, "new-image",
"New image",
"Create a new image",
FALSE,
G_PARAM_READWRITE);
PIKA_PROC_ARG_BOOLEAN (procedure, "transparent-background",
"Transparent background",
"Make background transparent",
FALSE,
G_PARAM_READWRITE);
}
return procedure;
}
static void
set_default_settings (void)
{
gint k;
mapvals.update_enabled = TRUE;
mapvals.light_selected = 0;
mapvals.light_isolated = FALSE;
pika_vector3_set (&mapvals.viewpoint, 0.5, 0.5, 0.25);
pika_vector3_set (&mapvals.planenormal, 0.0, 0.0, 1.0);
pika_vector3_set (&mapvals.lightsource[0].position, -1.0, -1.0, 1.0);
pika_vector3_set (&mapvals.lightsource[0].direction, -1.0, -1.0, 1.0);
pika_rgba_set (&mapvals.lightsource[0].color, 1.0, 1.0, 1.0, 1.0);
mapvals.lightsource[0].intensity = 1.0;
mapvals.lightsource[0].type = POINT_LIGHT;
mapvals.lightsource[0].active = TRUE;
/* init lights 2 and 3 pos to upper left and below */
pika_vector3_set (&mapvals.lightsource[1].position, 2.0, -1.0, 1.0);
pika_vector3_set (&mapvals.lightsource[1].direction, 1.0, -1.0, 1.0);
pika_vector3_set (&mapvals.lightsource[2].position, 1.0, 2.0, 1.0);
pika_vector3_set (&mapvals.lightsource[2].direction, 0.0, 1.0, 1.0);
/* init any remaining lights to directly overhead */
for (k = 3; k < NUM_LIGHTS; k++)
{
pika_vector3_set (&mapvals.lightsource[k].position, 0.0, 0.0, 1.0);
pika_vector3_set (&mapvals.lightsource[k].direction, 0.0, 0.0, 1.0);
}
for (k = 1; k < NUM_LIGHTS; k++)
{
pika_rgba_set (&mapvals.lightsource[k].color, 1.0, 1.0, 1.0, 1.0);
mapvals.lightsource[k].intensity = 1.0;
mapvals.lightsource[k].type = NO_LIGHT;
mapvals.lightsource[k].active = TRUE;
}
mapvals.material.ambient_int = 0.2;
mapvals.material.diffuse_int = 0.5;
mapvals.material.diffuse_ref = 0.4;
mapvals.material.specular_ref = 0.5;
mapvals.material.highlight = 27.0;
mapvals.material.metallic = FALSE;
mapvals.pixel_threshold = 0.25;
mapvals.max_depth = 3.0;
mapvals.preview_zoom_factor = 1.0;
mapvals.bumpmaptype = 0;
mapvals.bumpmin = 0.0;
mapvals.bumpmax = 0.1;
mapvals.antialiasing = FALSE;
mapvals.create_new_image = FALSE;
mapvals.transparent_background = FALSE;
mapvals.bump_mapped = FALSE;
mapvals.env_mapped = FALSE;
mapvals.ref_mapped = FALSE;
mapvals.previewquality = FALSE;
mapvals.interactive_preview = TRUE;
mapvals.bumpmap_id = -1;
mapvals.envmap_id = -1;
}
static void
check_drawables (void)
{
PikaDrawable *drawable;
PikaDrawable *map;
if (mapvals.bump_mapped)
{
if (! pika_item_id_is_drawable (mapvals.bumpmap_id))
{
mapvals.bump_mapped = FALSE;
mapvals.bumpmap_id = -1;
}
else
{
drawable = pika_drawable_get_by_id (mapvals.drawable_id);
map = pika_drawable_get_by_id (mapvals.bumpmap_id);
if (pika_drawable_is_indexed (map) ||
(pika_drawable_get_width (drawable) != pika_drawable_get_width (map)) ||
(pika_drawable_get_height (drawable) != pika_drawable_get_height (map)))
{
mapvals.bump_mapped = FALSE;
mapvals.bumpmap_id = -1;
}
}
}
if (mapvals.env_mapped)
{
if (! pika_item_id_is_drawable (mapvals.envmap_id))
{
mapvals.env_mapped = FALSE;
mapvals.envmap_id = -1;
}
else
{
map = pika_drawable_get_by_id (mapvals.envmap_id);
if (pika_drawable_is_gray (map) ||
pika_drawable_has_alpha (map))
{
mapvals.env_mapped = FALSE;
mapvals.envmap_id = -1;
}
}
}
}
static PikaValueArray *
lighting_run (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *image,
gint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args,
gpointer run_data)
{
PikaDrawable *drawable;
gegl_init (NULL, NULL);
if (n_drawables != 1)
{
GError *error = NULL;
g_set_error (&error, PIKA_PLUG_IN_ERROR, 0,
_("Procedure '%s' only works with one drawable."),
pika_procedure_get_name (procedure));
return pika_procedure_new_return_values (procedure,
PIKA_PDB_CALLING_ERROR,
error);
}
else
{
drawable = drawables[0];
}
set_default_settings ();
pika_get_data (PLUG_IN_PROC, &mapvals);
mapvals.drawable_id = pika_item_get_id (PIKA_ITEM (drawable));
check_drawables ();
if (pika_drawable_is_rgb (drawable))
{
switch (run_mode)
{
case PIKA_RUN_INTERACTIVE:
if (! main_dialog (drawable))
{
return pika_procedure_new_return_values (procedure,
PIKA_PDB_CANCEL,
NULL);
}
compute_image ();
pika_set_data (PLUG_IN_PROC, &mapvals, sizeof (LightingValues));
pika_displays_flush ();
break;
case PIKA_RUN_WITH_LAST_VALS:
if (image_setup (drawable, FALSE))
compute_image ();
pika_displays_flush ();
break;
case PIKA_RUN_NONINTERACTIVE:
mapvals.bumpmap_id = PIKA_VALUES_GET_DRAWABLE_ID (args, 0);
mapvals.envmap_id = PIKA_VALUES_GET_DRAWABLE_ID (args, 1);
mapvals.bump_mapped = PIKA_VALUES_GET_BOOLEAN (args, 2);
mapvals.env_mapped = PIKA_VALUES_GET_BOOLEAN (args, 3);
mapvals.bumpmaptype = PIKA_VALUES_GET_INT (args, 4);
mapvals.lightsource[0].type = PIKA_VALUES_GET_INT (args, 5);
PIKA_VALUES_GET_RGB (args, 6, &mapvals.lightsource[0].color);
mapvals.lightsource[0].position.x = PIKA_VALUES_GET_DOUBLE (args, 7);
mapvals.lightsource[0].position.y = PIKA_VALUES_GET_DOUBLE (args, 8);
mapvals.lightsource[0].position.z = PIKA_VALUES_GET_DOUBLE (args, 9);
mapvals.lightsource[0].direction.x = PIKA_VALUES_GET_DOUBLE (args, 10);
mapvals.lightsource[0].direction.y = PIKA_VALUES_GET_DOUBLE (args, 11);
mapvals.lightsource[0].direction.z = PIKA_VALUES_GET_DOUBLE (args, 12);
mapvals.material.ambient_int = PIKA_VALUES_GET_DOUBLE (args, 13);
mapvals.material.diffuse_int = PIKA_VALUES_GET_DOUBLE (args, 14);
mapvals.material.diffuse_ref = PIKA_VALUES_GET_DOUBLE (args, 15);
mapvals.material.specular_ref = PIKA_VALUES_GET_DOUBLE (args, 16);
mapvals.material.highlight = PIKA_VALUES_GET_DOUBLE (args, 17);
mapvals.antialiasing = PIKA_VALUES_GET_BOOLEAN (args, 18);
mapvals.create_new_image = PIKA_VALUES_GET_BOOLEAN (args, 19);
mapvals.transparent_background = PIKA_VALUES_GET_BOOLEAN (args, 20);
check_drawables ();
if (image_setup (drawable, FALSE))
compute_image ();
default:
break;
}
}
else
{
return pika_procedure_new_return_values (procedure,
PIKA_PDB_EXECUTION_ERROR,
NULL);
}
g_free (xpostab);
g_free (ypostab);
return pika_procedure_new_return_values (procedure, PIKA_PDB_SUCCESS, NULL);
}

View File

@ -0,0 +1,104 @@
#ifndef __LIGHTING_MAIN_H__
#define __LIGHTING_MAIN_H__
/* Defines and stuff */
/* ================= */
#define PLUG_IN_PROC "plug-in-lighting"
#define PLUG_IN_BINARY "lighting"
#define PLUG_IN_ROLE "pika-lighting"
#define TILE_CACHE_SIZE 16
#define NUM_LIGHTS 6
/* Typedefs */
/* ======== */
typedef enum
{
POINT_LIGHT,
DIRECTIONAL_LIGHT,
SPOT_LIGHT,
NO_LIGHT
} LightType;
enum
{
LINEAR_MAP,
LOGARITHMIC_MAP,
SINUSOIDAL_MAP,
SPHERICAL_MAP
};
enum
{
IMAGE_BUMP,
WAVES_BUMP
};
typedef struct
{
gdouble ambient_int;
gdouble diffuse_int;
gdouble diffuse_ref;
gdouble specular_ref;
gdouble highlight;
gboolean metallic;
PikaRGB color;
} MaterialSettings;
typedef struct
{
LightType type;
PikaVector3 position;
PikaVector3 direction;
PikaRGB color;
gdouble intensity;
gboolean active;
} LightSettings;
typedef struct
{
gint32 drawable_id;
gint32 bumpmap_id;
gint32 envmap_id;
/* Render variables */
/* ================ */
PikaVector3 viewpoint;
PikaVector3 planenormal;
LightSettings lightsource[NUM_LIGHTS];
MaterialSettings material;
MaterialSettings ref_material;
gdouble pixel_threshold;
gdouble bumpmax,bumpmin;
gint max_depth;
gint bumpmaptype;
/* Flags */
gint antialiasing;
gint create_new_image;
gint transparent_background;
gint bump_mapped;
gint env_mapped;
gint ref_mapped;
gint bumpstretch;
gint previewquality;
gboolean symbols;
gboolean interactive_preview;
/* Misc */
gboolean update_enabled;
gint light_selected;
gboolean light_isolated;
gdouble preview_zoom_factor;
} LightingValues;
/* Externally visible variables */
/* ============================ */
extern LightingValues mapvals;
#endif /* __LIGHTING_MAIN_H__ */

View File

@ -0,0 +1,487 @@
/*************************************************/
/* Compute a preview image and preview wireframe */
/*************************************************/
#include "config.h"
#include <gtk/gtk.h>
#include <libpika/pika.h>
#include <libpikamath/pikamath.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 );
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;
PikaRGB color;
PikaRGB lightcheck, darkcheck;
PikaVector3 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);
pika_rgba_set (&lightcheck,
PIKA_CHECK_LIGHT, PIKA_CHECK_LIGHT, PIKA_CHECK_LIGHT,
1.0);
pika_rgba_set (&darkcheck, PIKA_CHECK_DARK, PIKA_CHECK_DARK,
PIKA_CHECK_DARK, 1.0);
if (mapvals.bump_mapped == TRUE && mapvals.bumpmap_id != -1)
{
bumpmap_setup (pika_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 (pika_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));
}
color = (*ray_func) (&pos);
if (color.a < 1.0)
{
f1 = ((xcnt % 32) < 16);
f2 = ((ycnt % 32) < 16);
f1 = f1 ^ f2;
if (f1)
{
if (color.a == 0.0)
color = lightcheck;
else
pika_rgb_composite (&color,
&lightcheck,
PIKA_RGB_COMPOSITE_BEHIND);
}
else
{
if (color.a == 0.0)
color = darkcheck;
else
pika_rgb_composite (&color,
&darkcheck,
PIKA_RGB_COMPOSITE_BEHIND);
}
}
pika_rgb_get_uchar (&color, &r, &g, &b);
PIKA_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;
PikaVector3 viewpoint;
PikaVector3 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;
pika_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;
pika_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;
PikaVector3 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:
pika_vector_2d_to_3d (startx,
starty,
pw,
ph,
xpos, ypos, &vp, &mapvals.lightsource[k].position);
break;
case DIRECTIONAL_LIGHT:
pika_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);
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;
mapvals.update_enabled = FALSE; /* disable apply_settings() */
gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_pos_x),
mapvals.lightsource[k].position.x);
gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_pos_y),
mapvals.lightsource[k].position.y);
gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_pos_z),
mapvals.lightsource[k].position.z);
gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_dir_x),
mapvals.lightsource[k].direction.x);
gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_dir_y),
mapvals.lightsource[k].direction.y);
gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_dir_z),
mapvals.lightsource[k].direction.z);
mapvals.update_enabled = TRUE;
preview_compute ();
gtk_widget_queue_draw (previewarea);
preview_update_timer = 0;
return FALSE;
}

View File

@ -0,0 +1,38 @@
/* Lighting Effects - A plug-in for PIKA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __LIGHTING_PREVIEW_H__
#define __LIGHTING_PREVIEW_H__
#define PREVIEW_WIDTH 200
#define PREVIEW_HEIGHT 200
/* Externally visible variables */
extern gdouble *xpostab, *ypostab;
/* Externally visible functions */
void preview_compute (void);
void interactive_preview_callback (GtkWidget *widget);
gboolean preview_events (GtkWidget *area,
GdkEvent *event);
gboolean preview_draw (GtkWidget *area,
cairo_t *cr);
void update_light (gint xpos,
gint ypos);
#endif /* __LIGHTING_PREVIEW_H__ */

View File

@ -0,0 +1,856 @@
/*****************/
/* Shading stuff */
/*****************/
#include "config.h"
#include <libpika/pika.h>
#include "lighting-main.h"
#include "lighting-image.h"
#include "lighting-shade.h"
static PikaVector3 *triangle_normals[2] = { NULL, NULL };
static PikaVector3 *vertex_normals[3] = { NULL, NULL, NULL };
static gdouble *heights[3] = { NULL, NULL, NULL };
static gdouble xstep, ystep;
static guchar *bumprow = NULL;
static gint pre_w = -1;
static gint pre_h = -1;
/*****************/
/* Phong shading */
/*****************/
static PikaRGB
phong_shade (PikaVector3 *position,
PikaVector3 *viewpoint,
PikaVector3 *normal,
PikaVector3 *lightposition,
PikaRGB *diff_col,
PikaRGB *light_col,
LightType light_type)
{
PikaRGB diffuse_color, specular_color;
gdouble nl, rv, dist;
PikaVector3 l, v, n, lnormal, h;
/* Compute ambient intensity */
/* ========================= */
n = *normal;
/* Compute (N*L) term of Phong's equation */
/* ====================================== */
if (light_type == POINT_LIGHT)
pika_vector3_sub (&l, lightposition, position);
else
{
l = *lightposition;
pika_vector3_normalize (&l);
}
dist = pika_vector3_length (&l);
if (dist != 0.0)
pika_vector3_mul (&l, 1.0 / dist);
nl = MAX (0., 2.0 * pika_vector3_inner_product (&n, &l));
lnormal = l;
pika_vector3_normalize (&lnormal);
if (nl >= 0.0)
{
/* Compute (R*V)^alpha term of Phong's equation */
/* ============================================ */
pika_vector3_sub (&v, viewpoint, position);
pika_vector3_normalize (&v);
pika_vector3_add (&h, &lnormal, &v);
pika_vector3_normalize (&h);
rv = MAX (0.01, pika_vector3_inner_product (&n, &h));
rv = pow (rv, mapvals.material.highlight);
rv *= nl;
/* Compute diffuse and specular intensity contribution */
/* =================================================== */
diffuse_color = *light_col;
pika_rgb_multiply (&diffuse_color, mapvals.material.diffuse_int);
diffuse_color.r *= diff_col->r;
diffuse_color.g *= diff_col->g;
diffuse_color.b *= diff_col->b;
pika_rgb_multiply (&diffuse_color, nl);
specular_color = *light_col;
if (mapvals.material.metallic) /* for metals, specular color = diffuse color */
{
specular_color.r *= diff_col->r;
specular_color.g *= diff_col->g;
specular_color.b *= diff_col->b;
}
pika_rgb_multiply (&specular_color, mapvals.material.specular_ref);
pika_rgb_multiply (&specular_color, rv);
pika_rgb_add (&diffuse_color, &specular_color);
pika_rgb_clamp (&diffuse_color);
}
pika_rgb_clamp (&diffuse_color);
return diffuse_color;
}
void
precompute_init (gint w,
gint h)
{
gint n;
gint bpp=1;
xstep = 1.0 / (gdouble) width;
ystep = 1.0 / (gdouble) height;
pre_w = w;
pre_h = h;
for (n = 0; n < 3; n++)
{
if (vertex_normals[n] != NULL)
g_free (vertex_normals[n]);
if (heights[n] != NULL)
g_free (heights[n]);
heights[n] = g_new (gdouble, w);
vertex_normals[n] = g_new (PikaVector3, w);
}
for (n = 0; n < 2; n++)
if (triangle_normals[n] != NULL)
g_free (triangle_normals[n]);
g_clear_pointer (&bumprow, g_free);
if (mapvals.bumpmap_id != -1)
{
PikaDrawable *drawable = pika_drawable_get_by_id (mapvals.bumpmap_id);
bpp = pika_drawable_get_bpp (drawable);
}
bumprow = g_new (guchar, w * bpp);
triangle_normals[0] = g_new (PikaVector3, (w << 1) + 2);
triangle_normals[1] = g_new (PikaVector3, (w << 1) + 2);
for (n = 0; n < (w << 1) + 1; n++)
{
pika_vector3_set (&triangle_normals[0][n], 0.0, 0.0, 1.0);
pika_vector3_set (&triangle_normals[1][n], 0.0, 0.0, 1.0);
}
for (n = 0; n < w; n++)
{
pika_vector3_set (&vertex_normals[0][n], 0.0, 0.0, 1.0);
pika_vector3_set (&vertex_normals[1][n], 0.0, 0.0, 1.0);
pika_vector3_set (&vertex_normals[2][n], 0.0, 0.0, 1.0);
heights[0][n] = 0.0;
heights[1][n] = 0.0;
heights[2][n] = 0.0;
}
}
/* Interpol linearly height[2] and triangle_normals[1]
* using the next row
*/
void
interpol_row (gint x1,
gint x2,
gint y)
{
PikaVector3 p1, p2, p3;
gint n, i;
guchar *map = NULL;
gint bpp = 1;
guchar *bumprow1 = NULL;
guchar *bumprow2 = NULL;
if (mapvals.bumpmap_id != -1)
{
bumpmap_setup (pika_drawable_get_by_id (mapvals.bumpmap_id));
bpp = babl_format_get_bytes_per_pixel (bump_format);
}
bumprow1 = g_new0 (guchar, pre_w * bpp);
bumprow2 = g_new0 (guchar, pre_w * bpp);
gegl_buffer_get (bump_buffer, GEGL_RECTANGLE (x1, y, x2 - x1, 1), 1.0,
bump_format, bumprow1,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
gegl_buffer_get (bump_buffer, GEGL_RECTANGLE (x1, y - 1, x2 - x1, 1), 1.0,
bump_format, bumprow2,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
if (mapvals.bumpmaptype > 0)
{
switch (mapvals.bumpmaptype)
{
case 1:
map = logmap;
break;
case 2:
map = sinemap;
break;
default:
map = spheremap;
break;
}
}
for (n = 0; n < (x2 - x1); n++)
{
gdouble diff;
guchar mapval;
guchar mapval1, mapval2;
if (bpp > 1)
{
mapval1 = (guchar)((float)((bumprow1[n * bpp] +bumprow1[n * bpp +1] + bumprow1[n * bpp + 2])/3.0 )) ;
mapval2 = (guchar)((float)((bumprow2[n * bpp] +bumprow2[n * bpp +1] + bumprow2[n * bpp + 2])/3.0 )) ;
}
else
{
mapval1 = bumprow1[n * bpp];
mapval2 = bumprow2[n * bpp];
}
diff = mapval1 - mapval2;
mapval = (guchar) CLAMP (mapval1 + diff, 0.0, 255.0);
if (mapvals.bumpmaptype > 0)
{
heights[1][n] = (gdouble) mapvals.bumpmax * (gdouble) map[mapval1] / 255.0;
heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) map[mapval] / 255.0;
}
else
{
heights[1][n] = (gdouble) mapvals.bumpmax * (gdouble) mapval1 / 255.0;
heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) mapval / 255.0;
}
}
i = 0;
for (n = 0; n < (x2 - x1 - 1); n++)
{
/* heights rows 1 and 2 are inverted */
p1.x = 0.0;
p1.y = ystep;
p1.z = heights[1][n] - heights[2][n];
p2.x = xstep;
p2.y = ystep;
p2.z = heights[1][n+1] - heights[2][n];
p3.x = xstep;
p3.y = 0.0;
p3.z = heights[2][n+1] - heights[2][n];
triangle_normals[1][i] = pika_vector3_cross_product (&p2, &p1);
triangle_normals[1][i+1] = pika_vector3_cross_product (&p3, &p2);
pika_vector3_normalize (&triangle_normals[1][i]);
pika_vector3_normalize (&triangle_normals[1][i+1]);
i += 2;
}
g_free (bumprow1);
g_free (bumprow2);
}
/********************************************/
/* Compute triangle and then vertex normals */
/********************************************/
void
precompute_normals (gint x1,
gint x2,
gint y)
{
PikaVector3 *tmpv, p1, p2, p3, normal;
gdouble *tmpd;
gint n, i, nv;
guchar *map = NULL;
gint bpp = 1;
guchar mapval;
/* First, compute the heights */
/* ========================== */
tmpv = triangle_normals[0];
triangle_normals[0] = triangle_normals[1];
triangle_normals[1] = tmpv;
tmpv = vertex_normals[0];
vertex_normals[0] = vertex_normals[1];
vertex_normals[1] = vertex_normals[2];
vertex_normals[2] = tmpv;
tmpd = heights[0];
heights[0] = heights[1];
heights[1] = heights[2];
heights[2] = tmpd;
if (mapvals.bumpmap_id != -1)
{
bumpmap_setup (pika_drawable_get_by_id (mapvals.bumpmap_id));
bpp = babl_format_get_bytes_per_pixel (bump_format);
}
gegl_buffer_get (bump_buffer, GEGL_RECTANGLE (x1, y, x2 - x1, 1), 1.0,
bump_format, bumprow,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
if (mapvals.bumpmaptype > 0)
{
switch (mapvals.bumpmaptype)
{
case 1:
map = logmap;
break;
case 2:
map = sinemap;
break;
default:
map = spheremap;
break;
}
for (n = 0; n < (x2 - x1); n++)
{
if (bpp > 1)
{
mapval = (guchar)((float)((bumprow[n * bpp + 0] +
bumprow[n * bpp + 1] +
bumprow[n * bpp + 2]) /3.0));
}
else
{
mapval = bumprow[n * bpp];
}
heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) map[mapval] / 255.0;
}
}
else
{
for (n = 0; n < (x2 - x1); n++)
{
if (bpp > 1)
{
mapval = (guchar)((float)((bumprow[n * bpp + 0] +
bumprow[n * bpp + 1] +
bumprow[n * bpp + 2]) / 3.0));
}
else
{
mapval = bumprow[n * bpp];
}
heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) mapval / 255.0;
}
}
/* Compute triangle normals */
/* ======================== */
i = 0;
for (n = 0; n < (x2 - x1 - 1); n++)
{
p1.x = 0.0;
p1.y = ystep;
p1.z = heights[2][n] - heights[1][n];
p2.x = xstep;
p2.y = ystep;
p2.z = heights[2][n+1] - heights[1][n];
p3.x = xstep;
p3.y = 0.0;
p3.z = heights[1][n+1] - heights[1][n];
triangle_normals[1][i] = pika_vector3_cross_product (&p2, &p1);
triangle_normals[1][i+1] = pika_vector3_cross_product (&p3, &p2);
pika_vector3_normalize (&triangle_normals[1][i]);
pika_vector3_normalize (&triangle_normals[1][i+1]);
i += 2;
}
/* Compute vertex normals */
/* ====================== */
i = 0;
pika_vector3_set (&normal, 0.0, 0.0, 0.0);
for (n = 0; n < (x2 - x1 - 1); n++)
{
nv = 0;
if (n > 0)
{
if (y > 0)
{
pika_vector3_add (&normal, &normal, &triangle_normals[0][i-1]);
pika_vector3_add (&normal, &normal, &triangle_normals[0][i-2]);
nv += 2;
}
if (y < pre_h)
{
pika_vector3_add (&normal, &normal, &triangle_normals[1][i-1]);
nv++;
}
}
if (n < pre_w)
{
if (y > 0)
{
pika_vector3_add (&normal, &normal, &triangle_normals[0][i]);
pika_vector3_add (&normal, &normal, &triangle_normals[0][i+1]);
nv += 2;
}
if (y < pre_h)
{
pika_vector3_add (&normal, &normal, &triangle_normals[1][i]);
pika_vector3_add (&normal, &normal, &triangle_normals[1][i+1]);
nv += 2;
}
}
pika_vector3_mul (&normal, 1.0 / (gdouble) nv);
pika_vector3_normalize (&normal);
vertex_normals[1][n] = normal;
i += 2;
}
}
/***********************************************************************/
/* Compute the reflected ray given the normalized normal and ins. vec. */
/***********************************************************************/
static PikaVector3
compute_reflected_ray (PikaVector3 *normal,
PikaVector3 *view)
{
PikaVector3 ref;
gdouble nl;
nl = 2.0 * pika_vector3_inner_product (normal, view);
ref = *normal;
pika_vector3_mul (&ref, nl);
pika_vector3_sub (&ref, &ref, view);
return ref;
}
/************************************************************************/
/* Given the NorthPole, Equator and a third vector (normal) compute */
/* the conversion from spherical coordinates to image space coordinates */
/************************************************************************/
static void
sphere_to_image (PikaVector3 *normal,
gdouble *u,
gdouble *v)
{
static gdouble alpha, fac;
static PikaVector3 cross_prod;
static PikaVector3 firstaxis = { 1.0, 0.0, 0.0 };
static PikaVector3 secondaxis = { 0.0, 1.0, 0.0 };
alpha = acos (-pika_vector3_inner_product (&secondaxis, normal));
*v = alpha / G_PI;
if (*v == 0.0 || *v == 1.0)
{
*u = 0.0;
}
else
{
fac = pika_vector3_inner_product (&firstaxis, normal) / sin (alpha);
/* Make sure that we map to -1.0..1.0 (take care of rounding errors) */
/* ================================================================= */
if (fac > 1.0)
fac = 1.0;
else if (fac < -1.0)
fac = -1.0;
*u = acos (fac) / (2.0 * G_PI);
cross_prod = pika_vector3_cross_product (&secondaxis, &firstaxis);
if (pika_vector3_inner_product (&cross_prod, normal) < 0.0)
*u = 1.0 - *u;
}
}
/*********************************************************************/
/* These routines computes the color of the surface at a given point */
/*********************************************************************/
PikaRGB
get_ray_color (PikaVector3 *position)
{
PikaRGB color;
PikaRGB color_int;
PikaRGB color_sum;
PikaRGB light_color;
gint x, f;
gdouble xf, yf;
PikaVector3 normal, *p;
gint k;
pos_to_float (position->x, position->y, &xf, &yf);
x = RINT (xf);
if (mapvals.transparent_background && heights[1][x] == 0)
{
pika_rgb_set_alpha (&color_sum, 0.0);
}
else
{
color = get_image_color (xf, yf, &f);
color_sum = color;
pika_rgb_multiply (&color_sum, mapvals.material.ambient_int);
for (k = 0; k < NUM_LIGHTS; k++)
{
if (! mapvals.lightsource[k].active ||
mapvals.lightsource[k].type == NO_LIGHT)
continue;
else if (mapvals.lightsource[k].type == POINT_LIGHT)
p = &mapvals.lightsource[k].position;
else
p = &mapvals.lightsource[k].direction;
color_int = mapvals.lightsource[k].color;
pika_rgb_multiply (&color_int, mapvals.lightsource[k].intensity);
if (mapvals.bump_mapped == FALSE ||
mapvals.bumpmap_id == -1)
{
light_color = phong_shade (position,
&mapvals.viewpoint,
&mapvals.planenormal,
p,
&color,
&color_int,
mapvals.lightsource[k].type);
}
else
{
normal = vertex_normals[1][(gint) RINT (xf)];
light_color = phong_shade (position,
&mapvals.viewpoint,
&normal,
p,
&color,
&color_int,
mapvals.lightsource[k].type);
}
pika_rgb_add (&color_sum, &light_color);
}
}
pika_rgb_clamp (&color_sum);
return color_sum;
}
PikaRGB
get_ray_color_ref (PikaVector3 *position)
{
PikaRGB color_sum;
PikaRGB color_int;
PikaRGB light_color;
PikaRGB color, env_color;
gint x, f;
gdouble xf, yf;
PikaVector3 normal, *p, v, r;
gint k;
gdouble tmpval;
pos_to_float (position->x, position->y, &xf, &yf);
x = RINT (xf);
if (mapvals.bump_mapped == FALSE ||
mapvals.bumpmap_id == -1)
{
normal = mapvals.planenormal;
}
else
{
normal = vertex_normals[1][(gint) RINT (xf)];
}
pika_vector3_normalize (&normal);
if (mapvals.transparent_background && heights[1][x] == 0)
{
pika_rgb_set_alpha (&color_sum, 0.0);
}
else
{
color = get_image_color (xf, yf, &f);
color_sum = color;
pika_rgb_multiply (&color_sum, mapvals.material.ambient_int);
for (k = 0; k < NUM_LIGHTS; k++)
{
p = &mapvals.lightsource[k].direction;
if (! mapvals.lightsource[k].active ||
mapvals.lightsource[k].type == NO_LIGHT)
continue;
else if (mapvals.lightsource[k].type == POINT_LIGHT)
p = &mapvals.lightsource[k].position;
color_int = mapvals.lightsource[k].color;
pika_rgb_multiply (&color_int, mapvals.lightsource[k].intensity);
light_color = phong_shade (position,
&mapvals.viewpoint,
&normal,
p,
&color,
&color_int,
mapvals.lightsource[0].type);
}
pika_vector3_sub (&v, &mapvals.viewpoint, position);
pika_vector3_normalize (&v);
r = compute_reflected_ray (&normal, &v);
/* Get color in the direction of r */
/* =============================== */
sphere_to_image (&r, &xf, &yf);
env_color = peek_env_map (RINT (env_width * xf),
RINT (env_height * yf));
tmpval = mapvals.material.diffuse_int;
mapvals.material.diffuse_int = 0.;
light_color = phong_shade (position,
&mapvals.viewpoint,
&normal,
&r,
&color,
&env_color,
DIRECTIONAL_LIGHT);
mapvals.material.diffuse_int = tmpval;
pika_rgb_add (&color_sum, &light_color);
}
pika_rgb_clamp (&color_sum);
return color_sum;
}
PikaRGB
get_ray_color_no_bilinear (PikaVector3 *position)
{
PikaRGB color;
PikaRGB color_int;
PikaRGB color_sum;
PikaRGB light_color;
gint x;
gdouble xf, yf;
PikaVector3 normal, *p;
gint k;
pos_to_float (position->x, position->y, &xf, &yf);
x = RINT (xf);
if (mapvals.transparent_background && heights[1][x] == 0)
{
pika_rgb_set_alpha (&color_sum, 0.0);
}
else
{
color = peek (x, RINT (yf));
color_sum = color;
pika_rgb_multiply (&color_sum, mapvals.material.ambient_int);
for (k = 0; k < NUM_LIGHTS; k++)
{
p = &mapvals.lightsource[k].direction;
if (! mapvals.lightsource[k].active ||
mapvals.lightsource[k].type == NO_LIGHT)
continue;
else if (mapvals.lightsource[k].type == POINT_LIGHT)
p = &mapvals.lightsource[k].position;
color_int = mapvals.lightsource[k].color;
pika_rgb_multiply (&color_int, mapvals.lightsource[k].intensity);
if (mapvals.bump_mapped == FALSE ||
mapvals.bumpmap_id == -1)
{
light_color = phong_shade (position,
&mapvals.viewpoint,
&mapvals.planenormal,
p,
&color,
&color_int,
mapvals.lightsource[k].type);
}
else
{
normal = vertex_normals[1][x];
light_color = phong_shade (position,
&mapvals.viewpoint,
&normal,
p,
&color,
&color_int,
mapvals.lightsource[k].type);
}
pika_rgb_add (&color_sum, &light_color);
}
}
pika_rgb_clamp (&color_sum);
return color_sum;
}
PikaRGB
get_ray_color_no_bilinear_ref (PikaVector3 *position)
{
PikaRGB color_sum;
PikaRGB color_int;
PikaRGB light_color;
PikaRGB color, env_color;
gint x;
gdouble xf, yf;
PikaVector3 normal, *p, v, r;
gint k;
gdouble tmpval;
pos_to_float (position->x, position->y, &xf, &yf);
x = RINT (xf);
if (mapvals.bump_mapped == FALSE ||
mapvals.bumpmap_id == -1)
{
normal = mapvals.planenormal;
}
else
{
normal = vertex_normals[1][(gint) RINT (xf)];
}
pika_vector3_normalize (&normal);
if (mapvals.transparent_background && heights[1][x] == 0)
{
pika_rgb_set_alpha (&color_sum, 0.0);
}
else
{
color = peek (RINT (xf), RINT (yf));
color_sum = color;
pika_rgb_multiply (&color_sum, mapvals.material.ambient_int);
for (k = 0; k < NUM_LIGHTS; k++)
{
p = &mapvals.lightsource[k].direction;
if (!mapvals.lightsource[k].active
|| mapvals.lightsource[k].type == NO_LIGHT)
continue;
else if (mapvals.lightsource[k].type == POINT_LIGHT)
p = &mapvals.lightsource[k].position;
color_int = mapvals.lightsource[k].color;
pika_rgb_multiply (&color_int, mapvals.lightsource[k].intensity);
light_color = phong_shade (position,
&mapvals.viewpoint,
&normal,
p,
&color,
&color_int,
mapvals.lightsource[0].type);
}
pika_vector3_sub (&v, &mapvals.viewpoint, position);
pika_vector3_normalize (&v);
r = compute_reflected_ray (&normal, &v);
/* Get color in the direction of r */
/* =============================== */
sphere_to_image (&r, &xf, &yf);
env_color = peek_env_map (RINT (env_width * xf),
RINT (env_height * yf));
tmpval = mapvals.material.diffuse_int;
mapvals.material.diffuse_int = 0.;
light_color = phong_shade (position,
&mapvals.viewpoint,
&normal,
&r,
&color,
&env_color,
DIRECTIONAL_LIGHT);
mapvals.material.diffuse_int = tmpval;
pika_rgb_add (&color_sum, &light_color);
}
pika_rgb_clamp (&color_sum);
return color_sum;
}

View File

@ -0,0 +1,20 @@
#ifndef __LIGHTING_SHADE_H__
#define __LIGHTING_SHADE_H__
typedef PikaRGB (* get_ray_func) (PikaVector3 *vector);
PikaRGB get_ray_color (PikaVector3 *position);
PikaRGB get_ray_color_no_bilinear (PikaVector3 *position);
PikaRGB get_ray_color_ref (PikaVector3 *position);
PikaRGB get_ray_color_no_bilinear_ref (PikaVector3 *position);
void precompute_init (gint w,
gint h);
void precompute_normals (gint x1,
gint x2,
gint y);
void interpol_row (gint x1,
gint x2,
gint y);
#endif /* __LIGHTING_SHADE_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
#ifndef __LIGHTING_UI_H__
#define __LIGHTING_UI_H__
/* Externally visible variables */
/* ============================ */
extern GtkWidget *previewarea;
extern GtkWidget *spin_pos_x;
extern GtkWidget *spin_pos_y;
extern GtkWidget *spin_pos_z;
extern GtkWidget *spin_dir_x;
extern GtkWidget *spin_dir_y;
extern GtkWidget *spin_dir_z;
/* Externally visible functions */
/* ============================ */
gboolean main_dialog (PikaDrawable *drawable);
#endif /* __LIGHTING_UI_H__ */

View File

@ -0,0 +1,38 @@
subdir('images')
plugin_name = 'lighting'
plugin_sources = [
'lighting-apply.c',
'lighting-icons.c',
'lighting-image.c',
'lighting-main.c',
'lighting-preview.c',
'lighting-shade.c',
'lighting-ui.c',
lighting_icon_sources,
]
if platform_windows
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
'--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
'--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
'--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
],
)
endif
executable(plugin_name,
plugin_sources,
dependencies: [
libpikaui_dep,
math,
],
install: true,
install_dir: pikaplugindir / 'plug-ins' / plugin_name,
)