1 /*
2  * Compiz cube model plugin
3  *
4  * cubemodel.c
5  *
6  * This plugin displays wavefront (.obj) 3D mesh models inside of
7  * the transparent cube.
8  *
9  * Copyright : (C) 2008 by David Mikos
10  * E-mail    : infiniteloopcounter@gmail.com
11  *
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  */
24 
25 /*
26  * Model loader code based on cubemodel/cubefx plugin "cubemodelModel.c.in"
27  * code - originally written by Joel Bosvel (b0le).
28  */
29 
30 /*
31  * Note - The textures in animations are only
32  *        displayed from the first frame.
33  */
34 
35 #define _GNU_SOURCE /* for strndup */
36 
37 #include <errno.h>
38 #include <pthread.h>
39 
40 #include <string.h>
41 #include <unistd.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 
45 #include "cubemodel-internal.h"
46 #include "cubemodel_options.h"
47 
48 
49 /**************************
50 * Gets path from object   *
51 * and file name from file *
52 * and returns full path   *
53 * to the file             *
54 **************************/
55 
56 static char *
findPath(char * object,char * file)57 findPath (char *object,
58 	  char *file)
59 {
60     char *filePath; /* string containing /full/path/to/file */
61     int  i;
62 
63     if (!file || !object)
64 	return NULL;
65 
66     if (file[0] == '/')
67 	return strdup (file);
68 
69     filePath = strdup (object);
70     if (!filePath)
71 	return NULL;
72 
73     for (i = strlen (filePath) - 1; i >= 0; i--)
74     {
75 	if (filePath[i] == '/')
76 	{
77 	    filePath[i + 1]='\0'; /* end string at last /
78 				     (gives path to object) */
79 	    break;
80 	}
81     }
82 
83     filePath = realloc (filePath,
84   			sizeof (char) *
85 			(strlen (filePath) + strlen (file) + 1));
86     if (!filePath)
87 	return NULL;
88 
89     strcat (filePath, file);
90 
91     return filePath;
92 }
93 
94 static int
addNumToString(char ** sp,unsigned int size,int offset,char * post,unsigned int x,unsigned int maxNumZeros)95 addNumToString (char         **sp,
96                 unsigned int size,
97                 int          offset,
98                 char         *post,
99                 unsigned int x,
100                 unsigned int maxNumZeros)
101 {
102     int  c = 0;
103     int  numZeros = 0;
104     char *s = *sp;
105     int  i = x, j;
106 
107     while (i != 0)
108     {
109 	c++;
110 	i /= 10;
111     }
112 
113     if (maxNumZeros > c)
114 	numZeros = maxNumZeros - c;
115 
116     j = offset + c + numZeros + strlen (post) + 4 + 1;
117     if (j > size)
118     {
119 	size = j;
120 	s = *sp = realloc (*sp, size * sizeof (char));
121     }
122 
123     snprintf (s + offset, size - offset, "%0*d%s.obj", maxNumZeros, x, post);
124 
125     return size;
126 }
127 
128 static int
addVertex(unsigned int ** indices,int nUniqueIndices,int iTexture,int iNormal)129 addVertex (unsigned int **indices,
130 	   int		nUniqueIndices,
131 	   int		iTexture,
132 	   int		iNormal)
133 {
134     int i, len;
135 
136     if (*indices == NULL)
137     {
138 	*indices = malloc (4 * sizeof (int));
139 	(*indices)[0] = 1; /* store size of array as 1st element */
140 	(*indices)[1] = iTexture;
141 	(*indices)[2] = iNormal;
142 	(*indices)[3] = nUniqueIndices; /* ptr to new unique vertex index */
143 
144 	return -1; /* new vertex/texture/normal */
145     }
146 
147     len = (*indices)[0];
148     for (i = 0; i < len; i++)
149     {
150 	if ((*indices)[1 + 3 * i] == iTexture &&
151 	    (*indices)[2 + 3 * i] == iNormal)
152 	{
153 	    return (*indices)[3 + 3 * i]; /* found same vertex/texture/normal
154 					     before */
155 	}
156     }
157 
158     *indices = realloc (*indices, (1 + 3 * ((*indices)[0] + 1)) *
159                          sizeof (int));
160     (*indices)[1 + 3 * (*indices)[0]] = iTexture;
161     (*indices)[2 + 3 * (*indices)[0]] = iNormal;
162     (*indices)[3 + 3 * (*indices)[0]] = nUniqueIndices;
163     (*indices)[0]++;
164 
165     return -1;
166 }
167 
168 static Bool
compileDList(CompScreen * s,CubemodelObject * data)169 compileDList (CompScreen      *s,
170 	      CubemodelObject *data)
171 {
172     if (!data->animation && data->finishedLoading && !data->compiledDList)
173     {
174 	data->dList = glGenLists (1);
175 	glNewList (data->dList, GL_COMPILE);
176 
177 	glDisable (GL_CULL_FACE);
178 	glEnable  (GL_NORMALIZE);
179 	glEnable  (GL_DEPTH_TEST);
180 
181 	glDisable (GL_COLOR_MATERIAL);
182 
183 	cubemodelDrawVBOModel (s, data,
184 	                       (float *) data->reorderedVertex[0],
185 	                       (float *) data->reorderedNormal[0]);
186 	glEndList ();
187 
188 	data->compiledDList = TRUE;
189 
190 	return TRUE;
191     }
192     return FALSE;
193 }
194 
195 static void
loadMaterials(CompScreen * s,CubemodelObject * data,char * approxPath,char * filename,mtlStruct ** material,int * nMat)196 loadMaterials (CompScreen      *s,
197                CubemodelObject *data,
198                char            *approxPath,
199                char            *filename,
200                mtlStruct       **material,
201                int             *nMat)
202 {
203     int i;
204 
205     /* getLine stuff */
206     char *strline    = NULL;
207     int tempBufferSize = 2048; /* get character data from files
208 				  in these size chunks */
209     fileParser *fParser = NULL;
210 
211 
212     mtlStruct *currentMaterial = NULL;
213 
214     char *mtlFilename;
215     FILE *mtlfp;
216 
217     int nMaterial = *nMat;
218 
219     if (nMaterial == 0)
220 	*material = NULL;
221 
222     mtlFilename = findPath (approxPath, filename);
223     if (!mtlFilename)
224 	return;
225 
226     mtlfp = fopen (mtlFilename, "r");
227 
228     if (mtlFilename)
229 	free (mtlFilename);
230 
231     if (!mtlfp)
232     {
233 	compLogMessage ("cubemodel", CompLogLevelWarn,
234 	                "Failed to open material file : %s", mtlFilename);
235 	return;
236     }
237 
238     fParser = initFileParser (mtlfp, tempBufferSize);
239 
240     /* now read all the materials in the mtllib referenced file */
241 
242     while ((strline = getLineToken2 (fParser, FALSE)))
243     {
244 	char *tmpPtr[3] = { NULL, NULL, NULL }; /* used to check numerical
245 						   parameters*/
246 	float tmpNum[3] = {0, 0, 0 };
247 	float tmpIllum = 100;
248 
249 	if (strline[0] == '\0')
250 	    continue;
251 
252 	if (!strcmp (strline, "newmtl"))
253 	{
254 	    strline = getLineToken2 (fParser, TRUE);
255 	    if (!strline)
256 		continue;
257 
258 	    *material = realloc (*material, sizeof (mtlStruct) *
259 	                         (nMaterial + 1));
260 	    currentMaterial = &((*material)[nMaterial]);
261 
262 	    nMaterial++;
263 
264 	    currentMaterial->name = strdup (strline);
265 
266 	    /* set defaults */
267 	    currentMaterial->Ns[0] = 100;
268 	    currentMaterial->Ni[0] = 1;
269 	    currentMaterial->illum = 2;
270 
271 	    for (i = 0; i < 3; i++)
272 	    {
273 		currentMaterial->Ka[i] = 0.2;
274 		currentMaterial->Kd[i] = 0.8;
275 		currentMaterial->Ks[i] = 1;
276 	    }
277 	    currentMaterial->Ka[3] = 1;
278 	    currentMaterial->Kd[3] = 1;
279 	    currentMaterial->Ks[3] = 1;
280 
281 	    currentMaterial->map_Ka = -1;
282 	    currentMaterial->map_Kd = -1;
283 	    currentMaterial->map_Ks = -1;
284 	    currentMaterial->map_d  = -1;
285 
286 	    currentMaterial->map_params = -1;
287 	}
288 
289 	if (!currentMaterial)
290 	    continue;
291 
292 	for (i = 0; i < 3; i++)
293 	{
294 	    tmpPtr[i] = getLineToken2 (fParser, TRUE);
295 	    if (!tmpPtr[i])
296 		break;
297 
298 	    tmpNum[i] = atof (tmpPtr[i]);
299 
300 	    if (i == 0)
301 		tmpIllum = atoi (tmpPtr[i]);
302 	}
303 
304 	if (!strcmp (strline, "Ns"))
305 	{
306 	    currentMaterial->Ns[0] = tmpNum[0];
307 	}
308 	else if (!strcmp (strline, "Ka"))
309 	{
310 	    for (i = 0; i < 3; i++)
311 		currentMaterial->Ka[i] = tmpNum[i];
312 	}
313 	else if (!strcmp (strline, "Kd"))
314 	{
315 	    for (i = 0; i < 3; i++)
316 		currentMaterial->Kd[i] = tmpNum[i];
317 	}
318 	else if (!strcmp (strline, "Ks"))
319 	{
320 	    for (i = 0; i < 3; i++)
321 		currentMaterial->Ks[i] = tmpNum[i];
322 	}
323 	else if (!strcmp (strline, "Ni"))
324 	{
325 	    currentMaterial->Ni[0] = tmpNum[0];
326 	}
327 	else if (!strcmp (strline, "d") || !strcmp(strline,"Tr"))
328 	{
329 	    currentMaterial->Ka[3] = tmpNum[0];
330 	    currentMaterial->Kd[3] = tmpNum[0];
331 	    currentMaterial->Ks[3] = tmpNum[0];
332 	}
333 	else if (!strcmp (strline, "illum"))
334 	{
335 	    currentMaterial->illum = tmpIllum;
336 	}
337 	else if (!strcmp (strline, "map_Ka") || !strcmp (strline, "map_Kd") ||
338 		 !strcmp (strline, "map_Ks") || !strcmp (strline, "map_d" ) )
339 	{
340 	    char *tmpName = NULL;
341 
342 	    if (!data->tex)
343 	    {
344 		data->tex = malloc (sizeof (CompTexture));
345 		if (!data->tex)
346 		{
347 		    compLogMessage ("cubemodel", CompLogLevelWarn,
348 		                    "Error allocating texture memory");
349 		    break;
350 		}
351 		data->texName = NULL;
352 
353 		data->texWidth  = malloc (sizeof (unsigned int));
354 		if (!data->texWidth)
355 		{
356 		    free (data->tex);
357 		    data->tex = NULL;
358 		    break;
359 		}
360 		data->texHeight = malloc (sizeof (unsigned int));
361 		if (!data->texHeight)
362 		{
363 		    free (data->tex);
364 		    free (data->texWidth);
365 		    data->tex = NULL;
366 		    break;
367 		}
368 
369 		data->nTex = 0;
370 	    }
371 	    else
372 	    {
373 		Bool match = FALSE;
374 
375 		if (!data->texName && data->nTex > 0)
376 		    continue;
377 
378 		for (i = 0; i < data->nTex; i++)
379 		{
380 		    if (!data->texName[i])
381 			break;
382 
383 		    if (!strcmp (tmpPtr[0], data->texName[i]))
384 		    {
385 			if (!strcmp (strline, "map_Ka"))
386 			    currentMaterial->map_Ka = i;
387 			else if (!strcmp (strline, "map_Kd"))
388 			    currentMaterial->map_Kd = i;
389 			else if (!strcmp (strline, "map_Ks"))
390 			    currentMaterial->map_Ks = i;
391 			else if (!strcmp (strline, "map_d"))
392 			    currentMaterial->map_d = i;
393 
394 			currentMaterial->width  = data->texWidth[i];
395 			currentMaterial->height = data->texHeight[i];
396 
397 			currentMaterial->map_params = i;
398 
399 			match = TRUE;
400 			break;
401 		    }
402 		}
403 
404 		if (match)
405 		    continue;
406 
407 		data->tex      = realloc (data->tex,
408 		                          sizeof (CompTexture) *
409 		                          (data->nTex + 1));
410 		data->texWidth = realloc (data->texWidth,
411 		                          sizeof (unsigned int) *
412 		                          (data->nTex + 1));
413 		data->texHeight= realloc (data->texHeight,
414 		                          sizeof (unsigned int) *
415 		                          (data->nTex + 1));
416 	    }
417 
418 	    initTexture (s, &(data->tex[data->nTex]));
419 
420 	    if (!data->tex)
421 	    {
422 		compLogMessage ("cubemodel", CompLogLevelWarn,
423 		                "CompTexture is not malloced properly");
424 	    }
425 	    else
426 	    {
427 		tmpName = findPath (approxPath, tmpPtr[0]);
428 		if (!readImageToTexture (s,
429 		                         &(data->tex[data->nTex]), /*texture*/
430 		                         tmpName, /*file*/
431 		                         &(currentMaterial->width),  /*width*/
432 		                         &(currentMaterial->height)))/*height*/
433 		{
434 		    compLogMessage ("cubemodel", CompLogLevelWarn,
435 		                   "Failed to load image: %s", tmpName);
436 
437 		    finiTexture (s, &(data->tex[data->nTex]));
438 		}
439 		else
440 		{
441 		    data->texName  = realloc (data->texName,
442 					      sizeof (char *) *
443 					      (data->nTex + 1));
444 
445 		    data->texName[data->nTex] = strdup (tmpPtr[0]);
446 
447 		    if (!strcmp (strline, "map_Ka"))
448 			currentMaterial->map_Ka = data->nTex;
449 		    else if (!strcmp (strline, "map_Kd"))
450 			currentMaterial->map_Kd = data->nTex;
451 		    else if (!strcmp (strline, "map_Ks"))
452 			currentMaterial->map_Ks = data->nTex;
453 		    else if (!strcmp (strline, "map_d"))
454 			currentMaterial->map_d = data->nTex;
455 
456 		    data->texWidth[data->nTex]  = currentMaterial->width;
457 		    data->texHeight[data->nTex] = currentMaterial->height;
458 
459 		    currentMaterial->map_params = data->nTex;
460 
461 		    data->nTex++;
462 		}
463 	    }
464 
465 	    if (tmpName)
466 		free (tmpName);
467 	    tmpName = NULL;
468 	}
469 
470 	if (!fParser->lastTokenOnLine)
471 	    skipLine (fParser);
472     }
473 
474     freeFileParser(fParser);
475 
476     fclose (mtlfp);
477 
478     *nMat = nMaterial;
479 }
480 
481 static Bool
initLoadModelObject(CompScreen * s,CubemodelObject * modelData)482 initLoadModelObject (CompScreen      *s,
483 		     CubemodelObject *modelData)
484 {
485     char *filename = modelData->filename;
486     char *post     = modelData->post;
487 
488     int size            = modelData->size;
489     int lenBaseFilename = modelData->lenBaseFilename;
490     int startFileNum    = modelData->startFileNum;
491     int maxNumZeros     = modelData->maxNumZeros;
492 
493     /* getLine stuff */
494     char *strline    = NULL;
495     int tempBufferSize = 4 * 1024; /* get character data from files
496 				      in these size chunks */
497     fileParser *fParser = NULL;
498 
499     int nVertex = 0;
500     int nNormal = 0;
501     int nTexture = 0;
502     int nIndices = 0;
503 
504     FILE *fp;
505 
506     modelData->nMaterial[0] = 0;
507     modelData->material[0] = NULL;
508 
509     /* First pass - count how much data we need to store and
510      *		  - load the materials from any mtllib references.
511      */
512 
513     if (modelData->animation)
514 	size = addNumToString (&filename, size, lenBaseFilename, post,
515 	                       startFileNum, maxNumZeros);
516 
517     fp = fopen (filename, "r");
518     if (!fp)
519     {
520 	compLogMessage ("cubemodel", CompLogLevelWarn,
521 	                "Failed to open model file - %s", filename);
522 	return FALSE;
523     }
524 
525     fParser = initFileParser (fp, tempBufferSize);
526 
527     while ((strline = getLineToken2 (fParser, FALSE)))
528     {
529 	if (strline[0] == '\0')
530 	    continue;
531 
532 	if (!strcmp (strline, "v"))
533 	    nVertex++;
534 	else if (!strcmp (strline, "vn"))
535 	    nNormal++;
536 	else if (!strcmp (strline, "vt"))
537 	    nTexture++;
538 	else if (!strcmp (strline, "f") || !strcmp (strline, "fo") ||
539 		 !strcmp (strline, "p") || !strcmp (strline, "l") )
540 	{
541 	    while (getLineToken2 (fParser, TRUE))
542 		nIndices++;
543 	}
544 	else if (!strcmp (strline, "mtllib"))
545 	{
546 	    while ((strline = getLineToken2 (fParser, TRUE)))
547 	    {
548 		loadMaterials (s, modelData, filename, strline,
549 		               &(modelData->material[0]),
550 		               &(modelData->nMaterial[0]));
551 	    }
552 	}
553 
554 	if (!fParser->lastTokenOnLine)
555 	    skipLine (fParser);
556     }
557 
558     modelData->reorderedVertex[0]  = malloc (sizeof (vect3d) * nIndices);
559     modelData->reorderedTexture[0] = malloc (sizeof (vect2d) * nIndices);
560     modelData->reorderedNormal[0]  = malloc (sizeof (vect3d) * nIndices);
561 
562     modelData->indices = malloc (sizeof (unsigned int *) * nIndices);
563     modelData->reorderedVertexBuffer  = malloc (sizeof (vect3d) * nIndices);
564     modelData->reorderedTextureBuffer = malloc (sizeof (vect2d) * nIndices);
565     modelData->reorderedNormalBuffer  = malloc (sizeof (vect3d) * nIndices);
566 
567     modelData->nVertex  = nVertex;
568     modelData->nNormal  = nNormal;
569     modelData->nTexture = nTexture;
570     modelData->nIndices = nIndices;
571 
572     freeFileParser (fParser);
573 
574     return TRUE;
575 }
576 
577 static Bool
loadModelObject(CubemodelObject * modelData)578 loadModelObject (CubemodelObject *modelData)
579 {
580     int i, j;
581 
582     char *filename = modelData->filename;
583     char *post     = modelData->post;
584 
585     int size            = modelData->size;
586     int lenBaseFilename = modelData->lenBaseFilename;
587     int startFileNum    = modelData->startFileNum;
588     int maxNumZeros     = modelData->maxNumZeros;
589 
590     /* getLine stuff */
591     char *strline    = NULL;
592     int tempBufferSize = 4 * 1024; /* get character data from files
593 				      in these size chunks */
594     fileParser *fParser = NULL;
595 
596     int fileCounter = modelData->fileCounter;
597 
598     int nVertex=0;
599     int nNormal=0;
600     int nTexture=0;
601     int nIndices=0;
602     int nUniqueIndices = 0;
603 
604     unsigned int **tmpIndices = NULL; /* reorder indices per vertex
605 					 (store alternating corresponding
606 					 textures/normals) */
607     vect3d *vertex  = NULL;
608     vect3d *normal  = NULL;
609     vect2d *texture = NULL;
610 
611     FILE *fp;
612 
613     int nGroups  = 0;
614 
615     int oldPolyCount = 0;
616     Bool oldUsingNormal = FALSE;
617     Bool oldUsingTexture = FALSE;
618 
619     /* store size of each array */
620     int sVertex = 0;
621     int sTexture = 0;
622     int sNormal = 0;
623     int sIndices = 0;
624 
625     int fc;
626 
627     fParser = initFileParser (NULL, tempBufferSize);
628 
629     for (fc = 0; fc < fileCounter; fc++)
630     {
631 	int lastLoadedMaterial = -1;
632 	int prevLoadedMaterial = -1;
633 
634 	if (modelData->animation)
635 	    size = addNumToString (&filename, size, lenBaseFilename,
636 	                           post, startFileNum+fc, maxNumZeros);
637 
638 	fp = fopen(filename, "r");
639 	if (!fp)
640 	{
641 	    compLogMessage ("cubemodel", CompLogLevelWarn,
642 	                    "Failed to open model file - %s", filename);
643 	    free (normal);
644 	    free (tmpIndices);
645 	    free (texture);
646 	    free (vertex);
647 	    freeFileParser (fParser);
648 	    return FALSE;
649 	}
650 
651 	updateFileParser (fParser, fp);
652 
653 	if (fc == 0)
654 	{
655 	    nVertex  = modelData->nVertex;
656 	    nTexture = modelData->nTexture;
657 	    nNormal  = modelData->nNormal;
658 	    nIndices = modelData->nIndices;
659 
660 	    sVertex  = nVertex;
661 	    sTexture = nTexture;
662 	    sNormal  = nNormal;
663 	    sIndices = nIndices;
664 	}
665 	else
666 	{
667 	    sIndices = modelData->nIndices;
668 	}
669 
670 	modelData->reorderedVertex[fc]  = malloc (sizeof (vect3d) * sIndices);
671 	modelData->reorderedTexture[fc] = malloc (sizeof (vect2d) * sIndices);
672 	modelData->reorderedNormal[fc]  = malloc (sizeof (vect3d) * sIndices);
673 
674 	if (fc == 0)
675 	{
676 	    vertex  = malloc (sizeof (vect3d) * nVertex);
677 	    texture = malloc (sizeof (vect2d) * nTexture);
678 	    normal  = malloc (sizeof (vect3d) * nNormal);
679 
680 	    modelData->indices = malloc (sizeof (unsigned int *) * nIndices);
681 	    modelData->reorderedVertexBuffer  = malloc (sizeof (vect3d) *
682 	                                                nIndices);
683 	    modelData->reorderedTextureBuffer = malloc (sizeof (vect2d) *
684 	                                                nIndices);
685 	    modelData->reorderedNormalBuffer  = malloc (sizeof (vect3d) *
686 	                                                nIndices);
687 
688 	    modelData->nVertex  = nVertex;
689 	    modelData->nNormal  = nNormal;
690 	    modelData->nTexture = nTexture;
691 	    modelData->nIndices = nIndices;
692 
693 	    tmpIndices = malloc (sizeof (unsigned int **) * sVertex);
694 	    for (i = 0; i < sVertex; i++)
695 		tmpIndices[i] = NULL;
696 	}
697 	else
698 	{
699 	    for (i = 0; i < sVertex; i++)
700 	    {
701 		if (tmpIndices[i])
702 		    tmpIndices[i][0] = 0; /* set length to 0 */
703 	    }
704 	}
705 
706 	nVertex  = 0;
707 	nNormal  = 0;
708 	nTexture = 0;
709 	nIndices = 0;
710 	nUniqueIndices = 0;
711 
712 	/* Second pass - fill arrays
713 	 * 	       - reorder data and store into vertex/normal/texture
714 	 * 		 buffers
715 	 */
716 
717 	while ((strline = getLineToken2 (fParser, FALSE)))
718 	{
719 	    int complexity = 0;
720 	    int polyCount  = 0;
721 	    Bool updateGroup  = FALSE;
722 	    Bool usingNormal  = FALSE;
723 	    Bool usingTexture = FALSE;
724 
725 	    if (strline[0] == '\0')
726 		continue;
727 
728 	    if (!strcmp (strline, "v"))
729 	    {
730 		if (sVertex <= nVertex)
731 		{
732 		    sVertex++;
733 		    vertex     = realloc (vertex, sizeof (vect3d) * sVertex);
734 		    tmpIndices = realloc (tmpIndices,
735 					  sizeof (vect3d) * sVertex);
736 		    tmpIndices[sVertex - 1] = NULL;
737 		}
738 
739 		for (i = 0; i < 3; i++)
740 		{
741 		    strline = getLineToken2 (fParser, TRUE);
742 
743 		    if (!strline)
744 		    {
745 			vertex[nVertex].r[0] = 0;
746 			vertex[nVertex].r[1] = 0;
747 			vertex[nVertex].r[2] = 0;
748 			break;
749 		    }
750 		    vertex[nVertex].r[i] = atof (strline);
751 		}
752 		nVertex++;
753 	    }
754 	    else if (!strcmp (strline, "vn"))
755 	    {
756 		if (sNormal <= nNormal)
757 		{
758 		    sNormal++;
759 		    normal = realloc (normal, sizeof (vect3d) * sNormal);
760 		}
761 
762 		for (i = 0; i < 3; i++)
763 		{
764 		    strline = getLineToken2 (fParser, TRUE);
765 
766 		    if (!strline)
767 		    {
768 			normal[nNormal].r[0] = 0;
769 			normal[nNormal].r[1] = 0;
770 			normal[nNormal].r[2] = 1;
771 			break;
772 		    }
773 		    normal[nNormal].r[i] = atof(strline);
774 		}
775 		nNormal++;
776 	    }
777 	    else if (!strcmp (strline, "vt"))
778 	    {
779 		if (sTexture <= nTexture)
780 		{
781 		    sVertex++;
782 		    texture = realloc (texture, sizeof (vect3d) * sTexture);
783 		}
784 
785 		/* load the 1D/2D coordinates for textures */
786 		for (i = 0; i < 2; i++)
787 		{
788 		    strline = getLineToken2 (fParser, TRUE);
789 		    if (!strline)
790 		    {
791 			if (i == 0)
792 			    texture[nTexture].r[0] = 0;
793 
794 			texture[nTexture].r[1] = 0;
795 			break;
796 		    }
797 		    texture[nTexture].r[i] = atof (strline);
798 		}
799 		nTexture++;
800 	    }
801 	    else if (!strcmp (strline, "usemtl") && fc == 0)
802 	    {
803 		/* parse mtl file(s) and load specified material */
804 		strline = getLineToken2 (fParser, TRUE);
805 		if (!strline)
806 		    continue;
807 
808 		for (j = 0; j < modelData->nMaterial[fc]; j++)
809 		{
810 		    if (!strcmp (strline, modelData->material[fc][j].name))
811 		    {
812 			lastLoadedMaterial = j;
813 			updateGroup = TRUE;
814 			break;
815 		    }
816 		}
817 	    }
818 	    else if (!strcmp (strline, "f") || !strcmp (strline, "fo") ||
819 		     !strcmp (strline, "p") || !strcmp (strline, "l"))
820 	    {
821 		char *tmpPtr; /* used to check value of vertex/texture/normal */
822 
823 		if (!strcmp (strline, "l"))
824 		    complexity = 1;
825 		else if (!strcmp (strline, "f") || !strcmp (strline, "fo"))
826 		    complexity = 2;
827 
828 		while ((strline = getLineToken2 (fParser, TRUE)))
829 		{
830 		    int vertexIndex  = -1;
831 		    int textureIndex = -1;
832 		    int normalIndex  = -1;
833 		    int tmpInd;
834 
835 
836 		    tmpPtr = strsep (&strline, "/");
837 		    if (tmpPtr)
838 		    {
839 			vertexIndex = atoi (tmpPtr);
840 			if (vertexIndex > 0)
841 			{
842 			    /* skip vertex index past last in obj file */
843 			    if (vertexIndex > modelData->nVertex)
844 				break;
845 			    vertexIndex--;
846 			}
847 			else if (vertexIndex < 0)
848 			{
849 			    vertexIndex += nVertex;
850 
851 			    /* skip vertex index < 0 in obj file */
852 			    if (vertexIndex < 0)
853 				break;
854 			}
855 			else /* skip vertex index of 0 in obj file */
856 			    break;
857 		    }
858 		    else
859 			break;
860 
861 		    tmpPtr = strsep (&strline, "/");
862 		    if (tmpPtr && complexity != 0)
863 		    {
864 			/* texture */
865 
866 			if (tmpPtr[0] != '\0')
867 			{
868 			    textureIndex = atoi (tmpPtr);
869 
870 			    if (textureIndex > 0)
871 			    {
872 				 /* skip normal index past last in obj file */
873 				if (textureIndex > modelData->nTexture)
874 				    break;
875 				textureIndex--;
876 			    }
877 			    else if (textureIndex < 0)
878 			    {
879 				textureIndex += nTexture;
880 
881 				/* skip texture index < 0 in obj file */
882 				if (textureIndex < 0)
883 				    break;
884 			    }
885 			    else /* skip texture index of 0 in obj file */
886 				break;
887 
888 			    usingTexture = TRUE;
889 			}
890 
891 			tmpPtr = strsep (&strline, "/");
892 			if (tmpPtr)
893 			{
894 			    if (tmpPtr[0]!='\0' && complexity == 2)
895 			    {
896 				/* normal */
897 
898 				normalIndex = atoi (tmpPtr);
899 
900 				if (normalIndex > 0)
901 				{
902 				    /* skip normal index past last in obj file */
903 				    if (normalIndex > modelData->nNormal)
904 					break;
905 				    normalIndex--;
906 				}
907 				else if (normalIndex < 0)
908 				{
909 				    normalIndex += nNormal;
910 
911 				    /* skip normal index < 0 in obj file */
912 				    if (normalIndex < 0)
913 					break;
914 				}
915 				else /* skip normal index of 0 in obj file */
916 				    break;
917 
918 				usingNormal = TRUE;
919 			    }
920 			}
921 		    }
922 
923 		    /* reorder vertices/textures/normals */
924 
925 		    tmpInd = addVertex (&tmpIndices[vertexIndex],
926 					nUniqueIndices, textureIndex,
927 					normalIndex);
928 		    if (tmpInd < 0)
929 		    {
930 			if (nUniqueIndices >= sIndices)
931 			{
932 			    sIndices++;
933 			    modelData->reorderedVertex[fc]  =
934 				realloc (modelData->reorderedVertex[fc],
935 				         sizeof (vect3d) * sIndices);
936 			    modelData->reorderedTexture[fc] =
937 				realloc (modelData->reorderedTexture[fc],
938 				         sizeof (vect2d) * sIndices);
939 			    modelData->reorderedNormal[fc]  =
940 				realloc (modelData->reorderedNormal[fc],
941 				         sizeof (vect3d) * sIndices);
942 			}
943 
944 			if (vertexIndex < nVertex)
945 			{
946 			    memcpy (modelData->reorderedVertex[fc]
947 				    [nUniqueIndices].r,
948 				    vertex[vertexIndex].r,
949 				    3 * sizeof (float));
950 			}
951 			else
952 			{
953 			    for (i = 0; i < 3; i++)
954 				modelData->reorderedVertex[fc]
955 				    [nUniqueIndices].r[i] = 0;
956 			}
957 
958 			if (textureIndex >= 0 && textureIndex < nTexture)
959 			{
960 			    memcpy (modelData->reorderedTexture[fc]
961 				    [nUniqueIndices].r,
962 				    texture[textureIndex].r,
963 				    2 * sizeof (float));
964 
965 
966 			    /* scale as per 1st loaded texture for
967 			     * that material (1st frame)*/
968 
969 			    if (lastLoadedMaterial >=0 && modelData->tex)
970 			    {
971 				mtlStruct *currentMaterial =
972 				    &(modelData->material[fc]
973 				      [lastLoadedMaterial]);
974 
975 				if (currentMaterial->map_params >= 0)
976 				{
977 				    CompMatrix *ct =
978 					&((&(modelData->tex
979 					[currentMaterial->map_params]))->
980 					matrix);
981 
982 				    modelData->reorderedTexture[fc]
983 				    [nUniqueIndices].r[0] =
984 					COMP_TEX_COORD_X (ct,
985 					(currentMaterial->width - 1) *
986 					(texture[textureIndex].r[0]));
987 				    modelData->reorderedTexture[fc]
988 				    [nUniqueIndices].r[1] =
989 					COMP_TEX_COORD_Y (ct,
990 					(currentMaterial->height - 1) *
991 					(1 - texture[textureIndex].r[1]));
992 				}
993 			    }
994 			}
995 			else
996 			{
997 			    modelData->reorderedTexture[fc]
998 			    [nUniqueIndices].r[0] = 0;
999 			    modelData->reorderedTexture[fc]
1000 			    [nUniqueIndices].r[1] = 0;
1001 			}
1002 
1003 			if (normalIndex >= 0 && normalIndex < nNormal)
1004 			    memcpy (modelData->reorderedNormal[fc]
1005 				    [nUniqueIndices].r,
1006 				    normal[normalIndex].r,
1007 				    3 * sizeof (float));
1008 			else
1009 			{
1010 			    modelData->reorderedNormal[fc]
1011 				[nUniqueIndices].r[0] = 0;
1012 			    modelData->reorderedNormal[fc]
1013 				[nUniqueIndices].r[1] = 0;
1014 			    modelData->reorderedNormal[fc]
1015 				[nUniqueIndices].r[2] = 1;
1016 			}
1017 
1018 			modelData->indices[nIndices] = nUniqueIndices;
1019 			nUniqueIndices++;
1020 		    }
1021 		    else
1022 			modelData->indices[nIndices] = tmpInd;
1023 
1024 		    nIndices++;
1025 		    polyCount++;
1026 		}
1027 
1028 		updateGroup = TRUE;
1029 	    }
1030 
1031 	    if (!fParser->lastTokenOnLine)
1032 		skipLine (fParser);
1033 
1034 	    if (updateGroup && fc == 0)
1035 	    {
1036 		if (polyCount !=0 &&
1037 		    (polyCount != oldPolyCount       ||
1038 		     usingNormal != oldUsingNormal   ||
1039 		     usingTexture != oldUsingTexture ||
1040 		     lastLoadedMaterial != prevLoadedMaterial))
1041 		{
1042 		    oldPolyCount = polyCount;
1043 		    oldUsingTexture = usingTexture;
1044 		    oldUsingNormal  = usingNormal;
1045 		    prevLoadedMaterial = lastLoadedMaterial;
1046 
1047 		    modelData->group = realloc (modelData->group,
1048 						(nGroups + 1) *
1049 						sizeof (groupIndices));
1050 
1051 		    modelData->group[nGroups].polyCount = polyCount;
1052 		    modelData->group[nGroups].complexity = complexity;
1053 		    modelData->group[nGroups].startV = nIndices - polyCount;
1054 
1055 		    modelData->group[nGroups].materialIndex =
1056 			lastLoadedMaterial;
1057 
1058 		    if (nGroups > 0)
1059 			modelData->group[nGroups - 1].numV = nIndices -
1060 			    polyCount - modelData->group[nGroups - 1].startV;
1061 
1062 		    modelData->group[nGroups].texture = usingTexture;
1063 		    modelData->group[nGroups].normal  = usingNormal;
1064 
1065 		    nGroups++;
1066 		}
1067 	    }
1068 	}
1069 
1070 	if (nGroups != 0 && fc == 0)
1071 	    modelData->group[nGroups - 1].numV = nIndices -
1072 		modelData->group[nGroups - 1].startV;
1073 
1074 	if (fc == 0)
1075 	    modelData->nUniqueIndices = nUniqueIndices;
1076 
1077 	fclose (fp);
1078 
1079 	if (fc == 0 && modelData->animation)
1080 	{ /* set up 1st frame for display */
1081 	    vect3d *reorderedVertex  = modelData->reorderedVertex[0];
1082 	    vect3d *reorderedNormal  = modelData->reorderedNormal[0];
1083 
1084 	    for (i = 0; i < modelData->nUniqueIndices; i++)
1085 	    {
1086 		for (j = 0; j < 3; j++)
1087 		{
1088 		    modelData->reorderedVertexBuffer[i].r[j] =
1089 			reorderedVertex[i].r[j];
1090 		    modelData->reorderedNormalBuffer[i].r[j] =
1091 			reorderedNormal[i].r[j];
1092 		}
1093 	    }
1094 	}
1095 
1096     }
1097 
1098     modelData->nGroups = nGroups;
1099 
1100     if (vertex)
1101 	free (vertex);
1102     if (normal)
1103 	free (normal);
1104     if (texture)
1105 	free (texture);
1106 
1107 
1108     if (tmpIndices)
1109     {
1110 	for (i = 0; i < sVertex; i++)
1111 	    if (tmpIndices[i])
1112 		free (tmpIndices[i]);
1113 	free (tmpIndices);
1114     }
1115 
1116     freeFileParser (fParser);
1117 
1118     modelData->finishedLoading = TRUE;
1119 
1120     return TRUE;
1121 }
1122 
1123 static void *
loadModelObjectThread(void * ptr)1124 loadModelObjectThread (void *ptr)
1125 {
1126     CubemodelObject *modelData = (CubemodelObject *) ptr;
1127     modelData->threadRunning = TRUE;
1128 
1129     loadModelObject (modelData);
1130 
1131     modelData->updateAttributes = TRUE;
1132     modelData->threadRunning = FALSE;
1133 
1134     pthread_exit (NULL);
1135 }
1136 
1137 Bool
cubemodelAddModelObject(CompScreen * s,CubemodelObject * modelData,char * file,float * translate,float * rotate,float rotateSpeed,float * scale,float * color,Bool animation,float fps)1138 cubemodelAddModelObject (CompScreen      *s,
1139 			 CubemodelObject *modelData,
1140 			 char            *file,
1141 			 float           *translate,
1142                          float           *rotate,
1143 			 float           rotateSpeed,
1144                          float           *scale,
1145 			 float           *color,
1146                          Bool            animation,
1147 			 float           fps)
1148 {
1149     int  i, size;
1150     int  fileCounter = 0; /* value checked in cubemodelDeleteModelObject */
1151     int  lenFilename;
1152     int  startFileNum = 0;
1153     int  maxNumZeros = 6;
1154     int  lenBaseFilename;
1155     FILE *fp;
1156     Bool flag;
1157 
1158     modelData->fileCounter = 0;
1159     modelData->updateAttributes = FALSE;
1160 
1161     if (!file)
1162 	return FALSE;
1163     if (!strlen (file))
1164 	return FALSE;
1165 
1166     modelData->rotate[0] = rotate[0]; /* rotation angle */
1167     modelData->rotate[1] = rotate[1]; /* rotateX */
1168     modelData->rotate[2] = rotate[2]; /* rotateY */
1169     modelData->rotate[3] = rotate[3]; /* rotateZ */
1170 
1171     modelData->translate[0] = translate[0]; /* translateX */
1172     modelData->translate[1] = translate[1]; /* translateY */
1173     modelData->translate[2] = translate[2]; /* translateZ */
1174 
1175     modelData->scaleGlobal = scale[0];
1176     modelData->scale[0] = scale[1]; /* scaleX */
1177     modelData->scale[1] = scale[2]; /* scaleY */
1178     modelData->scale[2] = scale[3]; /* scaleZ */
1179 
1180     modelData->rotateSpeed = rotateSpeed;
1181     modelData->animation   = animation;
1182     modelData->fps         = fps;
1183     modelData->time        = 0;
1184 
1185     if (!color)
1186     {
1187 	modelData->color[0] = 1;
1188 	modelData->color[1] = 1;
1189 	modelData->color[2] = 1;
1190 	modelData->color[3] = 1;
1191     }
1192     else
1193     {
1194 	modelData->color[0] = color[0]; /* R */
1195 	modelData->color[1] = color[1]; /* G */
1196 	modelData->color[2] = color[2]; /* B */
1197 	modelData->color[3] = color[3]; /* alpha */
1198     }
1199 
1200     /* set to NULL so delete will not crash for threads */
1201     modelData->reorderedVertex        = NULL;
1202     modelData->reorderedTexture	      = NULL;
1203     modelData->reorderedNormal        = NULL;
1204     modelData->nMaterial 	      = NULL;
1205     modelData->material 	      = NULL;
1206     modelData->tex      	      = NULL;
1207     modelData->texName   	      = NULL;
1208     modelData->texWidth   	      = NULL;
1209     modelData->texHeight   	      = NULL;
1210     modelData->reorderedVertexBuffer  = NULL;
1211     modelData->reorderedTextureBuffer = NULL;
1212     modelData->reorderedNormalBuffer  = NULL;
1213     modelData->indices 		      = NULL;
1214     modelData->group                  = NULL;
1215 
1216 
1217     modelData->compiledDList = FALSE;
1218     modelData->finishedLoading = FALSE;
1219 
1220     modelData->threadRunning = FALSE;
1221 
1222     modelData->post = NULL;
1223     modelData->filename = NULL;
1224 
1225     lenFilename = strlen (file);
1226     size = lenFilename + 1 + 4;
1227 
1228     if (lenFilename > 3)
1229     {
1230 	if (strstr (file + lenFilename - 4, ".obj"))
1231 	{
1232 	    lenFilename -= 4;
1233 	    size -= 4;
1234 	}
1235     }
1236 
1237     modelData->filename = calloc (size, sizeof (char));
1238     if (!modelData->filename)
1239         return FALSE;
1240 
1241     strncpy (modelData->filename, file, lenFilename);
1242     if (!modelData->animation)
1243 	strcat (modelData->filename, ".obj");
1244 
1245     lenBaseFilename = lenFilename;
1246 
1247     if (modelData->animation)
1248     {
1249 	char *start, *numbers = NULL;
1250 	char *post = modelData->filename + lenFilename;
1251 
1252 	start = strrchr (modelData->filename, '/');
1253 	if (!start)
1254 	    start = modelData->filename;
1255 
1256 	start++;
1257 
1258 	Bool lastCharANumber = FALSE;
1259 
1260 	while (*start)
1261 	{
1262 	    if (*start >= '0' && *start <= '9')
1263 	    {
1264 		if (!numbers || !lastCharANumber)
1265 		    numbers = start;
1266 		post = start + 1;
1267 
1268 		lastCharANumber = TRUE;
1269 	    }
1270 	    else
1271 		lastCharANumber = FALSE;
1272 
1273 	    start++;
1274 	}
1275 
1276 	if (numbers)
1277 	{
1278 	    lenBaseFilename = numbers - modelData->filename;
1279 	    maxNumZeros     = post - numbers;
1280 
1281 	    modelData->post = strdup (post);
1282 	    if (!modelData->post)
1283 		return FALSE;
1284 
1285 	    strncpy (modelData->filename, file, lenBaseFilename);
1286 	    startFileNum = strtol (numbers, NULL, 10);
1287 	}
1288 	else
1289 	{
1290 	    modelData->animation = FALSE;
1291 	    strcat (modelData->filename, ".obj");
1292 	}
1293     }
1294 
1295     /* verify existence of files and/or check for animation frames */
1296 
1297     do
1298     {
1299 	if (modelData->animation)
1300 	    size = addNumToString (&modelData->filename, size,
1301 				   lenBaseFilename, modelData->post,
1302 				   startFileNum + fileCounter, maxNumZeros);
1303 
1304 	fp = fopen (modelData->filename, "r");
1305 	if (fp)
1306 	{
1307 	    printf ("opened %s\n", modelData->filename);
1308 
1309 	    fclose (fp);
1310 	    fileCounter++;
1311 	}
1312     }
1313     while (modelData->animation && fp);
1314 
1315     modelData->fileCounter = fileCounter;
1316     if (!fileCounter)
1317     {
1318 	compLogMessage ("cubemodel", CompLogLevelWarn,
1319 			"Failed to open model file : %s", modelData->filename);
1320 
1321 	if (modelData->filename)
1322 	    free (modelData->filename);
1323 	if (modelData->post)
1324 	    free (modelData->post);
1325 
1326 	return FALSE;
1327     }
1328 
1329     modelData->reorderedVertex  = malloc (sizeof (vect3d *) * fileCounter);
1330     modelData->reorderedTexture = malloc (sizeof (vect2d *) * fileCounter);
1331     modelData->reorderedNormal  = malloc (sizeof (vect3d *) * fileCounter);
1332 
1333     modelData->reorderedVertexBuffer  = NULL;
1334     modelData->reorderedTextureBuffer = NULL;
1335     modelData->reorderedNormalBuffer  = NULL;
1336 
1337     modelData->material  = malloc (sizeof (mtlStruct *) * fileCounter);
1338     modelData->nMaterial = malloc (sizeof (int) * fileCounter);
1339 
1340     for (i = 0; i < fileCounter; i++)
1341     {
1342 	modelData->material[i]  = 0;
1343 	modelData->nMaterial[i] = 0;
1344     }
1345 
1346     modelData->tex = NULL;
1347     modelData->texName = NULL;
1348     modelData->nTex = 0;
1349     modelData->texWidth = NULL;
1350     modelData->texHeight = NULL;
1351 
1352     modelData->indices = NULL;
1353     modelData->group = NULL;
1354 
1355     modelData->size = size;
1356     modelData->lenBaseFilename = lenBaseFilename;
1357     modelData->startFileNum = startFileNum;
1358     modelData->maxNumZeros = maxNumZeros;
1359 
1360     flag = initLoadModelObject (s, modelData);
1361 
1362     if (flag)
1363     {
1364 	if  (cubemodelGetConcurrentLoad (s))
1365 	{
1366 	    int iret;
1367 
1368 	    modelData->threadRunning = TRUE;
1369 
1370 	    iret = pthread_create (&modelData->thread, NULL,
1371 				   loadModelObjectThread,
1372 				   (void*) modelData);
1373 	    if (!iret)
1374 		return TRUE;
1375 
1376 	    compLogMessage ("cubemodel", CompLogLevelWarn,
1377 			    "Error creating thread: %s\n"
1378 			    "Trying single threaded approach", file);
1379 	    modelData->threadRunning = FALSE;
1380 	}
1381 
1382 	flag = loadModelObject (modelData);
1383     }
1384 
1385     return flag;
1386 }
1387 
1388 Bool
cubemodelDeleteModelObject(CompScreen * s,CubemodelObject * data)1389 cubemodelDeleteModelObject (CompScreen      *s,
1390 			    CubemodelObject *data)
1391 {
1392     int i, fc;
1393 
1394     if (!data)
1395 	return FALSE;
1396 
1397     if (data->fileCounter == 0)
1398 	return FALSE;
1399 
1400     if (data->threadRunning)
1401     {
1402 	int ret;
1403 
1404 	ret = pthread_join (data->thread, NULL); /* not best in all
1405 						    circumstances */
1406 	if (ret)
1407 	{
1408 	    compLogMessage ("cubemodel", CompLogLevelWarn,
1409 			    "Could not synchronize with thread.\n"
1410 			    "Possible memory leak)");
1411 	    return FALSE;
1412 	}
1413     }
1414 
1415     if (data->filename)
1416 	free (data->filename);
1417 
1418     if (data->post)
1419 	free (data->post);
1420 
1421     if (!data->animation && data->compiledDList)
1422 	glDeleteLists (data->dList, 1);
1423 
1424     for (fc = 0; fc < data->fileCounter; fc++)
1425     {
1426 	if (data->reorderedVertex && data->reorderedVertex[fc])
1427 	    free (data->reorderedVertex[fc]);
1428 	if (data->reorderedTexture && data->reorderedTexture[fc])
1429 	    free (data->reorderedTexture[fc]);
1430 	if (data->reorderedNormal && data->reorderedNormal[fc])
1431 	    free (data->reorderedNormal[fc]);
1432 
1433 	if (data->nMaterial)
1434 	{
1435 	    for (i = 0; i< data->nMaterial[fc]; i++)
1436 	    {
1437 		if (data->material[fc][i].name)
1438 		    free (data->material[fc][i].name);
1439 	    }
1440 	}
1441 
1442 	if (data->material && data->material[fc])
1443 	    free(data->material[fc]);
1444     }
1445 
1446     if (data->tex)
1447     {
1448 	for (i = 0; i < data->nTex; i++)
1449 	{
1450 	    if (&(data->tex[i]) != NULL)
1451 		finiTexture (s, &(data->tex[i]));
1452 	}
1453 	free (data->tex);
1454     }
1455 
1456     if (data->texName)
1457     {
1458 	for (i = 0; i < data->nTex; i++)
1459 	{
1460 	    if (data->texName[i])
1461 		free (data->texName[i]);
1462 	}
1463     }
1464 
1465     if (data->texWidth)
1466 	free (data->texWidth);
1467     if (data->texHeight)
1468 	free (data->texHeight);
1469 
1470     if (data->reorderedVertex)
1471 	free (data->reorderedVertex);
1472     if (data->reorderedTexture)
1473 	free (data->reorderedTexture);
1474     if (data->reorderedNormal)
1475 	free (data->reorderedNormal);
1476     if (data->material)
1477 	free (data->material);
1478 
1479     if (data->reorderedVertexBuffer)
1480 	free (data->reorderedVertexBuffer);
1481     if (data->reorderedTextureBuffer)
1482 	free (data->reorderedTextureBuffer);
1483     if (data->reorderedNormalBuffer)
1484 	free (data->reorderedNormalBuffer);
1485 
1486     if (data->indices)
1487 	free (data->indices);
1488     if (data->group)
1489 	free (data->group);
1490 
1491     return TRUE;
1492 }
1493 
1494 Bool
cubemodelDrawModelObject(CompScreen * s,CubemodelObject * data,float scale)1495 cubemodelDrawModelObject (CompScreen      *s,
1496 			  CubemodelObject *data,
1497 			  float           scale)
1498 {
1499     if (!data->fileCounter || !data->finishedLoading)
1500 	return FALSE;
1501 
1502     if (!data->animation && !data->compiledDList)
1503 	compileDList (s, data);
1504 
1505     /* Rotate, translate and scale  */
1506 
1507     glTranslatef (data->translate[0], data->translate[2], data->translate[1]);
1508 
1509     glScalef (data->scaleGlobal * data->scale[0],
1510 	      data->scaleGlobal * data->scale[1],
1511 	      data->scaleGlobal * data->scale[2]);
1512 
1513     glScalef (scale, scale, scale);
1514 
1515     glRotatef (data->rotate[0], data->rotate[1],
1516 	       data->rotate[2], data->rotate[3]);
1517 
1518     glDisable (GL_CULL_FACE);
1519     glEnable (GL_NORMALIZE);
1520     glEnable (GL_DEPTH_TEST);
1521 
1522     glEnable (GL_COLOR_MATERIAL);
1523     glColor4fv (data->color);
1524 
1525     if (data->animation)
1526     {
1527 	cubemodelDrawVBOModel (s, data,
1528 	                       (float *) data->reorderedVertexBuffer,
1529 	                       (float *) data->reorderedNormalBuffer);
1530     }
1531     else
1532     {
1533 	glCallList (data->dList);
1534     }
1535 
1536     return TRUE;
1537 }
1538 
1539 Bool
cubemodelUpdateModelObject(CompScreen * s,CubemodelObject * data,float time)1540 cubemodelUpdateModelObject (CompScreen      *s,
1541 			    CubemodelObject *data,
1542 			    float           time)
1543 {
1544     int i, j;
1545 
1546     if (!data->fileCounter || !data->finishedLoading)
1547 	return FALSE;
1548 
1549     if (!data->animation && !data->compiledDList)
1550 	compileDList (s, data);
1551 
1552     data->rotate[0] += 360 * time * data->rotateSpeed;
1553     data->rotate[0] = fmodf (data->rotate[0], 360.0f);
1554 
1555     if (data->animation && data->fps)
1556     {
1557 	float  t, dt, dt2;
1558 	int    ti, ti2;
1559 	vect3d *reorderedVertex, *reorderedVertex2;
1560 	vect3d *reorderedNormal, *reorderedNormal2;
1561 
1562 	data->time += time * data->fps;
1563 	data->time = fmodf (data->time, (float) data->fileCounter);
1564 
1565 	t = data->time;
1566 	if (t < 0)
1567 	    t += (float) data->fileCounter;
1568 
1569 	ti  = (int) t;
1570 	ti2 = (ti + 1) % data->fileCounter;
1571 	dt  = t - ti;
1572 	dt2 = 1 - dt;
1573 
1574 	reorderedVertex  = data->reorderedVertex[ti];
1575 	reorderedVertex2 = data->reorderedVertex[ti2];
1576 	reorderedNormal  = data->reorderedNormal[ti];
1577 	reorderedNormal2 = data->reorderedNormal[ti2];
1578 
1579 	for (i = 0; i < data->nUniqueIndices; i++)
1580 	{
1581 	    for (j = 0; j < 3; j++)
1582 	    {
1583 		data->reorderedVertexBuffer[i].r[j] =
1584 		    dt2 * (reorderedVertex[i].r[j]) +
1585 		    dt  * (reorderedVertex2[i].r[j]);
1586 		data->reorderedNormalBuffer[i].r[j] =
1587 		    dt2 * (reorderedNormal[i].r[j]) +
1588 		    dt  * (reorderedNormal2[i].r[j]);
1589 	    }
1590 	}
1591     }
1592 
1593     return TRUE;
1594 }
1595 
1596 static void
setMaterial(const float * shininess,const float * ambient,const float * diffuse,const float * specular)1597 setMaterial (const float *shininess,
1598 	     const float *ambient,
1599 	     const float *diffuse,
1600 	     const float *specular)
1601 {
1602     glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1603 
1604     glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, shininess);
1605     glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
1606     glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
1607     glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, specular);
1608 }
1609 
1610 Bool
cubemodelDrawVBOModel(CompScreen * s,CubemodelObject * data,float * vertex,float * normal)1611 cubemodelDrawVBOModel (CompScreen      *s,
1612 		       CubemodelObject *data,
1613 		       float           *vertex,
1614 		       float           *normal)
1615 {
1616     groupIndices *group;
1617     int          i, j;
1618 
1619     static const float white[4] = { 1.0, 1.0, 1.0, 1.0 };
1620     static const float black[4] = { 0.0, 0.0, 0.0, 0.0 };
1621     static const float defaultShininess[1] = { 100 };
1622 
1623     float *v = vertex;
1624     float *n = normal;
1625     float *t = (float *) data->reorderedTexture[0];
1626 
1627     CompTexture *currentTexture = NULL;
1628     int         currentTextureIndex = -1; /* last loaded texture -
1629 					     to prevent multiple loadings */
1630 
1631     Bool prevNormal = TRUE, prevTexture = FALSE;
1632 
1633     int prevMaterialIndex = -1;
1634 
1635     int ambientTextureIndex     = -1;
1636     int diffuseTextureIndex     = -1;
1637     int specularTextureIndex    = -1;
1638     int transparentTextureIndex = -1;
1639 
1640     const float *ambient   = white;
1641     const float *diffuse   = white;
1642     const float *specular  = white;
1643     const float *shininess = defaultShininess;
1644 
1645     glVertexPointer (3, GL_FLOAT, 0, v);
1646     glNormalPointer (GL_FLOAT, 0, n);
1647     glTexCoordPointer (2, GL_FLOAT, 0, t);
1648 
1649     glEnableClientState (GL_VERTEX_ARRAY);
1650     glEnableClientState (GL_NORMAL_ARRAY);
1651     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1652     glDisable (GL_TEXTURE_2D);
1653 
1654     for (i = 0; i < data->nGroups; i++)
1655     {
1656 	GLenum cap = GL_QUADS;
1657 
1658 	group = &(data->group[i]);
1659 	if (group->polyCount < 1)
1660 	    continue;
1661 
1662 	if (group->polyCount == 3)
1663 	    cap = GL_TRIANGLES;
1664 	if (group->polyCount == 2 || group->complexity == 1)
1665 	    cap = GL_LINE_LOOP;
1666 	if (group->polyCount == 1 || group->complexity == 0)
1667 	    cap = GL_POINTS;
1668 
1669 	if (group->normal && !prevNormal)
1670 	{
1671 	    glEnableClientState (GL_NORMAL_ARRAY);
1672 	    prevNormal = TRUE;
1673 	}
1674 	else if (!group->normal && prevNormal)
1675 	{
1676 	    glDisableClientState (GL_NORMAL_ARRAY);
1677 	    prevNormal = FALSE;
1678 	}
1679 
1680 	if (group->materialIndex >= 0)
1681 	{
1682 	    if (group->materialIndex != prevMaterialIndex)
1683 	    {
1684 		glDisable (GL_COLOR_MATERIAL);
1685 
1686 		ambientTextureIndex     =
1687 		    data->material[0][group->materialIndex].map_Ka;
1688 		diffuseTextureIndex     =
1689 		    data->material[0][group->materialIndex].map_Kd;
1690 		specularTextureIndex    =
1691 		    data->material[0][group->materialIndex].map_Ks;
1692 		transparentTextureIndex =
1693 		    data->material[0][group->materialIndex].map_d;
1694 
1695 		ambient   = data->material[0][group->materialIndex].Ka;
1696 		diffuse   = data->material[0][group->materialIndex].Kd;
1697 		specular  = data->material[0][group->materialIndex].Ks;
1698 		shininess = data->material[0][group->materialIndex].Ns;
1699 
1700 		setMaterial (shininess, ambient, diffuse, specular);
1701 
1702 		switch (data->material[0][group->materialIndex].illum) {
1703 		case 0:
1704 		    glDisable (GL_LIGHTING);
1705 		    break;
1706 		case 1:
1707 		    specular = black;
1708 		default:
1709 		    glEnable (GL_LIGHTING);
1710 		}
1711 	    }
1712 	    prevMaterialIndex = group->materialIndex;
1713 	}
1714 
1715 	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1716 
1717 	if (group->texture && transparentTextureIndex >= 0)
1718 	{
1719 	    if (!prevTexture)
1720 	    {
1721 		glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1722 		glEnable (GL_TEXTURE_2D);
1723 		prevTexture = TRUE;
1724 	    }
1725 
1726 	    if (transparentTextureIndex >= 0)
1727 	    {
1728 		if (!currentTexture ||
1729 		    transparentTextureIndex != currentTextureIndex)
1730 		{
1731 		    currentTextureIndex = transparentTextureIndex;
1732 		    if (currentTexture)
1733 			disableTexture (s, currentTexture);
1734 
1735 		    currentTexture =  &(data->tex[transparentTextureIndex]);
1736 		    if (currentTexture)
1737 		    {
1738 			glEnable (currentTexture->target);
1739 			enableTexture (s, currentTexture,
1740 				       COMP_TEXTURE_FILTER_GOOD);
1741 		    }
1742 		}
1743 
1744 		glBlendFunc (GL_SRC_ALPHA, GL_ONE);
1745 		setMaterial (shininess, white, white, white);
1746 
1747 		if (data->group[i].polyCount < 5)
1748 		    glDrawElements (cap, group->numV, GL_UNSIGNED_INT,
1749 				    data->indices + group->startV);
1750 		else
1751 		{
1752 		    for (j = 0; j < group->numV / group->polyCount; j++)
1753 		    {
1754 			glDrawElements (GL_POLYGON,
1755 					group->polyCount,
1756 					GL_UNSIGNED_INT,
1757 					data->indices + group->startV +
1758 					j * group->polyCount);
1759 		    }
1760 		}
1761 
1762 		glBlendFunc (GL_ONE_MINUS_DST_ALPHA, GL_SRC_COLOR);
1763 		setMaterial (shininess, ambient, diffuse, specular);
1764 	    }
1765 	}
1766 
1767 	if (group->texture && diffuseTextureIndex >= 0)
1768 	{
1769 	    if (!prevTexture)
1770 	    {
1771 		glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1772 		glEnable (GL_TEXTURE_2D);
1773 		prevTexture = TRUE;
1774 	    }
1775 
1776 	    glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, white);
1777 
1778 	    if (!currentTexture || diffuseTextureIndex != currentTextureIndex)
1779 	    {
1780 		currentTextureIndex = diffuseTextureIndex;
1781 		if (currentTexture)
1782 		    disableTexture (s, currentTexture);
1783 
1784 		currentTexture =  &(data->tex[diffuseTextureIndex]);
1785 		if (currentTexture)
1786 		{
1787 		    glEnable (currentTexture->target);
1788 		    enableTexture (s, currentTexture, COMP_TEXTURE_FILTER_GOOD);
1789 		}
1790 	    }
1791 	}
1792 	else
1793 	{
1794 	    if (prevTexture)
1795 	    {
1796 		glDisable (GL_TEXTURE_2D);
1797 		glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1798 		prevTexture = FALSE;
1799 	    }
1800 
1801 	    glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
1802 	}
1803 
1804 	if (data->group[i].polyCount < 5)
1805 	    glDrawElements (cap, group->numV, GL_UNSIGNED_INT,
1806 			    data->indices + group->startV);
1807 	else
1808 	{
1809 	    for (j = 0; j < group->numV/group->polyCount; j++)
1810 	    {
1811 		glDrawElements (GL_POLYGON, group->polyCount, GL_UNSIGNED_INT,
1812 				data->indices + group->startV +
1813 				j * group->polyCount);
1814 	    }
1815 	}
1816     }
1817 
1818     if (currentTexture)
1819 	disableTexture (s, currentTexture);
1820 
1821     glDisable (GL_TEXTURE_2D);
1822     glDisableClientState (GL_NORMAL_ARRAY);
1823     glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1824 
1825     return TRUE;
1826 }
1827