1 /*
2 * mapping.c
3 *
4 * Copyright (C) 1989, 1991, Craig E. Kolb
5 * All rights reserved.
6 *
7 * This software may be freely copied, modified, and redistributed
8 * provided that this copyright notice is preserved on all copies.
9 *
10 * You may not distribute this software, in whole or in part, as part of
11 * any commercial product without the express consent of the authors.
12 *
13 * There is no warranty or other guarantee of fitness of this software
14 * for any purpose. It is provided solely "as is".
15 *
16 * $Id: mapping.c,v 4.0 91/07/17 14:42:54 kolb Exp Locker: kolb $
17 *
18 * $Log: mapping.c,v $
19 * Revision 4.0 91/07/17 14:42:54 kolb
20 * Initial version.
21 *
22 */
23 #include "libobj/geom.h"
24 #include "mapping.h"
25
26 void UVMapping(), SphereMapping(), CylinderMapping(), LinearMapping();
27
28 Mapping *
UVMappingCreate()29 UVMappingCreate()
30 {
31 Mapping *res;
32
33 res = (Mapping *)Malloc(sizeof(Mapping));
34 res->flags = PRIMSPACE;
35 res->method = UVMapping;
36 return res;
37 }
38
39 Mapping *
SphereMappingCreate(center,norm,uaxis)40 SphereMappingCreate(center, norm, uaxis)
41 Vector *center, *norm, *uaxis;
42 {
43 Mapping *res;
44
45 res = (Mapping *)Malloc(sizeof(Mapping));
46 res->flags = OBJSPACE;
47 res->method = SphereMapping;
48 if (center)
49 res->center = *center;
50 else
51 res->center.x = res->center.y = res->center.z = 0.;
52 if (norm && uaxis) {
53 res->norm = *norm;
54 if (VecNormalize(&res->norm) == 0.) {
55 RLerror(RL_ABORT, "Degenerate mapping vector.\n");
56 return (Mapping *)NULL;
57 }
58 if (VecNormCross(norm, uaxis, &res->vaxis) == 0.) {
59 RLerror(RL_ABORT, "Degenerate mapping vector.\n");
60 return (Mapping *)NULL;
61 }
62 (void)VecNormCross(&res->vaxis, norm, &res->uaxis);
63 } else {
64 res->norm.x = res->norm.y = res->uaxis.y = res->uaxis.z =
65 res->vaxis.x = res->vaxis.z = 0.;
66 res->norm.z = res->uaxis.x = res->vaxis.y = 1.;
67 }
68 return res;
69 }
70
71 Mapping *
CylMappingCreate(center,norm,uaxis)72 CylMappingCreate(center, norm, uaxis)
73 Vector *center, *norm, *uaxis;
74 {
75 Mapping *res;
76
77 res = (Mapping *)Malloc(sizeof(Mapping));
78 res->flags = OBJSPACE;
79 res->method = CylinderMapping;
80 if (center)
81 res->center = *center;
82 else
83 res->center.x = res->center.y = res->center.z = 0.;
84 if (norm && uaxis) {
85 res->norm = *norm;
86 if (VecNormalize(&res->norm) == 0.) {
87 RLerror(RL_ABORT, "Degenerate mapping vector.\n");
88 return (Mapping *)NULL;
89 }
90 /*
91 * Here, uaxis indicates where theta (u) = 0.
92 */
93 if (VecNormCross(norm, uaxis, &res->vaxis) == 0.) {
94 RLerror(RL_ABORT, "Degenerate mapping vector.\n");
95 return (Mapping *)NULL;
96 }
97 (void)VecNormCross(&res->vaxis, norm, &res->uaxis);
98 } else {
99 res->norm.x = res->norm.y = res->uaxis.y = res->uaxis.z =
100 res->vaxis.x = res->vaxis.z = 0.;
101 res->norm.z = res->uaxis.x = res->vaxis.y = 1.;
102 }
103 return res;
104 }
105
106 Mapping *
LinearMappingCreate(center,vaxis,uaxis)107 LinearMappingCreate(center, vaxis, uaxis)
108 Vector *center, *vaxis, *uaxis;
109 {
110 Mapping *res;
111 RSMatrix m;
112 Vector n;
113
114 res = (Mapping *)Malloc(sizeof(Mapping));
115 res->flags = OBJSPACE;
116 res->method= LinearMapping;
117
118 if (center)
119 res->center = *center;
120 else
121 res->center.x = res->center.y = res->center.z = 0.;
122
123 if (uaxis && vaxis) {
124 VecCross(uaxis, vaxis, &n);
125 /* this is wrong, since uaxis and vaxis
126 * give U and V in world space, and we
127 * need the inverse.
128 */
129 ArbitraryMatrix(
130 uaxis->x, uaxis->y, uaxis->z,
131 vaxis->x, vaxis->y, vaxis->z,
132 n.x, n.y, n.z,
133 res->center.x, res->center.y, res->center.z,
134 &m);
135 MatrixInvert(&m, &res->m);
136 res->uaxis = *uaxis;
137 res->vaxis = *vaxis;
138 VecNormalize(&res->uaxis);
139 VecNormalize(&res->vaxis);
140 } else {
141 VecScale(-1., res->center, &n);
142 TranslationMatrix(n.x, n.y, n.z, &res->m);
143 res->uaxis.x = res->vaxis.y = 1.;
144 res->uaxis.y = res->uaxis.z = res->vaxis.x =
145 res->vaxis.z = 0.;
146 }
147 return res;
148 }
149
150 void
UVMapping(map,obj,pos,norm,uv,dpdu,dpdv)151 UVMapping(map, obj, pos, norm, uv, dpdu, dpdv)
152 Mapping *map;
153 Geom *obj;
154 Vec2d *uv;
155 Vector *pos, *norm, *dpdu, *dpdv;
156 {
157 PrimUV(obj, pos, norm, uv, dpdu, dpdv);
158 }
159
160 void
SphereMapping(map,obj,pos,norm,uv,dpdu,dpdv)161 SphereMapping(map, obj, pos, norm, uv, dpdu, dpdv)
162 Mapping *map;
163 Geom *obj;
164 Vec2d *uv;
165 Vector *pos, *norm, *dpdu, *dpdv;
166 {
167 Vector vtmp;
168 Float nx, ny, nz, phi, theta;
169
170 VecSub(*pos, map->center, &vtmp);
171 if (VecNormalize(&vtmp) == 0.) {
172 /*
173 * Point is coincident with origin of sphere. Punt.
174 */
175 uv->u = uv->v = 0.;
176 return;
177 }
178
179 /*
180 * Find location of point projected onto unit sphere
181 * in the sphere's coordinate system.
182 */
183 nx = dotp(&map->uaxis, &vtmp);
184 ny = dotp(&map->vaxis, &vtmp);
185 nz = dotp(&map->norm, &vtmp);
186
187 if (nz > 1.) /* roundoff */
188 phi = PI;
189 else if (nz < -1.)
190 phi = 0;
191 else
192 phi = acos(-nz);
193
194 uv->v = phi / PI;
195
196 if (fabs(uv->v) < EPSILON || equal(uv->v, 1.))
197 uv->u = 0.;
198 else {
199 theta = nx / sin(phi);
200 if (theta > 1.)
201 theta = 0.;
202 else if (theta < -1.)
203 theta = 0.5;
204 else
205 theta = acos(theta) / TWOPI;
206
207 if (ny > 0)
208 uv->u = theta;
209 else
210 uv->u = 1 - theta;
211 }
212 }
213
214 void
CylinderMapping(map,obj,pos,norm,uv,dpdu,dpdv)215 CylinderMapping(map, obj, pos, norm, uv, dpdu, dpdv)
216 Mapping *map;
217 Geom *obj;
218 Vec2d *uv;
219 Vector *pos, *norm, *dpdu, *dpdv;
220 {
221 Vector vtmp;
222 Float nx, ny, r;
223
224 VecSub(*pos, map->center, &vtmp);
225 nx = dotp(&map->uaxis, &vtmp);
226 ny = dotp(&map->vaxis, &vtmp);
227 uv->v = dotp(&map->norm, &vtmp);
228
229 r = sqrt(nx*nx + ny*ny);
230
231 if (r < EPSILON) {
232 uv->u = 0.;
233 return;
234 }
235
236 nx /= r;
237 ny /= r;
238
239 if (fabs(nx) > 1.)
240 uv->u = 0.5;
241 else
242 uv->u = acos(nx) / TWOPI;
243 if (ny < 0.)
244 uv->u = 1. - uv->u;
245
246 if (dpdv)
247 *dpdv = map->norm;
248 if (dpdu)
249 (void)VecNormCross(&map->norm, pos, dpdu);
250 }
251
252 void
LinearMapping(map,obj,pos,norm,uv,dpdu,dpdv)253 LinearMapping(map, obj, pos, norm, uv, dpdu, dpdv)
254 Mapping *map;
255 Geom *obj;
256 Vec2d *uv;
257 Vector *pos, *norm, *dpdu, *dpdv;
258 {
259 Vector vtmp;
260
261 vtmp = *pos;
262 VecTransform(&vtmp, &map->m);
263 uv->u = vtmp.x; uv->v = vtmp.y;
264
265 if (dpdu) {
266 *dpdu = map->uaxis;
267 }
268 if (dpdv) {
269 *dpdv = map->vaxis;
270 }
271 }
272