首页 > 代码库 > lib3ds类库

lib3ds类库

lib3ds类库

   1 /*   2 * The 3D Studio File Format Library   3 * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.lib3ds.org>   4 * All rights reserved.   5 *   6 * This program is  free  software;  you can redistribute it and/or modify it   7 * under the terms of the  GNU Lesser General Public License  as published by    8 * the  Free Software Foundation;  either version 2.1 of the License,  or (at    9 * your option) any later version.  10 *  11 * This  program  is  distributed in  the  hope that it will  be useful,  but  12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY  13 * or  FITNESS FOR A  PARTICULAR PURPOSE.  See the  GNU Lesser General Public    14 * License for more details.  15 *  16 * You should  have received  a copy of the GNU Lesser General Public License  17 * along with  this program;  if not, write to the  Free Software Foundation,  18 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  19 *  20 * $Id: 3dsplay.c,v 1.14 2007/06/18 06:51:53 jeh Exp $  21 */  22   23 #ifdef HAVE_CONFIG_H  24 #include "config.h"  25 #endif  26   27 #include <lib3ds/file.h>  28 #include <lib3ds/camera.h>  29 #include <lib3ds/mesh.h>  30 #include <lib3ds/node.h>  31 #include <lib3ds/material.h>  32 #include <lib3ds/matrix.h>  33 #include <lib3ds/vector.h>  34 #include <lib3ds/light.h>  35 #include <string.h>  36 #include <stdlib.h>  37 #include <math.h>  38   39 // OS X has a different path than everyone else  40 #ifdef __APPLE__  41 #include <GLUT/glut.h>  42 #else  43 #include <GL/glut.h>  44 #endif  45   46 #ifdef    USE_SDL  47 #include <SDL_image.h>  48 #endif  49   50   51   52   53 #define    MOUSE_SCALE    .1    /* degrees/pixel movement */  54   55 /*!  56 \example player.c  57   58 Previews a <i>3DS</i> file using OpenGL.  59   60 \code  61 Syntax: player filename  62 \endcode  63   64 \warning To compile this program you must have OpenGL and glut installed.  65 */  66   67   68 typedef    enum {ROTATING, WALKING} RunMode;  69   70 static    RunMode runMode = ROTATING;  71   72 static const char* filepath=NULL;  73 static char datapath[256];  74 static char filename[256];  75 static int dbuf=1;  76 static int halt=0;  77 static int flush=0;  78 static int anti_alias=1;  79   80 static const char* camera=0;  81 static Lib3dsFile *file=0;  82 static float current_frame=0.0;  83 static int gl_width;  84 static int gl_height;  85 static int menu_id=0;  86 static int show_object=1;  87 static int show_bounds=0;  88 static int rotating = 0;  89 static int show_cameras = 0;  90 static int show_lights = 0;  91   92 static int cameraList, lightList;    /* Icon display lists */  93   94 static Lib3dsVector bmin, bmax;  95 static float    sx, sy, sz, size;    /* bounding box dimensions */  96 static float    cx, cy, cz;        /* bounding box center */  97   98 static    float    view_rotx = 0., view_roty = 0., view_rotz = 0.;  99 static    float    anim_rotz = 0.; 100  101 static    int    mx, my; 102  103 static const GLfloat white[4] = {1.,1.,1.,1.}; 104 static const GLfloat dgrey[4] = {.25,.25,.25,1.}; 105 static const GLfloat grey[4] = {.5,.5,.5,1.}; 106 static const GLfloat lgrey[4] = {.75,.75,.75,1.}; 107 static const GLfloat black[] = {0.,0.,0.,1.}; 108 static const GLfloat red[4] = {1.,0.,0.,1.}; 109 static const GLfloat green[4] = {0.,1.,0.,1.}; 110 static const GLfloat blue[4] = {0.,0.,1.,1.}; 111  112  113 static    void    solidBox(double bx, double by, double bz); 114 static    void    solidCylinder(double r, double h, int slices); 115 static    int    callback(void (*cb)(int m, int d, void *), void *client); 116 static    void    call_callback(int idx, int data); 117  118 static void solidBox(double bx, double by, double bz); 119 static void solidCylinder(double r, double h, int slices); 120 static const char *Basename(const char *filename); 121  122  123 // texture size: by now minimum standard 124 #define    TEX_XSIZE    1024 125 #define    TEX_YSIZE    1024 126  127 struct _player_texture 128 { 129   int valid; // was the loading attempt successful ?  130 #ifdef    USE_SDL 131   SDL_Surface *bitmap; 132 #else 133   void *bitmap; 134 #endif 135   GLuint tex_id; //OpenGL texture ID 136   float scale_x, scale_y; // scale the texcoords, as OpenGL thinks in TEX_XSIZE and TEX_YSIZE 137 }; 138  139 typedef struct _player_texture Player_texture;  140 Player_texture *pt;  141 int tex_mode; // Texturing active ?  142  143 #define    NA(a)    (sizeof(a)/sizeof(a[0])) 144  145 #ifndef    MIN 146 #define    MIN(a,b) ((a)<(b)?(a):(b)) 147 #define    MAX(a,b) ((a)>(b)?(a):(b)) 148 #endif 149  150  151  152  153 static    void menu_cb(int value) 154 { 155   call_callback(value, 0); 156 } 157  158  159 /*! 160 * Switch cameras based on user‘s menu choice. 161 */ 162 static void camera_menu(int menu, int value, void *client) 163 { 164   Lib3dsCamera *c = (Lib3dsCamera*)client; 165   view_rotx = view_roty = view_rotz = anim_rotz = 0.; 166   camera=c->name; 167 } 168  169  170 /*! 171 * Toggle an arbitrary int (bool) variable 172 */ 173 static    void toggle_bool(int menu, int value, void *client) 174 { 175   int *var = client; 176   *var = !*var; 177   glutPostRedisplay(); 178 } 179  180  181  182 /*! 183 * Build the menu 184 */ 185 static void build_menu() 186 { 187   Lib3dsCamera *c; 188   int i; 189   menu_id=glutCreateMenu(menu_cb); 190  191   for (c=file->cameras,i=0; c; c=c->next,++i) 192     glutAddMenuEntry(c->name, callback(camera_menu, c)); 193  194   glutAddMenuEntry("Show cameras", callback(toggle_bool, &show_cameras)); 195   glutAddMenuEntry("Show lights", callback(toggle_bool, &show_lights)); 196   glutAddMenuEntry("Show bounds", callback(toggle_bool, &show_bounds)); 197 } 198  199  200 /*! 201 * Time function, called every frame 202 */ 203 static    void timer_cb(int value) 204 { 205   glutPostRedisplay(); 206  207   if (!halt) { 208     view_rotz += anim_rotz; 209     current_frame+=1.0; 210     if (current_frame>file->frames) { 211       current_frame=0; 212     } 213     lib3ds_file_eval(file, current_frame); 214     glutTimerFunc(10, timer_cb, 0); 215   } 216 } 217  218 static    void set_halt(int h) 219 { 220   if( h != halt ) { 221     halt = h; 222     if( !halt ) 223       glutTimerFunc(10, timer_cb, 0); 224   } 225 } 226  227  228  229 /*! 230 * Initialize OpenGL 231 */ 232 static void init(void) 233 { 234   glClearColor(0.5, 0.5, 0.5, 1.0); 235   glShadeModel(GL_SMOOTH); 236   glEnable(GL_LIGHTING); 237   glEnable(GL_LIGHT0); 238   glDisable(GL_LIGHT1); 239   glDepthFunc(GL_LEQUAL); 240   glEnable(GL_DEPTH_TEST); 241   glCullFace(GL_BACK); 242   //glDisable(GL_NORMALIZE); 243   //glPolygonOffset(1.0, 2); 244 } 245  246  247 /*! 248 * Load the model from .3ds file. 249 */ 250 static void load_model(void) 251 { 252   file=lib3ds_file_load(filepath); 253   if (!file) { 254     puts("3dsplayer: Error: Loading 3DS file failed.\n"); 255     exit(1); 256   } 257  258   /* No nodes?  Fabricate nodes to display all the meshes. */ 259   if( !file->nodes ) 260   { 261     Lib3dsMesh *mesh; 262     Lib3dsNode *node; 263  264     for(mesh = file->meshes; mesh != NULL; mesh = mesh->next) 265     { 266       node = lib3ds_node_new_object(); 267       strcpy(node->name, mesh->name); 268       node->parent_id = LIB3DS_NO_PARENT; 269       lib3ds_file_insert_node(file, node); 270     } 271   } 272  273   lib3ds_file_eval(file, 1.0f); 274   lib3ds_file_bounding_box_of_nodes(file, LIB3DS_TRUE, LIB3DS_FALSE, LIB3DS_FALSE, bmin, bmax); 275   sx = bmax[0] - bmin[0]; 276   sy = bmax[1] - bmin[1]; 277   sz = bmax[2] - bmin[2]; 278   size = MAX(sx, sy); size = MAX(size, sz); 279   cx = (bmin[0] + bmax[0])/2; 280   cy = (bmin[1] + bmax[1])/2; 281   cz = (bmin[2] + bmax[2])/2; 282  283  284   /* No cameras in the file?  Add four */ 285  286   if( !file->cameras ) { 287  288     /* Add some cameras that encompass the bounding box */ 289  290     Lib3dsCamera *camera = lib3ds_camera_new("Camera_X"); 291     camera->target[0] = cx; 292     camera->target[1] = cy; 293     camera->target[2] = cz; 294     memcpy(camera->position, camera->target, sizeof(camera->position)); 295     camera->position[0] = bmax[0] + 1.5 * MAX(sy,sz); 296     camera->near_range = ( camera->position[0] - bmax[0] ) * .5; 297     camera->far_range = ( camera->position[0] - bmin[0] ) * 2; 298     lib3ds_file_insert_camera(file, camera); 299  300     /* Since lib3ds considers +Y to be into the screen, we‘ll put 301     * this camera on the -Y axis, looking in the +Y direction. 302     */ 303     camera = lib3ds_camera_new("Camera_Y"); 304     camera->target[0] = cx; 305     camera->target[1] = cy; 306     camera->target[2] = cz; 307     memcpy(camera->position, camera->target, sizeof(camera->position)); 308     camera->position[1] = bmin[1] - 1.5 * MAX(sx,sz); 309     camera->near_range = ( bmin[1] - camera->position[1] ) * .5; 310     camera->far_range = ( bmax[1] - camera->position[1] ) * 2; 311     lib3ds_file_insert_camera(file, camera); 312  313     camera = lib3ds_camera_new("Camera_Z"); 314     camera->target[0] = cx; 315     camera->target[1] = cy; 316     camera->target[2] = cz; 317     memcpy(camera->position, camera->target, sizeof(camera->position)); 318     camera->position[2] = bmax[2] + 1.5 * MAX(sx,sy); 319     camera->near_range = ( camera->position[2] - bmax[2] ) * .5; 320     camera->far_range = ( camera->position[2] - bmin[2] ) * 2; 321     lib3ds_file_insert_camera(file, camera); 322  323     camera = lib3ds_camera_new("Camera_ISO"); 324     camera->target[0] = cx; 325     camera->target[1] = cy; 326     camera->target[2] = cz; 327     memcpy(camera->position, camera->target, sizeof(camera->position)); 328     camera->position[0] = bmax[0] + .75 * size; 329     camera->position[1] = bmin[1] - .75 * size; 330     camera->position[2] = bmax[2] + .75 * size; 331     camera->near_range = ( camera->position[0] - bmax[0] ) * .5; 332     camera->far_range = ( camera->position[0] - bmin[0] ) * 3; 333     lib3ds_file_insert_camera(file, camera); 334   } 335  336  337   /* No lights in the file?  Add some. */ 338  339   if (file->lights == NULL) 340   { 341     Lib3dsLight *light; 342  343     light = lib3ds_light_new("light0"); 344     light->spot_light = 0; 345     light->see_cone = 0; 346     light->color[0] = light->color[1] = light->color[2] = .6; 347     light->position[0] = cx + size * .75; 348     light->position[1] = cy - size * 1.; 349     light->position[2] = cz + size * 1.5; 350     light->position[3] = 0.; 351     light->outer_range = 100; 352     light->inner_range = 10; 353     light->multiplier = 1; 354     lib3ds_file_insert_light(file, light); 355  356     light = lib3ds_light_new("light1"); 357     light->spot_light = 0; 358     light->see_cone = 0; 359     light->color[0] = light->color[1] = light->color[2] = .3; 360     light->position[0] = cx - size; 361     light->position[1] = cy - size; 362     light->position[2] = cz + size * .75; 363     light->position[3] = 0.; 364     light->outer_range = 100; 365     light->inner_range = 10; 366     light->multiplier = 1; 367     lib3ds_file_insert_light(file, light); 368  369     light = lib3ds_light_new("light2"); 370     light->spot_light = 0; 371     light->see_cone = 0; 372     light->color[0] = light->color[1] = light->color[2] = .3; 373     light->position[0] = cx; 374     light->position[1] = cy + size; 375     light->position[2] = cz + size; 376     light->position[3] = 0.; 377     light->outer_range = 100; 378     light->inner_range = 10; 379     light->multiplier = 1; 380     lib3ds_file_insert_light(file, light); 381  382   } 383  384   if (!file->cameras) { 385     fputs("3dsplayer: Error: No Camera found.\n", stderr); 386     lib3ds_file_free(file); 387     file=0; 388     exit(1); 389   } 390   if (!camera) { 391     camera=file->cameras->name; 392   } 393  394   lib3ds_file_eval(file,0.); 395 } 396  397  398  399 #ifdef  USE_SDL 400 /** 401 * Convert an SDL bitmap for use with OpenGL. 402 * 403 * Written by Gernot < gz@lysator.liu.se > 404 */ 405 void *convert_to_RGB_Surface(SDL_Surface *bitmap) 406 { 407   unsigned char *pixel = (unsigned char *)malloc(sizeof(char) * 4 * bitmap->h * bitmap->w);  408   int soff = 0;    409   int doff = 0;    410   int x, y; 411   unsigned char *spixels = (unsigned char *)bitmap->pixels; 412   SDL_Palette *pal = bitmap->format->palette;  413  414   for (y = 0; y < bitmap->h; y++) 415     for (x = 0; x < bitmap->w; x++) 416     { 417       SDL_Color* col = &pal->colors[spixels[soff]]; 418  419       pixel[doff] = col->r;  420       pixel[doff+1] = col->g;  421       pixel[doff+2] = col->b;  422       pixel[doff+3] = 255;  423       doff += 4;  424       soff++; 425     } 426  427     return (void *)pixel;  428 } 429 #endif 430  431  432  433  434 /*! 435 * Render node recursively, first children, then parent. 436 * Each node receives its own OpenGL display list. 437 */ 438 static void render_node(Lib3dsNode *node) 439 { 440   ASSERT(file); 441  442   { 443     Lib3dsNode *p; 444     for (p=node->childs; p!=0; p=p->next) { 445       render_node(p); 446     } 447   } 448   if (node->type==LIB3DS_OBJECT_NODE) { 449     Lib3dsMesh *mesh; 450  451     if (strcmp(node->name,"$$$DUMMY")==0) { 452       return; 453     } 454  455     mesh = lib3ds_file_mesh_by_name(file, node->data.object.morph); 456     if( mesh == NULL ) 457       mesh = lib3ds_file_mesh_by_name(file, node->name); 458  459     if (!mesh->user.d) { 460       ASSERT(mesh); 461       if (!mesh) { 462         return; 463       } 464  465       mesh->user.d=glGenLists(1); 466       glNewList(mesh->user.d, GL_COMPILE); 467  468       { 469         unsigned p; 470         Lib3dsVector *normalL=malloc(3*sizeof(Lib3dsVector)*mesh->faces); 471         Lib3dsMaterial *oldmat = (Lib3dsMaterial *)-1; 472         { 473           Lib3dsMatrix M; 474           lib3ds_matrix_copy(M, mesh->matrix); 475           lib3ds_matrix_inv(M); 476           glMultMatrixf(&M[0][0]); 477         } 478         lib3ds_mesh_calculate_normals(mesh, normalL); 479  480         for (p=0; p<mesh->faces; ++p) { 481           Lib3dsFace *f=&mesh->faceL[p]; 482           Lib3dsMaterial *mat=0; 483 #ifdef    USE_SDL 484           Player_texture *pt = NULL; 485           int tex_mode = 0; 486 #endif 487           if (f->material[0]) { 488             mat=lib3ds_file_material_by_name(file, f->material); 489           } 490  491           if( mat != oldmat ) { 492             if (mat) { 493               if( mat->two_sided ) 494                 glDisable(GL_CULL_FACE); 495               else 496                 glEnable(GL_CULL_FACE); 497  498               glDisable(GL_CULL_FACE); 499  500               /* Texturing added by Gernot < gz@lysator.liu.se > */ 501  502               if (mat->texture1_map.name[0]) {        /* texture map? */ 503                 Lib3dsTextureMap *tex = &mat->texture1_map; 504                 if (!tex->user.p) {        /* no player texture yet? */ 505                   char texname[1024]; 506                   pt = malloc(sizeof(*pt)); 507                   tex->user.p = pt; 508                   //snprintf(texname, sizeof(texname), "%s/%s", datapath, tex->name); 509                   strcpy(texname, datapath); 510                   strcat(texname, "/"); 511                   strcat(texname, tex->name); 512 #ifdef    DEBUG 513                   printf("Loading texture map, name %s\n", texname); 514 #endif    /* DEBUG */ 515 #ifdef    USE_SDL 516 #ifdef  USE_SDL_IMG_load 517                   pt->bitmap = IMG_load(texname); 518 #else 519                   pt->bitmap = IMG_Load(texname); 520 #endif /* IMG_Load */ 521  522 #else /* USE_SDL */ 523                   pt->bitmap = NULL; 524                   fputs("3dsplayer: Warning: No image loading support, skipping texture.\n", stderr); 525 #endif /* USE_SDL */ 526                   if (pt->bitmap) {    /* could image be loaded ? */ 527                     /* this OpenGL texupload code is incomplete format-wise! 528                     * to make it complete, examine SDL_surface->format and 529                     * tell us @lib3ds.sf.net about your improvements :-) 530                     */ 531                     int upload_format = GL_RED; /* safe choice, shows errors */ 532 #ifdef USE_SDL 533                     int bytespp = pt->bitmap->format->BytesPerPixel; 534                     void *pixel = NULL; 535                     glGenTextures(1, &pt->tex_id); 536 #ifdef    DEBUG 537                     printf("Uploading texture to OpenGL, id %d, at %d bytepp\n", 538                       pt->tex_id, bytespp); 539 #endif    /* DEBUG */ 540                     if (pt->bitmap->format->palette) { 541                       pixel = convert_to_RGB_Surface(pt->bitmap); 542                       upload_format = GL_RGBA; 543                     } 544                     else { 545                       pixel = pt->bitmap->pixels; 546                       /* e.g. this could also be a color palette */ 547                       if (bytespp == 1) upload_format = GL_LUMINANCE; 548                       else if (bytespp == 3) upload_format = GL_RGB; 549                       else if (bytespp == 4) upload_format = GL_RGBA; 550                     } 551                     glBindTexture(GL_TEXTURE_2D, pt->tex_id); 552                     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 553                       TEX_XSIZE, TEX_YSIZE, 0, 554                       GL_RGBA, GL_UNSIGNED_BYTE, NULL); 555                     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 556                     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 557                     glTexParameteri(GL_TEXTURE_2D, 558                       GL_TEXTURE_MAG_FILTER, GL_LINEAR); 559                     glTexParameteri(GL_TEXTURE_2D, 560                       GL_TEXTURE_MIN_FILTER, GL_LINEAR); 561                     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 562                     glTexSubImage2D(GL_TEXTURE_2D, 563                       0, 0, 0, pt->bitmap->w, pt->bitmap->h, 564                       upload_format, GL_UNSIGNED_BYTE, pixel); 565                     pt->scale_x = (float)pt->bitmap->w/(float)TEX_XSIZE; 566                     pt->scale_y = (float)pt->bitmap->h/(float)TEX_YSIZE; 567 #endif /* USE_SDL */ 568                     pt->valid = 1; 569                   } 570                   else { 571                     fprintf(stderr, 572                       "Load of texture %s did not succeed " 573                       "(format not supported !)\n", 574                       texname); 575                     pt->valid = 0; 576                   } 577                 } 578                 else { 579                   pt = (Player_texture *)tex->user.p; 580                 } 581                 tex_mode = pt->valid; 582               } 583               else { 584                 tex_mode = 0; 585               } 586               glMaterialfv(GL_FRONT, GL_AMBIENT, mat->ambient); 587               glMaterialfv(GL_FRONT, GL_DIFFUSE, mat->diffuse); 588               glMaterialfv(GL_FRONT, GL_SPECULAR, mat->specular); 589               glMaterialf(GL_FRONT, GL_SHININESS, pow(2, 10.0*mat->shininess)); 590             } 591             else { 592               static const Lib3dsRgba a={0.7, 0.7, 0.7, 1.0}; 593               static const Lib3dsRgba d={0.7, 0.7, 0.7, 1.0}; 594               static const Lib3dsRgba s={1.0, 1.0, 1.0, 1.0}; 595               glMaterialfv(GL_FRONT, GL_AMBIENT, a); 596               glMaterialfv(GL_FRONT, GL_DIFFUSE, d); 597               glMaterialfv(GL_FRONT, GL_SPECULAR, s); 598               glMaterialf(GL_FRONT, GL_SHININESS, pow(2, 10.0*0.5)); 599             } 600             oldmat = mat; 601           } 602  603           else if (mat != NULL && mat->texture1_map.name[0]) { 604             Lib3dsTextureMap *tex = &mat->texture1_map; 605             if (tex != NULL && tex->user.p != NULL) { 606               pt = (Player_texture *)tex->user.p; 607               tex_mode = pt->valid; 608             } 609           } 610  611  612           { 613             int i; 614  615             if (tex_mode) { 616               //printf("Binding texture %d\n", pt->tex_id); 617               glEnable(GL_TEXTURE_2D); 618               glBindTexture(GL_TEXTURE_2D, pt->tex_id); 619             } 620  621             glBegin(GL_TRIANGLES); 622             glNormal3fv(f->normal); 623             for (i=0; i<3; ++i) { 624               glNormal3fv(normalL[3*p+i]); 625  626               if (tex_mode) { 627                 glTexCoord2f(mesh->texelL[f->points[i]][1]*pt->scale_x, 628                   pt->scale_y - mesh->texelL[f->points[i]][0]*pt->scale_y); 629               } 630  631               glVertex3fv(mesh->pointL[f->points[i]].pos); 632             } 633             glEnd(); 634  635             if (tex_mode) 636               glDisable(GL_TEXTURE_2D); 637           } 638         } 639  640         free(normalL); 641       } 642  643       glEndList(); 644     } 645  646     if (mesh->user.d) { 647       Lib3dsObjectData *d; 648  649       glPushMatrix(); 650       d=&node->data.object; 651       glMultMatrixf(&node->matrix[0][0]); 652       glTranslatef(-d->pivot[0], -d->pivot[1], -d->pivot[2]); 653       glCallList(mesh->user.d); 654       /* glutSolidSphere(50.0, 20,20); */ 655       glPopMatrix(); 656       if( flush ) 657         glFlush(); 658     } 659   } 660 } 661  662  663  664  665 /*! 666 * Update information about a light.  Try to find corresponding nodes 667 * if possible, and copy values from nodes into light struct. 668 */ 669  670 static void light_update(Lib3dsLight *l) 671 { 672   Lib3dsNode *ln, *sn; 673  674   ln = lib3ds_file_node_by_name(file, l->name, LIB3DS_LIGHT_NODE); 675   sn = lib3ds_file_node_by_name(file, l->name, LIB3DS_SPOT_NODE); 676  677   if( ln != NULL ) { 678     memcpy(l->color, ln->data.light.col, sizeof(Lib3dsRgb)); 679     memcpy(l->position, ln->data.light.pos, sizeof(Lib3dsVector)); 680   } 681  682   if( sn != NULL ) 683     memcpy(l->spot, sn->data.spot.pos, sizeof(Lib3dsVector)); 684 } 685  686  687  688  689 static    void draw_bounds(Lib3dsVector tgt) 690 { 691   double cx,cy,cz; 692   double lx,ly,lz; 693  694   lx = sx / 10.; ly = sy / 10.; lz = sz / 10.; 695   cx = tgt[0]; cy = tgt[1]; cz = tgt[2]; 696  697   glDisable(GL_LIGHTING); 698   glColor4fv(white); 699   glBegin(GL_LINES); 700   glVertex3f(bmin[0],bmin[1],bmin[2]); 701   glVertex3f(bmax[0],bmin[1],bmin[2]); 702   glVertex3f(bmin[0],bmax[1],bmin[2]); 703   glVertex3f(bmax[0],bmax[1],bmin[2]); 704   glVertex3f(bmin[0],bmin[1],bmax[2]); 705   glVertex3f(bmax[0],bmin[1],bmax[2]); 706   glVertex3f(bmin[0],bmax[1],bmax[2]); 707   glVertex3f(bmax[0],bmax[1],bmax[2]); 708  709   glVertex3f(bmin[0],bmin[1],bmin[2]); 710   glVertex3f(bmin[0],bmax[1],bmin[2]); 711   glVertex3f(bmax[0],bmin[1],bmin[2]); 712   glVertex3f(bmax[0],bmax[1],bmin[2]); 713   glVertex3f(bmin[0],bmin[1],bmax[2]); 714   glVertex3f(bmin[0],bmax[1],bmax[2]); 715   glVertex3f(bmax[0],bmin[1],bmax[2]); 716   glVertex3f(bmax[0],bmax[1],bmax[2]); 717  718   glVertex3f(bmin[0],bmin[1],bmin[2]); 719   glVertex3f(bmin[0],bmin[1],bmax[2]); 720   glVertex3f(bmax[0],bmin[1],bmin[2]); 721   glVertex3f(bmax[0],bmin[1],bmax[2]); 722   glVertex3f(bmin[0],bmax[1],bmin[2]); 723   glVertex3f(bmin[0],bmax[1],bmax[2]); 724   glVertex3f(bmax[0],bmax[1],bmin[2]); 725   glVertex3f(bmax[0],bmax[1],bmax[2]); 726  727   glVertex3f(cx-size/32, cy, cz); 728   glVertex3f(cx+size/32, cy, cz); 729   glVertex3f(cx, cy-size/32, cz); 730   glVertex3f(cx, cy+size/32, cz); 731   glVertex3f(cx, cy, cz-size/32); 732   glVertex3f(cx, cy, cz+size/32); 733   glEnd(); 734  735  736   glColor4fv(red); 737   glBegin(GL_LINES); 738   glVertex3f(0.,0.,0.); 739   glVertex3f(lx,0.,0.); 740   glEnd(); 741  742   glColor4fv(green); 743   glBegin(GL_LINES); 744   glVertex3f(0.,0.,0.); 745   glVertex3f(0.,ly,0.); 746   glEnd(); 747  748   glColor4fv(blue); 749   glBegin(GL_LINES); 750   glVertex3f(0.,0.,0.); 751   glVertex3f(0.,0.,lz); 752   glEnd(); 753  754   glEnable(GL_LIGHTING); 755 } 756  757  758 static void draw_light(const GLfloat *pos, const GLfloat *color) 759 { 760   glMaterialfv(GL_FRONT, GL_EMISSION, color); 761   glPushMatrix(); 762   glTranslatef(pos[0], pos[1], pos[2]); 763   glScalef(size/20, size/20, size/20); 764   glCallList(lightList); 765   glPopMatrix(); 766 } 767  768  769  770 /*! 771 * Main display function; called whenever the scene needs to be redrawn. 772 */ 773 static void display(void) 774 { 775   Lib3dsNode *c,*t; 776   Lib3dsFloat fov, roll; 777   float near, far, dist; 778   float *campos; 779   float *tgt; 780   Lib3dsMatrix M; 781   Lib3dsCamera *cam; 782   Lib3dsVector v; 783   Lib3dsNode *p; 784  785   if( file != NULL && file->background.solid.use ) 786     glClearColor(file->background.solid.col[0], 787     file->background.solid.col[1], 788     file->background.solid.col[2], 1.); 789  790   /* TODO: fog */ 791  792   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 793  794   if( anti_alias ) 795     glEnable(GL_POLYGON_SMOOTH); 796   else 797     glDisable(GL_POLYGON_SMOOTH); 798  799  800   if (!file) { 801     return; 802   } 803  804   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, file->ambient); 805  806   c=lib3ds_file_node_by_name(file, camera, LIB3DS_CAMERA_NODE); 807   t=lib3ds_file_node_by_name(file, camera, LIB3DS_TARGET_NODE); 808  809   if( t != NULL ) 810     tgt = t->data.target.pos; 811  812   if( c != NULL ) { 813     fov = c->data.camera.fov; 814     roll = c->data.camera.roll; 815     campos = c->data.camera.pos; 816   } 817  818   if ((cam = lib3ds_file_camera_by_name(file, camera)) == NULL) 819     return; 820  821   near = cam->near_range; 822   far = cam->far_range; 823  824   if (c == NULL || t == NULL) { 825     if( c == NULL ) { 826       fov = cam->fov; 827       roll = cam->roll; 828       campos = cam->position; 829     } 830     if( t == NULL ) 831       tgt = cam->target; 832   } 833  834   glMatrixMode(GL_PROJECTION); 835   glLoadIdentity(); 836  837   /* KLUDGE alert:  OpenGL can‘t handle a near clip plane of zero, 838   * so if the camera‘s near plane is zero, we give it a small number. 839   * In addition, many .3ds files I‘ve seen have a far plane that‘s 840   * much too close and the model gets clipped away.  I haven‘t found 841   * a way to tell OpenGL not to clip the far plane, so we move it 842   * further away.  A factor of 10 seems to make all the models I‘ve 843   * seen visible. 844   */ 845   if( near <= 0. ) near = far * .001; 846  847   gluPerspective( fov, 1.0*gl_width/gl_height, near, far); 848  849   glMatrixMode(GL_MODELVIEW); 850   glLoadIdentity(); 851   glRotatef(-90, 1.0,0,0); 852  853   /* User rotates the view about the target point */ 854  855   lib3ds_vector_sub(v, tgt, campos); 856   dist = lib3ds_vector_length(v); 857  858   glTranslatef(0.,dist, 0.); 859   glRotatef(view_rotx, 1., 0., 0.); 860   glRotatef(view_roty, 0., 1., 0.); 861   glRotatef(view_rotz, 0., 0., 1.); 862   glTranslatef(0.,-dist, 0.); 863  864   lib3ds_matrix_camera(M, campos, tgt, roll); 865   glMultMatrixf(&M[0][0]); 866  867   /* Lights.  Set them from light nodes if possible.  If not, use the 868   * light objects directly. 869   */ 870   { 871     static const GLfloat a[] = {0.0f, 0.0f, 0.0f, 1.0f}; 872     static GLfloat c[] = {1.0f, 1.0f, 1.0f, 1.0f}; 873     static GLfloat p[] = {0.0f, 0.0f, 0.0f, 1.0f}; 874     Lib3dsLight *l; 875  876     int li=GL_LIGHT0; 877     for (l=file->lights; l; l=l->next) { 878       glEnable(li); 879  880       light_update(l); 881  882       c[0] = l->color[0]; 883       c[1] = l->color[1]; 884       c[2] = l->color[2]; 885       glLightfv(li, GL_AMBIENT, a); 886       glLightfv(li, GL_DIFFUSE, c); 887       glLightfv(li, GL_SPECULAR, c); 888  889       p[0] = l->position[0]; 890       p[1] = l->position[1]; 891       p[2] = l->position[2]; 892       glLightfv(li, GL_POSITION, p); 893  894       if (l->spot_light) { 895         p[0] = l->spot[0] - l->position[0]; 896         p[1] = l->spot[1] - l->position[1]; 897         p[2] = l->spot[2] - l->position[2]; 898         glLightfv(li, GL_SPOT_DIRECTION, p); 899       } 900       ++li; 901     } 902   } 903  904  905  906  907   if( show_object ) 908   { 909     for (p=file->nodes; p!=0; p=p->next) { 910       render_node(p); 911     } 912   } 913  914   if( show_bounds ) 915     draw_bounds(tgt); 916  917   if( show_cameras ) 918   { 919     for( cam = file->cameras; cam != NULL; cam = cam->next ) 920     { 921       lib3ds_matrix_camera(M, cam->position, cam->target, cam->roll); 922       lib3ds_matrix_inv(M); 923  924       glPushMatrix(); 925       glMultMatrixf(&M[0][0]); 926       glScalef(size/20, size/20, size/20); 927       glCallList(cameraList); 928       glPopMatrix(); 929     } 930   } 931  932   if( show_lights ) 933   { 934     Lib3dsLight *light; 935     for( light = file->lights; light != NULL; light = light->next ) 936       draw_light(light->position, light->color); 937     glMaterialfv(GL_FRONT, GL_EMISSION, black); 938   } 939  940  941   glutSwapBuffers(); 942 } 943  944  945 /*! 946 * 947 */ 948 static void reshape (int w, int h) 949 { 950   gl_width=w; 951   gl_height=h; 952   glViewport(0,0,w,h); 953 } 954  955  956 /*! 957 * 958 */ 959 static void keyboard(unsigned char key, int x, int y) 960 { 961   switch (key) { 962 case 27: 963   exit(0); 964   break; 965 case h: 966   set_halt(!halt); 967   break; 968 case a: 969   anim_rotz += .05; 970   break; 971 case A: 972   anim_rotz -= .05; 973   break; 974 case r: 975   view_rotx = view_roty = view_rotz = anim_rotz = 0.; 976   break; 977 case z: 978   view_roty += 5.; 979   break; 980 case Z: 981   view_roty -= 5.; 982   break; 983 case b: 984   show_bounds = !show_bounds; 985   break; 986 case o: 987   show_object = !show_object; 988   break; 989 case \001: 990   anti_alias = !anti_alias; 991   break; 992   } 993 } 994  995  996 /*! 997 * Respond to mouse buttons.  Action depends on current operating mode. 998 */ 999 static    void mouse_cb(int button, int state, int x, int y)1000 {1001   mx = x; my = y;1002   switch( button ) {1003 case GLUT_LEFT_BUTTON:1004   switch( runMode ) {1005 case ROTATING: rotating = state == GLUT_DOWN; break;1006 default: break;1007   }1008   break;1009 default:1010   break;1011   }1012 }1013 1014 1015 /*!1016 * Respond to mouse motions; left button rotates the image or performs1017 * other action according to current operating mode.1018 */1019 static void drag_cb(int x, int y)1020 {1021   if( rotating ) {1022     view_rotz += MOUSE_SCALE * (x - mx);1023     view_rotx += MOUSE_SCALE * (y - my);1024     mx = x;1025     my = y;1026     glutPostRedisplay();1027   }1028 }1029 1030 1031 /*!1032 * Create camera and light icons1033 */1034 static void create_icons()1035 {1036   GLUquadricObj *qobj;1037 1038 #define    CBX    .25    // camera body dimensions1039 #define    CBY    1.51040 #define    CBZ    1.1041 1042   qobj = gluNewQuadric();1043   gluQuadricDrawStyle(qobj, GLU_FILL);1044   gluQuadricNormals(qobj, GLU_SMOOTH);1045 1046   cameraList = glGenLists(1);1047   glNewList(cameraList, GL_COMPILE);1048   glMaterialfv(GL_FRONT, GL_AMBIENT, dgrey);1049   glMaterialfv(GL_FRONT, GL_DIFFUSE, lgrey);1050   glMaterialfv(GL_FRONT, GL_SPECULAR, black);1051   glEnable(GL_CULL_FACE);1052   solidBox(CBX,CBY,CBZ);1053   glPushMatrix();1054   glTranslatef(0.,.9,1.8);1055   glRotatef(90., 0.,1.,0.);1056   solidCylinder(1., CBX*2, 12);1057   glTranslatef(0.,-1.8,0.);1058   solidCylinder(1., CBX*2, 12);1059   glPopMatrix();1060   glDisable(GL_CULL_FACE);1061   glPushMatrix();1062   glTranslated(0.,CBY,0.);1063   glRotated(-90., 1.,0.,0.);1064   gluCylinder(qobj, .2, .5, 1., 12, 1);1065   glPopMatrix();1066   glEndList();1067 1068   lightList = glGenLists(1);1069   glNewList(lightList, GL_COMPILE);1070   glPushMatrix();1071   glMaterialfv(GL_FRONT, GL_AMBIENT, dgrey);1072   glMaterialfv(GL_FRONT, GL_DIFFUSE, dgrey);1073   glMaterialfv(GL_FRONT, GL_SPECULAR, grey);1074   glEnable(GL_CULL_FACE);1075   gluSphere(qobj, .5, 12., 6.);1076   glRotated(180.,1.,0.,0.);1077   glMaterialfv(GL_FRONT, GL_EMISSION, dgrey);1078   gluCylinder(qobj, .2, .2, 1., 12, 1);1079   glPopMatrix();1080   glEndList();1081 }1082 1083 1084 void decompose_datapath(const char *fn)1085 {1086   const char *ptr = strrchr(fn, /);1087 1088   if (ptr == NULL) {1089     strcpy(datapath, ".");1090     strcpy(filename, fn);1091   }1092   else {1093     strcpy(filename, ptr+1);1094     strcpy(datapath, fn);1095     datapath[ptr - fn] = \0;1096   }1097 }1098 1099 1100 /*!1101 *1102 */1103 int main(int argc, char** argv)1104 {1105   char *progname = argv[0];1106 1107   glutInit(&argc, argv);1108 1109   for(++argv; --argc > 0; ++argv)1110   {1111     if( strcmp(*argv, "-help") ==  0 || strcmp(*argv, "--help") == 0 )1112     {1113       fputs("View a 3DS model file using OpenGL.\n", stderr);1114       fputs("Usage: 3dsplayer [-nodb|-aa|-flush] <filename>\n", stderr);1115 #ifndef USE_SDL1116       fputs("Texture rendering is not available; install SDL_image and recompile.\n", stderr);1117 #endif1118       exit(0);1119     }1120     else if( strcmp(*argv, "-nodb") == 0 )1121       dbuf = 0;1122     else if( strcmp(*argv, "-aa") == 0 )1123       anti_alias = 1;1124     else if( strcmp(*argv, "-flush") == 0 )1125       flush = 1;1126     else {1127       filepath = *argv;1128       decompose_datapath(filepath);1129     }1130   }1131 1132   if (filepath == NULL) {1133     fputs("3dsplayer: Error: No 3DS file specified\n", stderr);1134     exit(1);1135   }1136 1137   glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | (dbuf ? GLUT_DOUBLE:0) );1138   glutInitWindowSize(500, 500);1139   glutInitWindowPosition(100, 100);1140   glutCreateWindow(filepath != NULL ? Basename(filepath) : progname);1141 1142   init();1143   create_icons();1144   load_model();1145 1146   build_menu();1147   glutAttachMenu(2);1148 1149   glutDisplayFunc(display);1150   glutReshapeFunc(reshape);1151   glutKeyboardFunc(keyboard);1152   glutMouseFunc(mouse_cb);1153   glutMotionFunc(drag_cb);1154   glutTimerFunc(10, timer_cb, 0);1155   glutMainLoop();1156   return(0);1157 }1158 1159 1160 1161 /* A few small utilities, so generic that they probably1162 * don‘t even belong in this file.1163 */1164 1165 1166 1167 /*!1168 * Render a box, centered at 0,0,01169 *1170 * Box may be rendered with face culling enabled.1171 */1172 static void solidBox(double bx, double by, double bz)1173 {1174   glBegin(GL_POLYGON);1175   glNormal3d(0.,0.,1.);1176   glVertex3d(bx,by,bz);1177   glVertex3d(-bx,by,bz);1178   glVertex3d(-bx,-by,bz);1179   glVertex3d(bx,-by,bz);1180   glEnd();1181   glBegin(GL_POLYGON);1182   glNormal3d(0.,0.,-1.);1183   glVertex3d(-bx,by,-bz);1184   glVertex3d(bx,by,-bz);1185   glVertex3d(bx,-by,-bz);1186   glVertex3d(-bx,-by,-bz);1187   glEnd();1188   glBegin(GL_POLYGON);1189   glNormal3d(0.,-1.,0.);1190   glVertex3d(-bx,by,bz);1191   glVertex3d(bx,by,bz);1192   glVertex3d(bx,by,-bz);1193   glVertex3d(-bx,by,-bz);1194   glEnd();1195   glBegin(GL_POLYGON);1196   glNormal3d(0.,-1.,0.);1197   glVertex3d(bx,-by,bz);1198   glVertex3d(-bx,-by,bz);1199   glVertex3d(-bx,-by,-bz);1200   glVertex3d(bx,-by,-bz);1201   glEnd();1202   glBegin(GL_POLYGON);1203   glNormal3d(1.,0.,0.);1204   glVertex3d(bx,by,bz);1205   glVertex3d(bx,-by,bz);1206   glVertex3d(bx,-by,-bz);1207   glVertex3d(bx,by,-bz);1208   glEnd();1209   glBegin(GL_POLYGON);1210   glNormal3d(-1.,0.,0.);1211   glVertex3d(-bx,by,-bz);1212   glVertex3d(-bx,-by,-bz);1213   glVertex3d(-bx,-by,bz);1214   glVertex3d(-bx,by,bz);1215   glEnd();1216 }1217 1218 1219 1220 /*!1221 * Render a cylinder with end caps, along the Z axis centered at 0,0,01222 *1223 * Cylinder may be rendered with face culling enabled.1224 */1225 static void solidCylinder(double r, double h, int slices)1226 {1227   GLUquadricObj *qobj = gluNewQuadric();1228   gluQuadricDrawStyle(qobj, GLU_FILL);1229   gluQuadricNormals(qobj, GLU_SMOOTH);1230 1231   glPushMatrix();1232   glTranslated(0., 0., -h/2);1233   gluCylinder( qobj, r, r, h, slices, 1 );1234   glPushMatrix();1235   glRotated(180., 1.,0.,0.);1236   gluDisk( qobj, 0., r, slices, 1 );1237   glPopMatrix();1238   glTranslated(0., 0., h);1239   gluDisk( qobj, 0., r, slices, 1 );1240   glPopMatrix();1241 }1242 1243 1244 static const char * Basename(const char *filename)1245 {1246   char *ptr = strrchr(filename, /);1247   return ptr != NULL ? ptr+1 : filename;1248 }1249 1250 1251 1252 /*1253 * This module is a crude front end to the GLUT menu system, allowing for1254 * slightly more sophisticated callbacks.1255 */1256 1257 #include <stdio.h>1258 1259 #define    MAX_CALLBACKS    1001260 1261 typedef struct {1262   void (*cb)(int, int, void *);1263   void    *client;1264 } Callback;1265 1266 1267 static    Callback    callbacks[MAX_CALLBACKS];1268 static    int        ncb = 0;1269 1270 /*!1271 * Register a callback, returning an integer value suitable for1272 * passing to glutAddMenuEntry()1273 *1274 * \param cb Callback function to be called.1275 * \param client Data to be passed to the callback.1276 *1277 * \return integer callback id1278 */1279 static int callback(void (*cb)(int, int, void *client), void *client)1280 {1281   if( ncb == 0 )1282   {1283     int i;1284     for(i=0; i < NA(callbacks); ++i)1285       callbacks[i].cb = NULL;1286   }1287   else if( ncb >= NA(callbacks) ) {1288     fprintf(stderr,1289       "callback() out of callbacks, try changing MAX_CALLBACKS\n");1290   }1291 1292   callbacks[ncb].cb = cb;1293   callbacks[ncb].client = client;1294   return ncb++;1295 }1296 1297 1298 /*!1299 * Call the indexed callback.1300 *1301 * \param idx Callback index.1302 * \param data Data to be passed to the callback1303 */1304 static void call_callback(int idx, int data)1305 {1306   if( idx >= 0 && idx < NA(callbacks) && callbacks[idx].cb != NULL )1307     callbacks[idx].cb(idx, data, callbacks[idx].client);1308 }
View Code

 

lib3ds类库