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.
");
 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.
", 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
", 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.
", 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
",
 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 !)
",
 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
", 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 '01':
 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 performs
1017 * 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 icons
1033 */
1034 static void create_icons()
1035 {
1036   GLUquadricObj *qobj;
1037 
1038 #define    CBX    .25    // camera body dimensions
1039 #define    CBY    1.5
1040 #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] = '';
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.
", stderr);
1114       fputs("Usage: 3dsplayer [-nodb|-aa|-flush] <filename>
", stderr);
1115 #ifndef USE_SDL
1116       fputs("Texture rendering is not available; install SDL_image and recompile.
", stderr);
1117 #endif
1118       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
", 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 probably
1162 * don't even belong in this file.
1163 */
1164 
1165 
1166 
1167 /*!
1168 * Render a box, centered at 0,0,0
1169 *
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,0
1222 *
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 for
1254 * slightly more sophisticated callbacks.
1255 */
1256 
1257 #include <stdio.h>
1258 
1259 #define    MAX_CALLBACKS    100
1260 
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 for
1272 * passing to glutAddMenuEntry()
1273 *
1274 * param cb Callback function to be called.
1275 * param client Data to be passed to the callback.
1276 *
1277 * 
eturn integer callback id
1278 */
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
");
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 callback
1303 */
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
原文地址:https://www.cnblogs.com/yhlx125/p/3931568.html