Code

patch by Dennis Lin: optionally for debugging paint the rect-to-redraw yellow
[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-utils.h"
21 #include "display/nr-light.h"
22 #include "libnr/nr-blit.h"
23 #include "libnr/nr-pixblock.h"
24 #include "libnr/nr-matrix.h"
25 #include "libnr/nr-rect-l.h"
26 #include "color.h"
28 namespace NR {
30 FilterDiffuseLighting::FilterDiffuseLighting() 
31 {
32     light_type = NO_LIGHT;
33     diffuseConstant = 1;
34     surfaceScale = 1;
35     lighting_color = 0xffffffff;
36 }
38 FilterPrimitive * FilterDiffuseLighting::create() {
39     return new FilterDiffuseLighting();
40 }
42 FilterDiffuseLighting::~FilterDiffuseLighting()
43 {}
45 #define COMPUTE_INTER(inter, N, L, kd) \
46 do {\
47     (inter) = (kd) * scalar_product((N), (L)); \
48     if ((inter) < 0) (inter) = 0; \
49 }while(0)
52 int FilterDiffuseLighting::render(FilterSlot &slot, Matrix const &trans) {
53     NRPixBlock *in = filter_get_alpha(slot.get(_input));
54     NRPixBlock *out = new NRPixBlock;
56     int w = in->area.x1 - in->area.x0;
57     int h = in->area.y1 - in->area.y0;
58     int x0 = in->area.x0;
59     int y0 = in->area.y0;
60     int i, j;
61     //As long as FilterRes and kernel unit is not supported we hardcode the
62     //default value
63     int dx = 1; //TODO setup
64     int dy = 1; //TODO setup
65     //surface scale
66     //TODO for the time being, assumes userSpaceOnUse
67     gdouble ss = surfaceScale * trans[0];
68     gdouble kd = diffuseConstant; //diffuse lighting constant
70     Fvector L, N, LC;
71     gdouble inter;
73     nr_pixblock_setup_fast(out, in->mode,
74             in->area.x0, in->area.y0, in->area.x1, in->area.y1,
75             true);
76     unsigned char *data_i = NR_PIXBLOCK_PX (in);
77     unsigned char *data_o = NR_PIXBLOCK_PX (out);
78     //No light, nothing to do
79     switch (light_type) {
80         case DISTANT_LIGHT:  
81             //the light vector is constant
82             {
83             DistantLight *dl = new DistantLight(light.distant, lighting_color);
84             dl->light_vector(L);
85             dl->light_components(LC);
86             //finish the work
87             for (i = 0, j = 0; i < w*h; i++) {
88                 compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
89                 COMPUTE_INTER(inter, N, L, kd);
91                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]);
92                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
93                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
94                 data_o[j++] = 255;
95             }
96             out->empty = FALSE;
97             delete dl;
98             }
99             break;
100         case POINT_LIGHT:
101             {
102             PointLight *pl = new PointLight(light.point, lighting_color, trans);
103             pl->light_components(LC);
104         //TODO we need a reference to the filter to determine primitiveUnits
105         //slot._arena_item->filter seems to be ok on simple examples
106         //for now assume userSpaceOnUse
107         //if objectBoundingBox is used, use a different matrix for light_vector
108             //finish the work
109             for (i = 0, j = 0; i < w*h; i++) {
110                 compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
111                 pl->light_vector(L,
112                         i % w + x0,
113                         i / w + y0,
114                         ss * (double) data_i[4*i+3]/ 255);
115                 COMPUTE_INTER(inter, N, L, kd);
117                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]);
118                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
119                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
120                 data_o[j++] = 255;
121             }
122             out->empty = FALSE;
123             delete pl;
124             }
125             break;
126         case SPOT_LIGHT:
127             {
128             SpotLight *sl = new SpotLight(light.spot, lighting_color, trans);
129         //TODO we need a reference to the filter to determine primitiveUnits
130         //slot._arena_item->filter seems to be ok on simple examples
131         //for now assume userSpaceOnUse
132         //if objectBoundingBox is used, use a different matrix for light_vector
133             //finish the work
134             for (i = 0, j = 0; i < w*h; i++) {
135                 compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
136                 sl->light_vector(L,
137                     i % w + x0,
138                     i / w + y0,
139                     ss * (double) data_i[4*i+3]/ 255);
140                 sl->light_components(LC, L);
141                 COMPUTE_INTER(inter, N, L, kd);
142                 
143                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]);
144                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
145                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
146                 data_o[j++] = 255;
147             }
148             out->empty = FALSE;
149             delete sl;
150             }
151             break;
152         //else unknown light source, doing nothing
153         case NO_LIGHT:
154         default:
155             {
156             if (light_type != NO_LIGHT)
157                 g_warning("unknown light source %d", light_type);
158             for (i = 0; i < w*h; i++) {
159                 data_o[4*i+3] = 255;
160             }
161             out->empty = false;
162             }
163     }
164         
165     //finishing
166     slot.set(_output, out);
167     nr_pixblock_release(in);
168     delete in;
169     return 0;
172 } /* namespace NR */
174 /*
175   Local Variables:
176   mode:c++
177   c-file-style:"stroustrup"
178   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
179   indent-tabs-mode:nil
180   fill-column:99
181   End:
182 */
183 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :