1 /*
2 * 3D utils.
3 *
4 * Authors:
5 * Jean-Rene Reinhard <jr@komite.net>
6 *
7 * Copyright (C) 2007 authors
8 *
9 * Released under GNU GPL, read the file 'COPYING' for more information
10 */
12 #include <glib/gmessages.h>
14 #include "libnr/nr-pixblock.h"
15 #include "display/nr-3dutils.h"
16 #include <cmath>
18 namespace NR {
20 #define BEGIN 0 // TOP or LEFT
21 #define MIDDLE 1
22 #define END 2 // BOTTOM or RIGHT
24 #define START(v) ((v)==BEGIN? 1 : 0)
25 #define FINISH(v) ((v)==END? 1 : 2)
27 signed char K_X[3][3][3][3] = {
28 //K_X[TOP]
29 {
30 //K_X[TOP][LEFT]
31 {
32 { 0, 0, 0},
33 { 0, -2, 2},
34 { 0, -1, 1}
35 },
36 {
37 { 0, 0, 0},
38 {-2, 0, 2},
39 {-1, 0, 1}
40 },
41 {
42 { 0, 0, 0},
43 {-2, 2, 0},
44 {-1, 1, 0}
45 }
46 },
47 //K_X[MIDDLE]
48 {
49 //K_X[MIDDLE][LEFT]
50 {
51 { 0, -1, 1},
52 { 0, -2, 2},
53 { 0, -1, 1}
54 },
55 {
56 {-1, 0, 1},
57 {-2, 0, 2},
58 {-1, 0, 1}
59 },
60 {
61 {-1, 1, 0},
62 {-2, 2, 0},
63 {-1, 1, 0}
64 }
65 },
66 //K_X[BOTTOM]
67 {
68 //K_X[BOTTOM][LEFT]
69 {
70 { 0, -1, 1},
71 { 0, -2, 2},
72 { 0, 0, 0}
73 },
74 {
75 {-1, 0, 1},
76 {-2, 0, 2},
77 { 0, 0, 0}
78 },
79 {
80 {-1, 1, 0},
81 {-2, 2, 0},
82 { 0, 0, 0}
83 }
84 }
85 };
87 //K_Y is obtained by transposing K_X globally and each of its components
89 gdouble FACTOR_X[3][3] = {
90 {2./3, 1./3, 2./3},
91 {1./2, 1./4, 1./2},
92 {2./3, 1./3, 2./3}
93 };
95 //FACTOR_Y is obtained by transposing FACTOR_X
97 inline
98 int get_carac(int i, int len, int delta) {
99 if (i < delta)
100 return BEGIN;
101 else if (i > len - 1 - delta)
102 return END;
103 else
104 return MIDDLE;
105 }
107 //assumes in is RGBA
108 //should be made more resistant
109 void compute_surface_normal(Fvector &N, gdouble ss, NRPixBlock *in, int i, int j, int dx, int dy) {
110 int w = in->area.x1 - in->area.x0;
111 int h = in->area.y1 - in->area.y0;
112 int k, l, alpha_idx, alpha_idx_y;
113 int x_carac, y_carac;
114 gdouble alpha;
115 gdouble accu_x;
116 gdouble accu_y;
117 unsigned char *data = NR_PIXBLOCK_PX (in);
118 g_assert(NR_PIXBLOCK_BPP(in) == 4);
119 x_carac = get_carac(j, w, dx); //LEFT, MIDDLE or RIGHT
120 y_carac = get_carac(i, h, dy); //TOP, MIDDLE or BOTTOM
121 alpha_idx = 4*(i*w + j);
122 accu_x = 0;
123 accu_y = 0;
124 for (k = START(y_carac); k <= FINISH(y_carac); k++) {
125 alpha_idx_y = alpha_idx + 4*(k-1)*dy*w;
126 for (l = START(x_carac); l <= FINISH(x_carac); l++) {
127 alpha = (data + alpha_idx_y + 4*dx*(l-1))[3];
128 accu_x += K_X[y_carac][x_carac][k][l] * alpha / 255;
129 accu_y += K_X[x_carac][y_carac][l][k] * alpha / 255;
130 }
131 }
132 N[X_3D] = -1 * ss * FACTOR_X[y_carac][x_carac] * accu_x / dx;
133 N[Y_3D] = -1 * ss * FACTOR_X[x_carac][y_carac] * accu_y / dy;
134 N[Z_3D] = 1;
135 normalize_vector(N);
136 //std::cout << "(" << N[X_3D] << ", " << N[Y_3D] << ", " << N[Z_3D] << ")" << std::endl;
137 }
139 void convert_coord(gdouble &x, gdouble &y, gdouble &z, Geom::Matrix const &trans) {
140 Point p = Point(x, y);
141 p *= trans;
142 x = p[Geom::X];
143 y = p[Geom::Y];
144 z *= trans[0];
145 }
147 gdouble norm(const Fvector &v) {
148 return sqrt(v[X_3D]*v[X_3D] + v[Y_3D]*v[Y_3D] + v[Z_3D]*v[Z_3D]);
149 }
151 void normalize_vector(Fvector &v) {
152 gdouble nv = norm(v);
153 //TODO test nv == 0
154 for (int j = 0; j < 3; j++) {
155 v[j] /= nv;
156 }
157 }
159 gdouble scalar_product(const Fvector &a, const Fvector &b) {
160 return a[X_3D] * b[X_3D] +
161 a[Y_3D] * b[Y_3D] +
162 a[Z_3D] * b[Z_3D];
163 }
165 void normalized_sum(Fvector &r, const Fvector &a, const Fvector &b) {
166 r[X_3D] = a[X_3D] + b[X_3D];
167 r[Y_3D] = a[Y_3D] + b[Y_3D];
168 r[Z_3D] = a[Z_3D] + b[Z_3D];
169 normalize_vector(r);
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 :