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