diff --git a/Extras/readblend/abs-file.h b/Extras/readblend/abs-file.h index 1f0e89f7b..3e98ad06b 100644 --- a/Extras/readblend/abs-file.h +++ b/Extras/readblend/abs-file.h @@ -10,13 +10,18 @@ #ifndef _ABS_FILE_H #define _ABS_FILE_H - typedef unsigned char uint8_t; - typedef unsigned long int uint64_t; - typedef unsigned int uint32_t; - typedef int int32_t; +#ifdef WIN32 + + typedef unsigned char uint8_t; + typedef unsigned long int uint64_t; + typedef unsigned int uint32_t; + typedef int int32_t; typedef unsigned short uint16_t; typedef short int16_t; +#else +#include +#endif /* PLEASE NOTE: This license applies to abs-file.h ONLY; The version of @@ -194,6 +199,8 @@ static int MY_PUTS(const char *s, MY_FILETYPE *const fp) { #else /* !USE_PHYSFS */ +//#define USE_POSIX_FILES 1 +#ifdef USE_POSIX_FILES #define MY_FILETYPE FILE #define MY_READ(p,s,n,fp) fread(p,s,n,fp) #define MY_WRITE(p,s,n,fp) fwrite(p,s,n,fp) @@ -221,6 +228,33 @@ static long MY_FILELENGTH(FILE *fp) { fseek(fp, currentpos, SEEK_SET); /* restore previous cursor position */ return newpos; } +#else +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MY_FILETYPE char + + +long MY_FILELENGTH(FILE *fp); +MY_FILETYPE* MY_OPEN_FOR_READ(const char *const filename); +int MY_GETC(MY_FILETYPE *const fp); +void MY_SEEK(MY_FILETYPE* fp,int pos); +#define MY_REWIND(fp) MY_SEEK(fp,0) +int MY_READ(unsigned char* dest,int size,int num,MY_FILETYPE* fp); + +void MY_CLOSE(MY_FILETYPE* fp); +int MY_TELL(MY_FILETYPE* fp); +int MY_ATEOF(MY_FILETYPE* fp); + +#ifdef __cplusplus +} +#endif + +#endif //USE_POSIX_FILES + #endif /* USE_PHYSFS */ #endif /* _ABS_FILE_H */ diff --git a/Extras/readblend/blendtype.h b/Extras/readblend/blendtype.h new file mode 100644 index 000000000..da6feeb2e --- /dev/null +++ b/Extras/readblend/blendtype.h @@ -0,0 +1,87 @@ +#ifndef BLEND_TYPE_H +#define BLEND_TYPE_H +#include "abs-file.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _BlendField BlendField; +struct _BlendField { + char* field_bytes; + int field_bytes_count; + + /* the offset into field_bytes at which each field of a + structure begins. this is so we can keep the data aligned + correctly for various architectures. a non-structure type + is equivalent to a structure with a single field. + */ + int* field_offsets; + int field_offsets_count; +}; +struct _BlendBlock { + char tag[5]; + uint32_t blender_pointer; + /*void* fixed_pointer;*/ + + int type_index; + /* a block is simply an array of its type as defined by type_index. + array_entries is an array of pointers to each entry in the block's + array. + */ + BlendField *array_entries; + int array_entries_count; + void* customData; /* for Link blocks, with custom data such as .jpg pictures etc */ + int customDataSize; +}; + + +typedef struct _BlendBlock BlendBlock; + +/* the types extracted from the Blender file */ +typedef struct _BlendType BlendType; +struct _BlendType { + char* name; + int size; + + int is_struct; + + /* if is_struct... this defines the types of each of the structure fields */ + int fieldtypes_count; + int* fieldtypes; /* type indices */ + int fieldnames_count; + int* fieldnames; /* name indices */ +}; + + + + + + +/* the opaque BlendFile structure */ +typedef struct _BlendFile{ + BlendType* types; + int types_count; + + char* *names; + int names_count; + + int* strc_indices; + int strc_indices_count; + + BlendBlock *blocks; + int blocks_count; + + int name_undef; /* index of the name we add specially for top blocks */ + +} BlendFile; + + + + +#ifdef __cplusplus +} +#endif + +#endif //BLEND_TYPE_H \ No newline at end of file diff --git a/Extras/readblend/readblend.c b/Extras/readblend/readblend.c index 9a229d7cb..bf720d9a5 100644 --- a/Extras/readblend/readblend.c +++ b/Extras/readblend/readblend.c @@ -1,3 +1,4 @@ +#include "blendtype.h" #include //#include @@ -6,6 +7,90 @@ #include "abs-file.h" +#ifndef USE_POSIX_FILES + + + + +static char* gBuffer = 0; +static int gCurrentFilePtr = 0; +static int gFileSize = 0; + + +long MY_FILELENGTH(FILE *fp) { + long currentpos = ftell(fp); /* save current cursor position */ + long newpos; + fseek(fp, 0, SEEK_END); /* seek to end */ + newpos = ftell(fp); /* find position of end -- this is the length */ + fseek(fp, currentpos, SEEK_SET); /* restore previous cursor position */ + return newpos; +} + + +MY_FILETYPE* MY_OPEN_FOR_READ(const char *const filename) +{ + FILE* gFile = fopen(filename,"rb"); + if (gFile) + { + long currentpos = ftell(gFile); /* save current cursor position */ + long newpos; + int bytesRead; + + fseek(gFile, 0, SEEK_END); /* seek to end */ + newpos = ftell(gFile); /* find position of end -- this is the length */ + fseek(gFile, currentpos, SEEK_SET); /* restore previous cursor position */ + gFileSize = newpos; + gBuffer = (char*)malloc(gFileSize); + bytesRead = fread(gBuffer,gFileSize,1,gFile); + gCurrentFilePtr = 0; + fclose(gFile); + gFile = 0; + return gBuffer; + } + return 0; +} + +int MY_GETC(MY_FILETYPE *const fp) +{ + return gBuffer[gCurrentFilePtr++]; +} + +void MY_SEEK(MY_FILETYPE* fp,int pos) +{ + gCurrentFilePtr = pos; +} + +#define MY_REWIND(fp) MY_SEEK(fp,0) +int MY_READ(unsigned char* dest,int size,int num,MY_FILETYPE* fp) +{ + int n; + memcpy(dest,&gBuffer[gCurrentFilePtr],size*num); + gCurrentFilePtr += size*num; + return num; +} + +void MY_CLOSE(MY_FILETYPE* fp) +{ + free(gBuffer); + gBuffer = 0; + gCurrentFilePtr = 0; + gFileSize = 0; + +} + +int MY_TELL(MY_FILETYPE* fp) +{ + return gCurrentFilePtr; +} + +int MY_ATEOF(MY_FILETYPE* fp) +{ + return gCurrentFilePtrtypes = NULL; - rtn->types_count = 0; - rtn->names = NULL; - rtn->names_count = 0; - rtn->blocks = NULL; - rtn->blocks_count = 0; - rtn->strc_indices = NULL; - rtn->strc_indices_count = 0; - rtn->name_undef = -1; - return rtn; + BlendFile *rtn = malloc(sizeof(BlendFile)); + if (!rtn) { + dprintf(stderr, "out of mem making bf handle\n"); + return NULL; + } + rtn->types = NULL; + rtn->types_count = 0; + rtn->names = NULL; + rtn->names_count = 0; + rtn->blocks = NULL; + rtn->blocks_count = 0; + rtn->strc_indices = NULL; + rtn->strc_indices_count = 0; + rtn->name_undef = -1; + return rtn; } static long seek_past_string(MY_FILETYPE* file, const char *str) { - const int match_max = strlen(str); - int match_now = 0; + const int match_max = strlen(str); + int match_now = 0; - do { - const char c = MY_GETC(file); - if (c == str[match_now]) { - ++match_now; - } else { - match_now = 0; - } - } while(match_now < match_max && - !MY_ATEOF(file)); + do { + const char c = MY_GETC(file); + if (c == str[match_now]) { + ++match_now; + } else { + match_now = 0; + } + } while(match_now < match_max && + !MY_ATEOF(file)); - if (MY_ATEOF(file)) { - return -1; - } + if (MY_ATEOF(file)) { + return -1; + } - return MY_TELL(file) - match_max; + return MY_TELL(file) - match_max; } #define EXPANDO_MULTIPLE(ARRAY,ADDITIONPTR,NUMBER) \ -do { \ - (ARRAY) = realloc((ARRAY), sizeof((ARRAY)[0]) * (NUMBER +(ARRAY##_count))); \ - memcpy(&(ARRAY)[ARRAY##_count], ADDITIONPTR, sizeof((ARRAY)[0]) * NUMBER); \ - (ARRAY##_count) += NUMBER; \ -} while(0) + do { \ + (ARRAY) = realloc((ARRAY), sizeof((ARRAY)[0]) * (NUMBER +(ARRAY##_count))); \ + memcpy(&(ARRAY)[ARRAY##_count], ADDITIONPTR, sizeof((ARRAY)[0]) * NUMBER); \ + (ARRAY##_count) += NUMBER; \ + } while(0) #define EXPANDO(ARRAY,ADDITION) \ -do { \ - (ARRAY) = realloc((ARRAY), sizeof((ARRAY)[0]) * (1 + (ARRAY##_count))); \ - (ARRAY)[ARRAY##_count] = (ADDITION); \ - ++(ARRAY##_count); \ -} while(0) - + do { \ + (ARRAY) = realloc((ARRAY), sizeof((ARRAY)[0]) * (1 + (ARRAY##_count))); \ + (ARRAY)[ARRAY##_count] = (ADDITION); \ + ++(ARRAY##_count); \ + } while(0) static unsigned short read_ushort(MY_FILETYPE* file) { - unsigned char c[2]; - if (MY_READ(c, 2, 1, file) == 1) { - return c[0] | (c[1]<<8); - } else { - return 0xFFFF; - } + unsigned char c[2]; + if (MY_READ(c, 2, 1, file) == 1) + { + return c[0] | (c[1]<<8); + } else { + return 0xFFFF; + } } static long read_long(MY_FILETYPE* file) { - unsigned char c[4]; - if (MY_READ(c, 4, 1, file) == 1) { - return ((unsigned long)c[0] | (c[1]<<8) | (c[2]<<16) | (c[3]<<24)); - } else { - return 0xFFFFFFFF; - } + unsigned char c[4]; + if (MY_READ(c, 4, 1, file) == 1) { + return ((unsigned long)c[0] | (c[1]<<8) | (c[2]<<16) | (c[3]<<24)); + } else { + return 0xFFFFFFFF; + } } static unsigned long read_ulong(MY_FILETYPE* file) { - unsigned char c[4]; - if (MY_READ(c, 4, 1, file) == 1) { - return c[0] | (c[1]<<8) | (c[2]<<16) | (c[3]<<24); - } else { - return 0xFFFFFFFF; - } + unsigned char c[4]; + if (MY_READ(c, 4, 1, file) == 1) { + return c[0] | (c[1]<<8) | (c[2]<<16) | (c[3]<<24); + } else { + return 0xFFFFFFFF; + } } static int name_is_pointer(char* name) { - int len = strlen(name); - /*fprintf(stderr,"[%s]",name);*/ - if (len >= 1) { - if (name[0] == '*') - return 1; - } - if (len >= 2) { - if (name[1] == '*') - return 1; - } - return 0; + int len = strlen(name); + /*fprintf(stderr,"[%s]",name);*/ + if (len >= 1) { + if (name[0] == '*') + return 1; + } + if (len >= 2) { + if (name[1] == '*') + return 1; + } + return 0; } /* note: we only deal with 1d or 2d arrays at the moment. haven't - seen any arrays of a higher order from Blender yet. */ +seen any arrays of a higher order from Blender yet. */ static int name_is_array(char* name, int* dim1, int* dim2) { - int len = strlen(name); - /*fprintf(stderr,"[%s]",name);*/ - /*if (len >= 1) { - if (name[len-1] != ']') - return 1; - } - return 0;*/ - char *bp; - int num; - if (dim1) { - *dim1 = 1; - } - if (dim2) { - *dim2 = 1; - } - bp = strchr(name, '['); - if (!bp) { - return 0; - } - num = 0; - while (++bp < name+len-1) { - const char c = *bp; - if (c == ']') { - break; - } - if (c <= '9' && c >= '0') { - num *= 10; - num += (c - '0'); - } else { - dprintf(stderr, "array parse error.\n"); - return 0; - } - } - if (dim2) { - *dim2 = num; - } + int len = strlen(name); + /*fprintf(stderr,"[%s]",name);*/ + /*if (len >= 1) { + if (name[len-1] != ']') + return 1; + } + return 0;*/ + char *bp; + int num; + if (dim1) { + *dim1 = 1; + } + if (dim2) { + *dim2 = 1; + } + bp = strchr(name, '['); + if (!bp) { + return 0; + } + num = 0; + while (++bp < name+len-1) { + const char c = *bp; + if (c == ']') { + break; + } + if (c <= '9' && c >= '0') { + num *= 10; + num += (c - '0'); + } else { + dprintf(stderr, "array parse error.\n"); + return 0; + } + } + if (dim2) { + *dim2 = num; + } - /* find second dim, if any. */ - bp = strchr(bp, '['); - if (!bp) { - return 1; /* at least we got the first dim. */ - } - num = 0; - while (++bp < name+len-1) { - const char c = *bp; - if (c == ']') { - break; - } - if (c <= '9' && c >= '0') { - num *= 10; - num += (c - '0'); - } else { - dprintf(stderr, "array2 parse error.\n"); - return 1; - } - } - if (dim1) { - if (dim2) { - *dim1 = *dim2; - *dim2 = num; - } else { - *dim1 = num; - } - } + /* find second dim, if any. */ + bp = strchr(bp, '['); + if (!bp) { + return 1; /* at least we got the first dim. */ + } + num = 0; + while (++bp < name+len-1) { + const char c = *bp; + if (c == ']') { + break; + } + if (c <= '9' && c >= '0') { + num *= 10; + num += (c - '0'); + } else { + dprintf(stderr, "array2 parse error.\n"); + return 1; + } + } + if (dim1) { + if (dim2) { + *dim1 = *dim2; + *dim2 = num; + } else { + *dim1 = num; + } + } - return 1; + return 1; } @@ -317,782 +344,831 @@ name_is_array(char* name, int* dim1, int* dim2) { static void recursively_read_type(MY_FILETYPE* file, BlendFile* bf, - unsigned long section_type, - BlendField* field) + unsigned long section_type, + BlendField* field) { - char *new_data = NULL; - int new_data_size = 0; - int dim1, dim2; + char *new_data = NULL; + int new_data_size = 0; + int dim1, dim2; - if (bf->types[section_type].is_struct) { - int i; - /*fprintf(stderr, "type%d(%s)is_struct(%d) ", section_type, bf->types[section_type].name, bf->types[section_type].size);*/ - for (i=0; itypes[section_type].fieldtypes_count; ++i) { - /*fprintf(stderr, "@%d ", i);*/ - int j,k; + if (bf->types[section_type].is_struct) { + int i; + /*fprintf(stderr, "type%d(%s)is_struct(%d) ", section_type, bf->types[section_type].name, bf->types[section_type].size);*/ + for (i=0; itypes[section_type].fieldtypes_count; ++i) { + /*fprintf(stderr, "@%d ", i);*/ + int j,k; #if 0 - if (name_is_array(bf->names[bf->types[section_type].fieldnames[i]], - &j,&k) || 1) { - dprintf(stderr, " %s/%s=[%d][%d] ", - bf->types[bf->types[section_type].fieldtypes[i]].name, - bf->names[bf->types[section_type].fieldnames[i]], j, k); - } + if (name_is_array(bf->names[bf->types[section_type].fieldnames[i]], + &j,&k) || 1) { + dprintf(stderr, " %s/%s=[%d][%d] ", + bf->types[bf->types[section_type].fieldtypes[i]].name, + bf->names[bf->types[section_type].fieldnames[i]], j, k); + } #endif - if (name_is_pointer(bf->names[bf->types[section_type].fieldnames[i]])) { - /*fprintf(stderr, "*(4) ");*/ - name_is_array(bf->names[bf->types[section_type].fieldnames[i]], - &dim1,&dim2); - new_data_size = SIZE_ROUNDUP(4); - new_data = malloc(new_data_size); - /*fprintf(stderr, " ");*/ - for (j=0; jfield_offsets, field->field_bytes_count); - EXPANDO_MULTIPLE(field->field_bytes, new_data, new_data_size); - /*fprintf(stderr, "N*(%d) ", new_data_size);*/ - } + if (name_is_pointer(bf->names[bf->types[section_type].fieldnames[i]])) { + /*fprintf(stderr, "*(4) ");*/ + name_is_array(bf->names[bf->types[section_type].fieldnames[i]], + &dim1,&dim2); + new_data_size = SIZE_ROUNDUP(4); + new_data = malloc(new_data_size); + /*fprintf(stderr, " ");*/ + for (j=0; jfield_offsets, field->field_bytes_count); + + (field->field_offsets) = realloc((field->field_offsets), sizeof((field->field_offsets)[0]) * (1 + (field->field_offsets_count))); + (field->field_offsets)[field->field_offsets_count] = (field->field_bytes_count); + ++(field->field_offsets_count); + + + // EXPANDO_MULTIPLE(field->field_bytes, new_data, new_data_size); + { + (field->field_bytes) = realloc((field->field_bytes), sizeof((field->field_bytes)[0]) * (new_data_size +(field->field_bytes_count))); + memcpy(&(field->field_bytes)[field->field_bytes_count], new_data, sizeof((field->field_bytes)[0]) * new_data_size); + (field->field_bytes_count) += new_data_size; + } + + /*fprintf(stderr, "N*(%d) ", new_data_size);*/ + } + } + free(new_data); + } else { + name_is_array(bf->names[bf->types[section_type].fieldnames[i]], + &dim1,&dim2); + /*fprintf(stderr, " ");*/ + for (j=0; jtypes[section_type].fieldtypes[i], + field); + } + } + } + } + } else { + /*fprintf(stderr, "type%d(%s)plain(%d) ", section_type, bf->types[section_type].name, bf->types[section_type].size); */ + new_data_size = SIZE_ROUNDUP(bf->types[section_type].size); + /*fprintf(stderr, "%d... ", bf->types[section_type].size); + if (bf->types[section_type].size > 4) { + fprintf(stderr, "%d ", field->field_bytes_count); + }*/ + if (new_data_size) { + new_data = malloc(new_data_size); + MY_READ(new_data, 1, bf->types[section_type].size, file); + EXPANDO(field->field_offsets, field->field_bytes_count); + EXPANDO_MULTIPLE(field->field_bytes, new_data, new_data_size); + /*fprintf(stderr, "ND(%d) ", new_data_size); */ + free(new_data); + } else { + dprintf(stderr, " ", + bf->types[section_type].size); + } } - free(new_data); - } else { - name_is_array(bf->names[bf->types[section_type].fieldnames[i]], - &dim1,&dim2); - /*fprintf(stderr, " ");*/ - for (j=0; jtypes[section_type].fieldtypes[i], - field); - } - } - } - } - } else { - /*fprintf(stderr, "type%d(%s)plain(%d) ", section_type, bf->types[section_type].name, bf->types[section_type].size); */ - new_data_size = SIZE_ROUNDUP(bf->types[section_type].size); - /*fprintf(stderr, "%d... ", bf->types[section_type].size); - if (bf->types[section_type].size > 4) { - fprintf(stderr, "%d ", field->field_bytes_count); - }*/ - if (new_data_size) { - new_data = malloc(new_data_size); - MY_READ(new_data, 1, bf->types[section_type].size, file); - EXPANDO(field->field_offsets, field->field_bytes_count); - EXPANDO_MULTIPLE(field->field_bytes, new_data, new_data_size); - /*fprintf(stderr, "ND(%d) ", new_data_size); */ - free(new_data); - } else { - dprintf(stderr, " ", - bf->types[section_type].size); - } - } } static BlendField read_type(MY_FILETYPE* file, BlendFile* bf, - unsigned long section_type) + unsigned long section_type) { - BlendField rtn; + BlendField rtn; - rtn.field_bytes = NULL; - rtn.field_bytes_count = 0; - rtn.field_offsets = NULL; - rtn.field_offsets_count = 0; - - recursively_read_type(file, bf, section_type, &rtn); + rtn.field_bytes = NULL; + rtn.field_bytes_count = 0; + rtn.field_offsets = NULL; + rtn.field_offsets_count = 0; - return rtn; + recursively_read_type(file, bf, section_type, &rtn); + + return rtn; } static int blend_read_data(MY_FILETYPE* file, BlendFile* bf) { - long next_block_start = 12; - int finished_extracting = 0; - char section_name[5] = {0,0, 0,0, 0}; + long next_block_start = 12; + int finished_extracting = 0; + char section_name[5] = {0,0, 0,0, 0}; - /* slurp up the whole file block by block! */ + /* slurp up the whole file block by block! */ - do { - unsigned long section_size; - unsigned long section_pointer; - unsigned long section_type; - unsigned long section_ents; + do { + unsigned long section_size; + unsigned long section_pointer; + unsigned long section_type; + unsigned long section_ents; + MY_SEEK(file, next_block_start); - MY_SEEK(file, next_block_start); + MY_READ(section_name, 4, 1, file); - MY_READ(section_name, 4, 1, file); - if (strcmp(section_name, "DNA1") != 0) { - int i; - BlendBlock block; + if (strcmp(section_name, "DNA1") != 0) { - section_size = read_ulong(file); - section_pointer = read_ulong(file); - section_type = read_ulong(file); - section_type = bf->strc_indices[section_type]; - section_ents = read_ulong(file); - memcpy(block.tag, section_name, 4); - block.tag[4] = '\0'; - block.type_index = section_type; - block.blender_pointer = section_pointer; - /*block.fixed_pointer = NULL;*/ - block.array_entries = NULL; - block.array_entries_count = 0; + int i; + BlendBlock block; - /*dprintf(stderr, "\nsizeof(%s)=%ld: %s[%ld]\n", section_name, section_size, bf->types[section_type].name, section_ents); */ - for (i=0; iblocks, block); + if (strcmp(section_name, "IM") == 0) { + //printf("image\n"); + } - next_block_start += 4+4+4+4+4 + section_size; + + + + if (strcmp(section_name, "IP") == 0) { +// printf("ipo\n"); + } + + section_size = read_ulong(file); + section_pointer = read_ulong(file); + section_type = read_ulong(file); + section_type = bf->strc_indices[section_type]; + section_ents = read_ulong(file); + + if (dumpNames) + { +// printf("section_name = %s, section_type = %d / %s\n",section_name,section_type,bf->types[section_type]); + + } + + memcpy(block.tag, section_name, 4); + block.tag[4] = '\0'; + block.type_index = section_type; + block.blender_pointer = section_pointer; + /*block.fixed_pointer = NULL;*/ + block.array_entries = NULL; + block.array_entries_count = 0; + block.customData = 0; + block.customDataSize = 0; + + // dprintf(stderr, "\nsizeof(%s)=%ld: %s[%ld]\n", section_name, section_size, bf->types[section_type].name, section_ents); + + if (strcmp("Link",bf->types[section_type].name)==0) + { + if (section_size>0) + { + //read customData + block.customData= (char*)malloc(section_size); + block.customDataSize = section_size; + MY_READ(block.customData,1,section_size,file); + } + } else + { + for (i=0; iblocks, block); + + next_block_start += 4+4+4+4+4 + section_size; #ifdef B_DEBUG - if (MY_TELL(file) > next_block_start) { - dprintf(stderr, " **OVER-READ(%ld,%ld)** ", - MY_TELL(file), next_block_start); - if (strcmp(bf->types[section_type].name, "Link") == 0 && - MY_TELL(file) - next_block_start == 4) { - dprintf(stderr, "<- don't panic, known Link struct weirdness."); - } else { - dprintf(stderr, "<- okay, PANIC!"); - } - dprintf(stderr, "\n"); - } else if (MY_TELL(file) < next_block_start) { - /*dprintf(stderr, " **under-READ(%ld,%ld)** ", - MY_TELL(file), next_block_start);*/ - } else { - /*dprintf(stderr, " :) ");*/ - } + if (MY_TELL(file) > next_block_start) { + //dprintf(stderr, " **OVER-READ(%ld,%ld)** ", MY_TELL(file), next_block_start); + if (strcmp(bf->types[section_type].name, "Link") == 0 && + MY_TELL(file) - next_block_start == 4) { + //dprintf(stderr, "<- don't panic, known Link struct weirdness."); + } else { + dprintf(stderr, "<- okay, PANIC!"); + } + //dprintf(stderr, "\n"); + } else if (MY_TELL(file) < next_block_start) { + /*dprintf(stderr, " **under-READ(%ld,%ld)** ", + MY_TELL(file), next_block_start);*/ + } else { + /*dprintf(stderr, " :) ");*/ + } #endif - - } else { - finished_extracting = 1; - } - } while (!finished_extracting); + } else { + finished_extracting = 1; + } - return 1; + } while (!finished_extracting); + + return 1; } BlendFile* blend_read(MY_FILETYPE* file) { - char blender_mark[8] = {0,0,0,0, 0,0,0,0}; - BlendFile *bf; - long sdnaname_offs, type_offs, tlen_offs, strc_offs, endb_offs; - long sdnaname_size, type_size, tlen_size, strc_size; - long sdnaname_ents, type_ents, tlen_ents, strc_ents; + char blender_mark[10] = {0,0,0,0, 0,0,0,0,0,0}; + BlendFile *bf; + long sdnaname_offs, type_offs, tlen_offs, strc_offs, endb_offs; + long sdnaname_size, type_size, tlen_size, strc_size; + long sdnaname_ents, type_ents, tlen_ents, strc_ents; - MY_REWIND(file); + MY_REWIND(file); - /* Check file signature */ + /* Check file signature */ - MY_READ(blender_mark, 1, 7, file); - if (strcmp(blender_mark, "BLENDER") != 0) { - dprintf(stderr, "Not a Blender file.\n"); - return NULL; - } - - /* Alloc a handle to return */ - - bf = bf_new(); - - /* Scan the whole file (!) for file section markers */ - - sdnaname_offs = seek_past_string(file, "SDNANAME"); - sdnaname_ents = read_long(file); - type_offs = seek_past_string(file, "TYPE"); - type_ents = read_long(file); - tlen_offs = seek_past_string(file, "TLEN"); - tlen_ents = type_ents; - strc_offs = seek_past_string(file, "STRC"); - strc_ents = read_long(file); - endb_offs = seek_past_string(file, "ENDB"); - - if (sdnaname_offs == -1 || type_offs == -1 || tlen_offs == -1 || - strc_offs == -1 || endb_offs == -1) { - dprintf(stderr, "Couldn't find all necessary file markers. :(\n"); - return NULL; - } - - /* Move marker offsets to point to the start of each one's block */ - - sdnaname_offs += 8 + 4; - sdnaname_size = type_offs - sdnaname_offs; - - type_offs += 4 + 4; - type_size = tlen_offs - type_offs; - - tlen_offs += 4; - tlen_size = strc_offs - tlen_offs; - - strc_offs += 4 + 4; - strc_size = endb_offs - strc_offs; - - /* read the NAME table */ - - MY_SEEK(file, sdnaname_offs); - { - long offs = 0; - int i; - char *top_block_name; - - for (i=0; inames, this_name_chars); - } - /* our top-block name */ + /* Alloc a handle to return */ + + bf = bf_new(); + + /* Scan the whole file (!) for file section markers */ + + sdnaname_offs = seek_past_string(file, "SDNANAME"); + sdnaname_ents = read_long(file); + type_offs = seek_past_string(file, "TYPE"); + type_ents = read_long(file); + tlen_offs = seek_past_string(file, "TLEN"); + tlen_ents = type_ents; + strc_offs = seek_past_string(file, "STRC"); + strc_ents = read_long(file); + endb_offs = seek_past_string(file, "ENDB"); + + if (sdnaname_offs == -1 || type_offs == -1 || tlen_offs == -1 || + strc_offs == -1 || endb_offs == -1) { + dprintf(stderr, "Couldn't find all necessary file markers. :(\n"); + return NULL; + } + + /* Move marker offsets to point to the start of each one's block */ + + sdnaname_offs += 8 + 4; + sdnaname_size = type_offs - sdnaname_offs; + + type_offs += 4 + 4; + type_size = tlen_offs - type_offs; + + tlen_offs += 4; + tlen_size = strc_offs - tlen_offs; + + strc_offs += 4 + 4; + strc_size = endb_offs - strc_offs; + + /* read the NAME table */ + + MY_SEEK(file, sdnaname_offs); + { + long offs = 0; + int i; + char *top_block_name; + + for (i=0; inames, this_name_chars); + } + + /* our top-block name */ #define BLEND_TOP_BLOCK_NAME "READBLEND_TOP_BLOCK" - top_block_name = calloc(1, 1+strlen(BLEND_TOP_BLOCK_NAME)); - strcpy(top_block_name, BLEND_TOP_BLOCK_NAME); - bf->name_undef = bf->names_count; - EXPANDO(bf->names, top_block_name); - } - - /* read the TYPE table */ - - MY_SEEK(file, type_offs); - { - long offs = 0; - int i; - - for (i=0; iname_undef = bf->names_count; + EXPANDO(bf->names, top_block_name); } - - EXPANDO(this_type_chars, c); - } while (!finished_type); - - bt.name = this_type_chars; - bt.size = -1; - bt.is_struct = 0; - bt.fieldtypes_count = 0; - bt.fieldtypes = NULL; - bt.fieldnames_count = 0; - bt.fieldnames = NULL; - /* fprintf(stderr, "(%d:%s)", bt.size, bt.name);*/ + /* read the TYPE table */ - EXPANDO(bf->types, bt); - } - } + MY_SEEK(file, type_offs); + { + long offs = 0; + int i; - /* read the TLEN table */ + for (i=0; itypes_count; ++i) { - unsigned short len = read_ushort(file); - bf->types[i].size = len; - /*fprintf(stderr, "sizeof(%s)=%d ", bf->types[i].name, len); */ - } - } + do { + const char c = MY_GETC(file); + ++offs; + if (offs == type_size || + c == '\0') { + finished_type = 1; + } - /* Read the STRC table */ - - MY_SEEK(file, strc_offs); - { - int i,j; - for (i=0; itypes[struc_type_index].is_struct = 1; - EXPANDO(bf->strc_indices, struc_type_index); - /*dprintf(stderr, "\n%s: ", bf->types[struc_type_index].name); */ - for (j=0; jtypes[struc_type_index].fieldtypes, ftype); - EXPANDO(bf->types[struc_type_index].fieldnames, fname); - /*dprintf(stderr, "%s %s , ", bf->types[ftype].name, bf->names[fname]); */ - } - } - } + EXPANDO(this_type_chars, c); + } while (!finished_type); - blend_read_data(file, bf); + bt.name = this_type_chars; + bt.size = -1; + bt.is_struct = 0; + bt.fieldtypes_count = 0; + bt.fieldtypes = NULL; + bt.fieldnames_count = 0; + bt.fieldnames = NULL; - /* Return the new handle */ + /* fprintf(stderr, "(%d:%s)", bt.size, bt.name);*/ - return bf; + EXPANDO(bf->types, bt); + } + } + + /* read the TLEN table */ + + MY_SEEK(file, tlen_offs); + { + int i; + for (i=0; itypes_count; ++i) { + unsigned short len = read_ushort(file); + bf->types[i].size = len; + /*fprintf(stderr, "sizeof(%s)=%d ", bf->types[i].name, len); */ + } + } + + /* Read the STRC table */ + + MY_SEEK(file, strc_offs); + { + int i,j; + for (i=0; itypes[struc_type_index].is_struct = 1; + EXPANDO(bf->strc_indices, struc_type_index); + /*dprintf(stderr, "\n%s: ", bf->types[struc_type_index].name); */ + for (j=0; jtypes[struc_type_index].fieldtypes, ftype); + EXPANDO(bf->types[struc_type_index].fieldnames, fname); + /*dprintf(stderr, "%s %s , ", bf->types[ftype].name, bf->names[fname]); */ + } + } + } + + blend_read_data(file, bf); + + /* Return the new handle */ + + return bf; } static void free_btype_inner(BlendType *btype) { - if (btype->name) { - free(btype->name); - } else { - dprintf(stderr, "null typename.\n"); - } + if (btype->name) { + free(btype->name); + } else { + dprintf(stderr, "null typename.\n"); + } - if (btype->fieldtypes) { - free(btype->fieldtypes); - } + if (btype->fieldtypes) { + free(btype->fieldtypes); + } - if (btype->fieldnames) { - free(btype->fieldnames); - } + if (btype->fieldnames) { + free(btype->fieldnames); + } } static void free_bfield_inner(BlendField *bfield) { - if (bfield->field_bytes) { - free(bfield->field_bytes); - } + if (bfield->field_bytes) { + free(bfield->field_bytes); + } - if (bfield->field_offsets) { - free(bfield->field_offsets); - } + if (bfield->field_offsets) { + free(bfield->field_offsets); + } } static void free_bblock_inner(BlendBlock *bblock) { - int i; - - for (i=0; iarray_entries_count; ++i) { - free_bfield_inner(&bblock->array_entries[i]); - } - free(bblock->array_entries); + int i; + + for (i=0; iarray_entries_count; ++i) { + free_bfield_inner(&bblock->array_entries[i]); + } + free(bblock->array_entries); } void blend_free(BlendFile* blend_file) { - int i; + int i; - for (i=0; itypes_count; ++i) { - free_btype_inner(&blend_file->types[i]); - } - if (blend_file->types) { - free(blend_file->types); - } + for (i=0; itypes_count; ++i) { + free_btype_inner(&blend_file->types[i]); + } + if (blend_file->types) { + free(blend_file->types); + } - for (i=0; inames_count; ++i) { - if (blend_file->names[i]) { - free(blend_file->names[i]); - } else { - dprintf(stderr, "null name.\n"); - } - } - if (blend_file->names) { - free(blend_file->names); - } + for (i=0; inames_count; ++i) { + if (blend_file->names[i]) { + free(blend_file->names[i]); + } else { + dprintf(stderr, "null name.\n"); + } + } + if (blend_file->names) { + free(blend_file->names); + } - for (i=0; iblocks_count; ++i) { - free_bblock_inner(&blend_file->blocks[i]); - } - if (blend_file->blocks) { - free(blend_file->blocks); - } + for (i=0; iblocks_count; ++i) { + free_bblock_inner(&blend_file->blocks[i]); + } + if (blend_file->blocks) { + free(blend_file->blocks); + } - if (blend_file->strc_indices) { - free(blend_file->strc_indices); - } + if (blend_file->strc_indices) { + free(blend_file->strc_indices); + } - free(blend_file); + free(blend_file); } /******************************************************************** - * done with the reading/parsing logic; now for the querying logic * - ********************************************************************/ - +* done with the reading/parsing logic; now for the querying logic * +********************************************************************/ + /******************************************************************** - * LOW-LEVEL * - ********************************************************************/ +* LOW-LEVEL * +********************************************************************/ const char* blend_block_get_tagname(BlendFile* blend_file, - BlendBlockPointer block) + BlendBlockPointer block) { - const BlendBlock *const bb = block; - return bb->tag; + const BlendBlock *const bb = block; + return bb->tag; } const char* blend_block_get_typename(BlendFile* blend_file, - BlendBlockPointer block) + BlendBlockPointer block) { - const BlendBlock *const bb = block; - return blend_file->types[bb->type_index].name; + const BlendBlock *const bb = block; + return blend_file->types[bb->type_index].name; } int blend_block_get_entry_count(BlendFile* blend_file, - BlendBlockPointer block) + BlendBlockPointer block) { - const BlendBlock *const bb = block; - return bb->array_entries_count;; + const BlendBlock *const bb = block; + return bb->array_entries_count;; } void blend_foreach_block(BlendFile* blend_file, - BlendBlockCallback* func, - void* userdata) + BlendBlockCallback* func, + void* userdata) { - int i; - for (i=0; iblocks_count; ++i) { - if (!func(&blend_file->blocks[i], blend_file, userdata)) return; - } + int i; + for (i=0; iblocks_count; ++i) { + if (!func(&blend_file->blocks[i], blend_file, userdata)) return; + } } static int blend_type_basename_compare(const char *fancy, const char *raw) { - const int flen = strlen(fancy); - const int rlen = strlen(raw); - int i, strcmp_result = 123; + const int flen = strlen(fancy); + const int rlen = strlen(raw); + int i, strcmp_result = 123; - i = 0; - while (i < flen && (fancy[i]=='*' || fancy[i]=='(')) { - ++i; - } + i = 0; + while (i < flen && (fancy[i]=='*' || fancy[i]=='(')) { + ++i; + } - strcmp_result = strncmp(&fancy[i], raw, rlen); + strcmp_result = strncmp(&fancy[i], raw, rlen); - if (strcmp_result == 0 && flen > rlen+i) { - i = rlen + i; - if (fancy[i] != ')' && fancy[i] != '(' && fancy[i] != '[') { - strcmp_result = -1; - } - } + if (strcmp_result == 0 && flen > rlen+i) { + i = rlen + i; + if (fancy[i] != ')' && fancy[i] != '(' && fancy[i] != '[') { + strcmp_result = -1; + } + } - return strcmp_result; + return strcmp_result; } static BlendObjType typestring_to_blendobj_type(BlendFile* blend_file, - const char* type_name) { - if (blend_type_basename_compare(type_name, "char") == 0) { - return BLEND_OBJ_CHAR8; - } else if (blend_type_basename_compare(type_name, "uchar") == 0) { - return BLEND_OBJ_UCHAR8; - } else if (blend_type_basename_compare(type_name, "short") == 0) { - return BLEND_OBJ_SHORT16; - } else if (blend_type_basename_compare(type_name, "ushort") == 0) { - return BLEND_OBJ_USHORT16; - } else if (blend_type_basename_compare(type_name, "int") == 0) { - return BLEND_OBJ_LONG32; - } else if (blend_type_basename_compare(type_name, "long") == 0) { - return BLEND_OBJ_LONG32; - } else if (blend_type_basename_compare(type_name, "ulong") == 0) { - return BLEND_OBJ_ULONG32; - } else if (blend_type_basename_compare(type_name, "float") == 0) { - return BLEND_OBJ_FLOAT; - } else if (blend_type_basename_compare(type_name, "double") == 0) { - return BLEND_OBJ_DOUBLE; - } else if (blend_type_basename_compare(type_name, "void") == 0) { - return BLEND_OBJ_OPAQUE; - } else { - return BLEND_OBJ_STRUCT; /* structure */ - } + const char* type_name) +{ + if (blend_type_basename_compare(type_name, "char") == 0) { + return BLEND_OBJ_CHAR8; + } else if (blend_type_basename_compare(type_name, "uchar") == 0) { + return BLEND_OBJ_UCHAR8; + } else if (blend_type_basename_compare(type_name, "short") == 0) { + return BLEND_OBJ_SHORT16; + } else if (blend_type_basename_compare(type_name, "ushort") == 0) { + return BLEND_OBJ_USHORT16; + } else if (blend_type_basename_compare(type_name, "int") == 0) { + return BLEND_OBJ_LONG32; + } else if (blend_type_basename_compare(type_name, "long") == 0) { + return BLEND_OBJ_LONG32; + } else if (blend_type_basename_compare(type_name, "ulong") == 0) { + return BLEND_OBJ_ULONG32; + } else if (blend_type_basename_compare(type_name, "float") == 0) { + return BLEND_OBJ_FLOAT; + } else if (blend_type_basename_compare(type_name, "double") == 0) { + return BLEND_OBJ_DOUBLE; + } else if (blend_type_basename_compare(type_name, "void") == 0) { + return BLEND_OBJ_OPAQUE; + } else { + return BLEND_OBJ_STRUCT; /* structure */ + } } static BlendObjType typelong_to_blendobj_type(BlendFile* blend_file, - long btype, long bname) + long btype, long bname) { - if (name_is_pointer(blend_file->names[bname])) { - return BLEND_OBJ_POINTER; - } else if (blend_file->types[btype].is_struct) { - return BLEND_OBJ_STRUCT; - } else { - return typestring_to_blendobj_type(blend_file, - blend_file->types[btype].name); - } + if (name_is_pointer(blend_file->names[bname])) { + return BLEND_OBJ_POINTER; + } else if (blend_file->types[btype].is_struct) { + return BLEND_OBJ_STRUCT; + } else { + return typestring_to_blendobj_type(blend_file, + blend_file->types[btype].name); + } } BlendObjType blend_object_type(BlendFile* blend_file, - BlendObject obj) { - return typelong_to_blendobj_type(blend_file, - obj.type, - obj.name); + BlendObject obj) { + return typelong_to_blendobj_type(blend_file, + obj.type, + obj.name); } BlendBlockPointer blend_block_from_blendpointer(BlendFile *blend_file, - uint32_t blendpointer) + uint32_t blendpointer) { - int i; + int i; - /* fprintf(stderr, "%04x: ", blendpointer);*/ + /* fprintf(stderr, "%04x: ", blendpointer);*/ - if (blendpointer != 0) { - for (i=0; iblocks_count; ++i) { - /*fprintf(stderr, "%04x? ", blend_file->blocks[i].blender_pointer); */ - if (blend_file->blocks[i].blender_pointer == blendpointer) { - return &blend_file->blocks[i]; - } - } - } + if (blendpointer != 0) { + for (i=0; iblocks_count; ++i) { + /*fprintf(stderr, "%04x? ", blend_file->blocks[i].blender_pointer); */ + if (blend_file->blocks[i].blender_pointer == blendpointer) { + return &blend_file->blocks[i]; + } + } + } - return NULL; + return NULL; } static BlendBlockPointer blend_block_from_object(BlendFile *blend_file, - BlendObject *obj) { - return obj->block; + BlendObject *obj) { + return obj->block; } int blend_object_array_getdata(BlendFile* blend_file, - void* dest, BlendObject obj, - int dim_index_1, int dim_index_2) + void* dest, BlendObject obj, + int dim_index_1, int dim_index_2) { - const char* type_name = blend_file->types[obj.type].name; - const BlendBlock *const bb = obj.block; - BlendField *bf = &bb->array_entries[obj.entry_index]; - void* data; - int dim1, dim2; + const char* type_name = blend_file->types[obj.type].name; + const BlendBlock *const bb = obj.block; + BlendField *bf = &bb->array_entries[obj.entry_index]; + void* data; + int dim1, dim2; - name_is_array(blend_file->names[obj.name], &dim1, &dim2); - /*dprintf(stderr, "copying:'%s'[%d][%d] (of [%d][%d]) ", type_name, dim_index_1, dim_index_2, dim1, dim2);*/ + if (!bf) + return 0; - if (dim_index_1 >= dim1 || - dim_index_2 >= dim2) { - dprintf(stderr, "Array index (%d,%d) out of bounds for dimensionality [%d][%d]\n", dim_index_1, dim_index_2, dim1, dim2); - return 0; - } + name_is_array(blend_file->names[obj.name], &dim1, &dim2); + /*dprintf(stderr, "copying:'%s'[%d][%d] (of [%d][%d]) ", type_name, dim_index_1, dim_index_2, dim1, dim2);*/ - data = &bf->field_bytes[bf->field_offsets[obj.field_index + - dim2*dim_index_1 + dim_index_2]]; - /*dprintf(stderr, "fi[%d]byteo[%d]", obj.field_index, - bf->field_offsets[obj.field_index + - dim2*dim_index_1 + dim_index_2]);*/ + if (dim_index_1 >= dim1 || + dim_index_2 >= dim2) { + dprintf(stderr, "Array index (%d,%d) out of bounds for dimensionality [%d][%d]\n", dim_index_1, dim_index_2, dim1, dim2); + return 0; + } - if (name_is_pointer(blend_file->names[obj.name])) { - *(BlendBlockPointer*)dest = - blend_block_from_blendpointer(blend_file, - BGETLEUINT32(data)); - return 1; - } + data = &bf->field_bytes[bf->field_offsets[obj.field_index + + dim2*dim_index_1 + dim_index_2]]; + /*dprintf(stderr, "fi[%d]byteo[%d]", obj.field_index, + bf->field_offsets[obj.field_index + + dim2*dim_index_1 + dim_index_2]);*/ - /* FIXME: might be a good idea to do less-crappy word-size conversions - here -- these might read beyond the end of malloc'd blocks if we - ever change our field-padding policy. There were endian problems - too; these are believed fixed now. */ - /* The signed conversions look strange because they have to sign-expand - negative results without relying on right-shifts which have undefined - behaviour on negative data according to ANSI C. */ - if (blend_type_basename_compare(type_name, "char") == 0) { - *(char*)dest = (*(char*)data) << (8*sizeof(char)-8) / (1<<(8*sizeof(char)-8)); - } else if (blend_type_basename_compare(type_name, "uchar") == 0) { - *(unsigned char*)dest = *(unsigned char*)data; - } else if (blend_type_basename_compare(type_name, "short") == 0) { - *(int16_t*)dest = BGETLEINT16(data) << (8*sizeof(int16_t)-16) / (1<<(8*sizeof(int16_t)-16)); - } else if (blend_type_basename_compare(type_name, "ushort") == 0) { - *(uint16_t*)dest = BGETLEUINT16(data); - } else if (blend_type_basename_compare(type_name, "int") == 0) { - *(int32_t*)dest = BGETLEINT32(data) << (8*sizeof(int32_t)-32) / (1<<(8*sizeof(int32_t)-32)); - } else if (blend_type_basename_compare(type_name, "long") == 0) { - *(int32_t*)dest = BGETLEINT32(data) << (8*sizeof(int32_t)-32) / (1<<(8*sizeof(int32_t)-32)); - } else if (blend_type_basename_compare(type_name, "ulong") == 0) { - *(uint32_t*)dest = BGETLEUINT32(data); - } else if (blend_type_basename_compare(type_name, "float") == 0) { - *(float*)dest = BGETLEFLOAT32(data); - /*fprintf(stderr, "GOT{%f'%f} ", *(float*)dest, *(float*)data);*/ - } else if (blend_type_basename_compare(type_name, "double") == 0) { - *(double*)dest = BGETLEDOUBLE64(data); - } else if (blend_type_basename_compare(type_name, "void") == 0) { - dprintf(stderr, "Tried to fetch a void.\n"); - return 0; - } else { - dprintf(stderr, "Tried to fetch a whole structure.\n"); - return 0; - } - return 1; /* success */ + if (name_is_pointer(blend_file->names[obj.name])) { + *(BlendBlockPointer*)dest = + blend_block_from_blendpointer(blend_file, + BGETLEUINT32(data)); + return 1; + } + + /* FIXME: might be a good idea to do less-crappy word-size conversions + here -- these might read beyond the end of malloc'd blocks if we + ever change our field-padding policy. There were endian problems + too; these are believed fixed now. */ + /* The signed conversions look strange because they have to sign-expand + negative results without relying on right-shifts which have undefined + behaviour on negative data according to ANSI C. */ + if (blend_type_basename_compare(type_name, "char") == 0) { + *(char*)dest = (*(char*)data) << (8*sizeof(char)-8) / (1<<(8*sizeof(char)-8)); + } else if (blend_type_basename_compare(type_name, "uchar") == 0) { + *(unsigned char*)dest = *(unsigned char*)data; + } else if (blend_type_basename_compare(type_name, "short") == 0) { + *(int16_t*)dest = BGETLEINT16(data) << (8*sizeof(int16_t)-16) / (1<<(8*sizeof(int16_t)-16)); + } else if (blend_type_basename_compare(type_name, "ushort") == 0) { + *(uint16_t*)dest = BGETLEUINT16(data); + } else if (blend_type_basename_compare(type_name, "int") == 0) { + *(int32_t*)dest = BGETLEINT32(data) << (8*sizeof(int32_t)-32) / (1<<(8*sizeof(int32_t)-32)); + } else if (blend_type_basename_compare(type_name, "long") == 0) { + *(int32_t*)dest = BGETLEINT32(data) << (8*sizeof(int32_t)-32) / (1<<(8*sizeof(int32_t)-32)); + } else if (blend_type_basename_compare(type_name, "ulong") == 0) { + *(uint32_t*)dest = BGETLEUINT32(data); + } else if (blend_type_basename_compare(type_name, "float") == 0) { + *(float*)dest = BGETLEFLOAT32(data); + /*fprintf(stderr, "GOT{%f'%f} ", *(float*)dest, *(float*)data);*/ + } else if (blend_type_basename_compare(type_name, "double") == 0) { + *(double*)dest = BGETLEDOUBLE64(data); + } else if (blend_type_basename_compare(type_name, "void") == 0) { + dprintf(stderr, "Tried to fetch a void.\n"); + return 0; + } else { + dprintf(stderr, "Tried to fetch a whole structure.\n"); + return 0; + } + return 1; /* success */ } int blend_object_getdata(BlendFile* blend_file, - void* dest, BlendObject obj) + void* dest, BlendObject obj) { - int dim1, dim2; + int dim1, dim2; - if (name_is_array(blend_file->names[obj.name], &dim1, &dim2)) { - if (dim1 != 1 || dim2 != 1) { - dprintf(stderr, "Tried to fetch a whole array.\n"); - return 0; - } - } + if (name_is_array(blend_file->names[obj.name], &dim1, &dim2)) { + if (dim1 != 1 || dim2 != 1) { + dprintf(stderr, "Tried to fetch a whole array.\n"); + return 0; + } + } - return (blend_object_array_getdata(blend_file, dest, obj, 0, 0)); + return (blend_object_array_getdata(blend_file, dest, obj, 0, 0)); } /* recursively count the number of fields and array items in this - structure, for the purposes of skipping in the field offset array */ +structure, for the purposes of skipping in the field offset array */ static long get_num_type_segments(BlendFile* blend_file, - BlendObject obj) + BlendObject obj) { - int i; - long rtn = 0; - int dim1,dim2; + int i; + long rtn = 0; + int dim1,dim2; - name_is_array(blend_file->names[obj.name], + name_is_array(blend_file->names[obj.name], &dim1, &dim2); - if (name_is_pointer(blend_file->names[obj.name]) || - !blend_file->types[obj.type].is_struct) { - return (1 * dim1 * dim2); - } + if (name_is_pointer(blend_file->names[obj.name]) || + !blend_file->types[obj.type].is_struct) { + return (1 * dim1 * dim2); + } - /* fprintf(stderr, "STRUCTYAYYY ");*/ + /* fprintf(stderr, "STRUCTYAYYY ");*/ - for (i=0; itypes[obj.type].fieldnames_count; ++i) { - BlendObject qo = obj; - qo.type = blend_file->types[obj.type].fieldtypes[i]; - qo.name = blend_file->types[obj.type].fieldnames[i]; - qo.field_index = i; - rtn += get_num_type_segments(blend_file, qo) * dim1 * dim2; - } + for (i=0; itypes[obj.type].fieldnames_count; ++i) { + BlendObject qo = obj; + qo.type = blend_file->types[obj.type].fieldtypes[i]; + qo.name = blend_file->types[obj.type].fieldnames[i]; + qo.field_index = i; + rtn += get_num_type_segments(blend_file, qo) * dim1 * dim2; + } - return (rtn); + return (rtn); } int blend_object_structure_getfield(BlendFile* blend_file, - BlendObject *result, - BlendObject obj, - const char* field_name) + BlendObject *result, + BlendObject obj, + const char* field_name) { - if (blend_file->types[obj.type].is_struct) { - int i; - int field_index = 0; - for (i=0; itypes[obj.type].fieldnames_count; ++i) { - if (blend_type_basename_compare( - blend_file->names[blend_file->types[obj.type].fieldnames[i]], - field_name) - == 0) { - result->type = blend_file->types[obj.type].fieldtypes[i]; - result->name = blend_file->types[obj.type].fieldnames[i]; - result->block = obj.block; - result->entry_index = obj.entry_index; - result->field_index = field_index; - return 1; - } + if (blend_file->types[obj.type].is_struct) { + int i; + int field_index = 0; + for (i=0; itypes[obj.type].fieldnames_count; ++i) { + if (blend_type_basename_compare( + blend_file->names[blend_file->types[obj.type].fieldnames[i]], + field_name) + == 0) { + result->type = blend_file->types[obj.type].fieldtypes[i]; + result->name = blend_file->types[obj.type].fieldnames[i]; + result->block = obj.block; + result->entry_index = obj.entry_index; + result->field_index = field_index; + return 1; + } - { - BlendObject qo = obj; - int fos; - qo.type = blend_file->types[obj.type].fieldtypes[i]; - qo.name = blend_file->types[obj.type].fieldnames[i]; - qo.field_index = field_index; - fos = get_num_type_segments(blend_file, qo); - /*fprintf(stderr, ">>%s %s:%d ", - blend_file->types[qo.type].name, - blend_file->names[qo.name], fos);*/ - field_index += fos; - } - } - return 0; - } else { - dprintf(stderr, "Indexed object isn't a structure!\n"); - return 0; - } + { + BlendObject qo = obj; + int fos; + qo.type = blend_file->types[obj.type].fieldtypes[i]; + qo.name = blend_file->types[obj.type].fieldnames[i]; + qo.field_index = field_index; + fos = get_num_type_segments(blend_file, qo); + /*fprintf(stderr, ">>%s %s:%d ", + blend_file->types[qo.type].name, + blend_file->names[qo.name], fos);*/ + field_index += fos; + } + } + return 0; + } else { + dprintf(stderr, "Indexed object isn't a structure!\n"); + return 0; + } } void blend_object_array_getdims(BlendFile* blend_file, - BlendObject obj, - int* dim1, int* dim2) + BlendObject obj, + int* dim1, int* dim2) { - name_is_array(blend_file->names[obj.name], + name_is_array(blend_file->names[obj.name], dim1, dim2); } BlendObject blend_block_get_object(BlendFile* blend_file, - BlendBlockPointer block, - int entry_index) + BlendBlockPointer block, + int entry_index) { - BlendObject bo; - const BlendBlock *const bb = block; - /*BlendField *bf = &bb->array_entries[entry_index]; */ + BlendObject bo; + const BlendBlock *const bb = block; + /*BlendField *bf = &bb->array_entries[entry_index]; */ - bo.type = bb->type_index; - bo.name = blend_file->name_undef; - bo.block = block; - bo.entry_index = entry_index; - bo.field_index = 0; + bo.type = bb->type_index; + bo.name = blend_file->name_undef; + bo.block = block; + bo.entry_index = entry_index; + bo.field_index = 0; - return bo; + return bo; } - + /******************************************************************** - * MID-LEVEL * - ********************************************************************/ +* MID-LEVEL * +********************************************************************/ /* general helpers */ @@ -1100,44 +1176,44 @@ blend_block_get_object(BlendFile* blend_file, int blend_object_getstring(BlendFile* blend_file, - BlendObject obj, - char *dest, int max_chars) + BlendObject obj, + char *dest, int max_chars) { - int strpos = 0; - int dim1, dim2; - int rtn = 1; - BlendObjType bo_type; + int strpos = 0; + int dim1, dim2; + int rtn = 1; + BlendObjType bo_type; - name_is_array(blend_file->names[obj.name], + name_is_array(blend_file->names[obj.name], &dim1, &dim2); - if (dim2 < max_chars) { - max_chars = dim2; - } + if (dim2 < max_chars) { + max_chars = dim2; + } - bo_type = blend_object_type(blend_file, obj); - if (! (bo_type==BLEND_OBJ_CHAR8 || bo_type==BLEND_OBJ_UCHAR8)) { - dprintf(stderr, "tried to get string from an object that's not of type uchar/char. (is type %d)\n", bo_type); - rtn = 0; - goto done; - } - - for (strpos=0; strposIDname) { /* don't freak out, but hmm, do we do the right thing? */ - const int strl = strlen(ifd->IDname); - char *obj_string = malloc(3+ strl); - - for (i=0; iIDname) == 0) { - ifd->found = obj; - ifd->success = 1; - want_more = 0; - goto done; - } else { - /* next entry please. */ - } - } - - done:; - free(obj_string); - } + if (ifd->IDname) { /* don't freak out, but hmm, do we do the right thing? */ + const int strl = strlen(ifd->IDname); + char *obj_string = malloc(3+ strl); - return want_more; + for (i=0; iIDname) == 0) { + ifd->found = obj; + ifd->success = 1; + want_more = 0; + goto done; + } else { + /* next entry please. */ + } + } + +done:; + free(obj_string); + } + + return want_more; } int blend_object_get_by_IDname(BlendFile* blend_file, - BlendObject *result, - const char* IDname) + BlendObject *result, + const char* IDname) { - IDFinderData ifd; + IDFinderData ifd; - ifd.success = 0; - ifd.IDname = IDname; - ifd.just_print_it = 0; + ifd.success = 0; + ifd.IDname = IDname; + ifd.just_print_it = 0; - blend_foreach_block(blend_file, block_ID_finder, &ifd); + blend_foreach_block(blend_file, block_ID_finder, &ifd); - if (!ifd.success) { - return 0; - } + if (!ifd.success) { + return 0; + } - *result = ifd.found; - return 1; + *result = ifd.found; + return 1; } void blend_dump_typedefs(BlendFile* bf) { - int i; + int i; - /* dump out display of types and their sizes */ - for (i=0; itypes_count; ++i) { - /* if (!bf->types[i].is_struct)*/ - { - printf("%3d: sizeof(%s%s)=%d", - i, - bf->types[i].is_struct ? "struct " : "atomic ", - bf->types[i].name, bf->types[i].size); - if (bf->types[i].is_struct) { - int j; - printf(", %d fields: { ", bf->types[i].fieldtypes_count); - for (j=0; jtypes[i].fieldtypes_count; ++j) { - printf("%s %s", - bf->types[bf->types[i].fieldtypes[j]].name, - bf->names[bf->types[i].fieldnames[j]]); - if (j == bf->types[i].fieldtypes_count-1) { - printf("; }\n"); - } else { - printf("; "); - } + /* dump out display of types and their sizes */ + for (i=0; itypes_count; ++i) { + /* if (!bf->types[i].is_struct)*/ + { + printf("%3d: sizeof(%s%s)=%d", + i, + bf->types[i].is_struct ? "struct " : "atomic ", + bf->types[i].name, bf->types[i].size); + if (bf->types[i].is_struct) { + int j; + printf(", %d fields: { ", bf->types[i].fieldtypes_count); + for (j=0; jtypes[i].fieldtypes_count; ++j) { + printf("%s %s", + bf->types[bf->types[i].fieldtypes[j]].name, + bf->names[bf->types[i].fieldnames[j]]); + if (j == bf->types[i].fieldtypes_count-1) { + printf(";}"); + } else { + printf("; "); + } + } + } + printf("\n\n"); + + } } - } - - } - } } void blend_dump_blocks(BlendFile* bf) { - int i; - IDFinderData ifd; + int i; + IDFinderData ifd; - ifd.success = 0; - ifd.IDname = NULL; - ifd.just_print_it = 1; + ifd.success = 0; + ifd.IDname = NULL; + ifd.just_print_it = 1; - for (i=0; iblocks_count; ++i) { - BlendBlock* bb = &bf->blocks[i]; - printf("tag='%s'\tptr=%p\ttype=%s\t[%4d]", - bb->tag, /*bb->blender_pointer,*/ bb, - bf->types[bb->type_index].name, - bb->array_entries_count); - block_ID_finder(bb, bf, &ifd); - printf("\n"); - } + for (i=0; iblocks_count; ++i) { + BlendBlock* bb = &bf->blocks[i]; + printf("tag='%s'\tptr=%p\ttype=%s\t[%4d]", + bb->tag, /*bb->blender_pointer,*/ bb, + bf->types[bb->type_index].name, + bb->array_entries_count); + block_ID_finder(bb, bf, &ifd); + printf("\n"); + } } int blend_obj_is_rootobject(BlendFile *bf, BlendObject *objobj) { - BlendObject obj; - BlendBlockPointer block; - if ((blend_object_structure_getfield(bf, &obj, *objobj, "parent") && - blend_object_getdata(bf, &block, obj))) { - return (block == NULL); - } - return 0; + BlendObject obj; + BlendBlockPointer block; + if ((blend_object_structure_getfield(bf, &obj, *objobj, "parent") && + blend_object_getdata(bf, &block, obj))) { + return (block == NULL); + } + return 0; } BlendLayerMask blend_obj_get_layermask(BlendFile *bf, BlendObject *objobj) { - BlendObject obj; - int32_t ldata; - if ((blend_object_structure_getfield(bf, &obj, *objobj, "lay") && - blend_object_getdata(bf, &ldata, obj))) { - return (BlendLayerMask) ldata; - } - return 0; + BlendObject obj; + int32_t ldata; + if ((blend_object_structure_getfield(bf, &obj, *objobj, "lay") && + blend_object_getdata(bf, &ldata, obj))) { + return (BlendLayerMask) ldata; + } + return 0; } /* Bizarrely, blender doesn't seem to carry a mapping of parent - to children -- only of children to parent. So, to find the children - of an Object we have to scan all objects to see if their parent is - the Object in question. */ +to children -- only of children to parent. So, to find the children +of an Object we have to scan all objects to see if their parent is +the Object in question. */ typedef struct { - BlendBlockPointer wanted_parent; - BlendBlockPointer child; - int just_counting; - int num_so_far; - int wanted_index; + BlendBlockPointer wanted_parent; + BlendBlockPointer child; + int just_counting; + int num_so_far; + int wanted_index; } childfinderData; static BLENDBLOCKCALLBACK_RETURN block_childfinder(BLENDBLOCKCALLBACK_ARGS) { - childfinderData *cfd = (childfinderData *)userdata; - const char *tagname = blend_block_get_typename(blend_file, block); - int entry_count = blend_block_get_entry_count(blend_file, block); - int want_more = 1; - int i; + childfinderData *cfd = (childfinderData *)userdata; + const char *tagname = blend_block_get_typename(blend_file, block); + int entry_count = blend_block_get_entry_count(blend_file, block); + int want_more = 1; + int i; - if (strcmp(tagname, "Object") == 0) { - /* Is Object */ - for (i=0; iwanted_parent) { - if ((cfd->num_so_far == cfd->wanted_index) && - !cfd->just_counting) { - cfd->child = block; - want_more = 0; - } - ++cfd->num_so_far; - } else { - cfd->child = NULL; - } - } - } - } + if (strcmp(tagname, "Object") == 0) { + /* Is Object */ + for (i=0; iwanted_parent) { + if ((cfd->num_so_far == cfd->wanted_index) && + !cfd->just_counting) { + cfd->child = block; + want_more = 0; + } + ++cfd->num_so_far; + } else { + cfd->child = NULL; + } + } + } + } - return want_more; + return want_more; } int blend_obj_get_childcount(BlendFile *bf, BlendObject *objobj) { - childfinderData cfd; - cfd.wanted_parent = blend_block_from_object(bf, objobj); - cfd.child = NULL; - cfd.just_counting = 1; - cfd.num_so_far = 0; - cfd.wanted_index = 0; - blend_foreach_block(bf, block_childfinder, &cfd); - return cfd.num_so_far; + childfinderData cfd; + cfd.wanted_parent = blend_block_from_object(bf, objobj); + cfd.child = NULL; + cfd.just_counting = 1; + cfd.num_so_far = 0; + cfd.wanted_index = 0; + blend_foreach_block(bf, block_childfinder, &cfd); + return cfd.num_so_far; } BlendBlockPointer blend_obj_get_child(BlendFile *bf, BlendObject *objobj, int childnum) { - childfinderData cfd; - cfd.wanted_parent = blend_block_from_object(bf, objobj); - cfd.child = NULL; - cfd.just_counting = 0; - cfd.num_so_far = 0; - cfd.wanted_index = childnum; - blend_foreach_block(bf, block_childfinder, &cfd); - return cfd.child; + childfinderData cfd; + cfd.wanted_parent = blend_block_from_object(bf, objobj); + cfd.child = NULL; + cfd.just_counting = 0; + cfd.num_so_far = 0; + cfd.wanted_index = childnum; + blend_foreach_block(bf, block_childfinder, &cfd); + return cfd.child; } /******************************************************************** - * HIGH-LEVEL * - ********************************************************************/ +* HIGH-LEVEL * +********************************************************************/ #ifndef LEN3POW2 /* length squared */ @@ -1410,911 +1488,1231 @@ blend_obj_get_child(BlendFile *bf, BlendObject *objobj, int childnum) { #ifndef NORMALIZE3 /* vector normalization (expensive) */ #define NORMALIZE3(xd,yd,zd) \ -do { \ - const double norm3_macro_len3 = LEN3((xd),(yd),(zd)); \ - if (norm3_macro_len3 != 0.0F) \ - { \ - (xd) = (xd) / norm3_macro_len3; \ - (yd) = (yd) / norm3_macro_len3; \ - (zd) = (zd) / norm3_macro_len3; \ - } \ -} while (0) + do { \ + const double norm3_macro_len3 = LEN3((xd),(yd),(zd)); \ + if (norm3_macro_len3 != 0.0F) \ +{ \ + (xd) = (xd) / norm3_macro_len3; \ + (yd) = (yd) / norm3_macro_len3; \ + (zd) = (zd) / norm3_macro_len3; \ +} \ + } while (0) #endif static void bMatIdentity(bMatrix mat) { - int i,j; - for (i=0; i<4; ++i) { - for (j=0; j<4; ++j) { - mat[i][j] = 0.0f; - } - mat[i][i] = 1.0f; - } + int i,j; + for (i=0; i<4; ++i) { + for (j=0; j<4; ++j) { + mat[i][j] = 0.0f; + } + mat[i][i] = 1.0f; + } } static void bMatMultVec(float xyz[3], bMatrix mat) { - int i; - float r[3]; - for (i=0; i<3; ++i) { - r[i] = 0.0f; - } - for (i=0; i<3; ++i) { - r[i] += xyz[0] * mat[0][i]; - r[i] += xyz[1] * mat[1][i]; - r[i] += xyz[2] * mat[2][i]; - r[i] += 1.0f * mat[3][i]; - } - for (i=0; i<3; ++i) { - xyz[i] = r[i]; - } + int i; + float r[3]; + for (i=0; i<3; ++i) { + r[i] = 0.0f; + } + for (i=0; i<3; ++i) { + r[i] += xyz[0] * mat[0][i]; + r[i] += xyz[1] * mat[1][i]; + r[i] += xyz[2] * mat[2][i]; + r[i] += 1.0f * mat[3][i]; + } + for (i=0; i<3; ++i) { + xyz[i] = r[i]; + } } bMesh *blend_alloc_mesh(void) { - return malloc(sizeof(bMesh)); + return malloc(sizeof(bMesh)); } void blend_init_mesh(bMesh *mesh) { - int i,j; - mesh->vert = NULL; - mesh->vert_count = 0; - mesh->face = NULL; - mesh->face_count = 0; - mesh->material = NULL; + int i,j; + mesh->vert = NULL; + mesh->vert_count = 0; + mesh->face = NULL; + mesh->face_count = 0; + mesh->material = NULL; } void blend_free_mesh_inner(bMesh *mesh) { - if (mesh->vert) { - free(mesh->vert); - } - if (mesh->face) { - free(mesh->face); - } - if (mesh->material) { - blend_free_material(mesh->material); - } + if (mesh->vert) { + free(mesh->vert); + } + if (mesh->face) { + free(mesh->face); + } + if (mesh->material) { + blend_free_material(mesh->material); + } } void blend_free_mesh(bMesh *mesh) { - blend_free_mesh_inner(mesh); - free(mesh); + blend_free_mesh_inner(mesh); + free(mesh); } bObj * blend_alloc_obj(void) { - return malloc(sizeof(bObj)); + return malloc(sizeof(bObj)); } void blend_init_obj(bObj *obj) { - obj->type = BOBJ_TYPE_UNKNOWN; - obj->name = NULL; - bMatIdentity(obj->transform); - bMatIdentity(obj->parentimat); - obj->location[0] = - obj->location[1] = - obj->location[2] = 0.0f; - obj->scaling[0] = - obj->scaling[1] = - obj->scaling[2] = 1.0f; - obj->rotphr[0] = - obj->rotphr[1] = - obj->rotphr[2] = 0.0f; - obj->data.dummy = NULL; - obj->transflags = 0; + obj->type = BOBJ_TYPE_UNKNOWN; + obj->name = NULL; + bMatIdentity(obj->transform); + bMatIdentity(obj->parentimat); + obj->location[0] = + obj->location[1] = + obj->location[2] = 0.0f; + obj->scaling[0] = + obj->scaling[1] = + obj->scaling[2] = 1.0f; + obj->rotphr[0] = + obj->rotphr[1] = + obj->rotphr[2] = 0.0f; + obj->data.dummy = NULL; + obj->transflags = 0; } void blend_free_obj_inner(bObj *obj) { - if (obj->name) { - free(obj->name); - } - switch (obj->type) { + if (obj->name) { + free(obj->name); + } + switch (obj->type) { case BOBJ_TYPE_MESH: - blend_free_mesh(obj->data.mesh); + blend_free_mesh(obj->data.mesh); case BOBJ_TYPE_UNKNOWN: case BOBJ_TYPE_NULL: default: - break; - } + break; + } } void blend_free_obj(bObj *obj) { - blend_free_obj_inner(obj); - free(obj); + blend_free_obj_inner(obj); + free(obj); } void blend_acquire_obj_from_obj(BlendFile *bf, BlendObject *objobj, - bObj *outobj, BlendObject **mallocdoutblendobject) { - - BlendObject obj, dataobj; - BlendBlockPointer block; - short sdata = 12345; + bObj *outobj, BlendObject **mallocdoutblendobject) +{ + + BlendObject obj, dataobj; + BlendBlockPointer block,ipoblock,curveblock=0; + short sdata = 12345; + #define B_IDNAME_MAX_SIZE 80 - char *idname = malloc(1 + B_IDNAME_MAX_SIZE); - float fdata1, fdata2, fdata3; + char *idname = malloc(1 + B_IDNAME_MAX_SIZE); + float fdata1, fdata2, fdata3; - if (mallocdoutblendobject) *mallocdoutblendobject = NULL; + if (mallocdoutblendobject) *mallocdoutblendobject = NULL; - blend_init_obj(outobj); + blend_init_obj(outobj); - if (!(blend_object_structure_getfield(bf, &obj, *objobj, - "type") && - blend_object_getdata(bf, &sdata, obj))) { - abort(); /* couldn't get type */ - } else { - switch (sdata) { - case 1: /* mesh */ - outobj->type = BOBJ_TYPE_MESH; break; - case 10: /* lamp */ - case 11: /* camera */ - default: - outobj->type = BOBJ_TYPE_UNKNOWN; break; - } - } - - if (blend_object_get_IDname(bf, *objobj, idname, B_IDNAME_MAX_SIZE)) { - outobj->name = idname; - } else { - free(idname); - abort(); /* couldn't get obj name */ - } - - /* now we override the mesh transform with the object's. should - we merge, instead??? - hm, dunno, don't think so. */ + if (!(blend_object_structure_getfield(bf, &obj, *objobj, + "type") && + blend_object_getdata(bf, &sdata, obj))) + { + abort(); /* couldn't get type */ + } else { + switch (sdata) { + case 1: /* mesh */ + outobj->type = BOBJ_TYPE_MESH; break; + case 10: /* lamp */ + outobj->type = BOBJ_TYPE_LAMP; break; + case 11: /* camera */ + outobj->type = BOBJ_TYPE_CAMERA; break; + default: + outobj->type = BOBJ_TYPE_UNKNOWN; break; + } + } - if (blend_object_structure_getfield(bf, &obj, *objobj, "loc") && - blend_object_array_getdata(bf, &fdata1, obj, 0,0) && - blend_object_array_getdata(bf, &fdata2, obj, 0,1) && - blend_object_array_getdata(bf, &fdata3, obj, 0,2)) { - outobj->location[0] = fdata1; - outobj->location[1] = fdata2; - outobj->location[2] = fdata3; - } else { - outobj->location[0] = - outobj->location[1] = - outobj->location[2] = 0.0f; - } - - if (blend_object_structure_getfield(bf, &obj, *objobj, "size") && - blend_object_array_getdata(bf, &fdata1, obj, 0,0) && - blend_object_array_getdata(bf, &fdata2, obj, 0,1) && - blend_object_array_getdata(bf, &fdata3, obj, 0,2)) { - outobj->scaling[0] = fdata1; - outobj->scaling[1] = fdata2; - outobj->scaling[2] = fdata3; - } else { - outobj->scaling[0] = - outobj->scaling[1] = - outobj->scaling[2] = 1.0f; - } - - if (blend_object_structure_getfield(bf, &obj, *objobj, "rot") && - blend_object_array_getdata(bf, &fdata1, obj, 0,0) && - blend_object_array_getdata(bf, &fdata2, obj, 0,1) && - blend_object_array_getdata(bf, &fdata3, obj, 0,2)) { - outobj->rotphr[0] = fdata1; - outobj->rotphr[1] = fdata2; - outobj->rotphr[2] = fdata3; - } else { - outobj->rotphr[0] = - outobj->rotphr[1] = - outobj->rotphr[2] = 0.0f; - } + if (blend_object_get_IDname(bf, *objobj, idname, B_IDNAME_MAX_SIZE)) { + outobj->name = idname; + } else { + free(idname); + abort(); /* couldn't get obj name */ + } - if (blend_object_structure_getfield(bf, &obj, *objobj, "parentinv")) { - int i,j; - for (i=0; i<4; ++i) { - for (j=0; j<4; ++j) { - blend_object_array_getdata(bf, &fdata1, obj, i,j); - outobj->parentimat[i][j] = fdata1; - } - } - } - - if (blend_object_structure_getfield(bf, &obj, *objobj, "transflag")) { - char cdata; - /* TODO: decode what these flags precisely mean. */ - /* top bit is 'powertrack' */ - if (blend_object_getdata(bf, &cdata, obj)) { - outobj->transflags = (unsigned char)cdata; - } - } - - if (blend_object_structure_getfield(bf, &obj, *objobj, "obmat")) { - int i,j; - for (i=0; i<4; ++i) { - for (j=0; j<4; ++j) { - blend_object_array_getdata(bf, &fdata1, obj, i,j); - outobj->transform[i][j] = fdata1; - dprintf(stderr, "%0.3f ", fdata1); - } - dprintf(stderr, "\n"); - } - } - - /* get actual obj here */ - - if (! (blend_object_structure_getfield(bf, &obj, *objobj, "data") && - blend_object_getdata(bf, &block, obj))) { - abort(); - } - - if (block == NULL) { - outobj->type = BOBJ_TYPE_NULL; - } else { - dataobj = blend_block_get_object(bf, block, 0); - if (mallocdoutblendobject) { - *mallocdoutblendobject = malloc(sizeof(BlendObject)); - **mallocdoutblendobject = dataobj; - } - } + /* now we override the mesh transform with the object's. should + we merge, instead??? - hm, dunno, don't think so. */ - switch (outobj->type) { + if (blend_object_structure_getfield(bf, &obj, *objobj, "loc") && + blend_object_array_getdata(bf, &fdata1, obj, 0,0) && + blend_object_array_getdata(bf, &fdata2, obj, 0,1) && + blend_object_array_getdata(bf, &fdata3, obj, 0,2)) { + outobj->location[0] = fdata1; + outobj->location[1] = fdata2; + outobj->location[2] = fdata3; + } else { + outobj->location[0] = + outobj->location[1] = + outobj->location[2] = 0.0f; + } + + if (blend_object_structure_getfield(bf, &obj, *objobj, "size") && + blend_object_array_getdata(bf, &fdata1, obj, 0,0) && + blend_object_array_getdata(bf, &fdata2, obj, 0,1) && + blend_object_array_getdata(bf, &fdata3, obj, 0,2)) { + outobj->scaling[0] = fdata1; + outobj->scaling[1] = fdata2; + outobj->scaling[2] = fdata3; + } else { + outobj->scaling[0] = + outobj->scaling[1] = + outobj->scaling[2] = 1.0f; + } + + if (blend_object_structure_getfield(bf, &obj, *objobj, "rot") && + blend_object_array_getdata(bf, &fdata1, obj, 0,0) && + blend_object_array_getdata(bf, &fdata2, obj, 0,1) && + blend_object_array_getdata(bf, &fdata3, obj, 0,2)) { + outobj->rotphr[0] = fdata1; + outobj->rotphr[1] = fdata2; + outobj->rotphr[2] = fdata3; + } else { + outobj->rotphr[0] = + outobj->rotphr[1] = + outobj->rotphr[2] = 0.0f; + } + + if (blend_object_structure_getfield(bf, &obj, *objobj, "parentinv")) { + int i,j; + for (i=0; i<4; ++i) { + for (j=0; j<4; ++j) { + blend_object_array_getdata(bf, &fdata1, obj, i,j); + outobj->parentimat[i][j] = fdata1; + } + } + } +#if 0 + if (blend_object_structure_getfield(bf, &obj, *objobj, "transflag")) { + char cdata; + /* TODO: decode what these flags precisely mean. */ + /* top bit is 'powertrack' */ + if (blend_object_getdata(bf, &cdata, obj)) { + outobj->transflags = (unsigned char)cdata; + } + } +#endif + + outobj->mass = 0.f; + if (blend_object_structure_getfield(bf, &obj, *objobj, "mass")) + { + float mass; + if (blend_object_getdata(bf, &mass, obj)) + { + outobj->mass = mass; + } + } + + + if ((blend_object_structure_getfield(bf, &obj, *objobj,"ipo") && blend_object_getdata(bf, &ipoblock, obj))) + { + if (ipoblock) + { + BlendObject ipo = blend_block_get_object(bf, ipoblock, 0); +#define MAX_CHARS 31 + char iponame[MAX_CHARS]; + BlendObject obj2,obj3; + + blend_object_get_IDname(bf,ipo,iponame,MAX_CHARS-1); +// printf("ipo.ID.name = %s\n",iponame); + + if (blend_object_structure_getfield(bf, &obj2, ipo,"curve")) + { + BlendBlock* block = (BlendBlock*)obj2.block; + + + void** ptrptr = &block->array_entries->field_bytes[block->array_entries->field_offsets[obj2.field_index]]; + BlendBlockPointer ptr = *ptrptr; + //ptrptr++; contains the 'last' pointer + if (ptr) + { + BlendBlockPointer curveblockptr = blend_block_from_blendpointer(bf, ptr); + BlendObject curve = blend_block_get_object(bf, curveblockptr, 0); + + } + + } + + + } + } + + + + + outobj->boundtype = 0; + if (blend_object_structure_getfield(bf, &obj, *objobj, "boundtype")) + { + short int boundtype; + if (blend_object_getdata(bf, &boundtype, obj)) + { + outobj->boundtype= boundtype; + } + } + + outobj->gameflag = 0; + if (blend_object_structure_getfield(bf, &obj, *objobj, "gameflag")) + { + int gameflag; + if (blend_object_getdata(bf, &gameflag, obj)) + { + outobj->gameflag= gameflag; + } + } + + + + + if (blend_object_structure_getfield(bf, &obj, *objobj, "obmat")) { + int i,j; + for (i=0; i<4; ++i) { + for (j=0; j<4; ++j) { + blend_object_array_getdata(bf, &fdata1, obj, i,j); + outobj->transform[i][j] = fdata1; + dprintf(stderr, "%0.3f ", fdata1); + } + dprintf(stderr, "\n"); + } + } + + /* get actual mesh obj here */ + + if (! (blend_object_structure_getfield(bf, &obj, *objobj, "data") && + blend_object_getdata(bf, &block, obj))) + { + printf("no mesh\n"); + outobj->data.mesh = 0; + return; + //abort(); + } + + if (block == NULL) { + outobj->type = BOBJ_TYPE_NULL; + } else { + dataobj = blend_block_get_object(bf, block, 0); + if (mallocdoutblendobject) { + *mallocdoutblendobject = malloc(sizeof(BlendObject)); + **mallocdoutblendobject = dataobj; + } + } + + + switch (outobj->type) { case BOBJ_TYPE_MESH: - outobj->data.mesh = blend_alloc_mesh(); - blend_acquire_mesh_from_obj(bf, &dataobj, outobj->data.mesh); - break; + outobj->data.mesh = blend_alloc_mesh(); + blend_acquire_mesh_from_obj(bf, &dataobj, outobj->data.mesh); + break; case BOBJ_TYPE_UNKNOWN: default: case BOBJ_TYPE_NULL: - outobj->data.dummy = NULL; - break; - } + outobj->data.dummy = NULL; + break; + } + } bTexLayer * blend_alloc_texlayer(void) { - return malloc(sizeof(bTexLayer)); + return malloc(sizeof(bTexLayer)); } void blend_init_texlayer(bTexLayer *tl) { - tl->filename = NULL; - tl->affects_mask = 0; - tl->blend_mode = BTEX_BLEND_NORMAL; - tl->coords_type = BTEX_COORDS_NONE; - tl->is_st_clamped = 0; - tl->flags = 0; - tl->Nflags = tl->Ntype = 0; - tl->xrepeat = tl->yrepeat = 1; + tl->filename = NULL; + tl->affects_mask = 0; + tl->blend_mode = BTEX_BLEND_NORMAL; + tl->coords_type = BTEX_COORDS_NONE; + tl->is_st_clamped = 0; + tl->flags = 0; + tl->Nflags = tl->Ntype = 0; + tl->xrepeat = tl->yrepeat = 1; } static void blend_free_texlayer_inner(bTexLayer *tl) { - if (tl->filename) { - free(tl->filename); - } + if (tl->filename) { + free(tl->filename); + } } void blend_free_texlayer(bTexLayer *tl) { - blend_free_texlayer_inner(tl); - free(tl); + blend_free_texlayer_inner(tl); + free(tl); } void /* MTex */ blend_acquire_texlayer_from_obj(BlendFile *bf, BlendObject *tlobj, - bTexLayer *tl) { - BlendObject obj; - BlendBlockPointer tex_block; - short sdata = 12345; + bTexLayer *tl) +{ + BlendObject obj; + BlendBlockPointer tex_block; + short sdata = 12345; - blend_init_texlayer(tl); + blend_init_texlayer(tl); - if (!(blend_object_structure_getfield(bf, &obj, *tlobj, - "mapto") && - blend_object_getdata(bf, &sdata, obj))) { - abort(); - } - if (sdata & 0x01) { - tl->affects_mask |= BTEX_AFFECT_COLOUR; - } - if (sdata & 0x40) { - tl->affects_mask |= BTEX_AFFECT_EMIT; - } - if (sdata & 0x80) { - tl->affects_mask |= BTEX_AFFECT_ALPHA; - } - /* note: mapto not fully decoded. */ + if (!(blend_object_structure_getfield(bf, &obj, *tlobj, + "mapto") && + blend_object_getdata(bf, &sdata, obj))) { + abort(); + } + if (sdata & 0x01) { + tl->affects_mask |= BTEX_AFFECT_COLOUR; + } + if (sdata & 0x40) { + tl->affects_mask |= BTEX_AFFECT_EMIT; + } + if (sdata & 0x80) { + tl->affects_mask |= BTEX_AFFECT_ALPHA; + } + /* note: mapto not fully decoded. */ - if (!(blend_object_structure_getfield(bf, &obj, *tlobj, - "texflag") && - blend_object_getdata(bf, &sdata, obj))) { - abort(); - } - if (sdata & 0x02) { - tl->affects_mask |= BTEX_AFFECT_STENCIL; - } + if (!(blend_object_structure_getfield(bf, &obj, *tlobj, + "texflag") && + blend_object_getdata(bf, &sdata, obj))) { + abort(); + } + if (sdata & 0x02) { + tl->affects_mask |= BTEX_AFFECT_STENCIL; + } - if (!(blend_object_structure_getfield(bf, &obj, *tlobj, - "texco") && - blend_object_getdata(bf, &sdata, obj))) { - abort(); - } - switch (sdata) { + if (!(blend_object_structure_getfield(bf, &obj, *tlobj, + "texco") && + blend_object_getdata(bf, &sdata, obj))) { + abort(); + } + switch (sdata) { case 1: case 2: - tl->coords_type = BTEX_COORDS_REFLECT; - break; + tl->coords_type = BTEX_COORDS_REFLECT; + break; case 16: - tl->coords_type = BTEX_COORDS_UV; - break; + tl->coords_type = BTEX_COORDS_UV; + break; default: - /* I haven't seen this happen, but it probably does... */ - tl->coords_type = BTEX_COORDS_NONE; - break; - } + /* I haven't seen this happen, but it probably does... */ + tl->coords_type = BTEX_COORDS_NONE; + break; + } - if (!(blend_object_structure_getfield(bf, &obj, *tlobj, - "blendtype") && - blend_object_getdata(bf, &sdata, obj))) { - abort(); - } - tl->blend_mode = sdata; /* not decoded yet :( */ + if (!(blend_object_structure_getfield(bf, &obj, *tlobj, + "blendtype") && + blend_object_getdata(bf, &sdata, obj))) { + abort(); + } + tl->blend_mode = sdata; /* not decoded yet :( */ - if (blend_object_structure_getfield(bf, &obj, *tlobj, "tex") && - blend_object_getdata(bf, &tex_block, obj) && tex_block) { - BlendObject tobj = blend_block_get_object(bf, tex_block, 0); - BlendBlockPointer im_block; - BlendObject obj; - - if (!(blend_object_structure_getfield(bf, &obj, tobj, "extend") && - blend_object_getdata(bf, &sdata, obj))) { - abort(); - } - tl->is_st_clamped = !(sdata & 2 /*'repeat'*/); - /*fprintf(stderr, "CLAMP=%d (was %d)\n", tl->is_st_clamped, sdata);*/ - if (!(blend_object_structure_getfield(bf, &obj, tobj, "xrepeat") && - blend_object_getdata(bf, &sdata, obj))) { - tl->xrepeat = 1; - } else { - tl->xrepeat = sdata; - } - if (!(blend_object_structure_getfield(bf, &obj, tobj, "yrepeat") && - blend_object_getdata(bf, &sdata, obj))) { - tl->yrepeat = 1; - } else { - tl->yrepeat = sdata; - } - if (!(blend_object_structure_getfield(bf, &obj, tobj, "flag") && - blend_object_getdata(bf, &sdata, obj))) { - abort(); - } else { - tl->flags = sdata; - } - if (!(blend_object_structure_getfield(bf, &obj, tobj, "imaflag") && - blend_object_getdata(bf, &sdata, obj))) { - abort(); - } else { - if (sdata & 0x0001) { - tl->flags |= BIMG_FLAG_INTERPOLATE; - } - if (sdata & 0x0004) { - tl->flags |= BIMG_FLAG_MIPMAP; - } - if (sdata & 0x0100) { - tl->flags |= BIMG_FLAG_ANTIALIAS; - } - } - if (!(blend_object_structure_getfield(bf, &obj, tobj, "type") && - blend_object_getdata(bf, &sdata, obj))) { - abort(); - } else { - tl->Ntype = sdata; - } - if (blend_object_structure_getfield(bf, &obj, tobj, "ima") && - blend_object_getdata(bf, &im_block, obj) && im_block) { - BlendObject imobj = blend_block_get_object(bf, im_block, 0); + if (blend_object_structure_getfield(bf, &obj, *tlobj, "tex") && + blend_object_getdata(bf, &tex_block, obj) && tex_block) { + BlendObject tobj = blend_block_get_object(bf, tex_block, 0); + BlendBlockPointer im_block; + BlendObject obj; + + if (!(blend_object_structure_getfield(bf, &obj, tobj, "extend") && + blend_object_getdata(bf, &sdata, obj))) { + abort(); + } + tl->is_st_clamped = !(sdata & 2 /*'repeat'*/); + /*fprintf(stderr, "CLAMP=%d (was %d)\n", tl->is_st_clamped, sdata);*/ + if (!(blend_object_structure_getfield(bf, &obj, tobj, "xrepeat") && + blend_object_getdata(bf, &sdata, obj))) { + tl->xrepeat = 1; + } else { + tl->xrepeat = sdata; + } + if (!(blend_object_structure_getfield(bf, &obj, tobj, "yrepeat") && + blend_object_getdata(bf, &sdata, obj))) { + tl->yrepeat = 1; + } else { + tl->yrepeat = sdata; + } + if (!(blend_object_structure_getfield(bf, &obj, tobj, "flag") && + blend_object_getdata(bf, &sdata, obj))) { + abort(); + } else { + tl->flags = sdata; + } + if (!(blend_object_structure_getfield(bf, &obj, tobj, "imaflag") && + blend_object_getdata(bf, &sdata, obj))) { + abort(); + } else { + if (sdata & 0x0001) { + tl->flags |= BIMG_FLAG_INTERPOLATE; + } + if (sdata & 0x0004) { + tl->flags |= BIMG_FLAG_MIPMAP; + } + if (sdata & 0x0100) { + tl->flags |= BIMG_FLAG_ANTIALIAS; + } + } + if (!(blend_object_structure_getfield(bf, &obj, tobj, "type") && + blend_object_getdata(bf, &sdata, obj))) { + abort(); + } else { + tl->Ntype = sdata; + } + if (blend_object_structure_getfield(bf, &obj, tobj, "ima") && + blend_object_getdata(bf, &im_block, obj) && im_block) { + BlendObject imobj = blend_block_get_object(bf, im_block, 0); #define BF_IMAGE_FILENAME_MAXSIZE 160 - tl->filename = malloc(BF_IMAGE_FILENAME_MAXSIZE); - if (!(blend_object_structure_getfield(bf, &obj, imobj, "name") && - blend_object_getstring(bf, obj, - tl->filename, BF_IMAGE_FILENAME_MAXSIZE))) { - abort(); - } - } - } else { - abort(); - } + tl->filename = malloc(BF_IMAGE_FILENAME_MAXSIZE); + if (!(blend_object_structure_getfield(bf, &obj, imobj, "name") && + blend_object_getstring(bf, obj, + tl->filename, BF_IMAGE_FILENAME_MAXSIZE))) { + abort(); + } + } + } else { + abort(); + } } bMaterial * blend_alloc_material(void) { - return malloc(sizeof(bMaterial)); + return malloc(sizeof(bMaterial)); } void blend_init_material(bMaterial *mat) { - int i; - for (i=0; itex_layer[i] = NULL; - } - mat->feature_mask = 0; - for (i=0; i<4; ++i) { - mat->colour_rgba[i] = 1.0f; - } - mat->emit = 0.0f; + int i; + for (i=0; itex_layer[i] = NULL; + } + mat->feature_mask = 0; + for (i=0; i<4; ++i) { + mat->colour_rgba[i] = 1.0f; + } + mat->emit = 0.0f; } void blend_free_material(bMaterial *mat) { - int i; - for (i=0; itex_layer[i]) { - blend_free_texlayer(mat->tex_layer[i]); - } - } + int i; + for (i=0; itex_layer[i]) { + blend_free_texlayer(mat->tex_layer[i]); + } + } } void blend_acquire_material_from_obj(BlendFile *bf, BlendObject *matobj, - bMaterial *mat) { - BlendObject obj; - int i; - int32_t ldata = 123456; - float fdata = 123456.0; + bMaterial *mat) +{ + BlendObject obj; + int i; + int32_t ldata = 123456; + float fdata = 123456.0; - blend_init_material(mat); + blend_init_material(mat); - if ((blend_object_structure_getfield(bf, &obj, *matobj, "r") && - blend_object_getdata(bf, &fdata, obj))) { - mat->colour_rgba[0] = fdata; - } - if ((blend_object_structure_getfield(bf, &obj, *matobj, "g") && - blend_object_getdata(bf, &fdata, obj))) { - mat->colour_rgba[1] = fdata; - } - if ((blend_object_structure_getfield(bf, &obj, *matobj, "b") && - blend_object_getdata(bf, &fdata, obj))) { - mat->colour_rgba[2] = fdata; - } - if ((blend_object_structure_getfield(bf, &obj, *matobj, "alpha") && - blend_object_getdata(bf, &fdata, obj))) { - mat->colour_rgba[3] = fdata; - } - if ((blend_object_structure_getfield(bf, &obj, *matobj, "emit") && - blend_object_getdata(bf, &fdata, obj))) { - mat->emit = fdata; - } + if ((blend_object_structure_getfield(bf, &obj, *matobj, "r") && + blend_object_getdata(bf, &fdata, obj))) { + mat->colour_rgba[0] = fdata; + } + if ((blend_object_structure_getfield(bf, &obj, *matobj, "g") && + blend_object_getdata(bf, &fdata, obj))) { + mat->colour_rgba[1] = fdata; + } + if ((blend_object_structure_getfield(bf, &obj, *matobj, "b") && + blend_object_getdata(bf, &fdata, obj))) { + mat->colour_rgba[2] = fdata; + } + if ((blend_object_structure_getfield(bf, &obj, *matobj, "alpha") && + blend_object_getdata(bf, &fdata, obj))) { + mat->colour_rgba[3] = fdata; + } + if ((blend_object_structure_getfield(bf, &obj, *matobj, "emit") && + blend_object_getdata(bf, &fdata, obj))) { + mat->emit = fdata; + } - if (!(blend_object_structure_getfield(bf, &obj, *matobj, "mode") && - blend_object_getdata(bf, &ldata, obj))) { - abort(); - } - if (ldata & 0x04) { - mat->feature_mask |= BMAT_FEATURE_SHADELESS; - } - if (ldata & 0x08) { - mat->feature_mask |= BMAT_FEATURE_WIRE; - } - if (ldata & 0x10) { - mat->feature_mask |= BMAT_FEATURE_VCOLLIGHT; - } - if (ldata & 0x80) { - mat->feature_mask |= BMAT_FEATURE_VCOLPAINT; - } - if (ldata & (1024 | 512 | 256)) { /* not sure about this, it's strange. */ - mat->feature_mask |= BMAT_FEATURE_TEXFACE; - } + if (!(blend_object_structure_getfield(bf, &obj, *matobj, "mode") && + blend_object_getdata(bf, &ldata, obj))) { + abort(); + } + if (ldata & 0x04) { + mat->feature_mask |= BMAT_FEATURE_SHADELESS; + } + if (ldata & 0x08) { + mat->feature_mask |= BMAT_FEATURE_WIRE; + } + if (ldata & 0x10) { + mat->feature_mask |= BMAT_FEATURE_VCOLLIGHT; + } + if (ldata & 0x80) { + mat->feature_mask |= BMAT_FEATURE_VCOLPAINT; + } + if (ldata & (1024 | 512 | 256)) { /* not sure about this, it's strange. */ + mat->feature_mask |= BMAT_FEATURE_TEXFACE; + } - for (i=0; itex_layer[i] = blend_alloc_texlayer(); - /*fprintf(stderr, "GETTING LAYER AT POS %d\n", i);*/ - blend_acquire_texlayer_from_obj(bf, &tlobj, mat->tex_layer[i]); - } else { - /*fprintf(stderr, "NOTHING FOUND AT POS %d\n", i);*/ - } - } + for (i=0; itex_layer[i] = blend_alloc_texlayer(); + /*fprintf(stderr, "GETTING LAYER AT POS %d\n", i);*/ + blend_acquire_texlayer_from_obj(bf, &tlobj, mat->tex_layer[i]); + } else { + /*fprintf(stderr, "NOTHING FOUND AT POS %d\n", i);*/ + } + } } void blend_acquire_mesh_from_obj(BlendFile *bf, BlendObject *meobj, bMesh *mesh) { - { - BlendObject obj; - BlendBlockPointer vblock, fblock, cblock, tblock, - dblock, matlink; - int i; - int32_t ldata = 123456; - float fdata1, fdata2, fdata3; + { + BlendObject obj; + BlendBlockPointer vblock, fblock, cblock, ttblock,mtblock,dblock, matlink; + int i; + int32_t ldata = 123456; + float fdata1, fdata2, fdata3; - blend_init_mesh(mesh); - - if (!(blend_object_structure_getfield(bf, &obj, *meobj, - "totvert") && - blend_object_getdata(bf, &ldata, obj))) { - abort(); - } - mesh->vert_count = ldata; - - if (!(blend_object_structure_getfield(bf, &obj, *meobj, - "totface") && - blend_object_getdata(bf, &ldata, obj))) { - abort(); - } - mesh->face_count = ldata; + blend_init_mesh(mesh); - dprintf(stderr, "%d verts, %d faces...\n", - mesh->vert_count, mesh->face_count); - - if (!(blend_object_structure_getfield(bf, &obj, *meobj, - "mface") && - blend_object_getdata(bf, &fblock, obj))) { - abort(); - } - /* null fblock is okay */ + if (!(blend_object_structure_getfield(bf, &obj, *meobj, + "totvert") && + blend_object_getdata(bf, &ldata, obj))) + { + printf("invalid mesh 0x1\n"); + meobj->type = BOBJ_TYPE_INVALID_MESH; + return; + } + mesh->vert_count = ldata; - if (blend_object_structure_getfield(bf, &obj, *meobj, - "mat") && - blend_object_getdata(bf, &matlink, obj) && matlink) { - /* found an indirect material link, follow it */ - BlendObject matlinkobj = blend_block_get_object(bf, matlink, 0); - BlendBlockPointer matblock; - if (blend_object_structure_getfield(bf, &obj, matlinkobj, - "next") && - blend_object_getdata(bf, &matblock, obj)) { - if (matblock) { - BlendObject matobj = blend_block_get_object(bf, matblock, 0); - mesh->material = blend_alloc_material(); - blend_acquire_material_from_obj(bf, &matobj, mesh->material); - } else { - /* um, okay, link went nowhere, leave mesh->material NULL */ - } - } else { - abort(); - } - } else { - /* no material -- mesh->material will remain NULL */ - } - - if (!(blend_object_structure_getfield(bf, &obj, *meobj, - "mvert") && - blend_object_getdata(bf, &vblock, obj))) { - abort(); - } - /* null vblock is okay */ - - if (!(blend_object_structure_getfield(bf, &obj, *meobj, - "tface") && - blend_object_getdata(bf, &tblock, obj))) { - abort(); - } - - if (!(blend_object_structure_getfield(bf, &obj, *meobj, - "mcol") && - blend_object_getdata(bf, &cblock, obj))) { - abort(); - } - - if (!(blend_object_structure_getfield(bf, &obj, *meobj, - "dvert") && - blend_object_getdata(bf, &dblock, obj))) { - /* sometimes there isn't a dvert block... */ - dblock = NULL; - } + if (!(blend_object_structure_getfield(bf, &obj, *meobj, + "totface") && + blend_object_getdata(bf, &ldata, obj))) + { + printf("invalid mesh 0x2\n"); + meobj->type = BOBJ_TYPE_INVALID_MESH; + return; + } + mesh->face_count = ldata; - mesh->vert = malloc(sizeof(bVert) * mesh->vert_count); + dprintf(stderr, "%d verts, %d faces...\n", mesh->vert_count, mesh->face_count); - for (i=0; ivert_count; ++i) { - BlendObject obj = blend_block_get_object(bf, vblock, i); - BlendObject aobj; - float fdata1, fdata2, fdata3; - int32_t sdata1, sdata2, sdata3; - char cdata; + if (!(blend_object_structure_getfield(bf, &obj, *meobj, + "mface") && + blend_object_getdata(bf, &fblock, obj))) + { + printf("invalid mesh 0x3\n"); + meobj->type = BOBJ_TYPE_INVALID_MESH; + return; + } + /* null fblock is okay */ - mesh->vert[i].xyz[0] = - mesh->vert[i].xyz[1] = - mesh->vert[i].xyz[2] = -12345; - mesh->vert[i].cnormal[0] = - mesh->vert[i].cnormal[1] = - mesh->vert[i].cnormal[2] = -12345; - mesh->vert[i].mat = -1; + if (blend_object_structure_getfield(bf, &obj, *meobj, + "mat") && + blend_object_getdata(bf, &matlink, obj) && matlink) { + /* found an indirect material link, follow it */ + BlendObject matlinkobj = blend_block_get_object(bf, matlink, 0); + BlendBlockPointer matblock; + if (obj.block) + { + if (blend_object_structure_getfield(bf, &obj, matlinkobj, + "next") && + blend_object_getdata(bf, &matblock, obj)) { + if (matblock) { + BlendObject matobj = blend_block_get_object(bf, matblock, 0); + mesh->material = blend_alloc_material(); + blend_acquire_material_from_obj(bf, &matobj, mesh->material); + } else { + /* um, okay, link went nowhere, leave mesh->material NULL */ + } + } else { + //abort();//might fail? + } + } + } else { + /* no material -- mesh->material will remain NULL */ + } - if (!(blend_object_structure_getfield(bf, &aobj, obj, "co") && - blend_object_array_getdata(bf, &fdata1, aobj, 0,0) && - blend_object_array_getdata(bf, &fdata2, aobj, 0,1) && - blend_object_array_getdata(bf, &fdata3, aobj, 0,2))) { - abort(); + if (!(blend_object_structure_getfield(bf, &obj, *meobj, + "mvert") && + blend_object_getdata(bf, &vblock, obj))) { + abort(); + } + /* null vblock is okay */ + + if (!(blend_object_structure_getfield(bf, &obj, *meobj, + "tface") && + blend_object_getdata(bf, &ttblock, obj))) { + abort(); + } + + if (!(blend_object_structure_getfield(bf, &obj, *meobj, + "mtface") && + blend_object_getdata(bf, &mtblock, obj))) { + mtblock=0; + } + + if (!(blend_object_structure_getfield(bf, &obj, *meobj, + "mcol") && + blend_object_getdata(bf, &cblock, obj))) { + abort(); + } + + if (!(blend_object_structure_getfield(bf, &obj, *meobj, + "dvert") && + blend_object_getdata(bf, &dblock, obj))) { + /* sometimes there isn't a dvert block... */ + dblock = NULL; + } + + mesh->vert = malloc(sizeof(bVert) * mesh->vert_count); + + for (i=0; ivert_count; ++i) { + BlendObject obj = blend_block_get_object(bf, vblock, i); + BlendObject aobj; + float fdata1, fdata2, fdata3; + int32_t sdata1, sdata2, sdata3; + char cdata; + + mesh->vert[i].xyz[0] = + mesh->vert[i].xyz[1] = + mesh->vert[i].xyz[2] = -12345; + mesh->vert[i].cnormal[0] = + mesh->vert[i].cnormal[1] = + mesh->vert[i].cnormal[2] = -12345; + mesh->vert[i].mat = -1; + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "co") && + blend_object_array_getdata(bf, &fdata1, aobj, 0,0) && + blend_object_array_getdata(bf, &fdata2, aobj, 0,1) && + blend_object_array_getdata(bf, &fdata3, aobj, 0,2))) { + abort(); + } + mesh->vert[i].xyz[0] = fdata1; + mesh->vert[i].xyz[1] = fdata2; + mesh->vert[i].xyz[2] = fdata3; + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "no") && + blend_object_array_getdata(bf, &sdata1, aobj, 0,0) && + blend_object_array_getdata(bf, &sdata2, aobj, 0,1) && + blend_object_array_getdata(bf, &sdata3, aobj, 0,2))) { + abort(); + } + mesh->vert[i].cnormal[0] = sdata1; + mesh->vert[i].cnormal[1] = sdata2; + mesh->vert[i].cnormal[2] = sdata3; + /*fprintf(stderr, "%f ", LEN3(mesh->vert[i].normal[0], + mesh->vert[i].normal[1], + mesh->vert[i].normal[2]));*/ + if (sdata1 != 0 || sdata2 != 0 || sdata3 != 0) { + NORMALIZE3(mesh->vert[i].cnormal[0], + mesh->vert[i].cnormal[1], + mesh->vert[i].cnormal[2]); + } + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "mat_nr") && + blend_object_getdata(bf, &cdata, aobj))) { + abort(); + } + mesh->vert[i].mat = cdata; + } + + mesh->face = malloc(sizeof(bFace) * mesh->face_count); + + for (i=0; iface_count; ++i) { + int j,k; + BlendObject obj = blend_block_get_object(bf, fblock, i); + BlendObject aobj; + char cdata; + + mesh->face[i].v[0] = mesh->face[i].v[1] = + mesh->face[i].v[2] = mesh->face[i].v[3] = -1; + mesh->face[i].mat = -1; + mesh->face[i].flags = 0; + + for (j=0; j<4; ++j) { + for (k=0; k<3; ++k) { + mesh->face[i].rgba[j][k] = 1.0; + } + mesh->face[i].rgba[j][3] = 1.0f; + mesh->face[i].uv[j][0] = 0.0f; + mesh->face[i].uv[j][1] = 0.0f; + mesh->face[i].m_image = NULL; + } + + if (blend_object_structure_getfield(bf, &aobj, obj, "v1")) { + if (0!=strcmp(bf->types[aobj.type].name,"int") && + 0!=strcmp(bf->types[aobj.type].name,"ushort")) { + dprintf(stderr, "Expected vertex-index type to be 'ushort' or 'int', got '%s'\n", bf->types[aobj.type].name); + abort(); + } + + if (0==strcmp(bf->types[aobj.type].name,"int")) { + /* index type is a 32bit int, generated by newish Blenders */ + int32_t idata; + if (!(blend_object_structure_getfield(bf, &aobj, obj, "v1") && + blend_object_getdata(bf, &idata, aobj))) { + abort(); + } + mesh->face[i].v[0] = idata; + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "v2") && + blend_object_getdata(bf, &idata, aobj))) { + abort(); + } + mesh->face[i].v[1] = idata; + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "v3") && + blend_object_getdata(bf, &idata, aobj))) { + abort(); + } + mesh->face[i].v[2] = idata; + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "v4") && + blend_object_getdata(bf, &idata, aobj))) { + abort(); + } + mesh->face[i].v[3] = idata; + } else { + /* index type is a 16bit ushort, generated by old Blenders */ + uint16_t usdata; + if (!(blend_object_structure_getfield(bf, &aobj, obj, "v1") && + blend_object_getdata(bf, &usdata, aobj))) { + abort(); + } + mesh->face[i].v[0] = usdata; + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "v2") && + blend_object_getdata(bf, &usdata, aobj))) { + abort(); + } + mesh->face[i].v[1] = usdata; + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "v3") && + blend_object_getdata(bf, &usdata, aobj))) { + abort(); + } + mesh->face[i].v[2] = usdata; + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "v4") && + blend_object_getdata(bf, &usdata, aobj))) { + abort(); + } + mesh->face[i].v[3] = usdata; + } + } else { + abort(); + } + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "mat_nr") && + blend_object_getdata(bf, &cdata, aobj))) { + abort(); + } + mesh->face[i].mat = cdata; + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "flag") && + blend_object_getdata(bf, &cdata, aobj))) { + abort(); + } + mesh->face[i].flags = cdata; + } + + if (cblock) { + /* we have vertex colours */ + for (i=0; iface_count; ++i) { + int j; + unsigned char cdata; + BlendObject aobj; + for (j=0; j<4; ++j) { + BlendObject obj = blend_block_get_object(bf, cblock, i*4+j); + if (!(blend_object_structure_getfield(bf, &aobj, obj, "b") && + blend_object_getdata(bf, &cdata, aobj))) { + abort(); + } + mesh->face[i].rgba[j][0] = cdata / 255.0f; + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "g") && + blend_object_getdata(bf, &cdata, aobj))) { + abort(); + } + mesh->face[i].rgba[j][1] = cdata / 255.0f; + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "r") && + blend_object_getdata(bf, &cdata, aobj))) { + abort(); + } + mesh->face[i].rgba[j][2] = cdata / 255.0f; + + /* alpha seems to be nonsense :( */ + /* + if (!(blend_object_structure_getfield(bf, &aobj, obj, "a") && + blend_object_getdata(bf, &cdata, aobj))) { + abort(); + } + mesh->face[i].rgba[j][3] = cdata / 255.0f; + */ + mesh->face[i].rgba[j][3] = 1.0f; + } + } + } else { + /* !cblock (no vertex colours) */ + for (i=0; iface_count; ++i) { + int j; + for (j=0; j<4; ++j) { + mesh->face[i].rgba[j][0] = 1.0f; + mesh->face[i].rgba[j][1] = 1.0f; + mesh->face[i].rgba[j][2] = 1.0f; + mesh->face[i].rgba[j][3] = 1.0f; + } + } + } + + if (mtblock) + { + /* we have tex co-ords */ + for (i=0; iface_count; ++i) + { + int j,k; + void *pdata; + BlendObject aobj; + BlendObject obj = blend_block_get_object(bf, mtblock, i); + BlendObject obj2,obj3; + unsigned char flag; + unsigned short int mode; + + BlendBlockPointer tpageptr; + + if (blend_object_structure_getfield(bf, &obj3, obj, "flag")) + { + blend_object_getdata(bf, &flag, obj3); + mesh->face[i].m_flag = flag; + } else + { + mesh->face[i].m_flag = 0; + } + + if (blend_object_structure_getfield(bf, &obj3, obj, "mode")) + { + blend_object_getdata(bf, &mode, obj3); + mesh->face[i].m_mode = mode; + } else + { + mesh->face[i].m_mode = 0; + } + + if ((blend_object_structure_getfield(bf, &obj3, obj, "tpage") + && blend_object_getdata(bf, &tpageptr, obj3))) + { + + mesh->face[i].m_image = 0; + + for (j=0; j<4; ++j) + { + uint32_t uldata; + for (k=0; k<2; ++k) { + float fdata; + if (!(blend_object_structure_getfield(bf, &aobj, obj, "uv") && + blend_object_array_getdata(bf, &fdata, aobj, j,k))) { + abort(); + } + mesh->face[i].uv[j][k] = fdata; + } + mesh->face[i].uv[j][1] = 1.0f - mesh->face[i].uv[j][1]; + /* texture face colour... not sure how this conceptually + differs from the face vertex colours, but it does. */ + + /* in its usual inconsistant style, blender packs this + RGBA value into the bytes of an unsigned long... */ + + } + + //printf("got tpage\n"); + + { + int k; + for (k=0;kface[i].m_image=tCachedImages[k]; + break; + } + } + } + + if (!mesh->face[i].m_image) + { + bImage* bimg= (bImage*)malloc (sizeof(bImage)); + tCachedImages[gNumCachedImages]=bimg; + tCachedTPage[gNumCachedImages] = tpageptr; + gNumCachedImages++; + mesh->face[i].m_image = bimg; + bimg->m_packedImagePtr = 0; + bimg->m_sizePackedImage = 0; + + if (tpageptr) + { + BlendObject name_block; + BlendObject tpage = blend_block_get_object(bf,tpageptr,0); + + BlendObject okblock; + + + if ((blend_object_structure_getfield(bf, &okblock, tpage, "ok"))) + { + short int okval; + if (blend_object_getdata(bf,&okval,okblock)) + { +// printf("ok=%d\n",okval); + bimg->m_ok = okval; + } else + { + bimg->m_ok=0; + } + + } + + if ((blend_object_structure_getfield(bf, &okblock, tpage, "xrep"))) + { + short int xrep; + if (blend_object_getdata(bf,&xrep,okblock)) + { +// printf("xrep=%d\n",xrep); + bimg->m_xrep = xrep; + } else + { + bimg->m_xrep = 0; + } + } + + if ((blend_object_structure_getfield(bf, &okblock, tpage, "yrep"))) + { + short int yrep; + if (blend_object_getdata(bf,&yrep,okblock)) + { +// printf("yrep=%d\n",yrep); + bimg->m_yrep = yrep; + } else + { + bimg->m_yrep = 0; + } + } + + mesh->face[i].image_id = 0; + { + BlendBlockPointer packptr; + + if ((blend_object_structure_getfield(bf, &obj3, tpage, "packedfile") + && blend_object_getdata(bf, &packptr, obj3))) + { + if (packptr) + { + BlendObject packfile= blend_block_get_object(bf,packptr,0); + BlendBlockPointer dataptr; + if ((blend_object_structure_getfield(bf, &obj3, packfile, "data") + && blend_object_getdata(bf, &dataptr, obj3))) + { + /*BlendObject data= blend_block_get_object(bf,dataptr,0); + char dest[1024]; + blend_object_getstring(bf,data,dest,1023); + */ + +// printf("...\n"); + + //if (blend_object_structure_getfield(bf, &obj2, ipo,"curve")) + { + BlendBlock* block = (BlendBlock*)obj3.block; + + + void** ptrptr = &block->array_entries->field_bytes[block->array_entries->field_offsets[obj3.field_index]]; + BlendBlockPointer ptr = *ptrptr; + if (ptr) + { + BlendBlockPointer curveblockptr = blend_block_from_blendpointer(bf, ptr); + BlendObject curve = blend_block_get_object(bf, curveblockptr, 0); + BlendBlock* bb = (BlendBlock* )curve.block; + BlendBlock imgblock; + mesh->face[i].image_id = bb->blender_pointer; + //imgblock = blend_block_get_object(bf, bb->blender_pointer, 0); + bimg->m_packedImagePtr = bb->customData; + bimg->m_sizePackedImage = bb->customDataSize; + } + + } + } + + + } + + } + } + + + + + if ((blend_object_structure_getfield(bf, &name_block, tpage, "name"))) + { + int max_chars=127; + + if (blend_object_getstring(bf,name_block,bimg->m_imagePathName, max_chars)) + { +// printf("texname=%s\n",bimg->m_imagePathName); + } + + } + + + + } + + } + + + } + + + + + } + } + else + { + if (ttblock) { + /* we have tex co-ords */ + for (i=0; iface_count; ++i) { + int j,k; + void *pdata; + BlendObject aobj; + BlendObject obj = blend_block_get_object(bf, ttblock, i); + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "tpage") && + blend_object_getdata(bf, &pdata, aobj))) { + abort(); + } + mesh->face[i].image_id = pdata; + + for (j=0; j<4; ++j) { + uint32_t uldata; + for (k=0; k<2; ++k) { + float fdata; + if (!(blend_object_structure_getfield(bf, &aobj, obj, "uv") && + blend_object_array_getdata(bf, &fdata, aobj, j,k))) { + abort(); + } + mesh->face[i].uv[j][k] = fdata; + } + mesh->face[i].uv[j][1] = 1.0f - mesh->face[i].uv[j][1]; + /* texture face colour... not sure how this conceptually + differs from the face vertex colours, but it does. */ + if (!(blend_object_structure_getfield(bf, &aobj, obj, "col") && + blend_object_array_getdata(bf, &uldata, aobj, 0,j))) { + abort(); + } + /* in its usual inconsistant style, blender packs this + RGBA value into the bytes of an unsigned long... */ + mesh->face[i].rgba2[j][0] = ((uldata >> 24) & 0xFF) / 255.0f; + mesh->face[i].rgba2[j][1] = ((uldata >> 16) & 0xFF) / 255.0f; + mesh->face[i].rgba2[j][2] = ((uldata >> 8) & 0xFF) / 255.0f; + mesh->face[i].rgba2[j][3] = ((uldata >> 0) & 0xFF) / 255.0f; + } + /*mesh->face[i].uv[0][0]=0; mesh->face[i].uv[0][1]=0; + mesh->face[i].uv[1][0]=1; mesh->face[i].uv[1][1]=0; + mesh->face[i].uv[2][0]=1; mesh->face[i].uv[2][1]=1; + mesh->face[i].uv[3][0]=0; mesh->face[i].uv[3][1]=1;*/ + + } + } else { + /* !tblock (no texture co-ords, no face tex-colours) */ + for (i=0; iface_count; ++i) { + int j; + for (j=0; j<4; ++j) { + mesh->face[i].rgba2[j][0] = 1.0f; + mesh->face[i].rgba2[j][1] = 1.0f; + mesh->face[i].rgba2[j][2] = 1.0f; + mesh->face[i].rgba2[j][3] = 1.0f; + } + } + } + } + + if (mtblock) + { + BlendObject obj = blend_block_get_object(bf, mtblock, 0); + + //6155 + } + + + if (dblock) { + /* we have vertex deformation weights */ + for (i=0; ivert_count; ++i) { + int j; + int32_t ldata; + float fdata; + BlendBlockPointer pdata; + BlendObject aobj; + BlendObject obj = blend_block_get_object(bf, dblock, i); + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "totweight") && + blend_object_getdata(bf, &ldata, aobj))) { + abort(); + } + mesh->vert[i].deform_weights_count = ldata; + mesh->vert[i].deform_weights = malloc(ldata*sizeof(bDeformWeight)); + + if (!(blend_object_structure_getfield(bf, &aobj, obj, "dw") && + blend_object_getdata(bf, &pdata, aobj))) { + abort(); + } + + for (j=0; jvert[i].deform_weights_count; ++j) { + BlendObject dwobj = blend_block_get_object(bf, pdata, j); + + if (!(blend_object_structure_getfield(bf, &aobj, dwobj, "def_nr") + && blend_object_getdata(bf, &ldata, aobj))) { + abort(); + } + mesh->vert[i].deform_weights[j].bone_id = ldata; + + if (!(blend_object_structure_getfield(bf, &aobj, dwobj, "weight") + && blend_object_getdata(bf, &fdata, aobj))) { + abort(); + } + mesh->vert[i].deform_weights[j].weight = fdata; + } + } + } else { + /* !dblock (no vertex deformation weights) */ + for (i=0; ivert_count; ++i) { + mesh->vert[i].deform_weights = NULL; + mesh->vert[i].deform_weights_count = 0; + } + } } - mesh->vert[i].xyz[0] = fdata1; - mesh->vert[i].xyz[1] = fdata2; - mesh->vert[i].xyz[2] = fdata3; - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "no") && - blend_object_array_getdata(bf, &sdata1, aobj, 0,0) && - blend_object_array_getdata(bf, &sdata2, aobj, 0,1) && - blend_object_array_getdata(bf, &sdata3, aobj, 0,2))) { - abort(); - } - mesh->vert[i].cnormal[0] = sdata1; - mesh->vert[i].cnormal[1] = sdata2; - mesh->vert[i].cnormal[2] = sdata3; - /*fprintf(stderr, "%f ", LEN3(mesh->vert[i].normal[0], - mesh->vert[i].normal[1], - mesh->vert[i].normal[2]));*/ - if (sdata1 != 0 || sdata2 != 0 || sdata3 != 0) { - NORMALIZE3(mesh->vert[i].cnormal[0], - mesh->vert[i].cnormal[1], - mesh->vert[i].cnormal[2]); - } - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "mat_nr") && - blend_object_getdata(bf, &cdata, aobj))) { - abort(); - } - mesh->vert[i].mat = cdata; - } - - mesh->face = malloc(sizeof(bFace) * mesh->face_count); - - for (i=0; iface_count; ++i) { - int j,k; - BlendObject obj = blend_block_get_object(bf, fblock, i); - BlendObject aobj; - char cdata; - - mesh->face[i].v[0] = mesh->face[i].v[1] = - mesh->face[i].v[2] = mesh->face[i].v[3] = -1; - mesh->face[i].mat = -1; - mesh->face[i].flags = 0; - for (j=0; j<4; ++j) { - for (k=0; k<3; ++k) { - mesh->face[i].rgba[j][k] = 1.0; - } - mesh->face[i].rgba[j][3] = 1.0f; - mesh->face[i].uv[j][0] = 0.0f; - mesh->face[i].uv[j][1] = 0.0f; - mesh->face[i].image_id = NULL; - } - - if (blend_object_structure_getfield(bf, &aobj, obj, "v1")) { - if (0!=strcmp(bf->types[aobj.type].name,"int") && - 0!=strcmp(bf->types[aobj.type].name,"ushort")) { - dprintf(stderr, "Expected vertex-index type to be 'ushort' or 'int', got '%s'\n", bf->types[aobj.type].name); - abort(); - } - - if (0==strcmp(bf->types[aobj.type].name,"int")) { - /* index type is a 32bit int, generated by newish Blenders */ - int32_t idata; - if (!(blend_object_structure_getfield(bf, &aobj, obj, "v1") && - blend_object_getdata(bf, &idata, aobj))) { - abort(); - } - mesh->face[i].v[0] = idata; - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "v2") && - blend_object_getdata(bf, &idata, aobj))) { - abort(); - } - mesh->face[i].v[1] = idata; - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "v3") && - blend_object_getdata(bf, &idata, aobj))) { - abort(); - } - mesh->face[i].v[2] = idata; - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "v4") && - blend_object_getdata(bf, &idata, aobj))) { - abort(); - } - mesh->face[i].v[3] = idata; - } else { - /* index type is a 16bit ushort, generated by old Blenders */ - uint16_t usdata; - if (!(blend_object_structure_getfield(bf, &aobj, obj, "v1") && - blend_object_getdata(bf, &usdata, aobj))) { - abort(); - } - mesh->face[i].v[0] = usdata; - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "v2") && - blend_object_getdata(bf, &usdata, aobj))) { - abort(); - } - mesh->face[i].v[1] = usdata; - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "v3") && - blend_object_getdata(bf, &usdata, aobj))) { - abort(); - } - mesh->face[i].v[2] = usdata; - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "v4") && - blend_object_getdata(bf, &usdata, aobj))) { - abort(); - } - mesh->face[i].v[3] = usdata; - } - } else { - abort(); - } - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "mat_nr") && - blend_object_getdata(bf, &cdata, aobj))) { - abort(); - } - mesh->face[i].mat = cdata; - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "flag") && - blend_object_getdata(bf, &cdata, aobj))) { - abort(); - } - mesh->face[i].flags = cdata; - } - - if (cblock) { - /* we have vertex colours */ - for (i=0; iface_count; ++i) { - int j; - unsigned char cdata; - BlendObject aobj; - for (j=0; j<4; ++j) { - BlendObject obj = blend_block_get_object(bf, cblock, i*4+j); - if (!(blend_object_structure_getfield(bf, &aobj, obj, "b") && - blend_object_getdata(bf, &cdata, aobj))) { - abort(); - } - mesh->face[i].rgba[j][0] = cdata / 255.0f; - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "g") && - blend_object_getdata(bf, &cdata, aobj))) { - abort(); - } - mesh->face[i].rgba[j][1] = cdata / 255.0f; - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "r") && - blend_object_getdata(bf, &cdata, aobj))) { - abort(); - } - mesh->face[i].rgba[j][2] = cdata / 255.0f; - - /* alpha seems to be nonsense :( */ - /* - if (!(blend_object_structure_getfield(bf, &aobj, obj, "a") && - blend_object_getdata(bf, &cdata, aobj))) { - abort(); - } - mesh->face[i].rgba[j][3] = cdata / 255.0f; - */ - mesh->face[i].rgba[j][3] = 1.0f; - } - } - } else { - /* !cblock (no vertex colours) */ - for (i=0; iface_count; ++i) { - int j; - for (j=0; j<4; ++j) { - mesh->face[i].rgba[j][0] = 1.0f; - mesh->face[i].rgba[j][1] = 1.0f; - mesh->face[i].rgba[j][2] = 1.0f; - mesh->face[i].rgba[j][3] = 1.0f; - } - } - } - - if (tblock) { - /* we have tex co-ords */ - for (i=0; iface_count; ++i) { - int j,k; - void *pdata; - BlendObject aobj; - BlendObject obj = blend_block_get_object(bf, tblock, i); - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "tpage") && - blend_object_getdata(bf, &pdata, aobj))) { - abort(); - } - mesh->face[i].image_id = pdata; - - for (j=0; j<4; ++j) { - uint32_t uldata; - for (k=0; k<2; ++k) { - float fdata; - if (!(blend_object_structure_getfield(bf, &aobj, obj, "uv") && - blend_object_array_getdata(bf, &fdata, aobj, j,k))) { - abort(); - } - mesh->face[i].uv[j][k] = fdata; - } - mesh->face[i].uv[j][1] = 1.0f - mesh->face[i].uv[j][1]; - /* texture face colour... not sure how this conceptually - differs from the face vertex colours, but it does. */ - if (!(blend_object_structure_getfield(bf, &aobj, obj, "col") && - blend_object_array_getdata(bf, &uldata, aobj, 0,j))) { - abort(); - } - /* in its usual inconsistant style, blender packs this - RGBA value into the bytes of an unsigned long... */ - mesh->face[i].rgba2[j][0] = ((uldata >> 24) & 0xFF) / 255.0f; - mesh->face[i].rgba2[j][1] = ((uldata >> 16) & 0xFF) / 255.0f; - mesh->face[i].rgba2[j][2] = ((uldata >> 8) & 0xFF) / 255.0f; - mesh->face[i].rgba2[j][3] = ((uldata >> 0) & 0xFF) / 255.0f; - } - /*mesh->face[i].uv[0][0]=0; mesh->face[i].uv[0][1]=0; - mesh->face[i].uv[1][0]=1; mesh->face[i].uv[1][1]=0; - mesh->face[i].uv[2][0]=1; mesh->face[i].uv[2][1]=1; - mesh->face[i].uv[3][0]=0; mesh->face[i].uv[3][1]=1;*/ - - } - } else { - /* !tblock (no texture co-ords, no face tex-colours) */ - for (i=0; iface_count; ++i) { - int j; - for (j=0; j<4; ++j) { - mesh->face[i].rgba2[j][0] = 1.0f; - mesh->face[i].rgba2[j][1] = 1.0f; - mesh->face[i].rgba2[j][2] = 1.0f; - mesh->face[i].rgba2[j][3] = 1.0f; - } - } - } - - if (dblock) { - /* we have vertex deformation weights */ - for (i=0; ivert_count; ++i) { - int j; - int32_t ldata; - float fdata; - BlendBlockPointer pdata; - BlendObject aobj; - BlendObject obj = blend_block_get_object(bf, dblock, i); - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "totweight") && - blend_object_getdata(bf, &ldata, aobj))) { - abort(); - } - mesh->vert[i].deform_weights_count = ldata; - mesh->vert[i].deform_weights = malloc(ldata*sizeof(bDeformWeight)); - - if (!(blend_object_structure_getfield(bf, &aobj, obj, "dw") && - blend_object_getdata(bf, &pdata, aobj))) { - abort(); - } - - for (j=0; jvert[i].deform_weights_count; ++j) { - BlendObject dwobj = blend_block_get_object(bf, pdata, j); - - if (!(blend_object_structure_getfield(bf, &aobj, dwobj, "def_nr") - && blend_object_getdata(bf, &ldata, aobj))) { - abort(); - } - mesh->vert[i].deform_weights[j].bone_id = ldata; - - if (!(blend_object_structure_getfield(bf, &aobj, dwobj, "weight") - && blend_object_getdata(bf, &fdata, aobj))) { - abort(); - } - mesh->vert[i].deform_weights[j].weight = fdata; - } - } - } else { - /* !dblock (no vertex deformation weights) */ - for (i=0; ivert_count; ++i) { - mesh->vert[i].deform_weights = NULL; - mesh->vert[i].deform_weights_count = 0; - } - } - } } @@ -2322,76 +2720,76 @@ blend_acquire_mesh_from_obj(BlendFile *bf, BlendObject *meobj, bMesh *mesh) void blend_acquire_mesh(const char *fname, const char *want_name, bMesh *mesh) { - BlendFile* bf; - MY_FILETYPE *fp; + BlendFile* bf; + MY_FILETYPE *fp; - fp = MY_OPEN_FOR_READ(fname); + fp = MY_OPEN_FOR_READ(fname); - if (!fp) { - dprintf(stderr, "couldn't open file %s.\n", fname); - abort(); - } + if (!fp) { + dprintf(stderr, "couldn't open file %s.\n", fname); + abort(); + } - bf = blend_read(fp); - { - BlendObject meobj; - if (!blend_object_get_by_IDname(bf, &meobj, want_name)) { - dprintf(stderr, "couldn't find %s.\n", want_name); - abort(); - } - blend_dump_blocks(bf); - blend_acquire_mesh_from_obj(bf, &meobj, mesh); - } - blend_free(bf); + bf = blend_read(fp); + { + BlendObject meobj; + if (!blend_object_get_by_IDname(bf, &meobj, want_name)) { + dprintf(stderr, "couldn't find %s.\n", want_name); + abort(); + } + blend_dump_blocks(bf); + blend_acquire_mesh_from_obj(bf, &meobj, mesh); + } + blend_free(bf); - MY_CLOSE(fp); + MY_CLOSE(fp); } /* apply pitch, head, roll */ static void bRotPHR(float xyz[3], const float rot[3]) { - float rx,ry,rz; - float ix,iy,iz; - float cosang, sinang; + float rx,ry,rz; + float ix,iy,iz; + float cosang, sinang; - ix = xyz[0]; iy = xyz[1]; iz = xyz[2]; + ix = xyz[0]; iy = xyz[1]; iz = xyz[2]; - cosang = cos(rot[0]); - sinang = sin(rot[0]); - /* pitch */ - rx = ix; - ry = iy * cosang - iz * sinang; - rz = iy * sinang + iz * cosang; + cosang = cos(rot[0]); + sinang = sin(rot[0]); + /* pitch */ + rx = ix; + ry = iy * cosang - iz * sinang; + rz = iy * sinang + iz * cosang; - ix = rx; iy = ry; iz = rz; + ix = rx; iy = ry; iz = rz; - cosang = cos(rot[1]); - sinang = sin(rot[1]); - /* head */ - rx = ix * cosang + iz * sinang; - ry = iy; - rz = -ix * sinang + iz * cosang; + cosang = cos(rot[1]); + sinang = sin(rot[1]); + /* head */ + rx = ix * cosang + iz * sinang; + ry = iy; + rz = -ix * sinang + iz * cosang; - ix = rx; iy = ry; iz = rz; + ix = rx; iy = ry; iz = rz; - cosang = cos(rot[2]); - sinang = sin(rot[2]); - /* roll */ - rx = ix * cosang - iy * sinang; - ry = ix * sinang + iy * cosang; - rz = iz; + cosang = cos(rot[2]); + sinang = sin(rot[2]); + /* roll */ + rx = ix * cosang - iy * sinang; + ry = ix * sinang + iy * cosang; + rz = iz; - xyz[0] = rx; xyz[1] = ry; xyz[2] = rz; + xyz[0] = rx; xyz[1] = ry; xyz[2] = rz; } void blend_transform_mesh_from_obj(bMesh *mesh, bObj *obj) { - int i; - for (i=0; ivert_count; ++i) { - /* this one looks good. */ - bMatMultVec(mesh->vert[i].xyz, obj->transform); - bRotPHR(mesh->vert[i].cnormal, obj->rotphr); - } + int i; + for (i=0; ivert_count; ++i) { + /* this one looks good. */ + bMatMultVec(mesh->vert[i].xyz, obj->transform); + bRotPHR(mesh->vert[i].cnormal, obj->rotphr); + } } diff --git a/Extras/readblend/readblend.h b/Extras/readblend/readblend.h index 53ea69aeb..102686049 100644 --- a/Extras/readblend/readblend.h +++ b/Extras/readblend/readblend.h @@ -38,11 +38,11 @@ /* TODO: Doxygen me. */ -/* don't worry yourself about this. */ -#ifndef BlendFile -#define BlendFile void -#endif +#include "blendtype.h" +#ifdef __cplusplus +extern "C" { +#endif @@ -101,6 +101,7 @@ typedef struct { long entry_index; long field_index; } BlendObject; + /* The callback type for passing to blend_foreach_block() (the callback should return zero if it doesn't want to see any more blocks.) */ #define BLENDBLOCKCALLBACK_RETURN int @@ -312,20 +313,41 @@ typedef struct { bDeformWeight* deform_weights; int deform_weights_count; } bVert; + + #define BVERT_HAS_CNORMAL(BV) ((BV)->cnormal[0] != 0.0f || \ (BV)->cnormal[1] != 0.0f || \ (BV)->cnormal[2] != 0.0f) #define BFACE_FLAG_SMOOTH 0x01 + +typedef struct _bImage { + + void* m_packedImagePtr; + int m_sizePackedImage; + char m_imagePathName [128]; + + int m_ok; + + int m_xrep; + int m_yrep; + +} bImage; + typedef struct { int v[4]; float rgba[4][4]; /* vertex colours */ float rgba2[4][4]; /* texture face colours (errrr...?) */ float uv[4][2]; - BlendBlockPointer image_id; + bImage* m_image; int mat; unsigned char flags; + int m_flag; + int m_mode; + BlendBlockPointer image_id; } bFace; + + #define BFACE_HAS_TEXTURE(BF) ((BF)->image_id != NULL) #define BFACE_IS_QUAD(BF) ((BF)->v[3] != 0) #define BFACE_IS_TRI(BF) ((BF)->v[2] != 0 && (BF)->v[3] == 0) @@ -389,7 +411,7 @@ typedef struct { typedef float bMatrix[4][4]; -typedef struct { +typedef struct _bMesh{ bVert *vert; int vert_count; bFace *face; @@ -400,14 +422,17 @@ typedef struct { typedef enum { BOBJ_TYPE_UNKNOWN, BOBJ_TYPE_NULL, /* indicates object has no data associated with it! */ - BOBJ_TYPE_MESH + BOBJ_TYPE_MESH, + BOBJ_TYPE_INVALID_MESH, + BOBJ_TYPE_CAMERA, + BOBJ_TYPE_LAMP } bObjType; typedef enum { BAQ_INCLUDE_CHILDREN = 0x0001 } bAcquireFlags; -typedef struct { +typedef struct _bObj{ bObjType type; char *name; @@ -417,11 +442,15 @@ typedef struct { float rotphr[3]; /* pitch/head/roll rotation component of transform (use for normals) */ float location[3]; /* location component of transform */ unsigned char transflags; /* NOT DECODED YET, RAW BYTE */ - + float mass;//used for rigid body dynamics + int gameflag; //used to detect object type (static, ghost, dynamic, rigid body, soft body) + int boundtype; //used to detect collision shape type + union { void *dummy; bMesh *mesh; } data; + } bObj; @@ -456,4 +485,8 @@ void blend_free_texlayer(bTexLayer *tl); void blend_acquire_texlayer_from_obj(BlendFile *bf, BlendObject *tlobj, bTexLayer *tl); +#ifdef __cplusplus +} +#endif + #endif diff --git a/Extras/readblend/testblend.c b/Extras/readblend/testblend.c index 488294274..86e207176 100644 --- a/Extras/readblend/testblend.c +++ b/Extras/readblend/testblend.c @@ -4,107 +4,170 @@ #include "abs-file.h" #include "readblend.h" +#include "blendtype.h" + +#define MAX_MESHES 10 +bMesh gMeshes[MAX_MESHES]; +int gNumMesh = 0; + +#define MAX_OBJECTS 10 +bObj gObjects[MAX_OBJECTS]; +int gNumObjects = 0; void crawl(BlendFile* blend_file, - BlendObject obj) + BlendObject obj) { - BlendObject data_obj; + BlendObject data_obj; + BlendObject data_obj2; + + BlendBlock* tmpBlock=0; - if (blend_object_structure_getfield(blend_file, &data_obj, obj, "totvert")) { - if (blend_object_type(blend_file, data_obj) == BLEND_OBJ_LONG32) { - long data1 = 123456; - if (blend_object_getdata(blend_file, &data1, data_obj)) { - fprintf(stderr, "TOTVERT=(%ld) ", data1); - } else { - fprintf(stderr, "FETCH ERROR\n"); - } - } - } + { + const char* type_name = blend_file->types[obj.type].name; + if (strcmp(type_name,"Object")==0) + { + if (gNumObjectsgetWorldTransform(); gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); - btScalar sepDist = gjkPairDetector.getCachedSeparatingDistance()+dispatchInfo.m_convexConservativeDistanceThreshold; - //now perturbe directions to get multiple contact points btVector3 v0,v1; - btVector3 sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis().normalized(); - btPlaneSpace1(sepNormalWorldSpace,v0,v1); + btVector3 sepNormalWorldSpace; + btScalar sepDist = 0.f; + +#ifdef USE_SEPDISTANCE_UTIL2 + if (dispatchInfo.m_useConvexConservativeDistanceUtil) + { + sepDist = gjkPairDetector.getCachedSeparatingDistance()+dispatchInfo.m_convexConservativeDistanceThreshold; + if (sepDist>SIMD_EPSILON) + { + //now perturbe directions to get multiple contact points + sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis().normalized(); + btPlaneSpace1(sepNormalWorldSpace,v0,v1); + } + } +#endif //USE_SEPDISTANCE_UTIL2 + //now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects //perform perturbation when more then 'm_minimumPointsPerturbationThreshold' points @@ -280,7 +292,7 @@ void btConvexConvexAlgorithm ::processCollision (btCollisionObject* body0,btColl #ifdef USE_SEPDISTANCE_UTIL2 - if (dispatchInfo.m_useConvexConservativeDistanceUtil) + if (dispatchInfo.m_useConvexConservativeDistanceUtil && (sepDist>SIMD_EPSILON)) { m_sepDistance.initSeparatingDistance(gjkPairDetector.getCachedSeparatingAxis(),sepDist,body0->getWorldTransform(),body1->getWorldTransform()); } diff --git a/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp b/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp index 50a79451f..54914d27c 100644 --- a/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp +++ b/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp @@ -29,6 +29,12 @@ Written by: Marcus Hennix #define CONETWIST_DEF_FIX_THRESH btScalar(.05f) +SIMD_FORCE_INLINE btScalar computeAngularImpulseDenominator(const btVector3& axis, const btMatrix3x3& invInertiaWorld) +{ + btVector3 vec = axis * invInertiaWorld; + return axis.dot(vec); +} + btConeTwistConstraint::btConeTwistConstraint() :btTypedConstraint(CONETWIST_CONSTRAINT_TYPE), @@ -70,8 +76,6 @@ void btConeTwistConstraint::init() } - - void btConeTwistConstraint::getInfo1 (btConstraintInfo1* info) { if (m_useSolveConstraintObsolete) @@ -83,7 +87,7 @@ void btConeTwistConstraint::getInfo1 (btConstraintInfo1* info) { info->m_numConstraintRows = 3; info->nub = 3; - calcAngleInfo2(); + calcAngleInfo2(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getInvInertiaTensorWorld(),m_rbB.getInvInertiaTensorWorld()); if(m_solveSwingLimit) { info->m_numConstraintRows++; @@ -101,22 +105,31 @@ void btConeTwistConstraint::getInfo1 (btConstraintInfo1* info) } } } - +void btConeTwistConstraint::getInfo1NonVirtual (btConstraintInfo1* info) +{ + //always reserve 6 rows: object transform is not available on SPU + info->m_numConstraintRows = 6; + info->nub = 0; + +} + void btConeTwistConstraint::getInfo2 (btConstraintInfo2* info) { + getInfo2NonVirtual(info,m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getInvInertiaTensorWorld(),m_rbB.getInvInertiaTensorWorld()); +} + +void btConeTwistConstraint::getInfo2NonVirtual (btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB) +{ + calcAngleInfo2(transA,transB,invInertiaWorldA,invInertiaWorldB); + btAssert(!m_useSolveConstraintObsolete); - //retrieve matrices - btTransform body0_trans; - body0_trans = m_rbA.getCenterOfMassTransform(); - btTransform body1_trans; - body1_trans = m_rbB.getCenterOfMassTransform(); // set jacobian info->m_J1linearAxis[0] = 1; info->m_J1linearAxis[info->rowskip+1] = 1; info->m_J1linearAxis[2*info->rowskip+2] = 1; - btVector3 a1 = body0_trans.getBasis() * m_rbAFrame.getOrigin(); + btVector3 a1 = transA.getBasis() * m_rbAFrame.getOrigin(); { btVector3* angular0 = (btVector3*)(info->m_J1angularAxis); btVector3* angular1 = (btVector3*)(info->m_J1angularAxis+info->rowskip); @@ -124,7 +137,7 @@ void btConeTwistConstraint::getInfo2 (btConstraintInfo2* info) btVector3 a1neg = -a1; a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2); } - btVector3 a2 = body1_trans.getBasis() * m_rbBFrame.getOrigin(); + btVector3 a2 = transB.getBasis() * m_rbBFrame.getOrigin(); { btVector3* angular0 = (btVector3*)(info->m_J2angularAxis); btVector3* angular1 = (btVector3*)(info->m_J2angularAxis+info->rowskip); @@ -136,7 +149,7 @@ void btConeTwistConstraint::getInfo2 (btConstraintInfo2* info) int j; for (j=0; j<3; j++) { - info->m_constraintError[j*info->rowskip] = k * (a2[j] + body1_trans.getOrigin()[j] - a1[j] - body0_trans.getOrigin()[j]); + info->m_constraintError[j*info->rowskip] = k * (a2[j] + transB.getOrigin()[j] - a1[j] - transA.getOrigin()[j]); info->m_lowerLimit[j*info->rowskip] = -SIMD_INFINITY; info->m_upperLimit[j*info->rowskip] = SIMD_INFINITY; } @@ -275,7 +288,7 @@ void btConeTwistConstraint::buildJacobian() } } - calcAngleInfo2(); + calcAngleInfo2(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getInvInertiaTensorWorld(),m_rbB.getInvInertiaTensorWorld()); } } @@ -593,7 +606,7 @@ static btVector3 vTwist(1,0,0); // twist axis in constraint's space -void btConeTwistConstraint::calcAngleInfo2() +void btConeTwistConstraint::calcAngleInfo2(const btTransform& transA, const btTransform& transB, const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB) { m_swingCorrection = btScalar(0.); m_twistLimitSign = btScalar(0.); @@ -606,8 +619,8 @@ void btConeTwistConstraint::calcAngleInfo2() // TODO : split rotation to pure swing and pure twist // compute desired transforms in world btTransform trPose(m_qTarget); - btTransform trA = getRigidBodyA().getCenterOfMassTransform() * m_rbAFrame; - btTransform trB = getRigidBodyB().getCenterOfMassTransform() * m_rbBFrame; + btTransform trA = transA * m_rbAFrame; + btTransform trB = transB * m_rbBFrame; btTransform trDeltaAB = trB * trPose * trA.inverse(); btQuaternion qDeltaAB = trDeltaAB.getRotation(); btVector3 swingAxis = btVector3(qDeltaAB.x(), qDeltaAB.y(), qDeltaAB.z()); @@ -624,8 +637,8 @@ void btConeTwistConstraint::calcAngleInfo2() { // compute rotation of A wrt B (in constraint space) - btQuaternion qA = getRigidBodyA().getCenterOfMassTransform().getRotation() * m_rbAFrame.getRotation(); - btQuaternion qB = getRigidBodyB().getCenterOfMassTransform().getRotation() * m_rbBFrame.getRotation(); + btQuaternion qA = transA.getRotation() * m_rbAFrame.getRotation(); + btQuaternion qB = transB.getRotation() * m_rbBFrame.getRotation(); btQuaternion qAB = qB.inverse() * qA; // split rotation into cone and twist // (all this is done from B's perspective. Maybe I should be averaging axes...) @@ -673,10 +686,10 @@ void btConeTwistConstraint::calcAngleInfo2() // you haven't set any limits; // or you're trying to set at least one of the swing limits too small. (if so, do you really want a conetwist constraint?) // anyway, we have either hinge or fixed joint - btVector3 ivA = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(0); - btVector3 jvA = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(1); - btVector3 kvA = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(2); - btVector3 ivB = getRigidBodyB().getCenterOfMassTransform().getBasis() * m_rbBFrame.getBasis().getColumn(0); + btVector3 ivA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(0); + btVector3 jvA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(1); + btVector3 kvA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(2); + btVector3 ivB = transB.getBasis() * m_rbBFrame.getBasis().getColumn(0); btVector3 target; btScalar x = ivB.dot(ivA); btScalar y = ivB.dot(jvA); diff --git a/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h b/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h index 8a893d4fb..db1e061db 100644 --- a/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h +++ b/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h @@ -110,9 +110,12 @@ public: virtual void buildJacobian(); virtual void getInfo1 (btConstraintInfo1* info); + + void getInfo1NonVirtual(btConstraintInfo1* info); virtual void getInfo2 (btConstraintInfo2* info); + void getInfo2NonVirtual(btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB); virtual void solveConstraintObsolete(btSolverBody& bodyA,btSolverBody& bodyB,btScalar timeStep); @@ -198,7 +201,7 @@ public: } void calcAngleInfo(); - void calcAngleInfo2(); + void calcAngleInfo2(const btTransform& transA, const btTransform& transB,const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB); inline btScalar getSwingSpan1() { diff --git a/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp b/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp index 012c321fd..72116c6ba 100644 --- a/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp +++ b/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp @@ -14,6 +14,59 @@ subject to the following restrictions: */ +#include "btContactConstraint.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "LinearMath/btVector3.h" +#include "btJacobianEntry.h" +#include "btContactSolverInfo.h" +#include "LinearMath/btMinMax.h" +#include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h" + +btContactConstraint::btContactConstraint() +:btTypedConstraint(CONTACT_CONSTRAINT_TYPE) +{ +} + +btContactConstraint::btContactConstraint(btPersistentManifold* contactManifold,btRigidBody& rbA,btRigidBody& rbB) +:btTypedConstraint(CONTACT_CONSTRAINT_TYPE,rbA,rbB), + m_contactManifold(*contactManifold) +{ + +} + +btContactConstraint::~btContactConstraint() +{ + +} + +void btContactConstraint::setContactManifold(btPersistentManifold* contactManifold) +{ + m_contactManifold = *contactManifold; +} + +void btContactConstraint::getInfo1 (btConstraintInfo1* info) +{ + +} + +void btContactConstraint::getInfo2 (btConstraintInfo2* info) +{ + +} + +void btContactConstraint::buildJacobian() +{ + +} + +void btContactConstraint::solveConstraintObsolete(btSolverBody& bodyA,btSolverBody& bodyB,btScalar timeStep) +{ + +} + + + + #include "btContactConstraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btVector3.h" @@ -85,345 +138,4 @@ void resolveSingleBilateral(btRigidBody& body1, const btVector3& pos1, -//response between two dynamic objects with friction -btScalar resolveSingleCollision( - btRigidBody& body1, - btRigidBody& body2, - btManifoldPoint& contactPoint, - const btContactSolverInfo& solverInfo) -{ - - const btVector3& pos1_ = contactPoint.getPositionWorldOnA(); - const btVector3& pos2_ = contactPoint.getPositionWorldOnB(); - const btVector3& normal = contactPoint.m_normalWorldOnB; - - //constant over all iterations - btVector3 rel_pos1 = pos1_ - body1.getCenterOfMassPosition(); - btVector3 rel_pos2 = pos2_ - body2.getCenterOfMassPosition(); - - btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); - btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); - btVector3 vel = vel1 - vel2; - btScalar rel_vel; - rel_vel = normal.dot(vel); - - btScalar Kfps = btScalar(1.) / solverInfo.m_timeStep ; - - // btScalar damping = solverInfo.m_damping ; - btScalar Kerp = solverInfo.m_erp; - btScalar Kcor = Kerp *Kfps; - - btConstraintPersistentData* cpd = (btConstraintPersistentData*) contactPoint.m_userPersistentData; - btAssert(cpd); - btScalar distance = cpd->m_penetration; - btScalar positionalError = Kcor *-distance; - btScalar velocityError = cpd->m_restitution - rel_vel;// * damping; - - btScalar penetrationImpulse = positionalError * cpd->m_jacDiagABInv; - - btScalar velocityImpulse = velocityError * cpd->m_jacDiagABInv; - - btScalar normalImpulse = penetrationImpulse+velocityImpulse; - - // See Erin Catto's GDC 2006 paper: Clamp the accumulated impulse - btScalar oldNormalImpulse = cpd->m_appliedImpulse; - btScalar sum = oldNormalImpulse + normalImpulse; - cpd->m_appliedImpulse = btScalar(0.) > sum ? btScalar(0.): sum; - - normalImpulse = cpd->m_appliedImpulse - oldNormalImpulse; - -#ifdef USE_INTERNAL_APPLY_IMPULSE - if (body1.getInvMass()) - { - body1.internalApplyImpulse(contactPoint.m_normalWorldOnB*body1.getInvMass(),cpd->m_angularComponentA,normalImpulse); - } - if (body2.getInvMass()) - { - body2.internalApplyImpulse(contactPoint.m_normalWorldOnB*body2.getInvMass(),cpd->m_angularComponentB,-normalImpulse); - } -#else //USE_INTERNAL_APPLY_IMPULSE - body1.applyImpulse(normal*(normalImpulse), rel_pos1); - body2.applyImpulse(-normal*(normalImpulse), rel_pos2); -#endif //USE_INTERNAL_APPLY_IMPULSE - - return normalImpulse; -} - - -btScalar resolveSingleFriction( - btRigidBody& body1, - btRigidBody& body2, - btManifoldPoint& contactPoint, - const btContactSolverInfo& solverInfo) -{ - - (void)solverInfo; - - const btVector3& pos1 = contactPoint.getPositionWorldOnA(); - const btVector3& pos2 = contactPoint.getPositionWorldOnB(); - - btVector3 rel_pos1 = pos1 - body1.getCenterOfMassPosition(); - btVector3 rel_pos2 = pos2 - body2.getCenterOfMassPosition(); - - btConstraintPersistentData* cpd = (btConstraintPersistentData*) contactPoint.m_userPersistentData; - btAssert(cpd); - - btScalar combinedFriction = cpd->m_friction; - - btScalar limit = cpd->m_appliedImpulse * combinedFriction; - - if (cpd->m_appliedImpulse>btScalar(0.)) - //friction - { - //apply friction in the 2 tangential directions - - // 1st tangent - btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); - btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); - btVector3 vel = vel1 - vel2; - - btScalar j1,j2; - - { - - btScalar vrel = cpd->m_frictionWorldTangential0.dot(vel); - - // calculate j that moves us to zero relative velocity - j1 = -vrel * cpd->m_jacDiagABInvTangent0; - btScalar oldTangentImpulse = cpd->m_accumulatedTangentImpulse0; - cpd->m_accumulatedTangentImpulse0 = oldTangentImpulse + j1; - btSetMin(cpd->m_accumulatedTangentImpulse0, limit); - btSetMax(cpd->m_accumulatedTangentImpulse0, -limit); - j1 = cpd->m_accumulatedTangentImpulse0 - oldTangentImpulse; - - } - { - // 2nd tangent - - btScalar vrel = cpd->m_frictionWorldTangential1.dot(vel); - - // calculate j that moves us to zero relative velocity - j2 = -vrel * cpd->m_jacDiagABInvTangent1; - btScalar oldTangentImpulse = cpd->m_accumulatedTangentImpulse1; - cpd->m_accumulatedTangentImpulse1 = oldTangentImpulse + j2; - btSetMin(cpd->m_accumulatedTangentImpulse1, limit); - btSetMax(cpd->m_accumulatedTangentImpulse1, -limit); - j2 = cpd->m_accumulatedTangentImpulse1 - oldTangentImpulse; - } - -#ifdef USE_INTERNAL_APPLY_IMPULSE - if (body1.getInvMass()) - { - body1.internalApplyImpulse(cpd->m_frictionWorldTangential0*body1.getInvMass(),cpd->m_frictionAngularComponent0A,j1); - body1.internalApplyImpulse(cpd->m_frictionWorldTangential1*body1.getInvMass(),cpd->m_frictionAngularComponent1A,j2); - } - if (body2.getInvMass()) - { - body2.internalApplyImpulse(cpd->m_frictionWorldTangential0*body2.getInvMass(),cpd->m_frictionAngularComponent0B,-j1); - body2.internalApplyImpulse(cpd->m_frictionWorldTangential1*body2.getInvMass(),cpd->m_frictionAngularComponent1B,-j2); - } -#else //USE_INTERNAL_APPLY_IMPULSE - body1.applyImpulse((j1 * cpd->m_frictionWorldTangential0)+(j2 * cpd->m_frictionWorldTangential1), rel_pos1); - body2.applyImpulse((j1 * -cpd->m_frictionWorldTangential0)+(j2 * -cpd->m_frictionWorldTangential1), rel_pos2); -#endif //USE_INTERNAL_APPLY_IMPULSE - - - } - return cpd->m_appliedImpulse; -} - - -btScalar resolveSingleFrictionOriginal( - btRigidBody& body1, - btRigidBody& body2, - btManifoldPoint& contactPoint, - const btContactSolverInfo& solverInfo); - -btScalar resolveSingleFrictionOriginal( - btRigidBody& body1, - btRigidBody& body2, - btManifoldPoint& contactPoint, - const btContactSolverInfo& solverInfo) -{ - - (void)solverInfo; - - const btVector3& pos1 = contactPoint.getPositionWorldOnA(); - const btVector3& pos2 = contactPoint.getPositionWorldOnB(); - - btVector3 rel_pos1 = pos1 - body1.getCenterOfMassPosition(); - btVector3 rel_pos2 = pos2 - body2.getCenterOfMassPosition(); - - btConstraintPersistentData* cpd = (btConstraintPersistentData*) contactPoint.m_userPersistentData; - btAssert(cpd); - - btScalar combinedFriction = cpd->m_friction; - - btScalar limit = cpd->m_appliedImpulse * combinedFriction; - //if (contactPoint.m_appliedImpulse>btScalar(0.)) - //friction - { - //apply friction in the 2 tangential directions - - { - // 1st tangent - btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); - btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); - btVector3 vel = vel1 - vel2; - - btScalar vrel = cpd->m_frictionWorldTangential0.dot(vel); - - // calculate j that moves us to zero relative velocity - btScalar j = -vrel * cpd->m_jacDiagABInvTangent0; - btScalar total = cpd->m_accumulatedTangentImpulse0 + j; - btSetMin(total, limit); - btSetMax(total, -limit); - j = total - cpd->m_accumulatedTangentImpulse0; - cpd->m_accumulatedTangentImpulse0 = total; - body1.applyImpulse(j * cpd->m_frictionWorldTangential0, rel_pos1); - body2.applyImpulse(j * -cpd->m_frictionWorldTangential0, rel_pos2); - } - - - { - // 2nd tangent - btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); - btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); - btVector3 vel = vel1 - vel2; - - btScalar vrel = cpd->m_frictionWorldTangential1.dot(vel); - - // calculate j that moves us to zero relative velocity - btScalar j = -vrel * cpd->m_jacDiagABInvTangent1; - btScalar total = cpd->m_accumulatedTangentImpulse1 + j; - btSetMin(total, limit); - btSetMax(total, -limit); - j = total - cpd->m_accumulatedTangentImpulse1; - cpd->m_accumulatedTangentImpulse1 = total; - body1.applyImpulse(j * cpd->m_frictionWorldTangential1, rel_pos1); - body2.applyImpulse(j * -cpd->m_frictionWorldTangential1, rel_pos2); - } - } - return cpd->m_appliedImpulse; -} - - -//velocity + friction -//response between two dynamic objects with friction -btScalar resolveSingleCollisionCombined( - btRigidBody& body1, - btRigidBody& body2, - btManifoldPoint& contactPoint, - const btContactSolverInfo& solverInfo) -{ - - const btVector3& pos1 = contactPoint.getPositionWorldOnA(); - const btVector3& pos2 = contactPoint.getPositionWorldOnB(); - const btVector3& normal = contactPoint.m_normalWorldOnB; - - btVector3 rel_pos1 = pos1 - body1.getCenterOfMassPosition(); - btVector3 rel_pos2 = pos2 - body2.getCenterOfMassPosition(); - - btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); - btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); - btVector3 vel = vel1 - vel2; - btScalar rel_vel; - rel_vel = normal.dot(vel); - - btScalar Kfps = btScalar(1.) / solverInfo.m_timeStep ; - - //btScalar damping = solverInfo.m_damping ; - btScalar Kerp = solverInfo.m_erp; - btScalar Kcor = Kerp *Kfps; - - btConstraintPersistentData* cpd = (btConstraintPersistentData*) contactPoint.m_userPersistentData; - btAssert(cpd); - btScalar distance = cpd->m_penetration; - btScalar positionalError = Kcor *-distance; - btScalar velocityError = cpd->m_restitution - rel_vel;// * damping; - - btScalar penetrationImpulse = positionalError * cpd->m_jacDiagABInv; - - btScalar velocityImpulse = velocityError * cpd->m_jacDiagABInv; - - btScalar normalImpulse = penetrationImpulse+velocityImpulse; - - // See Erin Catto's GDC 2006 paper: Clamp the accumulated impulse - btScalar oldNormalImpulse = cpd->m_appliedImpulse; - btScalar sum = oldNormalImpulse + normalImpulse; - cpd->m_appliedImpulse = btScalar(0.) > sum ? btScalar(0.): sum; - - normalImpulse = cpd->m_appliedImpulse - oldNormalImpulse; - - -#ifdef USE_INTERNAL_APPLY_IMPULSE - if (body1.getInvMass()) - { - body1.internalApplyImpulse(contactPoint.m_normalWorldOnB*body1.getInvMass(),cpd->m_angularComponentA,normalImpulse); - } - if (body2.getInvMass()) - { - body2.internalApplyImpulse(contactPoint.m_normalWorldOnB*body2.getInvMass(),cpd->m_angularComponentB,-normalImpulse); - } -#else //USE_INTERNAL_APPLY_IMPULSE - body1.applyImpulse(normal*(normalImpulse), rel_pos1); - body2.applyImpulse(-normal*(normalImpulse), rel_pos2); -#endif //USE_INTERNAL_APPLY_IMPULSE - - { - //friction - btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); - btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); - btVector3 vel = vel1 - vel2; - - rel_vel = normal.dot(vel); - - - btVector3 lat_vel = vel - normal * rel_vel; - btScalar lat_rel_vel = lat_vel.length(); - - btScalar combinedFriction = cpd->m_friction; - - if (cpd->m_appliedImpulse > 0) - if (lat_rel_vel > SIMD_EPSILON) - { - lat_vel /= lat_rel_vel; - btVector3 temp1 = body1.getInvInertiaTensorWorld() * rel_pos1.cross(lat_vel); - btVector3 temp2 = body2.getInvInertiaTensorWorld() * rel_pos2.cross(lat_vel); - btScalar friction_impulse = lat_rel_vel / - (body1.getInvMass() + body2.getInvMass() + lat_vel.dot(temp1.cross(rel_pos1) + temp2.cross(rel_pos2))); - btScalar normal_impulse = cpd->m_appliedImpulse * combinedFriction; - - btSetMin(friction_impulse, normal_impulse); - btSetMax(friction_impulse, -normal_impulse); - body1.applyImpulse(lat_vel * -friction_impulse, rel_pos1); - body2.applyImpulse(lat_vel * friction_impulse, rel_pos2); - } - } - - - - return normalImpulse; -} - -btScalar resolveSingleFrictionEmpty( - btRigidBody& body1, - btRigidBody& body2, - btManifoldPoint& contactPoint, - const btContactSolverInfo& solverInfo); - -btScalar resolveSingleFrictionEmpty( - btRigidBody& body1, - btRigidBody& body2, - btManifoldPoint& contactPoint, - const btContactSolverInfo& solverInfo) -{ - (void)contactPoint; - (void)body1; - (void)body2; - (void)solverInfo; - - - return btScalar(0.); -} diff --git a/src/BulletDynamics/ConstraintSolver/btContactConstraint.h b/src/BulletDynamics/ConstraintSolver/btContactConstraint.h index e8871f386..481b89e54 100644 --- a/src/BulletDynamics/ConstraintSolver/btContactConstraint.h +++ b/src/BulletDynamics/ConstraintSolver/btContactConstraint.h @@ -16,107 +16,56 @@ subject to the following restrictions: #ifndef CONTACT_CONSTRAINT_H #define CONTACT_CONSTRAINT_H -///@todo: make into a proper class working with the iterative constraint solver - -class btRigidBody; #include "LinearMath/btVector3.h" -#include "LinearMath/btScalar.h" -struct btContactSolverInfo; -class btManifoldPoint; +#include "btJacobianEntry.h" +#include "btTypedConstraint.h" +#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" -enum { - DEFAULT_CONTACT_SOLVER_TYPE=0, - CONTACT_SOLVER_TYPE1, - CONTACT_SOLVER_TYPE2, - USER_CONTACT_SOLVER_TYPE1, - MAX_CONTACT_SOLVER_TYPES -}; - - -typedef btScalar (*ContactSolverFunc)(btRigidBody& body1, - btRigidBody& body2, - class btManifoldPoint& contactPoint, - const btContactSolverInfo& info); - -///stores some extra information to each contact point. It is not in the contact point, because that want to keep the collision detection independent from the constraint solver. -struct btConstraintPersistentData +///btContactConstraint can be automatically created to solve contact constraints using the unified btTypedConstraint interface +ATTRIBUTE_ALIGNED16(class) btContactConstraint : public btTypedConstraint { - inline btConstraintPersistentData() - :m_appliedImpulse(btScalar(0.)), - m_prevAppliedImpulse(btScalar(0.)), - m_accumulatedTangentImpulse0(btScalar(0.)), - m_accumulatedTangentImpulse1(btScalar(0.)), - m_jacDiagABInv(btScalar(0.)), - m_persistentLifeTime(0), - m_restitution(btScalar(0.)), - m_friction(btScalar(0.)), - m_penetration(btScalar(0.)), - m_contactSolverFunc(0), - m_frictionSolverFunc(0) +protected: + + btPersistentManifold m_contactManifold; + +public: + + btContactConstraint(); + + btContactConstraint(btPersistentManifold* contactManifold,btRigidBody& rbA,btRigidBody& rbB); + + void setContactManifold(btPersistentManifold* contactManifold); + + btPersistentManifold* getContactManifold() { + return &m_contactManifold; } - - - /// total applied impulse during most recent frame - btScalar m_appliedImpulse; - btScalar m_prevAppliedImpulse; - btScalar m_accumulatedTangentImpulse0; - btScalar m_accumulatedTangentImpulse1; - - btScalar m_jacDiagABInv; - btScalar m_jacDiagABInvTangent0; - btScalar m_jacDiagABInvTangent1; - int m_persistentLifeTime; - btScalar m_restitution; - btScalar m_friction; - btScalar m_penetration; - btVector3 m_frictionWorldTangential0; - btVector3 m_frictionWorldTangential1; - btVector3 m_frictionAngularComponent0A; - btVector3 m_frictionAngularComponent0B; - btVector3 m_frictionAngularComponent1A; - btVector3 m_frictionAngularComponent1B; + const btPersistentManifold* getContactManifold() const + { + return &m_contactManifold; + } - //some data doesn't need to be persistent over frames: todo: clean/reuse this - btVector3 m_angularComponentA; - btVector3 m_angularComponentB; - - ContactSolverFunc m_contactSolverFunc; - ContactSolverFunc m_frictionSolverFunc; + virtual ~btContactConstraint(); + + virtual void getInfo1 (btConstraintInfo1* info); + + virtual void getInfo2 (btConstraintInfo2* info); + + ///obsolete methods + virtual void buildJacobian(); + + ///obsolete methods + virtual void solveConstraintObsolete(btSolverBody& bodyA,btSolverBody& bodyB,btScalar timeStep); }; -///bilateral constraint between two dynamic objects -///positive distance = separation, negative distance = penetration + +///resolveSingleBilateral is an obsolete methods used for vehicle friction between two dynamic objects void resolveSingleBilateral(btRigidBody& body1, const btVector3& pos1, btRigidBody& body2, const btVector3& pos2, btScalar distance, const btVector3& normal,btScalar& impulse ,btScalar timeStep); -///contact constraint resolution: -///calculate and apply impulse to satisfy non-penetration and non-negative relative velocity constraint -///positive distance = separation, negative distance = penetration -btScalar resolveSingleCollision( - btRigidBody& body1, - btRigidBody& body2, - btManifoldPoint& contactPoint, - const btContactSolverInfo& info); - -btScalar resolveSingleFriction( - btRigidBody& body1, - btRigidBody& body2, - btManifoldPoint& contactPoint, - const btContactSolverInfo& solverInfo - ); - - - -btScalar resolveSingleCollisionCombined( - btRigidBody& body1, - btRigidBody& body2, - btManifoldPoint& contactPoint, - const btContactSolverInfo& solverInfo - ); #endif //CONTACT_CONSTRAINT_H diff --git a/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp b/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp index d769c918e..7e6323402 100644 --- a/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp +++ b/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp @@ -26,7 +26,7 @@ subject to the following restrictions: #define HINGE_USE_OBSOLETE_SOLVER false - +#ifndef __SPU__ btHingeConstraint::btHingeConstraint() : btTypedConstraint (HINGE_CONSTRAINT_TYPE), @@ -249,7 +249,7 @@ void btHingeConstraint::buildJacobian() m_accLimitImpulse = btScalar(0.); // test angular limit - testLimit(); + testLimit(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); //Compute K = J*W*J' for hinge axis btVector3 axisA = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(2); @@ -259,6 +259,166 @@ void btHingeConstraint::buildJacobian() } } +void btHingeConstraint::solveConstraintObsolete(btSolverBody& bodyA,btSolverBody& bodyB,btScalar timeStep) +{ + + ///for backwards compatibility during the transition to 'getInfo/getInfo2' + if (m_useSolveConstraintObsolete) + { + + btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_rbAFrame.getOrigin(); + btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_rbBFrame.getOrigin(); + + btScalar tau = btScalar(0.3); + + //linear part + if (!m_angularOnly) + { + btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition(); + btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition(); + + btVector3 vel1,vel2; + bodyA.getVelocityInLocalPointObsolete(rel_pos1,vel1); + bodyB.getVelocityInLocalPointObsolete(rel_pos2,vel2); + btVector3 vel = vel1 - vel2; + + for (int i=0;i<3;i++) + { + const btVector3& normal = m_jac[i].m_linearJointAxis; + btScalar jacDiagABInv = btScalar(1.) / m_jac[i].getDiagonal(); + + btScalar rel_vel; + rel_vel = normal.dot(vel); + //positional error (zeroth order error) + btScalar depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal + btScalar impulse = depth*tau/timeStep * jacDiagABInv - rel_vel * jacDiagABInv; + m_appliedImpulse += impulse; + btVector3 impulse_vector = normal * impulse; + btVector3 ftorqueAxis1 = rel_pos1.cross(normal); + btVector3 ftorqueAxis2 = rel_pos2.cross(normal); + bodyA.applyImpulse(normal*m_rbA.getInvMass(), m_rbA.getInvInertiaTensorWorld()*ftorqueAxis1,impulse); + bodyB.applyImpulse(normal*m_rbB.getInvMass(), m_rbB.getInvInertiaTensorWorld()*ftorqueAxis2,-impulse); + } + } + + + { + ///solve angular part + + // get axes in world space + btVector3 axisA = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(2); + btVector3 axisB = getRigidBodyB().getCenterOfMassTransform().getBasis() * m_rbBFrame.getBasis().getColumn(2); + + btVector3 angVelA; + bodyA.getAngularVelocity(angVelA); + btVector3 angVelB; + bodyB.getAngularVelocity(angVelB); + + btVector3 angVelAroundHingeAxisA = axisA * axisA.dot(angVelA); + btVector3 angVelAroundHingeAxisB = axisB * axisB.dot(angVelB); + + btVector3 angAorthog = angVelA - angVelAroundHingeAxisA; + btVector3 angBorthog = angVelB - angVelAroundHingeAxisB; + btVector3 velrelOrthog = angAorthog-angBorthog; + { + + + //solve orthogonal angular velocity correction + //btScalar relaxation = btScalar(1.); + btScalar len = velrelOrthog.length(); + if (len > btScalar(0.00001)) + { + btVector3 normal = velrelOrthog.normalized(); + btScalar denom = getRigidBodyA().computeAngularImpulseDenominator(normal) + + getRigidBodyB().computeAngularImpulseDenominator(normal); + // scale for mass and relaxation + //velrelOrthog *= (btScalar(1.)/denom) * m_relaxationFactor; + + bodyA.applyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*velrelOrthog,-(btScalar(1.)/denom)); + bodyB.applyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*velrelOrthog,(btScalar(1.)/denom)); + + } + + //solve angular positional correction + btVector3 angularError = axisA.cross(axisB) *(btScalar(1.)/timeStep); + btScalar len2 = angularError.length(); + if (len2>btScalar(0.00001)) + { + btVector3 normal2 = angularError.normalized(); + btScalar denom2 = getRigidBodyA().computeAngularImpulseDenominator(normal2) + + getRigidBodyB().computeAngularImpulseDenominator(normal2); + //angularError *= (btScalar(1.)/denom2) * relaxation; + + bodyA.applyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*angularError,(btScalar(1.)/denom2)); + bodyB.applyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*angularError,-(btScalar(1.)/denom2)); + + } + + + + + + // solve limit + if (m_solveLimit) + { + btScalar amplitude = ( (angVelB - angVelA).dot( axisA )*m_relaxationFactor + m_correction* (btScalar(1.)/timeStep)*m_biasFactor ) * m_limitSign; + + btScalar impulseMag = amplitude * m_kHinge; + + // Clamp the accumulated impulse + btScalar temp = m_accLimitImpulse; + m_accLimitImpulse = btMax(m_accLimitImpulse + impulseMag, btScalar(0) ); + impulseMag = m_accLimitImpulse - temp; + + + + bodyA.applyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*axisA,impulseMag * m_limitSign); + bodyB.applyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*axisA,-(impulseMag * m_limitSign)); + + } + } + + //apply motor + if (m_enableAngularMotor) + { + //todo: add limits too + btVector3 angularLimit(0,0,0); + + btVector3 velrel = angVelAroundHingeAxisA - angVelAroundHingeAxisB; + btScalar projRelVel = velrel.dot(axisA); + + btScalar desiredMotorVel = m_motorTargetVelocity; + btScalar motor_relvel = desiredMotorVel - projRelVel; + + btScalar unclippedMotorImpulse = m_kHinge * motor_relvel;; + + // accumulated impulse clipping: + btScalar fMaxImpulse = m_maxMotorImpulse; + btScalar newAccImpulse = m_accMotorImpulse + unclippedMotorImpulse; + btScalar clippedMotorImpulse = unclippedMotorImpulse; + if (newAccImpulse > fMaxImpulse) + { + newAccImpulse = fMaxImpulse; + clippedMotorImpulse = newAccImpulse - m_accMotorImpulse; + } + else if (newAccImpulse < -fMaxImpulse) + { + newAccImpulse = -fMaxImpulse; + clippedMotorImpulse = newAccImpulse - m_accMotorImpulse; + } + m_accMotorImpulse += clippedMotorImpulse; + + bodyA.applyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*axisA,clippedMotorImpulse); + bodyB.applyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*axisA,-clippedMotorImpulse); + + } + } + } + +} + + +#endif //__SPU__ void btHingeConstraint::getInfo1(btConstraintInfo1* info) @@ -272,52 +432,77 @@ void btHingeConstraint::getInfo1(btConstraintInfo1* info) { info->m_numConstraintRows = 5; // Fixed 3 linear + 2 angular info->nub = 1; + //always add the row, to avoid computation (data is not available yet) //prepare constraint - testLimit(); + testLimit(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); if(getSolveLimit() || getEnableAngularMotor()) { info->m_numConstraintRows++; // limit 3rd anguar as well info->nub--; } + } } - +void btHingeConstraint::getInfo1NonVirtual(btConstraintInfo1* info) +{ + if (m_useSolveConstraintObsolete) + { + info->m_numConstraintRows = 0; + info->nub = 0; + } + else + { + //always add the 'limit' row, to avoid computation (data is not available yet) + info->m_numConstraintRows = 6; // Fixed 3 linear + 2 angular + info->nub = 0; + } +} void btHingeConstraint::getInfo2 (btConstraintInfo2* info) +{ + getInfo2NonVirtual(info, m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getAngularVelocity(),m_rbB.getAngularVelocity()); +} + +void btHingeConstraint::getInfo2NonVirtual (btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB) { btAssert(!m_useSolveConstraintObsolete); - int i, s = info->rowskip; + int i, skip = info->rowskip; // transforms in world space - btTransform trA = m_rbA.getCenterOfMassTransform()*m_rbAFrame; - btTransform trB = m_rbB.getCenterOfMassTransform()*m_rbBFrame; + btTransform trA = transA*m_rbAFrame; + btTransform trB = transB*m_rbBFrame; // pivot point btVector3 pivotAInW = trA.getOrigin(); btVector3 pivotBInW = trB.getOrigin(); + // linear (all fixed) info->m_J1linearAxis[0] = 1; - info->m_J1linearAxis[s + 1] = 1; - info->m_J1linearAxis[2 * s + 2] = 1; - btVector3 a1 = pivotAInW - m_rbA.getCenterOfMassTransform().getOrigin(); + info->m_J1linearAxis[skip + 1] = 1; + info->m_J1linearAxis[2 * skip + 2] = 1; + + + + + btVector3 a1 = pivotAInW - transA.getOrigin(); { btVector3* angular0 = (btVector3*)(info->m_J1angularAxis); - btVector3* angular1 = (btVector3*)(info->m_J1angularAxis + s); - btVector3* angular2 = (btVector3*)(info->m_J1angularAxis + 2 * s); + btVector3* angular1 = (btVector3*)(info->m_J1angularAxis + skip); + btVector3* angular2 = (btVector3*)(info->m_J1angularAxis + 2 * skip); btVector3 a1neg = -a1; a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2); } - btVector3 a2 = pivotBInW - m_rbB.getCenterOfMassTransform().getOrigin(); + btVector3 a2 = pivotBInW - transB.getOrigin(); { btVector3* angular0 = (btVector3*)(info->m_J2angularAxis); - btVector3* angular1 = (btVector3*)(info->m_J2angularAxis + s); - btVector3* angular2 = (btVector3*)(info->m_J2angularAxis + 2 * s); + btVector3* angular1 = (btVector3*)(info->m_J2angularAxis + skip); + btVector3* angular2 = (btVector3*)(info->m_J2angularAxis + 2 * skip); a2.getSkewSymmetricMatrix(angular0,angular1,angular2); } // linear RHS btScalar k = info->fps * info->erp; for(i = 0; i < 3; i++) { - info->m_constraintError[i * s] = k * (pivotBInW[i] - pivotAInW[i]); + info->m_constraintError[i * skip] = k * (pivotBInW[i] - pivotAInW[i]); } // make rotations around X and Y equal // the hinge axis should be the only unconstrained @@ -436,8 +621,8 @@ void btHingeConstraint::getInfo2 (btConstraintInfo2* info) btScalar bounce = m_relaxationFactor; if(bounce > btScalar(0.0)) { - btScalar vel = m_rbA.getAngularVelocity().dot(ax1); - vel -= m_rbB.getAngularVelocity().dot(ax1); + btScalar vel = angVelA.dot(ax1); + vel -= angVelB.dot(ax1); // only apply bounce if the velocity is incoming, and if the // resulting c[] exceeds what we already have. if(limit == 1) @@ -470,163 +655,6 @@ void btHingeConstraint::getInfo2 (btConstraintInfo2* info) -void btHingeConstraint::solveConstraintObsolete(btSolverBody& bodyA,btSolverBody& bodyB,btScalar timeStep) -{ - - ///for backwards compatibility during the transition to 'getInfo/getInfo2' - if (m_useSolveConstraintObsolete) - { - - btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_rbAFrame.getOrigin(); - btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_rbBFrame.getOrigin(); - - btScalar tau = btScalar(0.3); - - //linear part - if (!m_angularOnly) - { - btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition(); - btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition(); - - btVector3 vel1,vel2; - bodyA.getVelocityInLocalPointObsolete(rel_pos1,vel1); - bodyB.getVelocityInLocalPointObsolete(rel_pos2,vel2); - btVector3 vel = vel1 - vel2; - - for (int i=0;i<3;i++) - { - const btVector3& normal = m_jac[i].m_linearJointAxis; - btScalar jacDiagABInv = btScalar(1.) / m_jac[i].getDiagonal(); - - btScalar rel_vel; - rel_vel = normal.dot(vel); - //positional error (zeroth order error) - btScalar depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal - btScalar impulse = depth*tau/timeStep * jacDiagABInv - rel_vel * jacDiagABInv; - m_appliedImpulse += impulse; - btVector3 impulse_vector = normal * impulse; - btVector3 ftorqueAxis1 = rel_pos1.cross(normal); - btVector3 ftorqueAxis2 = rel_pos2.cross(normal); - bodyA.applyImpulse(normal*m_rbA.getInvMass(), m_rbA.getInvInertiaTensorWorld()*ftorqueAxis1,impulse); - bodyB.applyImpulse(normal*m_rbB.getInvMass(), m_rbB.getInvInertiaTensorWorld()*ftorqueAxis2,-impulse); - } - } - - - { - ///solve angular part - - // get axes in world space - btVector3 axisA = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(2); - btVector3 axisB = getRigidBodyB().getCenterOfMassTransform().getBasis() * m_rbBFrame.getBasis().getColumn(2); - - btVector3 angVelA; - bodyA.getAngularVelocity(angVelA); - btVector3 angVelB; - bodyB.getAngularVelocity(angVelB); - - btVector3 angVelAroundHingeAxisA = axisA * axisA.dot(angVelA); - btVector3 angVelAroundHingeAxisB = axisB * axisB.dot(angVelB); - - btVector3 angAorthog = angVelA - angVelAroundHingeAxisA; - btVector3 angBorthog = angVelB - angVelAroundHingeAxisB; - btVector3 velrelOrthog = angAorthog-angBorthog; - { - - - //solve orthogonal angular velocity correction - btScalar relaxation = btScalar(1.); - btScalar len = velrelOrthog.length(); - if (len > btScalar(0.00001)) - { - btVector3 normal = velrelOrthog.normalized(); - btScalar denom = getRigidBodyA().computeAngularImpulseDenominator(normal) + - getRigidBodyB().computeAngularImpulseDenominator(normal); - // scale for mass and relaxation - //velrelOrthog *= (btScalar(1.)/denom) * m_relaxationFactor; - - bodyA.applyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*velrelOrthog,-(btScalar(1.)/denom)); - bodyB.applyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*velrelOrthog,(btScalar(1.)/denom)); - - } - - //solve angular positional correction - btVector3 angularError = axisA.cross(axisB) *(btScalar(1.)/timeStep); - btScalar len2 = angularError.length(); - if (len2>btScalar(0.00001)) - { - btVector3 normal2 = angularError.normalized(); - btScalar denom2 = getRigidBodyA().computeAngularImpulseDenominator(normal2) + - getRigidBodyB().computeAngularImpulseDenominator(normal2); - //angularError *= (btScalar(1.)/denom2) * relaxation; - - bodyA.applyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*angularError,(btScalar(1.)/denom2)); - bodyB.applyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*angularError,-(btScalar(1.)/denom2)); - - } - - - - - - // solve limit - if (m_solveLimit) - { - btScalar amplitude = ( (angVelB - angVelA).dot( axisA )*m_relaxationFactor + m_correction* (btScalar(1.)/timeStep)*m_biasFactor ) * m_limitSign; - - btScalar impulseMag = amplitude * m_kHinge; - - // Clamp the accumulated impulse - btScalar temp = m_accLimitImpulse; - m_accLimitImpulse = btMax(m_accLimitImpulse + impulseMag, btScalar(0) ); - impulseMag = m_accLimitImpulse - temp; - - - - bodyA.applyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*axisA,impulseMag * m_limitSign); - bodyB.applyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*axisA,-(impulseMag * m_limitSign)); - - } - } - - //apply motor - if (m_enableAngularMotor) - { - //todo: add limits too - btVector3 angularLimit(0,0,0); - - btVector3 velrel = angVelAroundHingeAxisA - angVelAroundHingeAxisB; - btScalar projRelVel = velrel.dot(axisA); - - btScalar desiredMotorVel = m_motorTargetVelocity; - btScalar motor_relvel = desiredMotorVel - projRelVel; - - btScalar unclippedMotorImpulse = m_kHinge * motor_relvel;; - - // accumulated impulse clipping: - btScalar fMaxImpulse = m_maxMotorImpulse; - btScalar newAccImpulse = m_accMotorImpulse + unclippedMotorImpulse; - btScalar clippedMotorImpulse = unclippedMotorImpulse; - if (newAccImpulse > fMaxImpulse) - { - newAccImpulse = fMaxImpulse; - clippedMotorImpulse = newAccImpulse - m_accMotorImpulse; - } - else if (newAccImpulse < -fMaxImpulse) - { - newAccImpulse = -fMaxImpulse; - clippedMotorImpulse = newAccImpulse - m_accMotorImpulse; - } - m_accMotorImpulse += clippedMotorImpulse; - - bodyA.applyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*axisA,clippedMotorImpulse); - bodyB.applyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*axisA,-clippedMotorImpulse); - - } - } - } - -} @@ -637,12 +665,16 @@ void btHingeConstraint::updateRHS(btScalar timeStep) } - btScalar btHingeConstraint::getHingeAngle() { - const btVector3 refAxis0 = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(0); - const btVector3 refAxis1 = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(1); - const btVector3 swingAxis = getRigidBodyB().getCenterOfMassTransform().getBasis() * m_rbBFrame.getBasis().getColumn(1); + return getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); +} + +btScalar btHingeConstraint::getHingeAngle(const btTransform& transA,const btTransform& transB) +{ + const btVector3 refAxis0 = transA.getBasis() * m_rbAFrame.getBasis().getColumn(0); + const btVector3 refAxis1 = transA.getBasis() * m_rbAFrame.getBasis().getColumn(1); + const btVector3 swingAxis = transB.getBasis() * m_rbBFrame.getBasis().getColumn(1); btScalar angle = btAtan2Fast(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1)); return m_referenceSign * angle; } @@ -676,10 +708,10 @@ void btHingeConstraint::testLimit() #else -void btHingeConstraint::testLimit() +void btHingeConstraint::testLimit(const btTransform& transA,const btTransform& transB) { // Compute limit information - m_hingeAngle = getHingeAngle(); + m_hingeAngle = getHingeAngle(transA,transB); m_correction = btScalar(0.); m_limitSign = btScalar(0.); m_solveLimit = false; @@ -741,7 +773,7 @@ void btHingeConstraint::setMotorTarget(btScalar targetAngle, btScalar dt) } // compute angular velocity - btScalar curAngle = getHingeAngle(); + btScalar curAngle = getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); btScalar dAngle = targetAngle - curAngle; m_motorTargetVelocity = dAngle / dt; } diff --git a/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h b/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h index 6c5badeb0..ce11d388a 100644 --- a/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h +++ b/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h @@ -26,7 +26,7 @@ class btRigidBody; /// hinge constraint between two rigidbodies each with a pivotpoint that descibes the axis location in local space /// axis defines the orientation of the hinge axis -class btHingeConstraint : public btTypedConstraint +ATTRIBUTE_ALIGNED16(class) btHingeConstraint : public btTypedConstraint { #ifdef IN_PARALLELL_SOLVER public: @@ -81,8 +81,12 @@ public: virtual void getInfo1 (btConstraintInfo1* info); + void getInfo1NonVirtual(btConstraintInfo1* info); + virtual void getInfo2 (btConstraintInfo2* info); - + + void getInfo2NonVirtual(btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB); + virtual void solveConstraintObsolete(btSolverBody& bodyA,btSolverBody& bodyB,btScalar timeStep); void updateRHS(btScalar timeStep); @@ -174,7 +178,9 @@ public: btScalar getHingeAngle(); - void testLimit(); + btScalar getHingeAngle(const btTransform& transA,const btTransform& transB); + + void testLimit(const btTransform& transA,const btTransform& transB); const btTransform& getAFrame() const { return m_rbAFrame; }; diff --git a/src/BulletDynamics/ConstraintSolver/btJacobianEntry.h b/src/BulletDynamics/ConstraintSolver/btJacobianEntry.h index bfeb24c2d..22a8af66b 100644 --- a/src/BulletDynamics/ConstraintSolver/btJacobianEntry.h +++ b/src/BulletDynamics/ConstraintSolver/btJacobianEntry.h @@ -28,7 +28,7 @@ subject to the following restrictions: /// Jacobian entry is an abstraction that allows to describe constraints /// it can be used in combination with a constraint solver /// Can be used to relate the effect of an impulse to the constraint error -class btJacobianEntry +ATTRIBUTE_ALIGNED16(class) btJacobianEntry { public: btJacobianEntry() {}; diff --git a/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp b/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp index 1da749517..0c58b907d 100644 --- a/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp +++ b/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp @@ -43,6 +43,7 @@ m_useSolveConstraintObsolete(false) void btPoint2PointConstraint::buildJacobian() { + ///we need it for both methods { m_appliedImpulse = btScalar(0.); @@ -66,10 +67,15 @@ void btPoint2PointConstraint::buildJacobian() } } + } - void btPoint2PointConstraint::getInfo1 (btConstraintInfo1* info) +{ + getInfo1NonVirtual(info); +} + +void btPoint2PointConstraint::getInfo1NonVirtual (btConstraintInfo1* info) { if (m_useSolveConstraintObsolete) { @@ -82,22 +88,26 @@ void btPoint2PointConstraint::getInfo1 (btConstraintInfo1* info) } } + + + void btPoint2PointConstraint::getInfo2 (btConstraintInfo2* info) +{ + getInfo2NonVirtual(info, m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); +} + +void btPoint2PointConstraint::getInfo2NonVirtual (btConstraintInfo2* info, const btTransform& body0_trans, const btTransform& body1_trans) { btAssert(!m_useSolveConstraintObsolete); //retrieve matrices - btTransform body0_trans; - body0_trans = m_rbA.getCenterOfMassTransform(); - btTransform body1_trans; - body1_trans = m_rbB.getCenterOfMassTransform(); // anchor points in global coordinates with respect to body PORs. // set jacobian info->m_J1linearAxis[0] = 1; - info->m_J1linearAxis[info->rowskip+1] = 1; - info->m_J1linearAxis[2*info->rowskip+2] = 1; + info->m_J1linearAxis[info->rowskip+1] = 1; + info->m_J1linearAxis[2*info->rowskip+2] = 1; btVector3 a1 = body0_trans.getBasis()*getPivotInA(); { @@ -150,6 +160,7 @@ void btPoint2PointConstraint::getInfo2 (btConstraintInfo2* info) void btPoint2PointConstraint::solveConstraintObsolete(btSolverBody& bodyA,btSolverBody& bodyB,btScalar timeStep) { + if (m_useSolveConstraintObsolete) { btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_pivotInA; @@ -220,6 +231,7 @@ void btPoint2PointConstraint::solveConstraintObsolete(btSolverBody& bodyA,btSolv normal[i] = 0; } } + } void btPoint2PointConstraint::updateRHS(btScalar timeStep) diff --git a/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h b/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h index e2b865cd4..dcc194068 100644 --- a/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h +++ b/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h @@ -36,7 +36,7 @@ struct btConstraintSetting }; /// point to point constraint between two rigidbodies each with a pivotpoint that descibes the 'ballsocket' location in local space -class btPoint2PointConstraint : public btTypedConstraint +ATTRIBUTE_ALIGNED16(class) btPoint2PointConstraint : public btTypedConstraint { #ifdef IN_PARALLELL_SOLVER public: @@ -65,8 +65,11 @@ public: virtual void getInfo1 (btConstraintInfo1* info); + void getInfo1NonVirtual (btConstraintInfo1* info); + virtual void getInfo2 (btConstraintInfo2* info); + void getInfo2NonVirtual (btConstraintInfo2* info, const btTransform& body0_trans, const btTransform& body1_trans); virtual void solveConstraintObsolete(btSolverBody& bodyA,btSolverBody& bodyB,btScalar timeStep); diff --git a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h index 321930be9..2ec39251e 100644 --- a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h +++ b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h @@ -22,7 +22,7 @@ class btIDebugDraw; #include "btSolverBody.h" #include "btSolverConstraint.h" #include "btTypedConstraint.h" - +#include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h" ///The btSequentialImpulseConstraintSolver is a fast SIMD implementation of the Projected Gauss Seidel (iterative LCP) method. class btSequentialImpulseConstraintSolver : public btConstraintSolver diff --git a/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp b/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp index 6e59a4c6a..76b982c7c 100755 --- a/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp +++ b/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp @@ -126,6 +126,7 @@ void btSliderConstraint::buildJacobian() void btSliderConstraint::buildJacobianInt(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB) { +#ifndef __SPU__ //calculate transforms m_calculatedTransformA = rbA.getCenterOfMassTransform() * frameInA; m_calculatedTransformB = rbB.getCenterOfMassTransform() * frameInB; @@ -175,10 +176,10 @@ void btSliderConstraint::buildJacobianInt(btRigidBody& rbA, btRigidBody& rbB, co // clear accumulator for motors m_accumulatedLinMotorImpulse = btScalar(0.0); m_accumulatedAngMotorImpulse = btScalar(0.0); +#endif //__SPU__ } - void btSliderConstraint::getInfo1(btConstraintInfo1* info) { if (m_useSolveConstraintObsolete) @@ -191,7 +192,7 @@ void btSliderConstraint::getInfo1(btConstraintInfo1* info) info->m_numConstraintRows = 4; // Fixed 2 linear + 2 angular info->nub = 2; //prepare constraint - calculateTransforms(); + calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); testLinLimits(); if(getSolveLinLimit() || getPoweredLinMotor()) { @@ -207,14 +208,34 @@ void btSliderConstraint::getInfo1(btConstraintInfo1* info) } } +void btSliderConstraint::getInfo1NonVirtual(btConstraintInfo1* info) +{ + info->m_numConstraintRows = 6; // Fixed 2 linear + 2 angular + 1 limit (even if not used) + info->nub = 0; +} void btSliderConstraint::getInfo2(btConstraintInfo2* info) { - btAssert(!m_useSolveConstraintObsolete); - int i, s = info->rowskip; const btTransform& trA = getCalculatedTransformA(); const btTransform& trB = getCalculatedTransformB(); + + getInfo2NonVirtual(info,m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(), m_rbA.getLinearVelocity(),m_rbB.getLinearVelocity(), m_rbA.getInvMass(),m_rbB.getInvMass()); +} + +void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB, const btVector3& linVelA,const btVector3& linVelB, btScalar rbAinvMass,btScalar rbBinvMass ) +{ + //prepare constraint + calculateTransforms(transA,transB); + testLinLimits(); + testAngLimits(); + + const btTransform& trA = getCalculatedTransformA(); + const btTransform& trB = getCalculatedTransformB(); + + btAssert(!m_useSolveConstraintObsolete); + int i, s = info->rowskip; + btScalar signFact = m_useLinearReferenceFrameA ? btScalar(1.0f) : btScalar(-1.0f); // make rotations around Y and Z equal // the slider axis should be the only unconstrained @@ -269,12 +290,12 @@ void btSliderConstraint::getInfo2(btConstraintInfo2* info) // result in three equations, so we project along the planespace vectors // so that sliding along the slider axis is disregarded. for symmetry we // also consider rotation around center of mass of two bodies (factA and factB). - btTransform bodyA_trans = m_rbA.getCenterOfMassTransform(); - btTransform bodyB_trans = m_rbB.getCenterOfMassTransform(); + btTransform bodyA_trans = transA; + btTransform bodyB_trans = transB; int s2 = 2 * s, s3 = 3 * s; btVector3 c; - btScalar miA = m_rbA.getInvMass(); - btScalar miB = m_rbB.getInvMass(); + btScalar miA = rbAinvMass; + btScalar miB = rbBinvMass; btScalar miS = miA + miB; btScalar factA, factB; if(miS > btScalar(0.f)) @@ -389,8 +410,8 @@ void btSliderConstraint::getInfo2(btConstraintInfo2* info) btScalar bounce = btFabs(btScalar(1.0) - getDampingLimLin()); if(bounce > btScalar(0.0)) { - btScalar vel = m_rbA.getLinearVelocity().dot(ax1); - vel -= m_rbB.getLinearVelocity().dot(ax1); + btScalar vel = linVelA.dot(ax1); + vel -= linVelB.dot(ax1); vel *= signFact; // only apply bounce if the velocity is incoming, and if the // resulting c[] exceeds what we already have. @@ -539,6 +560,7 @@ void btSliderConstraint::solveConstraintObsolete(btSolverBody& bodyA,btSolverBod void btSliderConstraint::solveConstraintInt(btRigidBody& rbA, btSolverBody& bodyA,btRigidBody& rbB, btSolverBody& bodyB) { +#ifndef __SPU__ int i; // linear btVector3 velA; @@ -719,22 +741,24 @@ void btSliderConstraint::solveConstraintInt(btRigidBody& rbA, btSolverBody& body bodyB.applyImpulse(btVector3(0,0,0), rbB.getInvInertiaTensorWorld()*axisA,-angImpulse); } } +#endif //__SPU__ } -void btSliderConstraint::calculateTransforms(void){ +void btSliderConstraint::calculateTransforms(const btTransform& transA,const btTransform& transB) +{ if(m_useLinearReferenceFrameA || (!m_useSolveConstraintObsolete)) { - m_calculatedTransformA = m_rbA.getCenterOfMassTransform() * m_frameInA; - m_calculatedTransformB = m_rbB.getCenterOfMassTransform() * m_frameInB; + m_calculatedTransformA = transA * m_frameInA; + m_calculatedTransformB = transB * m_frameInB; } else { - m_calculatedTransformA = m_rbB.getCenterOfMassTransform() * m_frameInB; - m_calculatedTransformB = m_rbA.getCenterOfMassTransform() * m_frameInA; + m_calculatedTransformA = transB * m_frameInB; + m_calculatedTransformB = transA * m_frameInA; } m_realPivotAInW = m_calculatedTransformA.getOrigin(); m_realPivotBInW = m_calculatedTransformB.getOrigin(); diff --git a/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h b/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h index 499c3bd3f..57b0ed062 100755 --- a/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h +++ b/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h @@ -131,9 +131,13 @@ public: // overrides virtual void buildJacobian(); virtual void getInfo1 (btConstraintInfo1* info); + + void getInfo1NonVirtual(btConstraintInfo1* info); virtual void getInfo2 (btConstraintInfo2* info); + void getInfo2NonVirtual(btConstraintInfo2* info, const btTransform& transA, const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB, btScalar rbAinvMass,btScalar rbBinvMass); + virtual void solveConstraintObsolete(btSolverBody& bodyA,btSolverBody& bodyB,btScalar timeStep); @@ -215,13 +219,13 @@ public: void buildJacobianInt(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB); void solveConstraintInt(btRigidBody& rbA, btSolverBody& bodyA,btRigidBody& rbB, btSolverBody& bodyB); // shared code used by ODE solver - void calculateTransforms(void); - void testLinLimits(void); + void calculateTransforms(const btTransform& transA,const btTransform& transB); + void testLinLimits(); void testLinLimits2(btConstraintInfo2* info); - void testAngLimits(void); + void testAngLimits(); // access for PE Solver - btVector3 getAncorInA(void); - btVector3 getAncorInB(void); + btVector3 getAncorInA(); + btVector3 getAncorInB(); }; diff --git a/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h b/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h index 4fbca04aa..6c9179378 100644 --- a/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h +++ b/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h @@ -30,7 +30,8 @@ enum btTypedConstraintType HINGE_CONSTRAINT_TYPE, CONETWIST_CONSTRAINT_TYPE, D6_CONSTRAINT_TYPE, - SLIDER_CONSTRAINT_TYPE + SLIDER_CONSTRAINT_TYPE, + CONTACT_CONSTRAINT_TYPE }; ///TypedConstraint is the baseclass for Bullet constraints and vehicles diff --git a/src/BulletMultiThreaded/SequentialThreadSupport.h b/src/BulletMultiThreaded/SequentialThreadSupport.h index 031de7ea9..4256ebd2a 100644 --- a/src/BulletMultiThreaded/SequentialThreadSupport.h +++ b/src/BulletMultiThreaded/SequentialThreadSupport.h @@ -81,6 +81,11 @@ public: virtual void setNumTasks(int numTasks); + virtual int getNumTasks() const + { + return 1; + } + }; #endif //SEQUENTIAL_THREAD_SUPPORT_H diff --git a/src/BulletMultiThreaded/Win32ThreadSupport.cpp b/src/BulletMultiThreaded/Win32ThreadSupport.cpp index 32bfbac3e..f934a8035 100644 --- a/src/BulletMultiThreaded/Win32ThreadSupport.cpp +++ b/src/BulletMultiThreaded/Win32ThreadSupport.cpp @@ -183,6 +183,8 @@ void Win32ThreadSupport::startThreads(const Win32ThreadConstructionInfo& threadC m_activeSpuStatus.resize(threadConstructionInfo.m_numThreads); m_completeHandles.resize(threadConstructionInfo.m_numThreads); + m_maxNumTasks = threadConstructionInfo.m_numThreads; + for (int i=0;i