Пример #1
0
/*!
 * Calculates the vertex normals corresponding to the smoothing group
 * settings for each face of a mesh.
 *
 * \param mesh      A pointer to the mesh to calculate the normals for.
 * \param normalL   A pointer to a buffer to store the calculated
 *                  normals. The buffer must have the size:
 *                  3*sizeof(Lib3dsVector)*mesh->faces. 
 *
 * To allocate the normal buffer do for example the following:
 * \code
 *  Lib3dsVector *normalL = malloc(3*sizeof(Lib3dsVector)*mesh->faces);
 * \endcode
 *
 * To access the normal of the i-th vertex of the j-th face do the 
 * following:
 * \code
 *   normalL[3*j+i]
 * \endcode
 *
 * \ingroup mesh
 */
void
lib3ds_mesh_calculate_normals(Lib3dsMesh *mesh, Lib3dsVector *normalL)
{
  Lib3dsFaces **fl; 
  Lib3dsFaces *fa; 
  unsigned i,j,k;

  if (!mesh->faces) {
    return;
  }

  fl=calloc(sizeof(Lib3dsFaces*),mesh->points);
  ASSERT(fl);
  fa=calloc(sizeof(Lib3dsFaces),3*mesh->faces);
  ASSERT(fa);
  k=0;
  for (i=0; i<mesh->faces; ++i) {
    Lib3dsFace *f=&mesh->faceL[i];
    for (j=0; j<3; ++j) {
      Lib3dsFaces* l=&fa[k++];
      ASSERT(f->points[j]<mesh->points);
      l->face=f;
      l->next=fl[f->points[j]];
      fl[f->points[j]]=l;
    }
  }
  
  for (i=0; i<mesh->faces; ++i) {
    Lib3dsFace *f=&mesh->faceL[i];
    for (j=0; j<3; ++j) {
      // FIXME: static array needs at least check!!
      Lib3dsVector n,N[128];
      Lib3dsFaces *p;
      int k,l;
      int found;

      ASSERT(f->points[j]<mesh->points);

      if (f->smoothing) {
        lib3ds_vector_zero(n);
        k=0;
        for (p=fl[f->points[j]]; p; p=p->next) {
          found=0;
          for (l=0; l<k; ++l) {
	    if( l >= 128 )
	      printf("array N overflow: i=%d, j=%d, k=%d\n", i,j,k);
            if (fabs(lib3ds_vector_dot(N[l], p->face->normal)-1.0)<1e-5) {
              found=1;
              break;
            }
          }
          if (!found) {
            if (f->smoothing & p->face->smoothing) {
              lib3ds_vector_add(n,n, p->face->normal);
              lib3ds_vector_copy(N[k], p->face->normal);
              ++k;
            }
          }
        }
      } 
      else {
        lib3ds_vector_copy(n, f->normal);
      }
      lib3ds_vector_normalize(n);

      lib3ds_vector_copy(normalL[3*i+j], n);
    }
  }

  free(fa);
  free(fl);
}
Пример #2
0
/*!
 * Calculates the vertex normals corresponding to the smoothing group
 * settings for each face of a mesh.
 *
 * \param mesh      A pointer to the mesh to calculate the normals for.
 * \param normals   A pointer to a buffer to store the calculated
 *                  normals. The buffer must have the size:
 *                  3*3*sizeof(float)*mesh->nfaces.
 *
 * To allocate the normal buffer do for example the following:
 * \code
 *  Lib3dsVector *normals = malloc(3*3*sizeof(float)*mesh->nfaces);
 * \endcode
 *
 * To access the normal of the i-th vertex of the j-th face do the
 * following:
 * \code
 *   normals[3*j+i]
 * \endcode
 */
void
lib3ds_mesh_calculate_vertex_normals(Lib3dsMesh *mesh, float (*normals)[3]) {
    Lib3dsFaces **fl;
    Lib3dsFaces *fa;
    int i, j;

    if (!mesh->nfaces) {
        return;
    }

    fl = (Lib3dsFaces**)calloc(sizeof(Lib3dsFaces*), mesh->nvertices);
    fa = (Lib3dsFaces*)malloc(sizeof(Lib3dsFaces) * 3 * mesh->nfaces);

    for (i = 0; i < mesh->nfaces; ++i) {
        for (j = 0; j < 3; ++j) {
            Lib3dsFaces* l = &fa[3*i+j];
            float p[3], q[3], n[3];
            float len, weight;

            l->index = i;
            l->next = fl[mesh->faces[i].index[j]];
            fl[mesh->faces[i].index[j]] = l;

            lib3ds_vector_sub(p, mesh->vertices[mesh->faces[i].index[j<2? j + 1 : 0]], mesh->vertices[mesh->faces[i].index[j]]);
            lib3ds_vector_sub(q, mesh->vertices[mesh->faces[i].index[j>0? j - 1 : 2]], mesh->vertices[mesh->faces[i].index[j]]);
            lib3ds_vector_cross(n, p, q);
            len = lib3ds_vector_length(n);
            if (len > 0) {
                weight = (float)atan2(len, lib3ds_vector_dot(p, q));
                lib3ds_vector_scalar_mul(l->normal, n, weight / len);
            } else {
                lib3ds_vector_zero(l->normal);
            }
        }
    }

    for (i = 0; i < mesh->nfaces; ++i) {
        Lib3dsFace *f = &mesh->faces[i];
        for (j = 0; j < 3; ++j) {
            float n[3];
            Lib3dsFaces *p;
            Lib3dsFace *pf;

            assert(mesh->faces[i].index[j] < mesh->nvertices);

            if (f->smoothing_group) {
                unsigned smoothing_group = f->smoothing_group;

                lib3ds_vector_zero(n);
                for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) {
                    pf = &mesh->faces[p->index];
                    if (pf->smoothing_group & f->smoothing_group)
                        smoothing_group |= pf->smoothing_group;
                }

                for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) {
                    pf = &mesh->faces[p->index];
                    if (smoothing_group & pf->smoothing_group) {
                        lib3ds_vector_add(n, n, p->normal);
                    }
                }
            } else {
                lib3ds_vector_copy(n, fa[3*i+j].normal);
            }

            lib3ds_vector_normalize(n);
            lib3ds_vector_copy(normals[3*i+j], n);
        }
    }

    free(fa);
    free(fl);
}
Пример #3
0
/*!
* Render node recursively, first children, then parent.
* Each node receives its own OpenGL display list.
*/
static void
render_node(Lib3dsNode *node) {
	assert(file);
	
	
	{
		Lib3dsNode *p;
		for (p = node->childs; p != 0; p = p->next) {
			render_node(p);
		}
	}
	if (node->type == LIB3DS_NODE_MESH_INSTANCE) {
		int index;
		Lib3dsMesh *mesh;
		Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
		
		
		if (strcmp(node->name, "$$$DUMMY") == 0) {
			return;
		}
		
		
		index = lib3ds_file_mesh_by_name(file, n->instance_name);
		if (index < 0)
			index = lib3ds_file_mesh_by_name(file, node->name);
		if (index < 0) {
			return;
		}
		mesh = file->meshes[index];
		
		
		if (!mesh->user_id) {
			assert(mesh);
			
			
			mesh->user_id = glGenLists(1);
			glNewList(mesh->user_id, GL_COMPILE);
			
			
			{
				int p;
				float (*normalL)[3] = (float(*)[3])malloc(3 * 3 * sizeof(float) * mesh->nfaces);
				Lib3dsMaterial *oldmat = (Lib3dsMaterial *) - 1;
				{
					float M[4][4];
					lib3ds_matrix_copy(M, mesh->matrix);
					lib3ds_matrix_inv(M);
					glMultMatrixf(&M[0][0]);
				}
				lib3ds_mesh_calculate_vertex_normals(mesh, normalL);
				
				
				for (p = 0; p < mesh->nfaces; ++p) {
					Lib3dsMaterial *mat = 0;
#ifdef USE_SDL
					Player_texture *pt = NULL;
					int tex_mode = 0;
#endif
					if (mesh->faces[p].material > 0) {
						mat = file->materials[mesh->faces[p].material];
					}
					
					
					if (mat != oldmat) {
						if (mat) {
							if (mat->two_sided)
								glDisable(GL_CULL_FACE);
							else
								glEnable(GL_CULL_FACE);
							
							
							glDisable(GL_CULL_FACE);
							
							
							/* Texturing added by Gernot < *****@*****.** > */
							
							
							if (mat->texture1_map.name[0]) { /* texture map? */
								Lib3dsTextureMap *tex = &mat->texture1_map;
								if (!tex->user_ptr) { /* no player texture yet? */
									char texname[1024];
									pt = (Player_texture*)malloc(sizeof(*pt));
									tex->user_ptr = pt;
									//snprintf(texname, sizeof(texname), "%s/%s", datapath, tex->name);
									strcpy(texname, datapath);
									strcat(texname, "/");
									strcat(texname, tex->name);
#ifdef DEBUG
									printf("Loading texture map, name %s\n", texname);
#endif /* DEBUG */
#ifdef USE_SDL
#ifdef USE_SDL_IMG_load
									pt->bitmap = IMG_load(texname);
#else
									pt->bitmap = IMG_Load(texname);
#endif /* IMG_Load */
									
									
#else /* USE_SDL */
									pt->bitmap = NULL;
									fputs("3dsplayer: Warning: No image loading support, skipping texture.\n", stderr);
#endif /* USE_SDL */
									if (pt->bitmap) { /* could image be loaded ? */
																		/* this OpenGL texupload code is incomplete format-wise!
																		* to make it complete, examine SDL_surface->format and
																		* tell us @lib3ds.sf.net about your improvements :-)
										*/
										int upload_format = GL_RED; /* safe choice, shows errors */
#ifdef USE_SDL
										int bytespp = pt->bitmap->format->BytesPerPixel;
										void *pixel = NULL;
										glGenTextures(1, &pt->tex_id);
#ifdef DEBUG
										printf("Uploading texture to OpenGL, id %d, at %d bytepp\n",
											pt->tex_id, bytespp);
#endif /* DEBUG */
										if (pt->bitmap->format->palette) {
											pixel = convert_to_RGB_Surface(pt->bitmap);
											upload_format = GL_RGBA;
										} else {
											pixel = pt->bitmap->pixels;
											/* e.g. this could also be a color palette */
											if (bytespp == 1) upload_format = GL_LUMINANCE;
											else if (bytespp == 3) upload_format = GL_RGB;
											else if (bytespp == 4) upload_format = GL_RGBA;
										}
										glBindTexture(GL_TEXTURE_2D, pt->tex_id);
										glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
											TEX_XSIZE, TEX_YSIZE, 0,
											GL_RGBA, GL_UNSIGNED_BYTE, NULL);
										glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
										glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
										glTexParameteri(GL_TEXTURE_2D,
											GL_TEXTURE_MAG_FILTER, GL_LINEAR);
										glTexParameteri(GL_TEXTURE_2D,
											GL_TEXTURE_MIN_FILTER, GL_LINEAR);
										glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
										glTexSubImage2D(GL_TEXTURE_2D,
											0, 0, 0, pt->bitmap->w, pt->bitmap->h,
											upload_format, GL_UNSIGNED_BYTE, pixel);
										pt->scale_x = (float)pt->bitmap->w / (float)TEX_XSIZE;
										pt->scale_y = (float)pt->bitmap->h / (float)TEX_YSIZE;
#endif /* USE_SDL */
										pt->valid = 1;
									} else {
										fprintf(stderr,
											"Load of texture %s did not succeed "
											"(format not supported !)\n",
											texname);
										pt->valid = 0;
									}
								} else {
									pt = (Player_texture *)tex->user_ptr;
								}
								tex_mode = pt->valid;
							} else {
								tex_mode = 0;
							}
							
							
							{
								float a[4], d[4], s[4];
								int i;
								for (i=0; i<3; ++i) {
									a[i] = mat->ambient[i];
									d[i] = mat->diffuse[i];
									s[i] = mat->specular[i];
								}
								a[3] = d[3] = s[3] = 1.0f;
								
								glMaterialfv(GL_FRONT, GL_AMBIENT, a);
								glMaterialfv(GL_FRONT, GL_DIFFUSE, d);
								glMaterialfv(GL_FRONT, GL_SPECULAR, s);
							}
							glMaterialf(GL_FRONT, GL_SHININESS, pow(2, 10.0*mat->shininess));
 } else {
	 static const float a[4] = {0.7, 0.7, 0.7, 1.0};
	 static const float d[4] = {0.7, 0.7, 0.7, 1.0};
	 static const float s[4] = {1.0, 1.0, 1.0, 1.0};
	 glMaterialfv(GL_FRONT, GL_AMBIENT, a);
	 glMaterialfv(GL_FRONT, GL_DIFFUSE, d);
	 glMaterialfv(GL_FRONT, GL_SPECULAR, s);
	 glMaterialf(GL_FRONT, GL_SHININESS, pow(2, 10.0*0.5));
 }
 oldmat = mat;
 }
 
 
 else if (mat != NULL && mat->texture1_map.name[0]) {
	 Lib3dsTextureMap *tex = &mat->texture1_map;
	 if (tex != NULL && tex->user_ptr != NULL) {
		 pt = (Player_texture *)tex->user_ptr;
		 tex_mode = pt->valid;
	 }
 }
 
 
 
 
 {
	 int i;
	 
#ifndef USE_GL10
	 if (tex_mode) {
		 //printf("Binding texture %d\n", pt->tex_id);
		 glEnable(GL_TEXTURE_2D);
		 glBindTexture(GL_TEXTURE_2D, pt->tex_id);
	 }
#endif	 
	 
#if 0
	 {
		 float v1[3], n[3], v2[3];
		 glBegin(GL_LINES);
		 for (i = 0; i < 3; ++i) {
			 lib3ds_vector_copy(v1, mesh->vertices[f->points[i]]);
			 glVertex3fv(v1);
			 lib3ds_vector_copy(n, normalL[3*p+i]);
			 lib3ds_vector_scalar(n, 10.f);
			 lib3ds_vector_add(v2, v1, n);
			 glVertex3fv(v2);
		 }
		 glEnd();
	 }
#endif
	 
	 
	 glBegin(GL_TRIANGLES);
	 for (i = 0; i < 3; ++i) {
		 glNormal3fv(normalL[3*p+i]);
		 
		 
		 if (tex_mode) {
			 glTexCoord2f(
				 mesh->texcos[mesh->faces[p].index[i]][1]*pt->scale_x,
				 pt->scale_y - mesh->texcos[mesh->faces[p].index[i]][0]*pt->scale_y);
		 }
		 
		 
		 glVertex3fv(mesh->vertices[mesh->faces[p].index[i]]);
	 }
	 glEnd();
	 
	 
	 if (tex_mode)
		 glDisable(GL_TEXTURE_2D);
 }
 }
 
 
 free(normalL);
 }
 
 
 glEndList();
 }
 
 
 if (mesh->user_id) {
	 glPushMatrix();
	 glMultMatrixf(&node->matrix[0][0]);
	 glTranslatef(-n->pivot[0], -n->pivot[1], -n->pivot[2]);
	 glCallList(mesh->user_id);
	 /* glutSolidSphere(50.0, 20,20); */
	 glPopMatrix();
	 if (flush)
		 glFlush();
 }
 }
}