📄 glm.c
字号:
/* reverse facet normals */ for (i = 1; i <= model->numfacetnorms; i++) { model->facetnorms[3 * i + 0] = -model->facetnorms[3 * i + 0]; model->facetnorms[3 * i + 1] = -model->facetnorms[3 * i + 1]; model->facetnorms[3 * i + 2] = -model->facetnorms[3 * i + 2]; } /* reverse vertex normals */ for (i = 1; i <= model->numnormals; i++) { model->normals[3 * i + 0] = -model->normals[3 * i + 0]; model->normals[3 * i + 1] = -model->normals[3 * i + 1]; model->normals[3 * i + 2] = -model->normals[3 * i + 2]; }}/* glmFacetNormals: Generates facet normals for a model (by taking the * cross product of the two vectors derived from the sides of each * triangle). Assumes a counter-clockwise winding. * * model - initialized GLMmodel structure */GLvoidglmFacetNormals(GLMmodel* model){ GLuint i; GLfloat u[3]; GLfloat v[3]; assert(model); assert(model->vertices); /* clobber any old facetnormals */ if (model->facetnorms) free(model->facetnorms); /* allocate memory for the new facet normals */ model->numfacetnorms = model->numtriangles; model->facetnorms = (GLfloat*)malloc(sizeof(GLfloat) * 3 * (model->numfacetnorms + 1)); for (i = 0; i < model->numtriangles; i++) { model->triangles[i].findex = i+1; u[0] = model->vertices[3 * T(i).vindices[1] + 0] - model->vertices[3 * T(i).vindices[0] + 0]; u[1] = model->vertices[3 * T(i).vindices[1] + 1] - model->vertices[3 * T(i).vindices[0] + 1]; u[2] = model->vertices[3 * T(i).vindices[1] + 2] - model->vertices[3 * T(i).vindices[0] + 2]; v[0] = model->vertices[3 * T(i).vindices[2] + 0] - model->vertices[3 * T(i).vindices[0] + 0]; v[1] = model->vertices[3 * T(i).vindices[2] + 1] - model->vertices[3 * T(i).vindices[0] + 1]; v[2] = model->vertices[3 * T(i).vindices[2] + 2] - model->vertices[3 * T(i).vindices[0] + 2]; glmCross(u, v, &model->facetnorms[3 * (i+1)]); glmNormalize(&model->facetnorms[3 * (i+1)]); }}/* glmVertexNormals: Generates smooth vertex normals for a model. * First builds a list of all the triangles each vertex is in. Then * loops through each vertex in the the list averaging all the facet * normals of the triangles each vertex is in. Finally, sets the * normal index in the triangle for the vertex to the generated smooth * normal. If the dot product of a facet normal and the facet normal * associated with the first triangle in the list of triangles the * current vertex is in is greater than the cosine of the angle * parameter to the function, that facet normal is not added into the * average normal calculation and the corresponding vertex is given * the facet normal. This tends to preserve hard edges. The angle to * use depends on the model, but 90 degrees is usually a good start. * * model - initialized GLMmodel structure * angle - maximum angle (in degrees) to smooth across */GLvoidglmVertexNormals(GLMmodel* model, GLfloat angle){ GLMnode* node; GLMnode* tail; GLMnode** members; GLfloat* normals; GLuint numnormals; GLfloat average[3]; GLfloat dot, cos_angle; GLuint i, avg; assert(model); assert(model->facetnorms); /* calculate the cosine of the angle (in degrees) */ cos_angle = cos(angle * M_PI / 180.0); /* nuke any previous normals */ if (model->normals) free(model->normals); /* allocate space for new normals */ model->numnormals = model->numtriangles * 3; /* 3 normals per triangle */ model->normals = (GLfloat*)malloc(sizeof(GLfloat)* 3* (model->numnormals+1)); /* allocate a structure that will hold a linked list of triangle indices for each vertex */ members = (GLMnode**)malloc(sizeof(GLMnode*) * (model->numvertices + 1)); for (i = 1; i <= model->numvertices; i++) members[i] = NULL; /* for every triangle, create a node for each vertex in it */ for (i = 0; i < model->numtriangles; i++) { node = (GLMnode*)malloc(sizeof(GLMnode)); node->index = i; node->next = members[T(i).vindices[0]]; members[T(i).vindices[0]] = node; node = (GLMnode*)malloc(sizeof(GLMnode)); node->index = i; node->next = members[T(i).vindices[1]]; members[T(i).vindices[1]] = node; node = (GLMnode*)malloc(sizeof(GLMnode)); node->index = i; node->next = members[T(i).vindices[2]]; members[T(i).vindices[2]] = node; } /* calculate the average normal for each vertex */ numnormals = 1; for (i = 1; i <= model->numvertices; i++) { /* calculate an average normal for this vertex by averaging the facet normal of every triangle this vertex is in */ node = members[i]; if (!node) fprintf(stderr, "glmVertexNormals(): vertex w/o a triangle\n"); average[0] = 0.0; average[1] = 0.0; average[2] = 0.0; avg = 0; while (node) { /* only average if the dot product of the angle between the two facet normals is greater than the cosine of the threshold angle -- or, said another way, the angle between the two facet normals is less than (or equal to) the threshold angle */ dot = glmDot(&model->facetnorms[3 * T(node->index).findex], &model->facetnorms[3 * T(members[i]->index).findex]); if (dot > cos_angle) { node->averaged = GL_TRUE; average[0] += model->facetnorms[3 * T(node->index).findex + 0]; average[1] += model->facetnorms[3 * T(node->index).findex + 1]; average[2] += model->facetnorms[3 * T(node->index).findex + 2]; avg = 1; /* we averaged at least one normal! */ } else { node->averaged = GL_FALSE; } node = node->next; } if (avg) { /* normalize the averaged normal */ glmNormalize(average); /* add the normal to the vertex normals list */ model->normals[3 * numnormals + 0] = average[0]; model->normals[3 * numnormals + 1] = average[1]; model->normals[3 * numnormals + 2] = average[2]; avg = numnormals; numnormals++; } /* set the normal of this vertex in each triangle it is in */ node = members[i]; while (node) { if (node->averaged) { /* if this node was averaged, use the average normal */ if (T(node->index).vindices[0] == i) T(node->index).nindices[0] = avg; else if (T(node->index).vindices[1] == i) T(node->index).nindices[1] = avg; else if (T(node->index).vindices[2] == i) T(node->index).nindices[2] = avg; } else { /* if this node wasn't averaged, use the facet normal */ model->normals[3 * numnormals + 0] = model->facetnorms[3 * T(node->index).findex + 0]; model->normals[3 * numnormals + 1] = model->facetnorms[3 * T(node->index).findex + 1]; model->normals[3 * numnormals + 2] = model->facetnorms[3 * T(node->index).findex + 2]; if (T(node->index).vindices[0] == i) T(node->index).nindices[0] = numnormals; else if (T(node->index).vindices[1] == i) T(node->index).nindices[1] = numnormals; else if (T(node->index).vindices[2] == i) T(node->index).nindices[2] = numnormals; numnormals++; } node = node->next; } } model->numnormals = numnormals - 1; /* free the member information */ for (i = 1; i <= model->numvertices; i++) { node = members[i]; while (node) { tail = node; node = node->next; free(tail); } } free(members); /* pack the normals array (we previously allocated the maximum number of normals that could possibly be created (numtriangles * 3), so get rid of some of them (usually alot unless none of the facet normals were averaged)) */ normals = model->normals; model->normals = (GLfloat*)malloc(sizeof(GLfloat)* 3* (model->numnormals+1)); for (i = 1; i <= model->numnormals; i++) { model->normals[3 * i + 0] = normals[3 * i + 0]; model->normals[3 * i + 1] = normals[3 * i + 1]; model->normals[3 * i + 2] = normals[3 * i + 2]; } free(normals);}/* glmLinearTexture: Generates texture coordinates according to a * linear projection of the texture map. It generates these by * linearly mapping the vertices onto a square. * * model - pointer to initialized GLMmodel structure */GLvoidglmLinearTexture(GLMmodel* model){ GLMgroup *group; GLfloat dimensions[3]; GLfloat x, y, scalefactor; GLuint i; assert(model); if (model->texcoords) free(model->texcoords); model->numtexcoords = model->numvertices; model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(model->numtexcoords+1)); glmDimensions(model, dimensions); scalefactor = 2.0 / glmAbs(glmMax(glmMax(dimensions[0], dimensions[1]), dimensions[2])); /* do the calculations */ for(i = 1; i <= model->numvertices; i++) { x = model->vertices[3 * i + 0] * scalefactor; y = model->vertices[3 * i + 2] * scalefactor; model->texcoords[2 * i + 0] = (x + 1.0) / 2.0; model->texcoords[2 * i + 1] = (y + 1.0) / 2.0; } /* go through and put texture coordinate indices in all the triangles */ group = model->groups; while(group) { for(i = 0; i < group->numtriangles; i++) { T(group->triangles[i]).tindices[0] = T(group->triangles[i]).vindices[0]; T(group->triangles[i]).tindices[1] = T(group->triangles[i]).vindices[1]; T(group->triangles[i]).tindices[2] = T(group->triangles[i]).vindices[2]; } group = group->next; }#if 0 printf("glmLinearTexture(): generated %d linear texture coordinates\n", model->numtexcoords);#endif}/* glmSpheremapTexture: Generates texture coordinates according to a * spherical projection of the texture map. Sometimes referred to as * spheremap, or reflection map texture coordinates. It generates * these by using the normal to calculate where that vertex would map * onto a sphere. Since it is impossible to map something flat * perfectly onto something spherical, there is distortion at the * poles. This particular implementation causes the poles along the X * axis to be distorted. * * model - pointer to initialized GLMmodel structure */GLvoidglmSpheremapTexture(GLMmodel* model){ GLMgroup* group; GLfloat theta, phi, rho, x, y, z, r; GLuint i; assert(model); assert(model->normals); if (model->texcoords) free(model->texcoords); model->numtexcoords = model->numnormals; model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(model->numtexcoords+1)); for (i = 1; i <= model->numnormals; i++) { z = model->normals[3 * i + 0]; /* re-arrange for pole distortion */ y = model->normals[3 * i + 1]; x = model->normals[3 * i + 2]; r = sqrt((x * x) + (y * y)); rho = sqrt((r * r) + (z * z)); if(r == 0.0) { theta = 0.0; phi = 0.0; } else { if(z == 0.0) phi = 3.14159265 / 2.0; else phi = acos(z / rho); if(y == 0.0) theta = 3.141592365 / 2.0; else theta = asin(y / r) + (3.14159265 / 2.0); } model->texcoords[2 * i + 0] = theta / 3.14159265; model->texcoords[2 * i + 1] = phi / 3.14159265; } /* go through and put texcoord indices in all the triangles */ group = model->groups; while(group) { for (i = 0; i < group->numtriangles; i++) { T(group->triangles[i]).tindices[0] = T(group->triangles[i]).nindices[0]; T(group->triangles[i]).tindices[1] = T(group->triangles[i]).nindices[1]; T(group->triangles[i]).tindices[2] = T(group->triangles[i]).nindices[2]; } group = group->next; }}/* glmDelete: Deletes a GLMmodel structure. * * model - initialized GLMmodel structure */GLvoidglmDelete(GLMmodel* model){ GLMgroup* group; GLuint i; assert(model); if (model->pathname) free(model->pathname); if (model->mtllibname) free(model->mtllibname); if (model->vertices) free(model->vertices); if (model->normals) free(model->normals); if (model->texcoords) free(model->texcoords); if (model->facetnorms) free(model->facetnorms); if (model->triangles) free(model->triangles); if (model->materials) { for (i = 0; i < model->nummaterials; i++) free(model->materials[i].name); } free(model->materials); while(model->groups) { group = model->groups; model->groups = model->groups->next; free(group->name); free(group->triangles); free(group); } free(model);}/* glmReadOBJ: Reads a model description from a Wavefront .OBJ file. * Returns a pointer to the created object which should be free'd with * glmDelete(). * * filename - name of the file containing the Wavefront .OBJ format data. */GLMmodel* glmReadOBJ(char* filename){ GLMmodel* model; FILE* file; /* open the file */ file = fopen(filename, "r"); if (!file) { fprintf(stderr, "glmReadOBJ() failed: can't open data file \"%s\".\n", filename); exit(1); } /* allocate a new model */ model = (GLMmodel*)malloc(sizeof(GLMmodel)); model->pathname = strdup(filename); model->mtllibname = NULL; model->numvertices = 0; model->vertices = NULL; model->numnormals = 0; model->normals = NULL; model->numtexcoords = 0; model->texcoords = NULL; model->numfacetnorms = 0; model->facetnorms = NULL; model->numtriangles = 0; model->triangles = NULL; model->nummaterials = 0; model->materials = NULL; model->numgroups = 0; model->groups = NULL; model->position[0] = 0.0; model->position[1] = 0.0; model->position[2] = 0.0; /* make a first pass through the file to get a count of the number of vertices, normals, texcoords & triangles */ glmFirstPass(model, file); /* allocate memory */ model->vertices = (GLfloat*)malloc(sizeof(GLfloat) * 3 * (model->numvertices + 1)); model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) * model->numtriangles); if (model->numnormals) { model->normals = (GLfloat*)malloc(sizeof(GLfloat) * 3 * (model->numnormals + 1)); } if (model->numtexcoords) { model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * 2 * (model->numtexcoords + 1)); } /* rewind to beginning of file and read in the data this pass */ rewind(file); glmSecondPass(model, file); /* close the file */ fclose(file); return model;}/* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to * a file. * * model - initialized GLMmodel structure * filename - name of the file to write the Wavefront .OBJ format data to * mode - a bitwise or of values describing what is written to the file * GLM_NONE - render with only vertices * GLM_FLAT - render with facet normals * GLM_SMOOTH - render with vertex normals * GLM_TEXTURE - render with texture coords * GLM_COLOR - render with colors (color material)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -