From 1192c4575ea7afdf38e3fa0df4587a08620af11e Mon Sep 17 00:00:00 2001 From: root Date: Tue, 21 Jul 2020 10:00:46 +0200 Subject: SZS v2.18a --- project/src/lib-mdl.c | 4556 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4556 insertions(+) create mode 100644 project/src/lib-mdl.c (limited to 'project/src/lib-mdl.c') diff --git a/project/src/lib-mdl.c b/project/src/lib-mdl.c new file mode 100644 index 0000000..5e623bf --- /dev/null +++ b/project/src/lib-mdl.c @@ -0,0 +1,4556 @@ + +/*************************************************************************** + * _______ _______ _______ * + * | ___ |____ | ___ | * + * | | |_| / /| | |_| * + * | |_____ / / | |_____ * + * |_____ | / / |_____ | * + * _ | | / / _ | | * + * | |___| |/ /____| |___| | * + * |_______|_______|_______| * + * * + * 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 * + * * + *************************************************************************** + * * + * 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 +#include +#include +#include +#include +#include + +#include "lib-brres.h" +#include "lib-mdl.h" +#include "lib-bzip2.h" + +#include "mdl.inc" + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// MDL action log /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static bool MDL_ACTION_LOG ( bool is_patch, const char * format, ... ) + __attribute__ ((__format__(__printf__,2,3))); + +static bool MDL_ACTION_LOG ( bool is_patch, const char * format, ... ) +{ + #if HAVE_PRINT + { + char buf[200]; + snprintf(buf,sizeof(buf),">>>[MDL]<<< %s",format); + va_list arg; + va_start(arg,format); + PRINT_ARG_FUNC(buf,arg); + va_end(arg); + } + #endif + + if ( verbose > 2 || MDL_MODE & MDLMD_LOG || is_patch && ~MDL_MODE & MDLMD_SILENT ) + { + fflush(stdout); + fprintf(stdlog," %s>[MDL]%s ",colset->heading,colset->info); + va_list arg; + va_start(arg,format); + vfprintf(stdlog,format,arg); + va_end(arg); + fputs(colset->reset,stdlog); + fflush(stdlog); + return true; + } + + return false; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// mdl_mode_t /////////////// +/////////////////////////////////////////////////////////////////////////////// + +mdl_mode_t MDL_MODE = MDLMD_M_DEFAULT; +int have_mdl_patch_count = 0; + +/////////////////////////////////////////////////////////////////////////////// + +static const KeywordTab_t opt_mdl_tab[] = +{ + { 0, "CLEAR", "RESET", MDLMD_M_ALL | MDLMD_F_HIDE }, + { MDLMD_M_DEFAULT, "DEFAULT", 0, MDLMD_M_ALL | MDLMD_F_HIDE }, + + { MDLMD_LOG, "LOG", 0, 0 }, + { MDLMD_SILENT, "SILENT", 0, 0 }, + + { MDLMD_M_NODES, "ALL-NODES", "ALLNODES", MDLMD_M_NODES }, + { MDLMD_PARENT_NODE, "PARENT-NODE", "PARENTNODES", MDLMD_M_NODES }, + { MDLMD_CHILD_NODES, "CHILD-NODES", "CHILDNODES", MDLMD_M_NODES }, + + { MDLMD_VECTOR, "VECTOR", 0, 0 }, + { MDLMD_MATRIX, "MATRIX", 0, 0 }, + { MDLMD_VERTEX, "VERTEX", "VERTICES", 0 }, + + { MDLMD_TEST0, "TEST0", "T0", MDLMD_M_TEST | MDLMD_F_HIDE }, + { MDLMD_TEST1, "TEST1", "T1", MDLMD_M_TEST }, + { MDLMD_TEST2, "TEST2", "T2", MDLMD_M_TEST }, + { MDLMD_TEST3, "TEST3", "T3", MDLMD_M_TEST }, + + { 0,0,0,0 } +}; + +/////////////////////////////////////////////////////////////////////////////// + +void LoadParametersMDL +( + ccp log_prefix // not NULL: + // print log message with prefix +) +{ + static bool done = false; + if (done) + return; + done = true; + + SetMdlMode(MDL_MODE); + + + //--- logging + + if ( !MDL_ACTION_LOG(false,"Global MDL Modes: %s\n",GetMdlMode()) + && log_prefix + && MDL_MODE != MDLMD_M_DEFAULT + && !(MDL_MODE & MDLMD_SILENT) ) + { + fprintf(stdlog,"%sglobal mdl modes: %s [%x]\n",log_prefix,GetMdlMode(),MDL_MODE); + fflush(stdlog); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +mdl_mode_t GetRelevantMdlMode ( mdl_mode_t mode ) +{ + mode = mode & MDLMD_M_ALL; + + if ( !( mode & (MDLMD_VECTOR|MDLMD_MATRIX) )) + mode &= ~MDLMD_M_NODES; + else if ( !( mode & MDLMD_M_NODES )) + mode |= MDLMD_M_NODES; + + if ( PATCH_FILE_MODE & PFILE_F_LOG_ALL ) + mode |= MDLMD_LOG; + + return mode; +} + +/////////////////////////////////////////////////////////////////////////////// + +void SetMdlMode ( uint new_mode ) +{ + //-------------------------------------- + DASSERT( 0x40 == sizeof(mdl_head_t) ); + DASSERT( 0xd0 == sizeof(mdl_sect1_t) ); + DASSERT( 0x38 == sizeof(mdl_sect2_t) ); + DASSERT( 0x418 == sizeof(mdl_sect8_t) ); + DASSERT( 0x34 == sizeof(mdl_sect8_layer_t) ); + DASSERT( 0x68 == sizeof(mdl_sect10_t) ); + //-------------------------------------- + + noPRINT("SET-MDL/IN: PC=%d, MPC=%d\n", + have_patch_count, have_mdl_patch_count ); + + if (have_mdl_patch_count) + have_patch_count--, have_mdl_patch_count--; + + if ( mdl_switched_to_vertex + && ( new_mode & (MDLMD_VECTOR|MDLMD_VERTEX) ) == MDLMD_VECTOR ) + { + new_mode = new_mode & ~MDLMD_VECTOR | MDLMD_VERTEX; + PRINT("MDL: VECTOR diabled, VERTEX enabled\n"); + if ( mdl_switched_to_vertex == 1 ) + mdl_switched_to_vertex++; + } + + MDL_MODE = GetRelevantMdlMode(new_mode); + + if ( MDL_MODE & MDLMD_M_PATCH ) + have_patch_count++, have_mdl_patch_count++; + + noPRINT("SET-MDL/OUT: PC=%d, MPC=%d\n", + have_patch_count, have_mdl_patch_count ); +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptMdl ( ccp arg ) +{ + if (!arg) + return 0; + + static bool done = false; + if (!done) + { + done = true; + if ( *arg != '+' && *arg != '-' ) + MDL_MODE = 0; + } + + s64 stat = ScanKeywordList(arg,opt_mdl_tab,0,true,0,MDL_MODE, + "Option --mdl",ERR_SYNTAX); + if ( stat != -1 ) + { + SetMdlMode(stat); + return 0; + } + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint PrintMdlMode ( char *buf, uint bufsize, mdl_mode_t mode ) +{ + DASSERT(buf); + DASSERT(bufsize>10); + char *dest = buf; + char *end = buf + bufsize - 1; + + mode = GetRelevantMdlMode(mode) | MDLMD_F_HIDE; + mdl_mode_t mode1 = mode; + + const KeywordTab_t *ct; + for ( ct = opt_mdl_tab; ct->name1 && dest < end; ct++ ) + { + if ( ct->opt & MDLMD_F_HIDE ) + continue; + + if ( ct->opt ? (mode & ct->opt) == ct->id : mode & ct->id ) + { + if ( dest > buf ) + *dest++ = ','; + dest = StringCopyE(dest,end,ct->name1); + mode &= ~(ct->id|ct->opt); + } + } + + if ( mode1 == (MDLMD_M_DEFAULT|MDLMD_F_HIDE) ) + dest = StringCopyE(dest,end," (default)"); + else if (!mode1) + dest = StringCopyE(dest,end,"(none)"); + + *dest = 0; + return dest-buf; +} + +/////////////////////////////////////////////////////////////////////////////// + +ccp GetMdlMode() +{ + static char buf[100] = {0}; + if (!*buf) + PrintMdlMode(buf,sizeof(buf),MDL_MODE); + return buf; +} + +/////////////////////////////////////////////////////////////////////////////// + +void SetupMDL() +{ + #if 0 + if ( opt_tiny > 0 ) + { + const mdl_mode_t tiny + = ( (mdl_mode_t)opt_tiny << MDLMD_S_TINY ) & MDLMD_M_TINY; + if ( tiny > ( MDL_MODE & MDLMD_M_TINY )) + MDL_MODE = MDL_MODE & ~MDLMD_M_TINY | tiny; + } + #endif +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// general helpers /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void * GetVectorMDL +( + float3 *dest, + const void *src, + uint format, + uint r_shift +) +{ + DASSERT(dest); + DASSERT(src); + + switch (format) + { + case 0: // u8 + dest->x = ldexpf(((u8*)src)[0],-r_shift); + dest->y = ldexpf(((u8*)src)[1],-r_shift); + dest->z = ldexpf(((u8*)src)[2],-r_shift); + return (u8*)src + 3; + + case 1: // s8 + dest->x = ldexpf(((s8*)src)[0],-r_shift); + dest->y = ldexpf(((s8*)src)[1],-r_shift); + dest->z = ldexpf(((s8*)src)[2],-r_shift); + return (s8*)src + 3; + + case 2: // u16 + dest->x = ldexpf(be16((u16*)src+0),-r_shift); + dest->y = ldexpf(be16((u16*)src+1),-r_shift); + dest->z = ldexpf(be16((u16*)src+2),-r_shift); + return (u16*)src + 3; + + case 3: // s16 + dest->x = ldexpf((s16)be16((u16*)src+0),-r_shift); + dest->y = ldexpf((s16)be16((u16*)src+1),-r_shift); + dest->z = ldexpf((s16)be16((u16*)src+2),-r_shift); + return (s16*)src + 3; + + case 4: // float + bef4n(dest->v,src,3); + return (float*)src + 3; + + default: + dest->x = dest->y = dest->z = 0.0; + return (void*)src; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static inline int float_to_mdl_int +( + float num, + uint r_shift, + int min, + int max +) +{ + //const int res = truncf( ldexpf(num,r_shift) + 0.5 ); + const int res = ldexpf(num,r_shift); + return res < min ? min : res > max ? max : res; +} + +//----------------------------------------------------------------------------- + +static void * SetVectorMDL +( + const float3 *src, + void *dest, + uint format, + uint r_shift +) +{ + DASSERT(dest); + DASSERT(src); + + switch (format) + { + case 0: // u8 + ((u8*)dest)[0] = float_to_mdl_int(src->x,r_shift,0,0xff); + ((u8*)dest)[1] = float_to_mdl_int(src->y,r_shift,0,0xff); + ((u8*)dest)[2] = float_to_mdl_int(src->z,r_shift,0,0xff); + return (u8*)dest + 3; + + case 1: // s8 + ((s8*)dest)[0] = float_to_mdl_int(src->x,r_shift,-0x80,0x7f); + ((s8*)dest)[1] = float_to_mdl_int(src->y,r_shift,-0x80,0x7f); + ((s8*)dest)[2] = float_to_mdl_int(src->z,r_shift,-0x80,0x7f); + return (s8*)dest + 3; + + case 2: // u16 + write_be16((u16*)dest+0,float_to_mdl_int(src->x,r_shift,0,0xffff)); + write_be16((u16*)dest+1,float_to_mdl_int(src->y,r_shift,0,0xffff)); + write_be16((u16*)dest+2,float_to_mdl_int(src->z,r_shift,0,0xffff)); + return (u16*)dest + 3; + + case 3: // s16 + write_be16((s16*)dest+0,float_to_mdl_int(src->x,r_shift,-0x8000,0x7fff)); + write_be16((s16*)dest+1,float_to_mdl_int(src->y,r_shift,-0x8000,0x7fff)); + write_be16((s16*)dest+2,float_to_mdl_int(src->z,r_shift,-0x8000,0x7fff)); + return (s16*)dest + 3; + + case 4: // float + write_bef4n(dest,src->v,3); + return (float*)dest + 3; + + default: + return (void*)dest; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static const MemItem_t * GetMemItemMDLs1 +( + const mdl_t *mdl, // pointer to valid MDL + const MemItem_t *eptr, // pointer to section data + s32 offset // offset to neigbour section 1 +) +{ + DASSERT(mdl); + DASSERT(eptr); + + if (!offset) + return 0; + + const MemItem_t *ebase = GetMemListElem(&mdl->elem,0,0); + const MemItem_t *ptr, *eend = ebase + mdl->elem.used; + + #if USE_NEW_CONTAINER_MDL + if (InContainerP(&mdl->container,eptr->data)) + #else + if (InDataContainer(mdl->old_container,eptr->data)) + #endif + { + const u8 * search = eptr->data + offset; + for ( ptr = ebase; ptr < eend; ptr++ ) + if ( ptr->idx1 == 1 && ptr->data == search ) + { + noPRINT("MDLs1 found by address: %u + %x = %u\n", + eptr->idx2, offset, ptr->idx2 ); + return ptr; + } + } + + int idx = offset / (int)sizeof(mdl_sect1_t); + if ( idx * (int)sizeof(mdl_sect1_t) == offset ) + { + idx += eptr->idx2; + for ( ptr = ebase; ptr < eend; ptr++ ) + if ( ptr->idx1 == 1 && ptr->idx2 == idx ) + { + noPRINT("MDLs1 found by index: %u + %x = %u\n", + eptr->idx2, offset, ptr->idx2 ); + return ptr; + } + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static ccp GetNameMDLs1 +( + const mdl_t *mdl, // pointer to valid MDL + const MemItem_t *eptr, // pointer to section data + s32 offset, // offset to neigbour section 1 + ccp if_not_found // return this, if not found +) +{ + DASSERT(mdl); + DASSERT(eptr); + + eptr = GetMemItemMDLs1(mdl,eptr,offset); + return eptr ? eptr->name : if_not_found; +} + +/////////////////////////////////////////////////////////////////////////////// + +static MemItem_t * FindSectionbyTypeMDL +( + const mdl_t *mdl, // pointer to valid MDL + uint idx // index of section to find +) +{ + DASSERT(mdl); + + MemItem_t *ptr = GetMemListElem(&mdl->elem,0,0); + MemItem_t *end = ptr + mdl->elem.used; + + for ( ; ptr < end; ptr++ ) + if ( ptr->idx1 == idx ) + return ptr; + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static MemItem_t * FindSectionbyPtrMDL +( + const mdl_t *mdl, // valid MDL + const u8 *sptr, // pointer to search + int sect // >=0: search section type only +) +{ + MemItem_t *ptr = GetMemListElem(&mdl->elem,0,0); + MemItem_t *end = ptr + mdl->elem.used; + + for ( ; ptr < end; ptr++ ) + if ( ptr->data == sptr ) + return sect < 0 || sect == ptr->idx1 ? ptr : 0; + return 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// MDL0 string iterator /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void scan_sections +( + struct StringIteratorMDL_t *sit, // string iterator data + MemItem_t *mi // memory item of section +) +{ + DASSERT(sit); + DASSERT(sit->mdl); + DASSERT(mi); + + switch(mi->idx1) + { + //case 1: + // offsets: 0x5c..: parent, child1, next, prev, part2 + + //case 8: + // offsets: 0x28=shader, 0x30=layer, 0x34=part2, + // 0x38=display_8_9, 0x3c=display_10_11, + + //case 10: + // offsets: 0x20=vertex_decl, 0x2c=vertex_data, 0x64=bone + + case 11: + { + MemItem_t *m8_base = GetMemListElem(&sit->mdl->elem,0,0); + MemItem_t *m8_ptr, *m8_end = m8_base + sit->mdl->elem.used; + + uint n = ( mi->size - 4 ) / 8; + if ( n > 0 ) + { + uint max = be32(mi->data); + if ( n > max ) + n = max; + u32 *sptr = GetStrIdxMIL(mi,2*n); + u32 *src = (u32*)mi->data + 1; + for ( ; n-- > 0; sptr += 2, src += 2 ) + { + sptr[0] = sptr[1] = 1; // default to "-" + const u8* ptr1 = mi->data + be32(src); + for ( m8_ptr = m8_base; m8_ptr < m8_end; m8_ptr++ ) + if ( m8_ptr->idx1 == 8 && m8_ptr->data == ptr1 ) + { + const u32 *m8_sptr = GetStrIdxListMIL(m8_ptr); + sptr[0] = m8_sptr[0]; + + const u8* ptr2 = mi->data + be32(src+1); + if ( ptr2 < m8_ptr->data + m8_ptr->size ) + { + const u8 *layer0 = m8_ptr->data + be32(m8_ptr->data+0x30); + const uint layer_index = ( ptr2 - layer0 ) / 0x34; + //printf("%p %p => 0x%06zx => %d\n",ptr2,layer0,ptr2-layer0,layer_index); + if ( layer0 + 0x34 * layer_index == ptr2 ) + sptr[1] = m8_sptr[layer_index+1]; + } + break; + } + } + } + } + break; + } +} + +//----------------------------------------------------------------------------- + +void scan_strings +( + struct StringIteratorMDL_t *sit, // string iterator data + u32 *sptr, // pointer to string index + u8 *base, // base of item + u32 *data // pointer to string reference +) +{ + DASSERT(sit); + DASSERT(sit->mdl); + DASSERT(sit->sp); + DASSERT(sptr); + DASSERT(base); + DASSERT(data); + + #if USE_NEW_CONTAINER_MDL + if (InContainerP(&sit->mdl->container,data)) + #else + if (InDataContainer(sit->mdl->old_container,data)) + #endif + { + ccp str = (ccp)base + ntohl(*data); + #if USE_NEW_CONTAINER_MDL + if (InContainerP(&sit->mdl->container,str)) + #else + if (InDataContainer(sit->mdl->old_container,str)) + #endif + { + noPRINT("%p %p+%06x = %p |%s|\n",base,data,ntohl(*data),str,str); + *sptr = InsertStringPool(sit->sp,str,false,str); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void string_collect +( + struct StringIteratorMDL_t *sit, // string iterator data + u32 *sptr, // pointer to string index + u8 *base, // base of item + u32 *data // pointer to string reference +) +{ + DASSERT(sit); + DASSERT(sit->mdl); + DASSERT(sit->sp); + DASSERT(base); + DASSERT(data); + + const uint idx = be32(data); + if ( idx < sit->mdl->spool.n2s_size ) + { + ccp str = sit->mdl->spool.n2s_list[idx]; + if (str) + InsertStringPool(sit->sp,str,false,0); + } +} + +//----------------------------------------------------------------------------- + +void string_export +( + struct StringIteratorMDL_t *sit, // string iterator data + u32 *sptr, // pointer to string index + u8 *base, // base of item + u32 *data // pointer to string reference +) +{ + DASSERT(sit); + DASSERT(sit->mdl); + DASSERT(sit->sp); + DASSERT(sptr); + DASSERT(base); + DASSERT(data); + + u32 res = 0; + const uint idx = *sptr; + if ( idx < sit->mdl->spool.n2s_size ) + { + ccp str = sit->mdl->spool.n2s_list[idx]; + if (str) + res = FindStringPool(sit->sp,str,0) + sit->mdl->raw_data - base; + noPRINT("-> %d/%d : %zx %x %s\n", + idx, sit->sp->n2s_size, res + base - sit->mdl->raw_data, res, str ); + } + write_be32(data,res); +} + +//----------------------------------------------------------------------------- + +void offset_export +( + struct StringIteratorMDL_t *sit, // string iterator data + u8 *base, // base of item + u32 *data // pointer to string reference +) +{ + DASSERT(sit); + DASSERT(sit->mdl); + DASSERT(sit->sp); + DASSERT(base); + DASSERT(data); + + write_be32(data,sit->mdl->raw_data-base); +} + +//----------------------------------------------------------------------------- + +void string_copy +( + struct StringIteratorMDL_t *sit, // string iterator data + u32 *sptr, // pointer to string index + u8 *base, // base of item + u32 *data // pointer to string reference +) +{ + DASSERT(sit); + DASSERT(sit->mdl); + DASSERT(sit->sp); + DASSERT(sptr); + DASSERT(base); + DASSERT(data); + + u32 res = 0; + const uint idx = *sptr; + if ( idx < sit->mdl->spool.n2s_size ) + { + ccp str = sit->mdl->spool.n2s_list[idx]; + if (str) + res = InsertStringPool(sit->sp,str,false,0); + } + *sptr = res; +} + +/////////////////////////////////////////////////////////////////////////////// + +void IterateStringsMDL +( + StringIteratorMDL_t *sit, // string iterator data + MemItem_t *mi, // pointer to memlist + int mi_count // number of elements of 'ml_ptr' +) +{ + DASSERT(sit); + DASSERT(sit->mdl); + DASSERT(sit->sp); + DASSERT(mi); + + // => GetStrIdxMIL() must be called for every access, because data may be moved! + + for ( ; mi_count > 0; mi_count--, mi++ ) + { + u8 *data = (u8*)mi->data; + if (!data) + continue; + + noPRINT("--- grp=%d, idx=%d, size=%u\n",mi->idx1,mi->idx2,mi->size); + + if (sit->sect_func) + sit->sect_func(sit,mi); + + if ( sit->off_func && mi->idx1 >= 1 && mi->idx1 <= 10 ) + sit->off_func(sit,data,(u32*)(data+0x04)); + + switch(mi->idx1) // group + { + case 1: + if (sit->str_func) + sit->str_func(sit,GetStrIdxMIL(mi,1),data,(u32*)(data+0x08)); + break; + + case 2: + case 3: + case 4: + case 5: + if (sit->str_func) + sit->str_func(sit,GetStrIdxMIL(mi,1),data,(u32*)(data+0x0c)); + break; + + case 8: + if (sit->str_func) + { + const uint n_layer = be32(data+0x2c); + sit->str_func(sit,GetStrIdxMIL(mi,n_layer+1),data,(u32*)(data+0x08)); + noPRINT("[%d] %p %x\n",count,data,be32(data+0x08)); + u32 layer_off = be32(data+0x30); + uint i; + for ( i = 0; i < n_layer; i++, layer_off += 0x34 ) + { + u8 * d = data + layer_off; + sit->str_func(sit,GetStrIdxMIL(mi,0)+i+1,d,(u32*)d); + } + } + break; + + case 10: + if (sit->str_func) + sit->str_func(sit,GetStrIdxMIL(mi,1),data,(u32*)(data+0x38)); + break; + } + } +} + +//----------------------------------------------------------------------------- + +void IterateAllStringsMDL +( + StringIteratorMDL_t *sit // string iterator data +) +{ + DASSERT(sit); + DASSERT(sit->mdl); + + MemItem_t *mi = GetMemListElem(&sit->mdl->elem,0,0); + IterateStringsMDL(sit,mi,sit->mdl->elem.used); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// MDL0 iterator /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static int mdl_iter_func +( + brsub_cut_t *bcut, // pointer to data structure + int grp, // index of group, <0: grp_entry_t + int entry // index of entry, -1: no entry +) +{ + DASSERT(bcut); + szs_iterator_t *it = bcut->it; + DASSERT(it); + DASSERT(it->func_it); + + it->brsub_version = bcut->version; + it->group = grp; + it->entry = entry; + + noPRINT("MDL( %2d, %2d, %s )\n",grp,entry,it->path); + + switch (grp) + { + case GROUP_IDX_SUB_HEADER: + { + const mdl_head_t *head = (mdl_head_t*)( bcut->data + it->off ); + it->size = sizeof(*head); + it->entry = 0; + //int stat = IterateFilesFuncBRSUB(bcut,grp,entry,name); + int stat = it->func_it(it,false); + it->index++; + + //--- MDL bone table + + u32 off = be32(&head->bone_offset); + if ( off && !stat ) + { + u8 * d = (u8*)head + off; + it->off = d - bcut->data; + it->size = be32(d) * 4 + 4; + it->entry = 1; + snprintf(it->path,sizeof(it->path),"%s.bone-table.bin",bcut->id); + stat = it->func_it(it,false); + it->index++; + } + return stat; + } + + case 0: + { + mdl_sect0_t ms0; + InitializeMDLs0(&ms0,bcut->data+it->off,bcut->size-it->off); + it->size = ms0.data_size; + } + break; + + case 11: + if (entry>=0) + it->size = it->endian->rd32(bcut->data+it->off) * 8 + 4; + break; + } + + const int stat = it->func_it(it,false); + it->index++; + return stat; +} + +//----------------------------------------------------------------------------- + +static ccp mdl_names[] = +{ + ".draw-list", // 0 + ".bones", // 1 + ".verticies", // 2 + ".normals", // 3 + ".colors", // 4 + ".t-coord", // 5 + "", // 6 + "", // 7 + ".materials", // 8 + ".mat-nodes", // 9 + ".objects", // 10 + ".t-links", // 11 + 0 +}; + +static ccp GetSectNameMDL ( uint index ) +{ + ccp res = index < sizeof(mdl_names)/sizeof(*mdl_names) + ? mdl_names[index] + : 0; + if ( !res || !*res ) + { + const int bufsize = 12; + char *buf = GetCircBuf(bufsize); + snprintf(buf,bufsize,".%u",index); + res = buf; + } + return res; +} + +//----------------------------------------------------------------------------- + +int IterateFilesMDL +( + struct szs_iterator_t *it, // iterator struct with all infos + bool term // true: termination hint +) +{ + DASSERT(it); + return CutFilesBRSUB( it, mdl_iter_func, 0, + mdl_names, sizeof(mdl_names) / sizeof(*mdl_names) -1 ); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// MDL0 base interface /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void InitializeMDL ( mdl_t * mdl ) +{ + DASSERT(mdl); + memset(mdl,0,sizeof(*mdl)); + + mdl->fname = EmptyString; + InitializeMIL(&mdl->elem); + InitializeStringPool(&mdl->spool); + + LoadParametersMDL( verbose > 0 ? " - " : 0 ); + + // [[2do]] [[mdl]] ??? +} + +/////////////////////////////////////////////////////////////////////////////// + +void ResetMDL ( mdl_t * mdl ) +{ + DASSERT(mdl); + FREE(mdl->bone_tab); + FreeString(mdl->fname); + FreeString(mdl->name); + ResetMIL(&mdl->elem); + ResetStringPool(&mdl->spool); + #if USE_NEW_CONTAINER_MDL + ResetContainer(&mdl->container); + #else + FreeContainer(mdl->old_container); + #endif + InitializeMDL(mdl); +} + +/////////////////////////////////////////////////////////////////////////////// + +ccp GetStringMDL +( + mdl_t * mdl, // MDL data structure + const void * base, // base for offset + u32 offset, // offset of string + ccp if_invalid // result if invalid +) +{ + DASSERT(mdl); + DASSERT(base); + + if (offset) + { + ccp string = (ccp)base + offset; + #if USE_NEW_CONTAINER_MDL + if (InContainerP(&mdl->container,string)) + #else + if (InDataContainer(mdl->old_container,string)) + #endif + { + //HEXDUMP16(0,0,string,32); + return string; + } + } + + return if_invalid; +} + +/////////////////////////////////////////////////////////////////////////////// + +static ccp GetStringDataMDL +( + mdl_t *mdl, // MDL data structure + const void *data, // pointer to data + int group, // group index + ccp if_invalid // result if invalid +) +{ + DASSERT(mdl); + DASSERT(data); + + #if USE_NEW_CONTAINER_MDL + if (IsValidContainer(&mdl->container)) + #else + if (mdl->old_container) + #endif + { + switch (group) + { + case 1: + { + const mdl_sect1_t *ms = (mdl_sect1_t*)data; + const u32 name_off = ntohl(ms->name_off); + return GetStringMDL(mdl,data,name_off,if_invalid); + } + + case 2: + { + const mdl_sect2_t *ms = (mdl_sect2_t*)data; + const u32 name_off = ntohl(ms->name_off); + return GetStringMDL(mdl,data,name_off,if_invalid); + } + + case 8: + { + const mdl_sect8_t *ms = (mdl_sect8_t*)data; + const u32 name_off = ntohl(ms->name_off); + return GetStringMDL(mdl,data,name_off,if_invalid); + } + + case 10: + { + const mdl_sect10_t *ms = (mdl_sect10_t*)data; + const u32 name_off = ntohl(ms->name_off); + return GetStringMDL(mdl,data,name_off,if_invalid); + } + + // [[newsect]] + } + } + + return if_invalid; +} + +/////////////////////////////////////////////////////////////////////////////// + +ccp GetStringItMDL +( + struct + szs_iterator_t *it, // iterator struct with all infos + bool *res_alloced // result => true: name is alloced +) +{ + DASSERT(it); + DASSERT(res_alloced); + DASSERT(it->szs); + mdl_t *mdl = it->param; + DASSERT(mdl); + + *res_alloced = false; + + + //--- first try 'it->name' + + #if USE_NEW_CONTAINER_MDL + if (InContainerP(&mdl->container,it->name)) + #else + if (InDataContainer(mdl->old_container,it->name)) + #endif + { + noPRINT("GetStringItMDL() LINK NAME => %s\n",it->name); + return it->name; + } + + + //--- analyse well known name offsets + + const u8 *data = it->szs->data + it->off; + ccp res = GetStringDataMDL(mdl,data,it->group,0); + + + //--- should never happen: make a copy of it->name + + if ( !res && it->name ) + { + noPRINT("!!!!!!!!!! GetStringItMDL() => |%.30s|\n",it->name); + res = STRDUP(it->name); + *res_alloced = true; + } + + return res; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// setup mdl parser /////////////// +/////////////////////////////////////////////////////////////////////////////// + +const VarMap_t * SetupVarsMDL() +{ + static VarMap_t vm = {0}; + if (!vm.used) + { + #if 0 + //--- setup integer variables + + struct inttab_t { ccp name; int val; }; + static const struct inttab_t inttab[] = + { + {0,0} + }; + + const struct inttab_t * ip; + for ( ip = inttab; ip->name; ip++ ) + DefineIntVar(&vm,ip->name,ip->val); + #endif + + //--- setup basic parser variables + + DefineParserVars(&vm); + } + + return &vm; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// Scan MDL sections /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static enumError ScanSetupMDL +( + mdl_t * mdl, // MDL data structure + ScanInfo_t * si // valid data +) +{ + DASSERT(mdl); + DASSERT(si); + TRACE("ScanTextSETUP()\n"); + + ScanParam_t ptab[] = + { + { "MDL-NAME", SPM_STRING, &mdl->name }, + { "MDL-VERSION", SPM_NONE, 0 }, + { "N-SECTIONS", SPM_NONE, 0 }, + {0} + }; + + for(;;) + { + char ch = NextCharSI(si,true); + if ( !ch || ch == '[' ) + break; + + if ( ch == '@' ) + { + ScanParamSI(si,ptab); + continue; + } + + // ignore all others + GotoEolSI(si); + } + CheckLevelSI(si); + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError ScanHexMDL +( + mdl_t * mdl, // MDL data structure + mdl_section_id sect, // MDL section + ScanInfo_t * si // valid data +) +{ + DASSERT(mdl); + DASSERT(si); + TRACE("ScanTextSETUP()\n"); + + char *name = 0; + uint sort_index = 0; + ScanParam_t ptab[] = + { + { "NAME", SPM_STRING, &name }, + { "SORT-INDEX", SPM_UINT, &sort_index }, + {0} + }; + + char fb_buf[1000]; + FastBuf_t *fb = InitializeFastBuf(fb_buf,sizeof(fb_buf)); + + for(;;) + { + char ch = NextCharSI(si,true); + if ( !ch || ch == '[' ) + break; + + if ( ch == '@' ) + { + ScanParamSI(si,ptab); + continue; + } + + if ( ch == '$' ) + { + GotoEolSI(si); + continue; + } + + ScanHexlineSI(si,fb,true); + } + CheckLevelSI(si); + + printf("NAME: %s\nSORT: %u\n",name,sort_index); + HexDump16(stdout,0,0,fb->buf,fb->ptr-fb->buf); + + FreeString(name); + ResetFastBuf(fb); + return ERR_OK; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// ScanTextMDL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static const KeywordTab_t mdl_section_name[] = +{ + { MDL_IGNORE, "END", "--", 0 }, + { MDL_SETUP, "SETUP", "Setup", 0 }, + { MDL_SETUP, "BONE-TABLE", "Bone Table", 0 }, + + { MDL_SECTION_0, "SECTION-0", "Section 0", 0 }, + { MDL_SECTION_1, "SECTION-1", "Section 1", 0 }, + { MDL_SECTION_2, "SECTION-2", "Section 2", 0 }, + { MDL_SECTION_3, "SECTION-3", "Section 3", 0 }, + { MDL_SECTION_4, "SECTION-4", "Section 4", 0 }, + { MDL_SECTION_5, "SECTION-5", "Section 5", 0 }, + { MDL_SECTION_6, "SECTION-6", "Section 6", 0 }, + { MDL_SECTION_7, "SECTION-7", "Section 7", 0 }, + { MDL_SECTION_8, "SECTION-8", "Section 8", 0 }, + { MDL_SECTION_9, "SECTION-9", "Section 9", 0 }, + { MDL_SECTION_10, "SECTION-10", "Section 10", 0 }, + { MDL_SECTION_11, "SECTION-11", "Section 11", 0 }, + + + { 0,0,0,0 } +}; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanTextMDL +( + mdl_t * mdl, // MDL data structure + bool init_mdl, // true: initialize 'mdl' first + const void * data, // data to scan + uint data_size // size of 'data' +) +{ + PRINT("ScanTextMDL(init=%d)\n",init_mdl); + + DASSERT(mdl); + if (init_mdl) + InitializeMDL(mdl); + + mdl->version = 11; + mdl->n_sect = 14; + + ScanInfo_t si; + InitializeSI(&si,data,data_size,mdl->fname,mdl->revision); + si.predef = SetupVarsMDL(); + + enumError max_err = ERR_OK; + mdl->is_pass2 = false; + + for(;;) + { + PRINT("----- SCAN MDL SECTIONS, PASS%u ...\n",mdl->is_pass2+1); + + max_err = ERR_OK; + si.mdl = mdl; + si.no_warn = !mdl->is_pass2; + si.total_err = 0; + DefineIntVar(&si.gvar, "$PASS", mdl->is_pass2+1 ); + + for(;;) + { + char ch = NextCharSI(&si,true); + if (!ch) + break; + + if ( ch != '[' ) + { + NextLineSI(&si,true,false); + continue; + } + ResetLocalVarsSI(&si,mdl->revision); + + si.cur_file->ptr++; + char sect_name[20]; + ScanNameSI(&si,sect_name,sizeof(sect_name),true,true,0); + PRINT0("--> pass=%u: #%04u: %s\n",mdl->is_pass2+1,si.cur_file->line,sect_name); + + int abbrev_count; + const KeywordTab_t *cmd = ScanKeyword(&abbrev_count,sect_name,mdl_section_name); + if ( !cmd || abbrev_count ) + continue; + NextLineSI(&si,false,false); + PRINT0("--> %-6s #%-4u |%.3s|\n",cmd->name1,si.cur_file->line,si.cur_file->ptr); + + enumError err = ERR_OK; + switch (cmd->id) + { + case MDL_IGNORE: + // ignore it without warning + break; + + case MDL_SETUP: + ScanSetupMDL(mdl,&si); + break; + + case MDL_BONE_TABLE: + case MDL_SECTION_0: + case MDL_SECTION_1: + case MDL_SECTION_2: + case MDL_SECTION_3: + case MDL_SECTION_4: + case MDL_SECTION_5: + case MDL_SECTION_6: + case MDL_SECTION_7: + case MDL_SECTION_8: + case MDL_SECTION_9: + case MDL_SECTION_10: + case MDL_SECTION_11: + ScanHexMDL(mdl,cmd->id,&si); + break; + + default: + err = ERROR0(ERR_WARNING,"Unknown section (ignored): %s\n",sect_name); + break; + } + + if ( max_err < err ) + max_err = err; + } + + if (mdl->is_pass2) + break; + + mdl->is_pass2 = true; + RestartSI(&si); + } + + ResetSI(&si); + + return max_err; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// ScanRawMDL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static int scan_raw_mdl_func +( + struct szs_iterator_t *it, // iterator struct with all infos + bool term // true: termination hint +) +{ + DASSERT(it); + DASSERT(it->szs); + mdl_t *mdl = it->param; + DASSERT(mdl); + + noPRINT("--> %3d,%3d term=%u size=%4u : %s\n", + it->group, it->entry, term, it->size, it->path ); + if ( term || it->size <= 0 ) + return 0; + + const u8 *data = it->szs->data + it->off; + if ( it->group == GROUP_IDX_SUB_HEADER ) + { + if ( it->entry == 0 && it->size >= sizeof(mdl_head_t) ) + { + const mdl_head_t *hsrc = (mdl_head_t*)data; + mdl_head_t *hdest = &mdl->head; + be32n(&hdest->head_len,&hsrc->head_len,10); + bef4n(hdest->min,hsrc->min,6); + } + else if ( it->entry == 1 && it->size >= 4 ) + { + const int max = (it->size-4) / sizeof(*mdl->bone_tab); + uint n = be32(data); + PRINT("BONE TABLE: N=%u,%u\n",n,max); + if ( n > max ) + n = max; + if ( n > 0 ) + { + mdl->bone_n = n; + FREE(mdl->bone_tab); + const u32 *src = (u32*)(data+4); + u32 *dest = mdl->bone_tab = MALLOC( n * sizeof(*mdl->bone_tab) ); + while ( n-- > 0 ) + *dest++ = be32(src++); + DASSERT( (u8*)src <= data + it->size ); + } + } + } + else if ( it->entry >= 0 ) + { + MemItem_t * item = AppendMIL(&mdl->elem); + DASSERT(item); + item->idx1 = it->group; + item->idx2 = it->entry; + item->size = it->size; + #if USE_NEW_CONTAINER_MDL + if (InContainerP(&mdl->container,data)) + #else + if (InDataContainer(mdl->old_container,data)) + #endif + item->data = (u8*)data; + else + { + item->data = MEMDUP(data,item->size); + item->data_alloced = true; + } + + item->name = GetStringItMDL(it,&item->name_alloced); + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanRawMDL +( + mdl_t * mdl, // MDL data structure + bool init_mdl, // true: initialize 'mdl' first + const void * data, // data to scan + uint data_size, // size of 'data' + ContainerMDL_t * cdata // NULL or container-data +) +{ + DASSERT(mdl); + + #ifdef TEST + SaveFile("_mdl-1.tmp",0,FM_OVERWRITE,data,data_size,0); + #endif + + #if USE_NEW_CONTAINER_MDL // --------------------------------------- + + if (init_mdl) + InitializeMDL(mdl); + + CatchContainerData(&mdl->container,0,cdata); + AssignContainer(&mdl->container,0,data,data_size,CPM_COPY); + #ifdef TEST + DumpInfoContainer(stdlog,collog,2,"MDL: ",&mdl->container,0); + #endif + + if (InContainerP(&mdl->container,data)) + mdl->mdl_offset = (u8*)data - mdl->container.cdata->data; + + #else // !USE_NEW_CONTAINER_MDL // --------------------------------- + + if (init_mdl) + InitializeMDL(mdl); + else + FreeContainer(mdl->old_container); + + mdl->old_container = DupContainer(cdata,data,data_size,true,&data); + PRINT("CONTAINER: %p,0x%x -> %p,0x%x [%d]\n", + data, data_size, + mdl->old_container->data, mdl->old_container->size, + mdl->old_container->ref_count ); + + if (InDataContainer(cdata,data)) + mdl->mdl_offset = (u8*)data - cdata->data; + + #endif // !USE_NEW_CONTAINER_MDL // -------------------------------- + + const endian_func_t * endian = &be_func; + if ( IsValidMDL(data,data_size,data_size,0,mdl->fname,endian) >= VALID_ERROR ) + { + return ERROR0(ERR_INVALID_DATA, + "Invalid MDL file: %s\n", mdl->fname ? mdl->fname : "?"); + } + + + //--- scan MDL base infos + + mdl->version = endian->rd32(data+8); + mdl->n_sect = GetSectionNumBRSUB(data,data_size,endian); + + + //--- get MDL name + + const uint off = offsetof(brsub_header_t,grp_offset) + mdl->n_sect * 4; + const uint name_off = be32(data+off); + ccp name = GetStringBRSUB(data,data+data_size,off,data,name_off,0,0); + if (name) + mdl->name = STRDUP(name); + + + //--- scan MDL header & sections + + cut_iter_func[FF_MDL] = IterateFilesMDL; // enable MDL support +// [[fname+]] + IterateFilesData(data,data_size,scan_raw_mdl_func,mdl,FF_MDL,mdl->fname); + SortMIL(&mdl->elem,false); + + + //--- string handling + + ResetStringPool(&mdl->spool); + InsertStringPool(&mdl->spool,"-",false,0); + + StringIteratorMDL_t sim; + memset(&sim,0,sizeof(sim)); + sim.mdl = mdl; + sim.sp = &mdl->spool; + sim.sect_func = scan_sections; + sim.str_func = scan_strings; + IterateAllStringsMDL(&sim); + + #ifdef TEST0 + { + uint i; + for ( i = 0; i < mdl->spool.n2s_size; i++ ) + { + ccp str = mdl->spool.n2s_list[i]; + if (str) + PRINT("SP %2u: %s\n",i,str); + } + } + #endif + + #ifdef TEST + SaveFile("_mdl-2.tmp",0,FM_OVERWRITE,data,data_size,0); + #endif + return ERR_OK; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// iterate MDL sub files /////////////// +/////////////////////////////////////////////////////////////////////////////// + +typedef struct iter_helper_mdl_t +{ + struct raw_data_t * raw; // valid raw data + CheckMode_t check_mode; // not NULL: call CheckMDL(mode) + iterate_mdl_func func; // function to call + void *param; // user defined parameter + enumError max_err; // max error code + +} iter_helper_mdl_t; + +//----------------------------------------------------------------------------- + +static int iter_raw_data_mdl +( + struct szs_iterator_t *it, // iterator struct with all infos + bool term // true: termination hint +) +{ + DASSERT(it); + if ( term || it->is_dir ) + return 0; + + DASSERT(it->szs); + const u8 *data = it->szs->data + it->off; +// [[analyse-magic]] + file_format_t fform = GetByMagicFF(data,it->size,it->size); + if ( fform != FF_MDL && fform != FF_MDL_TXT ) + return 0; + + DASSERT(it->param); + iter_helper_mdl_t *iparam = it->param; + DASSERT(iparam->raw); + DASSERT(iparam->func); + + mdl_t mdl; + InitializeMDL(&mdl); + mdl.fname = STRDUP3(iparam->raw->fname,"/",it->path); + + #if USE_NEW_CONTAINER_MDL + enumError err = ScanMDL(&mdl,false,data,it->size, + LinkContainerRawData(iparam->raw),iparam->check_mode); + #else + enumError err = ScanMDL(&mdl,false,data,it->size, + ContainerRawData(iparam->raw),iparam->check_mode); + #endif + if ( err < ERR_WARNING ) + err = iparam->func(&mdl,iparam->param); + if ( iparam->max_err < err ) + iparam->max_err = err; + ResetMDL(&mdl); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError IterateRawDataMDL +( + struct raw_data_t * raw, // valid raw data + CheckMode_t check_mode, // not NULL: call CheckMDL(mode) + iterate_mdl_func func, // call this function for each found MDL + void * param // a user defined parameter +) +{ + DASSERT(raw); + DASSERT(func); + + if ( raw->fform == FF_MDL + || raw->fform == FF_MDL_TXT + || !IsArchiveFF(raw->fform) ) + { + mdl_t mdl; + enumError err = ScanRawDataMDL(&mdl,true,raw,check_mode); + if ( err < ERR_WARNING ) + err = func(&mdl,param); + ResetMDL(&mdl); + return err; + } + + iter_helper_mdl_t iparam; + iparam.raw = raw; + iparam.check_mode = check_mode; + iparam.func = func; + iparam.param = param; + iparam.max_err = ERR_OK; + + szs_file_t szs; +// [[fname+]] + AssignSZS(&szs,true,raw->data,raw->data_size,false,raw->fform,raw->fname); + IterateFilesSZS(&szs,iter_raw_data_mdl,&iparam,false,-1,-1,SORT_NONE); + ResetSZS(&szs); + return iparam.max_err; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// MDL0 scan + load /////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanMDL +( + mdl_t * mdl, // MDL data structure + bool init_mdl, // true: initialize 'mdl' first + const void * data, // data to scan + uint data_size, // size of 'data' + ContainerMDL_t * cdata, // NULL or container-data + CheckMode_t mode // not NULL: call CheckMDL(mode) +) +{ + DASSERT(mdl); + PRINT("ScanMDL(mode=%x) size=%u\n",mode,data_size); + + enumError err; +// [[analyse-magic]] + switch (GetByMagicFF(data,data_size,data_size)) + { + case FF_MDL: + mdl->fform = FF_MDL; + if ( disable_patch_on_load > 0 || !HavePatchMDL() ) + err = ScanRawMDL(mdl,init_mdl,data,data_size,cdata); + else + { + //dc = 0; + u8 *temp = MEMDUP(data,data_size); + PatchRawDataMDL(temp,data_size,0,mdl->fname); + err = ScanRawMDL(mdl,init_mdl,temp,data_size,0); + FREE(temp); + } + break; + + case FF_MDL_TXT: + #if USE_NEW_CONTAINER_MDL + FreeContainerData(cdata); + #else + FreeContainer(cdata); + #endif + mdl->fform = FF_MDL_TXT; + err = ScanTextMDL(mdl,init_mdl,data,data_size); + break; + + default: + #if USE_NEW_CONTAINER_MDL + FreeContainerData(cdata); + #else + FreeContainer(cdata); + #endif + if (init_mdl) + InitializeMDL(mdl); + return ERROR0(ERR_INVALID_DATA, + "No MDL file: %s\n", mdl->fname ? mdl->fname : "?"); + } + + if ( err <= ERR_WARNING && mode ) + CheckMDL(mdl,mode); + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanRawDataMDL +( + mdl_t * mdl, // MDL data structure + bool init_mdl, // true: initialize 'mdl' first + struct raw_data_t * raw, // valid raw data + CheckMode_t mode // not NULL: call CheckMDL(mode) +) +{ + DASSERT(mdl); + DASSERT(raw); + if (init_mdl) + InitializeMDL(mdl); + else + ResetMDL(mdl); + + mdl->fname = raw->fname; + raw->fname = 0; + #if USE_NEW_CONTAINER_MDL + return ScanMDL(mdl,false,raw->data,raw->data_size,LinkContainerRawData(raw),mode); + #else + return ScanMDL(mdl,false,raw->data,raw->data_size,ContainerRawData(raw),mode); + #endif +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError LoadMDL +( + mdl_t * mdl, // MDL data structure + bool init_mdl, // true: initialize 'mdl' first + ccp fname, // valid pointer to filenname + bool ignore_no_file, // ignore if file does not exists + // and return warning ERR_NOT_EXISTS + CheckMode_t mode // not NULL: call CheckMDL(mode) +) +{ + DASSERT(mdl); + DASSERT(fname); + if (init_mdl) + InitializeMDL(mdl); + else + ResetMDL(mdl); + + //--- load and scan data + + raw_data_t raw; + enumError err = LoadRawData(&raw,true,fname,0,ignore_no_file,false); + if (!err) + { + mdl->fname = raw.fname; + raw.fname = 0; + #if USE_NEW_CONTAINER_MDL + err = ScanMDL(mdl,false,raw.data,raw.data_size,LinkContainerRawData(&raw),mode); + #else + err = ScanMDL(mdl,false,raw.data,raw.data_size,ContainerRawData(&raw),mode); + #endif + } + + ResetRawData(&raw); + return err; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// CreateRawMDL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError CreateRawMDL +( + mdl_t * mdl // pointer to valid MDL +) +{ + DASSERT(mdl); + TRACE("CreateRawMDL()\n"); + + const uint MAX_SECT = 20; // max supported sections + + + //--- setup string pool + + string_pool_t sp; + InitializeStringPool(&sp); + + char fname_buf[200]; + ccp mdl_name = 0; + if (mdl->name) + { + mdl_name = mdl->name; + InsertStringPool(&sp,mdl_name,false,0); + } + else if (mdl->fname) + { + mdl_name = strrchr(mdl->fname,'/'); + mdl_name = mdl_name ? mdl_name+1 : mdl->fname; + uint cut = 0; + const int len = strlen(mdl_name); + if ( len > 4 && ( !strcasecmp(mdl_name+len-4,".mdl") + || !strcasecmp(mdl_name+len-4,".bin") )) + cut = len-4; + else if ( len > 5 && !strcasecmp(mdl_name+len-5,".mdl0") ) + cut = len-5; + + if (cut) + { + StringCopySM(fname_buf,sizeof(fname_buf),mdl_name,cut); + mdl_name = fname_buf; + } + InsertStringPool(&sp,mdl_name,false,0); + } + + + //--- version and sections + + uint sect_count[MAX_SECT]; + memset(sect_count,0,sizeof(sect_count)); + + int version = mdl->version; + int n_sect = GetKnownSectionNumBRSUB(FF_MDL,version); + if ( n_sect <= 0 ) + { + version = 11; + n_sect = GetKnownSectionNumBRSUB(FF_MDL,version); + ASSERT(n_sect>0); + } + const int max_sect = n_sect < MAX_SECT ? n_sect : MAX_SECT; + + + //--- calculate data size (section data) + + SortMIL(&mdl->elem,true); + MemItem_t *mi_base = GetMemListElem(&mdl->elem,0,0); + MemItem_t *mi_ptr, *mi_prev, *mi_end = mi_base + mdl->elem.used; + + uint data_size = 0; + for ( mi_ptr = mi_base, mi_prev = 0; mi_ptr < mi_end; mi_ptr++ ) + { + u8 *data = (u8*)mi_ptr->data; + if ( !data || mi_ptr->idx1 >= max_sect ) + continue; + + if ( !mi_prev || mi_ptr->size != mi_prev->size + || memcmp(mi_ptr->data,mi_prev->data,mi_ptr->size) ) + { + data_size += mi_ptr->size; + } + sect_count[mi_ptr->idx1]++; + + InsertStringPool(&sp,mi_ptr->name,false,0); + mi_prev = mi_ptr; + } + + + //--- calculate header size + + const uint head_offset = 0x14 + 4*n_sect; + const uint bone_offset = head_offset + sizeof(mdl_head_t); + const uint header_size = bone_offset + + 4 + mdl->bone_n * sizeof(*mdl->bone_tab); + + uint sect, brsub_n = 0, brsub_size = 0; + for ( sect = 0; sect < max_sect; sect++ ) + { + const uint n = sect_count[sect]; + if (n) + { + brsub_n += 1 + n; // root + N + brsub_size += 0x18 + n*0x10; + } + } + + PRINT("NS=%d, header_size=0x%x, brsub_n/size=%u,0x%x\n", + n_sect, header_size, brsub_n, brsub_size ); + + + //--- create string pool + + const uint string_offset = header_size + brsub_size + data_size; + + StringIteratorMDL_t sim; + memset(&sim,0,sizeof(sim)); + sim.mdl = mdl; + sim.sp = &sp; + sim.str_func = string_collect; + IterateAllStringsMDL(&sim); + CalcStringPool(&sp,string_offset,&be_func); + const uint file_size = string_offset + sp.size; + + PRINT("CREATE MDL: size = %#x = %u\n",data_size,data_size); + MDL_ACTION_LOG(false,"CreateRawMDL() size=%u\n",data_size); + + + //--- alloc data + + FREE(mdl->raw_data); + u8 * mdata = CALLOC(1,file_size); + mdl->raw_data = mdata; + mdl->raw_data_size = string_offset; + mdl->raw_file_size = file_size; + + + //--- setup header + string pool + + memcpy(mdata,MDL_MAGIC,4); + write_be32(mdata+0x04,string_offset); + write_be32(mdata+0x08,version); + if (mdl_name) + write_be32(mdata+0x10+n_sect*4,FindStringPool(&sp,mdl_name,0)); + memcpy(mdata+string_offset,sp.data,sp.size); + write_be32n((u32*)(mdata+head_offset),(u32*)&mdl->head,16); + + + //--- copy bones + + u32 *ptr = (u32*)(mdata + bone_offset); + write_be32(ptr++,mdl->bone_n); + uint i; + for ( i = 0; i < mdl->bone_n; i++ ) + write_be32(ptr++,mdl->bone_tab[i]); + + + //--- prepare entries + + uint sect_info_idx[MAX_SECT]; + memset(sect_info_idx,0,sizeof(sect_info_idx)); + + brres_info_t *info = CALLOC(brsub_n,sizeof(*info)); + brres_info_t *info_ptr = info; + + u32 offset = header_size; + for ( sect = 0; sect < max_sect; sect++ ) + { + const uint n = sect_count[sect]; + if (n) + { + info_ptr->id = 0xffff; + info_ptr++; + sect_info_idx[sect] = info_ptr - info; + info_ptr += n; + } + } + //HEXDUMP16(0,0,sect_info_idx,sizeof(sect_info_idx)); + + + //--- copy section data + + memset(&sim,0,sizeof(sim)); + sim.mdl = mdl; + sim.sp = &sp; + sim.off_func = offset_export; + sim.str_func = string_export; + + offset = header_size + brsub_size; + for ( mi_ptr = mi_base, mi_prev = 0; mi_ptr < mi_end; mi_ptr++ ) + { + noPRINT("SECT-%d.%d, off=0x%x, size=0x%x\n", + mi_ptr->idx1, mi_ptr->idx2, offset, mi_ptr->size ); + u8 *data = (u8*)mi_ptr->data; + if ( !data || mi_ptr->idx1 >= max_sect ) + continue; + + if ( mi_prev && mi_ptr->size == mi_prev->size + && !memcmp(mi_ptr->data,mi_prev->data,mi_ptr->size) ) + { + offset -= mi_prev->size; + } + + brres_info_t *info_ptr = info + sect_info_idx[mi_ptr->idx1]++; + info_ptr->data_off = offset; + info_ptr->name = mi_ptr->name ? mi_ptr->name : ""; + info_ptr->nlen = strlen(info_ptr->name); + info_ptr->name_off = FindStringPool(&sp,info_ptr->name,0); + + mi_ptr->data = mdata+offset; // temporary + memcpy(mi_ptr->data,data,mi_ptr->size); + IterateStringsMDL(&sim,mi_ptr,1); + mi_ptr->data = data; + + offset += mi_ptr->size; + DASSERT( offset <= string_offset ); + mi_prev = mi_ptr; + } + DASSERT( offset == string_offset ); + //HEXDUMP16(0,0,sect_info_idx,sizeof(sect_info_idx)); + + #ifdef TEST0 + { + uint i; + for ( i = 0; i < brsub_n; i++ ) + { + brres_info_t *bi = info + i; + printf("\t%04x %04x %04x : %06x %06x : [%2d] |%s|\n", + bi->id, bi->left_idx, bi->right_idx, + bi->name_off, bi->data_off, + bi->nlen, bi->name ); + } + } + #endif + + + //--- finish brsub header + + offset = header_size; + for ( info_ptr = info, sect = 0; sect < max_sect; sect++ ) + { + uint n = sect_count[sect]; + if (n) + { + u32 base_offset = offset; + write_be32(mdata+0x10+4*sect,offset); + write_be32(mdata+offset,(n+1)*0x10+8); + offset += 4; + write_be32(mdata+offset,n); + offset += 4; + + uint i; + for ( i = 1; i <= n; i++ ) // without root + CalcEntryBRRES(info_ptr,i); + + for ( i = 0; i <= n; i++ ) // with root + { + brres_entry_t *entry_ptr = (brres_entry_t*)(mdata+offset); + write_be16( &entry_ptr->id, info_ptr->id ); + write_be16( &entry_ptr->left_idx, info_ptr->left_idx ); + write_be16( &entry_ptr->right_idx, info_ptr->right_idx ); + if (info_ptr->data_off) + write_be32( &entry_ptr->data_off, info_ptr->data_off - base_offset ); + if (info_ptr->name_off) + write_be32( &entry_ptr->name_off, info_ptr->name_off - base_offset ); + offset += 0x10; + info_ptr++; + } + } + } + + + //--- terminate + + ResetStringPool(&sp); + FREE(info); + return ERR_OK; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// SaveRawMDL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError SaveRawMDL +( + mdl_t * mdl, // pointer to valid MDL + ccp fname, // filename of destination + bool set_time // true: set time stamps +) +{ + DASSERT(mdl); + DASSERT(fname); + PRINT("SaveRawMDL(%s,%d)\n",fname,set_time); + MDL_ACTION_LOG(false,"SaveRawMDL() %s\n",fname); + + + //--- create raw data + + enumError err = CreateRawMDL(mdl); + if (err) + return err; + DASSERT(mdl->raw_data); + DASSERT(mdl->raw_file_size); + + + //--- write to file + + File_t F; + err = CreateFileOpt(&F,true,fname,testmode,mdl->fname); + if ( err > ERR_WARNING || !F.f ) + return err; + SetFileAttrib(&F.fatt,&mdl->fatt,0); + + if ( fwrite(mdl->raw_data,1,mdl->raw_file_size,F.f) != mdl->raw_file_size ) + FILEERROR1(&F,ERR_WRITE_FAILED,"Write failed: %s\n",fname); + return ResetFile(&F,set_time); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// SaveTextMDL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static enumError SaveTextMDLhex +( + FILE * f, // file to print to + const mdl_t * mdl, // pointer to valid MDL + const MemItem_t * eptr // pointer to section data +) +{ + DASSERT(f); + DASSERT(mdl); + DASSERT(eptr); + + fputs(text_mdl_hexdump_cr,f); + hexdump_eol = "\r\n"; + HexDump(f,0,0,5,16,eptr->data,eptr->size); + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SaveTextMDLs0 +( + FILE * f, // file to print to + const mdl_t * mdl, // pointer to valid MDL + const MemItem_t * eptr // pointer to section data +) +{ + DASSERT(f); + DASSERT(mdl); + DASSERT(eptr); + + if (!brief_count) + fprintf(f,text_mdl_s0_cr); + fprintf(f,text_mdl_s0_tabhead_cr); + + mdl_sect0_t ms0; + InitializeMDLs0(&ms0,eptr->data,eptr->size); + while (NextMDLs0(&ms0)) + { + ccp typestr = GetTypeMDLs0(*ms0.cur); + if (ms0.sub_size) + { + DASSERT(ms0.sub_n>0); + DASSERT(ms0.sub_ptr); + DASSERT(ms0.sub_ptr > ms0.cur); + PrintNumF(f,ms0.cur,ms0.sub_ptr-ms0.cur,typestr); + + typestr = strchr(typestr,'|'); + if (typestr) + typestr++; + + int i; + for ( i = 0; i < ms0.sub_n; i++ ) + { + fputs("\r\n\t> ",f); + PrintNumF(f,ms0.sub_ptr + i*ms0.sub_size,ms0.sub_size,typestr); + } + } + else + PrintNumF(f,ms0.cur,ms0.cur_size,typestr); + fputs("\r\n",f); + } + + if (ms0.fail) + { + fputs("$RAW",f); + PrintNumF(f,ms0.fail,ms0.cur_size,0); + fputs("\r\n",f); + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SaveTextMDLs1 +( + FILE * f, // file to print to + const mdl_t * mdl, // pointer to valid MDL + const MemItem_t * eptr // pointer to section data +) +{ + DASSERT(f); + DASSERT(mdl); + DASSERT(eptr); + + mdl_sect1_t ms; + ntoh_MDLs1(&ms,(mdl_sect1_t*)eptr->data); + if ( eptr->size != sizeof(ms) || ms.length != sizeof(ms) ) + return SaveTextMDLhex(f,mdl,eptr); + + fprintf(f, + "length = %#11x\r\n" + "mdl0-offset = %#11x\r\n" +// "name-offset = %#11x\r\n" + "index = %#11x\r\n" + "id = %#11x\r\n" + "flags = %#11x\r\n" + "padding = %#11x %#11x\r\n" + "\r\n" + "parent = %#11x \"%s\"\r\n" + "child = %#11x \"%s\"\r\n" + "next = %#11x \"%s\"\r\n" + "prev = %#11x \"%s\"\r\n" + "part2 = %#11x \"%s\"\r\n" + "\r\n" + + ,ms.length + ,ms.mdl0_off +// ,ms.name_off + ,ms.index + ,ms.id + ,ms.flags + ,ms.padding[0] ,ms.padding[1] + + ,ms.parent_off ,GetNameMDLs1(mdl,eptr,ms.parent_off,"") + ,ms.child_off ,GetNameMDLs1(mdl,eptr,ms.child_off,"") + ,ms.next_off ,GetNameMDLs1(mdl,eptr,ms.next_off,"") + ,ms.prev_off ,GetNameMDLs1(mdl,eptr,ms.prev_off,"") + ,ms.part2_off ,GetNameMDLs1(mdl,eptr,ms.part2_off,"") + ); + + PrintMatrixMDLs1(f,0,"\r\n",&ms,~0); + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SaveTextMDLs2 +( + FILE * f, // file to print to + const mdl_t * mdl, // pointer to valid MDL + const MemItem_t * eptr // pointer to section data +) +{ + DASSERT(f); + DASSERT(mdl); + DASSERT(eptr); + + mdl_sect2_t ms; + ntoh_MDLs2(&ms,(mdl_sect2_t*)eptr->data); + // if ( eptr->size != sizeof(ms) || ms.length != sizeof(ms) ) + if ( ms.length < sizeof(ms) ) + return SaveTextMDLhex(f,mdl,eptr); + + //--- print base data + + fprintf(f, + "length = %#11x\r\n" + "mdl0-offset = %#11x\r\n" + "data-offset = %#11x\r\n" +// "name-offset = %#11x\r\n" + "index = %#11x\r\n" + "has-bounds = %11u\r\n" + "format = %11u\r\n" + "r_shift = %11u\r\n" + "stride = %11u\r\n" + "n_vertex = %#11x = %6u\r\n" + "minimum = %11.3f %11.3f %11.3f\r\n" + "maximum = %11.3f %11.3f %11.3f\r\n" + "\r\n" + ,ms.length + ,ms.mdl0_off + ,ms.data_off +// ,ms.name_off + ,ms.index + ,ms.has_bounds + ,ms.format + ,ms.r_shift + ,ms.stride + ,ms.n_vertex ,ms.n_vertex + ,ms.minimum.x ,ms.minimum.y ,ms.minimum.z + ,ms.maximum.x ,ms.maximum.y ,ms.maximum.z + ); + + + //--- print vertex table + + const void *data = eptr->data + ms.data_off; + uint n_vertex = ms.n_vertex; + noPRINT("N-VERTEX=%u, FORMAT=%u, R-SHIFT=%u\n",n_vertex,ms.format,ms.r_shift); + + while ( n_vertex-- > 0 ) + { + float3 temp; + data = GetVectorMDL(&temp,data,ms.format,ms.r_shift); + fprintf(f,"v %11.3f %11.3f %11.3f\r\n", temp.x, temp.y, temp.z ); + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SaveTextMDLs10 +( + FILE * f, // file to print to + const mdl_t * mdl, // pointer to valid MDL + const MemItem_t * eptr // pointer to section data +) +{ + DASSERT(f); + DASSERT(mdl); + DASSERT(eptr); + + mdl_sect10_t ms; + ntoh_MDLs10(&ms,(mdl_sect10_t*)eptr->data); + if ( eptr->size < ms.length || ms.length < sizeof(ms) ) + return SaveTextMDLhex(f,mdl,eptr); + + //--- print base data + + fprintf(f, + "length = %#10x\r\n" + "mdl0_off = %#10x\r\n" + "bone_idx = %#10x\r\n" + "cp_vtx = %#10x\r\n" + "cp_tex = %#10x\r\n" + "xf_nor_spec = %#10x\r\n" + "v_decl_size = %#10x\r\n" + "flags = %#10x\r\n" + "v_decl_offset = %#10x\r\n" + "v_data_size1 = %#10x\r\n" + "v_data_size2 = %#10x\r\n" + "v_data_offset = %#10x\r\n" + "xf_flags = %#10x\r\n" + "unknown_0x34 = %#10x\r\n" + "name_off = %#10x\r\n" + "idx = %#10x = %6u\r\n" + "n_vertex = %#10x = %6u\r\n" + "n_face = %#10x = %6u\r\n" + "v_group = %#10x = %6u\r\n" + "n_group = %#10x = %6u\r\n" + "col_groups = %#10x %#06x\r\n" + "tex_groups = %#10x %#06x %#06x %#06x %#06x %#06x %#06x %#06x\r\n" + "unknown_0x60 = %#10x\r\n" + "bone_offset = %#10x\r\n" + ,ms.length + ,ms.mdl0_off + ,ms.bone_idx + ,ms.cp_vtx + ,ms.cp_tex + ,ms.xf_nor_spec + ,ms.v_decl_size + ,ms.flags + ,ms.v_decl_offset + ,ms.v_data_size1 + ,ms.v_data_size2 + ,ms.v_data_offset + ,ms.xf_flags + ,ms.unknown_0x34 + ,ms.name_off + ,ms.idx ,ms.idx + ,ms.n_vertex ,ms.n_vertex + ,ms.n_face ,ms.n_face + ,ms.v_group ,ms.v_group + ,ms.n_group ,ms.n_group + ,ms.col_group[0] ,ms.col_group[1] + ,ms.tex_group[0] ,ms.tex_group[1] ,ms.tex_group[2] ,ms.tex_group[3] + ,ms.tex_group[4] ,ms.tex_group[5] ,ms.tex_group[6] ,ms.tex_group[7] + ,ms.unknown_0x60 + ,ms.bone_offset + ); + + + //--- additonally data + + u32 bone_off = ms.bone_offset; + u32 v_decl_offset = ms.v_decl_offset + 0x20; + u32 v_data_offset = ms.v_data_offset + 0x24; + + + //--- bones + + u32 end = eptr->size; + if ( v_decl_offset > bone_off && end > v_decl_offset ) + end = v_decl_offset; + if ( v_data_offset > bone_off && end > v_data_offset ) + end = v_data_offset; + + if ( bone_off < end ) + { + fprintf(f,"\r\n# bones\r\n\r\n"); + hexdump_prefix = " $HEX "; + hexdump_eol = "\r\n"; + HexDump(f,0,bone_off,5,16,eptr->data+bone_off,end-bone_off); + } + + + //--- vertex declaration + + end = eptr->size; + if ( bone_off > v_decl_offset && end > bone_off ) + end = bone_off; + if ( v_data_offset > v_decl_offset && end > v_data_offset ) + end = v_data_offset; + + if ( v_decl_offset < end ) + { + fprintf(f,"\r\n# vertex declaration\r\n\r\n"); + hexdump_prefix = " $HEX "; + hexdump_eol = "\r\n"; + HexDump(f,0,v_decl_offset,5,16,eptr->data+v_decl_offset,end-v_decl_offset); + } + + + //--- vertex data + + end = eptr->size; + if ( bone_off > v_data_offset && end > bone_off ) + end = bone_off; + if ( v_decl_offset > v_data_offset && end > v_decl_offset ) + end = v_decl_offset; + + if ( v_data_offset < end ) + { + #ifdef TEST0 + fprintf(f,"\r\n# vertex data\r\n"); + mdl_sect2_t ms2; + const u8 *s2data = 0; + const MemItem_t *s2 = FindSectionbyTypeMDL(mdl,2); + if (s2) + { + ntoh_MDLs2(&ms2,(mdl_sect2_t*)s2->data); + s2data = s2->data + ms2.data_off; + } + + u8 *ptr = eptr->data + v_data_offset; + u8 *endptr = eptr->data + end; + + uint i_face = 0; + while ( ptr+3 < endptr && *ptr ) + { + uint max = (endptr-ptr-3)/4; + uint n = be16(ptr+1); + if ( n > max ) + n = max; + fprintf(f,"\r\n # face %u, mode = %#04x, n = %u\r\n",i_face++,*ptr,n); + ptr += 3; + + if (s2data) + { + for ( ; n > 0; n--, ptr += 4 ) + { + float3 temp; + uint vidx = be16(ptr); + if ( vidx < ms2.n_vertex ) + { + GetVectorMDL(&temp, s2data + vidx * ms2.stride, + ms2.format, ms2.r_shift ); + } + else + temp.x = temp.y = temp.z = NAN; + + fprintf(f,"\t%11.3f %11.3f %11.3f %#06x\r\n", + temp.x, temp.y, temp.z, be16(ptr+2) ); + } + } + else + { + for ( ; n > 0; n--, ptr += 4 ) + fprintf(f,"\t%5u %#06x\r\n",be16(ptr),be16(ptr+2)); + } + } + fprintf(f,"\r\n# vertex data as hexdump\r\n\r\n"); + #else + fprintf(f,"\r\n# vertex data\r\n\r\n"); + #endif + + hexdump_prefix = " $HEX "; + hexdump_eol = "\r\n"; + HexDump(f,0,v_data_offset,5,16,eptr->data+v_data_offset,end-v_data_offset); + } + + return ERR_OK; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError SaveTextMDL +( + const mdl_t * mdl, // pointer to valid MDL + ccp fname, // filename of destination + bool set_time // true: set time stamps +) +{ + // use DOS/Windows line format -> unix can handle it ;) + + DASSERT(mdl); + DASSERT(fname); + PRINT("SaveTextMDL(%s,%d)\n",fname,set_time); + + + //--- open file + + File_t F; + enumError err = CreateFileOpt(&F,true,fname,testmode,mdl->fname); + if ( err > ERR_WARNING || !F.f ) + return err; + SetFileAttrib(&F.fatt,&mdl->fatt,0); + + + //--- print file header + syntax info + + if ( print_header && !brief_count ) + fprintf(F.f,text_mdl_file_head_cr); + else + fprintf(F.f,"%s\r\n",MDL_TEXT_MAGIC); + + + //--- print info section + + if (brief_count) + { + fprintf(F.f, + "%s[SETUP]\r\n\r\n" + "TOOL = %s\r\n" + "SYSTEM = %s\r\n" + "VERSION = %s\r\n" + "REVISION = %u\r\n" + "DATE = %s\r\n" + "\r\n" + "MDL-NAME = \"%s\"\r\n" + "MDL-VERSION = %2u\r\n" + "N-SECTIONS = %2u\r\n" + "\r\n", + section_sep, + tool_name, SYSTEM, VERSION, REVISION_NUM, DATE, + mdl->name ? mdl->name : "", + mdl->version, mdl->n_sect ); + } + else + { + fprintf(F.f, text_mdl_setup_cr, + tool_name, SYSTEM, VERSION, REVISION_NUM, DATE, + mdl->name ? mdl->name : "", + mdl->version, mdl->n_sect ); + } + + #if 0 // [[2do]] [[mdl]] ??? + if (print_param) + { + if (!brief_count) + fwrite(text_mdl_param1_cr,1,sizeof(text_mdl_param1_cr)-1,F.f); + else + fprintf(F.f,"#%.78s\r\n# Parameter support\r\n",Minus300); + + fwrite(text_mdl_param2_cr,1,sizeof(text_mdl_param2_cr)-1,F.f); + if (!brief_count) + fwrite(text_mdl_param3_cr,1,sizeof(text_mdl_param3_cr)-1,F.f); + } + #endif + + + //--- write MDL header + + if (brief_count) + fprintf(F.f, + "%s[HEADER]\r\n" + "@REVISION = %u\r\n" + "\r\n", + section_sep, + REVISION_NUM ); + else + fprintf(F.f,text_mdl_header_cr,REVISION_NUM); + + const mdl_head_t *h = &mdl->head; + fprintf(F.f, + "HEAD-LEN = %#10x\r\n" + "OFFSET = %#10x\r\n" + "UNKNOWN-08 = %#10x\r\n" + "UNKNOWN-0c = %#10x\r\n" + "N-VERTEX = %10u\r\n" + "N-FACE = %10u\r\n" + "UNKNOWN-18 = %#10x\r\n" + "N-BONE = %10u\r\n" + "UNKNOWN-20 = %#10x\r\n" + "UNKNOWN-08 = %#10x\r\n" + "BONE-OFFSET = %#10x\r\n" + "MIN = %11.3f %11.3f %11.3f\r\n" + "MAX = %11.3f %11.3f %11.3f\r\n" + "\r\n", + h->head_len, + h->offset, + h->unknown_0x08, + h->unknown_0x0c, + h->n_vertex, + h->n_face, + h->unknown_0x18, + h->unknown_0x0c, + h->n_bone, + h->unknown_0x0c, + h->bone_offset, + h->min[0], h->min[1], h->min[2], + h->max[0], h->max[1], h->max[2] ); + + + //--- write bone table + +// [[2do]] +// if (brief_count) + fprintf(F.f, + "%s[BONE-TABLE]\r\n" + "@REVISION = %u\r\n" + "\r\n", + section_sep, + REVISION_NUM ); +// else +// fprintf(F.f,text_mdl_header_cr,REVISION_NUM); + + fprintf(F.f,"# N = %2u\r\n",mdl->bone_n); + int i; + for ( i = 0; i < mdl->bone_n; i++ ) + fprintf(F.f,"%8d\r\n",mdl->bone_tab[i]); + + + //--- write MDL sections + + const MemItem_t *eptr = GetMemListElem(&mdl->elem,0,0); + const MemItem_t *eend = eptr + mdl->elem.used; + for ( ; err < ERR_WARNING && eptr < eend; eptr++ ) + { + fprintf(F.f, + "%s[SECTION-%u]\r\n" + "# MDL%s.%02u", + section_sep, eptr->idx1, + GetSectNameMDL(eptr->idx1), eptr->idx2 + ); + + #if USE_NEW_CONTAINER_MDL + if (InContainerP(&mdl->container,eptr->data)) + { + u8* base = mdl->container.cdata->data; + // dont use "%zx" because of __APPLE__ + if ( mdl->mdl_offset ) + fprintf(F.f,", MDL file offset 0x%x, BRRES file offset 0x%x", + (int)( eptr->data - base - mdl->mdl_offset ), + (int)( eptr->data - base )); + else + fprintf(F.f,", MDL file offset 0x%x", + (int)( eptr->data - base )); + } + #else + if (InDataContainer(mdl->old_container,eptr->data)) + { + // dont use "%zx" because of __APPLE__ + if ( mdl->mdl_offset ) + fprintf(F.f,", MDL file offset 0x%x, BRRES file offset 0x%x", + (int)( eptr->data - mdl->old_container->data - mdl->mdl_offset ), + (int)( eptr->data - mdl->old_container->data )); + else + fprintf(F.f,", MDL file offset 0x%x", + (int)( eptr->data - mdl->old_container->data )); + } + #endif + + fprintf(F.f, + "\r\n" + "@REVISION = %5u\r\n" + "@ENTRY-INDEX = %5u\r\n" + "@SORT-INDEX = %5u\r\n" + "@NAME = \"%s\"\r\n" + "\r\n", + REVISION_NUM, + eptr->idx2, + eptr->sort_idx, + eptr->name ); + + switch(eptr->idx1) // [[newsect]] + { +// case 0: err = SaveTextMDLs0 (F.f,mdl,eptr); break; + case 1: err = SaveTextMDLs1 (F.f,mdl,eptr); break; + case 2: err = SaveTextMDLs2 (F.f,mdl,eptr); break; +// case 10: err = SaveTextMDLs10(F.f,mdl,eptr); break; + default: err = SaveTextMDLhex(F.f,mdl,eptr); break; + } + } + + + //--- terminate + + fputs(section_end,F.f); + ResetFile(&F,set_time); + return err; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// CkeckMDL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +int CheckMDL +( + // returns number of errors + + const mdl_t * mdl, // pointer to valid MDL + CheckMode_t mode // print mode +) +{ + // [[2do]] [[mdl]] ??? + return 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// MDL section 0 /////////////// +/////////////////////////////////////////////////////////////////////////////// + +bool InitializeMDLs0 ( mdl_sect0_t *ms, const void * data, uint data_size ) +{ + DASSERT(ms); + DASSERT(data); + + memset(ms,0,sizeof(*ms)); + ms->data_beg = data; + ms->data_end = ms->data_beg + data_size; + ms->ok = true; + + while (NextMDLs0(ms)) + { + ms->n++; + ms->data_size += ms->cur_size; + } + ClearMDLs0(ms); + + return ms->ok; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool ClearMDLs0 ( mdl_sect0_t *ms ) +{ + DASSERT(ms); + ms->cur = ms->fail = 0; + ms->cur_size = 0; + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool CheckMDLs0 ( mdl_sect0_t *ms ) +{ + DASSERT(ms); + ms->fail = 0; + ms->sub_size = 0; + if (!ms->cur) + return 0; + + if ( ms->cur < ms->data_beg || ms->cur >= ms->data_end ) + { + ms->fail = ms->cur; + ms->cur = 0; + ms->cur_size = 0; + return ms->ok = false; + } + + switch (*ms->cur) + { + case 1: // END (code) + ms->cur_size = 1; + break; + + case 2: // bone mapping (code,u16,u16) + case 5: // indexing (code,u16,u16) + ms->cur_size = 5; + break; + + case 3: // weighting (code,u16,N=u8,6*N) + ms->sub_size = 6; + ms->sub_ptr = ms->cur + 4; + ms->sub_n = ms->cur[3]; + ms->cur_size = 4 + 6 * ms->sub_n; + break; + + case 4: // draw polygon (code,u16,u16,u16,u8) + ms->cur_size = 8; + break; + + default: + ms->cur_size = 0; // == FAIL + break; + } + + if ( !ms->cur_size || ms->cur + ms->cur_size > ms->data_end ) + { + ms->fail = ms->cur; + ms->cur_size = ms->data_end - ms->cur; + ms->cur = 0; + return ms->ok = false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool FirstMDLs0 ( mdl_sect0_t *ms ) +{ + DASSERT(ms); + ms->cur = ms->data_beg; + return CheckMDLs0(ms); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool NextMDLs0 ( mdl_sect0_t *ms ) +{ + if (!ms->cur) + return FirstMDLs0(ms); + + if ( *ms->cur == 1 ) + return ClearMDLs0(ms); + + ms->cur += ms->cur_size; + return CheckMDLs0(ms); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static ccp MDLs0_types[] = +{ + 0, + "u1", // 1 + "u1u2u2", // 2 + "u1u2u1|u2f4", // 3 + "u1u2u2u2x1", // 4 + "u1u2u2" // 5 +}; + +//----------------------------------------------------------------------------- + +ccp GetTypeMDLs0 ( uint index ) +{ + return index < sizeof(MDLs0_types)/sizeof(*MDLs0_types) + ? MDLs0_types[index] + : 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// MDL section 1 /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void ResetMDLs1 ( mdl_sect1_t *ms, bool network_order ) +{ + DASSERT(ms); + memset(ms,0,sizeof(*ms)); + + ms->length = sizeof(*ms); + ms->flags = MINIMAP_DEFAULT_FLAGS; + ms->scale.x = ms->scale.y = ms->scale.z = 1.0; + + if (network_order) + hton_MDLs1(ms,ms); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ClearMDLs1 ( mdl_sect1_t *ms, bool network_order ) +{ + DASSERT(ms); + + if (network_order) + ntoh_MDLs1(ms,ms); + + memset(&ms->scale,0,sizeof(float3)*5); + memset(ms->trans_matrix.v,0,sizeof(ms->trans_matrix)); + memset(ms->inv_matrix.v,0,sizeof(ms->inv_matrix)); + ms->scale.x = ms->scale.y = ms->scale.z = 1.0; + + ms->length = sizeof(*ms); + ms->flags = MINIMAP_DEFAULT_FLAGS; + + if (network_order) + hton_MDLs1(ms,ms); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ntoh_MDLs1 ( mdl_sect1_t *dest, const mdl_sect1_t *src ) +{ + DASSERT(dest); + + if (src) + { + // float and u32 are equal for endian swapping! + be32n( (u32*)dest, (u32*)src, sizeof(*dest)/sizeof(u32) ); + } + else + memset(dest,0,sizeof(*dest)); +} + +/////////////////////////////////////////////////////////////////////////////// + +void hton_MDLs1 ( mdl_sect1_t *dest, const mdl_sect1_t *src ) +{ + DASSERT(dest); + DASSERT(src); + + #if 1 + // float and u32 are equal for endian swapping! + write_be32n( (u32*)dest, (u32*)src, sizeof(*dest)/sizeof(u32) ); + #else + write_be32n( &dest->length, &src->length, 6 ); + write_bef4n( &dest->scale, &src->scal, 5*3 ); + write_be32n( &dest->parent_off, &src->parent_off, 5 ); + write_bef4n( dest->trans_matrix, src->trans_matrix, 2*4*3 ); + #endif +} + +/////////////////////////////////////////////////////////////////////////////// + +void CalcMatrixMDLs1 ( mdl_sect1_t *ms ) +{ + DASSERT(ms); + + float3 rotate_rad; + Mult3f(rotate_rad,ms->rotate,M_PI/180.0); + + SetupMatrixF34( &ms->trans_matrix, + &ms->scale, + &rotate_rad, + &ms->translate ); + + CalcInverseMatrixF34( &ms->inv_matrix, + &ms->trans_matrix ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ImportMatrixMDLs1 // [[matrix]] [[test]] new function +( + mdl_sect1_t *ms, // valid and initialized data + bool network_order, // true: data is in network byte order + MatrixD_t *mat, // valid data, import from + uint import_mode // bit field: + // 1: import scale, rotate and translate + // 2: import transformation matrix + // 4: import inverse matrix +) +{ + DASSERT(ms); + DASSERT(mat); + + if (network_order) + ntoh_MDLs1(ms,ms); + + + //--- copy vectors + + if ( import_mode & 1 ) + { + CalcNormMatrixD(mat); + + ms->scale.x = mat->norm_scale.x; + ms->scale.y = mat->norm_scale.y; + ms->scale.z = mat->norm_scale.z; + + ms->rotate.x = mat->norm_rotate_deg.x; + ms->rotate.y = mat->norm_rotate_deg.y; + ms->rotate.z = mat->norm_rotate_deg.z; + + ms->translate.x = mat->norm_translate.x; + ms->translate.y = mat->norm_translate.y; + ms->translate.z = mat->norm_translate.z; + } + + + //--- copy matrices + + if ( import_mode & 2 ) + { + CalcTransMatrixD(mat,true); + CopyD34toF34(&ms->trans_matrix,&mat->trans_matrix); + } + + if ( import_mode & 4 ) + { + CalcMatrixD(mat,true); + CopyD34toF34(&ms->inv_matrix,&mat->inv_matrix); + } + + + //--- terminate + + if (network_order) + hton_MDLs1(ms,ms); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ExportMatrixMDLs1 // [[matrix]] [[test]] new function +( + mdl_sect1_t *ms, // valid and initialized data + bool network_order, // true: data is in network byte order + MatrixD_t *mat, // valid data, export to here + uint export_mode // bit field: + // 1: export scale, rotate and translate + // 2: export trans matrix and declare it valid + // 4: export inverse matrix and declare it valid +) +{ + DASSERT(ms); + DASSERT(mat); + + if (network_order) + ntoh_MDLs1(ms,ms); + + + //--- copy vectors + + InitializeMatrixD(mat); + + if ( export_mode & 1 ) + { + mat->scale.x = ms->scale.x; + mat->scale.y = ms->scale.y; + mat->scale.z = ms->scale.z; + + mat->rotate_deg.x = ms->rotate.x; + mat->rotate_deg.y = ms->rotate.y; + mat->rotate_deg.z = ms->rotate.z; + + mat->translate.x = ms->translate.x; + mat->translate.y = ms->translate.y; + mat->translate.z = ms->translate.z; + } + + CalcNormMatrixD(mat); + + + //--- copy matrices + + if ( export_mode & 2 ) + { + CopyF34toD34(&mat->trans_matrix,&ms->trans_matrix); + mat->tmatrix_valid = true; + } + + if ( export_mode & 4 ) + { + CopyF34toD34(&mat->inv_matrix,&ms->inv_matrix); + mat->imatrix_valid = true; + } + + + //--- terminate + + if (network_order) + hton_MDLs1(ms,ms); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool HaveStandardVectorsMDLs1 ( mdl_sect1_t *ms, bool network_order ) +{ + DASSERT(ms); + + mdl_sect1_t ms_local; + if (network_order) + { + ntoh_MDLs1(&ms_local,ms); + ms = &ms_local; + } + + return fabs(ms->scale.x-1.0) < 1e-6 + && fabs(ms->scale.y-1.0) < 1e-6 + && fabs(ms->scale.z-1.0) < 1e-6 + && fabs(ms->rotate.y) < 1e-6 + && fabs(ms->rotate.y) < 1e-6 + && fabs(ms->rotate.z) < 1e-6 + && fabs(ms->translate.x) < 1e-6 + && fabs(ms->translate.y) < 1e-6 + && fabs(ms->translate.z) < 1e-6; +} + +/////////////////////////////////////////////////////////////////////////////// + +void DefineMatrixMDLs1 +( + // modify the vectors and calculate the matrices + + mdl_sect1_t * ms1, // pointer to valid MDLs1 + bool network_order, // true: data is in network byte order + uint reset, // 0: do nothing + // 1: reset only scale+rot+trans vectors + // 2: reset all + double * scale, // not NULL: multiply 3D scale to record + double * rotate, // not NULL: add 3D rotation to record + double * translate // not NULL: add 3D translation to record +) +{ + DASSERT(ms1); + if ( reset > 1 ) + ResetMDLs1(ms1,false); + else + { + if (network_order) + ntoh_MDLs1(ms1,ms1); + if (reset) + ClearMDLs1(ms1,false); + } + + if (scale) + { + ms1->scale.x *= scale[0]; + ms1->scale.y *= scale[1]; + ms1->scale.z *= scale[2]; + } + + if (rotate) + { + ms1->rotate.x += rotate[0]; + ms1->rotate.y += rotate[1]; + ms1->rotate.z += rotate[2]; + } + + if (translate) + { + ms1->translate.x += translate[0]; + ms1->translate.y += translate[1]; + ms1->translate.z += translate[2]; + } + + CalcMatrixMDLs1(ms1); + if (network_order) + hton_MDLs1(ms1,ms1); +} + +/////////////////////////////////////////////////////////////////////////////// + +void PrintMatrixMDLs1 +( + FILE * f, // file to print to + uint indent, // indention + ccp eol, // not NULL: print as 'end of line' + const mdl_sect1_t * ms1, // pointer to valid MDLs1 + uint mode // bitfield: + // 1: print scale+rot+trans vectors + // 2: minimum + maximum + // 4: print matrix + // 8: print inverse matrix +) +{ + indent = NormalizeIndent(indent); + if (!eol) + eol = "\n"; + + if ( mode & 1 ) + { + fprintf(f, + "%*sscale = %11.3f %11.3f %11.3f%s" + "%*srotation = %11.3f %11.3f %11.3f%s" + "%*stranslation = %11.3f %11.3f %11.3f%s", + + indent,"", + ms1->scale.x, + ms1->scale.y, + ms1->scale.z, + eol, + + indent,"", + ms1->rotate.x, + ms1->rotate.y, + ms1->rotate.z, + eol, + + indent,"", + ms1->translate.x, + ms1->translate.y, + ms1->translate.z, + eol ); + } + + if ( mode & 2 ) + { + fprintf(f, + "%*sminimum = %11.3f %11.3f %11.3f%s" + "%*smaximum = %11.3f %11.3f %11.3f%s", + + indent,"", + ms1->minimum.x, + ms1->minimum.y, + ms1->minimum.z, + eol, + + indent,"", + ms1->maximum.x, + ms1->maximum.y, + ms1->maximum.z, + eol ); + } + + if ( mode & 3 ) + fputs(eol,f); + + if ( mode & 4 ) + { + fprintf(f, + "%*strans-matrix-x = %11.3f %11.3f %11.3f %11.3f%s" + "%*strans-matrix-y = %11.3f %11.3f %11.3f %11.3f%s" + "%*strans-matrix-z = %11.3f %11.3f %11.3f %11.3f%s" + "%s", + + indent,"", + ms1->trans_matrix.m[0][0], + ms1->trans_matrix.m[0][1], + ms1->trans_matrix.m[0][2], + ms1->trans_matrix.m[0][3], + eol, + + indent,"", + ms1->trans_matrix.m[1][0], + ms1->trans_matrix.m[1][1], + ms1->trans_matrix.m[1][2], + ms1->trans_matrix.m[1][3], + eol, + + indent,"", + ms1->trans_matrix.m[2][0], + ms1->trans_matrix.m[2][1], + ms1->trans_matrix.m[2][2], + ms1->trans_matrix.m[2][3], + eol, + eol ); + } + + if ( mode & 8 ) + { + fprintf(f, + "%*sinv-matrix-x = %11.3f %11.3f %11.3f %11.3f%s" + "%*sinv-matrix-y = %11.3f %11.3f %11.3f %11.3f%s" + "%*sinv-matrix-z = %11.3f %11.3f %11.3f %11.3f%s" + "%s", + + indent,"", + ms1->inv_matrix.m[0][0], + ms1->inv_matrix.m[0][1], + ms1->inv_matrix.m[0][2], + ms1->inv_matrix.m[0][3], + eol, + + indent,"", + ms1->inv_matrix.m[1][0], + ms1->inv_matrix.m[1][1], + ms1->inv_matrix.m[1][2], + ms1->inv_matrix.m[1][3], + eol, + + indent,"", + ms1->inv_matrix.m[2][0], + ms1->inv_matrix.m[2][1], + ms1->inv_matrix.m[2][2], + ms1->inv_matrix.m[2][3], + eol, + eol ); + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// MDL section 2 /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void ResetMDLs2 ( mdl_sect2_t *ms, bool network_order ) +{ + DASSERT(ms); + memset(ms,0,sizeof(*ms)); + + ms->length = sizeof(*ms); + if (network_order) + hton_MDLs2(ms,ms); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ntoh_MDLs2 ( mdl_sect2_t *dest, const mdl_sect2_t *src ) +{ + DASSERT(dest); + DASSERT(src); + + be32n ( &dest->length, &src->length, 7 ); + memcpy( &dest->r_shift, &src->r_shift, 2 ); + be16n ( &dest->n_vertex, &src->n_vertex, 1 ); + bef4n ( dest->minimum.v, src->minimum.v, 6 ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void hton_MDLs2 ( mdl_sect2_t *dest, const mdl_sect2_t *src ) +{ + DASSERT(dest); + DASSERT(src); + + write_be32n( &dest->length, &src->length, 7 ); + memcpy ( &dest->r_shift, &src->r_shift, 2 ); + write_be16n( &dest->n_vertex, &src->n_vertex, 1 ); + write_bef4n( dest->minimum.v, src->minimum.v, 6 ); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// MDL section 10 /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void ResetMDLs10 ( mdl_sect10_t *ms, bool network_order ) +{ + DASSERT(ms); + memset(ms,0,sizeof(*ms)); + + ms->length = sizeof(*ms); + ms->cp_vtx = 0x4400; + ms->cp_tex = 2; + ms->flags = 0x80; + ms->xf_flags = 0x2a00; + ms->unknown_0x60 = M1(ms->unknown_0x60); + + if (network_order) + hton_MDLs10(ms,ms); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ntoh_MDLs10 ( mdl_sect10_t *dest, const mdl_sect10_t *src ) +{ + DASSERT(dest); + DASSERT(src); + + be32n( &dest->length, &src->length, 18 ); + be16n( &dest->v_group, &src->v_group, 12 ); + be32n( &dest->unknown_0x60, &src->unknown_0x60, 2 ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void hton_MDLs10 ( mdl_sect10_t *dest, const mdl_sect10_t *src ) +{ + DASSERT(dest); + DASSERT(src); + + write_be32n( &dest->length, &src->length, 18 ); + write_be16n( &dest->v_group, &src->v_group, 12 ); + write_be32n( &dest->unknown_0x60, &src->unknown_0x60, 2 ); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// MDL minimap /////////////// +/////////////////////////////////////////////////////////////////////////////// + +#define MINIMAP_MAX_VISIBLE 49e3 + +/////////////////////////////////////////////////////////////////////////////// + +static int find_minimap_mdl +( + struct szs_iterator_t *it, // iterator struct with all infos + bool term // true: termination hint +) +{ + DASSERT(it); + DASSERT(it->szs); + + if ( term || it->entry < 0 ) + return 0; + + if ( it->group == 1 ) + { + noPRINT("MDL-s1: %d.%d '%s'\n",it->group,it->entry,it->name); + mdl_sect1_t *ms = (mdl_sect1_t*)( it->szs->data + it->off ); + mdl_minimap_t *mmap = it->param; + + if (!mmap->root) + { + noPRINT("root FOUND! %p %u %u\n",it->param,it->group,it->entry); + mmap->root = ms; + } + + if ( it->name ) + { + if ( be32(&ms->length) == sizeof(*ms) ) + { + DASSERT(mmap); + if (!strcmp(it->name,"posLD")) + { + noPRINT("posLD FOUND! %p %u %u\n",it->param,it->group,it->entry); + mmap->posLD = ms; + } + else if (!strcmp(it->name,"posRU")) + { + noPRINT("posRU FOUND! %p %u %u\n",it->param,it->group,it->entry); + mmap->posRU = ms; + } + } + } + } + else if ( it->group == 2 ) + { + mdl_sect2_t *ms = (mdl_sect2_t*)( it->szs->data + it->off ); + //HEXDUMP16(0,0,ms,sizeof(*ms)); + const void *data = (u8*)ms + be32(&ms->data_off); + const uint format = be32(&ms->format); + const uint r_shift = ms->r_shift; + uint n_vertex = be16(&ms->n_vertex); + noPRINT("N-VERTEX=%u, FORMAT=%u, R-SHIFT=%u\n",n_vertex,format,r_shift); + + mdl_minimap_t *mmap = it->param; + DASSERT(mmap); + if ( n_vertex && !mmap->vertex ) + mmap->vertex = ms; + + float3 min = mmap->min; + float3 max = mmap->max; + + while ( n_vertex-- > 0 ) + { + float3 temp; + data = GetVectorMDL(&temp,data,format,r_shift); + noPRINT("GET= %11.3f %11.3f %11.3f [%d,%d,%d->%d]\n", + temp.x, temp.y, temp.z, + IsNormalF(temp.x), IsNormalF(temp.y), IsNormalF(temp.z), + IsNormalF3(temp.v) ); + + if ( IsNormalF3(temp.v) + && fabsf(temp.x) < 1e7 + && fabsf(temp.y) < 1e7 + && fabsf(temp.z) < 1e7 + ) + { + if ( min.x > temp.x ) min.x = temp.x; + if ( min.y > temp.y ) min.y = temp.y; + if ( min.z > temp.z ) min.z = temp.z; + if ( max.x < temp.x ) max.x = temp.x; + if ( max.y < temp.y ) max.y = temp.y; + if ( max.z < temp.z ) max.z = temp.z; + } + } + + PRINT("MIN= %11.3f %11.3f %11.3f\n",min.x,min.y,min.z); + PRINT("MAX= %11.3f %11.3f %11.3f\n",max.x,max.y,max.z); + mmap->min = min; + mmap->max = max; + + const float x_add = ( max.x - min.x ) * 0.02 + 100; + const float z_add = ( max.z - min.z ) * 0.02 + 100; + + mmap->rec_trans_ld.x = min.x - x_add; + mmap->rec_trans_ld.y = 0.0; + mmap->rec_trans_ld.z = max.z + z_add; + + mmap->rec_trans_ru.x = max.x + x_add; + mmap->rec_trans_ru.y = 0.0; + mmap->rec_trans_ru.z = min.z - z_add; + + if ( max.y > MINIMAP_MAX_VISIBLE ) + mmap->rec_trans_ld.y = mmap->rec_trans_ru.y + = 1.34 * ( max.y - MINIMAP_MAX_VISIBLE ); + + mmap->rec_trans_valid + = IsNormalF(mmap->rec_trans_ld.x) && fabsf(mmap->rec_trans_ld.x) < 1e6 + && IsNormalF(mmap->rec_trans_ld.y) && fabsf(mmap->rec_trans_ld.y) < 1e6 + && IsNormalF(mmap->rec_trans_ld.z) && fabsf(mmap->rec_trans_ld.z) < 1e6 + && IsNormalF(mmap->rec_trans_ru.x) && fabsf(mmap->rec_trans_ru.x) < 1e6 + && IsNormalF(mmap->rec_trans_ru.z) && fabsf(mmap->rec_trans_ru.z) < 1e6; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static int find_minimap_brres +( + struct szs_iterator_t *it, // iterator struct with all infos + bool term // true: termination hint +) +{ + DASSERT(it); + DASSERT(it->szs); + + u8 *data = it->szs->data + it->off; + + if ( !term + && ( it->fform == FF_MDL + || it->fform == FF_UNKNOWN && !memcmp(data,MDL_MAGIC,4) ) + && !strcmp(it->name,"map") + ) + { + PRINT("MDL FOUND: %x |%s|%s|\n",it->fform,it->path,it->name); + szs_file_t szs; +// [[fname+]] + InitializeSubSZS(&szs,it->szs,it->off,it->size,FF_MDL,it->path,false); + int stat = IterateFilesSZS ( &szs, find_minimap_mdl, it->param, + true, 0, 1, SORT_NONE ); + ResetSZS(&szs); + return stat; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static int find_minimap_szs +( + struct szs_iterator_t *it, // iterator struct with all infos + bool term // true: termination hint +) +{ + DASSERT(it); + DASSERT(it->szs); + u8 *data = it->szs->data + it->off; + + if ( !term + && ( it->fform == FF_BRRES + || it->fform == FF_UNKNOWN && !memcmp(data,BRRES_MAGIC,4) ) + && !strcmp(it->name,"map_model.brres") + ) + { + PRINT("MAP MODEL FOUND: %x |%s|%s|\n",it->fform,it->path,it->name); + szs_file_t szs; +// [[fname+]] + InitializeSubSZS(&szs,it->szs,it->off,it->size,FF_BRRES,it->path,false); + int stat = IterateFilesSZS ( &szs, find_minimap_brres, it->param, + true, 0, -1, SORT_NONE ); + ResetSZS(&szs); + return stat; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool FindMinimapData +( + mdl_minimap_t *mmap, // minmap data to fill + struct szs_file_t *szs // valid szs data +) +{ + DASSERT(mmap); + DASSERT(szs); + noPRINT("FindMinimapData(mmap=%p)\n",mmap); + + memset(mmap,0,sizeof(*mmap)); + mmap->min.x = mmap->min.y = mmap->min.z = +INFINITY; + mmap->max.x = mmap->max.y = mmap->max.z = -INFINITY; + + if ( szs->fform_arch == FF_MDL ) + IterateFilesSZS ( szs, find_minimap_mdl, mmap, true, 0, 1, SORT_NONE ); + else if ( szs->fform_arch == FF_BRRES ) + IterateFilesSZS ( szs, find_minimap_brres, mmap, true, 0, -1, SORT_NONE ); + else if (IsArchiveFF(szs->fform_arch)) + IterateFilesSZS ( szs, find_minimap_szs, mmap, true, 0, -1, SORT_NONE ); + + PRINT_IF(mmap->posLD," posLD found, in=%d\n", + (u8*)mmap->posLD >= szs->data && (u8*)mmap->posLD < szs->data + szs->size ); + PRINT_IF(mmap->posRU," posLD found, in=%d\n", + (u8*)mmap->posRU >= szs->data && (u8*)mmap->posRU < szs->data + szs->size ); + + return mmap->posLD && mmap->posRU; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint AutoAdjustMinimap +( + // returns: + // 0: nothing done + // 1: minimap changed + // 3: minimap changed & vertex list flattened + + struct szs_file_t *szs // valid SZS data +) +{ + DASSERT(szs); + uint ret_status = 0; + + mdl_minimap_t mmap; + if ( FindMinimapData(&mmap,szs) && mmap.rec_trans_valid ) + { + PRINT("AutoAdjustMinimap()\n"); + DASSERT(mmap.posLD); + DASSERT(mmap.posRU); + ret_status = 1; + + if ( mmap.vertex && ( mmap.min.y < 0.0 || mmap.max.y > MINIMAP_MAX_VISIBLE ) ) + { + PATCH_ACTION_LOG("Patch","MINIMAP","(vertex list flattened)\n"); + ret_status |= 2; + mmap.rec_trans_ld.y = mmap.rec_trans_ru.y = 0; + // vertices are flattened only, if vectors or matrices changed. + } + else + PATCH_ACTION_LOG("Patch","MINIMAP",0); + + mdl_sect1_t ld; + ntoh_MDLs1(&ld,mmap.posLD); + ClearMDLs1(&ld,false); + ld.translate = mmap.rec_trans_ld; + CalcMatrixMDLs1(&ld); + + mdl_sect1_t ru; + ntoh_MDLs1(&ru,mmap.posRU); + ClearMDLs1(&ru,false); + ru.translate = mmap.rec_trans_ru; + CalcMatrixMDLs1(&ru); + + hton_MDLs1(&ld,&ld); + hton_MDLs1(&ru,&ru); + if ( memcmp(mmap.posLD,&ld,sizeof(ld)) + || memcmp(mmap.posRU,&ru,sizeof(ru)) ) + { + memcpy(mmap.posLD,&ld,sizeof(ld)); + memcpy(mmap.posRU,&ru,sizeof(ru)); + + if (ret_status&2) + { + void *data = (u8*)mmap.vertex + be32(&mmap.vertex->data_off); + const uint format = be32(&mmap.vertex->format); + const uint r_shift = mmap.vertex->r_shift; + uint n_vertex = be16(&mmap.vertex->n_vertex); + noPRINT("N-VERTEX=%u, FORMAT=%u, R-SHIFT=%u\n",n_vertex,r_shift); + + while ( n_vertex-- > 0 ) + { + float3 temp; + GetVectorMDL(&temp,data,format,r_shift); + temp.y = 20000.0; + data = SetVectorMDL(&temp,data,format,r_shift); + } + } + + return ret_status; + } + } + + return 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// MDL moonview data /////////////// +/////////////////////////////////////////////////////////////////////////////// +// CMD: ./work/scripts/etc/bin-to-bz_c.sh ext.tmp/*.bin +/////////////////////////////////////////////////////////////////////////////// + +const u8 S42_MDL_BZ2[] = +{ + 0x00,0x00,0x4b,0x00, // 19200 bytes decompressed + // 0x0: + 0x42,0x5a,0x68,0x39, 0x31,0x41,0x59,0x26, 0x53,0x59,0x0d,0x14, 0x24,0x06,0x00,0x0c, + 0x3b,0xff,0xff,0xff, 0xff,0xff,0xf7,0xcf, 0x7e,0x7f,0xcd,0xf5, 0xff,0x76,0xc7,0xbf, + 0xef,0xde,0xf4,0x4c, 0x54,0x66,0x48,0x44, 0x40,0x46,0x44,0xd2, 0xc1,0x05,0x50,0xff, + 0xce,0x58,0x49,0xd0, 0x04,0x97,0x80,0x34, 0x00,0x1a,0x29,0xaa, 0x0c,0xa2,0x50,0x06, + 0x98,0x80,0x3d,0x40, 0x00,0x00,0x01,0xa0, 0x01,0xa0,0x00,0x00, 0xc8,0x00,0x01,0xa0, + 0x0f,0x50,0x34,0x00, 0x00,0xd0,0x68,0x03, 0xd4,0x1a,0x50,0x53, 0xd4,0xcf,0x4a,0x66, + 0xa7,0xa4,0x1e,0x14, 0x00,0x00,0xd0,0x00, 0x68,0x68,0x00,0xd0, 0x00,0x00,0x00,0x00, + 0x03,0x40,0x00,0x00, 0x0d,0x00,0x00,0x81, 0x93,0x04,0x64,0xc0, 0x8d,0x31,0x0d,0x30, + 0x8c,0x43,0x4c,0x00, 0x46,0x04,0x60,0x20, 0xc9,0xa6,0x43,0x46, 0x43,0x40,0x62,0x60, + 0x26,0x21,0x80,0x98, 0x8d,0x34,0xc4,0xc0, 0x98,0x10,0x32,0x60, 0x8c,0x98,0x11,0xa6, + 0x21,0xa6,0x11,0x88, 0x69,0x80,0x08,0xc0, 0x8c,0x04,0x19,0x34, 0xc8,0x68,0xc8,0x68, + 0x0c,0x4c,0x04,0xc4, 0x30,0x13,0x11,0xa6, 0x98,0x98,0x13,0x00, 0x89,0x48,0x49,0xa6, + 0x26,0x86,0x8a,0x66, 0xa6,0x98,0xd4,0x69, 0x80,0x46,0x83,0x4f, 0x50,0x18,0x8c,0x8d, + 0x07,0xa8,0xc4,0xc8, 0x68,0x69,0xe8,0x86, 0x8f,0x50,0x64,0xc8, 0xd3,0x26,0x99,0x19, + 0x1a,0x1a,0x64,0x66, 0xa1,0xea,0x64,0xc1, 0x32,0xb3,0x91,0x32, 0xeb,0xae,0xba,0xcb, + 0x26,0xa3,0x06,0x6e, 0x70,0x23,0x8e,0x0e, 0x45,0xc6,0x33,0xc0, 0x0a,0xf1,0xaf,0xf0, + // 0x100: + 0x04,0xe1,0x59,0xc9, 0xd9,0xe3,0x19,0x3c, 0x25,0xc0,0x05,0xc5, 0xd0,0x73,0xac,0xb9, + 0x72,0xd5,0xcc,0x70, 0xc5,0x85,0xf0,0x44, 0xc5,0x06,0x76,0x33, 0xb1,0x70,0x71,0x3e, + 0x2c,0x8d,0x10,0x76, 0x97,0xfa,0x77,0x41, 0xd9,0x83,0x9a,0x0f, 0x43,0x1c,0x1d,0x4e, + 0x15,0x14,0xca,0x70, 0x50,0x89,0x22,0x5b, 0x04,0x49,0x01,0xfc, 0x54,0xfc,0xed,0x54, + 0x00,0x0c,0x47,0x99, 0x83,0x99,0xd2,0xe4, 0x6a,0x37,0xfe,0x69, 0x6a,0xe7,0xe5,0xcf, + 0xbc,0x0e,0x2e,0x65, 0xff,0x44,0x18,0x0f, 0x70,0x1d,0x88,0x36, 0x94,0xe7,0xe4,0x83, + 0x89,0x86,0xa9,0x98, 0x45,0x78,0x78,0x68, 0x54,0x86,0xeb,0xac, 0x9d,0xe9,0x59,0xd1, + 0x34,0xfb,0xaa,0x95, 0x00,0xe2,0x03,0xf0, 0x50,0x13,0x61,0x1b, 0xca,0x67,0xd0,0x1d, + 0xb6,0x35,0x10,0x78, 0xb1,0x1d,0x66,0xfe, 0x80,0xf0,0x63,0xbd, 0x8a,0xa3,0xce,0x80, + 0xd3,0x7d,0x4f,0xe6, 0x00,0x03,0x78,0x1a, 0xe8,0x8e,0x74,0xcf, 0x80,0xde,0xe2,0xeb, + 0x33,0x2b,0x06,0xed, 0x94,0x92,0x11,0x18, 0x40,0x72,0xfd,0xc0, 0x7f,0xc0,0x74,0x41, + 0x0c,0xc0,0x1f,0xf4, 0x1b,0x40,0xe1,0x45, 0x24,0x8f,0x72,0x80, 0xfb,0x40,0xc0,0x00, + 0x0d,0xb0,0x30,0x04, 0xec,0xc4,0x77,0x71, 0x1c,0x90,0x70,0x81, 0xa7,0xe9,0x04,0x10, + 0xcd,0x94,0x88,0x28, 0xd0,0x06,0x40,0x18, 0x76,0xa2,0x35,0x44, 0x0f,0x9c,0x19,0x97, + 0x55,0x0d,0xed,0x28, 0x69,0xa9,0x4c,0xfa, 0x76,0x01,0xa6,0x4b, 0xc0,0x26,0xed,0x29, + 0x42,0xca,0x80,0x00, 0x2a,0x10,0x54,0x73, 0x4f,0x03,0x08,0xd2, 0xa9,0x9d,0x1b,0x5c, + // 0x200: + 0x38,0x86,0xf5,0x61, 0xbb,0xe6,0xa8,0x07, 0xba,0x24,0x03,0x04, 0x07,0xea,0x13,0x24, + 0x10,0xa0,0x21,0x01, 0x80,0xc0,0x60,0x21, 0xfb,0x83,0x14,0x47, 0x1a,0x09,0x96,0x08, + 0x90,0x44,0x4b,0x91, 0x12,0xfc,0x51,0xc8, 0x8a,0xe0,0x8a,0x38, 0x20,0x09,0x91,0x11, + 0xe1,0x40,0xc8,0x88, 0x0b,0x4c,0x8a,0x20, 0x28,0x78,0x90,0x57, 0x55,0x06,0x31,0x91, + 0x5c,0x80,0x60,0x85, 0x22,0x2a,0xc8,0x23, 0x08,0x20,0xa4,0x82, 0x26,0x14,0x01,0xee, + 0x83,0xa5,0x52,0x98, 0xd8,0x94,0x51,0xd2, 0x83,0x8a,0xa5,0x24, 0xce,0x06,0x29,0x40, + 0x18,0x59,0x6d,0x0a, 0x49,0x08,0xb0,0x18, 0x8a,0x90,0x4b,0x54, 0x88,0x50,0x25,0x01, + 0x90,0x4c,0x68,0xe0, 0x06,0x08,0xdf,0x3b, 0x20,0x85,0x10,0x06, 0xc2,0x0a,0x5a,0x80, + 0xfb,0x20,0xf2,0x39, 0x55,0x00,0x5f,0x06, 0x22,0xf4,0xd4,0x80, 0xea,0x81,0x98,0x84, + 0x06,0x61,0xb4,0x51, 0x39,0x70,0x5b,0xc4, 0x4e,0xa5,0x77,0x9a, 0x91,0x06,0xd4,0x51, + 0xaa,0xaa,0x32,0xaa, 0x15,0x44,0x00,0x66, 0x9a,0xd5,0x40,0xd7, 0x30,0xb9,0x20,0xd0, + 0x1d,0x40,0x37,0x81, 0xa0,0x20,0x62,0x5b, 0xb7,0x5d,0x68,0xb8, 0x01,0xe1,0x50,0xae, + 0xcd,0x86,0xd7,0x81, 0x60,0x77,0x49,0xcc, 0xbc,0x0d,0xb2,0xa3, 0x6f,0x38,0x20,0xc8, + 0x0d,0x59,0x15,0x1c, 0x9c,0x6d,0x00,0x42, 0xa0,0xb2,0xca,0x6c, 0x83,0xdb,0xdc,0xd0, + 0xdc,0x71,0x3f,0x2b, 0xd5,0xe6,0x95,0xd9, 0x64,0x92,0x56,0x5b, 0x46,0x12,0x17,0x29, + 0x42,0x28,0xde,0xaa, 0xed,0x5b,0x98,0xd5, 0xa3,0x5e,0x40,0x9c, 0x70,0x01,0xb0,0x00, + // 0x300: + 0x60,0x00,0xe5,0x80, 0x0d,0x01,0xb4,0x08, 0x9e,0x28,0x38,0xa0, 0xed,0xc1,0xb7,0x65, + 0x01,0xa8,0x06,0x86, 0x7d,0xee,0x05,0xbc, 0x2d,0x97,0x07,0x2f, 0xa1,0xdb,0xeb,0xdd, + 0x0d,0x7e,0x93,0xca, 0xab,0x93,0x10,0xd2, 0x57,0x6e,0xad,0xfd, 0xf8,0x3c,0xa5,0x97, + 0x66,0x89,0x84,0x1c, 0x01,0x92,0xd7,0xac, 0x34,0x3c,0x1c,0x90, 0x04,0xca,0x64,0x08, + 0xf0,0x09,0x48,0xf4, 0x91,0x00,0xba,0x0f, 0x07,0xc3,0x53,0xee, 0xb7,0xa3,0x66,0xb4, + 0x32,0xee,0x62,0x50, 0xa4,0x74,0x9c,0x7a, 0x6b,0xba,0x72,0xaa, 0x83,0x43,0xad,0x67, + 0x2c,0x1b,0xa0,0xf5, 0x20,0xed,0x08,0x1b, 0x80,0x73,0xc1,0xb6, 0x74,0xb9,0x53,0xaa, + 0xa6,0x93,0xf8,0x2f, 0xeb,0x81,0xb8,0x0f, 0x7e,0x0d,0x01,0xc0, 0x0f,0x00,0x06,0xb0, + 0x60,0x30,0x10,0x0d, 0x78,0x9c,0x79,0xce, 0x07,0x2b,0x29,0xd0, 0xbf,0x28,0x66,0xec, + 0x7d,0x8a,0x80,0xca, 0xbb,0x1e,0xb6,0x3b, 0x87,0xa9,0xd0,0x6f, 0x6a,0xb4,0x36,0xd7, + 0x00,0x4c,0xa5,0x80, 0x64,0x23,0x69,0xdb, 0x11,0xf0,0xf0,0x60, 0xe6,0xe1,0x50,0x10, + 0x40,0xb9,0xe6,0x9c, 0xc1,0x07,0xca,0x10, 0x1e,0x2f,0x91,0x24, 0x5b,0x05,0xbc,0xac, + 0x98,0x28,0x04,0xc9, 0xa6,0xf2,0xfe,0xad, 0x81,0x8d,0x4c,0x7e, 0xae,0x56,0xdc,0xc7, + 0x30,0xf2,0xb7,0xcf, 0x7d,0x93,0x14,0xa6, 0xe2,0x9f,0xb7,0x08, 0x11,0x24,0x05,0x10, + 0xfa,0x01,0xc7,0x52, 0xd5,0x40,0x03,0xcd, 0x07,0x3c,0x1f,0x1c, 0x1e,0x30,0x3c,0x60, + 0x6f,0x03,0xdb,0x07, 0x86,0x62,0x75,0xfb, 0x1d,0x1f,0xfb,0xb3, 0xda,0x63,0xb9,0xa4, + // 0x400: + 0xba,0xca,0x00,0x63, 0xf0,0x9d,0xfd,0xb2, 0x55,0x0e,0xf5,0x93, 0x3d,0xb7,0xf9,0xf4, + 0x01,0x97,0xc8,0xaf, 0x6d,0xc0,0xfe,0xd7, 0x3d,0xc3,0x48,0x37, 0xa5,0xd2,0x01,0x02, + 0x43,0xfb,0xae,0xd1, 0x85,0x79,0xe8,0x7d, 0x7d,0xca,0xb5,0x9c, 0xdd,0x9e,0xb7,0x26, + 0xce,0xec,0x3e,0x6d, 0x3e,0x2e,0x5e,0xa6, 0xca,0xf7,0x7b,0xce, 0xde,0xaf,0xf5,0xf3, + 0xc1,0xc2,0x80,0x86, 0xd6,0x02,0x14,0x02, 0x80,0x00,0x05,0x08, 0x00,0x92,0xc1,0x92, + 0xce,0x97,0xdd,0x6c, 0xbc,0xee,0xbb,0xa7, 0x1e,0x0c,0x78,0xec, 0x12,0xcc,0x02,0xe5, + 0x2a,0x80,0x54,0x00, 0xa6,0xe0,0x07,0x56, 0xb5,0xeb,0xe8,0xd0, 0x1a,0xd0,0x60,0x30, + 0x00,0x6e,0x90,0x0a, 0x03,0x10,0x2e,0xc0, 0x6c,0x05,0x78,0xc0, 0xc0,0x1a,0x56,0xa6, + 0xca,0x80,0x3a,0xbf, 0x4c,0x1b,0x01,0xff, 0xc5,0xdc,0x91,0x4e, 0x14,0x24,0x03,0x45, + 0x09,0x01,0x80, + // 0x493 = 1171 Bytes +}; + +/////////////////////////////////////////////////////////////////////////////// + +mdl_t slot42_mdl = {0}; + +#undef def42 +#define def42(n,i) { S42M_##n, i, 0 }, + +Slot42MaterialInfo_t Slot42MaterialInfo[S42M__N+1] = +{ + def42( GOAL_MERG, "Goal_Merg" ) + def42( IWA, "Iwa" ) + def42( IWA_ALFA, "Iwa_alfa" ) + def42( NUKI_RYOUMEN, "Nuki_Ryoumen" ) + def42( WALLMERG00, "WallMerg00" ) + def42( MOON_KABE0000, "moon_kabe0000" ) + def42( MOON_ROAD00, "moon_road00" ) + def42( ROAD, "road" ) + def42( ROAD01, "road01" ) + def42( ROAD02, "road02" ) + def42( ROAD03, "road03" ) + def42( SIBA00, "siba00" ) + {0,"",0} +}; + +#undef def42 + +/////////////////////////////////////////////////////////////////////////////// + +const Slot42MaterialInfo_t * SetupSlot42Materials() +{ + if ( slot42_mdl.fform != FF_MDL ) + { + InitializeMDL(&slot42_mdl); + slot42_mdl.fname = STRDUP("course.mdl"); + slot42_mdl.fform = FF_MDL; + + u8 *data; + uint size; + if (!DecodeBZIP2(&data,&size,0,S42_MDL_BZ2,sizeof(S42_MDL_BZ2))) + { + #if USE_NEW_CONTAINER_MDL + Container_t *c = CreateContainer(0,0,data,size,CPM_MOVE); + ScanRawMDL(&slot42_mdl,false,data,size,LinkContainerData(c)); + #else + DataContainer_t *dc = NewContainer(0,data,size,CPM_MOVE); + ScanRawMDL(&slot42_mdl,false,data,size,dc); + #endif + + MemItem_t *ptr = GetMemListElem(&slot42_mdl.elem,0,0); + MemItem_t *end = ptr + slot42_mdl.elem.used; + for ( ; ptr < end; ptr++ ) + { + Slot42MaterialInfo_t *sptr; + for ( sptr = Slot42MaterialInfo; sptr->val; sptr++ ) + if (!strcmp(sptr->name,ptr->name)) + { + sptr->memitem = ptr; + break; + } + } + } + //HEXDUMP16(0,0,Slot42MaterialInfo,sizeof(Slot42MaterialInfo)); + } + return Slot42MaterialInfo; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// MDL moonview detection /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static int ana_slot42_mdl +( + struct szs_iterator_t *it, // iterator struct with all infos + bool term // true: termination hint +) +{ + DASSERT(it); + DASSERT(it->szs); + + if ( term || it->entry < 0 ) + return 0; + + Slot42MaterialStat_t *stat42 = it->param; + DASSERT(stat42); + + char buf[2000]; + + if ( it->group == 8 && it->name ) + { + const Slot42MaterialInfo_t *ptr; + for ( ptr = SetupSlot42Materials(); ptr->val; ptr++ ) + if (!strcasecmp(ptr->name,it->name)) + { + stat42->found |= ptr->val; + const MemItem_t *mi = ptr->memitem; + if (mi) + { + DASSERT( mi->size <= sizeof(buf) ); + if ( mi->size != it->size || mi->size > sizeof(buf) ) + stat42->modified |= ptr->val; + else + { + // fix name offsets before comparing + + memcpy(buf,mi->data,mi->size); + + u8 *sdata = it->szs->data + it->off; + memcpy(buf+0x04,sdata+0x04,8); // offset + name + memcpy(buf+0x18,sdata+0x18,4); // culling + + const endian_func_t * endian = it->endian; + DASSERT(endian); + + const uint n_layer = endian->rd32(buf+0x2c); + u32 layer_off = endian->rd32(buf+0x30); + uint i; + for ( i = 0; i < n_layer; i++, layer_off += 0x34 ) + memcpy(buf+layer_off,sdata+layer_off,4); // name + HEXDIFF16(0,0,sdata,mi->size,buf,mi->size); + + if ( memcmp(buf,sdata,mi->size) ) + stat42->modified |= ptr->val; + } + } + + stat42->all_found = stat42->found == S42M__ALL; + stat42->content_ok = !stat42->modified; + stat42->ok = stat42->all_found && stat42->content_ok; + + //-- extract + + File_t F; + if (PrepareExtract(&F,-1,"%s.bin",ptr->name)) + { + printf("EXTRACT: %s\n",F.fname); + fwrite(it->szs->data+it->off,it->size,1,F.f); + } + CloseFile(&F,false); + break; + } + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static int ana_slot42_brres +( + struct szs_iterator_t *it, // iterator struct with all infos + bool term // true: termination hint +) +{ + DASSERT(it); + DASSERT(it->szs); + + u8 *data = it->szs->data + it->off; + + if ( !term + && ( it->fform == FF_MDL + || it->fform == FF_UNKNOWN && !memcmp(data,MDL_MAGIC,4) ) + && !strcasecmp(it->name,"course") + ) + { + PRINT("MOONVIEW MDL FOUND: %x |%s|%s|\n",it->fform,it->path,it->name); + szs_file_t szs; +// [[fname+]] + InitializeSubSZS(&szs,it->szs,it->off,it->size,FF_MDL,it->path,false); + int stat = IterateFilesSZS ( &szs, ana_slot42_mdl, it->param, + true, 0, 1, SORT_NONE ); + + Slot42MaterialStat_t *stat42 = it->param; + DASSERT(stat42); + if (stat42->ok) + { + File_t F; + if (PrepareExtract(&F,-1,"course-42.mdl")) + { + printf("EXTRACT: %s\n",F.fname); + + mdl_t mdl; + #if USE_NEW_CONTAINER_MDL + if (!ScanRawMDL(&mdl,true,szs.data,szs.size,LinkContainerSZS(&szs))) + #else + if (!ScanRawMDL(&mdl,true,szs.data,szs.size,ContainerSZS(&szs))) + #endif + { + mdl.bone_n = 0; + MemItem_t *ptr = GetMemListElem(&mdl.elem,0,0); + MemItem_t *end = ptr + mdl.elem.used; + for ( ; ptr < end; ptr++ ) + { + bool delete = true; + if ( ptr->idx1 == 8 ) + { + const Slot42MaterialInfo_t *sptr; + for ( sptr = Slot42MaterialInfo; sptr->val; sptr++ ) + if (!strcmp(sptr->name,ptr->name)) + { + delete = false; + break; + } + } + if (delete) + { + if (ptr->data_alloced) + FREE(ptr->data); + ptr->data = 0; + ptr->size = 0; + } + } + + CreateRawMDL(&mdl); + fwrite(mdl.raw_data,mdl.raw_file_size,1,F.f); + } + } + CloseFile(&F,false); + } + + ResetSZS(&szs); + return stat; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static int ana_slot42_szs +( + struct szs_iterator_t *it, // iterator struct with all infos + bool term // true: termination hint +) +{ + DASSERT(it); + DASSERT(it->szs); + u8 *data = it->szs->data + it->off; + + if ( !term + && ( it->fform == FF_BRRES + || it->fform == FF_UNKNOWN && !memcmp(data,BRRES_MAGIC,4) ) + && ( !strcmp(it->name,"course_model.brres") + || !strcmp(it->name,"course_d_model.brres") ) + ) + { + PRINT("COURSE MODEL FOUND: %x |%s|%s|\n",it->fform,it->path,it->name); + szs_file_t szs; +// [[fname+]] + InitializeSubSZS(&szs,it->szs,it->off,it->size,FF_BRRES,it->path,false); + int stat = IterateFilesSZS ( &szs, ana_slot42_brres, it->param, + true, 0, -1, SORT_NONE ); + ResetSZS(&szs); + return stat; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +Slot42MaterialStat_t GetSlot42SupportSZS ( struct szs_file_t *szs ) +{ + DASSERT(szs); + + Slot42MaterialStat_t stat42; + memset(&stat42,0,sizeof(stat42)); + + if ( !szs->data ) + return stat42; + + PRINT("CHECK MOONVIEW [%zu] %s\n",szs->size,GetNameFF(szs->fform_arch,0)); + + if ( szs->fform_arch == FF_MDL ) + IterateFilesSZS ( szs, ana_slot42_mdl, &stat42, true, 0, 1, SORT_NONE ); + else if ( szs->fform_arch == FF_BRRES ) + IterateFilesSZS ( szs, ana_slot42_brres, &stat42, true, 0, -1, SORT_NONE ); + else if (IsArchiveFF(szs->fform_arch)) + IterateFilesSZS ( szs, ana_slot42_szs, &stat42, true, 0, -1, SORT_NONE ); + + PRINT("MOONVIEW [%zu] %s: found=%x, mod=%x -> all=%d, content=%d -> ok=%d\n", + szs->size, GetNameFF(szs->fform_arch,0), + stat42.found, stat42.modified, + stat42.all_found, stat42.content_ok, stat42.ok ); + + return stat42; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[obsolete]] 2016-06 +// RenameForSlot42MDL() Don't work! A modified track runs at slot 1.1, +// but not at 4.2. I assume, that the layers must be correct. + +ccp RenameForSlot42MDL +( + void *rawdata, // pointer to data, modified + uint size, // size of 'rawdata' + ContainerMDL_t * cdata // NULL or container-data +) +{ + mdl_t mdl; + enumError err = ScanMDL(&mdl,true,rawdata,size,cdata,0); + ccp errmsg = 0; + if (err) + { + errmsg = "Invalid MDL"; + goto abort; + } + + { + u8 slot42ok[S42M__N]; + memset(slot42ok,0,sizeof(slot42ok)); + uint n_ok = 0; + + const uint MAX_SECT8 = 1000; + const MemItem_t *sect8[MAX_SECT8]; + uint sect8_count = 0; + + const MemItem_t *mi = GetMemListElem(&mdl.elem,0,0); + const MemItem_t *mi_end = mi + mdl.elem.used; + for ( ; mi < mi_end && sect8_count < MAX_SECT8; mi++ ) + { + if ( mi->idx1 != 8 || !mi->data ) + continue; + + sect8[sect8_count] = mi; + + const Slot42MaterialInfo_t *sptr; + for ( sptr = Slot42MaterialInfo; sptr->val; sptr++ ) + if (!strcmp(sptr->name,mi->name)) + { + slot42ok[sptr-Slot42MaterialInfo] = 1; + sect8[sect8_count] = 0; + n_ok++; + break; + } + + sect8_count++; + } + PRINT("N(slot42)=%d, N(mat)=%d\n",S42M__N,sect8_count); + HEXDUMP16(5,0,slot42ok,sizeof(slot42ok)); + + if ( sect8_count < S42M__N ) + { + errmsg = "Too less materials"; + goto abort; + } + if ( n_ok == S42M__N ) + goto abort; // all done + + ccp rename[S42M__N]; + memset(rename,0,sizeof(rename)); + uint sect, n_rename = 0; + + for ( sect = 0; sect < S42M__N; sect++ ) + { + if (slot42ok[sect]) + continue; + const Slot42MaterialInfo_t *sptr = Slot42MaterialInfo + sect; + const uint mlen = strlen(sptr->name); + + int found = -1; + uint flen = 0x40000000, s8idx; + for ( s8idx = 0; s8idx < sect8_count; s8idx++ ) + { + const MemItem_t *mi = sect8[s8idx]; + if (!mi) + continue; + + const uint slen = strlen(mi->name); + if ( mlen <= slen && slen < flen ) + { + found = s8idx; + flen = slen; + } + } + if ( found < 0 ) + { + errmsg = "Material names to short"; + goto abort; + } + + + rename[sect] = sect8[found]->name; + sect8[found] = 0; + n_rename++; + } + + #ifdef TEST + //if ( logging > 1 && stdlog ) + { + fprintf(stdlog, + "\tRename %u MDL material%s:\n", + n_rename, n_rename == 1 ? "" : "s" ); + for ( sect = 0; sect < S42M__N; sect++ ) + if (rename[sect]) + { + ParamFieldItem_t *par = FindParamField(&mdl.spool.pf,rename[sect]); + ccp pdata = par ? par->data : 0; + fprintf(stdlog,"\t %-13s <- %-30s %p %s\n", + Slot42MaterialInfo[sect].name, rename[sect], + pdata, pdata ); + } + } + #endif + + #if USE_NEW_CONTAINER_MDL + DASSERT(mdl.container.cdata); + DASSERT(mdl.container.cdata->data); + const u8 *copy_start = mdl.container.cdata->data + size; + #else + DASSERT(mdl.old_container); + DASSERT(mdl.old_container->data); + const u8 *copy_start = mdl.old_container->data + size; + #endif + for ( sect = 0; sect < S42M__N; sect++ ) + if (rename[sect]) + { + ParamFieldItem_t *par = FindParamField(&mdl.spool.pf,rename[sect]); + if ( !par || !par->data ) + { + errmsg = "Internal Error"; + goto abort; + } + DASSERT(!strcmp(rename[sect],par->data)); + u8 *dest = par->data - 4; + if ( copy_start > dest ) + copy_start = dest; + const uint rlen = strlen(rename[sect]); + const uint mlen = strlen(Slot42MaterialInfo[sect].name); + DASSERT( mlen <= rlen ); + write_be32(par->data-4,mlen); + memset(par->data,0,rlen); + memcpy(par->data,Slot42MaterialInfo[sect].name,mlen); + } + + #if USE_NEW_CONTAINER_MDL + const int offset = copy_start - mdl.container.cdata->data; + if ( offset > 0 ) + memcpy( rawdata+offset, mdl.container.cdata->data+offset, size-offset ); + #else + const int offset = copy_start - mdl.old_container->data; + if ( offset > 0 ) + memcpy( rawdata+offset, mdl.old_container->data+offset, size-offset ); + #endif + } + + abort: + ResetMDL(&mdl); + return errmsg; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// PrintStringsMDL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void print_sections_mdl +( + struct StringIteratorMDL_t *sit, // string iterator data + MemItem_t *mi // memory item of section +) +{ + DASSERT(sit); + DASSERT(sit->f); + DASSERT(mi); + + fprintf( sit->f, "%*sSection %2d.%02d: %s\n", + sit->indent,"", mi->idx1, mi->idx2, mi->name ); + + const u32 *sptr = GetStrIdxListMIL(mi); + uint i, n = GetStrIdxCountMIL(mi); + for ( i = 0; i < n; i++ ) + { + const uint idx = sptr[i]; + if ( idx && idx < sit->sp->n2s_size ) + { + ccp str = sit->sp->n2s_list[idx]; + if (!str) + str = "-invalid-"; + fprintf( sit->f, "%*s %s\n", sit->indent, "", str ); + } + } +} + +//----------------------------------------------------------------------------- + +enumError PrintStringsMDL +( + FILE * f, // output file + int indent, // indention + mdl_t * mdl // valid MDL +) +{ + DASSERT(f); + DASSERT(mdl); + + StringIteratorMDL_t sim; + memset(&sim,0,sizeof(sim)); + sim.mdl = mdl; + sim.sp = &mdl->spool; + sim.sect_func = print_sections_mdl; + //sim.str_func = print_strings_mdl; + sim.f = f; + sim.indent = NormalizeIndent(indent)+2; + + fprintf(f,"%*sStrings of %s\n",sim.indent-2,"",mdl->fname); + IterateAllStringsMDL(&sim); + return ERR_OK; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// AppendMDL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError AppendMDL +( + mdl_t * mdl, // working MDL (valid) + const mdl_t * src_mdl // pointer to source MDL +) +{ + DASSERT(mdl); + DASSERT(src_mdl); + + //--- find max sort_index + + int total_max_sort = 0; + MemItem_t *base = GetMemListElem(&mdl->elem,0,0); + MemItem_t *ptr, *end = base + mdl->elem.used; + for ( ptr = base; ptr < end; ptr++ ) + if ( total_max_sort < ptr->sort_idx ) + total_max_sort = ptr->sort_idx; + + PRINT("TOTAL-MAX-SORT: %d\n",total_max_sort); + + StringIteratorMDL_t sim; + memset(&sim,0,sizeof(sim)); + sim.mdl = mdl; + sim.sp = &mdl->spool; + sim.str_func = string_copy; + + const MemItem_t *mi = GetMemListElem(&src_mdl->elem,0,0); + const MemItem_t *mi_end = mi + src_mdl->elem.used; + for ( ; mi < mi_end; mi++ ) + { + //--- start with index corrections + + int sort_idx = -1, found = 0; + for ( ptr = base; ptr < end; ptr++ ) + { + if ( ptr->idx1 == mi->idx1 && sort_idx < ptr->sort_idx ) + sort_idx = ptr->sort_idx; + if (!strcmp(ptr->name,mi->name)) + { + found++; + break; + } + } + if (found) + continue; + + //if ( sort_idx < 0 ) + sort_idx = total_max_sort; + for ( ptr = base; ptr < end; ptr++ ) + if ( ptr->sort_idx > sort_idx ) + ptr->sort_idx += 10; + total_max_sort += 10; + + + //--- insert element + + MemItem_t * item = AppendMIL(&mdl->elem); + item->idx1 = mi->idx1; + item->idx2 = mi->idx2; + item->sort_idx = sort_idx + 10; + item->name = STRDUP(mi->name); + item->data = MEMDUP(mi->data,mi->size); + item->size = mi->size; + item->name_alloced = item->data_alloced = true; + + IterateStringsMDL(&sim,item,1); + } + + return ERR_WARNING; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// Patch MDL /////////////// +/////////////////////////////////////////////////////////////////////////////// + +typedef struct mdl_patch_t +{ + patch_file_t brres_type; // type of related BRRES file + u32 patch_status; // mdl patch status + + bool root_s1_valid; // true: 'root_s1' is valid copy + bool is_transformed; // true: is transformed by vectors + mdl_sect1_t root_s1; // root section-1 element + MatrixD_t matrix; // calculated matrix, if 'is_transformed' + MatrixD_t *mat; // Matrix for transforming. Is a pointer to + // either 'matrix' or 'opt_transform' (=init) +} mdl_patch_t; + + +/////////////////////////////////////////////////////////////////////////////// + +float3 TransformByMatrix +( + float3 *val, + float m[3][4] +) +{ + DASSERT(val); + DASSERT(m); + + float3 res; + res.x = m[0][0] * val->x + m[0][1] * val->y + m[0][2] * val->z + m[0][3]; + res.y = m[1][0] * val->x + m[1][1] * val->y + m[1][2] * val->z + m[1][3]; + res.z = m[2][0] * val->x + m[2][1] * val->y + m[2][2] * val->z + m[2][3]; + return res; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool HavePatchMDL() +{ + LoadParametersMDL( verbose > 0 ? " - " : 0 ); + if ( have_patch_count <= 0 || have_mdl_patch_count <= 0 ) + return false; + + return MDL_MODE & MDLMD_MATRIX || transform_active; +} + +/////////////////////////////////////////////////////////////////////////////// + +static int patch_mdl +( + struct szs_iterator_t *it, // iterator struct with all infos + bool term // true: termination hint +) +{ + DASSERT(it); + DASSERT(it->szs); + mdl_patch_t *mdlpat = it->param; + DASSERT(mdlpat); + + if ( term || it->entry < 0 ) + return 0; + + if ( it->group == 1 ) + { + mdl_sect1_t *ms = (mdl_sect1_t*)( it->szs->data + it->off ); + if ( be32(&ms->length) == sizeof(*ms) ) + { + if ( !mdlpat->root_s1_valid && !ms->parent_off ) + { + mdlpat->root_s1_valid = true; + ntoh_MDLs1(&mdlpat->root_s1,ms); + mdlpat->is_transformed + = !( mdlpat->brres_type & PFILE_MINIMAP ) + && !HaveStandardVectorsMDLs1(&mdlpat->root_s1,false); + + if (mdlpat->is_transformed) + { + MatrixD_t temp; + ExportMatrixMDLs1( &mdlpat->root_s1, false, &temp, 1 ); + MultiplyMatrixD( &mdlpat->matrix, &temp, &opt_transform, 0 ); + MultiplyMatrixD( &mdlpat->matrix, 0, &temp, 2 ); + mdlpat->mat = &mdlpat->matrix; + mdlpat->patch_status |= 2; + } + } + + if ( mdl_switched_to_vertex == 2 ) + { + mdl_switched_to_vertex++; + ERROR0(ERR_WARNING, + "Because of the complex transformation matrix, it is" + " impossible to modify the scale and rotate vectors" + " of the MDL bones. So the VECTOR transformation is" + " disabled and the VERTEX transformation enabled" + " to support full transformation." ); + } + + if ( MDL_MODE & ( ms->parent_off ? MDLMD_CHILD_NODES : MDLMD_PARENT_NODE )) + { + PRINT(" - PATCH MDLs1 '%s'\n", it->name ); + mdl_sect1_t ms1; + ntoh_MDLs1(&ms1,ms); + + if ( MDL_MODE & MDLMD_VECTOR && opt_transform.norm_valid ) + { + if (opt_transform.scale_enabled) + { + ms1.scale.x *= opt_transform.norm_scale.x; + ms1.scale.y *= opt_transform.norm_scale.y; + ms1.scale.z *= opt_transform.norm_scale.z; + mdlpat->patch_status |= 1; + } + + if (opt_transform.rotate_enabled) + { + ms1.rotate.x += opt_transform.norm_rotate_deg.x; + ms1.rotate.y += opt_transform.norm_rotate_deg.y; + ms1.rotate.z += opt_transform.norm_rotate_deg.z; + mdlpat->patch_status |= 1; + } + + if (opt_transform.translate_enabled) + { + ms1.translate.x += opt_transform.norm_translate.x; + ms1.translate.y += opt_transform.norm_translate.y; + ms1.translate.z += opt_transform.norm_translate.z; + mdlpat->patch_status |= 1; + } + } + + if ( MDL_MODE & MDLMD_MATRIX ) + { + CalcMatrixMDLs1(&ms1); + mdlpat->patch_status |= 1; + } + + hton_MDLs1(ms,&ms1); + + #ifdef TEST0 + PrintMatrixMDLs1(stdout,0,0,&ms1,13); + #endif + } + } + } + else if ( it->group == 2 && MDL_MODE & MDLMD_VERTEX ) + { + mdl_sect2_t *ms = (mdl_sect2_t*)( it->szs->data + it->off ); + void *data = (u8*)ms + be32(&ms->data_off); + const uint format = be32(&ms->format); + const uint r_shift = ms->r_shift; + uint n_vertex = be16(&ms->n_vertex); + noPRINT("N-VERTEX=%u, FORMAT=%u, R-SHIFT=%u\n",n_vertex,r_shift); + + if ( n_vertex > 0 ) + { + // [[2do]] optimization?: load N, transform N, store N + + float3 min, max; + min.x = min.y = min.z = +INFINITY; + max.x = max.y = max.z = -INFINITY; + + DASSERT(mdlpat->mat); + while ( n_vertex-- > 0 ) + { + float3 temp; + GetVectorMDL(&temp,data,format,r_shift); + temp = TransformF3MatrixD(mdlpat->mat,&temp); + if (tform_script_enabled) + TformScriptCallF(3,&temp,1,0); + data = SetVectorMDL(&temp,data,format,r_shift); + + if (IsNormalF3(temp.v)) + { + if ( min.x > temp.x ) min.x = temp.x; + if ( min.y > temp.y ) min.y = temp.y; + if ( min.z > temp.z ) min.z = temp.z; + if ( max.x < temp.x ) max.x = temp.x; + if ( max.y < temp.y ) max.y = temp.y; + if ( max.z < temp.z ) max.z = temp.z; + } + } + write_bef4n(ms->minimum.v,min.v,3); + write_bef4n(ms->maximum.v,max.v,3); + mdlpat->patch_status |= 1; + } + } + #ifdef TEST0 + else if ( it->group == 8 ) + { + mdl_sect8_t *ms = (mdl_sect8_t*)( it->szs->data + it->off ); + const uint n_layer = ntohl(ms->n_layer); + PRINT("### MDL SECTION 8, brres-type=%x, size=0x%x, n-lay=%u\n", + it->szs->brres_type, be32(&ms->length), n_layer ); + + uint layer; + mdl_sect8_layer_t *msl = (mdl_sect8_layer_t*)( (u8*)ms + ntohl(ms->layer_off) ); + for ( layer = 0; layer < n_layer; layer++, msl++ ) + { + PRINT("\tLAYER #%u, off=%zx, min-filter=%x\n", + layer, (u8*)msl - (u8*)ms, ntohl(msl->min_filter) ); + } + } + #endif + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint PatchRawDataMDL +( + // returns + // 0: MDL not patched + // 1: MDL patched + // 3: MDL patched & vector transformation recognized + + void * data_ptr, // data to scan + uint data_size, // size of 'data' + patch_file_t brres_type, // type of related BRRES file + ccp fname // file name for error messages +) +{ + if (!HavePatchMDL()) + return false; + + MDL_ACTION_LOG(false,"PatchRawDataMDL(): %s\n",GetMdlMode()); + PRINT("PatchRawDataMDL(,,%x,): %s\n",brres_type,GetMdlMode()); + + mdl_patch_t mdlpat; + memset(&mdlpat,0,sizeof(mdlpat)); + mdlpat.brres_type = brres_type; + mdlpat.mat = &opt_transform; + + szs_file_t szs; +// [[fname+]] + AssignSZS(&szs,true,data_ptr,data_size,false,FF_MDL,fname); + szs.fname = fname; + IterateFilesSZS(&szs,patch_mdl,&mdlpat,true,0,1,SORT_NONE); + szs.fname = 0; + ResetSZS(&szs); + + return mdlpat.patch_status & 1 ? mdlpat.patch_status : 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// END /////////////// +/////////////////////////////////////////////////////////////////////////////// + -- cgit v1.3.1