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 < [email protected] >

 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 < [email protected] > */

 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 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] = '\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_SDL

1116       fputs("Texture rendering is not available; install SDL_image and recompile.\n", 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\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 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 * \return 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\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 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

 

你可能感兴趣的:(lib)