Initial checkin of Pika from heckimp
39
plug-ins/lighting/README
Normal 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
@ -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
|
15
plug-ins/lighting/images/lighting-icon-images.gresource.xml
Normal 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>
|
BIN
plug-ins/lighting/images/lighting-intensity-ambient-high.png
Normal file
After Width: | Height: | Size: 725 B |
BIN
plug-ins/lighting/images/lighting-intensity-ambient-low.png
Normal file
After Width: | Height: | Size: 918 B |
BIN
plug-ins/lighting/images/lighting-intensity-diffuse-high.png
Normal file
After Width: | Height: | Size: 829 B |
BIN
plug-ins/lighting/images/lighting-intensity-diffuse-low.png
Normal file
After Width: | Height: | Size: 504 B |
BIN
plug-ins/lighting/images/lighting-reflectivity-diffuse-high.png
Normal file
After Width: | Height: | Size: 805 B |
BIN
plug-ins/lighting/images/lighting-reflectivity-diffuse-low.png
Normal file
After Width: | Height: | Size: 441 B |
After Width: | Height: | Size: 822 B |
BIN
plug-ins/lighting/images/lighting-reflectivity-highlight-low.png
Normal file
After Width: | Height: | Size: 805 B |
BIN
plug-ins/lighting/images/lighting-reflectivity-specular-high.png
Normal file
After Width: | Height: | Size: 842 B |
BIN
plug-ins/lighting/images/lighting-reflectivity-specular-low.png
Normal file
After Width: | Height: | Size: 800 B |
18
plug-ins/lighting/images/meson.build
Normal 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(),
|
||||
)
|
153
plug-ins/lighting/lighting-apply.c
Normal 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 ();
|
||||
}
|
||||
}
|
7
plug-ins/lighting/lighting-apply.h
Normal 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__ */
|
42
plug-ins/lighting/lighting-icons.c
Normal 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");
|
||||
}
|
37
plug-ins/lighting/lighting-icons.h
Normal 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__ */
|
410
plug-ins/lighting/lighting-image.c
Normal 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);
|
||||
}
|
||||
}
|
72
plug-ins/lighting/lighting-image.h
Normal 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__ */
|
491
plug-ins/lighting/lighting-main.c
Normal 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);
|
||||
}
|
104
plug-ins/lighting/lighting-main.h
Normal 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__ */
|
487
plug-ins/lighting/lighting-preview.c
Normal 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;
|
||||
}
|
38
plug-ins/lighting/lighting-preview.h
Normal 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__ */
|
856
plug-ins/lighting/lighting-shade.c
Normal 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;
|
||||
}
|
20
plug-ins/lighting/lighting-shade.h
Normal 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__ */
|
1557
plug-ins/lighting/lighting-ui.c
Normal file
21
plug-ins/lighting/lighting-ui.h
Normal 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__ */
|
38
plug-ins/lighting/meson.build
Normal 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,
|
||||
)
|