diff options
Diffstat (limited to 'project/src/lib-kmp-draw.c')
| -rw-r--r-- | project/src/lib-kmp-draw.c | 2493 |
1 files changed, 2493 insertions, 0 deletions
diff --git a/project/src/lib-kmp-draw.c b/project/src/lib-kmp-draw.c new file mode 100644 index 0000000..b967a9f --- /dev/null +++ b/project/src/lib-kmp-draw.c @@ -0,0 +1,2493 @@ + +/*************************************************************************** + * _______ _______ _______ * + * | ___ |____ | ___ | * + * | | |_| / /| | |_| * + * | |_____ / / | |_____ * + * |_____ | / / |_____ | * + * _ | | / / _ | | * + * | |___| |/ /____| |___| | * + * |_______|_______|_______| * + * * + * Wiimms SZS Tools * + * https://szs.wiimm.de/ * + * * + *************************************************************************** + * * + * This file is part of the SZS project. * + * Visit https://szs.wiimm.de/ for project details and sources. * + * * + * Copyright (c) 2011-2020 by Dirk Clemens <wiimm@wiimm.de> * + * * + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt * + * * + ***************************************************************************/ + +#include "lib-kmp.h" +#include "lib-kcl.h" +#include "db-object.h" +#include "db-file.h" + +#include <math.h> + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// KMP draw support /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static const KeywordTab_t opt_draw_tab[] = +{ + { 0, "NONE", 0, DMD_M_RESET }, + { 0, "-ALL", 0, DMD_M_RESET }, + { DMD_M_ALL, "ALL", 0, DMD_M_RESET }, + { 0, "-POINTS", "-PTS", DMD_M_PTS }, + { DMD_M_PTS, "POINTS", "PTS", DMD_M_PTS }, + { 0, "-OBJECTS", "-GOBJ", DMD_M_GOBJ }, + { DMD_M_GOBJ, "OBJECTS", "GOBJ", DMD_M_GOBJ }, + { DMD_M_RESPAWN, "RESPAWN", 0, DMD_M_RESPAWN }, + { DMD_M_DEFAULT, "DEFAULT", 0, DMD_M_ALL }, + + { 0, "-OFFLINE", 0, DMD_M_OFFLINE }, + { DMD_M_OFFLINE, "OFFLINE", 0, DMD_M_OFFLINE }, + { 0, "-ONLINE", 0, DMD_M_ONLINE }, + { DMD_M_ONLINE, "ONLINE", 0, DMD_M_ONLINE }, + + { DMD_1OFFLINE, "1OFFLINE", 0, 0 }, + { DMD_2OFFLINE, "2OFFLINE", 0, 0 }, + { DMD_3OFFLINE, "3OFFLINE", "4OFFLINE", 0 }, + { DMD_1ONLINE, "1ONLINE", 0, 0 }, + { DMD_2ONLINE, "2ONLINE", 0, 0 }, + { DMD_3ONLINE, "3ONLINE", "4ONLINE", 0 }, + + { DMD_ENPT, "ENPT", 0, 0 }, + { DMD_ITPT, "ITPT", 0, 0 }, + { DMD_CKPT, "CKPT", 0, 0 }, + { DMD_CJGPT, "CJGPT", 0, 0 }, + { DMD_JGPT, "JGPT", 0, 0 }, + { DMD_KTPT, "KTPT", 0, 0 }, + { DMD_CNPT, "CNPT", 0, 0 }, + { DMD_POTI, "POTI", 0, 0 }, + { DMD_AREA, "AREA", 0, 0 }, + { DMD_ITEMBOX, "ITEMBOXES", 0, 0 }, + { DMD_COIN, "COINS", 0, 0 }, + { DMD_ROADOBJ, "ROADOBJECTS", 0, 0 }, + { DMD_SOLIDOBJ, "SOLIDOBJECTS", 0, 0 }, + { DMD_DECORATION, "DECORATION", 0, 0 }, + { DMD_BLACK, "BLACK", 0, 0 }, + { DMD_WHITE, "WHITE", 0, 0 }, + { DMD_KCL, "KCL", 0, 0 }, + + { DMD_DETAILED, "DETAILED", 0, 0 }, + { DMD_DISPATCH, "DISPATCH", 0, 0 }, + { DMD_WARNINGS, "WARNINGS", 0, 0 }, + + { 0,0,0,0 } +}; + +/////////////////////////////////////////////////////////////////////////////// + +draw_mode_t KMP_DRAW = DMD_M_DEFAULT; + +int ScanOptDraw ( ccp arg ) +{ + if (!arg) + return 0; + + s64 stat = ScanKeywordList( arg, opt_draw_tab, 0, true, 0, + *arg == '-' ? DMD_M_ALL : (DMD_M_ALL&~DMD_M_RESET), + "Option --draw", ERR_SYNTAX ); + if ( stat != M1(stat) ) + { + KMP_DRAW = stat & DMD_M_ALL; + return 0; + } + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +ccp GetDrawMode() +{ + static char buf[200] = {0}; + if (!*buf) + PrintKeywordList( buf, sizeof(buf), 0, opt_draw_tab, + KMP_DRAW, DMD_M_DEFAULT, 0 ); + return buf; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// helpers /////////////// +/////////////////////////////////////////////////////////////////////////////// + +#define OBJ_ROAD_COL 0x0000 + +/////////////////////////////////////////////////////////////////////////////// + +static void TransformByGOBJ +( + const + kmp_gobj_entry_t *obj, // object to draw + DbFlags_t flags, // flags DBF_SCALE and DBF_ROTATE + + double3 *pt, // pointer to first point to transform + uint pt_delta, // delta in bytes to next point + uint n_pt // number of points to rotate +) +{ + DASSERT(obj); + DASSERT(pt||!n_pt); + + double3 temp; + + if ( flags & DBF_SCALE ) + { + temp.x = obj->scale[0]; + temp.y = obj->scale[1]; + temp.z = obj->scale[2]; + Scale(0,&temp,pt,pt_delta,n_pt); + } + + if ( flags & DBF_ROTATE) + { + temp.x = obj->rotation[0]; + temp.y = obj->rotation[1]; + temp.z = obj->rotation[2]; + Rotate(0,&temp,pt,pt_delta,n_pt); + } + + temp.x = obj->position[0]; + temp.y = obj->position[1]; + temp.z = obj->position[2]; + Translate(&temp,pt,pt_delta,n_pt); +} + +/////////////////////////////////////////////////////////////////////////////// + +typedef struct rot_shape_t { int x; int y; } rot_shape_t; + +//----------------------------------------------------------------------------- + +static double3 * CreateRotatedShape +( + // returns an alloced list or NULL on error -> call FREE() + + const rot_shape_t *shape, // pointer to the shape + int n_shape, // number of elements of 'shape' + int n_segments, // number of segments + + const + kmp_gobj_entry_t *obj, // NULL or object for transformation + DbFlags_t flags // flags DBF_SCALE and DBF_ROTATE +) +{ + if ( n_shape < 1 || n_segments < 3 ) + return 0; + DASSERT(shape); + + const uint n_total = n_shape * n_segments; + double3 *res = MALLOC(n_total*sizeof(*res)); + + //--- create first segment + + uint i; + for ( i = 0; i < n_shape; i++ ) + { + res[i].x = shape[i].x; + res[i].y = shape[i].y; + res[i].z = 0.0; + } + + double3 rot; + rot.x = rot.y = rot.z = 0.0; + + //--- create additonal segments + + uint s; + for ( s = 1; s < n_segments; s++ ) + { + double3 *dest = res + s * n_shape; + memcpy( dest, res, sizeof(*dest) * n_shape ); + rot.y = 360.0 * s / n_segments; + Rotate(0,&rot,dest,sizeof(double3),n_shape); + } + + if (obj) + TransformByGOBJ(obj,flags,res,sizeof(double3),n_total); + + return res; +} + +/////////////////////////////////////////////////////////////////////////////// + +static int DrawRotatedShape +( + struct kcl_t *dk, // pointer to valid KCL + + const rot_shape_t *shape, // pointer to the shape + int n_shape, // number of elements of 'shape' + int n_segments, // number of segments + + const + kmp_gobj_entry_t *obj, // NULL or object for transformation + DbFlags_t flags, // flags DBF_SCALE and DBF_ROTATE + u32 col // print color +) +{ + DASSERT(dk); + + double3 *pt = CreateRotatedShape(shape,n_shape,n_segments,obj,flags); + if (!pt) + return 0; + +// [[append-p]] + + double3 *s2 = pt + n_shape * (n_segments-1); + uint s; + for ( s = 0; s < n_segments; s++ ) + { + double3 *s1 = s2; + s2 = pt + n_shape * s; + + double3 *p1 = s1, *p2 = s2; + uint i; + for ( i = 0; i < n_shape-1; i++, p1++, p2++ ) + { + if (!shape[i+1].x) + { + if ( shape[i+1].y == -1 ) + i++, p1++, p2++; + else if (shape[i].x) + AppendTriangleKCLp ( dk,col, p1, p1+1, p2 ); + } + else if (!shape[i].x) + AppendTriangleKCLp ( dk,col, p1, p1+1, p2+1 ); + else + AppendQuadrilateralKCLp( dk,col, p1, p1+1, p2+1, p2 ); + } + } + + FREE(pt); + return 1; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// AddAreas2KCL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void AddAreas2KCL +( + DrawKCL_t * dk // pointer to initalized object +) +{ + const double width = 150; + const double length = 1500; + + const uint n = dk->kmp->dlist[KMP_AREA].used; + const kmp_area_entry_t *area = (kmp_area_entry_t*)dk->kmp->dlist[KMP_AREA].list; + + uint i; + for ( i = 0; i < n; i++, area++ ) + { + double3 pos, rot, scale, base; + pos.x = area->position[0]; + pos.y = area->position[1]; + pos.z = area->position[2]; + rot.x = area->rotation[0]; + rot.y = area->rotation[1]; + rot.z = area->rotation[2]; + scale.x = area->scale[0]; + scale.y = area->scale[1]; + scale.z = area->scale[2]; + base.x = pos.x; + base.y = pos.y; + base.z = pos.z - length; + + Rotate(&pos,&rot,&base,sizeof(base),1); + + if (dk->detailed) + AppendPrismKCL( dk->draw, KCL_FLAG_AREA_ARROW, + &base, &pos, 0, width, 6, 0, + KCL_FLAG_AREA_ARROW, width, + KCL_FLAG_AREA_ARROW, 1.8, false ); + else + AppendPrismKCL( dk->draw, KCL_FLAG_AREA_ARROW, + &base, &pos, 0, width, 4, 1, + ~0, 0.0, ~0, 0.0, false ); + + if ( area->mode == 1 ) + { + AppendCylinderKCL( dk->draw, KCL_FLAG_AREA_BORDER, + &pos, &scale, 5000, &rot, 10, KCL_FLAG_AREA_BORDER ); + } + else + { + double3 size, shift; + size.x = size.y = size.z = 10000; + shift.x = shift.z = 0; + shift.y = 5000; + + cuboid_t cub; + CreateCuboid(&cub,&size,0,&shift); + ScaleCuboid(&cub,0,&scale); + RotateCuboid(&cub,0,&rot); + ShiftCuboid(&cub,&pos); + AppendCuboidKCL(dk->draw,KCL_FLAG_AREA_BORDER,&cub); + } + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// AddCheckPoints2KCL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void add_ckpt_joist +( + kcl_t *kcl, + const kmp_ckpt_entry_t *ckpt, + const kmp_ckpt_entry_t *c1, + uint next, + double min, + double max, + double width, + u32 kcl_flag_lt, + u32 kcl_flag_rt +) +{ + const kmp_ckpt_entry_t *c2 = ckpt + next; + + double3 d[3]; + d[0].y = d[1].y = max; + d[2].y = min; + + d[0].x = d[2].x = c1->left[0]; + d[0].z = d[2].z = c1->left[1]; + d[1].x = c2->left[0]; + d[1].z = c2->left[1]; + AppendJoistKCL(kcl,kcl_flag_lt,width,d,d+1,d+2,0,0); + + d[0].x = d[2].x = c1->right[0]; + d[0].z = d[2].z = c1->right[1]; + d[1].x = c2->right[0]; + d[1].z = c2->right[1]; + AppendJoistKCL(kcl,kcl_flag_rt,width,d,d+1,d+2,0,0); +} + +/////////////////////////////////////////////////////////////////////////////// + +void AddCheckPoints2KCL +( + DrawKCL_t * dk, // pointer to initalized object + bool draw_jgpt // true: draw connections to JGPT +) +{ + DASSERT(dk); + DASSERT(dk->draw); + if ( !dk || !dk->draw || !dk->kmp ) + return; + + const double lc_width = 600.0; + const double std_width = 300.0; + const double tie_width = 200.0; + const double next_width = 150.0; + const double jgpt_width = 150.0; + + + //--- find min and max heigth + + float min = 1000000; + float max = 0; + + uint n = dk->kmp->dlist[KMP_ENPT].used; + const kmp_enpt_entry_t * pt = (kmp_enpt_entry_t*)dk->kmp->dlist[KMP_ENPT].list; + for ( ; n > 0; n--, pt++ ) + { + if ( min > pt->position[1] ) + min = pt->position[1]; + if ( max < pt->position[1] ) + max = pt->position[1]; + } + if ( min > max ) + min = max; + min = round( min - 1500.0 ); + max = round( max + 4000.0 ); + + + //--- create rectangles for the check points + + n = dk->kmp->dlist[KMP_CKPT].used; + const kmp_ckpt_entry_t *ckpt = (kmp_ckpt_entry_t*)dk->kmp->dlist[KMP_CKPT].list; + const kmp_ckpt_entry_t *c1 = ckpt; + uint i; + for ( i = 0; i < n; i++, c1++ ) + { + //--- predefine params for check point gate + + uint kcl_flag, n_mark = 0; + double width = std_width; + + if ( !c1->mode ) + { + kcl_flag = KCL_FLAG_CKPT_LC; // KCL_FLAG_CKPT_LC_TT is used by 'kcl_flag+2' + width = lc_width; + } + else if ( c1->mode != M1(c1->mode) ) + { + kcl_flag = KCL_FLAG_CKPT_MD; // KCL_FLAG_CKPT_MD_TT is used by 'kcl_flag+2' + n_mark = (c1->mode-1) % 50 + 1; + } + else + kcl_flag = KCL_FLAG_CKPT_ETC; // KCL_FLAG_CKPT_ETC_TT is used by 'kcl_flag+2' + + + //--- iterate all links and draw them + + int std_next = GetNextPointKMP(dk->kmp,KMP_CKPT,c1-ckpt,-1,false,-1,0,0,0,0); + int link; + for ( link = 0; link < KMP_MAX_PH_LINK; link++ ) + { + bool new_group; + int next = GetNextPointKMP(dk->kmp,KMP_CKPT,c1-ckpt,link,true,-1,0,0,&new_group,0); + if ( next >= 0 ) + { + if ( std_next == next ) + std_next = -1; + + u32 flag_lt = new_group ? KCL_FLAG_CKPT_TIE_GROUP_LT : KCL_FLAG_CKPT_TIE_LT; + u32 flag_rt = new_group ? KCL_FLAG_CKPT_TIE_GROUP_RT : KCL_FLAG_CKPT_TIE_RT; + + if (dk->warnings) + { + double min_dist; + const int stat = CheckConvexCKPT(dk->kmp,i,next,&min_dist); + if ( stat || min_dist < KMP_DIST_WARN ) + { + flag_lt = flag_rt = kcl_flag = KCL_FLAG_CKPT_WARNING; + // KCL_FLAG_CKPT_WARNING_TT is used by 'kcl_flag+2' + } + } + + add_ckpt_joist(dk->draw,ckpt,c1,next,min,max,tie_width,flag_lt,flag_rt); + } + } + + if ( std_next >= 0 ) + add_ckpt_joist( dk->draw, ckpt, c1, std_next, min, max, next_width, + KCL_FLAG_CKPT_TIE_NEXT_LT, KCL_FLAG_CKPT_TIE_NEXT_RT ); + + + //--- draw check point gate + + double3 d[4]; + d[0].x = d[1].x = c1->left[0]; + d[0].z = d[1].z = c1->left[1]; + d[2].x = d[3].x = c1->right[0]; + d[2].z = d[3].z = c1->right[1]; + d[0].y = d[3].y = max; + d[1].y = d[2].y = min; + + AppendJoistKCL(dk->draw,kcl_flag,width,d+0,d+1,d+3,0,0); + AppendJoistKCL(dk->draw,kcl_flag,width,d+1,d+2,d+0,0,0); + AppendJoistKCL(dk->draw,kcl_flag,width,d+2,d+3,d+1,0,0); + AppendJoistKCL(dk->draw,kcl_flag,width,d+3,d+0,d+2,n_mark,KCL_FLAG_CKPT_MD5); + AppendTrianglesKCLp(dk->draw,kcl_flag+2,d,sizeof(double3),4); + + + //--- draw respawn point links + + if ( draw_jgpt && c1->respawn < dk->kmp->dlist[KMP_JGPT].used ) + { + const kmp_jgpt_entry_t *jgpt + = (kmp_jgpt_entry_t*)dk->kmp->dlist[KMP_JGPT].list + c1->respawn; + + d[0].y = max; + d[2].y = min; + d[0].x = d[2].x = c1->left[0]; + d[0].z = d[2].z = c1->left[1]; + d[1].x = jgpt->position[0]; + d[1].y = jgpt->position[1]; + d[1].z = jgpt->position[2]; + AppendJoistKCL(dk->draw,KCL_FLAG_CKPT_JGPT,jgpt_width,d,d+1,d+2,0,0); + + d[0].x = d[2].x = c1->right[0]; + d[0].z = d[2].z = c1->right[1]; + AppendJoistKCL(dk->draw,KCL_FLAG_CKPT_JGPT,jgpt_width,d,d+1,d+2,0,0); + } + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// AddArrow2KCL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void AddArrow2KCL +( + DrawKCL_t * dk, // pointer to initalized object + uint sect, // KMP section + uint arrow_color, // color of arrow + uint area_color, // color of area behind arrow + double area_len, // >0.0: width of area behind arrow + double area_wd // >0.0: length of area behind arrow +) +{ + DASSERT(dk); + DASSERT(dk->draw); + if ( !dk || !dk->draw || !dk->kmp ) + return; + + const bool have_area = area_len > 0.0 && area_wd > 0.0; + const double length = have_area ? area_len : 1500; + //const double width = length/2 < 200 ? length/2 : 200; + const double width = 150; + area_wd /= 2; + + const uint n = dk->kmp->dlist[sect].used; + const kmp_jgpt_entry_t * pt = (kmp_jgpt_entry_t*)dk->kmp->dlist[sect].list; + +// [[append-p]] + + uint i; + for ( i = 0; i < n; i++, pt++ ) + { + double3 pos, rot, base; + pos.x = pt->position[0]; + pos.y = pt->position[1]; + pos.z = pt->position[2]; + rot.x = pt->rotation[0]; + rot.y = pt->rotation[1]; + rot.z = pt->rotation[2]; + base.x = pos.x; + base.y = pos.y; + base.z = pos.z - length; + + Rotate(&pos,&rot,&base,sizeof(base),1); + + if (dk->detailed) + AppendPrismKCL( dk->draw, arrow_color, + &base, &pos, 0, width, 6, 0, + arrow_color, width, + arrow_color, 1.8, false ); + else + AppendPrismKCL( dk->draw, arrow_color, + &base, &pos, 0, width, 4, 1, + ~0, 0.0, ~0, 0.0, false ); + + if ( area_len > 0.0 && area_wd > 0.0 ) + { + double3 p[4]; + p[0].x = p[1].x = pos.x + area_wd; + p[2].x = p[3].x = pos.x - area_wd; + p[0].y = p[1].y = p[2].y = p[3].y = pos.y + 20; + p[0].z = p[3].z = pos.z; + p[1].z = p[2].z = pos.z - area_len; + + Rotate(&pos,&rot,p,sizeof(*p),4); + AppendQuadrilateralKCLp( dk->draw, area_color, p, p+1, p+2, p+3 ); + } + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// AddPotiRoute2KCL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void AddPotiRoute2KCL +( + struct kcl_t *kcl, // pointer to valid KCL + const u32 color, // color + double width, // width of pyramid + bool detailed, // print end points detailed + const kmp_poti_group_t *pg, // pointer to group + const kmp_poti_point_t *pp, // pointer to first point + int limit // max num of points to draw + +) +{ + uint en = pg->n_point; + if ( en > (uint)limit ) + en = limit; + if ( !en || limit <= 0 ) + return; + + const kmp_poti_point_t *pp0 = pp; + + double3 pt2; + pt2.x = pp->position[0]; + pt2.y = pp->position[1]; + pt2.z = pp->position[2]; + pp++; + + if ( en == 1 ) + { + double3 pt[4]; + pt[0] = pt2; pt[0].z += width; + pt[1] = pt2; pt[1].x += width; + pt[2] = pt2; pt[2].z -= width; + pt[3] = pt2; pt[3].x -= width; + + double3 apex; + apex = pt2; apex.y += width; + AppendPyramidKCL(kcl,color,&apex,pt,sizeof(*pt),4,false); + apex.y = pt2.y - width; + AppendPyramidKCL(kcl,color,&apex,pt,sizeof(*pt),4,false); + + return; + } + + uint ei; + for ( ei = 1; ei < en; ei++ ) + { + double3 pt1 = pt2; + pt2.x = pp->position[0]; + pt2.y = pp->position[1]; + pt2.z = pp->position[2]; + pp++; + + double3 helper = pt1; + helper.y += 1000; + + if (detailed) + AppendPrismKCL( kcl, color, &pt1, &pt2, &helper, + width, 6, 0, color, width, ~0, 0.0, false ); + else + AppendPrismKCL( kcl, color, &pt1, &pt2, &helper, + width, 4, 1, ~0, 0.0, ~0, 0.0, false ); + } + + if ( !pg->back && en > 2 ) // is cyclic + { + + double3 pt0; + pt0.x = pp0->position[0]; + pt0.y = pp0->position[1]; + pt0.z = pp0->position[2]; + + double3 helper = pt0; + helper.y += 1000; + + if (detailed) + AppendPrismKCL( kcl, color, &pt2, &pt0, &helper, + width, 6, 0, color, width, ~0, 0.0, false ); + else + AppendPrismKCL( kcl, color, &pt2, &pt0, &helper, + width, 4, 1, ~0, 0.0, ~0, 0.0, false ); + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// AddRoutes2KCL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void AddRoutes2KCL +( + DrawKCL_t * dk, // pointer to initalized object + uint sect_pt, // KMP section + uint color_std // standart color index +) +{ + DASSERT(dk); + DASSERT(dk->draw); + if ( !dk || !dk->draw || !dk->kmp ) + return; + DASSERT( sect_pt == KMP_ENPT || sect_pt == KMP_ITPT ); + + //--- setup + + const uint color_single = color_std + ( KCL_FLAG_ENPT_SINGLE - KCL_FLAG_ENPT ); + const uint color_tie_bi = color_std + ( KCL_FLAG_ENPT_TIE_BI - KCL_FLAG_ENPT ); + const uint color_tie_prev = color_std + ( KCL_FLAG_ENPT_TIE_PREV - KCL_FLAG_ENPT ); + const uint color_tie_next = color_std + ( KCL_FLAG_ENPT_TIE_NEXT - KCL_FLAG_ENPT ); + const uint color_dispatch = color_std + ( KCL_FLAG_ENPT_DISPATCH - KCL_FLAG_ENPT ); + + double3 max_pt; + max_pt.x = max_pt.y = max_pt.z = 0; + uint col1_used = 0, col2_used = 0; + + double3 pos_beg[KMP_MAX_LINFO], pos_end[KMP_MAX_LINFO]; + memset(pos_beg,0,sizeof(pos_beg)); + memset(pos_end,0,sizeof(pos_end)); + + const double width_std = 200.0; + const double width_tie2 = 120.0; + const double width_next = 70.0; + const double width_prev = 40.0; + const double width_oct = 1.8 * width_std; + const double dist_oct = 1.9 * width_std; + + kmp_linfo_t *li = SetupRouteLinksKMP(dk->kmp,sect_pt,false); + + const uint n = dk->kmp->dlist[li->sect_pt].used; + const kmp_enpt_entry_t *pt = (kmp_enpt_entry_t*)dk->kmp->dlist[li->sect_pt].list; + + + //--- draw dispatch points and sub routes, but no links + + uint i; + double3 pt0; + bool pt0_valid = false; + + for ( i = 0; i < n; i++ ) + { + //--- calculate position of point + + double3 pt1, helper; + pt1.x = helper.x = pt[i].position[0]; + pt1.y = pt[i].position[1]; + pt1.z = helper.y = pt[i].position[2]; + helper.y = pt1.y + 10000; + + if (i) + { + if ( max_pt.x < pt1.x ) max_pt.x = pt1.x; + if ( max_pt.y < pt1.y ) max_pt.y = pt1.y; + if ( max_pt.z < pt1.z ) max_pt.z = pt1.z; + } + else + max_pt = pt1; + + + //--- store postions of first and last point of a route + + int ph_index; + const kmp_enph_entry_t *ph = FindPH(dk->kmp,li->sect_ph,i,&ph_index); + if (!ph) + { + pt0_valid = false; + continue; + } + + DASSERT( ph_index >= 0 ); + if ( i == ph->pt_start ) + pos_beg[ph_index] = pt1; + + const bool is_last_pt = i == ph->pt_start + ph->pt_len - 1; + if ( is_last_pt ) + pos_end[ph_index] = pt1; + + + //-- draw dispatch point + + if ( li->gmode[i] & LINFOG_DISPATCH || li->n_point[i] == 1 ) + { + octahedron_t oct; + CreateRegularOctahedron(&oct,width_oct,0,&pt1); + + if ( !( li->gmode[i] & LINFOG_DISPATCH )) + AppendOctahedronKCL(dk->draw,color_single,&oct); + else if ( KMP_DRAW & DMD_DISPATCH ) + { + double3 shift; + shift.x = -dist_oct/2; + shift.y = width_tie2; + shift.z = 0.0; + ShiftOctahedron(&oct,&shift); + uint color = ph->setting[0] & 7; + col1_used |= 1 << color; + AppendOctahedronKCL(dk->draw,KCL_FLAG_TEST0+3*color,&oct); + + shift.x = dist_oct; + shift.y = 0.0; + ShiftOctahedron(&oct,&shift); + color = ph->setting[1] >> 5 & 7; + col2_used |= 1 << color; + AppendOctahedronKCL(dk->draw,KCL_FLAG_TEST0+3*color,&oct); + } + else + AppendOctahedronKCL(dk->draw,color_dispatch,&oct); + pt0_valid = false; + } + else + { + if ( pt0_valid ) + { + if (dk->detailed) + AppendPrismKCL( dk->draw, color_std, &pt0, &pt1, &helper, + width_std, 6, 0, color_std, + width_std, ~0, 0.0, false ); + else + AppendPrismKCL( dk->draw, color_std, &pt0, &pt1, &helper, + width_std, 4, 1, ~0, + 0.0, ~0, 0.0, false ); + } + pt0_valid = !is_last_pt; + pt0 = pt1; + } + } + + + //--- draw dispatch points summary + + if ( KMP_DRAW & DMD_DISPATCH && max_pt.y > 0.0 ) + { + max_pt.x += 1500; + max_pt.z -= 7*2.2*width_oct; + + double3 shift; + shift.x = dist_oct; + shift.y = shift.z = 0.0; + + uint i; + for ( i = 0; i < 8; i++ ) + { + octahedron_t oct1, oct2; + CreateRegularOctahedron(&oct1,width_oct,0,&max_pt); + CreateRegularOctahedron(&oct2,0.4*width_oct,0,&max_pt); + + const uint color = KCL_FLAG_TEST0 + 3*i; + if ( col1_used & 1<<i ) + AppendOctahedronKCL(dk->draw,color,&oct1); + else + AppendOctahedronKCL(dk->draw,color,&oct2); + + if (!(i&1)) + { + if ( col2_used & 1<<i ) + { + ShiftOctahedron(&oct1,&shift); + AppendOctahedronKCL(dk->draw,color,&oct1); + } + else + { + ShiftOctahedron(&oct2,&shift); + AppendOctahedronKCL(dk->draw,color,&oct2); + } + } + max_pt.z += 2.2*width_oct; + } + } + + + //--- draw group links in 2 passes (0,1): bidirect first, others second + + li = SetupRouteLinksKMP(dk->kmp,li->sect_ph,false); + + int pass; + for ( pass = 0; pass < 2; pass++ ) + { + for ( i = 0; i < li->used; i++ ) + { + const kmp_linfo_mode *lm = li->list[i]; + uint j0; + for ( j0 = 0; j0 < li->used; j0++ ) + { + kmp_linfo_mode mode = *lm++; + if (!mode) + continue; // fast skip + + uint j = j0; + uint color = 0; + double width = 0.0; + double3 *pt1 = pos_end+i; + double3 *pt2 = pos_beg+j; + u32 arrow_col = ~0; + bool arrow_flip = false; + + if ( mode & LINFO_G_NEXT && li->gmode[i] & LINFOG_DISPATCH ) + { + double3 *pt3 = pos_end+j; + if ( Length2D(pt1->v,pt3->v) < Length2D(pt1->v,pt2->v) ) + { + pt2 = pt3; + if ( mode & LINFO_G_BY_NEXT ) + mode |= LINFO_G_BY_PREV; + } + } + + if ( mode & LINFO_G_NEXT ) + { + if ( mode & LINFO_G_BY_PREV || + mode & LINFO_G_BY_NEXT && li->gmode[i] & LINFOG_DISPATCH ) + { + li->list[i][j] = li->list[j][i] = 0; // reset connection info + color = color_tie_bi; + width = width_tie2; + } + else if (pass) + { + color = arrow_col = color_tie_next; + width = width_next; + } + } + else if ( pass && mode & LINFO_G_BY_PREV ) + { + color = arrow_col = color_tie_prev; + width = width_prev; + double3 *temp = pt1; + pt1 = pt2; + pt2 = temp; + } + + if (color) + { + double3 helper; + helper.x = pt1->x; + helper.y = pt1->y + 10000; + helper.z = pt1->z; + + double arrow_size = 0.0; + if ( arrow_col != M1(arrow_col) ) + { + arrow_size = 1.5; + } + + if (dk->detailed) + AppendPrismKCL( dk->draw, color, pt1, pt2, &helper, + width, 6, 0, color, width, + arrow_col, arrow_size, arrow_flip ); + else + AppendPrismKCL( dk->draw, color, pt1, pt2, &helper, + width, 4, 1, ~0, 0.0, + arrow_col, arrow_size, arrow_flip ); + } + } + } + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// AddPotiRoutes2KCL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void AddPotiRoutes2KCL +( + DrawKCL_t * dk // pointer to initalized object +) +{ + DASSERT(dk); + DASSERT(dk->draw); + if ( !dk || !dk->draw || !dk->kmp ) + return; + + const double width = 200.0; + + const uint ng = dk->kmp->dlist[KMP_POTI].used; + const kmp_poti_group_t * pg = (kmp_poti_group_t*)dk->kmp->dlist[KMP_POTI].list; + const uint np = dk->kmp->poti_point.used; + const kmp_poti_point_t * pp = (kmp_poti_point_t*)dk->kmp->poti_point.list; + + uint gi, i; + for ( gi = i = 0; gi < ng && i < np; gi++, pg++ ) + { + u32 color = KCL_FLAG_POTI0 + gi%4; + if ( gi < MAX_ROUTE ) + switch (dk->route[gi]) + { + case DRTM_OFF: + color = 0; + break; + + case DRTM_POTI: + //case DRTM_CAME: + // use default + break; + + case DRTM_GOBJ: + color = KCL_FLAG_SOLID_ROUTE; + break; + + case DRTM_ITEMBOX: + color = KCL_FLAG_ITEMROUTE; + break; + + case DRTM_ITEMBOX_ENEMY: + color = KCL_FLAG_ITEMROUTE_ENEMY; + break; + + case DRTM_ITEMBOX_PLAYER: + color = KCL_FLAG_ITEMROUTE_PLAYER; + break; + } + + if (color) + AddPotiRoute2KCL( dk->draw, color, width, dk->detailed, pg, pp, np-i ); + pp += pg->n_point; + i += pg->n_point; + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// AddCannons2KCL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +const double cannon_aura = 50.0; + +//----------------------------------------------------------------------------- + +static uint td_minmax +( + const kcl_tridata_t *td, // valid tridata + double rot_rad, // rotation in radiant + double *res_min, // store min data here + double *res_max, // store max data here + double3 *res_sum // add points here +) +{ + DASSERT(td); + DASSERT(res_min); + DASSERT(res_max); + DASSERT(res_sum); + + const double3 *pt = td->pt; + double rad = atan2(pt->x,pt->z) + rot_rad; + double min, max = sin(rad) * sqrt( pt->x * pt->x + pt->z * pt->z ); + + pt++; + rad = atan2(pt->x,pt->z) + rot_rad; + double temp = sin(rad) * sqrt( pt->x * pt->x + pt->z * pt->z ); + if ( temp <= max ) + min = temp; + else + { + min = max; + max = temp; + } + + pt++; + rad = atan2(pt->x,pt->z) + rot_rad; + temp = sin(rad) * sqrt( pt->x * pt->x + pt->z * pt->z ); + *res_min = ( temp < min ? temp : min ) - cannon_aura; + *res_max = ( temp > min ? temp : max ) + cannon_aura; + + res_sum->x += td->pt[0].x + td->pt[1].x + td->pt[2].x; + res_sum->y += td->pt[0].y + td->pt[1].y + td->pt[2].y; + res_sum->z += td->pt[0].z + td->pt[1].z + td->pt[2].z; + return 3; +} + +/////////////////////////////////////////////////////////////////////////////// + +void AddCannons2KCL +( + DrawKCL_t * dk // pointer to initalized object +) +{ + DASSERT(dk); + DASSERT(dk->draw); + if ( !dk || !dk->draw || !dk->kmp || !dk->kcl ) + return; + + const uint ctype = 0x11; + const double cube_size = 500.0; + //const double way_size = 1500.0; + + //--- set td markers for unresolved cannon triangles + //--- and find first and last cannon (for optimization) + + const uint n_tri = dk->kcl->tridata.used; + uint i, first_can = n_tri+1, last_can = 0; + kcl_tridata_t *td = (kcl_tridata_t*)dk->kcl->tridata.list; + for ( i = 0; i < n_tri; i++, td++ ) + { + td->status &= ~TD_MARK; + if (IS_KCL_TYPE(td->cur_flag,ctype)) + { + td->status |= TD_MARK; + if ( first_can > i ) + first_can = i; + last_can = i; + } + } + PRINT("CANNONS: %u .. %u / %u\n",first_can,last_can,n_tri); + if ( first_can > last_can ) + return; + const uint n_can = last_can + 1 - first_can; + + + //--- main loop + + const uint nc = dk->kmp->dlist[KMP_CNPT].used; + const kmp_cnpt_entry_t * cnpt = (kmp_cnpt_entry_t*)dk->kmp->dlist[KMP_CNPT].list; + uint ic = 0; + while ( ic < nc ) + { + //--- find first cannon + + const uint ftype = ctype | ic << 5; + const double rot_rad = -cnpt->rotation[1] * (M_PI/180.0); + + bool retry = false; + kcl_tridata_t *td = (kcl_tridata_t*)dk->kcl->tridata.list + first_can; + kcl_tridata_t *td_end = td + n_can; + for ( ; td < td_end; td++ ) + if ( td->status & TD_MARK && td->cur_flag == ftype ) + { + double min, max; + double3 sum; + sum.x = sum.y = sum.z = 0.0; + uint n = td_minmax(td,rot_rad,&min,&max,&sum); + td->status &= ~TD_MARK; + for ( ; td < td_end; td++ ) + if ( td->status & TD_MARK && td->cur_flag == ftype ) + { + double min2, max2; + n += td_minmax(td,rot_rad,&min2,&max2,&sum); + if ( min2 <= max && max2 >= min ) + { + if ( min > min2 ) + min = min2; + if ( max < max2 ) + max = max2; + td->status &= ~TD_MARK; + } + } + min += cannon_aura; + max -= cannon_aura; + + PRINT("CANNON #%u found: %3.1f..%3.1f\n", ic, min, max ); + + double3 size; + size.x = max - min; + size.y = size.z = cube_size; + + double3 shift; + shift.x = ( min + max ) /2; + shift.y = cnpt->position[1]; + shift.z = cos( atan2(cnpt->position[0],cnpt->position[2]) + rot_rad ) + * sqrt( cnpt->position[0]*cnpt->position[0] + + cnpt->position[2]*cnpt->position[2] ); + + cuboid_t cub; + CreateCuboid(&cub,&size,0,&shift); + + double3 rotate; + rotate.x = rotate.z = 0.0; + rotate.y = cnpt->rotation[1]; + RotateCuboid(&cub,0,&rotate); + + double f = cnpt->rotation[0]; + if ( f > 0.0 && f <= 100.0 ) + { + shift.x = ( cub.p000.x + cub.p111.x ) / 2; + shift.y = ( cub.p000.y + cub.p111.y ) / 2; + shift.z = ( cub.p000.z + cub.p111.z ) / 2; + f /= 100.0; + shift.x = ( cnpt->position[0] - shift.x ) * f; + shift.y = ( cnpt->position[1] - shift.y ) * f; + shift.z = ( cnpt->position[2] - shift.z ) * f; + ShiftCuboid(&cub,&shift); + } + + AppendCuboidKCL(dk->draw,KCL_FLAG_CNPT_LANDING,&cub); + + double3 dest, helper; + dest.x = helper.x = ( cub.p000.x + cub.p011.x ) / 2; + dest.y = ( cub.p000.y + cub.p011.y ) / 2; + dest.z = helper.z = ( cub.p000.z + cub.p011.z ) / 2; + helper.y = dest.y + 10000; + sum.x /= n; + sum.y /= n; + sum.z /= n; + + if (dk->detailed) + AppendPrismKCL( dk->draw, KCL_FLAG_CNPT_WAY, + &sum, &dest, &helper, cube_size/4, 6, 0, + KCL_FLAG_CNPT_WAY, cube_size, + KCL_FLAG_CNPT_WAY, 2.0, false ); + else + AppendPrismKCL( dk->draw, KCL_FLAG_CNPT_WAY, + &sum, &dest, &helper, cube_size/4, 4, 1, + ~0, 0.0, ~0, 0.0, false ); + + #ifdef TEST0 + size.y = cube_size/3; + size.z = way_size; + shift.z -= (cube_size+way_size)/2; + CreateCuboid(&cub,&size,0,&shift); + RotateCuboid(&cub,0,&rotate); + AppendCuboidKCL(dk->draw,KCL_FLAG_CNPT_WAY,&cub); + #endif + + #ifdef TEST0 + CreateCube(&cub,10000,0,0); + AppendCuboidKCL(dk->draw,KCL_FLAG_BLUE,&cub); + #endif + + retry = true; + break; + } + + if (!retry) + { + ic++; + cnpt++; + continue; + } + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// AddObject helper /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void SetupMatrixD +( + MatrixD_t *mat, // will be initialized + const + kmp_gobj_entry_t *op, // object to draw + DbFlags_t flags, // file flags + const s16 *raise // NULL or value to raise +) +{ + DASSERT(mat); + DASSERT(op); + + InitializeMatrixD(mat); + + if ( raise && *raise ) + { + double3 shift; + shift.x = shift.z = 0.0; + shift.y = *raise; + SetShiftMatrixD(mat,&shift); + } + + if ( flags & DBF_SCALE ) + { + double3 scale; + scale.x = op->scale[0]; + scale.y = op->scale[1]; + scale.z = op->scale[2]; + SetScaleMatrixD(mat,&scale,0); + } + + if ( flags & DBF_ROTATE ) + { + SetRotateMatrixD(mat,0,op->rotation[0],0.0,0); + SetRotateMatrixD(mat,1,op->rotation[1],0.0,0); + SetRotateMatrixD(mat,2,op->rotation[2],0.0,0); + } + + double3 trans; + trans.x = op->position[0]; + trans.y = op->position[1]; + trans.z = op->position[2]; + SetTranslateMatrixD(mat,&trans); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// AddObject: Add_*() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +typedef uint (*add_func) +( + struct kcl_t *dk, // pointer to valid KCL + const + kmp_gobj_entry_t *op, // object to draw + DbFlags_t flags, // file flags + const s16 *data, // valid pointer to data + uint data_size, // size of data + bool detailed, // draw object detailed + bool as_road // draw as road +); + +/////////////////////////////////////////////////////////////////////////////// + +static uint Add_RECTANGLE +( + struct kcl_t *dk, // pointer to valid KCL + const + kmp_gobj_entry_t *op, // object to draw + DbFlags_t flags, // file flags + const s16 *data, // valid pointer to data + uint data_size, // size of data + bool detailed, // draw object detailed + bool as_road // draw as road +) +{ + DASSERT(dk); + DASSERT(op); + DASSERT(data); + + // ==> color x-len z-len x-rot y-rot z-rot + + if ( data_size < 6 ) + return 0; + + u32 col = *data++ + N_KCL_FLAG; + if (as_road) + col = OBJ_ROAD_COL; + + double xlen = *data++; + double zlen = *data++; + double3 rot; + rot.x = *data++; + rot.y = *data++; + rot.z = *data++; + + double3 pt[4]; + pt[0].x = pt[1].x = -xlen; + pt[2].x = pt[3].x = +xlen; + pt[0].y = pt[1].y = pt[2].y = pt[3].y = 25.0; // make it a little bit higher + pt[0].z = pt[3].z = -zlen; + pt[1].z = pt[2].z = +zlen; + + Rotate(0,&rot,pt,sizeof(double3),4); + TransformByGOBJ(op,flags,pt,sizeof(double3),4); + AppendQuadrilateralKCLp(dk,col,pt,pt+1,pt+2,pt+3); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint Add_CUBE +( + struct kcl_t *draw, // pointer to valid KCL + const + kmp_gobj_entry_t *op, // object to draw + DbFlags_t flags, // file flags + const s16 *data, // valid pointer to data + uint data_size, // size of data + bool detailed, // draw object detailed + bool as_road // draw as road +) +{ + DASSERT(draw); + DASSERT(op); + DASSERT(data); + + // ==> color width [raise] + + if ( data_size < 2 ) + return 0; + + u32 col = *data++ + N_KCL_FLAG; + double wd = *data++; + double raise = data_size >= 3 ? *data : 0.0; + + float3 pos; + pos.x = op->position[0]; + pos.y = op->position[1] + raise; + pos.z = op->position[2]; + + float3 size; + if ( flags & DBF_SCALE ) + { + size.x = wd * op->scale[0]; + size.y = wd * op->scale[1]; + size.z = wd * op->scale[2]; + } + else + size.x = size.y = size.z = wd; + + cuboid_t cub; + CreateCuboidF( &cub, size.v, flags & DBF_ROTATE ? op->rotation : 0, pos.v ); + AppendCuboidKCL(draw,col,&cub); + + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint Add_CUBOID +( + struct kcl_t *draw, // pointer to valid KCL + const + kmp_gobj_entry_t *op, // object to draw + DbFlags_t flags, // file flags + const s16 *data, // valid pointer to data + uint data_size, // size of data + bool detailed, // draw object detailed + bool as_road // draw as road +) +{ + DASSERT(draw); + DASSERT(op); + DASSERT(data); + + // ==> color width [raise] + + if ( data_size < 4 ) + return 0; + + u32 col = *data++ + N_KCL_FLAG; + float3 size; + size.x = *data++; + size.y = *data++; + size.z = *data++; + + float3 shift; + if ( data_size >= 7 ) + { + shift.x = *data++; + shift.y = *data++; + shift.z = *data++; + } + else + shift.x = shift.y = shift.z = 0.0; + + if ( flags & DBF_SCALE ) + { + size.x *= op->scale[0]; + size.y *= op->scale[1]; + size.z *= op->scale[2]; + + shift.x *= op->scale[0]; + shift.y *= op->scale[1]; + shift.z *= op->scale[2]; + } + + float3 pos; + pos.x = op->position[0] + shift.x; + pos.y = op->position[1] + shift.y; + pos.z = op->position[2] + shift.z; + + cuboid_t cub; + CreateCuboidF( &cub, size.v, flags & DBF_ROTATE ? op->rotation : 0, pos.v ); + AppendCuboidKCL(draw,col,&cub); + + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint Add_CYLINDER_Y +( + struct kcl_t *draw, // pointer to valid KCL + const + kmp_gobj_entry_t *op, // object to draw + DbFlags_t flags, // file flags + const s16 *data, // valid pointer to data + uint data_size, // size of data + bool detailed, // draw object detailed + bool as_road // draw as road +) +{ + DASSERT(draw); + DASSERT(op); + DASSERT(data); + + // ==> color length radius [raise] + + if ( data_size < 3 ) + return 0; + + u32 col = *data++ + N_KCL_FLAG; + double len = *data++; + double xr = *data++; + double zr = xr; + double raise = data_size >= 4 ? *data : 0.0; + len += raise; + + if ( flags & DBF_SCALE ) + { + xr *= op->scale[0]; + len *= op->scale[1]; + raise *= op->scale[1]; + zr *= op->scale[2]; + } + + const uint max_sides = 8; + double3 pt[2*max_sides+4]; + + const uint n_sides = detailed ? max_sides : 6; + const uint n_used = 2*n_sides+4; + double3 *tab0 = pt+2, *tab1 = tab0 + n_sides + 1; + + pt[0].x = pt[0].z = pt[1].x = pt[1].z = 0.0; + pt[0].y = raise; + pt[1].y = len; + + double3 *p0 = tab0, *p1 = tab1; + const double add_rad = M_PI / n_sides; + double rad = 0.0; + + uint i; + for ( i = 0; i < n_sides; i++ ) + { + p0->x = cos(rad) * xr; + p0->y = raise; + p0->z = sin(rad) * zr; + p0++; + rad += add_rad; + + p1->x = cos(rad) * xr; + p1->y = len; + p1->z = sin(rad) * zr; + p1++; + rad += add_rad; + } + *p0 = *tab0; + *p1 = *tab1; + + if ( flags & DBF_ROTATE ) + { + double3 rot; + rot.x = op->rotation[0]; + rot.y = op->rotation[1]; + rot.z = op->rotation[2]; + Rotate(0,&rot,pt,sizeof(*pt),n_used); + } + + double3 pos; + pos.x = op->position[0]; + pos.y = op->position[1]; + pos.z = op->position[2]; + Translate(&pos,pt,sizeof(*pt),n_used); + + for ( i = 0, p0 = tab0, p1 = tab1; i < n_sides; i++, p0++, p1++ ) + { + AppendTriangleKCLp( draw, col, p0+1, p0, p1 ); + AppendTriangleKCLp( draw, col, p0+1, p1, p1+1 ); + } + + AppendTrianglesKCLp(draw,col,tab0,sizeof(*tab0),n_sides); + AppendTrianglesKCLp(draw,col,tab1+n_sides-1,-(int)sizeof(*tab1),n_sides); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint Add_CYLINDER_Z +( + struct kcl_t *draw, // pointer to valid KCL + const + kmp_gobj_entry_t *op, // object to draw + DbFlags_t flags, // file flags + const s16 *data, // valid pointer to data + uint data_size, // size of data + bool detailed, // draw object detailed + bool as_road // draw as road +) +{ + DASSERT(draw); + DASSERT(op); + DASSERT(data); + + // ==> color length radius [raise] + + if ( data_size < 3 ) + return 0; + + u32 col = *data++ + N_KCL_FLAG; + double len = *data++; + double xr = *data++; + double yr = xr; + double raise = data_size >= 4 ? *data : 0.0; + len += raise; + + if ( flags & DBF_SCALE ) + { + xr *= op->scale[0]; + yr *= op->scale[1]; + len *= op->scale[2]; + raise *= op->scale[2]; + } + + const uint max_sides = 8; + double3 pt[2*max_sides+4]; + + const uint n_sides = detailed ? max_sides : 6; + const uint n_used = 2*n_sides+4; + double3 *tab0 = pt+2, *tab1 = tab0 + n_sides + 1; + + pt[0].x = pt[0].y = pt[1].x = pt[1].y = 0.0; + pt[0].z = raise; + pt[1].z = len; + + double3 *p0 = tab0, *p1 = tab1; + const double add_rad = M_PI / n_sides; + double rad = 0.0; + + uint i; + for ( i = 0; i < n_sides; i++ ) + { + p0->x = sin(rad) * xr; + p0->y = cos(rad) * yr + yr; + p0->z = raise; + p0++; + rad += add_rad; + + p1->x = sin(rad) * xr; + p1->y = cos(rad) * yr + yr; + p1->z = len; + p1++; + rad += add_rad; + } + *p0 = *tab0; + *p1 = *tab1; + + if ( flags & DBF_ROTATE ) + { + double3 rot; + rot.x = op->rotation[0]; + rot.y = op->rotation[1]; + rot.z = op->rotation[2]; + Rotate(0,&rot,pt,sizeof(*pt),n_used); + } + + double3 pos; + pos.x = op->position[0]; + pos.y = op->position[1]; + pos.z = op->position[2]; + Translate(&pos,pt,sizeof(*pt),n_used); + + for ( i = 0, p0 = tab0, p1 = tab1; i < n_sides; i++, p0++, p1++ ) + { + AppendTriangleKCLp( draw, col, p0+1, p0, p1 ); + AppendTriangleKCLp( draw, col, p0+1, p1, p1+1 ); + } + + AppendTrianglesKCLp(draw,col,tab0,sizeof(*tab0),n_sides); + AppendTrianglesKCLp(draw,col,tab1+n_sides-1,-(int)sizeof(*tab1),n_sides); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint Add_ITEMBOX +( + struct kcl_t *draw, // pointer to valid KCL + const + kmp_gobj_entry_t *op, // object to draw + DbFlags_t flags, // file flags + const s16 *data, // valid pointer to data + uint data_size, // size of data + bool detailed, // draw object detailed + bool as_road // draw as road +) +{ + DASSERT(draw); + DASSERT(op); + + float3 pos; + pos.x = op->position[0]; + pos.y = op->position[1] + 140.0; + pos.z = op->position[2]; + + float3 rot; + rot.x = 45.000; + rot.y = 0.000; + rot.z = 35.264; + + cuboid_t cub; + CreateCubeF(&cub,240.0,rot.v,pos.v); + + const u32 col = op->setting[1] + ? KCL_FLAG_ITEMBOX_PLAYER + : op->setting[2] + ? KCL_FLAG_ITEMBOX_ENEMY + : KCL_FLAG_ITEMBOX; + AppendCuboidKCL(draw,col,&cub); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint Add_COIN +( + struct kcl_t *draw, // pointer to valid KCL + const + kmp_gobj_entry_t *op, // object to draw + DbFlags_t flags, // file flags + const s16 *data, // valid pointer to data + uint data_size, // size of data + bool detailed, // draw object detailed + bool as_road // draw as road +) +{ + DASSERT(draw); + DASSERT(op); + + u32 col; + double size; + if ( op->setting[1] == M1(op->setting[1]) ) + { + col = KCL_FLAG_COIN_RESPAWN; + size = 150; + } + else if ( op->setting[1] < KMP_COIN_IS_INVALID ) + { + col = KCL_FLAG_COIN_START; + size = 220; + } + else + { + col = KCL_FLAG_COIN_INVALID; + size = 220; + } + + float3 pos; + pos.x = op->position[0]; + pos.y = op->position[1] + 150.0; + pos.z = op->position[2]; + + cuboid_t cub; + CreateCubeF(&cub,size,0,pos.v); + AppendCuboidKCL(draw,col,&cub); + + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint Add_KINOKO +( + struct kcl_t *dk, // pointer to valid KCL + const + kmp_gobj_entry_t *op, // object to draw + DbFlags_t flags, // file flags + const s16 *data, // valid pointer to data + uint data_size, // size of data + bool detailed, // draw object detailed + bool as_road // draw as road +) +{ + DASSERT(dk); + DASSERT(op); + + static const rot_shape_t shape[] = + { + { 0, 545 }, + { 760, 530 }, + { 1400, 420 }, + { 2050, 420 }, + { 2050, -50 }, + #ifdef TEST0 + { 100, -50 }, + { 100,-1000 }, + { 0,-1000 }, + { 0, -1 }, + { 2500, 500 }, + { 3000, 500 }, + { 3000, 0 }, + { 2500, 0 }, + #endif + }; + + const uint n_shp = sizeof(shape)/sizeof(*shape); + const uint n_seg = detailed ? 10 : 6; + const u32 col = as_road + ? OBJ_ROAD_COL + : op->obj_id == 0x1fa + ? KCL_FLAG_KINOKO_GREEN + : KCL_FLAG_KINOKO_RED; + + return DrawRotatedShape(dk,shape,n_shp,n_seg,op,flags,col); +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint Add_PYRAMID +( + struct kcl_t *draw, // pointer to valid KCL + const + kmp_gobj_entry_t *op, // object to draw + DbFlags_t flags, // file flags + const s16 *data, // valid pointer to data + uint data_size, // size of data + bool detailed, // draw object detailed + bool as_road // draw as road +) +{ + DASSERT(draw); + DASSERT(op); + DASSERT(data); + + // => color N height radius [raise] + + if ( data_size < 4 ) + return 0; + + u32 col = *data++ + N_KCL_FLAG; + uint n_side = *data++; + double ht = *data++; + double r = *data++; + const s16 *raise = data_size >= 4 ? data : 0; + + const uint max_side = 10; + if ( n_side > max_side ) + n_side = max_side; + + double3 pt[max_side+1]; // pt[0] is apex + pt[0].x = pt[0].z = 0.0; + pt[0].y = ht; + + const double rad_f = 2*M_PI / n_side; + double3 *p = pt + 1; + uint i; + for ( i = 0; i < n_side; i++, p++ ) + { + const double rad = i * rad_f; + p->x = cos(rad) * r; + p->y = 0.0; + p->z = sin(rad) * r; + } + + MatrixD_t mat; + SetupMatrixD(&mat,op,flags,raise); + TransformD3NMatrixD(&mat,pt,n_side+1,sizeof(*pt)); + + AppendPyramidKCL(draw,col,pt,pt+1,sizeof(*pt),n_side,true); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint Add_TREE +( + struct kcl_t *draw, // pointer to valid KCL + const + kmp_gobj_entry_t *op, // object to draw + DbFlags_t flags, // file flags + const s16 *data, // valid pointer to data + uint data_size, // size of data + bool detailed, // draw object detailed + bool as_road // draw as road +) +{ + DASSERT(draw); + DASSERT(op); + + // => trunk_wd trunk_dp trunk_ht crown_wd crown_dp crown_ht + // => data[0] data[1] data[2] data[3] data[4] data[5] + + if ( data_size < 6 ) + return 0; + + s16 d1[] = { KCL_FLAG_TREE_TRUNK - N_KCL_FLAG, + data[1] + data[2], data[0]/2, -data[1] }; + Add_CYLINDER_Y(draw,op,flags,d1,4,false,false); + + s16 d2[] = { KCL_FLAG_TREE_CROWN - N_KCL_FLAG, + 4, data[4] + data[5], data[3]/2, data[2] - data[4] }; + Add_PYRAMID(draw,op,flags,d2,5,false,false); + + return 1; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// AddObject*2KCL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void AddObject2KCL +( + DrawKCL_t * dk, // pointer to initalized object + const + kmp_gobj_entry_t * op // object to draw +) +{ + DASSERT(dk); + DASSERT(dk->draw); + DASSERT(op); + if ( !dk || !dk->draw || !op ) + return; + + uint draw_count = 0; + if ( op->obj_id < N_KMP_GOBJ ) + { + const ObjectInfo_t *oi = ObjectInfo + op->obj_id; + if ( oi->fname ) + { + int i; + for ( i = 0; i < sizeof(oi->group_idx)/sizeof(*oi->group_idx); i++ ) + { + uint gid = oi->group_idx[i]; + if ( gid >= N_DB_FILE_GROUP ) + break; + + const s16 *gp = DbFileRefGROUP + DbFileGROUP[gid].ref; + while ( *gp >= 0 ) + { + const DbFileFILE_t *f = DbFileFILE + *gp++; + if (f->draw_index) + { + const s16 *ptr = DbFileDraw + f->draw_index; + for(;;) + { + if ( *ptr < 2 ) + break; + + add_func func = 0; + switch(ptr[1]) + { + case DFD_RECTANGLE: func = Add_RECTANGLE; break; + case DFD_CUBE: func = Add_CUBE; break; + case DFD_CUBOID: func = Add_CUBOID; break; + case DFD_CYLINDER_Y: func = Add_CYLINDER_Y; break; + case DFD_CYLINDER_Z: func = Add_CYLINDER_Z; break; + case DFD_ITEMBOX: func = Add_ITEMBOX; break; + case DFD_KINOKO: func = Add_KINOKO; break; + case DFD_COIN: func = Add_COIN; break; + case DFD_PYRAMID: func = Add_PYRAMID; break; + case DFD_TREE: func = Add_TREE; break; + } + if (func) + draw_count += func( dk->draw, op, f->flags, ptr+2, *ptr-2, + dk->detailed, dk->as_road ); + ptr += *ptr; + } + } + } + } + } + } + + // fall back + + if (!draw_count) + { + const float radius = 150; + float3 pos; + pos.x = op->position[0]; + pos.y = op->position[1] + radius; + pos.z = op->position[2]; + + octahedron_t oct; + CreateRegularOctahedronF(&oct,radius,0,pos.v); + AppendOctahedronKCL(dk->draw,KCL_FLAG_SOLIDOBJ,&oct); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void AddObjectsById2KCL +( + DrawKCL_t * dk, // pointer to initalized object + u16 obj_id // object id to draw +) +{ + DASSERT(dk); + DASSERT(dk->draw); + if ( !dk || !dk->draw || !dk->kmp ) + return; + + uint n = dk->kmp->dlist[KMP_GOBJ].used; + const kmp_gobj_entry_t *op = (kmp_gobj_entry_t*)dk->kmp->dlist[KMP_GOBJ].list; + for ( ; n > 0; n--, op++ ) + if ( op->obj_id == obj_id ) + AddObject2KCL(dk,op); +} + +/////////////////////////////////////////////////////////////////////////////// + +void AddObjectsByFlag2KCL +( + DrawKCL_t * dk, // pointer to initalized object + u32 flag_mask, // mask the object flag with this ... + u32 flag_result // ... and draw it, if the result is this. +) +{ + DASSERT(dk); + DASSERT(dk->draw); + if ( !dk || !dk->draw || !dk->kmp ) + return; + + const draw_mode_t pflags = ( KMP_DRAW & DMD_M_PFLAGS ) >> DMD_SHIFT_PFLAGS; + + uint n = dk->kmp->dlist[KMP_GOBJ].used; + const kmp_gobj_entry_t *op = (kmp_gobj_entry_t*)dk->kmp->dlist[KMP_GOBJ].list; + for ( ; n > 0; n--, op++ ) + { + if ( op->obj_id < N_KMP_GOBJ && ( !pflags || pflags & op->pflags ) ) + { + const u32 flags = ObjectInfo[op->obj_id].flags; + if ( (flags & flag_mask) == flag_result ) + AddObject2KCL(dk,op); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void AddZeroGround2KCL +( + DrawKCL_t * dk, // pointer to initalized object + uint color // color of ground +) +{ + DASSERT(dk); + DASSERT(dk->draw); + if ( !dk || !dk->draw ) + return; + + const uint n_tri = dk->draw->tridata.used; + if (!n_tri) + return; + + uint i, n = 0; + double xmin = 0, xmax = 0, zmin = 0, zmax = 0; + const kcl_tridata_t *td = (kcl_tridata_t*)dk->draw->tridata.list; + + for ( i = 0; i < n_tri; i++, td++ ) + { + #if HAVE_PRINT0 + if ( td->cur_flag >= KCL_FLAG_TEST0 && td->cur_flag <= KCL_FLAG_TEST7 ) + printf("%6x: %04x %04x %7.1f\n", td->cur_flag, td->status, + td->status & (TD_REMOVED|TD_INVALID), td->pt[0].x ); + #endif + + if ( td->status & (TD_REMOVED|TD_INVALID) ) + continue; + + const double3 *pt = td->pt; + if (!n++) + { + xmin = xmax = pt[0].x; + zmin = zmax = pt[0].z; + } + + if ( xmin > pt[0].x ) xmin = pt[0].x; + if ( xmin > pt[1].x ) xmin = pt[1].x; + if ( xmin > pt[2].x ) xmin = pt[2].x; + + if ( xmax < pt[0].x ) xmax = pt[0].x; + if ( xmax < pt[1].x ) xmax = pt[1].x; + if ( xmax < pt[2].x ) xmax = pt[2].x; + + if ( zmin > pt[0].z ) zmin = pt[0].z; + if ( zmin > pt[1].z ) zmin = pt[1].z; + if ( zmin > pt[2].z ) zmin = pt[2].z; + + if ( zmax < pt[0].z ) zmax = pt[0].z; + if ( zmax < pt[1].z ) zmax = pt[1].z; + if ( zmax < pt[2].z ) zmax = pt[2].z; + } + + if (n) + { + PRINTF("xmax= %6.1f\n",xmax); + double3 pt1, pt2, pt3, pt4; + pt2.x = pt3.x = xmin - 1000; + pt1.x = pt4.x = xmax + 1000; + pt3.z = pt4.z = zmin - 1000; + pt1.z = pt2.z = zmax + 1000; + pt1.y = pt2.y = pt3.y = pt4.y = 0.0; + + AppendQuadrilateralKCLp(dk->draw,color,&pt1,&pt2,&pt3,&pt4); + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// pos file support /////////////// +/////////////////////////////////////////////////////////////////////////////// + +pos_param_t default_pos_param = {0}; +pos_file_t current_pos_param = {0}; +pos_file_t *first_pos_file = 0; + +static ParamField_t pos_autocolor = {0}; +static u32 pos_colors[] = +{ + KCL_FLAG_ORANGE, + KCL_FLAG_BLUE, + KCL_FLAG_GREEN, + KCL_FLAG_MAGENTA, + KCL_FLAG_YELLOW, + KCL_FLAG_RED, + KCL_FLAG_CYAN, + + KCL_FLAG_GOLD, + KCL_FLAG_SILVER, + KCL_FLAG_BRONZE, + + KCL_FLAG_WHITE, + KCL_FLAG_GREY, + KCL_FLAG_BROWN, + KCL_FLAG_BLACK, + + KCL_FLAG_ORANGE_YELLOW, + KCL_FLAG_BLUE_MAGENTA, + KCL_FLAG_GREEN_CYAN, + KCL_FLAG_MAGENTA_RED, + KCL_FLAG_YELLOW_GREEN, + KCL_FLAG_RED_ORANGE, + KCL_FLAG_CYAN_BLUE, +}; + +const uint n_pos_colors = sizeof(pos_colors)/sizeof(*pos_colors); + +/////////////////////////////////////////////////////////////////////////////// + +static void SetupPosMode() +{ + if (!default_pos_param.color) + { + memset(&default_pos_param,0,sizeof(default_pos_param)); + default_pos_param.color = KCL_FLAG_SILVER; + default_pos_param.idx_x = 8; + default_pos_param.idx_d = 16; + + memset(¤t_pos_param,0,sizeof(current_pos_param)); + current_pos_param.n_param = 1; + current_pos_param.param[0] = default_pos_param; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static void NormalizePosMode ( pos_file_t *pf ) +{ + DASSERT(pf); + + uint i; + pos_param_t *pp; + for ( i = 0, pp = pf->param; i < pf->n_param; i++, pp++ ) + { + if (!pp->idx_y) pp->idx_y = pp->idx_x + 1; + if (!pp->idx_z) pp->idx_z = pp->idx_y + 1; + if ( pp->transp > 0 ) + { + pp->color += pp->transp; + pp->transp = 0; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static void CopyPosMode() +{ + SetupPosMode(); + + pos_file_t *pf; + for ( pf = first_pos_file; pf; pf = pf->next ) + if (!pf->n_param) + { + ccp save_fname = pf->fname; + memcpy(pf,¤t_pos_param,sizeof(*pf)); + pf->fname = save_fname; + NormalizePosMode(pf); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptPosMode ( ccp arg ) +{ + if (!arg) + return 0; + + enum { SC_XPOS, SC_YPOS, SC_ZPOS, SC_DIR, SC_COLOR, SC_TRANSP, SC_FILTER }; + + static const KeywordTab_t keytab[] = + { + { SC_XPOS, "X", "XPOS", 0 }, + { SC_YPOS, "Y", "YPOS", 0 }, + { SC_ZPOS, "Z", "ZPOS", 0 }, + { SC_DIR, "D", "DIR", 0 }, + + { SC_COLOR, "C", "COLOR", 0 }, + { SC_TRANSP, "T", "TRANSPARENT", 0 }, + + { SC_FILTER, "FA", "FILTER-A", 0 }, + { SC_FILTER, "FB", "FILTER-B", 1 }, + { SC_FILTER, "FC", "FILTER-C", 2 }, + + {0,0,0,0} + }; + + SetupPosMode(); + pos_param_t *pp = current_pos_param.param; + + char skip_plus = '+'; + for(;;) + { + while ( *arg > 0 && *arg <= ' ' || *arg == ',' || *arg == skip_plus ) + arg++; + if (!*arg) + break; + + if ( *arg == '+' ) + { + if ( current_pos_param.n_param == MAX_POS_PARAM ) + return ERROR0(ERR_SYNTAX, + "Too many '+' terms for option --pos-mode: %s\n",arg); + memcpy(pp+1,pp,sizeof(*pp)); + pp++; + current_pos_param.n_param++; + skip_plus = '+'; + continue; + } + skip_plus = ' '; + + char name[50]; + uint i; + for ( i = 0; i < sizeof(name) - 1; i++ ) + { + char ch = toupper((int)(arg[i])); + if ( ch < 'A' || ch > 'Z' ) + break; + name[i] = ch; + } + if (!i) + return ERROR0(ERR_SYNTAX, + "Option --pos-mode: Missing sub command: %s\n",arg); + name[i] = 0; + //ccp subcmd = arg; + arg += i; + + int stat; + const KeywordTab_t *key = ScanKeyword(&stat,name,keytab); + if (!key) + { + int cstat; + const KeywordTab_t *ckey = ScanKeyword(&cstat,name,kcl_color_key_tab); + if (ckey) + { + pp->color = ckey->id; + pp->transp = ckey->opt & 1 ? 0 : -1; + goto next_parm; + } + if ( stat < 1 && cstat > 1 ) + return PrintKeywordError(kcl_color_key_tab,name,cstat,0, + "Color of --pos-mode:"); + return PrintKeywordError(keytab,name,stat,0, + "Sub command of --pos-mode:"); + } + + char *end = 0; + switch(key->id) + { + case SC_XPOS: pp->idx_x = str2ul(arg,&end,10); break; + case SC_YPOS: pp->idx_y = str2ul(arg,&end,10); break; + case SC_ZPOS: pp->idx_z = str2ul(arg,&end,10); break; + case SC_DIR: pp->idx_d = str2ul(arg,&end,10); break; + + case SC_COLOR: + { + const uint num = str2ul(arg,&end,10); + if ( num <= MAX_POS_FILE_INDEX ) + pp->autocolor = num; + } + break; + + case SC_TRANSP: + { + const uint num = str2ul(arg,&end,10); + if ( pp->transp >= 0 && num <= 2 ) + pp->transp = num; + } + break; + + case SC_FILTER: + { + uint idx = str2ul(arg,&end,10); + if ( (ccp)end > arg ) + { + if ( *end == '=' ) + end++; + arg = end; + pp->idx_f[key->opt] = idx; + while ( *arg && *arg != ',' && *arg != '+' ) + arg++; + StringCopySM( pp->filter[key->opt], sizeof(*pp->filter), + end, arg - end ); + end = 0; + PRINT("FILTER[%u.%llu]: %u = %s\n", + current_pos_param.n_param, key->opt, + pp->idx_f[key->opt], pp->filter[key->opt]); + } + } + break; + } + + if (end) + { + if ( arg == (ccp)end ) + return ERROR0(ERR_SYNTAX, + "Option --pos-mode: Missing parameter for '%s': %s\n", + key->name1,arg); + arg = end; + } + + next_parm: + while ( *arg > 0 && *arg <= ' ' ) + arg++; + if (!*arg) + break; + if ( *arg != ',' && *arg != '+' ) + return ERROR0(ERR_SYNTAX, + "Option --pos-mode: Comma or plus expected: %s\n",arg); + } + + #if HAVE_PRINT0 + { + pos_param_t *pp = current_pos_param.param; + PRINT(" - FA %u = %s\n",pp->idx_f[0],pp->filter[0]); + PRINT(" - FB %u = %s\n",pp->idx_f[1],pp->filter[1]); + PRINT(" - FC %u = %s\n",pp->idx_f[2],pp->filter[2]); + } + #endif + CopyPosMode(); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptPosFile ( ccp arg ) +{ + if ( !arg || !*arg ) + return 0; + + //SetupPosMode(); + + pos_file_t *pf = MALLOC(sizeof(*pf)); + DASSERT(pf); + memcpy(pf,¤t_pos_param,sizeof(*pf)); + pf->fname = STRDUP(arg); + NormalizePosMode(pf); + + pf->next = first_pos_file; + first_pos_file = pf; + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +void DrawPosFiles ( DrawKCL_t *draw ) +{ + CopyPosMode(); + + pos_file_t *pf; + for ( pf = first_pos_file; pf; pf = pf->next ) + DrawPosFile(draw,pf); +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError DrawPosFile ( DrawKCL_t *draw, pos_file_t *pf ) +{ + DASSERT(draw); + + if ( !pf || !pf->fname || !*pf->fname ) + return ERR_NOTHING_TO_DO; + + SetupPosMode(); + + File_t F; + enumError err = OpenFile(&F,true,pf->fname,FM_STDIO,0,0); + if (err) + { + FreeString(pf->fname); + pf->fname = 0; + return err; + } + + PRINT("scan [N=%u] %s\n",n_param,pf->fname); + PRINT(" - FA %u = %s\n",pf->param->idx_f[0],pf->param->filter[0]); + PRINT(" - FB %u = %s\n",pf->param->idx_f[1],pf->param->filter[1]); + PRINT(" - FC %u = %s\n",pf->param->idx_f[2],pf->param->filter[2]); + + double3 pos[3]; + pos[0].x = pos[0].y = pos[0].z = 0.0; + double3 rot; + rot.x = rot.y = rot.z = 0.0; + + char buf[1000]; + ccp cols[MAX_POS_FILE_INDEX+1]; + cols[0] = buf; + + while (fgets(buf,sizeof(buf)-1,F.f)) + { + char *ptr = buf; + + int idx; + for ( idx = 1; idx <= MAX_POS_FILE_INDEX; ) + { + while ( *ptr == ' ' || *ptr == '\t' ) + ptr++; + if ( (uchar)*ptr < ' ' || *ptr == '#' ) + break; + + cols[idx++] = ptr; + while ( (uchar)*ptr > ' ' ) + ptr++; + if (!*ptr) + break; + *ptr++ = 0; + } + + uint i; + pos_param_t *pp; + for ( i = 0, pp = pf->param; i < pf->n_param; i++, pp++ ) + { + uint fi, ok = 1; + for ( fi = 0; fi < MAX_POS_FILTER; fi++ ) + { + const uint fidx = pp->idx_f[fi]; + if (!fidx) + continue; + if ( fidx >= idx || strcmp(pp->filter[fi],cols[fidx]) ) + { + ok = 0; + break; + } + } + if (!ok) + continue; + + if ( pp->idx_x < idx && pp->idx_y < idx && pp->idx_z < idx ) + { + pos[0].x = strtod(cols[pp->idx_x],0); + pos[0].y = strtod(cols[pp->idx_y],0); + pos[0].z = strtod(cols[pp->idx_z],0); + } + else + continue; + + if ( pp->idx_d && pp->idx_d < idx ) + rot.y = strtod(cols[pp->idx_d],0); + + //printf("%9.1f %8.1f %9.1f | %4.0f\n",pos[0].x,pos[0].y,pos[0].z,rot.y); + + pos[1].x = pos[0].x + 40; + pos[2].x = pos[0].x - 40; + pos[1].y = pos[2].y = pos[0].y; + pos[1].z = pos[2].z = pos[0].z - 120; + + u32 col = pp->color; + if ( pp->autocolor && pp->autocolor < idx && cols[pp->autocolor][0] ) + { + if (!pos_autocolor.used) + InitializeParamField(&pos_autocolor); + + bool old; + ParamFieldItem_t *it + = FindInsertParamField(&pos_autocolor,cols[pp->autocolor],false,&old); + if (it) + { + if (!old) + it->num = ( pos_autocolor.used -1 ) % n_pos_colors; + col = pos_colors[it->num]; + if ( pp->transp >= 0 ) + col += pp->transp; + } + } + + Rotate(pos,&rot,pos+1,sizeof(double3),2); + AppendTriangleKCLp(draw->draw,col,pos+0,pos+1,pos+2); + } + } + + CloseFile(&F,0); + return ERR_OK; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// END /////////////// +/////////////////////////////////////////////////////////////////////////////// + |
