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);
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 }
165 //finishing
166 slot.set(_output, out);
167 nr_pixblock_release(in);
168 delete in;
169 return 0;
170 }
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 :