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 #include <dxconfig.h>
10 
11 #if defined(HAVE_STRING_H)
12 #include <string.h>
13 #endif
14 
15 #include "hwDeclarations.h"
16 #include "hwXfield.h"
17 #include "hwMatrix.h"
18 #include "hwMemory.h"
19 #include "hwPortLayer.h"
20 #include "hwWindow.h"
21 #include "hwObjectHash.h"
22 
23 #define String dxString
24 #define Object dxObject
25 #define Angle dxAngle
26 #define Matrix dxMatrix
27 #define Screen dxScreen
28 #define Boolean dxBoolean
29 #include "../libdx/internals.h"
30 #undef String
31 #undef Object
32 #undef Angle
33 #undef Matrix
34 #undef Screen
35 #undef Boolean
36 
37 #include "hwDebug.h"
38 
39 #define FLOAT_TO_UBYTE(val)  ((val)<=0.0 ? (ubyte)0.f   : \
40 			      (val)>=1.0 ? (ubyte)255.f : (ubyte)((val)*255.0f))
41 
42 typedef struct _texture
43 {
44     int       width, height;
45     ubyte     *pixels;
46     dxObject  textureObj;
47     int       myPixels;
48     int       isRGBA;
49 } *Texture;
50 
51 static Error _getTexture_Field(Texture);
52 static Error _getTexture_CompositeField(Texture);
53 
54 static Error
_deleteTexture(Pointer p)55 _deleteTexture(Pointer p)
56 {
57     if (p)
58     {
59 	Texture t = (Texture)p;
60 	if (t->myPixels)
61 	    DXFree((Pointer)t->pixels);
62 	if (t->textureObj)
63 	    DXDelete(t->textureObj);
64     }
65     return OK;
66 }
67 
68 static dxObject
_newTexture(dxObject obj)69 _newTexture(dxObject obj)
70 {
71     dxObject txo = NULL;
72     Texture texture = (Texture)DXAllocateZero(sizeof(struct _texture));
73     if (! texture)
74 	goto error;
75 
76     texture->textureObj = DXReference(obj);
77 
78     if (DXGetObjectClass(obj) == CLASS_FIELD)
79     {
80 	if (! _getTexture_Field(texture))
81 	    goto error;
82     }
83     else if (DXGetObjectClass(obj) == CLASS_GROUP &&
84 	    DXGetGroupClass((Group)obj) == CLASS_COMPOSITEFIELD)
85     {
86 	if (! _getTexture_CompositeField(texture))
87 	    goto error;
88     }
89     else
90     {
91 	DXSetError(ERROR_DATA_INVALID, "invalid object type for texture");
92 	goto error;
93     }
94 
95     txo = (dxObject)DXNewPrivate((Pointer)texture, _deleteTexture);
96     if (! txo)
97 	goto error;
98 
99     return txo;
100 
101 error:
102     _deleteTexture((Pointer)texture);
103     return ERROR;
104 }
105 
106 Error
_XTexture(Field f,xfieldT * xf,void * globals)107 _XTexture(Field f, xfieldT* xf, void *globals)
108 {
109     DEFGLOBALDATA(globals);
110     Type  type;
111     int   rank, shape[32];
112     dxObject attr, texture = _dxf_xfieldAttributes(xf)->texture;
113     dxObject txo;
114 
115     if (texture)
116     {
117 	Texture txp;
118 
119 	xf->uv_array = (Array)DXGetComponentValue(f, "uv");
120 	if (! xf->uv_array)
121 	{
122 	    DXSetError(ERROR_DATA_INVALID,
123 		"texture attribute but no uv component");
124 	    goto error;
125 	}
126 
127 	DXGetArrayInfo(xf->uv_array, NULL, &type, NULL, &rank, shape);
128 
129 	if (type != TYPE_FLOAT || rank != 1 || shape[0] != 2)
130 	{
131 	    DXSetError(ERROR_DATA_INVALID,
132 		"uv component must contain float 2-vectors");
133 		goto error;
134 	}
135 
136 	attr = DXGetAttribute((dxObject)xf->uv_array, "dep");
137 	if (DXGetObjectClass(attr) != CLASS_STRING)
138 	{
139 	    DXSetError(ERROR_DATA_INVALID,
140 		"uv dep attribute must be a DXString object");
141 	    goto error;
142 	}
143 
144 	if (strcmp(DXGetString((dxString)attr), "positions"))
145 	{
146 	    DXSetError(ERROR_DATA_INVALID,
147 		"uv must be dep on positions");
148 	    goto error;
149 	}
150 
151 	xf->uv = DXCreateArrayHandle(xf->uv_array);
152 	if (! xf->uv)
153 	    goto error;
154 
155 	DXReference((dxObject)xf->uv_array);
156 
157 	txo = _dxf_QueryObject(TEXTUREHASH, texture);
158 	if (! txo)
159 	{
160 	    txo = _newTexture(texture);
161 	    if (! txo)
162 		goto error;
163 
164 	    _dxf_InsertObject(TEXTUREHASH, texture, txo);
165 	}
166 
167 	xf->texture_field = DXReference(txo);
168 	txp = (Texture)DXGetPrivateData((Private)txo);
169 
170 	xf->textureWidth    = txp->width;
171 	xf->textureHeight   = txp->height;
172 	xf->texture         = txp->pixels;
173 	xf->textureIsRGBA   = txp->isRGBA;
174 
175         if ( xf->textureIsRGBA )
176             /*  Set flag so primitives will be added to transparent SORTLIST  */
177             _dxf_setFlags(_dxf_attributeFlags(_dxf_xfieldAttributes(xf)),
178                           CONTAINS_TRANSPARENT_TEXTURE);
179     }
180     else
181     {
182 	xf->texture_field = NULL;
183 	xf->uv_array      = NULL;
184 	xf->texture       = NULL;
185     }
186 
187     return OK;
188 
189 error:
190     if (xf->texture_field)
191 	DXDelete((dxObject)xf->texture_field);
192     if (xf->uv_array)
193 	DXDelete((dxObject)xf->uv_array);
194 
195     xf->texture_field = NULL;
196     xf->texture = NULL;
197     xf->uv_array = NULL;
198     xf->uv = NULL;
199     xf->myTextureData = 0;
200 
201     return ERROR;
202 }
203 
204 static Error
_expandColorMap(Field tf,ubyte cmap[768])205 _expandColorMap(Field tf, ubyte cmap[768] )
206     /*  Extract the color map and convert to ubyte[3] format  */
207 {
208     Type     type;
209     int      i, n, rank, shape[32];
210     Array    array;
211 
212     array = (Array)DXGetComponentValue(tf, "color map");
213     if (! array)
214     {
215 	DXSetError(ERROR_MISSING_DATA,
216 	    "texture map has indexed colors but is missing color map");
217 	goto error;
218     }
219 
220     DXGetArrayInfo(array, &n, &type, NULL, &rank, shape);
221 
222     if ( n > 256 )
223     {
224 	DXSetError(ERROR_MISSING_DATA,
225 	    "texture map's color map has more than 256 entries");
226 	goto error;
227     }
228 
229     if (type == TYPE_FLOAT && rank == 1 && shape[0] == 3)
230     {
231 	float *map_src = (float *)DXGetArrayData(array);
232 
233 	for (i = 0; i < 3*n; i++)
234 	{
235 	    float c = *map_src++;
236 	    cmap[i] = FLOAT_TO_UBYTE(c);
237 	}
238     }
239     else if (type == TYPE_UBYTE && rank == 1 && shape[0] == 3)
240     {
241 	memcpy( cmap, (ubyte *)DXGetArrayData(array), 3*n );
242     }
243     else
244     {
245 	DXSetError(ERROR_DATA_INVALID,
246 	    "texture has invalid color map type "
247 	    "(must be float or ubyte 3-vectors)");
248 	goto error;
249     }
250 
251     return OK;
252 
253 error:
254     return ERROR;
255 }
256 
257 
258 static Error
_expandOpacityMap(Field tf,ubyte omap[256])259 _expandOpacityMap(Field tf, ubyte omap[256] )
260     /*  Extract the opacity map and convert to ubyte format  */
261 {
262     Type     type;
263     int      i, n, rank, shape[32];
264     Array    array;
265 
266     array = (Array)DXGetComponentValue(tf, "opacity map");
267     if (! array)
268     {
269 	DXSetError(ERROR_MISSING_DATA,
270 	    "indirect texture map missing opacity map component");
271 	goto error;
272     }
273 
274     DXGetArrayInfo(array, &n, &type, NULL, &rank, shape);
275 
276     if ( n > 256 )
277     {
278 	DXSetError(ERROR_MISSING_DATA,
279 	    "texture map's opacity map has more than 256 entries");
280 	goto error;
281     }
282 
283     if ( (type == TYPE_FLOAT &&
284 	  (rank == 0 || (rank == 1 && shape[0] == 1) )) )
285     {
286 	float *map_src = (float *)DXGetArrayData(array);
287 
288 	for (i = 0; i < n; i++)
289 	{
290 	    float o = *map_src++;
291 	    omap[i] = FLOAT_TO_UBYTE(o);
292 	}
293     }
294     else
295     {
296 	DXSetError(ERROR_DATA_INVALID,
297 	    "texture has invalid opacity map type "
298 	    "(must be float scalars)");
299 	goto error;
300     }
301 
302     return OK;
303 
304 error:
305     return ERROR;
306 }
307 
308 
309 static Error
_getTexture_Field(Texture t)310 _getTexture_Field(Texture t)
311 {
312     Type     type, o_type;
313     Category cat , o_cat;
314     int   n, o_n, rank, o_rank, shape[32], o_shape[32];
315     int   counts[2];
316     Array tmp,colors,opac;
317     int i;
318     Field tf = (Field)t->textureObj;
319 
320     t->pixels   = NULL;
321     t->myPixels = 0;
322 
323     tmp = (Array)DXGetComponentValue(tf, "connections");
324     if (! tmp)
325     {
326 	DXSetError(ERROR_DATA_INVALID,
327 	    "texture field has no connections");
328 	goto error;
329     }
330 
331     if (! DXQueryGridConnections(tmp, &n, counts))
332     {
333 	DXSetError(ERROR_DATA_INVALID,
334 	    "texture field must have regular connections");
335 	goto error;
336     }
337 
338     if (n != 2)
339     {
340 	DXSetError(ERROR_DATA_INVALID,
341 	    "texture field must be 2-d regular connections");
342 	goto error;
343     }
344 
345     t->width  = counts[1];
346     t->height = counts[0];
347 
348     colors = (Array)DXGetComponentValue(tf, "colors");
349     if (! colors)
350 	colors = (Array)DXGetComponentValue(tf, "data");
351     if (! colors)
352     {
353 	DXSetError(ERROR_DATA_INVALID,
354 	    "texture has neither colors nor data");
355 	return ERROR;
356     }
357     DXGetArrayInfo(colors, &n, &type, &cat, &rank, shape);
358 
359     opac = (Array)DXGetComponentValue(tf, "opacities");
360     if ( opac ) {
361         DXGetArrayInfo(opac, &o_n, &o_type, &o_cat, &o_rank, o_shape);
362         if ( o_n != n ) {
363 	    DXSetError(ERROR_MISSING_DATA,
364 	        "length of color and opacity components do not match");
365 	    goto error;
366         }
367     }
368 
369     /*  Handle ubyte[3] colors (w/ optional float opacities)  */
370     if (type == TYPE_UBYTE && rank == 1 && shape[0] == 3)
371     {
372 	if ( !opac ) {
373 	    t->pixels = (ubyte *)DXGetArrayData(colors);
374 	    t->isRGBA   = 0;
375 	    t->myPixels = 0;
376 	}
377 	else {
378     	    if (! (o_type == TYPE_FLOAT &&
379     	          (o_rank == 0 || (o_rank == 1 && o_shape[0] == 1) )) ) {
380 		DXSetError(ERROR_MISSING_DATA,
381 		    "opacities for a direct color texture map must be float");
382 		goto error;
383 	    }
384 	    {
385 		ubyte *dst, *c_src = (ubyte *)DXGetArrayData(colors);
386 		float *o_src = (float *)DXGetArrayData(opac);
387 	        t->pixels = (ubyte *)tdmAllocate(4*n*sizeof(ubyte));
388 	        dst   = t->pixels;
389 
390 	        for (i = 0; i < n; i++) {
391 		    float opacity = *(o_src++);
392 		    *(dst++) = *(c_src++);
393 		    *(dst++) = *(c_src++);
394 		    *(dst++) = *(c_src++);
395 		    *(dst++) = FLOAT_TO_UBYTE(opacity);
396                 }
397 	        t->isRGBA   = 1;
398 	        t->myPixels = 1;
399 	    }
400 	}
401     }
402     else
403     {
404 	int Bpp = opac ? 4 : 3;
405 	t->pixels = (ubyte *)tdmAllocate(Bpp*n*sizeof(ubyte));
406 	if (! t->pixels)
407 		goto error;
408 	t->myPixels = 1;
409 
410 	/*  Handle float[3] colors (w/ optional float opacities)  */
411 	if (type == TYPE_FLOAT && rank == 1 && shape[0] == 3)
412 	{
413 	    int i;
414 	    ubyte *dst = t->pixels;
415 	    float *c_src = (float *)DXGetArrayData(colors);
416 	    float *o_src = NULL;
417 
418 	    if ( opac ) {
419 	        o_src = (float *)DXGetArrayData(opac);
420 		if ( ! (o_type == TYPE_FLOAT &&
421 			(o_rank == 0 || (o_rank == 1 && o_shape[0] == 1) )) ) {
422 		    DXSetError(ERROR_MISSING_DATA,
423 		     "opacities for a direct color texture map must be float");
424 		    goto error;
425 		}
426 		Bpp = 4;
427 	    }
428 
429 	    t->isRGBA = opac != NULL;
430 
431 	    for (i = 0; i < n; i++)
432 	    {
433 		float c, o;
434 		c = *c_src++, *dst++ = FLOAT_TO_UBYTE(c);
435 		c = *c_src++, *dst++ = FLOAT_TO_UBYTE(c);
436 		c = *c_src++, *dst++ = FLOAT_TO_UBYTE(c);
437 		if ( opac )
438 		  o = *o_src++, *dst++ = FLOAT_TO_UBYTE(o);
439 	    }
440 	}
441 
442 	/*  Handle ubyte colors w/ float[3] or ubyte[3] colormap    */
443 	/*    (w/ optional ubyte opacities with float opacity map)  */
444         else if (type == TYPE_UBYTE &&
445                  (rank == 0 || (rank == 1 && shape[0] == 1) ))
446 	{
447 	    int i;
448 	    ubyte *dst = t->pixels;
449 	    ubyte *c_src = (ubyte *)DXGetArrayData(colors);
450 	    ubyte *o_src = NULL;
451 	    ubyte cmap[768], omap[256];
452 
453 	    if (!_expandColorMap(tf, cmap))
454 	        goto error;
455 
456 	    if ( opac ) {
457 		if ( !(o_type == TYPE_UBYTE &&
458 		       (o_rank == 0 || (o_rank == 1 && o_shape[0] == 1) )) ) {
459 		    DXSetError(ERROR_MISSING_DATA,
460 			"indirect texture map opacities must be scalar ubytes");
461 		    goto error;
462 		}
463 		if ( !_expandOpacityMap(tf, omap))
464 		    goto error;
465 
466 	        o_src = (ubyte *)DXGetArrayData(opac);
467 	    }
468 
469 	    for (i = 0; i < n; i++)
470 	    {
471 		ubyte *c = cmap + 3 * *c_src++;
472 		*dst++ = *c++;
473 		*dst++ = *c++;
474 		*dst++ = *c++;
475 		if ( opac )
476 		   *dst++ = omap[ *o_src++ ];
477 	    }
478 	    t->isRGBA = opac != NULL;
479 	}
480 	else
481 	{
482 	    DXSetError(ERROR_DATA_INVALID,
483 		"Bad texture found.  Texture must contain float or ubyte "
484 		"3-vector colors (with optional float opacities), OR contain "
485 		"scalar ubyte colors with a float or ubyte 3-vector color map "
486 		"(with optional ubyte opacities and a float opacity map)");
487 	    goto error;
488 	}
489     }
490 
491     return OK;
492 
493 error:
494     if ( t->pixels && t->myPixels ) {
495         DXFree((Pointer)t->pixels);
496 	t->pixels   = NULL;
497 	t->myPixels = 0;
498     }
499     return ERROR;
500 }
501 
502 static Error
_getTexture_CompositeField(Texture t)503 _getTexture_CompositeField(Texture t)
504 {
505     Type  type, o_type;
506     Category cat, o_cat;
507     int   n, o_n, rank, o_rank, shape[32], o_shape[32], counts[2];
508     int i, Bpp;
509     Group cf = (Group)t->textureObj;
510     Field member;
511     int nMembers;
512 
513     t->pixels   = NULL;
514     t->myPixels = 0;
515 
516     DXGetMemberCount(cf, &nMembers);
517     if ( nMembers == 0 ) {
518         DXSetError(ERROR_DATA_INVALID,
519 	           "composite texture field has no members");
520 	goto error;
521     }
522 
523     counts[0] = counts[1] = 0;
524 
525     /*  Verify all members are regular 2D grids, and calc cumulative size  */
526     for (i = 0; i < nMembers; i++)
527     {
528 	Array grid;
529 	int memberCounts[2], memberOffsets[2], nDim, cnt;
530 
531 	member = (Field)DXGetEnumeratedMember(cf, i, NULL);
532 	grid = (Array)DXGetComponentValue(member, "connections");
533 
534 	if (!DXQueryGridConnections(grid, &nDim, memberCounts) ||
535 	    !DXGetMeshOffsets((MeshArray)grid, memberOffsets))
536 	{
537 	    DXSetError(ERROR_DATA_INVALID,
538 		"texture field must have regular connections");
539 	    goto error;
540 	}
541 
542 	if (nDim != 2)
543 	{
544 	    DXSetError(ERROR_DATA_INVALID, "texture fields must be 2-D");
545 	    goto error;
546 	}
547 
548 	if ((cnt = memberOffsets[0] + memberCounts[0]) > counts[0])
549 	    counts[0] = cnt;
550 
551 	if ((cnt = memberOffsets[1] + memberCounts[1]) > counts[1])
552 	    counts[1] = cnt;
553 
554     }
555     t->width  = counts[1];
556     t->height = counts[0];
557 
558     n = counts[0] * counts[1];
559 
560     /*  Allocate texture buffer  */
561     member = (Field)DXGetEnumeratedMember(cf, 0, NULL);
562     t->isRGBA = (DXGetComponentValue(member, "opacities") != NULL);
563     Bpp       = t->isRGBA ? 4 : 3;
564     t->pixels = (ubyte *)tdmAllocate(Bpp*n*sizeof(ubyte));
565     if (! t->pixels)
566 	goto error;
567     t->myPixels = 1;
568 
569     /*  Copy colors/opacities from each member into the texture buffer  */
570     for (i = 0; i < nMembers; i++)
571     {
572 	Array colors,opac;
573 	Array grid;
574 	int memberCounts[2], memberOffsets[2];
575 
576 	member = (Field)DXGetEnumeratedMember(cf, i, NULL);
577 	grid = (Array)DXGetComponentValue(member, "connections");
578 
579 	colors = (Array)DXGetComponentValue(member, "colors");
580 	if (! colors)
581 	    colors = (Array)DXGetComponentValue(member, "data");
582 	if (! colors)
583 	{
584 	    DXSetError(ERROR_DATA_INVALID,
585 		"texture has neither colors nor data");
586 	    return ERROR;
587 	}
588 	DXGetArrayInfo(colors, NULL, &type, &cat, &rank, shape);
589 
590 	opac = (Array)DXGetComponentValue(member, "opacities");
591 	if ( opac ) {
592 	    DXGetArrayInfo(opac, &o_n, &o_type, &o_cat, &o_rank, o_shape);
593 	    if ( o_n != n ) {
594 		DXSetError(ERROR_MISSING_DATA,
595 		    "length of color and opacity components do not match");
596 		goto error;
597 	    }
598 	}
599 
600 
601 	DXQueryGridConnections(grid, NULL, memberCounts);
602 	DXGetMeshOffsets((MeshArray)grid, memberOffsets);
603 
604 	/*  Handle ubyte[3] colors (w/ optional float opacities)  */
605 	if (type == TYPE_UBYTE && rank == 1 && shape[0] == 3)
606 	{
607 	    int j, k;
608 	    ubyte *c_src = (ubyte *)DXGetArrayData(colors);
609 	    float *o_src = NULL;
610 	    ubyte *dst = t->pixels + Bpp*((memberOffsets[0]*counts[1])
611 					     + memberOffsets[1]);
612 	    int dst_stride = Bpp*(counts[1] - memberCounts[1]);
613 
614 	    if ( opac ) {
615 		if (! (o_type == TYPE_FLOAT &&
616 		      (o_rank == 0 || (o_rank == 1 && o_shape[0] == 1) )) ) {
617 		    DXSetError(ERROR_MISSING_DATA,
618 		      "opacities for a direct color texture map must be float");
619 		    goto error;
620 		}
621 	        o_src = (float *)DXGetArrayData(opac);
622 	    }
623 
624 	    for (j = 0; j < memberCounts[0]; j++)
625 	    {
626 		for (k = 0; k < memberCounts[1]; k++)
627 		{
628 		    float o;
629 		    *dst++ = *c_src++;
630 		    *dst++ = *c_src++;
631 		    *dst++ = *c_src++;
632 		    if ( opac )
633 		        o = *o_src++, *dst++ = FLOAT_TO_UBYTE(o);
634 		}
635 		dst += dst_stride;
636 	    }
637 	}
638 
639 	/*  Handle float[3] colors (w/ optional float opacities)  */
640 	else if (type == TYPE_FLOAT && rank == 1 && shape[0] == 3)
641 	{
642 	    int j, k;
643 	    float *c_src = (float *)DXGetArrayData(colors);
644 	    float *o_src = NULL;
645 	    ubyte *dst = t->pixels + Bpp*((memberOffsets[0]*counts[1])
646 					     + memberOffsets[1]);
647 	    int dst_stride = Bpp*(counts[1] - memberCounts[1]);
648 
649 	    if ( opac ) {
650 		if (! (o_type == TYPE_FLOAT &&
651 		      (o_rank == 0 || (o_rank == 1 && o_shape[0] == 1) )) ) {
652 		    DXSetError(ERROR_MISSING_DATA,
653 		      "opacities for a direct color texture map must be float");
654 		    goto error;
655 		}
656 	        o_src = (float *)DXGetArrayData(opac);
657 	    }
658 
659 	    for (j = 0; j < memberCounts[0]; j++)
660 	    {
661 		for (k = 0; k < memberCounts[1]; k++)
662 		{
663 		    float c, o;
664 		    c = *c_src++, *dst++ = FLOAT_TO_UBYTE(c);
665 		    c = *c_src++, *dst++ = FLOAT_TO_UBYTE(c);
666 		    c = *c_src++, *dst++ = FLOAT_TO_UBYTE(c);
667 		    if ( opac )
668 		        o = *o_src++, *dst++ = FLOAT_TO_UBYTE(o);
669 		}
670 		dst += dst_stride;
671 	    }
672 	}
673 
674 	/*  Handle ubyte colors w/ float[3] or ubyte[3] colormap    */
675 	/*    (w/ optional ubyte opacities with float opacity map)  */
676 	else if (type == TYPE_UBYTE &&
677 	    (rank == 0 || (rank == 1 && shape[0] == 1) ))
678 	{
679 	    int j, k;
680 	    ubyte cmap[768], omap[256];
681 	    ubyte *c_src = (ubyte *)DXGetArrayData(colors);
682 	    ubyte *o_src = NULL;
683 	    int dst_stride = Bpp*(counts[1] - memberCounts[1]);
684 	    ubyte *dst = t->pixels + Bpp*((memberOffsets[0]*counts[1])
685 					     + memberOffsets[1]);
686 
687 	    if (!_expandColorMap(member, cmap))
688 	        goto error;
689 
690 	    if ( opac ) {
691 		if ( !(o_type == TYPE_UBYTE &&
692 		       (o_rank == 0 || (o_rank == 1 && o_shape[0] == 1) )) ) {
693 		    DXSetError(ERROR_MISSING_DATA,
694 			"indirect texture map opacities must be scalar ubytes");
695 		    goto error;
696 		}
697 
698 		if ( !_expandOpacityMap(member, omap))
699 		    goto error;
700 
701 	        o_src = (ubyte *)DXGetArrayData(opac);
702 	    }
703 
704 	    for (j = 0; j < memberCounts[0]; j++)
705 	    {
706 		for (k = 0; k < memberCounts[1]; k++)
707 		{
708 		    ubyte *c = cmap + (3 * *c_src++);
709 		    *dst++ = *c++;
710 		    *dst++ = *c++;
711 		    *dst++ = *c++;
712 		    if ( opac )
713 		        *dst++ = omap[ *o_src++ ];
714 		}
715 		dst += dst_stride;
716 	    }
717 	}
718 	else
719 	{
720 	    DXSetError(ERROR_DATA_INVALID,
721 		"Bad texture found.  Texture must contain float or ubyte "
722 		"3-vector colors (with optional float opacities), OR contain "
723 		"scalar ubyte colors with a float or ubyte 3-vector color map "
724 		"(with optional ubyte opacities and a float opacity map)");
725 	    goto error;
726 	}
727     }
728 
729     return OK;
730 
731 error:
732     if ( t->pixels && t->myPixels ) {
733         DXFree((Pointer)t->pixels);
734 	t->pixels   = NULL;
735 	t->myPixels = 0;
736     }
737     return ERROR;
738 }
739