lib3ds类库

 /*
* The 3D Studio File Format Library
* Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.lib3ds.org>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: 3dsplay.c,v 1.14 2007/06/18 06:51:53 jeh Exp $
*/ #ifdef HAVE_CONFIG_H
#include "config.h"
#endif #include <lib3ds/file.h>
#include <lib3ds/camera.h>
#include <lib3ds/mesh.h>
#include <lib3ds/node.h>
#include <lib3ds/material.h>
#include <lib3ds/matrix.h>
#include <lib3ds/vector.h>
#include <lib3ds/light.h>
#include <string.h>
#include <stdlib.h>
#include <math.h> // OS X has a different path than everyone else
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif #ifdef USE_SDL
#include <SDL_image.h>
#endif #define MOUSE_SCALE .1 /* degrees/pixel movement */ /*!
\example player.c Previews a <i>3DS</i> file using OpenGL. \code
Syntax: player filename
\endcode \warning To compile this program you must have OpenGL and glut installed.
*/ typedef enum {ROTATING, WALKING} RunMode; static RunMode runMode = ROTATING; static const char* filepath=NULL;
static char datapath[];
static char filename[];
static int dbuf=;
static int halt=;
static int flush=;
static int anti_alias=; static const char* camera=;
static Lib3dsFile *file=;
static float current_frame=0.0;
static int gl_width;
static int gl_height;
static int menu_id=;
static int show_object=;
static int show_bounds=;
static int rotating = ;
static int show_cameras = ;
static int show_lights = ; static int cameraList, lightList; /* Icon display lists */ static Lib3dsVector bmin, bmax;
static float sx, sy, sz, size; /* bounding box dimensions */
static float cx, cy, cz; /* bounding box center */ static float view_rotx = ., view_roty = ., view_rotz = .;
static float anim_rotz = .; static int mx, my; static const GLfloat white[] = {.,.,.,.};
static const GLfloat dgrey[] = {.,.,.,.};
static const GLfloat grey[] = {.,.,.,.};
static const GLfloat lgrey[] = {.,.,.,.};
static const GLfloat black[] = {.,.,.,.};
static const GLfloat red[] = {.,.,.,.};
static const GLfloat green[] = {.,.,.,.};
static const GLfloat blue[] = {.,.,.,.}; static void solidBox(double bx, double by, double bz);
static void solidCylinder(double r, double h, int slices);
static int callback(void (*cb)(int m, int d, void *), void *client);
static void call_callback(int idx, int data); static void solidBox(double bx, double by, double bz);
static void solidCylinder(double r, double h, int slices);
static const char *Basename(const char *filename); // texture size: by now minimum standard
#define TEX_XSIZE 1024
#define TEX_YSIZE 1024 struct _player_texture
{
int valid; // was the loading attempt successful ?
#ifdef USE_SDL
SDL_Surface *bitmap;
#else
void *bitmap;
#endif
GLuint tex_id; //OpenGL texture ID
float scale_x, scale_y; // scale the texcoords, as OpenGL thinks in TEX_XSIZE and TEX_YSIZE
}; typedef struct _player_texture Player_texture;
Player_texture *pt;
int tex_mode; // Texturing active ? #define NA(a) (sizeof(a)/sizeof(a[0])) #ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif static void menu_cb(int value)
{
call_callback(value, );
} /*!
* Switch cameras based on user's menu choice.
*/
static void camera_menu(int menu, int value, void *client)
{
Lib3dsCamera *c = (Lib3dsCamera*)client;
view_rotx = view_roty = view_rotz = anim_rotz = .;
camera=c->name;
} /*!
* Toggle an arbitrary int (bool) variable
*/
static void toggle_bool(int menu, int value, void *client)
{
int *var = client;
*var = !*var;
glutPostRedisplay();
} /*!
* Build the menu
*/
static void build_menu()
{
Lib3dsCamera *c;
int i;
menu_id=glutCreateMenu(menu_cb); for (c=file->cameras,i=; c; c=c->next,++i)
glutAddMenuEntry(c->name, callback(camera_menu, c)); glutAddMenuEntry("Show cameras", callback(toggle_bool, &show_cameras));
glutAddMenuEntry("Show lights", callback(toggle_bool, &show_lights));
glutAddMenuEntry("Show bounds", callback(toggle_bool, &show_bounds));
} /*!
* Time function, called every frame
*/
static void timer_cb(int value)
{
glutPostRedisplay(); if (!halt) {
view_rotz += anim_rotz;
current_frame+=1.0;
if (current_frame>file->frames) {
current_frame=;
}
lib3ds_file_eval(file, current_frame);
glutTimerFunc(, timer_cb, );
}
} static void set_halt(int h)
{
if( h != halt ) {
halt = h;
if( !halt )
glutTimerFunc(, timer_cb, );
}
} /*!
* Initialize OpenGL
*/
static void init(void)
{
glClearColor(0.5, 0.5, 0.5, 1.0);
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDisable(GL_LIGHT1);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glCullFace(GL_BACK);
//glDisable(GL_NORMALIZE);
//glPolygonOffset(1.0, 2);
} /*!
* Load the model from .3ds file.
*/
static void load_model(void)
{
file=lib3ds_file_load(filepath);
if (!file) {
puts("3dsplayer: Error: Loading 3DS file failed.\n");
exit();
} /* No nodes? Fabricate nodes to display all the meshes. */
if( !file->nodes )
{
Lib3dsMesh *mesh;
Lib3dsNode *node; for(mesh = file->meshes; mesh != NULL; mesh = mesh->next)
{
node = lib3ds_node_new_object();
strcpy(node->name, mesh->name);
node->parent_id = LIB3DS_NO_PARENT;
lib3ds_file_insert_node(file, node);
}
} lib3ds_file_eval(file, 1.0f);
lib3ds_file_bounding_box_of_nodes(file, LIB3DS_TRUE, LIB3DS_FALSE, LIB3DS_FALSE, bmin, bmax);
sx = bmax[] - bmin[];
sy = bmax[] - bmin[];
sz = bmax[] - bmin[];
size = MAX(sx, sy); size = MAX(size, sz);
cx = (bmin[] + bmax[])/;
cy = (bmin[] + bmax[])/;
cz = (bmin[] + bmax[])/; /* No cameras in the file? Add four */ if( !file->cameras ) { /* Add some cameras that encompass the bounding box */ Lib3dsCamera *camera = lib3ds_camera_new("Camera_X");
camera->target[] = cx;
camera->target[] = cy;
camera->target[] = cz;
memcpy(camera->position, camera->target, sizeof(camera->position));
camera->position[] = bmax[] + 1.5 * MAX(sy,sz);
camera->near_range = ( camera->position[] - bmax[] ) * .;
camera->far_range = ( camera->position[] - bmin[] ) * ;
lib3ds_file_insert_camera(file, camera); /* Since lib3ds considers +Y to be into the screen, we'll put
* this camera on the -Y axis, looking in the +Y direction.
*/
camera = lib3ds_camera_new("Camera_Y");
camera->target[] = cx;
camera->target[] = cy;
camera->target[] = cz;
memcpy(camera->position, camera->target, sizeof(camera->position));
camera->position[] = bmin[] - 1.5 * MAX(sx,sz);
camera->near_range = ( bmin[] - camera->position[] ) * .;
camera->far_range = ( bmax[] - camera->position[] ) * ;
lib3ds_file_insert_camera(file, camera); camera = lib3ds_camera_new("Camera_Z");
camera->target[] = cx;
camera->target[] = cy;
camera->target[] = cz;
memcpy(camera->position, camera->target, sizeof(camera->position));
camera->position[] = bmax[] + 1.5 * MAX(sx,sy);
camera->near_range = ( camera->position[] - bmax[] ) * .;
camera->far_range = ( camera->position[] - bmin[] ) * ;
lib3ds_file_insert_camera(file, camera); camera = lib3ds_camera_new("Camera_ISO");
camera->target[] = cx;
camera->target[] = cy;
camera->target[] = cz;
memcpy(camera->position, camera->target, sizeof(camera->position));
camera->position[] = bmax[] + . * size;
camera->position[] = bmin[] - . * size;
camera->position[] = bmax[] + . * size;
camera->near_range = ( camera->position[] - bmax[] ) * .;
camera->far_range = ( camera->position[] - bmin[] ) * ;
lib3ds_file_insert_camera(file, camera);
} /* No lights in the file? Add some. */ if (file->lights == NULL)
{
Lib3dsLight *light; light = lib3ds_light_new("light0");
light->spot_light = ;
light->see_cone = ;
light->color[] = light->color[] = light->color[] = .;
light->position[] = cx + size * .;
light->position[] = cy - size * .;
light->position[] = cz + size * 1.5;
light->position[] = .;
light->outer_range = ;
light->inner_range = ;
light->multiplier = ;
lib3ds_file_insert_light(file, light); light = lib3ds_light_new("light1");
light->spot_light = ;
light->see_cone = ;
light->color[] = light->color[] = light->color[] = .;
light->position[] = cx - size;
light->position[] = cy - size;
light->position[] = cz + size * .;
light->position[] = .;
light->outer_range = ;
light->inner_range = ;
light->multiplier = ;
lib3ds_file_insert_light(file, light); light = lib3ds_light_new("light2");
light->spot_light = ;
light->see_cone = ;
light->color[] = light->color[] = light->color[] = .;
light->position[] = cx;
light->position[] = cy + size;
light->position[] = cz + size;
light->position[] = .;
light->outer_range = ;
light->inner_range = ;
light->multiplier = ;
lib3ds_file_insert_light(file, light); } if (!file->cameras) {
fputs("3dsplayer: Error: No Camera found.\n", stderr);
lib3ds_file_free(file);
file=;
exit();
}
if (!camera) {
camera=file->cameras->name;
} lib3ds_file_eval(file,.);
} #ifdef USE_SDL
/**
* Convert an SDL bitmap for use with OpenGL.
*
* Written by Gernot < gz@lysator.liu.se >
*/
void *convert_to_RGB_Surface(SDL_Surface *bitmap)
{
unsigned char *pixel = (unsigned char *)malloc(sizeof(char) * * bitmap->h * bitmap->w);
int soff = ;
int doff = ;
int x, y;
unsigned char *spixels = (unsigned char *)bitmap->pixels;
SDL_Palette *pal = bitmap->format->palette; for (y = ; y < bitmap->h; y++)
for (x = ; x < bitmap->w; x++)
{
SDL_Color* col = &pal->colors[spixels[soff]]; pixel[doff] = col->r;
pixel[doff+] = col->g;
pixel[doff+] = col->b;
pixel[doff+] = ;
doff += ;
soff++;
} return (void *)pixel;
}
#endif /*!
* Render node recursively, first children, then parent.
* Each node receives its own OpenGL display list.
*/
static void render_node(Lib3dsNode *node)
{
ASSERT(file); {
Lib3dsNode *p;
for (p=node->childs; p!=; p=p->next) {
render_node(p);
}
}
if (node->type==LIB3DS_OBJECT_NODE) {
Lib3dsMesh *mesh; if (strcmp(node->name,"$$$DUMMY")==) {
return;
} mesh = lib3ds_file_mesh_by_name(file, node->data.object.morph);
if( mesh == NULL )
mesh = lib3ds_file_mesh_by_name(file, node->name); if (!mesh->user.d) {
ASSERT(mesh);
if (!mesh) {
return;
} mesh->user.d=glGenLists();
glNewList(mesh->user.d, GL_COMPILE); {
unsigned p;
Lib3dsVector *normalL=malloc(*sizeof(Lib3dsVector)*mesh->faces);
Lib3dsMaterial *oldmat = (Lib3dsMaterial *)-;
{
Lib3dsMatrix M;
lib3ds_matrix_copy(M, mesh->matrix);
lib3ds_matrix_inv(M);
glMultMatrixf(&M[][]);
}
lib3ds_mesh_calculate_normals(mesh, normalL); for (p=; p<mesh->faces; ++p) {
Lib3dsFace *f=&mesh->faceL[p];
Lib3dsMaterial *mat=;
#ifdef USE_SDL
Player_texture *pt = NULL;
int tex_mode = ;
#endif
if (f->material[]) {
mat=lib3ds_file_material_by_name(file, f->material);
} if( mat != oldmat ) {
if (mat) {
if( mat->two_sided )
glDisable(GL_CULL_FACE);
else
glEnable(GL_CULL_FACE); glDisable(GL_CULL_FACE); /* Texturing added by Gernot < gz@lysator.liu.se > */ if (mat->texture1_map.name[]) { /* texture map? */
Lib3dsTextureMap *tex = &mat->texture1_map;
if (!tex->user.p) { /* no player texture yet? */
char texname[];
pt = malloc(sizeof(*pt));
tex->user.p = pt;
//snprintf(texname, sizeof(texname), "%s/%s", datapath, tex->name);
strcpy(texname, datapath);
strcat(texname, "/");
strcat(texname, tex->name);
#ifdef DEBUG
printf("Loading texture map, name %s\n", texname);
#endif /* DEBUG */
#ifdef USE_SDL
#ifdef USE_SDL_IMG_load
pt->bitmap = IMG_load(texname);
#else
pt->bitmap = IMG_Load(texname);
#endif /* IMG_Load */ #else /* USE_SDL */
pt->bitmap = NULL;
fputs("3dsplayer: Warning: No image loading support, skipping texture.\n", stderr);
#endif /* USE_SDL */
if (pt->bitmap) { /* could image be loaded ? */
/* this OpenGL texupload code is incomplete format-wise!
* to make it complete, examine SDL_surface->format and
* tell us @lib3ds.sf.net about your improvements :-)
*/
int upload_format = GL_RED; /* safe choice, shows errors */
#ifdef USE_SDL
int bytespp = pt->bitmap->format->BytesPerPixel;
void *pixel = NULL;
glGenTextures(, &pt->tex_id);
#ifdef DEBUG
printf("Uploading texture to OpenGL, id %d, at %d bytepp\n",
pt->tex_id, bytespp);
#endif /* DEBUG */
if (pt->bitmap->format->palette) {
pixel = convert_to_RGB_Surface(pt->bitmap);
upload_format = GL_RGBA;
}
else {
pixel = pt->bitmap->pixels;
/* e.g. this could also be a color palette */
if (bytespp == ) upload_format = GL_LUMINANCE;
else if (bytespp == ) upload_format = GL_RGB;
else if (bytespp == ) upload_format = GL_RGBA;
}
glBindTexture(GL_TEXTURE_2D, pt->tex_id);
glTexImage2D(GL_TEXTURE_2D, , GL_RGBA,
TEX_XSIZE, TEX_YSIZE, ,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexSubImage2D(GL_TEXTURE_2D,
, , , pt->bitmap->w, pt->bitmap->h,
upload_format, GL_UNSIGNED_BYTE, pixel);
pt->scale_x = (float)pt->bitmap->w/(float)TEX_XSIZE;
pt->scale_y = (float)pt->bitmap->h/(float)TEX_YSIZE;
#endif /* USE_SDL */
pt->valid = ;
}
else {
fprintf(stderr,
"Load of texture %s did not succeed "
"(format not supported !)\n",
texname);
pt->valid = ;
}
}
else {
pt = (Player_texture *)tex->user.p;
}
tex_mode = pt->valid;
}
else {
tex_mode = ;
}
glMaterialfv(GL_FRONT, GL_AMBIENT, mat->ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat->diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat->specular);
glMaterialf(GL_FRONT, GL_SHININESS, pow(, 10.0*mat->shininess));
}
else {
static const Lib3dsRgba a={0.7, 0.7, 0.7, 1.0};
static const Lib3dsRgba d={0.7, 0.7, 0.7, 1.0};
static const Lib3dsRgba s={1.0, 1.0, 1.0, 1.0};
glMaterialfv(GL_FRONT, GL_AMBIENT, a);
glMaterialfv(GL_FRONT, GL_DIFFUSE, d);
glMaterialfv(GL_FRONT, GL_SPECULAR, s);
glMaterialf(GL_FRONT, GL_SHININESS, pow(, 10.0*0.5));
}
oldmat = mat;
} else if (mat != NULL && mat->texture1_map.name[]) {
Lib3dsTextureMap *tex = &mat->texture1_map;
if (tex != NULL && tex->user.p != NULL) {
pt = (Player_texture *)tex->user.p;
tex_mode = pt->valid;
}
} {
int i; if (tex_mode) {
//printf("Binding texture %d\n", pt->tex_id);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, pt->tex_id);
} glBegin(GL_TRIANGLES);
glNormal3fv(f->normal);
for (i=; i<; ++i) {
glNormal3fv(normalL[*p+i]); if (tex_mode) {
glTexCoord2f(mesh->texelL[f->points[i]][]*pt->scale_x,
pt->scale_y - mesh->texelL[f->points[i]][]*pt->scale_y);
} glVertex3fv(mesh->pointL[f->points[i]].pos);
}
glEnd(); if (tex_mode)
glDisable(GL_TEXTURE_2D);
}
} free(normalL);
} glEndList();
} if (mesh->user.d) {
Lib3dsObjectData *d; glPushMatrix();
d=&node->data.object;
glMultMatrixf(&node->matrix[][]);
glTranslatef(-d->pivot[], -d->pivot[], -d->pivot[]);
glCallList(mesh->user.d);
/* glutSolidSphere(50.0, 20,20); */
glPopMatrix();
if( flush )
glFlush();
}
}
} /*!
* Update information about a light. Try to find corresponding nodes
* if possible, and copy values from nodes into light struct.
*/ static void light_update(Lib3dsLight *l)
{
Lib3dsNode *ln, *sn; ln = lib3ds_file_node_by_name(file, l->name, LIB3DS_LIGHT_NODE);
sn = lib3ds_file_node_by_name(file, l->name, LIB3DS_SPOT_NODE); if( ln != NULL ) {
memcpy(l->color, ln->data.light.col, sizeof(Lib3dsRgb));
memcpy(l->position, ln->data.light.pos, sizeof(Lib3dsVector));
} if( sn != NULL )
memcpy(l->spot, sn->data.spot.pos, sizeof(Lib3dsVector));
} static void draw_bounds(Lib3dsVector tgt)
{
double cx,cy,cz;
double lx,ly,lz; lx = sx / .; ly = sy / .; lz = sz / .;
cx = tgt[]; cy = tgt[]; cz = tgt[]; glDisable(GL_LIGHTING);
glColor4fv(white);
glBegin(GL_LINES);
glVertex3f(bmin[],bmin[],bmin[]);
glVertex3f(bmax[],bmin[],bmin[]);
glVertex3f(bmin[],bmax[],bmin[]);
glVertex3f(bmax[],bmax[],bmin[]);
glVertex3f(bmin[],bmin[],bmax[]);
glVertex3f(bmax[],bmin[],bmax[]);
glVertex3f(bmin[],bmax[],bmax[]);
glVertex3f(bmax[],bmax[],bmax[]); glVertex3f(bmin[],bmin[],bmin[]);
glVertex3f(bmin[],bmax[],bmin[]);
glVertex3f(bmax[],bmin[],bmin[]);
glVertex3f(bmax[],bmax[],bmin[]);
glVertex3f(bmin[],bmin[],bmax[]);
glVertex3f(bmin[],bmax[],bmax[]);
glVertex3f(bmax[],bmin[],bmax[]);
glVertex3f(bmax[],bmax[],bmax[]); glVertex3f(bmin[],bmin[],bmin[]);
glVertex3f(bmin[],bmin[],bmax[]);
glVertex3f(bmax[],bmin[],bmin[]);
glVertex3f(bmax[],bmin[],bmax[]);
glVertex3f(bmin[],bmax[],bmin[]);
glVertex3f(bmin[],bmax[],bmax[]);
glVertex3f(bmax[],bmax[],bmin[]);
glVertex3f(bmax[],bmax[],bmax[]); glVertex3f(cx-size/, cy, cz);
glVertex3f(cx+size/, cy, cz);
glVertex3f(cx, cy-size/, cz);
glVertex3f(cx, cy+size/, cz);
glVertex3f(cx, cy, cz-size/);
glVertex3f(cx, cy, cz+size/);
glEnd(); glColor4fv(red);
glBegin(GL_LINES);
glVertex3f(.,.,.);
glVertex3f(lx,.,.);
glEnd(); glColor4fv(green);
glBegin(GL_LINES);
glVertex3f(.,.,.);
glVertex3f(.,ly,.);
glEnd(); glColor4fv(blue);
glBegin(GL_LINES);
glVertex3f(.,.,.);
glVertex3f(.,.,lz);
glEnd(); glEnable(GL_LIGHTING);
} static void draw_light(const GLfloat *pos, const GLfloat *color)
{
glMaterialfv(GL_FRONT, GL_EMISSION, color);
glPushMatrix();
glTranslatef(pos[], pos[], pos[]);
glScalef(size/, size/, size/);
glCallList(lightList);
glPopMatrix();
} /*!
* Main display function; called whenever the scene needs to be redrawn.
*/
static void display(void)
{
Lib3dsNode *c,*t;
Lib3dsFloat fov, roll;
float near, far, dist;
float *campos;
float *tgt;
Lib3dsMatrix M;
Lib3dsCamera *cam;
Lib3dsVector v;
Lib3dsNode *p; if( file != NULL && file->background.solid.use )
glClearColor(file->background.solid.col[],
file->background.solid.col[],
file->background.solid.col[], .); /* TODO: fog */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if( anti_alias )
glEnable(GL_POLYGON_SMOOTH);
else
glDisable(GL_POLYGON_SMOOTH); if (!file) {
return;
} glLightModelfv(GL_LIGHT_MODEL_AMBIENT, file->ambient); c=lib3ds_file_node_by_name(file, camera, LIB3DS_CAMERA_NODE);
t=lib3ds_file_node_by_name(file, camera, LIB3DS_TARGET_NODE); if( t != NULL )
tgt = t->data.target.pos; if( c != NULL ) {
fov = c->data.camera.fov;
roll = c->data.camera.roll;
campos = c->data.camera.pos;
} if ((cam = lib3ds_file_camera_by_name(file, camera)) == NULL)
return; near = cam->near_range;
far = cam->far_range; if (c == NULL || t == NULL) {
if( c == NULL ) {
fov = cam->fov;
roll = cam->roll;
campos = cam->position;
}
if( t == NULL )
tgt = cam->target;
} glMatrixMode(GL_PROJECTION);
glLoadIdentity(); /* KLUDGE alert: OpenGL can't handle a near clip plane of zero,
* so if the camera's near plane is zero, we give it a small number.
* In addition, many .3ds files I've seen have a far plane that's
* much too close and the model gets clipped away. I haven't found
* a way to tell OpenGL not to clip the far plane, so we move it
* further away. A factor of 10 seems to make all the models I've
* seen visible.
*/
if( near <= . ) near = far * .; gluPerspective( fov, 1.0*gl_width/gl_height, near, far); glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(-, 1.0,,); /* User rotates the view about the target point */ lib3ds_vector_sub(v, tgt, campos);
dist = lib3ds_vector_length(v); glTranslatef(.,dist, .);
glRotatef(view_rotx, ., ., .);
glRotatef(view_roty, ., ., .);
glRotatef(view_rotz, ., ., .);
glTranslatef(.,-dist, .); lib3ds_matrix_camera(M, campos, tgt, roll);
glMultMatrixf(&M[][]); /* Lights. Set them from light nodes if possible. If not, use the
* light objects directly.
*/
{
static const GLfloat a[] = {0.0f, 0.0f, 0.0f, 1.0f};
static GLfloat c[] = {1.0f, 1.0f, 1.0f, 1.0f};
static GLfloat p[] = {0.0f, 0.0f, 0.0f, 1.0f};
Lib3dsLight *l; int li=GL_LIGHT0;
for (l=file->lights; l; l=l->next) {
glEnable(li); light_update(l); c[] = l->color[];
c[] = l->color[];
c[] = l->color[];
glLightfv(li, GL_AMBIENT, a);
glLightfv(li, GL_DIFFUSE, c);
glLightfv(li, GL_SPECULAR, c); p[] = l->position[];
p[] = l->position[];
p[] = l->position[];
glLightfv(li, GL_POSITION, p); if (l->spot_light) {
p[] = l->spot[] - l->position[];
p[] = l->spot[] - l->position[];
p[] = l->spot[] - l->position[];
glLightfv(li, GL_SPOT_DIRECTION, p);
}
++li;
}
} if( show_object )
{
for (p=file->nodes; p!=; p=p->next) {
render_node(p);
}
} if( show_bounds )
draw_bounds(tgt); if( show_cameras )
{
for( cam = file->cameras; cam != NULL; cam = cam->next )
{
lib3ds_matrix_camera(M, cam->position, cam->target, cam->roll);
lib3ds_matrix_inv(M); glPushMatrix();
glMultMatrixf(&M[][]);
glScalef(size/, size/, size/);
glCallList(cameraList);
glPopMatrix();
}
} if( show_lights )
{
Lib3dsLight *light;
for( light = file->lights; light != NULL; light = light->next )
draw_light(light->position, light->color);
glMaterialfv(GL_FRONT, GL_EMISSION, black);
} glutSwapBuffers();
} /*!
*
*/
static void reshape (int w, int h)
{
gl_width=w;
gl_height=h;
glViewport(,,w,h);
} /*!
*
*/
static void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case :
exit();
break;
case 'h':
set_halt(!halt);
break;
case 'a':
anim_rotz += .;
break;
case 'A':
anim_rotz -= .;
break;
case 'r':
view_rotx = view_roty = view_rotz = anim_rotz = .;
break;
case 'z':
view_roty += .;
break;
case 'Z':
view_roty -= .;
break;
case 'b':
show_bounds = !show_bounds;
break;
case 'o':
show_object = !show_object;
break;
case '\001':
anti_alias = !anti_alias;
break;
}
} /*!
* Respond to mouse buttons. Action depends on current operating mode.
*/
static void mouse_cb(int button, int state, int x, int y)
{
mx = x; my = y;
switch( button ) {
case GLUT_LEFT_BUTTON:
switch( runMode ) {
case ROTATING: rotating = state == GLUT_DOWN; break;
default: break;
}
break;
default:
break;
}
} /*!
* Respond to mouse motions; left button rotates the image or performs
* other action according to current operating mode.
*/
static void drag_cb(int x, int y)
{
if( rotating ) {
view_rotz += MOUSE_SCALE * (x - mx);
view_rotx += MOUSE_SCALE * (y - my);
mx = x;
my = y;
glutPostRedisplay();
}
} /*!
* Create camera and light icons
*/
static void create_icons()
{
GLUquadricObj *qobj; #define CBX .25 // camera body dimensions
#define CBY 1.5
#define CBZ 1. qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_FILL);
gluQuadricNormals(qobj, GLU_SMOOTH); cameraList = glGenLists();
glNewList(cameraList, GL_COMPILE);
glMaterialfv(GL_FRONT, GL_AMBIENT, dgrey);
glMaterialfv(GL_FRONT, GL_DIFFUSE, lgrey);
glMaterialfv(GL_FRONT, GL_SPECULAR, black);
glEnable(GL_CULL_FACE);
solidBox(CBX,CBY,CBZ);
glPushMatrix();
glTranslatef(.,.,1.8);
glRotatef(., .,.,.);
solidCylinder(., CBX*, );
glTranslatef(.,-1.8,.);
solidCylinder(., CBX*, );
glPopMatrix();
glDisable(GL_CULL_FACE);
glPushMatrix();
glTranslated(.,CBY,.);
glRotated(-., .,.,.);
gluCylinder(qobj, ., ., ., , );
glPopMatrix();
glEndList(); lightList = glGenLists();
glNewList(lightList, GL_COMPILE);
glPushMatrix();
glMaterialfv(GL_FRONT, GL_AMBIENT, dgrey);
glMaterialfv(GL_FRONT, GL_DIFFUSE, dgrey);
glMaterialfv(GL_FRONT, GL_SPECULAR, grey);
glEnable(GL_CULL_FACE);
gluSphere(qobj, ., ., .);
glRotated(.,.,.,.);
glMaterialfv(GL_FRONT, GL_EMISSION, dgrey);
gluCylinder(qobj, ., ., ., , );
glPopMatrix();
glEndList();
} void decompose_datapath(const char *fn)
{
const char *ptr = strrchr(fn, '/'); if (ptr == NULL) {
strcpy(datapath, ".");
strcpy(filename, fn);
}
else {
strcpy(filename, ptr+);
strcpy(datapath, fn);
datapath[ptr - fn] = '\0';
}
} /*!
*
*/
int main(int argc, char** argv)
{
char *progname = argv[]; glutInit(&argc, argv); for(++argv; --argc > ; ++argv)
{
if( strcmp(*argv, "-help") == || strcmp(*argv, "--help") == )
{
fputs("View a 3DS model file using OpenGL.\n", stderr);
fputs("Usage: 3dsplayer [-nodb|-aa|-flush] <filename>\n", stderr);
#ifndef USE_SDL
fputs("Texture rendering is not available; install SDL_image and recompile.\n", stderr);
#endif
exit();
}
else if( strcmp(*argv, "-nodb") == )
dbuf = ;
else if( strcmp(*argv, "-aa") == )
anti_alias = ;
else if( strcmp(*argv, "-flush") == )
flush = ;
else {
filepath = *argv;
decompose_datapath(filepath);
}
} if (filepath == NULL) {
fputs("3dsplayer: Error: No 3DS file specified\n", stderr);
exit();
} glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | (dbuf ? GLUT_DOUBLE:) );
glutInitWindowSize(, );
glutInitWindowPosition(, );
glutCreateWindow(filepath != NULL ? Basename(filepath) : progname); init();
create_icons();
load_model(); build_menu();
glutAttachMenu(); glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse_cb);
glutMotionFunc(drag_cb);
glutTimerFunc(, timer_cb, );
glutMainLoop();
return();
} /* A few small utilities, so generic that they probably
* don't even belong in this file.
*/ /*!
* Render a box, centered at 0,0,0
*
* Box may be rendered with face culling enabled.
*/
static void solidBox(double bx, double by, double bz)
{
glBegin(GL_POLYGON);
glNormal3d(.,.,.);
glVertex3d(bx,by,bz);
glVertex3d(-bx,by,bz);
glVertex3d(-bx,-by,bz);
glVertex3d(bx,-by,bz);
glEnd();
glBegin(GL_POLYGON);
glNormal3d(.,.,-.);
glVertex3d(-bx,by,-bz);
glVertex3d(bx,by,-bz);
glVertex3d(bx,-by,-bz);
glVertex3d(-bx,-by,-bz);
glEnd();
glBegin(GL_POLYGON);
glNormal3d(.,-.,.);
glVertex3d(-bx,by,bz);
glVertex3d(bx,by,bz);
glVertex3d(bx,by,-bz);
glVertex3d(-bx,by,-bz);
glEnd();
glBegin(GL_POLYGON);
glNormal3d(.,-.,.);
glVertex3d(bx,-by,bz);
glVertex3d(-bx,-by,bz);
glVertex3d(-bx,-by,-bz);
glVertex3d(bx,-by,-bz);
glEnd();
glBegin(GL_POLYGON);
glNormal3d(.,.,.);
glVertex3d(bx,by,bz);
glVertex3d(bx,-by,bz);
glVertex3d(bx,-by,-bz);
glVertex3d(bx,by,-bz);
glEnd();
glBegin(GL_POLYGON);
glNormal3d(-.,.,.);
glVertex3d(-bx,by,-bz);
glVertex3d(-bx,-by,-bz);
glVertex3d(-bx,-by,bz);
glVertex3d(-bx,by,bz);
glEnd();
} /*!
* Render a cylinder with end caps, along the Z axis centered at 0,0,0
*
* Cylinder may be rendered with face culling enabled.
*/
static void solidCylinder(double r, double h, int slices)
{
GLUquadricObj *qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_FILL);
gluQuadricNormals(qobj, GLU_SMOOTH); glPushMatrix();
glTranslated(., ., -h/);
gluCylinder( qobj, r, r, h, slices, );
glPushMatrix();
glRotated(., .,.,.);
gluDisk( qobj, ., r, slices, );
glPopMatrix();
glTranslated(., ., h);
gluDisk( qobj, ., r, slices, );
glPopMatrix();
} static const char * Basename(const char *filename)
{
char *ptr = strrchr(filename, '/');
return ptr != NULL ? ptr+ : filename;
} /*
* This module is a crude front end to the GLUT menu system, allowing for
* slightly more sophisticated callbacks.
*/ #include <stdio.h> #define MAX_CALLBACKS 100 typedef struct {
void (*cb)(int, int, void *);
void *client;
} Callback; static Callback callbacks[MAX_CALLBACKS];
static int ncb = ; /*!
* Register a callback, returning an integer value suitable for
* passing to glutAddMenuEntry()
*
* \param cb Callback function to be called.
* \param client Data to be passed to the callback.
*
* \return integer callback id
*/
static int callback(void (*cb)(int, int, void *client), void *client)
{
if( ncb == )
{
int i;
for(i=; i < NA(callbacks); ++i)
callbacks[i].cb = NULL;
}
else if( ncb >= NA(callbacks) ) {
fprintf(stderr,
"callback() out of callbacks, try changing MAX_CALLBACKS\n");
} callbacks[ncb].cb = cb;
callbacks[ncb].client = client;
return ncb++;
} /*!
* Call the indexed callback.
*
* \param idx Callback index.
* \param data Data to be passed to the callback
*/
static void call_callback(int idx, int data)
{
if( idx >= && idx < NA(callbacks) && callbacks[idx].cb != NULL )
callbacks[idx].cb(idx, data, callbacks[idx].client);
}

lib3ds类库的更多相关文章

  1. .NET Core 系列5 :使用 Nuget打包类库

    NuGet是个开源项目,项目包括 NuGet VS插件/NuGet Explorer/NuGetServer/NuGet命令行等项目,.NET Core项目完全使用Nuget 管理组件之间的依赖关系, ...

  2. Xamarin+Prism开发详解一:PCL跨平台类库与Profile的关系

    在[Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用]中提到过以下错误,不知道大伙还记得不: 无法安装程序包"Microsoft.Identity.Client 1.0. ...

  3. C#创建dll类库

    类库让我们的代码可复用,我们只需要在类库中声明变量一次,就能在接下来的过程中无数次地使用,而无需在每次使用前都要声明它.这样一来,就节省了我们的内存空间.而想要在类库添加什么类,还需取决于类库要实现哪 ...

  4. .Net Core上用于代替System.Drawing的类库

    目前.Net Core上没有System.Drawing这个类库,想要在.Net Core上处理图片得另辟蹊径. 微软给出了将来取代System.Drawing的方案,偏向于使用一个单独的服务端进行各 ...

  5. 拥抱.NET Core,如何开发一个跨平台类库 (1)

    在此前的文章中详细介绍了使用.NET Core的基本知识,如果还没有看,可以先去了解“拥抱.NET Core,学习.NET Core的基础知识补遗”,以便接下来的阅读. 在本文将介绍如何配置类库项目支 ...

  6. CacheManager:–个通用缓存接口抽象类库

    CacheManager是–个缓存通用接口抽象类库,它支持各种高速缓存提供者,例如Memcache,Redis,并且有许多先进的功能特性.具体可以访问官方网站  http://cachemanager ...

  7. Atitit java onvif 开源类库 getProfiles getStreamUri

    Atitit java onvif 开源类库 getProfiles getStreamUri 1. ONVIF Java Library by Milgo1 1.1. https://github. ...

  8. Atitit 图像处理类库大总结attilax qc20

    Atitit 图像处理类库大总结attilax qc20 1.1. 选择与组合不同的图像处理类库1 1.2. Halcon 貌似商业工具,功能强大.1 1.3. Openvc  Openvc功能也是比 ...

  9. scikit-learn Adaboost类库使用小结

    在集成学习之Adaboost算法原理小结中,我们对Adaboost的算法原理做了一个总结.这里我们就从实用的角度对scikit-learn中Adaboost类库的使用做一个小结,重点对调参的注意事项做 ...

随机推荐

  1. [kuangbin带你飞]专题六 最小生成树

    学习最小生成树已经有一段时间了 做一些比较简单的题还算得心应手..花了三天的时间做完了kuangbin的专题 写一个题解出来记录一下(虽然几乎都是模板题) 做完的感想:有很多地方都要注意 n == 1 ...

  2. Linux 计划任务 Crontab 笔记与总结(1)

    Linux 版本:CentOS 6.6 应用场景,例如: ① 每分钟执行一个程序检查系统运行状态 ② 每天凌晨需要对过去一天的业务数据进行统计 ③ 每个星期需要把日志文件备份 ④ 每个月把数据库进行备 ...

  3. Vi问题

    ,ubuntu11.10下vi编辑器按i,左下方没有出现“输入模式”或者“insert”.在桌面环境下,用ctrl+alt+t调出命令行打开是这样,在第一控制台ctrl+alt+F1下打开,也是这样, ...

  4. filesort

  5. 费用性支出预分摊form方式和web方式区别

    预分摊 1 form方式 费用性支出先通过生产资产行请求 生成一个资产行,如果该资产行分摊到两个资产上则分割成两个资产行,既所谓的针对资产行进行分摊. 2 web方式 费用性支出直接分摊到资产上形成资 ...

  6. java event

    What is an Event? Change in the state of an object is known as event i.e. event describes the change ...

  7. 解决微软的两个恶心问题(VS2008死机、Win2008 WAS无法启动)

    1.Visual Studio 2008,在切换到Web设计界面或Html Markup界面时,过一段时间就出现假死,点击任何地方没反应,也关闭不了,只能用任务管理器结束任务. 上网查了下,应该是先装 ...

  8. 查询mysql当前连接数

    标签: mysql服务器cachedisk 2012-08-23 23:06 23377人阅读 评论(0) 收藏 举报  分类: MySql(36)  1.show status Threads_co ...

  9. 读书笔记——《图解TCP/IP》(3/4)

    经典摘抄 第五章 IP协议相关技术 1.DNS可以将网址自动转换为具体的IP地址. 2.主机识别码的识别方式:为每台计算机赋以唯一的主机名,在进行网络通信时,可以直接使用主机名称而无需输入一大长串的I ...

  10. centos apache安装和设置

    分类: LINUX 安装方式:yum install httpdyum install mysql-serveryum install phpyum install php-mysql 一.WEB服务 ...