1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8 /*
9 * $Header: /src/master/dx/src/exec/dxmods/shade.c,v 1.6 2006/01/03 17:02:25 davidt Exp $
10 */
11
12 #include <dxconfig.h>
13
14 #if defined(HAVE_STRING_H)
15 #include <string.h>
16 #endif
17
18 #include <stdio.h>
19 #include <math.h>
20 #include <dx/dx.h>
21 #include "_normals.h"
22
23 static Error ShadeField(Field, float, int, float, float);
24 static Error DoNormals(Object, int, char *, int);
25 static Error ShadeIt(Object, int, char *, float, int, float, float, int);
26 static Error CheckNormalsDirection(Object, int);
27 static Error CheckNormalsDirectionField(Field, int);
28
29 Error
m_Shade(Object * in,Object * out)30 m_Shade(Object *in, Object *out)
31 {
32 int shade, shininess, flipfront;
33 char *how;
34 float specular, ambient, diffuse;
35 Object outo=NULL;
36
37
38
39 if (!in[0]) {
40 DXSetError(ERROR_BAD_PARAMETER, "object must be specified");
41 return ERROR;
42 }
43
44
45 /* shade param */
46 if (!in[1]) {
47 shade = 1;
48 }
49 else {
50 if (!DXExtractInteger(in[1], &shade)) {
51 DXSetError(ERROR_BAD_PARAMETER,"shade must be either 0 or 1");
52 goto error;
53 }
54 }
55 if ((shade < 0)||(shade > 1)) {
56 DXSetError(ERROR_BAD_PARAMETER,"shade must be either 0 or 1");
57 goto error;
58 }
59
60
61 /* how param */
62 if (!in[2]) {
63 how = "default";
64 }
65 else {
66 if (!DXExtractString(in[2], &how)) {
67 DXSetError(ERROR_BAD_PARAMETER,
68 "how must be either `faceted' or `smooth'");
69 goto error;
70 }
71 /* XXX convert to lower case */
72 if (strcmp(how,"faceted")&&(strcmp(how,"smooth"))) {
73 DXSetError(ERROR_BAD_PARAMETER,
74 "how must be either `faceted' or `smooth'");
75 goto error;
76 }
77 }
78 if (in[2] && (shade==0)) {
79 DXWarning("how is ignored because shade is equal to 0");
80 }
81
82
83 /* specular param */
84 if (!in[3]) {
85 specular = -1.0;
86 }
87 else {
88 if (!DXExtractFloat(in[3], &specular)) {
89 DXSetError(ERROR_BAD_PARAMETER,
90 "specular must be a non-negative scalar value");
91 goto error;
92 }
93 if (specular < 0) {
94 DXSetError(ERROR_BAD_PARAMETER,
95 "specular must be a non-negative scalar value");
96 goto error;
97 }
98 }
99
100
101 /* shininess */
102 if (!in[4]) {
103 shininess = -1;
104 }
105 else {
106 if (!DXExtractInteger(in[4], &shininess)) {
107 DXSetError(ERROR_BAD_PARAMETER,
108 "shininess must be a non-negative integer");
109 goto error;
110 }
111 if (shininess < 0) {
112 DXSetError(ERROR_BAD_PARAMETER,
113 "shininess must be a non-negative integer");
114 goto error;
115 }
116 }
117
118
119 /* diffuse param */
120 if (!in[5]) {
121 diffuse = -1.0;
122 }
123 else {
124 if (!DXExtractFloat(in[5], &diffuse)) {
125 DXSetError(ERROR_BAD_PARAMETER,
126 "diffuse must be a non-negative scalar value");
127 goto error;
128 }
129 if (diffuse < 0) {
130 DXSetError(ERROR_BAD_PARAMETER,
131 "diffuse must be a non-negative scalar value");
132 goto error;
133 }
134 }
135
136 /* ambient param */
137 if (!in[6]) {
138 ambient = -1.0;
139 }
140 else {
141 if (!DXExtractFloat(in[6], &ambient)) {
142 DXSetError(ERROR_BAD_PARAMETER,
143 "ambient must be a non-negative scalar value");
144 goto error;
145 }
146 if (ambient < 0) {
147 DXSetError(ERROR_BAD_PARAMETER,
148 "ambient must be a non-negative scalar value");
149 goto error;
150 }
151 }
152
153 /* whether or not to flip front and back */
154 flipfront = 0;
155
156 if (!(outo = DXCopy(in[0], COPY_STRUCTURE)))
157 goto error;
158
159 /* do the stuff with normals (must be done at the field level) */
160
161 if (!ShadeIt(outo, shade, how, specular, shininess, diffuse, ambient,
162 flipfront))
163 goto error;
164
165
166 out[0] = outo;
167 return OK;
168
169 error:
170 DXDelete((Object)outo);
171 return ERROR;
172 }
173
174
ShadeIt(Object obj,int shade,char * how,float specular,int shininess,float diffuse,float ambient,int flipfront)175 static Error ShadeIt(Object obj, int shade, char *how, float specular,
176 int shininess, float diffuse, float ambient,
177 int flipfront)
178 {
179 Object child;
180 int i;
181
182 switch (DXGetObjectClass(obj)) {
183 case (CLASS_FIELD):
184 /* do the normals stuff here */
185 if (!DoNormals((Object)obj, shade, how, flipfront))
186 goto error;
187 if (!ShadeField((Field)obj, specular, shininess,
188 diffuse, ambient))
189 goto error;
190 break;
191 case (CLASS_GROUP):
192 switch (DXGetGroupClass((Group)obj)) {
193 case (CLASS_COMPOSITEFIELD):
194 /* do the normals stuff here, then continue through the
195 composite field */
196 if (!DoNormals((Object)obj, shade, how, flipfront))
197 goto error;
198 for (i=0; (child=DXGetEnumeratedMember((Group)obj,i,NULL));i++){
199 if (!ShadeField((Field)child, specular, shininess, diffuse,
200 ambient))
201 goto error;
202 }
203 break;
204 default:
205 for (i=0; (child=DXGetEnumeratedMember((Group)obj,i,NULL)); i++) {
206 if (!ShadeIt(child, shade, how, specular, shininess,
207 diffuse, ambient, flipfront))
208 goto error;
209 }
210 break;
211 }
212 break;
213 case (CLASS_XFORM):
214 if (!DXGetXformInfo((Xform)obj, &child, NULL))
215 goto error;
216 if (!ShadeIt(child, shade, how, specular, shininess, diffuse,
217 ambient, flipfront))
218 goto error;
219 break;
220 case (CLASS_CLIPPED):
221 if (!DXGetClippedInfo((Clipped)obj, &child, NULL))
222 goto error;
223 if (!ShadeIt(child, shade, how, specular, shininess, diffuse,
224 ambient, flipfront))
225 goto error;
226 break;
227 case (CLASS_SCREEN):
228 if (!DXGetScreenInfo((Screen)obj, &child, NULL, NULL))
229 goto error;
230 if (!ShadeIt(child, shade, how, specular, shininess, diffuse,
231 ambient, flipfront))
232 goto error;
233 break;
234 default:
235 DXSetError(ERROR_DATA_INVALID,
236 "object must be a field, group, xform, or clipped object");
237 goto error;
238 }
239
240 return OK;
241
242 error:
243 return ERROR;
244
245 }
246
ShadeField(Field field,float specular,int shininess,float diffuse,float ambient)247 static Error ShadeField(Field field, float specular,
248 int shininess, float diffuse, float ambient)
249 {
250 /* set all the rendering attributes */
251 if (specular != -1.0)
252 if (!DXSetFloatAttribute((Object)field, "specular", specular))
253 goto error;
254 if (shininess != -1)
255 if (!DXSetIntegerAttribute((Object)field, "shininess", shininess))
256 goto error;
257 if (diffuse != -1)
258 if (!DXSetFloatAttribute((Object)field, "diffuse", diffuse))
259 goto error;
260 if (ambient != -1)
261 if (!DXSetFloatAttribute((Object)field, "ambient", ambient))
262 goto error;
263
264 if (!DXEndField(field))
265 goto error;
266 return OK;
267
268 error:
269 return ERROR;
270
271 }
272
DoNormals(Object obj,int shade,char * how,int flipfront)273 static Error DoNormals(Object obj, int shade, char *how, int flipfront)
274 {
275 int i;
276 char *attr;
277 Field first, child;
278 int shadeattribute;
279
280 /* this is called at the Field or Composite field level */
281
282
283 switch (DXGetObjectClass(obj)) {
284 case CLASS_FIELD:
285
286
287 /* if we don't want the object shaded... */
288 /* regardless of what how is, make sure either there aren't any normals,
289 * or if there are, that the "no shade" attribute is set */
290 if (shade == 0) {
291 /* if there are normals, we need to disable them */
292 if (DXGetComponentValue((Field)obj, "normals")) {
293 if (!DXSetIntegerAttribute((Object)obj, "shade", 0))
294 goto error;
295 }
296 }
297
298 /* we want the object shaded */
299 else if (shade==1) {
300 /* if there's a shade=0 attribute set, set it to 1 */
301 if (DXGetAttribute((Object)obj,"shade")) {
302 if (!DXGetIntegerAttribute((Object)obj, "shade", &shadeattribute))
303 goto error;
304 if (shadeattribute==0) {
305 /* set it to 1 */
306 if (!DXSetIntegerAttribute((Object)obj, "shade", 1))
307 goto error;
308 }
309 else if (shadeattribute != 1) {
310 DXSetError(ERROR_DATA_INVALID,
311 "invalid shade attribute, must be 0 or 1");
312 goto error;
313 }
314 }
315 if (!strcmp(how, "default")) {
316 /* only do something if there aren't any normals. otherwise
317 * do nothing */
318 if (!DXGetComponentValue((Field)obj, "normals")) {
319
320 /* follow data if present */
321 if (DXGetComponentValue((Field)obj,"data")) {
322 attr = DXGetString((String)DXGetComponentAttribute((Field)obj,
323 "data","dep"));
324 if (!attr) {
325 DXSetError(ERROR_MISSING_DATA,
326 "missing data dependent attribute");
327 goto error;
328 }
329 }
330 else {
331 attr = "positions";
332 }
333
334 if (!_dxfNormalsObject((Object)obj, attr))
335 goto error;
336 }
337 else {
338 /* check whether the normals are consistent with the connections */
339 if (!CheckNormalsDirection(obj, flipfront))
340 goto error;
341 }
342 }
343 else if (!strcmp(how,"faceted")) {
344 /* call normals dep connections (make sure this routine does the
345 * check whether they are there already) */
346 if (!_dxfNormalsObject((Object)obj,"connections"))
347 goto error;
348 }
349 else if (!strcmp(how,"smooth")) {
350 /* call normals dep positions (make sure this routine does the
351 * check whether they are there already) */
352 if (!_dxfNormalsObject((Object)obj,"positions"))
353 goto error;
354 }
355 break;
356 case (CLASS_GROUP):
357 /* it's a composite field */
358 if (shade == 0) {
359 /* if there are normals, we need to disable them */
360 first = (Field)DXGetEnumeratedMember((Group)obj, 0, NULL);
361 /* if there are normals, we need to disable them */
362 if (DXGetComponentValue(first, "normals")) {
363
364 for (i=0; (child=(Field)DXGetEnumeratedMember((Group)obj,i,NULL));i++){
365 if (!DXSetIntegerAttribute((Object)child, "shade", 0))
366 goto error;
367 }
368 }
369 }
370 /* we want the object shaded */
371 else if (shade==1) {
372 if (!strcmp(how, "default")) {
373 /* only do something if there aren't any normals. otherwise
374 * do nothing */
375 first = (Field)DXGetEnumeratedMember((Group)obj, 0, NULL);
376 if (!DXGetComponentValue(first, "normals")) {
377
378 /* follow data if present */
379 if (DXGetComponentValue(first,"data")) {
380 attr = DXGetString((String)DXGetComponentAttribute(first,
381 "data",
382 "dep"));
383 if (!attr) {
384 DXSetError(ERROR_MISSING_DATA,
385 "missing data dependent attribute");
386 goto error;
387 }
388 }
389 else {
390 attr = "positions";
391 }
392
393 /* call normals on the composite field */
394 if (!_dxfNormalsObject(obj, attr))
395 goto error;
396 }
397 else {
398 /* check whether the normals are consistent with the connections */
399 if (!CheckNormalsDirection(obj, flipfront))
400 goto error;
401 }
402 }
403 else if (!strcmp(how,"faceted")) {
404 /* call normals dep connections (make sure this routine does the
405 * check whether they are there already) */
406 if (!_dxfNormalsObject((Object)obj,"connections"))
407 goto error;
408 }
409 else if (!strcmp(how,"smooth")) {
410 /* call normals dep positions (make sure this routine does the
411 * check whether they are there already) */
412 if (!_dxfNormalsObject((Object)obj,"positions"))
413 goto error;
414 }
415 }
416 }
417 break;
418 default:
419 break;
420 }
421
422 return OK;
423 error:
424 return ERROR;
425
426 }
427
428
429 /* this routine checks the normals against the direction of the
430 connections. If they disagree, it fixes the normals. This can
431 be called on either a field or a composite field. */
CheckNormalsDirection(Object obj,int flipfront)432 static Error CheckNormalsDirection(Object obj, int flipfront)
433 {
434 int i;
435 Object child;
436
437 switch (DXGetObjectClass(obj)) {
438 case (CLASS_FIELD):
439 if (!CheckNormalsDirectionField((Field)obj, flipfront))
440 goto error;
441 break;
442 case (CLASS_GROUP):
443 if (DXGetGroupClass((Group)obj) != CLASS_COMPOSITEFIELD) {
444 DXSetError(ERROR_UNEXPECTED,"unexpected class in CheckNormalsDirection");
445 goto error;
446 }
447 for (i=0; (child = DXGetEnumeratedMember((Group)obj,i,NULL));i++){
448 if (!CheckNormalsDirectionField((Field)child, flipfront))
449 goto error;
450 }
451 break;
452 default:
453 DXSetError(ERROR_UNEXPECTED,"unexpected class in CheckNormalsDirection");
454 goto error;
455
456 }
457
458 return OK;
459 error:
460 return ERROR;
461 }
462
CheckNormalsDirectionField(Field obj,int flipfront)463 static Error CheckNormalsDirectionField(Field obj, int flipfront)
464 {
465 Array connections, normals, positions, newnormals=NULL, newconnections=NULL;
466 Point *pos1, *pos2, *pos3, *norm, vec1, vec2, crossprod, newnormal;
467 Point position1, position2, position3;
468 Vector zerovec={0.0, 0.0, 0.0};
469 char *str1, *str2;
470 Object dep, eType;
471 ArrayHandle positionshandle=NULL, normalshandle=NULL, connectionshandle=NULL;
472 int rank, shape[10], *connections_ptr, conn1, conn2, conn3;
473 int numitems, i=0, *cptr1, numcon, scratchtri[3];
474 int scratchquad[4];
475 float dotprod, scratch[3];
476 Triangle newtri, *triptr=NULL;
477 Quadrilateral newquad, *quadptr=NULL;
478
479 /* get the connections component */
480 connections = (Array)DXGetComponentValue(obj, "connections");
481 if (!connections) {
482 goto done;
483 }
484 if (!DXGetArrayInfo(connections, &numcon, NULL, NULL, NULL, NULL))
485 goto error;
486 /* get the element type attribute */
487 eType = DXGetAttribute((Object)connections, "element type");
488 if (! eType || DXGetObjectClass(eType) != CLASS_STRING) {
489 DXSetError(ERROR_DATA_INVALID,
490 "invalid or missing element type attribute");
491 goto error;
492 }
493 str1 = DXGetString((String)eType);
494 /* what about faces XXX ? */
495 if (strcmp(str1, "quads") && strcmp(str1, "triangles"))
496 goto done;
497
498
499 connectionshandle = DXCreateArrayHandle(connections);
500 if (!connectionshandle)
501 goto error;
502
503 /* first do the flipping on the connections. That way we only
504 flip the normals once */
505 if (flipfront) {
506 if (!strcmp(str1,"triangles")) {
507 newconnections = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 3);
508 if (!newconnections)
509 goto error;
510 if (!DXAddArrayData(newconnections, 0, numcon, NULL))
511 goto error;
512 for (i=0; i<numcon; i++) {
513 if (NULL ==
514 (triptr = DXIterateArray(connectionshandle, i,
515 triptr, (Pointer)scratchtri)))
516 goto error;
517 newtri.p = triptr->p;
518 newtri.q = triptr->r;
519 newtri.r = triptr->q;
520 if (!DXAddArrayData(newconnections, i, 1, &newtri))
521 goto error;
522 }
523 }
524 else { /* quads */
525 /* else I'll treat it as irregular XXX */
526 newconnections = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 4);
527 if (!newconnections)
528 goto error;
529 if (!DXAddArrayData(newconnections, 0, numcon, NULL))
530 goto error;
531 for (i=0; i<numcon; i++) {
532 if (NULL ==
533 (quadptr = DXIterateArray(connectionshandle, i,
534 quadptr, (Pointer)scratchquad)))
535 goto error;
536 /* XXX this is irregular */
537 newquad.p = quadptr->r;
538 newquad.q = quadptr->s;
539 newquad.r = quadptr->p;
540 newquad.s = quadptr->q;
541 if (!DXAddArrayData(newconnections, i, 1, &newquad))
542 goto error;
543 }
544 }
545 if (!DXSetComponentValue(obj, "connections", (Object)newconnections))
546 goto error;
547 newconnections = NULL;
548 DXChangedComponentValues(obj,"connections");
549 connections = (Array)DXGetComponentValue(obj, "connections");
550 connectionshandle = DXCreateArrayHandle(connections);
551 if (!connectionshandle)
552 goto error;
553 }
554
555 /* get the dependency attribute of the normals */
556 normals = (Array)DXGetComponentValue(obj, "normals");
557 if (!normals) {
558 /* I don't think this should happen, but if it does, it's ok */
559 goto done;
560 }
561
562 dep = DXGetAttribute((Object)normals, "dep");
563 if (! dep || DXGetObjectClass(dep) != CLASS_STRING) {
564 DXSetError(ERROR_DATA_INVALID,
565 "invalid or missing normals dep attribute");
566 goto error;
567 }
568 str2 = DXGetString((String)dep);
569 if (strcmp(str2, "positions") && strcmp(str2, "connections")) {
570 DXSetError(ERROR_DATA_INVALID,"unrecognized normals dep attribute");
571 goto error;
572 }
573
574 positions = (Array)DXGetComponentValue(obj, "positions");
575 if (!positions) {
576 goto done;
577 }
578
579
580 positionshandle = DXCreateArrayHandle(positions);
581 if (!positionshandle)
582 goto error;
583 if (!DXGetArrayInfo(positions, NULL, NULL, NULL, &rank, shape))
584 goto error;
585 if (rank != 1) {
586 DXSetError(ERROR_DATA_INVALID,"rank %d positions not supported", rank);
587 goto error;
588 }
589
590 normalshandle = DXCreateArrayHandle(normals);
591 if (!normalshandle)
592 goto error;
593 if (!DXGetArrayInfo(normals, &numitems, NULL, NULL, NULL, NULL))
594 goto error;
595
596 if ((shape[0] != 2)&&(shape[0] != 3)) {
597 DXSetError(ERROR_DATA_INVALID,
598 "only 2D and 3D positions supported for quads and triangles");
599 goto error;
600 }
601
602 if (!strcmp(str1, "triangles")) {
603 /* check the first triangle */
604 connections_ptr = (int *)DXGetArrayData(connections);
605 conn1 = connections_ptr[0];
606 conn2 = connections_ptr[1];
607 conn3 = connections_ptr[2];
608
609 if (NULL == (pos1 = DXGetArrayEntry(positionshandle, conn1, scratch)))
610 goto error;
611 if (shape[0]==2)
612 position1 = DXPt(pos1->x, pos1->y, 0.0);
613 else
614 position1 = DXPt(pos1->x, pos1->y, pos1->z);
615
616 if (NULL == (pos2 = DXGetArrayEntry(positionshandle, conn2, scratch)))
617 goto error;
618 if (shape[0]==2)
619 position2 = DXPt(pos2->x, pos2->y, 0.0);
620 else
621 position2 = DXPt(pos2->x, pos2->y, pos2->z);
622
623 if (NULL == (pos3 = DXGetArrayEntry(positionshandle, conn3, scratch)))
624 goto error;
625 if (shape[0]==2)
626 position3 = DXPt(pos3->x, pos3->y, 0.0);
627 else
628 position3 = DXPt(pos3->x, pos3->y, pos3->z);
629
630 vec1 = DXSub(position2, position1);
631 vec2 = DXSub(position3, position2);
632 crossprod = DXCross(vec1, vec2);
633
634 /* now grab an appropriate normal */
635 if (!strcmp(str2,"positions")) {
636 if (NULL ==
637 (norm = DXGetArrayEntry(normalshandle, conn1, scratch)))
638 goto error;
639 }
640 else {
641 if (NULL ==
642 (norm = DXGetArrayEntry(normalshandle, 0, (Pointer)scratch)))
643 goto error;
644 }
645
646 /* check the dot product of the normal with crossprod. Should be + */
647 dotprod = DXDot(crossprod, *norm);
648 if (dotprod > 0)
649 goto done;
650 else {
651 /* flip the normals */
652 switch (DXGetArrayClass(normals)) {
653 case (CLASS_CONSTANTARRAY):
654 if (NULL ==
655 (norm = DXIterateArray(normalshandle, i,
656 norm, (Pointer)scratch)))
657 goto error;
658 newnormal = DXSub(zerovec, *norm);
659 newnormals = (Array)DXNewConstantArray(numitems, &newnormal, TYPE_FLOAT,
660 CATEGORY_REAL, 1, 3);
661 break;
662 default:
663 newnormals = DXNewArray(TYPE_FLOAT,CATEGORY_REAL, 1, 3);
664 if (!DXAddArrayData(newnormals, 0, numitems, NULL))
665 goto error;
666 for (i=0; i<numitems; i++) {
667 if (NULL ==
668 (norm = DXIterateArray(normalshandle, i,
669 norm, (Pointer)scratch)))
670 goto error;
671 newnormal = DXSub(zerovec, *norm);
672 if (!DXAddArrayData(newnormals, i, 1, &newnormal))
673 goto error;
674 }
675 break;
676 }
677 if (!DXSetComponentValue(obj, "normals", (Object)newnormals))
678 goto error;
679 newnormals = NULL;
680 DXChangedComponentValues(obj,"normals");
681 }
682 }
683 else {
684 /* check the first quad */
685
686 if (NULL==(cptr1 = DXGetArrayEntry(connectionshandle, 0, scratchquad)))
687 goto error;
688 if (NULL == (pos1 = DXGetArrayEntry(positionshandle, cptr1[0], scratch)))
689 goto error;
690 if (shape[0]==2)
691 position1 = DXPt(pos1->x, pos1->y, 0.0);
692 else
693 position1 = DXPt(pos1->x, pos1->y, pos1->z);
694
695 if (NULL == (pos2 = DXGetArrayEntry(positionshandle, cptr1[1], scratch)))
696 goto error;
697 if (shape[0]==2)
698 position2 = DXPt(pos2->x, pos2->y, 0.0);
699 else
700 position2 = DXPt(pos2->x, pos2->y, pos2->z);
701
702 if (NULL == (pos3 = DXGetArrayEntry(positionshandle, cptr1[2], scratch)))
703 goto error;
704 if (shape[0]==2)
705 position3 = DXPt(pos3->x, pos3->y, 0.0);
706 else
707 position3 = DXPt(pos3->x, pos3->y, pos3->z);
708
709
710 vec1 = DXSub(position3, position1);
711 vec2 = DXSub(position2, position1);
712 crossprod = DXCross(vec1, vec2);
713
714 /* now grab an appropriate normal */
715 if (!strcmp(str2,"positions")) {
716 if (NULL ==
717 (norm = DXGetArrayEntry(normalshandle, *cptr1, scratch)))
718 goto error;
719 }
720 else {
721 if (NULL ==
722 (norm = DXGetArrayEntry(normalshandle, 0, (Pointer)scratch)))
723 goto error;
724 }
725
726 /* check the dot product of the normal with crossprod. Should be + */
727 dotprod = DXDot(crossprod, *norm);
728 if (dotprod > 0)
729 goto done;
730 else {
731 /* flip the normals */
732 switch (DXGetArrayClass(normals)) {
733 case (CLASS_CONSTANTARRAY):
734 if (NULL ==
735 (norm = DXIterateArray(normalshandle, i,
736 norm, (Pointer)scratch)))
737 goto error;
738 newnormal = DXSub(zerovec, *norm);
739 newnormals = (Array)DXNewConstantArray(numitems, &newnormal, TYPE_FLOAT,
740 CATEGORY_REAL, 1, 3);
741 break;
742 default:
743 newnormals = DXNewArray(TYPE_FLOAT,CATEGORY_REAL, 1, 3);
744 if (!DXAddArrayData(newnormals, 0, numitems, NULL))
745 goto error;
746 for (i=0; i<numitems; i++) {
747 if (NULL ==
748 (norm = DXIterateArray(normalshandle, i,
749 norm, (Pointer)scratch)))
750 goto error;
751 newnormal = DXSub(zerovec, *norm);
752 if (!DXAddArrayData(newnormals, i, 1, &newnormal))
753 goto error;
754 }
755 break;
756 }
757 if (!DXSetComponentValue(obj, "normals", (Object)newnormals))
758 goto error;
759 newnormals = NULL;
760 DXChangedComponentValues(obj,"normals");
761 }
762 }
763
764
765 done:
766 DXFreeArrayHandle(positionshandle);
767 DXFreeArrayHandle(normalshandle);
768 DXFreeArrayHandle(connectionshandle);
769 return OK;
770 error:
771 DXFreeArrayHandle(positionshandle);
772 DXFreeArrayHandle(normalshandle);
773 DXFreeArrayHandle(connectionshandle);
774 DXDelete((Object)newnormals);
775 DXDelete((Object)newconnections);
776 return ERROR;
777
778 }
779