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. Javascript 笔记与总结(2-1)Javascript 与 DOM

    浏览器有渲染 html 的功能,把 html 源码在内存里形成一个 DOM 对象,就是文档对象. 浏览器内部有一个 js 的解释器 / 执行器 / 引擎,如 Chrome 的 V8 引擎. 在 htm ...

  2. Python实用工具包Scrapy安装教程

       对于想用每个想用Python开发网络爬虫的开发者来说,Scrapy无疑是一个极好的开源工具.今天安装之后觉得Scrapy的安装确实不易啊.所以在此博文一篇,往后来着少走弯路. 废话不多说了,如果 ...

  3. w win cmd VS broswer

    php -f Fetch data from db , use php without any bugs to analyse the data and read and write db, with ...

  4. socket 中午吃的啥

    http://www.cnblogs.com/thinksasa/archive/2013/02/26/2934206.html

  5. MetaWeblog 同时管理51cto,csdn,sina,163,oschina,cnblogs等博客

    我们技术人一般都会有自己的一个博客,用于记录一些技术笔记,也期望自己的笔记文章可以让更多人知道. 如何让更多人知道自己的博客? 搜索引擎收录,用户通过关键词搜索可能会进入 内容运营,但是一般技术人为了 ...

  6. (转)js一道比较考验的题目

    转载下别人曾经出过的一道面试题,此题是他出的一套前端面试题中的最后一题,用来考核面试者的JavaScript的综合能力,很可惜到目前为止的将近两年中,几乎没有人能够完全答对,并非多难只是因为大多面试者 ...

  7. 删除本地git版本库中受版本控制的文件

     git乱码解决方案汇总 乱码原因 搜索一番,发现git文件名.log乱码,是普遍问题,这其中有编码的原因,也有跨平台的原因.主要原因是Windows 系统中的Git对中文文件名采用不同的编码保存所致 ...

  8. 使用dotTrace6.0进行内存分析

    dotTrace6.0提供了内存分析功能,统计抓取的时间段内各个堆栈执行过程中使用的内存大小,按照堆栈执行情况树状排序:和它之前提供的时间统计类似,粗截了几个页面,希望对大家有所帮助. 下载安装Jet ...

  9. mysql慢查询

    查看当前服务器是否开启慢查询: 1.快速办法,运行sql语句show VARIABLES like "%slow%" 2.直接去my.conf中查看. my.conf中的配置(放在 ...

  10. 位与(&)常用编程技巧

    补充知识:1)正整数的补码与原码相同:                2)求负整数的补码:原码 符号位不变,数值位各位取反,最后整个数加1得到补码:                3)按位与& ...