/* * Copyright (C) 1998,1999 Janne Löf * * This library 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 of the License, or (at your option) any later version. * * This library 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 library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "old_lw.h" #include #include #include #include #define MK_ID(a,b,c,d) ((((guint32)(a))<<24)| \ (((guint32)(b))<<16)| \ (((guint32)(c))<< 8)| \ (((guint32)(d)) )) #define ID_FORM MK_ID('F','O','R','M') #define ID_LWOB MK_ID('L','W','O','B') #define ID_PNTS MK_ID('P','N','T','S') #define ID_SRFS MK_ID('S','R','F','S') #define ID_SURF MK_ID('S','U','R','F') #define ID_POLS MK_ID('P','O','L','S') #define ID_COLR MK_ID('C','O','L','R') #define ID_CTEX MK_ID('C','T','E','X') #define ID_DTEX MK_ID('D','T','E','X') #define ID_STEX MK_ID('S','T','E','X') #define ID_RTEX MK_ID('R','T','E','X') #define ID_TTEX MK_ID('T','T','E','X') #define ID_BTEX MK_ID('B','T','E','X') #define ID_TIMG MK_ID('T','I','M','G') #define ID_TFLG MK_ID('T','F','L','G') #define ID_TSIZ MK_ID('T','S','I','Z') #define ID_TCTR MK_ID('T','C','T','R') #define ID_TFAL MK_ID('T','F','A','L') #define ID_TVEL MK_ID('T','V','E','L') #define ID_TWRP MK_ID('T','W','R','P') #define FALSE 0 #define TRUE 1 #define g_return_val_if_fail(expr,val) if (!(expr)) return val; #define g_return_if_fail(expr) if (!(expr)) return; #define g_realloc(exp1,exp2) realloc(exp1,exp2) #define g_malloc0(exp) malloc(exp) #define g_warning printf #define g_free free static gint32 read_char(FILE *f) { int c = fgetc(f); g_return_val_if_fail(c != EOF, 0); return c; } static gint32 read_short(FILE *f) { return (read_char(f)<<8) | read_char(f); } static gint32 read_long(FILE *f) { return (read_char(f)<<24) | (read_char(f)<<16) | (read_char(f)<<8) | read_char(f); } static GLfloat read_float(FILE *f) { gint32 x = read_long(f); return *(GLfloat*)&x; } static gint read_string(FILE *f, char *s) { gint c; gint cnt = 0; do { c = read_char(f); if (cnt < LW_MAX_NAME_LEN) s[cnt] = c; else s[LW_MAX_NAME_LEN-1] = 0; cnt++; } while (c != 0); /* if length of string (including \0) is odd skip another byte */ if (cnt%2) { read_char(f); cnt++; } return cnt; } static void read_srfs(FILE *f, gint nbytes, lwObject *lwo) { int guess_cnt = lwo->material_cnt; while (nbytes > 0) { lwMaterial *material; /* allocate more memory for materials if needed */ if (guess_cnt <= lwo->material_cnt) { guess_cnt += guess_cnt/2 + 4; lwo->material = (lwMaterial*) g_realloc(lwo->material, sizeof(lwMaterial)*guess_cnt); } material = lwo->material + lwo->material_cnt++; /* read name */ nbytes -= read_string(f,material->name); /* defaults */ material->r = 0.7f; material->g = 0.7f; material->b = 0.7f; } lwo->material = (lwMaterial*) g_realloc(lwo->material, sizeof(lwMaterial)*lwo->material_cnt); } static void read_surf(FILE *f, gint nbytes, lwObject *lwo) { int i; char name[LW_MAX_NAME_LEN]; lwMaterial *material = NULL; /* read surface name */ nbytes -= read_string(f,name); /* find material */ for (i=0; i< lwo->material_cnt; i++) { if (strcmp(lwo->material[i].name,name) == 0) { material = &lwo->material[i]; break; } } g_return_if_fail(material != NULL); lwTexture* tex = NULL; /* read values */ while (nbytes > 0) { gint id = read_long(f); gint len = read_short(f); nbytes -= 6 + len + (len%2); switch (id) { case ID_COLR: material->r = read_char(f) / 255.0f; material->g = read_char(f) / 255.0f; material->b = read_char(f) / 255.0f; read_char(f); /* dummy */ break; case ID_CTEX: case ID_DTEX: case ID_STEX: case ID_RTEX: case ID_TTEX: case ID_BTEX: len -= read_string(f, name); if (id == ID_CTEX) { tex = &material->ctex; } else tex = NULL; break; case ID_TIMG: { len -= read_string(f, name); if (tex) { /* last component of path */ char* slash = strrchr(name, '/'); if (!slash) slash = strrchr(name, '\\'); if (slash) strcpy(tex->name, slash+1); else strcpy(tex->name, name); //printf("tex name=%s\n", tex->name); } } break; case ID_TFLG: if (tex) { tex->flags = read_short(f); } else fseek(f, len+(len%2), SEEK_CUR); break; case ID_TSIZ: if (tex) { tex->sx = read_float(f); tex->sy = read_float(f); tex->sz = read_float(f); } else fseek(f, len+(len%2), SEEK_CUR); break; case ID_TCTR: if (tex) { tex->cx = read_float(f); tex->cy = read_float(f); tex->cz = read_float(f); } else fseek(f, len+(len%2), SEEK_CUR); break; case ID_TFAL: if (tex) { //float vx,vy,vz; /*vx =*/ read_float(f); /*vy =*/ read_float(f); /*vz =*/ read_float(f); //printf("fal %.2f %.2f %.2f\n", vx,vy,vz); } else fseek(f, len+(len%2), SEEK_CUR); break; case ID_TVEL: if (tex) { //float vx,vy,vz; /*vx =*/ read_float(f); /*vy =*/ read_float(f); /*vz =*/ read_float(f); //printf("vel %.2f %.2f %.2f\n", vx,vy,vz); } else fseek(f, len+(len%2), SEEK_CUR); break; case ID_TWRP: if (tex) { tex->u_wrap = (lwTextureWrap) read_short(f); tex->v_wrap = (lwTextureWrap) read_short(f); } else fseek(f, len+(len%2), SEEK_CUR); break; default: fseek(f, len+(len%2), SEEK_CUR); } } } static void read_pols(FILE *f, int nbytes, lwObject *lwo) { int guess_cnt = lwo->face_cnt; while (nbytes > 0) { lwFace *face; int i; /* allocate more memory for polygons if necessary */ if (guess_cnt <= lwo->face_cnt) { guess_cnt += guess_cnt + 4; lwo->face = (lwFace*) g_realloc(lwo->face, sizeof(lwFace)*guess_cnt); } face = lwo->face + lwo->face_cnt++; face->init(); /* number of points in this face */ face->index_cnt = read_short(f); nbytes -= 2; /* allocate space for points */ face->index = (int*) g_malloc0(sizeof(int)*face->index_cnt); /* read points in */ for (i=0; iindex_cnt; i++) { face->index[i] = read_short(f); nbytes -= 2; } /* read surface material */ face->material = read_short(f); nbytes -= 2; /* skip over detail polygons */ if (face->material < 0) { printf("face->material=%i ",face->material); int det_cnt; face->material = -face->material; det_cnt = read_short(f); nbytes -= 2; while (det_cnt-- > 0) { int cnt = read_short(f); fseek(f, cnt*2+2, SEEK_CUR); nbytes -= cnt*2+2; } } face->material -= 1; } /* readjust to true size */ lwo->face = (lwFace*) g_realloc(lwo->face, sizeof(lwFace)*lwo->face_cnt); } static void read_pnts(FILE *f, gint nbytes, lwObject *lwo) { int i; lwo->vertex_cnt = nbytes / 12; lwo->vertex = (GLfloat*) g_malloc0(sizeof(GLfloat)*lwo->vertex_cnt*3); for (i=0; ivertex_cnt; i++) { lwo->vertex[i*3+0] = read_float(f); lwo->vertex[i*3+1] = read_float(f); lwo->vertex[i*3+2] = read_float(f); } } gint lw_is_lwobject(const char *lw_file) { FILE *f = fopen(lw_file, "rb"); if (f) { gint32 form = read_long(f); gint32 nlen = read_long(f); gint32 lwob = read_long(f); fclose(f); if (form == ID_FORM && nlen != 0 && lwob == ID_LWOB) return TRUE; } return FALSE; } lwObject *lw_object_read(const char *lw_file, std::ostream& output) { FILE *f = NULL; lwObject *lw_object = NULL; gint32 form_bytes = 0; gint32 read_bytes = 0; /* open file */ f = fopen(lw_file, "rb"); if (f == NULL) { output << "can't open file "<init(); /* read chunks */ while (read_bytes < form_bytes) { gint32 id = read_long(f); gint32 nbytes = read_long(f); read_bytes += 8 + nbytes + (nbytes%2); switch (id) { case ID_PNTS: read_pnts(f, nbytes, lw_object); break; case ID_POLS: read_pols(f, nbytes, lw_object); break; case ID_SRFS: read_srfs(f, nbytes, lw_object); break; case ID_SURF: read_surf(f, nbytes, lw_object); break; default: fseek(f, nbytes + (nbytes%2), SEEK_CUR); } } fclose(f); for (int i = 0; i < lw_object->face_cnt; i++) { int mati = lw_object->face[i].material; if (mati == 0) continue; /* fetch material */ lwMaterial* mat = &lw_object->material[mati]; unsigned int flags = mat->ctex.flags; if (flags == 0) continue; /* calculate texture coordinates */ lwFace* face = &lw_object->face[i]; face->texcoord = (float*) g_malloc0(face->index_cnt * sizeof(float) * 2); for (int j = 0; j < face->index_cnt; j++) { int vi = face->index[j]; GLfloat* vtx = &lw_object->vertex[vi*3]; GLfloat u,v; u = v = 0.0f; if (flags & X_AXIS) { u = (vtx[1] - mat->ctex.cy) / mat->ctex.sy; v = (vtx[2] - mat->ctex.cz) / mat->ctex.sz; } else if (flags & Y_AXIS) { u = (vtx[0] - mat->ctex.cx) / mat->ctex.sx; v = (vtx[2] - mat->ctex.cz) / mat->ctex.sz; } else if (flags & Z_AXIS) { u = (vtx[0] - mat->ctex.cx) / mat->ctex.sx; v = (vtx[1] - mat->ctex.cy) / mat->ctex.sy; } face->texcoord[j*2] = u + 0.5f; face->texcoord[j*2+1] = v + 0.5f; //printf("%.2f %.2f\n", u,v); } } return lw_object; } void lw_object_free(lwObject *lw_object) { g_return_if_fail(lw_object != NULL); if (lw_object->face) { int i; for (i=0; iface_cnt; i++) { g_free(lw_object->face[i].index); if (lw_object->face[i].texcoord) g_free(lw_object->face[i].texcoord); } g_free(lw_object->face); } g_free(lw_object->material); g_free(lw_object->vertex); g_free(lw_object); } GLfloat lw_object_radius(const lwObject *lwo) { int i; double max_radius = 0.0; g_return_val_if_fail(lwo != NULL, 0.0); for (i=0; ivertex_cnt; i++) { GLfloat *v = &lwo->vertex[i*3]; double r = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; if (r > max_radius) max_radius = r; } return (float)sqrt(max_radius); } void lw_object_scale(lwObject *lwo, GLfloat scale) { int i; g_return_if_fail(lwo != NULL); for (i=0; ivertex_cnt; i++) { lwo->vertex[i*3+0] *= scale; lwo->vertex[i*3+1] *= scale; lwo->vertex[i*3+2] *= scale; } }