diff options
| author | root <root@dc13.lemmi> | 2020-07-21 10:00:46 +0200 |
|---|---|---|
| committer | root <root@dc13.lemmi> | 2020-07-21 10:00:46 +0200 |
| commit | 1192c4575ea7afdf38e3fa0df4587a08620af11e (patch) | |
| tree | 6910a62487c282d0840d2e668aa7eb40b7c8a3fd /project/src/lib-kmp-diff.c | |
| parent | 76de8a89f7c1d1b4522eb66e8f89d248e8c1781f (diff) | |
SZS v2.18a
Diffstat (limited to 'project/src/lib-kmp-diff.c')
| -rwxr-xr-x | project/src/lib-kmp-diff.c | 2788 |
1 files changed, 2788 insertions, 0 deletions
diff --git a/project/src/lib-kmp-diff.c b/project/src/lib-kmp-diff.c new file mode 100755 index 0000000..b242bf9 --- /dev/null +++ b/project/src/lib-kmp-diff.c @@ -0,0 +1,2788 @@ + +/*************************************************************************** + * _______ _______ _______ * + * | ___ |____ | ___ | * + * | | |_| / /| | |_| * + * | |_____ / / | |_____ * + * |_____ | / / |_____ | * + * _ | | / / _ | | * + * | |___| |/ /____| |___| | * + * |_______|_______|_______| * + * * + * Wiimms SZS Tools * + * https://szs.wiimm.de/ * + * * + *************************************************************************** + * * + * This file is part of the SZS project. * + * Visit https://szs.wiimm.de/ for project details and sources. * + * * + * Copyright (c) 2011-2020 by Dirk Clemens <wiimm@wiimm.de> * + * * + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt * + * * + ***************************************************************************/ + +#include "lib-kmp.h" +//#include "lib-szs.h" +//#include "dclib-xdump.h" + +#include <stddef.h> + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// definitions /////////////// +/////////////////////////////////////////////////////////////////////////////// + +#define COL_OK reset +#define COL_HINT yellow +#define COL_WARN red +#define COL_DIFF magenta +#define COL_SRC1 cyan +#define COL_SRC2 b_blue + +#define OK_WARN0(a,b,n) a->n == b->n ? ok : warn +#define OK_WARN1(a,b,n) a->n == b->n ? ok : warn, a->n + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// section_info_t /////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[section_info_t]] + +typedef struct section_info_t +{ + kmp_entry_t sect; // section to compare + + kmp_t *kmp1; // first kmp to compare + kmp_t *kmp2; // first kmp to compare + uint verbose; // 0:quiet, 1:summary only, 2:full report + + char sect_name[5]; // section name + char subject[16]; // subject for status messages +} +section_info_t; + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// helper functions /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void print_float + ( uint n, const float *f1, const float *f2, double epsilon ) +{ + while ( n-- > 0 ) + { + printf(" %s%11.3f", + *f1 == *f2 ? colout->COL_OK + : fabsf(*f1-*f2) > epsilon ? colout->COL_WARN : colout->COL_HINT, + *f1 ); + f1++; + f2++; + } +} + +//----------------------------------------------------------------------------- + +static void print_rot ( uint n, const float *f1, const float *f2 ) +{ + while ( n-- > 0 ) + { + printf(" %s%7.2f", + *f1 == *f2 ? colout->COL_OK + : fabsf(*f1-*f2) > epsilon_rot ? colout->COL_WARN : colout->COL_HINT, + *f1 ); + f1++; + f2++; + } +} + +//----------------------------------------------------------------------------- + +static void print_hex16 ( uint n, const u16 *u1, const u16 *u2 ) +{ + while ( n-- > 0 ) + { + printf(" %s%#6x", + *u1 == *u2 ? colout->COL_OK : colout->COL_WARN, *u1 ); + u1++; + u2++; + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// ph: helper for CKPH, ENPH, ITPH /////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[sort_ph_t]] + +typedef struct sort_ph_t +{ + int rank; // previous rank order + kmp_enph_entry_t data; // original object data + +} sort_ph_t; + +//----------------------------------------------------------------------------- + +static sort_ph_t * sort_ph ( const List_t *list ) +{ + DASSERT(list); + if (!list->used) + return 0; + + sort_ph_t *res = CALLOC(list->used,sizeof(*res)); + sort_ph_t *ptr = res; + kmp_enph_entry_t *e = (kmp_enph_entry_t*)list->list; + const uint n = list->used; + + uint i; + for ( i = 0; i < n; i++, e++, ptr++ ) + { + ptr->rank = i; + memcpy(&ptr->data,e,sizeof(ptr->data)); + } + + #if 0 + if ( n > 1 && KMP_DIFF_MODE & KDMD_SORT ) + qsort( res, n, sizeof(*res), (qsort_func)compare_sort_ph ); + #endif + return res; +} + +//----------------------------------------------------------------------------- + +static void print_ph + ( char mode, const kmp_enph_entry_t *p1, const kmp_enph_entry_t *p2 ) +{ + if ( p2 && colout->colorize ) + { + ccp ok = colout->COL_OK; + ccp warn = colout->COL_WARN; + + const uint end1 = p1->pt_start + p1->pt_len - 1; + const uint end2 = p2->pt_start + p2->pt_len - 1; + printf("%c %s%3u %s%3u %s%3u %s:", + mode, + p1->pt_start == p2->pt_start ? ok : warn, p1->pt_start, + end1 == end2 ? ok : colout->COL_HINT, end1, + p1->pt_len == p2->pt_len ? ok : warn, p1->pt_len, + colout->reset ); + + uint j; + const u8 *d1 = p1->prev; + const u8 *d2 = p2->prev; + for ( j = 0; j < 12; j++, d1++, d2++ ) + { + if ( j == 6 ) + printf(" %s:",colout->reset); + fputs( *d1 == *d2 ? ok : warn, stdout ); + if ( *d1 == 0xff ) + fputs(" -",stdout); + else + printf("%4u",*d1); + } + putchar('\n'); + } + else + { + printf("%c %3u %3u %3u :", + mode, p1->pt_start, p1->pt_start + p1->pt_len - 1, p1->pt_len ); + + uint j; + const u8 *d1 = p1->prev; + for ( j = 0; j < 12; j++, d1++ ) + { + if ( j == 6 ) + fputs(" :",stdout); + if ( *d1 == 0xff ) + fputs(" -",stdout); + else + printf("%4u",*d1); + } + putchar('\n'); + } +} + +//----------------------------------------------------------------------------- + +static sort_ph_t * print_ph_single ( const section_info_t *si, + char mode, const sort_ph_t *e, sort_ph_t *end ) +{ + DASSERT(si); + DASSERT(e); + DASSERT(end); + + while ( e < end ) + { + printf("%s%s: Only found in source %c @%u%s\n", + mode == '<' ? colout->COL_SRC1 : colout->COL_SRC2, + si->sect_name, mode == '<' ? '1' : '2', e->rank, + colout->reset ); + print_ph(mode,&e->data,0); + e++; + } + return (sort_ph_t*)e; +} + +//----------------------------------------------------------------------------- + +static int diff_ph ( const sort_ph_t *e1, const sort_ph_t *e2 ) +{ + if (!memcmp(&e1->data,&e2->data,sizeof(e1->data))) + return 0; + + uint count = ( e1->data.pt_start != e2->data.pt_start ) + + ( e1->data.pt_len != e2->data.pt_len ); + + if (memcmp(e1->data.prev,e2->data.prev,sizeof(e1->data.prev))) + count++; + if (memcmp(e1->data.next,e2->data.next,sizeof(e1->data.next))) + count++; + if (memcmp(e1->data.setting,e2->data.setting,sizeof(e1->data.setting))) + count++; + + return count; +} + +//----------------------------------------------------------------------------- + +static uint diff_ph_si ( const section_info_t *si ) +{ + DASSERT(si); + DASSERT(si->kmp1); + DASSERT(si->kmp2); + + uint diff_count = 0; + List_t *l1 = si->kmp1->dlist + si->sect; + List_t *l2 = si->kmp2->dlist + si->sect; + + if ( l1->used != l2->used ) + { + if (!si->verbose) + return 1; + printf("%s%s: Number of %s groups differ: Have %u and %u.%s\n", + colout->COL_DIFF, + si->sect_name, si->subject, l1->used, l2->used, + colout->reset ); + if (si->verbose==1) + return 1; + diff_count++; + } + + sort_ph_t *s1 = sort_ph(l1), *e1 = s1, *end1 = e1 + l1->used; + sort_ph_t *s2 = sort_ph(l2), *e2 = s2, *end2 = e2 + l2->used; + uint order_differ = 0; + + while ( e1 < end1 && e2 < end2 ) + { + const int stat = diff_ph(e1,e2); + if (stat) + { + if ( si->verbose < 2 ) + { + if (si->verbose) + printf("%s%s: Data differ%s\n", + colout->COL_DIFF, si->sect_name, colout->reset ); + return 1; + } + + const int trigger = 2; + if ( stat >= trigger ) + { + //--- try to sync + + int dist1 = 99999; + sort_ph_t *p1; + for ( p1 = e1+1; p1 < end1; p1++ ) + if ( diff_ph(p1,e2) < trigger ) + { + dist1 = p1 - e1; + break; + } + + int dist2 = 99999; + sort_ph_t *p2; + for ( p2 = e2+1; p2 < end2; p2++ ) + if ( diff_ph(p2,e1) < trigger ) + { + dist2 = p2 - e2; + break; + } + + PRINT0("DIST: %d %d\n",dist1,dist2); + + if ( dist1 < 99999 && dist1 < dist2 ) + { + e1 = print_ph_single(si,'<',e1,e1+1); + diff_count++; + continue; + } + else if ( dist2 < 99999 && dist2 < dist1 ) + { + e2 = print_ph_single(si,'>',e2,e2+1); + diff_count++; + continue; + } + } + + //--- print data + + printf("%s%s: %c%s group @%u:%u differ%s\n", + colout->COL_DIFF, + si->sect_name, + toupper((int)si->subject[0]), si->subject+1, + e1->rank, e2->rank, colout->reset ); + print_ph('<',&e1->data,&e2->data); + print_ph('>',&e2->data,&e1->data); + diff_count++; + } + + if ( e1->rank != e2->rank ) + order_differ++; + + e1++; + e2++; + } + + if ( e1 < end1 ) + { + print_ph_single(si,'<',e1,end1); + diff_count++; + } + + if ( e2 < end2 ) + { + print_ph_single(si,'>',e2,end2); + diff_count++; + } + + if (order_differ) + { + if (si->verbose) + printf("%s%s: Order of groups differ%s\n", + colout->COL_DIFF, si->sect_name, colout->reset ); + if ( si->verbose < 2 ) + return 1; + diff_count++; + } + + FREE(s1); + FREE(s2); + return diff_count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// pt: helper for ENPT, ITPT /////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[sort_pt_t]] + +typedef struct sort_pt_t +{ + int rank; // previous rank order + kmp_enpt_entry_t data; // original object data + +} sort_pt_t; + +//----------------------------------------------------------------------------- + +static sort_pt_t * sort_pt ( const List_t *list ) +{ + DASSERT(list); + if (!list->used) + return 0; + + sort_pt_t *res = CALLOC(list->used,sizeof(*res)); + sort_pt_t *ptr = res; + kmp_enpt_entry_t *e = (kmp_enpt_entry_t*)list->list; + const uint n = list->used; + + uint i; + for ( i = 0; i < n; i++, e++, ptr++ ) + { + ptr->rank = i; + memcpy(&ptr->data,e,sizeof(ptr->data)); + } + + #if 0 + if ( n > 1 && KMP_DIFF_MODE & KDMD_SORT ) + qsort( res, n, sizeof(*res), (qsort_func)compare_sort_pt ); + #endif + return res; +} + +//----------------------------------------------------------------------------- + +static void print_pt + ( char mode, const kmp_enpt_entry_t *p1, const kmp_enpt_entry_t *p2 ) +{ + if ( p2 && colout->colorize ) + { + ccp ok = colout->COL_OK; + ccp warn = colout->COL_WARN; + + putchar(mode); + putchar(' '); + print_float(3,p1->position,p2->position,epsilon_pos); + + printf(" %s%7.3f %s%#6x %s%#6x%s\n", + p1->scale == p2->scale ? ok + : fabsf(p1->scale-p2->scale) > epsilon_scale ? colout->COL_WARN + : colout->COL_HINT, + p1->scale, + p1->prop[0] == p2->prop[0] ? ok : warn, p1->prop[0], + p1->prop[1] == p2->prop[1] ? ok : warn, p1->prop[1], + colout->reset ); + } + else + { + printf("%c %11.3f %11.3f %11.3f %7.3f %#6x %#6x\n", + mode, + p1->position[0], p1->position[1], p1->position[2], + p1->scale, + p1->prop[0], p1->prop[1] ); + } +} + +//----------------------------------------------------------------------------- + +static sort_pt_t * print_pt_single ( const section_info_t *si, + char mode, const sort_pt_t *e, sort_pt_t *end ) +{ + DASSERT(si); + DASSERT(e); + DASSERT(end); + + while ( e < end ) + { + printf("%s%s: Only found in source %c @%u%s\n", + mode == '<' ? colout->COL_SRC1 : colout->COL_SRC2, + si->sect_name, mode == '<' ? '1' : '2', e->rank, + colout->reset ); + print_pt(mode,&e->data,0); + e++; + } + return (sort_pt_t*)e; +} + +//----------------------------------------------------------------------------- + +static int diff_pt ( const sort_pt_t *e1, const sort_pt_t *e2 ) +{ + if (!memcmp(&e1->data,&e2->data,sizeof(e1->data))) + return 0; + + uint count = ( e1->data.prop[0] != e2->data.prop[0] ) + + ( e1->data.prop[1] != e2->data.prop[1] ); + + count += fabsf( e1->data.position[0] - e2->data.position[0] ) > epsilon_pos + || fabsf( e1->data.position[1] - e2->data.position[1] ) > epsilon_pos + || fabsf( e1->data.position[2] - e2->data.position[2] ) > epsilon_pos; + + count += fabsf( e1->data.scale - e2->data.scale ) > epsilon_scale; + return count; +} + +//----------------------------------------------------------------------------- + +static uint diff_pt_si ( const section_info_t *si ) +{ + DASSERT(si); + DASSERT(si->kmp1); + DASSERT(si->kmp2); + + uint diff_count = 0; + List_t *l1 = si->kmp1->dlist + si->sect; + List_t *l2 = si->kmp2->dlist + si->sect; + + if ( l1->used != l2->used ) + { + if (!si->verbose) + return 1; + printf("%s%s: Number of %ss differ: Have %u and %u.%s\n", + colout->COL_DIFF, + si->sect_name, si->subject, l1->used, l2->used, + colout->reset ); + if (si->verbose==1) + return 1; + diff_count++; + } + + sort_pt_t *s1 = sort_pt(l1), *e1 = s1, *end1 = e1 + l1->used; + sort_pt_t *s2 = sort_pt(l2), *e2 = s2, *end2 = e2 + l2->used; + uint order_differ = 0; + + while ( e1 < end1 && e2 < end2 ) + { + const int stat = diff_pt(e1,e2); + if (stat) + { + if ( si->verbose < 2 ) + { + if (si->verbose) + printf("%s%s: Data differ%s\n", + colout->COL_DIFF, si->sect_name, colout->reset ); + return 1; + } + + const int trigger = 2; + if ( stat >= trigger ) + { + //--- try to sync + + int dist1 = 99999; + sort_pt_t *p1; + for ( p1 = e1+1; p1 < end1; p1++ ) + if ( diff_pt(p1,e2) < trigger ) + { + dist1 = p1 - e1; + break; + } + + int dist2 = 99999; + sort_pt_t *p2; + for ( p2 = e2+1; p2 < end2; p2++ ) + if ( diff_pt(p2,e1) < trigger ) + { + dist2 = p2 - e2; + break; + } + + PRINT0("DIST: %d %d\n",dist1,dist2); + + if ( dist1 < 99999 && dist1 < dist2 ) + { + e1 = print_pt_single(si,'<',e1,e1+1); + diff_count++; + continue; + } + else if ( dist2 < 99999 && dist2 < dist1 ) + { + e2 = print_pt_single(si,'>',e2,e2+1); + diff_count++; + continue; + } + } + + //--- print data + + printf("%s%s: %s @%u:%u differ%s\n", + colout->COL_DIFF, + si->sect_name, si->subject, + e1->rank, e2->rank, colout->reset ); + print_pt('<',&e1->data,&e2->data); + print_pt('>',&e2->data,&e1->data); + diff_count++; + } + + if ( e1->rank != e2->rank ) + order_differ++; + + e1++; + e2++; + } + + if ( e1 < end1 ) + { + print_pt_single(si,'<',e1,end1); + diff_count++; + } + + if ( e2 < end2 ) + { + print_pt_single(si,'>',e2,end2); + diff_count++; + } + + if (order_differ) + { + if (si->verbose) + printf("%s%s: Order of %ss differ%s\n", + colout->COL_DIFF, si->sect_name, + si->subject, colout->reset ); + if ( si->verbose < 2 ) + return 1; + diff_count++; + } + + FREE(s1); + FREE(s2); + return diff_count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// pt2: helper for CNPT, JGPT, MSPT /////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[sort_pt2_t]] + +typedef struct sort_pt2_t +{ + int rank; // previous rank order + kmp_jgpt_entry_t data; // original object data + +} sort_pt2_t; + +//----------------------------------------------------------------------------- + +static sort_pt2_t * sort_pt2 ( const List_t *list ) +{ + DASSERT(list); + if (!list->used) + return 0; + + sort_pt2_t *res = CALLOC(list->used,sizeof(*res)); + sort_pt2_t *ptr = res; + kmp_jgpt_entry_t *e = (kmp_jgpt_entry_t*)list->list; + const uint n = list->used; + + uint i; + for ( i = 0; i < n; i++, e++, ptr++ ) + { + ptr->rank = i; + memcpy(&ptr->data,e,sizeof(ptr->data)); + } + + #if 0 + if ( n > 1 && KMP_DIFF_MODE & KDMD_SORT ) + qsort( res, n, sizeof(*res), (qsort_func)compare_sort_pt2 ); + #endif + return res; +} + +//----------------------------------------------------------------------------- + +static void print_pt2 + ( char mode, const kmp_jgpt_entry_t *p1, const kmp_jgpt_entry_t *p2 ) +{ + if ( p2 && colout->colorize ) + { + ccp ok = colout->COL_OK; + + putchar(mode); + print_float(3,p1->position,p2->position,epsilon_pos); + putchar(' '); + print_rot(3,p1->rotation,p2->rotation); + + printf(" %s%6d %s%#6x%s\n", + p1->id == p2->id ? ok : colout->COL_HINT, p1->id, + p1->effect == p2->effect ? ok : colout->COL_WARN, p1->effect, + colout->reset ); + } + else + { + printf("%c %11.3f %11.3f %11.3f %7.2f %7.2f %7.2f %6d %#6x\n", + mode, + p1->position[0], p1->position[1], p1->position[2], + p1->rotation[0], p1->rotation[1], p1->rotation[2], + p1->id, p1->effect ); + } +} + +//----------------------------------------------------------------------------- + +static sort_pt2_t * print_pt2_single ( const section_info_t *si, + char mode, const sort_pt2_t *e, sort_pt2_t *end ) +{ + DASSERT(si); + DASSERT(e); + DASSERT(end); + + while ( e < end ) + { + printf("%s%s: Only found in source %c @%u%s\n", + mode == '<' ? colout->COL_SRC1 : colout->COL_SRC2, + si->sect_name, mode == '<' ? '1' : '2', e->rank, + colout->reset ); + print_pt2(mode,&e->data,0); + e++; + } + return (sort_pt2_t*)e; +} + +//----------------------------------------------------------------------------- + +static int diff_pt2 ( const sort_pt2_t *e1, const sort_pt2_t *e2 ) +{ + if (!memcmp(&e1->data,&e2->data,sizeof(e1->data))) + return 0; + + // 'data.id' ignored! + uint count = e1->data.effect != e2->data.effect; + + count += fabsf( e1->data.position[0] - e2->data.position[0] ) > epsilon_pos + || fabsf( e1->data.position[1] - e2->data.position[1] ) > epsilon_pos + || fabsf( e1->data.position[2] - e2->data.position[2] ) > epsilon_pos; + + count += fabsf( e1->data.rotation[0] - e2->data.rotation[0] ) > epsilon_rot + || fabsf( e1->data.rotation[1] - e2->data.rotation[1] ) > epsilon_rot + || fabsf( e1->data.rotation[2] - e2->data.rotation[2] ) > epsilon_rot; + + return count; +} + +//----------------------------------------------------------------------------- + +static uint diff_pt2_si ( const section_info_t *si ) +{ + DASSERT(si); + DASSERT(si->kmp1); + DASSERT(si->kmp2); + + uint diff_count = 0; + List_t *l1 = si->kmp1->dlist + si->sect; + List_t *l2 = si->kmp2->dlist + si->sect; + + if ( l1->used != l2->used ) + { + if (!si->verbose) + return 1; + printf("%s%s: Number of %s points differ: Have %u and %u.%s\n", + colout->COL_DIFF, + si->sect_name, si->subject, l1->used, l2->used, + colout->reset ); + if (si->verbose==1) + return 1; + diff_count++; + } + + sort_pt2_t *s1 = sort_pt2(l1), *e1 = s1, *end1 = e1 + l1->used; + sort_pt2_t *s2 = sort_pt2(l2), *e2 = s2, *end2 = e2 + l2->used; + uint order_differ = 0; + + while ( e1 < end1 && e2 < end2 ) + { + const int stat = diff_pt2(e1,e2); + if (stat) + { + if ( si->verbose < 2 ) + { + if (si->verbose) + printf("%s%s: Data differ%s\n", + colout->COL_DIFF, si->sect_name, colout->reset ); + return 1; + } + + const int trigger = 2; + if ( stat >= trigger ) + { + //--- try to sync + + int dist1 = 99999; + sort_pt2_t *p1; + for ( p1 = e1+1; p1 < end1; p1++ ) + if ( diff_pt2(p1,e2) < trigger ) + { + dist1 = p1 - e1; + break; + } + + int dist2 = 99999; + sort_pt2_t *p2; + for ( p2 = e2+1; p2 < end2; p2++ ) + if ( diff_pt2(p2,e1) < trigger ) + { + dist2 = p2 - e2; + break; + } + + PRINT0("DIST: %d %d\n",dist1,dist2); + + if ( dist1 < 99999 && dist1 < dist2 ) + { + e1 = print_pt2_single(si,'<',e1,e1+1); + diff_count++; + continue; + } + else if ( dist2 < 99999 && dist2 < dist1 ) + { + e2 = print_pt2_single(si,'>',e2,e2+1); + diff_count++; + continue; + } + } + + //--- print data + + printf("%s%s: %s group @%u:%u differ%s\n", + colout->COL_DIFF, + si->sect_name, si->subject, + e1->rank, e2->rank, colout->reset ); + print_pt2('<',&e1->data,&e2->data); + print_pt2('>',&e2->data,&e1->data); + diff_count++; + } + + if ( e1->rank != e2->rank ) + order_differ++; + + e1++; + e2++; + } + + if ( e1 < end1 ) + { + print_pt2_single(si,'<',e1,end1); + diff_count++; + } + + if ( e2 < end2 ) + { + print_pt2_single(si,'>',e2,end2); + diff_count++; + } + + if (order_differ) + { + if (si->verbose) + printf("%s%s: Order of %s points differ%s\n", + colout->COL_DIFF, si->sect_name, + si->subject, colout->reset ); + if ( si->verbose < 2 ) + return 1; + diff_count++; + } + + FREE(s1); + FREE(s2); + return diff_count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_AREA() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +typedef struct sort_area_t +{ + int rank; // previous rank order + kmp_area_entry_t data; // original object data + +} sort_area_t; + +//----------------------------------------------------------------------------- + +static sort_area_t * sort_area ( const List_t *list ) +{ + DASSERT(list); + if (!list->used) + return 0; + + sort_area_t *res = CALLOC(list->used,sizeof(*res)); + sort_area_t *ptr = res; + kmp_area_entry_t *e = (kmp_area_entry_t*)list->list; + const uint n = list->used; + + uint i; + for ( i = 0; i < n; i++, e++, ptr++ ) + { + ptr->rank = i; + memcpy(&ptr->data,e,sizeof(ptr->data)); + } + + #if 0 + if ( n > 1 && KMP_DIFF_MODE & KDMD_SORT ) + qsort( res, n, sizeof(*res), (qsort_func)compare_sort_area ); + #endif + return res; +} + +//----------------------------------------------------------------------------- + +static void print_area + ( char mode, const kmp_area_entry_t *e1, const kmp_area_entry_t *e2 ) +{ + if ( e2 && colout->colorize ) + { + ccp ok = colout->COL_OK; + ccp warn = colout->COL_WARN; + + printf("%c %s%5u %s%5u", + mode, OK_WARN1(e1,e2,mode), OK_WARN1(e1,e2,type) ); + print_float(3,e1->position,e2->position,epsilon_pos); + putchar(' '); + print_hex16(4,e1->setting,e2->setting); + + printf("%s\n%c %s%5u %s%5u", + colout->reset, mode, + OK_WARN1(e1,e2,dest_id), OK_WARN1(e1,e2,unknown) ); + print_float(3,e1->rotation,e2->rotation,epsilon_rot); + + printf("%s\n%-14c", colout->reset, mode ); + print_float(3,e1->scale,e2->scale,epsilon_scale); + + printf("%s\n",colout->reset); + } + else + { + printf( "%c %5u %5u %11.3f %11.3f %11.3f %#6x %#6x %#6x %#6x\n" + "%c %5u %5u %11.3f %11.3f %11.3f\n" + "%c %24.3f %11.3f %11.3f\n", + mode, + e1->mode, e1->type, + e1->position[0], e1->position[1], e1->position[2], + e1->setting[0], e1->setting[1], e1->setting[2], e1->setting[3], + mode, + e1->dest_id, e1->unknown, + e1->rotation[0], e1->rotation[1], e1->rotation[2], + mode, + e1->scale[0], e1->scale[1], e1->scale[2] ); + } +} + +//----------------------------------------------------------------------------- + +static sort_area_t * print_area_single + ( char mode, const sort_area_t *e, sort_area_t *end ) +{ + DASSERT(e); + DASSERT(end); + + while ( e < end ) + { + printf("%sAREA: Only found in source %c @%u%s\n", + mode == '<' ? colout->COL_SRC1 : colout->COL_SRC2, + mode == '<' ? '1' : '2', e->rank, + colout->reset ); + print_area(mode,&e->data,0); + e++; + } + return (sort_area_t*)e; +} + +//----------------------------------------------------------------------------- + +static int diff_area ( const sort_area_t *e1, const sort_area_t *e2 ) +{ + if (!memcmp(&e1->data,&e2->data,sizeof(e1->data))) + return 0; + + uint count = ( e1->data.mode != e2->data.mode ) + + ( e1->data.type != e2->data.type ) + + ( e1->data.dest_id != e2->data.dest_id ) + + ( e1->data.unknown != e2->data.unknown ); + + uint i; + for ( i = 0; i < 4; i++ ) + count += e1->data.setting[i] != e2->data.setting[i]; + + count += fabsf( e1->data.position[0] - e2->data.position[0] ) > epsilon_pos + || fabsf( e1->data.position[1] - e2->data.position[1] ) > epsilon_pos + || fabsf( e1->data.position[2] - e2->data.position[2] ) > epsilon_pos; + + count += fabsf( e1->data.rotation[0] - e2->data.rotation[0] ) > epsilon_rot + || fabsf( e1->data.rotation[1] - e2->data.rotation[1] ) > epsilon_rot + || fabsf( e1->data.rotation[2] - e2->data.rotation[2] ) > epsilon_rot; + + count += fabsf( e1->data.scale[0] - e2->data.scale[0] ) > epsilon_scale + || fabsf( e1->data.scale[1] - e2->data.scale[1] ) > epsilon_scale + || fabsf( e1->data.scale[2] - e2->data.scale[2] ) > epsilon_scale; + + return count; +} + +//----------------------------------------------------------------------------- + +static uint diff_KMP_AREA +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + uint diff_count = 0; + List_t *l1 = kmp1->dlist + KMP_AREA; + List_t *l2 = kmp2->dlist + KMP_AREA; + + if ( l1->used != l2->used ) + { + if (!verbose) + return 1; + printf("%sAREA: Number of areas differ: Have %u and %u.%s\n", + colout->COL_WARN, l1->used, l2->used, colout->reset ); + if (verbose==1) + return 1; + diff_count++; + } + + sort_area_t *s1 = sort_area(l1), *e1 = s1, *end1 = e1 + l1->used; + sort_area_t *s2 = sort_area(l2), *e2 = s2, *end2 = e2 + l2->used; + uint order_differ = 0; + + while ( e1 < end1 && e2 < end2 ) + { + const int stat = diff_area(e1,e2); + if (stat) + { + if ( verbose < 2 ) + { + if (verbose) + printf("%sAREA: Data differ%s\n", + colout->COL_DIFF, colout->reset ); + return 1; + } + + const int trigger = 2; + if ( stat >= trigger ) + { + //--- try to sync + + int dist1 = 99999; + sort_area_t *p1; + for ( p1 = e1+1; p1 < end1; p1++ ) + if ( diff_area(p1,e2) < trigger ) + { + dist1 = p1 - e1; + break; + } + + int dist2 = 99999; + sort_area_t *p2; + for ( p2 = e2+1; p2 < end2; p2++ ) + if ( diff_area(p2,e1) < trigger ) + { + dist2 = p2 - e2; + break; + } + + PRINT0("DIST: %d %d\n",dist1,dist2); + + if ( dist1 < 99999 && dist1 < dist2 ) + { + e1 = print_area_single('<',e1,e1+1); + diff_count++; + continue; + } + else if ( dist2 < 99999 && dist2 < dist1 ) + { + e2 = print_area_single('>',e2,e2+1); + diff_count++; + continue; + } + } + + //--- print data + + printf("%sAREA: Area @%u:%u differ%s\n", + colout->COL_DIFF, e1->rank,e2->rank, + colout->reset ); + print_area('<',&e1->data,&e2->data); + print_area('>',&e2->data,&e1->data); + diff_count++; + } + + if ( e1->rank != e2->rank ) + order_differ++; + + e1++; + e2++; + } + + if ( e1 < end1 ) + { + print_area_single('<',e1,end1); + diff_count++; + } + + if ( e2 < end2 ) + { + print_area_single('>',e2,end2); + diff_count++; + } + + if (order_differ) + { + if (verbose) + printf("%sAREA: Order of areas differ%s\n", + colout->COL_DIFF, colout->reset ); + if ( verbose < 2 ) + return 1; + diff_count++; + } + + FREE(s1); + FREE(s2); + return diff_count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_CAME() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +typedef struct sort_came_t +{ + int rank; // previous rank order + kmp_came_entry_t data; // original object data + +} sort_came_t; + +//----------------------------------------------------------------------------- + +static sort_came_t * sort_came ( const List_t *list ) +{ + DASSERT(list); + if (!list->used) + return 0; + + sort_came_t *res = CALLOC(list->used,sizeof(*res)); + sort_came_t *ptr = res; + kmp_came_entry_t *e = (kmp_came_entry_t*)list->list; + const uint n = list->used; + + uint i; + for ( i = 0; i < n; i++, e++, ptr++ ) + { + ptr->rank = i; + memcpy(&ptr->data,e,sizeof(ptr->data)); + } + + #if 0 + if ( n > 1 && KMP_DIFF_MODE & KDMD_SORT ) + qsort( res, n, sizeof(*res), (qsort_func)compare_sort_came ); + #endif + return res; +} + +//----------------------------------------------------------------------------- + +static void print_came + ( char mode, const kmp_came_entry_t *e1, const kmp_came_entry_t *e2 ) +{ + if ( e2 && colout->colorize ) + { + ccp ok = colout->COL_OK; + ccp warn = colout->COL_WARN; + + printf("%c %s%5u %s%5u ", + mode, + OK_WARN1(e1,e2,type), + OK_WARN1(e1,e2,came_speed) ); + print_float(3,e1->position,e2->position,epsilon_pos); + putchar(' '); + print_float(1,&e1->zoom_begin,&e2->zoom_begin,epsilon_pos); + + printf("%s\n%c %s%5s %s%5u ", + colout->reset, + mode, + OK_WARN0(e1,e2,next),PrintU8M1(e1->next), + OK_WARN1(e1,e2,zoom_speed) ); + print_float(3,e1->rotation,e2->rotation,epsilon_pos); + putchar(' '); + print_float(1,&e1->zoom_end,&e2->zoom_end,epsilon_pos); + + printf("%s\n%c %s%5u %s%5u ", + colout->reset, + mode, + OK_WARN1(e1,e2,unknown_0x02), + OK_WARN1(e1,e2,viewpt_speed) ); + print_float(3,e1->viewpt_begin,e2->viewpt_begin,epsilon_pos); + + printf("%s\n%c %s%5s %s%5u ", + colout->reset, + mode, + OK_WARN0(e1,e2,route),PrintU8M1(e1->route), + OK_WARN1(e1,e2,unknown_0x0a) ); + print_float(3,e1->viewpt_end,e2->viewpt_end,epsilon_pos); + putchar(' '); + print_float(1,&e1->time,&e2->time,epsilon_time); + + printf("%s\n",colout->reset); + } + else + { + printf( "%c %5u %5u %11.3f %11.3f %11.3f %11.3f\n" + "%c %5s %5u %11.3f %11.3f %11.3f %11.3f\n" + "%c %5u %5u %11.3f %11.3f %11.3f\n" + "%c %5s %5u %11.3f %11.3f %11.3f %11.3f\n", + mode, + e1->type, e1->came_speed, + e1->position[0], e1->position[1], e1->position[2], + e1->zoom_begin, + mode, + PrintU8M1(e1->next), e1->zoom_speed, + e1->rotation[0], e1->rotation[1], e1->rotation[2], + e1->zoom_end, + mode, + e1->unknown_0x02, e1->viewpt_speed, + e1->viewpt_begin[0], e1->viewpt_begin[1], e1->viewpt_begin[2], + mode, + PrintU8M1(e1->route), e1->unknown_0x0a, + e1->viewpt_end[0], e1->viewpt_end[1], e1->viewpt_end[2], + e1->time ); + } +} + +//----------------------------------------------------------------------------- + +static sort_came_t * print_came_single + ( char mode, const sort_came_t *e, sort_came_t *end ) +{ + DASSERT(e); + DASSERT(end); + + while ( e < end ) + { + printf("%sCAME: Only found in source %c @%u%s\n", + mode == '<' ? colout->COL_SRC1 : colout->COL_SRC2, + mode == '<' ? '1' : '2', e->rank, + colout->reset ); + print_came(mode,&e->data,0); + e++; + } + return (sort_came_t*)e; +} + +//----------------------------------------------------------------------------- + +static int diff_came ( const sort_came_t *e1, const sort_came_t *e2 ) +{ + if (!memcmp(&e1->data,&e2->data,sizeof(e1->data))) + return 0; + + uint count = ( e1->data.type != e2->data.type ) + + ( e1->data.next != e2->data.next ) + + ( e1->data.unknown_0x02 != e2->data.unknown_0x02 ) + + ( e1->data.route != e2->data.route ) + + ( e1->data.came_speed != e2->data.came_speed ) + + ( e1->data.zoom_speed != e2->data.zoom_speed ) + + ( e1->data.viewpt_speed != e2->data.viewpt_speed ) + + ( e1->data.unknown_0x0a != e2->data.unknown_0x0a ); + + count += fabsf( e1->data.position[0] - e2->data.position[0] ) > epsilon_pos + || fabsf( e1->data.position[1] - e2->data.position[1] ) > epsilon_pos + || fabsf( e1->data.position[2] - e2->data.position[2] ) > epsilon_pos; + + count += fabsf( e1->data.rotation[0] - e2->data.rotation[0] ) > epsilon_rot + || fabsf( e1->data.rotation[1] - e2->data.rotation[1] ) > epsilon_rot + || fabsf( e1->data.rotation[2] - e2->data.rotation[2] ) > epsilon_rot; + + count += fabsf( e1->data.zoom_begin - e2->data.zoom_begin ) > epsilon_scale + || fabsf( e1->data.zoom_end - e2->data.zoom_end ) > epsilon_scale; + + count += fabsf( e1->data.viewpt_begin[0] - e2->data.viewpt_begin[0] ) > epsilon_pos + || fabsf( e1->data.viewpt_begin[1] - e2->data.viewpt_begin[1] ) > epsilon_pos + || fabsf( e1->data.viewpt_begin[2] - e2->data.viewpt_begin[2] ) > epsilon_pos; + + + count += fabsf( e1->data.viewpt_end[0] - e2->data.viewpt_end[0] ) > epsilon_pos + || fabsf( e1->data.viewpt_end[1] - e2->data.viewpt_end[1] ) > epsilon_pos + || fabsf( e1->data.viewpt_end[2] - e2->data.viewpt_end[2] ) > epsilon_pos; + + count += fabsf( e1->data.time - e2->data.time ) > epsilon_time; + + return count; +} + +//----------------------------------------------------------------------------- + +static uint diff_KMP_CAME +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + uint diff_count = 0; + List_t *l1 = kmp1->dlist + KMP_CAME; + List_t *l2 = kmp2->dlist + KMP_CAME; + + if ( l1->used != l2->used ) + { + if (!verbose) + return 1; + printf("%sCAME: Number of cameras differ: Have %u and %u.%s\n", + colout->COL_WARN, l1->used, l2->used, colout->reset ); + if (verbose==1) + return 1; + diff_count++; + } + + sort_came_t *s1 = sort_came(l1), *e1 = s1, *end1 = e1 + l1->used; + sort_came_t *s2 = sort_came(l2), *e2 = s2, *end2 = e2 + l2->used; + uint order_differ = 0; + + while ( e1 < end1 && e2 < end2 ) + { + const int stat = diff_came(e1,e2); + if (stat) + { + if ( verbose < 2 ) + { + if (verbose) + printf("%sCAME: Data differ%s\n", + colout->COL_DIFF, colout->reset ); + return 1; + } + + const int trigger = 2; + if ( stat >= trigger ) + { + //--- try to sync + + int dist1 = 99999; + sort_came_t *p1; + for ( p1 = e1+1; p1 < end1; p1++ ) + if ( diff_came(p1,e2) < trigger ) + { + dist1 = p1 - e1; + break; + } + + int dist2 = 99999; + sort_came_t *p2; + for ( p2 = e2+1; p2 < end2; p2++ ) + if ( diff_came(p2,e1) < trigger ) + { + dist2 = p2 - e2; + break; + } + + PRINT0("DIST: %d %d\n",dist1,dist2); + + if ( dist1 < 99999 && dist1 < dist2 ) + { + e1 = print_came_single('<',e1,e1+1); + diff_count++; + continue; + } + else if ( dist2 < 99999 && dist2 < dist1 ) + { + e2 = print_came_single('>',e2,e2+1); + diff_count++; + continue; + } + } + + //--- print data + + printf("%sCAME: Camera @%u:%u differ%s\n", + colout->COL_DIFF, e1->rank,e2->rank, + colout->reset ); + print_came('<',&e1->data,&e2->data); + print_came('>',&e2->data,&e1->data); + diff_count++; + } + + if ( e1->rank != e2->rank ) + order_differ++; + + e1++; + e2++; + } + + if ( e1 < end1 ) + { + print_came_single('<',e1,end1); + diff_count++; + } + + if ( e2 < end2 ) + { + print_came_single('>',e2,end2); + diff_count++; + } + + if (order_differ) + { + if (verbose) + printf("%sCAME: Order of cameras differ%s\n", + colout->COL_DIFF, colout->reset ); + if ( verbose < 2 ) + return 1; + diff_count++; + } + + FREE(s1); + FREE(s2); + return diff_count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_CKPH() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static uint diff_KMP_CKPH +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + section_info_t si = {KMP_CKPH,kmp1,kmp2,verbose,"CKPH","check point"}; + return diff_ph_si(&si); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_CKPT() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +typedef struct sort_ckpt_t +{ + int rank; // previous rank order + kmp_ckpt_entry_t data; // original object data + +} sort_ckpt_t; + +//----------------------------------------------------------------------------- + +static sort_ckpt_t * sort_ckpt ( const List_t *list ) +{ + DASSERT(list); + if (!list->used) + return 0; + + sort_ckpt_t *res = CALLOC(list->used,sizeof(*res)); + sort_ckpt_t *ptr = res; + kmp_ckpt_entry_t *e = (kmp_ckpt_entry_t*)list->list; + const uint n = list->used; + + uint i; + for ( i = 0; i < n; i++, e++, ptr++ ) + { + ptr->rank = i; + memcpy(&ptr->data,e,sizeof(ptr->data)); + } + + #if 0 + if ( n > 1 && KMP_DIFF_MODE & KDMD_SORT ) + qsort( res, n, sizeof(*res), (qsort_func)compare_sort_ckpt ); + #endif + return res; +} + +//----------------------------------------------------------------------------- + +static void print_ckpt + ( char mode, const kmp_ckpt_entry_t *e1, const kmp_ckpt_entry_t *e2 ) +{ + if ( e2 && colout->colorize ) + { + ccp ok = colout->COL_OK; + ccp warn = colout->COL_WARN; + + putchar(mode); + print_float(2,e1->left,e2->left,epsilon_pos); + putchar(' '); + print_float(2,e1->right,e2->right,epsilon_pos); + + printf(" %s%3d %s%3s %s%3s %s%3s%s\n", + OK_WARN1(e1,e2,respawn), + OK_WARN0(e1,e2,mode), PrintU8M1(e1->mode), + OK_WARN0(e1,e2,prev), PrintU8M1(e1->prev), + OK_WARN0(e1,e2,next), PrintU8M1(e1->next), + colout->reset ); + } + else + { + printf("%c %11.3f %11.3f %11.3f %11.3f %3d %3s %3s %3s\n", + mode, + e1->left[0], e1->left[1], + e1->right[0], e1->right[1], + e1->respawn, + PrintU8M1(e1->mode), + PrintU8M1(e1->prev), + PrintU8M1(e1->next) ); + } +} + +//----------------------------------------------------------------------------- + +static sort_ckpt_t * print_ckpt_single + ( char mode, const sort_ckpt_t *e, sort_ckpt_t *end ) +{ + DASSERT(e); + DASSERT(end); + + while ( e < end ) + { + printf("%sCKPT: Only found in source %c @%u%s\n", + mode == '<' ? colout->COL_SRC1 : colout->COL_SRC2, + mode == '<' ? '1' : '2', e->rank, + colout->reset ); + print_ckpt(mode,&e->data,0); + e++; + } + return (sort_ckpt_t*)e; +} + +//----------------------------------------------------------------------------- + +static int diff_ckpt ( const sort_ckpt_t *e1, const sort_ckpt_t *e2 ) +{ + if (!memcmp(&e1->data,&e2->data,sizeof(e1->data))) + return 0; + + uint count = ( e1->data.respawn != e2->data.respawn ) + + ( e1->data.mode != e2->data.mode ) + + ( e1->data.prev != e2->data.prev ) + + ( e1->data.next != e2->data.next ); + + count += fabsf( e1->data.left[0] - e2->data.left[0] ) > epsilon_pos + || fabsf( e1->data.left[1] - e2->data.left[1] ) > epsilon_pos; + + count += fabsf( e1->data.right[0] - e2->data.right[0] ) > epsilon_pos + || fabsf( e1->data.right[1] - e2->data.right[1] ) > epsilon_pos; + + return count; +} + +//----------------------------------------------------------------------------- + +static uint diff_KMP_CKPT +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + uint diff_count = 0; + List_t *l1 = kmp1->dlist + KMP_CKPT; + List_t *l2 = kmp2->dlist + KMP_CKPT; + + if ( l1->used != l2->used ) + { + if (!verbose) + return 1; + printf("%sCKPT: Number of check points differ: Have %u and %u.%s\n", + colout->COL_WARN, l1->used, l2->used, colout->reset ); + if (verbose==1) + return 1; + diff_count++; + } + + sort_ckpt_t *s1 = sort_ckpt(l1), *e1 = s1, *end1 = e1 + l1->used; + sort_ckpt_t *s2 = sort_ckpt(l2), *e2 = s2, *end2 = e2 + l2->used; + uint order_differ = 0; + + while ( e1 < end1 && e2 < end2 ) + { + const int stat = diff_ckpt(e1,e2); + if (stat) + { + if ( verbose < 2 ) + { + if (verbose) + printf("%sCKPT: Data differ%s\n", + colout->COL_DIFF, colout->reset ); + return 1; + } + + const int trigger = 2; + if ( stat >= trigger ) + { + //--- try to sync + + int dist1 = 99999; + sort_ckpt_t *p1; + for ( p1 = e1+1; p1 < end1; p1++ ) + if ( diff_ckpt(p1,e2) < trigger ) + { + dist1 = p1 - e1; + break; + } + + int dist2 = 99999; + sort_ckpt_t *p2; + for ( p2 = e2+1; p2 < end2; p2++ ) + if ( diff_ckpt(p2,e1) < trigger ) + { + dist2 = p2 - e2; + break; + } + + PRINT0("DIST: %d %d\n",dist1,dist2); + + if ( dist1 < 99999 && dist1 < dist2 ) + { + e1 = print_ckpt_single('<',e1,e1+1); + diff_count++; + continue; + } + else if ( dist2 < 99999 && dist2 < dist1 ) + { + e2 = print_ckpt_single('>',e2,e2+1); + diff_count++; + continue; + } + } + + //--- print data + + printf("%sCKPT: CKPT @%u:%u differ%s\n", + colout->COL_DIFF, e1->rank,e2->rank, + colout->reset ); + print_ckpt('<',&e1->data,&e2->data); + print_ckpt('>',&e2->data,&e1->data); + diff_count++; + } + + if ( e1->rank != e2->rank ) + order_differ++; + + e1++; + e2++; + } + + if ( e1 < end1 ) + { + print_ckpt_single('<',e1,end1); + diff_count++; + } + + if ( e2 < end2 ) + { + print_ckpt_single('>',e2,end2); + diff_count++; + } + + if (order_differ) + { + if (verbose) + printf("%sCKPT: Order of check points differ%s\n", + colout->COL_DIFF, colout->reset ); + if ( verbose < 2 ) + return 1; + diff_count++; + } + + FREE(s1); + FREE(s2); + return diff_count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_CNPT() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static uint diff_KMP_CNPT +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + section_info_t si = {KMP_CNPT,kmp1,kmp2,verbose,"CNPT","cannon"}; + return diff_pt2_si(&si); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_ENPH() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static uint diff_KMP_ENPH +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + section_info_t si = {KMP_ENPH,kmp1,kmp2,verbose,"ENPH","enemy point"}; + return diff_ph_si(&si); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_ENPT() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static uint diff_KMP_ENPT +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + section_info_t si = {KMP_ENPT,kmp1,kmp2,verbose,"ENPT","enemy point"}; + return diff_pt_si(&si); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_GOBJ() /////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[sort_gobj_t]] + +typedef struct sort_gobj_t +{ + int obj_id; // relevant object id + int rank; // previous rank order + kmp_gobj_entry_t data; // original object data + +} sort_gobj_t; + +//----------------------------------------------------------------------------- + +static int compare_sort_gobj ( const sort_gobj_t * a, const sort_gobj_t * b ) +{ + int stat = a->obj_id - b->obj_id; + if (!stat) + stat = a->rank - b->rank; + return stat; +} + +//----------------------------------------------------------------------------- + +static sort_gobj_t * sort_gobj ( const List_t *list ) +{ + DASSERT(list); + if (!list->used) + return 0; + + sort_gobj_t *res = CALLOC(list->used,sizeof(*res)); + sort_gobj_t *sg = res; + kmp_gobj_entry_t *e = (kmp_gobj_entry_t*)list->list; + const uint n = list->used; + + uint i; + for ( i = 0; i < n; i++, e++, sg++ ) + { + sg->obj_id = e->obj_id & ~GOBJ_M_LECODE; + sg->rank = i; + memcpy(&sg->data,e,sizeof(sg->data)); + } + + if ( n > 1 && KMP_DIFF_MODE & KDMD_SORT ) + qsort( res, n, sizeof(*res), (qsort_func)compare_sort_gobj ); + return res; +} + +//----------------------------------------------------------------------------- + +static void print_gobj ( char mode, const kmp_gobj_entry_t *g1, + const kmp_gobj_entry_t *g2, const ObjectInfo_t *oi ) +{ + char buf1[32], buf2[32]; + if (!oi) + oi = GetObjectInfo(g1->obj_id); + DASSERT(oi); + + if ( g2 && colout->colorize ) + { + ccp ok = colout->COL_OK; + ccp warn = colout->COL_WARN; + + printf("%c %s%#6x", + mode, g1->obj_id == g2->obj_id ? ok : warn, g1->obj_id ); + print_float(3,g1->position,g2->position,epsilon_pos); + + fputs(" ",stdout); + printf( oi->format1 ? oi->format1->col : settings_format_uuuu.col, + g1->setting[0] == g2->setting[0] ? ok : warn , g1->setting[0], + g1->setting[1] == g2->setting[1] ? ok : warn , g1->setting[1], + g1->setting[2] == g2->setting[2] ? ok : warn , g1->setting[2], + g1->setting[3] == g2->setting[3] ? ok : warn , g1->setting[3] ); + + printf(" %s%6s%s\n%c %s%#6x", + g1->route_id == g2->route_id ? ok : warn, PrintU16M1(g1->route_id), + colout->reset, + mode, + g1->ref_id == g2->ref_id ? ok : warn, g1->ref_id ); + print_float(3,g1->rotation,g2->rotation,epsilon_rot); + + fputs(" ",stdout); + printf( oi->format2 ? oi->format2->col : settings_format_uuuu.col, + g1->setting[4] == g2->setting[4] ? ok : warn , g1->setting[4], + g1->setting[5] == g2->setting[5] ? ok : warn , g1->setting[5], + g1->setting[6] == g2->setting[6] ? ok : warn , g1->setting[6], + g1->setting[7] == g2->setting[7] ? ok : warn , g1->setting[7] ); + + printf(" %s%#6x%s\n%c ", + g1->pflags == g2->pflags ? ok : warn, g1->pflags, + colout->reset, mode ); + print_float(3,g1->scale,g2->scale,epsilon_scale); + + printf( "%s\n",colout->reset); + } + else + { + snprintf( buf1, sizeof(buf1), + oi->format1 ? oi->format1->std : settings_format_uuuu.std, + g1->setting[0], g1->setting[1], g1->setting[2], g1->setting[3] ); + + snprintf( buf2, sizeof(buf2), + oi->format2 ? oi->format2->std : settings_format_uuuu.std, + g1->setting[4], g1->setting[5], g1->setting[6], g1->setting[7] ); + + printf( "%c %#6x %11.3f %11.3f %11.3f %s %6s\n" + "%c %#6x %11.3f %11.3f %11.3f %s %#6x\n" + "%c %11.3f %11.3f %11.3f\n", + mode, g1->obj_id, + g1->position[0], g1->position[1], g1->position[2], + buf1, PrintU16M1(g1->route_id), + mode, g1->ref_id, + g1->rotation[0], g1->rotation[1], g1->rotation[2], + buf2, g1->pflags, + mode, g1->scale[0], g1->scale[1], g1->scale[2] + ); + } +} + +//----------------------------------------------------------------------------- + +static sort_gobj_t * print_gobj_single + ( char mode, const sort_gobj_t *e, sort_gobj_t *end ) +{ + DASSERT(e); + DASSERT(end); + + while ( e < end ) + { + const ObjectInfo_t *oi = GetObjectInfo(e->data.obj_id); + printf("%sGOBJ: Only found in source %c (@%u,%s)%s\n", + mode == '<' ? colout->COL_SRC1 : colout->COL_SRC2, + mode == '<' ? '1' : '2', e->rank, + oi->name ? oi->name : "?", + colout->reset ); + print_gobj(mode,&e->data,0,0); + e++; + } + return (sort_gobj_t*)e; +} + +//----------------------------------------------------------------------------- +// return 0:equal, >0:number of different elements, 99:different relevant obj_id + +static int diff_gobj ( const sort_gobj_t *e1, const sort_gobj_t *e2 ) +{ + if (!memcmp(&e1->data,&e2->data,sizeof(e1->data))) + return 0; + + if ( e1->obj_id != e2->obj_id ) + return 99; + + uint count = ( e1->data.obj_id != e2->data.obj_id ) + + ( e1->data.ref_id != e2->data.ref_id ) + + ( e1->data.route_id != e2->data.route_id ) + + ( e1->data.pflags != e2->data.pflags ); + + uint i; + for ( i = 0; i < 8; i++ ) + count += e1->data.setting[i] != e2->data.setting[i]; + + count += fabsf( e1->data.position[0] - e2->data.position[0] ) > epsilon_pos + || fabsf( e1->data.position[1] - e2->data.position[1] ) > epsilon_pos + || fabsf( e1->data.position[2] - e2->data.position[2] ) > epsilon_pos; + + count += fabsf( e1->data.rotation[0] - e2->data.rotation[0] ) > epsilon_rot + || fabsf( e1->data.rotation[1] - e2->data.rotation[1] ) > epsilon_rot + || fabsf( e1->data.rotation[2] - e2->data.rotation[2] ) > epsilon_rot; + + count += fabsf( e1->data.scale[0] - e2->data.scale[0] ) > epsilon_scale + || fabsf( e1->data.scale[1] - e2->data.scale[1] ) > epsilon_scale + || fabsf( e1->data.scale[2] - e2->data.scale[2] ) > epsilon_scale; + + return count; +} + +//----------------------------------------------------------------------------- + +static uint diff_KMP_GOBJ +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + uint diff_count = 0; + List_t *l1 = kmp1->dlist + KMP_GOBJ; + List_t *l2 = kmp2->dlist + KMP_GOBJ; + + if ( l1->used != l2->used ) + { + if (!verbose) + return 1; + printf("%sGOBJ: Number of objects differ: Have %u and %u.%s\n", + colout->COL_DIFF, l1->used, l2->used, colout->reset ); + if (verbose==1) + return 1; + diff_count++; + } + + sort_gobj_t *sg1 = sort_gobj(l1), *e1 = sg1, *end1 = e1 + l1->used; + sort_gobj_t *sg2 = sort_gobj(l2), *e2 = sg2, *end2 = e2 + l2->used; + uint order_differ = 0; + + while ( e1 < end1 && e2 < end2 ) + { + if ( e1->obj_id < e2->obj_id ) + { + e1 = print_gobj_single('<',e1,e1+1); + diff_count++; + continue; + } + + if ( e2->obj_id < e1->obj_id ) + { + e2 = print_gobj_single('>',e2,e2+1); + diff_count++; + continue; + } + + const int stat = diff_gobj(e1,e2); + if (stat) + { + if ( verbose < 2 ) + { + if (verbose) + printf("%sGOBJ: Data differ%s\n", + colout->COL_DIFF, colout->reset ); + return 1; + } + + const int trigger = 2; + if ( stat >= trigger ) + { + //--- try to sync + + int dist1 = 99999; + sort_gobj_t *p1; + for ( p1 = e1+1; p1 < end1; p1++ ) + if ( diff_gobj(p1,e2) < trigger ) + { + dist1 = p1 - e1; + break; + } + + int dist2 = 99999; + sort_gobj_t *p2; + for ( p2 = e2+1; p2 < end2; p2++ ) + if ( diff_gobj(p2,e1) < trigger ) + { + dist2 = p2 - e2; + break; + } + + PRINT0("DIST: %d %d\n",dist1,dist2); + + if ( dist1 < 99999 && dist1 < dist2 ) + { + //e1 = print_gobj_single('<',e1,p1); + e1 = print_gobj_single('<',e1,e1+1); + diff_count++; + continue; + } + else if ( dist2 < 99999 && dist2 < dist1 ) + { + //e2 = print_gobj_single('>',e2,p2); + e2 = print_gobj_single('>',e2,e2+1); + diff_count++; + continue; + } + } + + //--- print data + + const ObjectInfo_t *oi = GetObjectInfo(e1->data.obj_id); + printf("%sGOBJ: Object @%u:%u (%s) differ%s\n", + colout->COL_DIFF, e1->rank,e2->rank, + oi->name ? oi->name : "?", colout->reset ); + print_gobj('<',&e1->data,&e2->data,oi); + print_gobj('>',&e2->data,&e1->data,oi); + diff_count++; + } + + if ( e1->rank != e2->rank ) + order_differ++; + + e1++; + e2++; + } + + if ( e1 < end1 ) + { + print_gobj_single('<',e1,end1); + diff_count++; + } + + if ( e2 < end2 ) + { + print_gobj_single('>',e2,end2); + diff_count++; + } + + if (order_differ) + { + if (verbose) + printf("%sGOBJ: Order of objects differ%s\n", + colout->COL_DIFF, colout->reset ); + if ( verbose < 2 ) + return 1; + diff_count++; + } + + FREE(sg1); + FREE(sg2); + return diff_count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_ITPH() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static uint diff_KMP_ITPH +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + section_info_t si = {KMP_ITPH,kmp1,kmp2,verbose,"ITPH","item point"}; + return diff_ph_si(&si); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_ITPT() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static uint diff_KMP_ITPT +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + section_info_t si = {KMP_ITPT,kmp1,kmp2,verbose,"ITPT","item point"}; + return diff_pt_si(&si); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_JGPT() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static uint diff_KMP_JGPT +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + section_info_t si = {KMP_JGPT,kmp1,kmp2,verbose,"JGPT","respawn"}; + return diff_pt2_si(&si); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_KTPT() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +typedef struct sort_ktpt_t +{ + int rank; // previous rank order + kmp_ktpt_entry_t data; // original object data + +} sort_ktpt_t; + +//----------------------------------------------------------------------------- + +static sort_ktpt_t * sort_ktpt ( const List_t *list ) +{ + DASSERT(list); + if (!list->used) + return 0; + + sort_ktpt_t *res = CALLOC(list->used,sizeof(*res)); + sort_ktpt_t *ptr = res; + kmp_ktpt_entry_t *e = (kmp_ktpt_entry_t*)list->list; + const uint n = list->used; + + uint i; + for ( i = 0; i < n; i++, e++, ptr++ ) + { + ptr->rank = i; + memcpy(&ptr->data,e,sizeof(ptr->data)); + } + + #if 0 + if ( n > 1 && KMP_DIFF_MODE & KDMD_SORT ) + qsort( res, n, sizeof(*res), (qsort_func)compare_sort_ktpt ); + #endif + return res; +} + +//----------------------------------------------------------------------------- + +static inline void print_ktpt + ( char mode, const kmp_ktpt_entry_t *e1, const kmp_ktpt_entry_t *e2 ) +{ + print_pt2(mode,(kmp_jgpt_entry_t*)e1,(kmp_jgpt_entry_t*)e2); +} + +//----------------------------------------------------------------------------- + +static sort_ktpt_t * print_ktpt_single + ( char mode, const sort_ktpt_t *e, sort_ktpt_t *end ) +{ + DASSERT(e); + DASSERT(end); + + while ( e < end ) + { + printf("%sKTPT: Only found in source %c @%u%s\n", + mode == '<' ? colout->COL_SRC1 : colout->COL_SRC2, + mode == '<' ? '1' : '2', e->rank, + colout->reset ); + print_ktpt(mode,&e->data,0); + e++; + } + return (sort_ktpt_t*)e; +} + +//----------------------------------------------------------------------------- + +static int diff_ktpt ( const sort_ktpt_t *e1, const sort_ktpt_t *e2 ) +{ + if (!memcmp(&e1->data,&e2->data,sizeof(e1->data))) + return 0; + + uint count = ( e1->data.player_index != e2->data.player_index ) + + ( e1->data.unknown != e2->data.unknown ); + + count += fabsf( e1->data.position[0] - e2->data.position[0] ) > epsilon_pos + || fabsf( e1->data.position[1] - e2->data.position[1] ) > epsilon_pos + || fabsf( e1->data.position[2] - e2->data.position[2] ) > epsilon_pos; + + count += fabsf( e1->data.rotation[0] - e2->data.rotation[0] ) > epsilon_rot + || fabsf( e1->data.rotation[1] - e2->data.rotation[1] ) > epsilon_rot + || fabsf( e1->data.rotation[2] - e2->data.rotation[2] ) > epsilon_rot; + + return count; +} + +//----------------------------------------------------------------------------- + +static uint diff_KMP_KTPT +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + uint diff_count = 0; + List_t *l1 = kmp1->dlist + KMP_KTPT; + List_t *l2 = kmp2->dlist + KMP_KTPT; + + if ( l1->used != l2->used ) + { + if (!verbose) + return 1; + printf("%sKTPT: Number of start positions differ: Have %u and %u.%s\n", + colout->COL_WARN, l1->used, l2->used, colout->reset ); + if (verbose==1) + return 1; + diff_count++; + } + + sort_ktpt_t *s1 = sort_ktpt(l1), *e1 = s1, *end1 = e1 + l1->used; + sort_ktpt_t *s2 = sort_ktpt(l2), *e2 = s2, *end2 = e2 + l2->used; + uint order_differ = 0; + + while ( e1 < end1 && e2 < end2 ) + { + const int stat = diff_ktpt(e1,e2); + if (stat) + { + if ( verbose < 2 ) + { + if (verbose) + printf("%sKTPT: Data differ%s\n", + colout->COL_DIFF, colout->reset ); + return 1; + } + + const int trigger = 2; + if ( stat >= trigger ) + { + //--- try to sync + + int dist1 = 99999; + sort_ktpt_t *p1; + for ( p1 = e1+1; p1 < end1; p1++ ) + if ( diff_ktpt(p1,e2) < trigger ) + { + dist1 = p1 - e1; + break; + } + + int dist2 = 99999; + sort_ktpt_t *p2; + for ( p2 = e2+1; p2 < end2; p2++ ) + if ( diff_ktpt(p2,e1) < trigger ) + { + dist2 = p2 - e2; + break; + } + + PRINT0("DIST: %d %d\n",dist1,dist2); + + if ( dist1 < 99999 && dist1 < dist2 ) + { + e1 = print_ktpt_single('<',e1,e1+1); + diff_count++; + continue; + } + else if ( dist2 < 99999 && dist2 < dist1 ) + { + e2 = print_ktpt_single('>',e2,e2+1); + diff_count++; + continue; + } + } + + //--- print data + + printf("%sKTPT: KTPT @%u:%u differ%s\n", + colout->COL_DIFF, e1->rank,e2->rank, + colout->reset ); + print_ktpt('<',&e1->data,&e2->data); + print_ktpt('>',&e2->data,&e1->data); + diff_count++; + } + + if ( e1->rank != e2->rank ) + order_differ++; + + e1++; + e2++; + } + + if ( e1 < end1 ) + { + print_ktpt_single('<',e1,end1); + diff_count++; + } + + if ( e2 < end2 ) + { + print_ktpt_single('>',e2,end2); + diff_count++; + } + + if (order_differ) + { + if (verbose) + printf("%sKTPT: Order of start positions differ%s\n", + colout->COL_DIFF, colout->reset ); + if ( verbose < 2 ) + return 1; + diff_count++; + } + + FREE(s1); + FREE(s2); + return diff_count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_MSPT() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static uint diff_KMP_MSPT +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + section_info_t si = {KMP_MSPT,kmp1,kmp2,verbose,"MSPT","mission success"}; + return diff_pt2_si(&si); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_POTI() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static int diff_poti_group ( const kmp_poti_group_t *e1, const kmp_poti_group_t *e2 ) +{ + if (!memcmp(e1,e2,sizeof(*e1))) + return 0; + + return ( e1->n_point != e2->n_point ) + + ( e1->smooth != e2->smooth ) + + ( e1->back != e2->back ); +} + +//----------------------------------------------------------------------------- + +static int diff_poti_point ( const kmp_poti_point_t *e1, const kmp_poti_point_t *e2 ) +{ + if (!memcmp(e1,e2,sizeof(*e1))) + return 0; + + uint count = ( e1->speed != e2->speed ) + + ( e1->unknown != e2->unknown ); + + count += fabsf( e1->position[0] - e2->position[0] ) > epsilon_pos + || fabsf( e1->position[1] - e2->position[1] ) > epsilon_pos + || fabsf( e1->position[2] - e2->position[2] ) > epsilon_pos; + + return count; +} + +//----------------------------------------------------------------------------- + +static uint diff_KMP_POTI +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + uint diff_count = 0; + List_t *gl1 = kmp1->dlist + KMP_POTI; + List_t *pl1 = &kmp1->poti_point; + List_t *gl2 = kmp2->dlist + KMP_POTI; + List_t *pl2 = &kmp2->poti_point; + + + if ( gl1->used != gl2->used ) + { + if (!verbose) + return 1; + printf("POTI: Number of routes differ: Have %u and %u.\n", + gl1->used, gl2->used ); + if (verbose==1) + return 1; + diff_count++; + } + + if ( pl1->used != pl2->used ) + { + if (!verbose) + return 1; + printf("POTI: Number of total route points differ: Have %u and %u.\n", + pl1->used, pl2->used ); + if (verbose==1) + return 1; + diff_count++; + } + +// [[2do]] ??? qqq + + uint i; + const uint gn = gl1->used < gl2->used ? gl1->used : gl2->used; + kmp_poti_group_t *ge1 = (kmp_poti_group_t*)gl1->list; + kmp_poti_group_t *ge2 = (kmp_poti_group_t*)gl2->list; + + for ( i = 0; i < gn; i++, ge1++, ge2++ ) + { + if (diff_poti_group(ge1,ge2)) + { + if ( verbose < 2 ) + { + if (verbose) + fputs("POTI: Groups differ\n",stdout); + return 1; + } + + printf("POTI: Group #%u differ\n",i); + diff_count++; + } + } + + +// [[2do]] ??? qqq + + const uint pn = pl1->used < pl2->used ? pl1->used : pl2->used; + kmp_poti_point_t *pe1 = (kmp_poti_point_t*)pl1->list; + kmp_poti_point_t *pe2 = (kmp_poti_point_t*)pl2->list; + + for ( i = 0; i < pn; i++, pe1++, pe2++ ) + { + if (diff_poti_point(pe1,pe2)) + { + if ( verbose < 2 ) + { + if (verbose) + fputs("POTI: Route points differ\n",stdout); + return 1; + } + + printf("POTI: Route point #%u differ\n",i); + diff_count++; + } + } + + return diff_count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// diff_KMP_STGI() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +typedef struct sort_stgi_t +{ + int rank; // previous rank order + kmp_stgi_entry_t data; // original object data + +} sort_stgi_t; + +//----------------------------------------------------------------------------- + +static sort_stgi_t * sort_stgi ( const List_t *list ) +{ + DASSERT(list); + if (!list->used) + return 0; + + sort_stgi_t *res = CALLOC(list->used,sizeof(*res)); + sort_stgi_t *ptr = res; + kmp_stgi_entry_t *e = (kmp_stgi_entry_t*)list->list; + const uint n = list->used; + + uint i; + for ( i = 0; i < n; i++, e++, ptr++ ) + { + ptr->rank = i; + memcpy(&ptr->data,e,sizeof(ptr->data)); + } + + #if 0 + if ( n > 1 && KMP_DIFF_MODE & KDMD_SORT ) + qsort( res, n, sizeof(*res), (qsort_func)compare_sort_stgi ); + #endif + return res; +} + +//----------------------------------------------------------------------------- + +static inline void print_stgi + ( char mode, const kmp_stgi_entry_t *e1, const kmp_stgi_entry_t *e2 ) +{ + if ( e2 && colout->colorize ) + { + ccp ok = colout->COL_OK; + ccp warn = colout->COL_WARN; + + printf("%c %s%5u %s%4u %s%5u %s%5u %s%#10x %s0x%02x %s%#5x %s%#6x", + mode, + OK_WARN1(e1,e2,lap_count), + OK_WARN1(e1,e2,pole_pos), + OK_WARN1(e1,e2,narrow_start), + OK_WARN1(e1,e2,enable_lens_flare), + OK_WARN1(e1,e2,flare_color), + OK_WARN1(e1,e2,flare_alpha), + OK_WARN1(e1,e2,unknown_09), + OK_WARN1(e1,e2,speed_mod) ); + + if (e1->speed_mod) + printf(" (%5.3f)",SpeedMod2float(e1->speed_mod)); + printf("%s\n",colout->reset); + } + else + { + printf("%c %5u %4u %5u %5u %#10x 0x%02x %#5x %#6x", + mode, + e1->lap_count, e1->pole_pos, + e1->narrow_start, e1->enable_lens_flare, + e1->flare_color, + e1->flare_alpha, e1->unknown_09, + e1->speed_mod ); + if (e1->speed_mod) + printf(" (%5.3f)\n",SpeedMod2float(e1->speed_mod)); + else + putchar('\n'); + } +} + +//----------------------------------------------------------------------------- + +static sort_stgi_t * print_stgi_single + ( char mode, const sort_stgi_t *e, sort_stgi_t *end ) +{ + DASSERT(e); + DASSERT(end); + + while ( e < end ) + { + printf("%sSTGI: Only found in source %c @%u%s\n", + mode == '<' ? colout->COL_SRC1 : colout->COL_SRC2, + mode == '<' ? '1' : '2', e->rank, + colout->reset ); + print_stgi(mode,&e->data,0); + e++; + } + return (sort_stgi_t*)e; +} + +//----------------------------------------------------------------------------- + +static int diff_stgi ( const sort_stgi_t *e1, const sort_stgi_t *e2 ) +{ + if (!memcmp(&e1->data,&e2->data,sizeof(e1->data))) + return 0; + + return ( e1->data.lap_count != e2->data.lap_count ) + + ( e1->data.pole_pos != e2->data.pole_pos ) + + ( e1->data.narrow_start != e2->data.narrow_start ) + + ( e1->data.enable_lens_flare != e2->data.enable_lens_flare ) + + ( e1->data.flare_color != e2->data.flare_color ) + + ( e1->data.flare_alpha != e2->data.flare_alpha ) + + ( e1->data.unknown_09 != e2->data.unknown_09 ) + + ( e1->data.speed_mod != e2->data.speed_mod ); +} + +//----------------------------------------------------------------------------- + +static uint diff_KMP_STGI +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + + uint diff_count = 0; + List_t *l1 = kmp1->dlist + KMP_STGI; + List_t *l2 = kmp2->dlist + KMP_STGI; + + if ( l1->used != l2->used ) + { + if (!verbose) + return 1; + printf("%sSTGI: Number of stage info records differ: Have %u and %u.%s\n", + colout->COL_WARN, l1->used, l2->used, colout->reset ); + if (verbose==1) + return 1; + diff_count++; + } + + sort_stgi_t *s1 = sort_stgi(l1), *e1 = s1, *end1 = e1 + l1->used; + sort_stgi_t *s2 = sort_stgi(l2), *e2 = s2, *end2 = e2 + l2->used; + uint order_differ = 0; + + while ( e1 < end1 && e2 < end2 ) + { + const int stat = diff_stgi(e1,e2); + if (stat) + { + if ( verbose < 2 ) + { + if (verbose) + printf("%sSTGI: Data differ%s\n", + colout->COL_DIFF, colout->reset ); + return 1; + } + + const int trigger = 2; + if ( stat >= trigger ) + { + //--- try to sync + + int dist1 = 99999; + sort_stgi_t *p1; + for ( p1 = e1+1; p1 < end1; p1++ ) + if ( diff_stgi(p1,e2) < trigger ) + { + dist1 = p1 - e1; + break; + } + + int dist2 = 99999; + sort_stgi_t *p2; + for ( p2 = e2+1; p2 < end2; p2++ ) + if ( diff_stgi(p2,e1) < trigger ) + { + dist2 = p2 - e2; + break; + } + + PRINT0("DIST: %d %d\n",dist1,dist2); + + if ( dist1 < 99999 && dist1 < dist2 ) + { + e1 = print_stgi_single('<',e1,e1+1); + diff_count++; + continue; + } + else if ( dist2 < 99999 && dist2 < dist1 ) + { + e2 = print_stgi_single('>',e2,e2+1); + diff_count++; + continue; + } + } + + //--- print data + + printf("%sSTGI: Stage info records @%u:%u differ%s\n", + colout->COL_DIFF, e1->rank,e2->rank, + colout->reset ); + print_stgi('<',&e1->data,&e2->data); + print_stgi('>',&e2->data,&e1->data); + diff_count++; + } + + if ( e1->rank != e2->rank ) + order_differ++; + + e1++; + e2++; + } + + if ( e1 < end1 ) + { + print_stgi_single('<',e1,end1); + diff_count++; + } + + if ( e2 < end2 ) + { + print_stgi_single('>',e2,end2); + diff_count++; + } + + if (order_differ) + { + if (verbose) + printf("%sSTGI: Order of stage info records differ%s\n", + colout->COL_DIFF, colout->reset ); + if ( verbose < 2 ) + return 1; + diff_count++; + } + + FREE(s1); + FREE(s2); + return diff_count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// DiffKMP() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError DiffKMP +( + kmp_t * kmp1, // first kmp to compare + kmp_t * kmp2, // second kmp tp compare + uint verbose // 0:quiet, 1:summary only, 2:full report +) +{ + DASSERT(kmp1); + DASSERT(kmp2); + PRINT("DiffKMP( %s, %s, verbose=%d )\n",kmp1->fname,kmp2->fname,verbose); + + //--- compare sections + + enumError diff_count = 0; + + if ( KMP_DIFF_MODE & KDMD_AREA && ( verbose || !diff_count )) + diff_count += diff_KMP_AREA(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_CAME && ( verbose || !diff_count )) + diff_count += diff_KMP_CAME(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_CKPH && ( verbose || !diff_count )) + diff_count += diff_KMP_CKPH(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_CKPT && ( verbose || !diff_count )) + diff_count += diff_KMP_CKPT(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_CNPT && ( verbose || !diff_count )) + diff_count += diff_KMP_CNPT(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_ENPH && ( verbose || !diff_count )) + diff_count += diff_KMP_ENPH(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_ENPT && ( verbose || !diff_count )) + diff_count += diff_KMP_ENPT(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_GOBJ && ( verbose || !diff_count )) + diff_count += diff_KMP_GOBJ(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_ITPH && ( verbose || !diff_count )) + diff_count += diff_KMP_ITPH(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_ITPT && ( verbose || !diff_count )) + diff_count += diff_KMP_ITPT(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_JGPT && ( verbose || !diff_count )) + diff_count += diff_KMP_JGPT(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_KTPT && ( verbose || !diff_count )) + diff_count += diff_KMP_KTPT(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_MSPT && ( verbose || !diff_count )) + diff_count += diff_KMP_MSPT(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_POTI && ( verbose || !diff_count )) + diff_count += diff_KMP_POTI(kmp1,kmp2,verbose); + + if ( KMP_DIFF_MODE & KDMD_STGI && ( verbose || !diff_count )) + diff_count += diff_KMP_STGI(kmp1,kmp2,verbose); + + return diff_count ? ERR_DIFFER : ERR_OK; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// END /////////////// +/////////////////////////////////////////////////////////////////////////////// |
