Code

Super duper mega (fun!) commit: replaced encoding=utf-8 with fileencoding=utf-8 in...
[inkscape.git] / src / display / nr-filter-diffuselighting.cpp
1 /*
2  * feDiffuseLighting renderer
3  *
4  * Authors:
5  *   Niko Kiirala <niko@kiirala.com>
6  *   Jean-Rene Reinhard <jr@komite.net>
7  *
8  * Copyright (C) 2007 authors
9  *
10  * Released under GNU GPL, read the file 'COPYING' for more information
11  */
13 #include <glib/gmessages.h>
15 #include "display/nr-3dutils.h"
16 #include "display/nr-arena-item.h"
17 #include "display/nr-filter-diffuselighting.h"
18 #include "display/nr-filter-getalpha.h"
19 #include "display/nr-filter-slot.h"
20 #include "display/nr-filter-units.h"
21 #include "display/nr-filter-utils.h"
22 #include "display/nr-light.h"
23 #include "libnr/nr-blit.h"
24 #include "libnr/nr-pixblock.h"
25 #include "libnr/nr-rect-l.h"
26 #include "color.h"
28 namespace Inkscape {
29 namespace Filters {
31 FilterDiffuseLighting::FilterDiffuseLighting() 
32 {
33     light_type = NO_LIGHT;
34     diffuseConstant = 1;
35     surfaceScale = 1;
36     lighting_color = 0xffffffff;
37 }
39 FilterPrimitive * FilterDiffuseLighting::create() {
40     return new FilterDiffuseLighting();
41 }
43 FilterDiffuseLighting::~FilterDiffuseLighting()
44 {}
46 int FilterDiffuseLighting::render(FilterSlot &slot, FilterUnits const &units) {
47     NRPixBlock *in = slot.get(_input);
48     if (!in) {
49         g_warning("Missing source image for feDiffuseLighting (in=%d)", _input);
50         return 1;
51     }
53     NRPixBlock *out = new NRPixBlock;
55     int w = in->area.x1 - in->area.x0;
56     int h = in->area.y1 - in->area.y0;
57     int x0 = in->area.x0;
58     int y0 = in->area.y0;
59     int i, j;
60     //As long as FilterRes and kernel unit is not supported we hardcode the
61     //default value
62     int dx = 1; //TODO setup
63     int dy = 1; //TODO setup
64     //surface scale
65     Geom::Matrix trans = units.get_matrix_primitiveunits2pb();
66     gdouble ss = surfaceScale * trans[0];
67     gdouble kd = diffuseConstant; //diffuse lighting constant
69     NR::Fvector L, N, LC;
70     gdouble inter;
72     nr_pixblock_setup_fast(out, in->mode,
73             in->area.x0, in->area.y0, in->area.x1, in->area.y1,
74             true);
75     unsigned char *data_i = NR_PIXBLOCK_PX (in);
76     unsigned char *data_o = NR_PIXBLOCK_PX (out);
77     //No light, nothing to do
78     switch (light_type) {
79         case DISTANT_LIGHT:  
80             //the light vector is constant
81             {
82             DistantLight *dl = new DistantLight(light.distant, lighting_color);
83             dl->light_vector(L);
84             dl->light_components(LC);
85             //finish the work
86             for (i = 0, j = 0; i < w*h; i++) {
87                 NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
88                 inter = kd * NR::scalar_product(N, L);
90                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]); // CLAMP includes rounding!
91                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
92                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
93                 data_o[j++] = 255;
94             }
95             out->empty = FALSE;
96             delete dl;
97             }
98             break;
99         case POINT_LIGHT:
100             {
101             PointLight *pl = new PointLight(light.point, lighting_color, trans);
102             pl->light_components(LC);
103         //TODO we need a reference to the filter to determine primitiveUnits
104         //if objectBoundingBox is used, use a different matrix for light_vector
105         // UPDATE: trans is now correct matrix from primitiveUnits to
106         // pixblock coordinates
107             //finish the work
108             for (i = 0, j = 0; i < w*h; i++) {
109                 NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
110                 pl->light_vector(L,
111                         i % w + x0,
112                         i / w + y0,
113                         ss * (double) data_i[4*i+3]/ 255);
114                 inter = kd * NR::scalar_product(N, L);
116                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]);
117                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
118                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
119                 data_o[j++] = 255;
120             }
121             out->empty = FALSE;
122             delete pl;
123             }
124             break;
125         case SPOT_LIGHT:
126             {
127             SpotLight *sl = new SpotLight(light.spot, lighting_color, trans);
128         //TODO we need a reference to the filter to determine primitiveUnits
129         //if objectBoundingBox is used, use a different matrix for light_vector
130         // UPDATE: trans is now correct matrix from primitiveUnits to
131         // pixblock coordinates
132             //finish the work
133             for (i = 0, j = 0; i < w*h; i++) {
134                 NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
135                 sl->light_vector(L,
136                     i % w + x0,
137                     i / w + y0,
138                     ss * (double) data_i[4*i+3]/ 255);
139                 sl->light_components(LC, L);
140                 inter = kd * NR::scalar_product(N, L);
141                 
142                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]);
143                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
144                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
145                 data_o[j++] = 255;
146             }
147             out->empty = FALSE;
148             delete sl;
149             }
150             break;
151         //else unknown light source, doing nothing
152         case NO_LIGHT:
153         default:
154             {
155             if (light_type != NO_LIGHT)
156                 g_warning("unknown light source %d", light_type);
157             for (i = 0; i < w*h; i++) {
158                 data_o[4*i+3] = 255;
159             }
160             out->empty = false;
161             }
162     }
163         
164     //finishing
165     slot.set(_output, out);
166     //nr_pixblock_release(in);
167     //delete in;
168     return 0;
171 void FilterDiffuseLighting::area_enlarge(NRRectL &area, Geom::Matrix const &trans)
173     // TODO: support kernelUnitLength
174     double scalex = std::fabs(trans[0]) + std::fabs(trans[1]);
175     double scaley = std::fabs(trans[2]) + std::fabs(trans[3]);
177     //FIXME: no +2 should be there!... (noticable only for big scales at big zoom factor)
178     area.x0 -= (int)(scalex) + 2;
179     area.x1 += (int)(scalex) + 2;
180     area.y0 -= (int)(scaley) + 2;
181     area.y1 += (int)(scaley) + 2;
184 FilterTraits FilterDiffuseLighting::get_input_traits() {
185     return TRAIT_PARALLER;
188 } /* namespace Filters */
189 } /* namespace Inkscape */
191 /*
192   Local Variables:
193   mode:c++
194   c-file-style:"stroustrup"
195   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
196   indent-tabs-mode:nil
197   fill-column:99
198   End:
199 */
200 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :