• 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
  • 相关阅读:
    洛谷 P1430 序列取数
    洛谷 P2042 维护数列
    洛谷 P3391 【模板】文艺平衡树(Splay)
    Permutation UVA
    treap板子(洛谷 P3369 【模板】普通平衡树(Treap/SBT))
    Jumping Jack CodeForces
    Increasing Sequence CodeForces
    Cunning Gena CodeForces
    Hie with the Pie POJ
    ACboy needs your help HDU
  • 原文地址:https://www.cnblogs.com/yhlx125/p/3931568.html
Copyright © 2020-2023  润新知