lib3ds 2.0 和 opengl32 例子程序
cheungmine
2009-2-13
本例使用lib3ds库读取3ds文件,并使用opengl绘制。本例不使用贴图,仅仅展示lib3ds2.0的使用过程。这个例子是用lib3ds1.2.0的一个例子的翻版。lib3ds1.2.0已经找不到了。所以,我提供这个2.0版本的例子,以供学习之用。
需要下载lib3ds2.0的包。编译成动态库。
下面是例子的源代码player.c。只需要这一个文件。
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<assert.h>
#include <windows.h>
// 使用 USE_SGI_OPENGL 可能在某些机器上运行 wglMakeCurrent 系列函数返回失败的结果
#define GLUT_NO_LIB_PRAGMA
// #define USE_SGI_OPENGL
#ifdef USE_SGI_OPENGL
#include "../../sgi-opengl2-sdk/include/gl/gl.h"
#include "../../sgi-opengl2-sdk/include/gl/glu.h"
#include "../../sgi-opengl2-sdk/include/gl/glut.h"
#pragma comment(lib, "../../sgi-opengl2-sdk/lib/opengl.lib")
#pragma comment(lib, "../../sgi-opengl2-sdk/lib/glu.lib")
#pragma comment(lib, "../../sgi-opengl2-sdk/lib/glut.lib")
#else
#include "../../win-opengl32/inc/GL.h"
#include "../../win-opengl32/inc/GLU.h"
#pragma comment(lib, "../../win-opengl32/lib/OPENGL32.lib")
#pragma comment(lib, "../../win-opengl32/lib/GLU32.lib")
#include "../../win-opengl32/inc/GLUT.h"
#pragma comment(lib, "../../win-opengl32/lib/glut32.lib")
#endif
//
// lib3ds
//
#include "../src/lib3ds.h"
#ifdef _DEBUG
# pragma comment(lib, "../src/debug/lib3ds20d.lib")
#else
# pragma comment(lib, "../src/release/lib3ds20.lib")
#endif
static const char* filename="E:/3DS/House/house.3ds";
static Lib3dsFile *model=0;
static const char* camera=0;
static float current_frame=0.0;
static int gl_width;
static int gl_height;
static int camera_menu_id=0;
static int halt=0;
#ifndef MAX
# define MAX(x,y) ((x)>(y)?(x):(y))
#endif
static void camera_menu(int value)
{
Lib3dsCamera *c;
int i;
for( i=0; i<value; i++ ){
if (i==model->ncameras)
return;
c = model->cameras[i];
}
if (c)
camera=c->name;
}
static void render_node(Lib3dsNode *node)
{
Lib3dsNode *p;
Lib3dsMesh *mesh;
Lib3dsFace *face;
Lib3dsMaterial *mat;
Lib3dsMeshInstanceNode *meshData;
Lib3dsVector *norm_verts;
Lib3dsVector *norm_faces;
int i;
unsigned fi;
float M[4][4];
assert(model);
// 递归
for (p=node->childs; p!=0; p=p->next){
render_node(p);
}
if (node->type==LIB3DS_NODE_MESH_INSTANCE)
{
if (strcmp(node->name,"$$$DUMMY")==0) {
return;
}
if (!node->user_id)
{
mesh = lib3ds_file_mesh_for_node(model, node);
assert(mesh);
if (!mesh) {
return;
}
node->user_id = glGenLists(1);
glNewList(node->user_id, GL_COMPILE);
norm_verts = (Lib3dsVector*) malloc(3*sizeof(Lib3dsVector)*mesh->nfaces);
norm_faces = (Lib3dsVector*) malloc(sizeof(Lib3dsVector)*mesh->nfaces);
lib3ds_matrix_copy(M, mesh->matrix);
lib3ds_matrix_inv(M);
glMultMatrixf(&M[0][0]);
lib3ds_mesh_calculate_face_normals(mesh, (float (*)[3])norm_faces);
lib3ds_mesh_calculate_vertex_normals(mesh, (float (*)[3])norm_verts);
for (fi=0; fi<mesh->nfaces; ++fi) {
face = &(mesh->faces[fi]);
mat = 0;
if (face->material>=0 && face->material<model->nmaterials)
mat=model->materials[face->material];
if (mat)
{
static GLfloat a[4]={0,0,0,1};
float s;
glMaterialfv(GL_FRONT, GL_AMBIENT, a);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat->diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat->specular);
s = pow(2, 10.0*mat->shininess);
if (s>128.0) {
s=128.0;
}
glMaterialf(GL_FRONT, GL_SHININESS, s);
}
else {
float a[]={0.2, 0.2, 0.2, 1.0};
float d[]={0.8, 0.8, 0.8, 1.0};
float s[]={0.0, 0.0, 0.0, 1.0};
glMaterialfv(GL_FRONT, GL_AMBIENT, a);
glMaterialfv(GL_FRONT, GL_DIFFUSE, d);
glMaterialfv(GL_FRONT, GL_SPECULAR, s);
}
// Draw tri-face
glBegin(GL_TRIANGLES);
glNormal3fv(norm_faces[fi].v); // face normal
for (i=0; i<3; ++i) {
glNormal3fv(norm_verts[3*fi+i].v); // vertex normal
glVertex3fv(mesh->vertices[face->index[i]]);
}
glEnd();
}
free(norm_faces);
free(norm_verts);
glEndList();
}
if (node->user_id) {
glPushMatrix();
meshData = (Lib3dsMeshInstanceNode*) node;
glMultMatrixf(&node->matrix[0][0]);
glTranslatef(-meshData->pivot[0], -meshData->pivot[1], -meshData->pivot[2]);
glCallList(node->user_id);
// glutSolidSphere(50.0, 20,20);
glPopMatrix();
}
}
}
static void display(void)
{
int i, li;
Lib3dsNode *nodC, *nodT, *nod;
Lib3dsCameraNode *camNode;
Lib3dsTargetNode *tgtNode;
float M[4][4];
GLfloat a[] = {0.0f, 0.0f, 0.0f, 1.0f};
GLfloat c[] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat p[] = {0.0f, 0.0f, 0.0f, 1.0f};
Lib3dsLight *l;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (!model) {
return;
}
nodC=lib3ds_file_node_by_name(model, camera, LIB3DS_NODE_CAMERA);
nodT=lib3ds_file_node_by_name(model, camera, LIB3DS_NODE_CAMERA_TARGET);
if (!nodC || !nodT) {
// 本测试程序要求必须存在 camera 和 target
// 这里存在问题?以后的文章再处理不存在的情形
assert(0 && "Camera or Target not found!");
return;
}
camNode = (Lib3dsCameraNode*) nodC;
tgtNode = (Lib3dsTargetNode*) nodT;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective( camNode->fov, 1.0*gl_width/gl_height, 100.0, 20000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(-90, 1.0, 0,0);
li=GL_LIGHT0;
for (i=0; i<model->nlights; i++)
{
l = model->lights[i];
glEnable(li);
glLightfv(li, GL_AMBIENT, a);
glLightfv(li, GL_DIFFUSE, c);
glLightfv(li, GL_SPECULAR, c); // p?
p[0] = l->position[0];
p[1] = l->position[1];
p[2] = l->position[2];
glLightfv(li, GL_POSITION, p);
if (!l->spot_light) {
continue;
}
p[0] = l->target[0] - l->position[0];
p[1] = l->target[1] - l->position[1];
p[2] = l->target[2] - l->position[2];
glLightfv(li, GL_SPOT_DIRECTION, p);
++li;
}
lib3ds_matrix_camera(M, camNode->pos, tgtNode->pos, camNode->roll);
glMultMatrixf(&M[0][0]);
for (nod=model->nodes; nod!=0; nod=nod->next) {
render_node(nod);
}
if (!halt) {
current_frame+=1.0;
if (current_frame>model->frames) {
current_frame=0;
}
lib3ds_file_eval(model, current_frame);
glutSwapBuffers();
glutPostRedisplay();
}
}
static void init(void)
{
int i;
glClearColor(0.5, 0.5, 0.5, 1.0);
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDisable(GL_LIGHT1);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
//glDisable(GL_NORMALIZE);
//glPolygonOffset(1.0, 2);
model=lib3ds_file_open(filename);
if (!model) {
printf("***ERROR*** Loading 3DS file failed.");
exit(1);
}
if (!model->cameras) {
printf("***ERROR*** No Camera found.");
lib3ds_file_free(model);
model=0;
exit(1);
}
if (!camera) {
camera = model->cameras[0]->name;
}
camera_menu_id = glutCreateMenu(camera_menu);
for (i=0; i<model->ncameras; i++){
glutAddMenuEntry(model->cameras[i]->name, i);
}
glutAttachMenu(0);
lib3ds_file_eval(model, 0);
}
static void reshape (int w, int h)
{
gl_width=w;
gl_height=h;
glViewport(0,0,w,h);
}
static void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
exit(0);
break;
case 'h':
halt=!halt;
glutPostRedisplay();
break;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(640, 480);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
/* Memory leaks detecting */
_CrtDumpMemoryLeaks();
return(0);
}
运行结果:
例子中使用的3ds23文件来自于:
house.3ds