convert line ends
[canaan.git] / prj / tech / libsrc / md / scale.c
blobd348aef61d4f5be90dd2fa725fd1a839de79238b
1 /*
2 * $Source: x:/prj/tech/libsrc/md/RCS/scale.c $
3 * $Revision: 1.6 $
4 * $Author: dc $
5 * $Date: 1997/07/03 04:26:20 $
7 * Model Library scaling routine
9 */
11 #include <string.h>
12 #include <math.h>
14 #include <lg.h>
15 #include <matrix.h>
16 #include <r3ds.h>
17 #include <md.h>
19 #define max(x,y) (((x)>(y))?(x):(y))
21 #ifndef SHIP
22 #define TEST_VERSION(fname,model) \
23 do { \
24 if (model->ver!=MD_CUR_VER) { \
25 char safename[10]; \
26 strncpy(safename,model->name,8); \
27 safename[8]='\0'; \
28 CriticalMsg3("%s: model %s is old version %d",fname,safename,model->ver); \
29 return model; \
30 } \
31 } while(0)
32 #else
33 #define TEST_VERSION(fname,model)
34 #endif
37 float radius_from_bbox(mxs_vector *bmin,mxs_vector *bmax)
39 float rad2,mn2,mx2;
41 // greatest x
42 mn2 = bmin->x*bmin->x;
43 mx2 = bmax->x*bmax->x;
44 rad2 = max(mn2,mx2);
46 // greatest y
47 mn2 = bmin->y*bmin->y;
48 mx2 = bmax->y*bmax->y;
49 rad2 += max(mn2,mx2);
51 // greatest z
52 mn2 = bmin->z*bmin->z;
53 mx2 = bmax->z*bmax->z;
54 rad2 += max(mn2,mx2);
56 // radius is dist from center to max point
57 return sqrt(rad2);
61 // Scale a model according to the scaling vector s. The scaling is
62 // done in source space. If the model *dst is NULL, it allocates memory
63 // for it
64 // light is whether or not to retransform the lighting vectors. Depending,
65 // you may actually want it to be the same, plus it's the slowest thing to
66 // do
67 mds_model *md_scale_model(mds_model *dst,mds_model *src,mxs_vector *s,bool light)
69 mds_vhot *v;
70 mxs_vector *pt;
71 mxs_vector sn; // normal scale factor
72 float sd; // plane scale factor
73 mds_pgon *pgon;
74 int i;
76 TEST_VERSION("md_scale_model",src);
78 // This is what normals get scaled by
79 sn.x = s->y*s->z;
80 sn.y = s->z*s->x;
81 sn.z = s->x*s->y;
83 sd = s->x*s->y*s->z;
85 if (dst == NULL) {
86 dst = Malloc(src->mod_size);
89 // copy it over
90 memcpy(dst,src,src->mod_size);
92 // Scale the bbox and pcen
93 mx_elmuleq_vec(&dst->bmin,s);
94 mx_elmuleq_vec(&dst->bmax,s);
95 mx_elmuleq_vec(&dst->pcen,s);
97 // Recompute bounding sphere
98 dst->radius = radius_from_bbox(&dst->bmin,&dst->bmax);
100 // Recompute max pgon radius, by putting bounding
101 // box around it and shrinking it
102 dst->max_pgon_radius *= mx_mag_vec(s);
104 // Scale the vhot lists
105 v = md_vhot_list(dst);
106 for (i=dst->vhots;i>0;--i) {
107 mx_elmuleq_vec(&v->v,s);
108 v++;
111 // Scale the points
112 pt = md_point_list(dst);
113 for (i=dst->verts;i>0;--i) {
114 mx_elmuleq_vec(pt,s);
115 pt++;
118 // lights, norms and pgons and nodes
119 // are done per subobj
121 for (i=0;i<dst->subobjs;++i) {
122 int j;
123 mxs_vector *norm;
124 mds_subobj *sb = &(md_subobj_list(dst)[i]);
125 uchar *n; // node
127 // Subobject header:
128 // trans.. gotta think about that...
129 // I think we just scale the offset
130 mx_elmuleq_vec(&(sb->trans.vec),s);
132 // These don't have to be normalized, but the d values
133 // need to be recomputed both in pgons and nodes
134 norm = md_norm_list(dst)+sb->norm_start;
135 for (j=sb->norm_num;j>0;--j) {
136 mx_elmuleq_vec(norm,&sn);
137 norm++;
140 // lighting normals:
141 if (light) {
142 mds_light *lt;
143 mxs_vector l;
145 lt = md_light_list(dst)+sb->light_start;
147 for (j=sb->light_num;j>0;--j) {
148 // Unpack the normal
149 l.x = X_NORM(lt->norm)*sn.x;
150 l.y = Y_NORM(lt->norm)*sn.y;
151 l.z = Z_NORM(lt->norm)*sn.z;
152 // renormalize
153 mx_normeq_vec(&l);
154 // repack
155 md_norm2light(&(lt->norm),&l);
156 lt++;
160 // Go through the nodes
162 n = (uchar *)dst + dst->node_off + sb->node_start;
163 for (j=sb->node_num;j>0;--j) {
164 switch (*n) {
165 case MD_NODE_SUBOBJ:
167 mds_node_subobj *node = (mds_node_subobj *)n;
168 n = (char *)(node+1);
169 ++j; // doesn't count
170 break;
172 case MD_NODE_VCALL:
174 mds_node_vcall *node = (mds_node_vcall *)n;
176 n = (char *)(node+1);
177 break;
179 case MD_NODE_CALL:
181 mds_node_call *node = (mds_node_call *)n;
183 n = (char *)(node+1);
184 n += (node->pgons_before+node->pgons_after)*sizeof(short);
185 break;
187 case MD_NODE_SPLIT:
189 mds_node_split *node = (mds_node_split *)n;
190 node->d *= sd;
191 n = (char *)(node+1);
192 n += (node->pgons_before+node->pgons_after)*sizeof(short);
193 break;
195 case MD_NODE_RAW:
197 mds_node_raw *node = (mds_node_raw *)n;
198 n = (char *)(node+1);
199 n += node->num*sizeof(short);
200 break;
206 // Go through the polygon list
207 // and touch up the d values
208 pgon = (mds_pgon *)(dst->pgon_off+(uchar*)dst);
209 for (i=dst->pgons;i>0;--i) {
210 uchar *next;
211 pgon->d *= sd;
212 next = (uchar *)pgon;
213 next += sizeof(mds_pgon);
214 next += 2*pgon->num*sizeof(ushort);
215 if ( ((pgon->type)&MD_PGON_PRIM_MASK)==MD_PGON_PRIM_TMAP) {
216 next += pgon->num * sizeof(ushort);
218 pgon = (mds_pgon *)next;
221 return dst;