THREED.C

[目次 | 関数 | マクロ]

目次

関数一覧

マクロ一覧


   1|/***********************************************************************
   2|*  1. <<< 浮動小数版・三次元グラフィック関連 [ThreeD] >>> 
   3|*
   4|* 
   5|*
   6|*・「視線」は、視点から物体への半直線(片方が無限遠)です。
   7|*・「三次元ワールド座標」は、三次元モデルの世界の座標です。
   8|*・「視点座標」は、視点の位置を原点(0,0)とする座標です。
   9|*・「二次元ワールド座標」は、視点座標の x,y を透視変換した座標です。
  10|*  z は、視点座標と同じです。視線上にあるモデルは (0,0) になります。
  11|*・三次元ワールド座標から視点座標の変換を、一般に「三次元座標変換」と呼びます。
  12|*・視点座標から二次元ワールド座標の変換を、一般に「透視変換」といい、これに
  13|*  よって、遠近法が表現されます。
  14|************************************************************************/
  15|#define  STDLIBS_INCLUDE
  16|#define  STDLIBS_INCLUDE_STDIO_H
  17|#define  STDLIBS_INCLUDE_LIMITS_H
  18|#define  STDLIBS_INCLUDE_MATH_H
  19|#ifdef  USES_MXP_AUTOINC
  20| #define  MATH_NAMESPC_PREFIX  0
  21| #include "threed.ah"  /* Auto include header, Look at mixer-... folder */
  22|#else
  23| #include  <all.h>
  24|#endif
  25|
  26|
  27| 
  28|/***********************************************************************
  29|*  2. <<< まるめ端数 >>> 
  30|************************************************************************/
  31|double  ThreeD_err = 0.001;
  32|
  33|
  34| 
  35|/*-----------------------------------------------------------------------*/
  36|/*  3. <<< ◆三次元の座標値(double型) (ThreeD_XYZ) >>>                                */ 
  37|/*-----------------------------------------------------------------------*/
  38|
  39|
  40| 
  41|/***********************************************************************
  42|*  4. <<< [ThreeD_XYZ_init] 初期化する >>> 
  43|************************************************************************/
  44|void  ThreeD_XYZ_init( ThreeD_XYZ* m, double x, double y, double z )
  45|{
  46|  m->x = x;
  47|  m->y = y;
  48|  m->z = z;
  49|}
  50|
  51|
  52| 
  53|/* #ifdef  USES_THREED_VIEWL */
  54|/***********************************************************************
  55|*  5. <<< [ThreeD_XYZ_get2D] 二次元ワールド座標へ変換する ★>>> 
  56|*【引数】
  57|*  ・ThreeD_XYZ*   m; ある点の三次元ワールド座標値(入力)
  58|*  ・ThreeD_ViewL* view; 視線
  59|*  ・ThreeD_XYZ*   out;  ある点を二次元ワールド座標に変換した値(出力)
  60|*【補足】
  61|*・m と out が同じアドレスでも構いません。
  62|*・透視変換は、以下のように改良しています。
  63|*  
  64|*・仮想視点は、仮想ユーザ(画面の中にいる仮の人)の視点です。
  65|*・ユーザ視点は、ユーザ(画面を見ている人)の視点です。
  66|*・もし遠近の歪みがひどい場合、視点を遠く( diffU を大きく)すること。
  67|************************************************************************/
  68|void  ThreeD_XYZ_get2D( ThreeD_XYZ* m, ThreeD_ViewL* view, ThreeD_XYZ* out )
  69|{
  70|  ThreeD_XYZ  p;
  71|
  72|  p = *m;
  73|
  74|  /* 三次元座標変換(三次元ワールド座標 p を視点座標 out に変換する) */
  75|  /* 投影変換とも言う*/
  76|  {
  77|    /* 視点が原点になるように平行移動変換する */
  78|    p.x -= view->p.x;
  79|    p.y -= view->p.y;
  80|    p.z -= view->p.z;
  81|
  82|    /* p を視線の方向に回転変換する */
  83|    ThreeD_XYZ_rotR( &p, &view->dir, &p );
  84|
  85|    /* x,y,z の関係を合わせる */
  86|    out->x = -p.y;  out->y = -p.z;  out->z = p.x;
  87|  }
  88|
  89|  /* 透視変換(遠近法、視点座標を二次元ワールド座標に変換する) */
  90|  /*(比率を定数にして、乗算をシフト演算にすれば高速にできる) */
  91|  if ( out->z > ThreeD_err || out->z < -ThreeD_err ) {
  92|    out->x = out->x * view->diffU / (out->z + view->diffV + view->diffU);
  93|    out->y = out->y * view->diffU / (out->z + view->diffV + view->diffU);
  94|  }
  95|  else {
  96|    #ifndef  NDEBUG
  97|      error();
  98|    #endif
  99|    out->x = 0.0;
 100|    out->y = 0.0;
 101|  }
 102|}
 103|/* #endif  USES_THREED_VIEWL */
 104|
 105|
 106| 
 107|/* #ifdef  USES_THREED_VIEWL */
 108|/*************************************************************************
 109|*  6. <<< [ThreeD_XYZ_get3D] 三次元ワールド座標へ変換する >>> 
 110|*【機能】
 111|*・二次元ワールド座標から三次元ワールド座標に変換します。
 112|*【補足】
 113|*・この関数とは別に、スクリーン座標から二次元ワールド座標に変換(または
 114|*  オフセットを修正)する必要があります。
 115|*【内部補足】
 116|*・実装は、ThreeD_XYZ_get2D 関数とまったく逆の手順をしています。
 117|**************************************************************************/
 118|void  ThreeD_XYZ_get3D( ThreeD_XYZ* m, ThreeD_ViewL* view, ThreeD_XYZ* out )
 119|{
 120|  ThreeD_XYZ  p;
 121|
 122|  #ifdef _CHECKER
 123|    if ( view->diffU == 0 )  error();
 124|  #endif
 125|
 126|  /* 透視変換の逆(遠近法、二次元ワールド座標を視点座標に変換する) */
 127|  p.x = m->x * (m->z + view->diffV + view->diffU) / view->diffU;
 128|  p.y = m->y * (m->z + view->diffV + view->diffU) / view->diffU;
 129|  p.z = m->z;
 130|
 131|  /* 三次元座標変換の逆(視点座標 p を三次元ワールド座標 out に変換する) */
 132|  {
 133|    /* x,y,z の関係を合わせる */
 134|    out->x = p.z;  out->y = -p.x;  out->z = -p.y;
 135|
 136|    /* p を視線の方向に逆回転変換する */
 137|    ThreeD_XYZ_rot( out, &view->dir, out );
 138|
 139|    /* 視点が原点になっているので平行移動変換する */
 140|    out->x += view->p.x;
 141|    out->y += view->p.y;
 142|    out->z += view->p.z;
 143|  }
 144|}
 145|/* #endif  USES_THREED_VIEWL */
 146|
 147|
 148| 
 149|/* #ifdef  USES_THREED_DIR */
 150|/***********************************************************************
 151|*  7. <<< [ThreeD_XYZ_move] 指定された方向を基準に平行移動する >>> 
 152|*【機能】
 153|*・方向 dir を基準に、座標値 m を前後上下左右に move だけ平行移動して
 154|*  out に格納します。
 155|*【補足】
 156|*・move は、視点座標で指定します。
 157|*・m == out でも構いません。
 158|************************************************************************/
 159|void  ThreeD_XYZ_move( ThreeD_XYZ* m, ThreeD_XYZ* move,
 160|  ThreeD_Dir* dir, ThreeD_XYZ* out )
 161|{
 162|  ThreeD_XYZ  move2;  /* 平行移動量 */
 163|
 164|  /* 三次元座標変換(視点座標 move を三次元ワールド座標 move2 に変換する) */
 165|  {
 166|    /* x,y,z の関係を合わせる */
 167|    move2.x = move->z;  move2.y = -move->x;  move2.z = -move->y;
 168|
 169|    /* p を視線の方向に回転変換する */
 170|    ThreeD_XYZ_rot( &move2, dir, &move2 );
 171|  }
 172|
 173|  /* 平行移動する */
 174|  out->x = m->x + move2.x;
 175|  out->y = m->y + move2.y;
 176|  out->z = m->z + move2.z;
 177|}
 178|/* #endif  USES_THREED_DIR */
 179|
 180|
 181| 
 182|/* #ifdef  USES_THREED_DIR */
 183|/***********************************************************************
 184|*  8. <<< [ThreeD_XYZ_rot] 原点を中心に回転する >>> 
 185|*【機能】
 186|*・方向 dir の角度成分だけ、座標値 m を回転させ out に格納します。
 187|*【補足】
 188|*・m == out でも構いません。
 189|************************************************************************/
 190|void  ThreeD_XYZ_rot( ThreeD_XYZ* m, ThreeD_Dir* dir, ThreeD_XYZ* out )
 191|{
 192|  double  x1,y1,z1;
 193|  double  x2,y2,z2;
 194|  double  x3,y3,z3;
 195|  double  x4,y4,z4;
 196|
 197|  x1 = m->x;  y1 = m->y;  z1 = m->z;
 198|
 199|  /* 角度 α(視線軸反時計周り) だけ座標値を回転する */
 200|  x2 = x1;
 201|  y2 = y1 * dir->cos_af - z1 * dir->sin_af;
 202|  z2 = y1 * dir->sin_af + z1 * dir->cos_af;
 203|
 204|  /* 角度 φ(xy→z) だけ座標値を回転する */
 205|  x3 = x2 * dir->cos_fy - z2 * dir->sin_fy;
 206|  y3 = y2;
 207|  z3 = x2 * dir->sin_fy + z2 * dir->cos_fy;
 208|
 209|  /* 角度 θ(x→y) だけ座標値を回転する */
 210|  x4 = x3 * dir->cos_th - y3 * dir->sin_th;
 211|  y4 = x3 * dir->sin_th + y3 * dir->cos_th;
 212|  z4 = z3;
 213|
 214|  out->x = x4;  out->y = y4;  out->z = z4;
 215|}
 216|/* #ifdef  USES_THREED_DIR */
 217|
 218|
 219| 
 220|/* #ifdef  USES_THREED_DIR */
 221|/***********************************************************************
 222|*  9. <<< [ThreeD_XYZ_rotR] 原点を中心に逆回転(座標変換)する >>> 
 223|*【機能】
 224|*・方向 dir の角度成分だけ、座標値 m を逆回転させ out に格納します。
 225|*・または、dir 方向の座標に回転変換して out に格納します。
 226|*【補足】
 227|*・m == out でも構いません。
 228|*【内部補足】
 229|*・座標値をθ回転させる行列は次のようになります。
 230|*  X = x*cosθ - y*sinθ
 231|*  Y = x*sinθ + y*cosθ
 232|*・座標変換するときは、座標値を逆回転させます。
 233|*  ただし、cos-θ = cosθ, sin-θ = -sinθ
 234|************************************************************************/
 235|void  ThreeD_XYZ_rotR( ThreeD_XYZ* m, ThreeD_Dir* dir, ThreeD_XYZ* out )
 236|{
 237|  double  x1,y1,z1;
 238|  double  x2,y2,z2;
 239|  double  x3,y3,z3;
 240|  double  x4,y4,z4;
 241|
 242|  x1 = m->x;  y1 = m->y;  z1 = m->z;
 243|
 244|  /* 角度 θ(x→y) だけ回転するように座標変換する */
 245|  x2 =  x1 * dir->cos_th + y1 * dir->sin_th;
 246|  y2 = -x1 * dir->sin_th + y1 * dir->cos_th;
 247|  z2 =  z1;
 248|
 249|  /* 角度 φ(xy→z) だけ回転するように座標変換する */
 250|  x3 =  x2 * dir->cos_fy + z2 * dir->sin_fy;
 251|  y3 =  y2;
 252|  z3 = -x2 * dir->sin_fy + z2 * dir->cos_fy;
 253|
 254|  /* 角度 α(視線軸反時計周り) だけ回転するように座標変換する */
 255|  x4 =  x3;
 256|  y4 =  y3 * dir->cos_af + z3 * dir->sin_af;
 257|  z4 = -y3 * dir->sin_af + z3 * dir->cos_af;
 258|
 259|  out->x = x4;  out->y = y4;  out->z = z4;
 260|}
 261|/* #ifdef  USES_THREED_DIR */
 262|
 263|
 264| 
 265|/***********************************************************************
 266|*  10. <<< [ThreeD_XYZ_rotDir] 任意軸を中心に点を回転する >>> 
 267|*【引数】
 268|*  ・ThreeD_XYZ*  in;        回転前の点の座標
 269|*  ・ThreeD_XYZ*  axis_xyz;  回転軸上の任意の点の座標
 270|*  ・ThreeD_Dir*  axis_dir;  回転軸の方向と回転角度
 271|*  ・ThreeD_XYZ*  out;       回転後の点の座標を格納するアドレス
 272|*【内部補足】
 273|*・座標値をθ回転させる行列は次のようになります。
 274|*  X = x*cosθ - y*sinθ
 275|*  Y = x*sinθ + y*cosθ
 276|*・変換行列を用いれば、キャッシュが効くと考えられます。(未対応)
 277|************************************************************************/
 278|#if 0
 279|void  ThreeD_XYZ_rotDir( ThreeD_XYZ* in, ThreeD_XYZ* axis_xyz,
 280|  ThreeD_Dir* axis_dir, ThreeD_XYZ* out )
 281|{
 282|  ThreeD_XYZ  p1, p2;
 283|
 284|  /* 回転軸を Z軸に合わせる */
 285|  /* in := { in, axis_xyz }, out := { p1->x, p2->y, p2->z } */
 286|  {
 287|    /* axiz_xyz が原点になるように平行移動する */
 288|    p1->x = in->x - axis->x;
 289|    p1->y = in->y - axis->y;
 290|    p1->z = in->z - axis->z;
 291|
 292|    /* Z 軸 -θ回転する */
 293|    p2->x =   p1->x * axis_dir->cos_th + p1->y * axis_dir->sin_th;
 294|    p2->y = - p1->x * axis_dir->sin_th + p1->y * axis_dir->cos_th;
 295|
 296|    /* Y 軸 90度−φ回転する */
 297|    /* sin(90-f)==cos(f), cos(90-f)==sin(f) */
 298|    p1->x = p2->x * axis_dir->sin_fy - p1->z * axis_dir->cos_fy;
 299|    p2->z = p2->x * axis_dir->cos_fy + p1->z * axis_dir->sin_fy;
 300|  }
 301|
 302|  /* -α回転する(Z 軸) */
 303|  p2->x =   p1->x * axis_dir->cos_af + p2->y * axis_dir->sin_af;
 304|  p1->y = - p1->x * axis_dir->sin_af + p2->y * axis_dir->cos_af;
 305|
 306|  /* 回転軸を戻す */
 307|  /* in := { p2->x, p1->y, p2->z }, out := { out } */
 308|  {
 309|    /* Y 軸 φ−90度回転する */
 310|    /* sin(f-90)== -cos(f), cos(f-90)==sin(f) */
 311|    p1->x =   p2->x * axis_dir->sin_fy + p2->z * axis_dir->cos_fy;
 312|    p1->z = - p2->x * axis_dir->cos_fy + p2->z * axis_dir->sin_fy;
 313|
 314|    /* Z 軸 θ回転する */
 315|    p2->x = p1->x * axis_dir->cos_th - p1->y * axis_dir->sin_th;
 316|    p2->y = p1->x * axis_dir->sin_th + p1->y * axis_dir->cos_th;
 317|
 318|    /* 原点が axiz_xyz になるように平行移動する */
 319|    out->x = p2->x + axis->x;
 320|    out->y = p2->y + axis->y;
 321|    out->z = p1->z + axis->z;
 322|  }
 323|}
 324|#endif
 325|
 326|
 327| 
 328|/***********************************************************************
 329|*  11. <<< [ThreeD_XYZ_getDistance] 2点の距離を返す >>> 
 330|************************************************************************/
 331|double  ThreeD_XYZ_getDistance( ThreeD_XYZ* a, ThreeD_XYZ* b )
 332|{
 333|  double  dx = a->x - b->x;
 334|  double  dy = a->y - b->y;
 335|  double  dz = a->z - b->z;
 336|
 337|  return  sqrt( dx*dx + dy*dy + dz*dz );
 338|}
 339|
 340|
 341| 
 342|/***********************************************************************
 343|*  12. <<< [ThreeD_XYZ_getZCross] 2点からなる直線と Z=z の面との交点を取得する >>> 
 344|*【機能】
 345|*・点 p1 と点 p2 からなる直線と Z=z の面の交点を p に格納します。
 346|************************************************************************/
 347|void  ThreeD_XYZ_getZCross( ThreeD_XYZ* p1, ThreeD_XYZ* p2,
 348|  double z, ThreeD_XYZ* p )
 349|{
 350|  p->x = p1->x + (p2->x - p1->x) * (z - p1->z) / (p2->z - p1->z);
 351|  p->y = p1->y + (p2->y - p1->y) * (z - p1->z) / (p2->z - p1->z);
 352|  p->z = z;
 353|}
 354|
 355|
 356| 
 357|/*************************************************************************
 358|*  13. <<< [ThreeD_XYZ_getSurfDistanceL] 点から平面までの直線上の長さを求める >>> 
 359|*【引数】
 360|*  ・ThreeD_Line*  line;  直線(長さを測るところ)
 361|*  ・double  返り値;      点から平面までの直線上の長さ
 362|*【補足】
 363|*  
 364|**************************************************************************/
 365|double  ThreeD_XYZ_getSurfDistanceL( ThreeD_XYZ* p, ThreeD_Surf* surf,
 366|  ThreeD_Line* line )
 367|{
 368|  double  w;
 369|
 370|  w = surf->a * line->xcos + surf->b * line->ycos + surf->c * line->zcos;
 371|  if ( w == 0.0 )  w = 0.001;
 372|  return -(surf->a * p->x + surf->b * p->y + surf->c * p->z + surf->d) / w;
 373|}
 374|
 375|
 376| 
 377|#ifdef USES_TWOD
 378|/*************************************************************************
 379|*  14. <<< [ThreeD_XYZ_isInPoly] 点がポリゴンの内部にあるかどうか判定する >>> 
 380|*【引数】
 381|*  ・TwoD_XY*  poly2_xy;      ワーク領域。ポリゴンの頂点数だけ格納できる配列
 382|*  ・size_t  poly2_xy_sizeof;     xy_work のメモリサイズ
 383|**************************************************************************/
 384|bool  ThreeD_XYZ_isInPoly( ThreeD_XYZ* p, ThreeD_Poly* poly,
 385|  TwoD_XY* poly2_xy, size_t poly2_xy_sizeof )
 386|{
 387|  ThreeD_TwoD  f;
 388|  TwoD_Poly    poly2;
 389|  TwoD_XY      p2;
 390|
 391|  #ifdef _CHECKER
 392|    if ( poly2_xy_sizeof / sizeof( TwoD_XY ) < (unsigned)poly->n )  error();
 393|  #endif
 394|
 395|  ThreeD_TwoD_initByPoly( &f, poly );
 396|  TwoD_Poly_initByThreeD2( &poly2, poly2_xy, poly2_xy_sizeof, &f, poly );
 397|  TwoD_XY_initBy3D( &p2, &f, p );
 398|
 399|  return  TwoD_XY_isInPoly( &p2, &poly2 );  /*★*/
 400|}
 401|#endif /* USES_TWOD */
 402|
 403|
 404| 
 405|/***********************************************************************
 406|*  15. <<< [ThreeD_XYZ_print] 属性を表示する >>> 
 407|************************************************************************/
 408|#ifndef  ERRORS_CUT_DEBUG_TOOL
 409|void  ThreeD_XYZ_print( ThreeD_XYZ* m, const char* title )
 410|{
 411|  Errors_printf( "%s:ThreeD_XYZ(%p): (%lf, %lf, %lf)", title, m,
 412|    m->x, m->y, m->z );
 413|}
 414|#endif
 415|
 416|
 417| 
 418|/*-----------------------------------------------------------------------*/
 419|/*  16. <<< ◆三次元の座標値(float型) (ThreeD_XYZ2) >>>                                */ 
 420|/*-----------------------------------------------------------------------*/
 421|
 422|
 423| 
 424|/***********************************************************************
 425|*  17. <<< [ThreeD_XYZ2_getDistance] 2点の距離を返す >>> 
 426|************************************************************************/
 427|float  ThreeD_XYZ2_getDistance( ThreeD_XYZ2* a, ThreeD_XYZ2* b )
 428|{
 429|  double  dx = (double)a->x - b->x;
 430|  double  dy = (double)a->y - b->y;
 431|  double  dz = (double)a->z - b->z;
 432|
 433|  return  (float)sqrt( dx*dx + dy*dy + dz*dz );
 434|}
 435|
 436|
 437| 
 438|/***********************************************************************
 439|*  18. <<< [ThreeD_XYZ2_print] 属性を表示する >>> 
 440|************************************************************************/
 441|#ifndef  ERRORS_CUT_DEBUG_TOOL
 442|void  ThreeD_XYZ2_print( ThreeD_XYZ2* m, const char* title )
 443|{
 444|  Errors_printf( "%s:ThreeD_XYZ2(%p):(%f, %f, %f)",
 445|    title, m, m->x, m->y, m->z );
 446|}
 447|#endif
 448|
 449|
 450| 
 451|/*-----------------------------------------------------------------------*/
 452|/*  19. <<< ◆方向, 角度 (ThreeD_Dir) >>>                                    */ 
 453|/*-----------------------------------------------------------------------*/
 454|
 455|
 456| 
 457|/***********************************************************************
 458|*  20. <<< [ThreeD_Dir_initDef] デフォルトで初期化する >>> 
 459|*【機能】
 460|*・X 軸方向に設定します。
 461|************************************************************************/
 462|void  ThreeD_Dir_initDef( ThreeD_Dir* m )
 463|{
 464|  m->th = 0.0;
 465|  m->fy = 0.0;
 466|  m->af = 0.0;
 467|
 468|  m->sin_th = 0.0;
 469|  m->cos_th = 1.0;
 470|  m->sin_fy = 0.0;
 471|  m->cos_fy = 1.0;
 472|  m->sin_af = 0.0;
 473|  m->cos_af = 1.0;
 474|}
 475|
 476|
 477| 
 478|/***********************************************************************
 479|*  21. <<< [ThreeD_Dir_init] 初期化する(角度指定)>>> 
 480|*【補足】
 481|*・引数は、ラジアン(〜0〜2π〜)です。
 482|************************************************************************/
 483|void  ThreeD_Dir_init( ThreeD_Dir* m, double th, double fy, double af )
 484|{
 485|  m->th = th;
 486|  m->fy = fy;
 487|  m->af = af;
 488|
 489|  m->sin_th = sin(th);
 490|  m->cos_th = cos(th);
 491|  m->sin_fy = sin(fy);
 492|  m->cos_fy = cos(fy);
 493|  m->sin_af = sin(af);
 494|  m->cos_af = cos(af);
 495|}
 496|
 497|
 498| 
 499|/***********************************************************************
 500|*  22. <<< [ThreeD_Dir_init2] 初期化する(ベクトル成分指定)>>> 
 501|*【補足】
 502|*・引数 af は、ラジアン(〜0〜2π〜)です。
 503|************************************************************************/
 504|void  ThreeD_Dir_init2( ThreeD_Dir* m, double dx, double dy,
 505|  double dz, double af )
 506|{
 507|#if 0
 508|  double  a;
 509|
 510|  a = dy / dx; ???
 511|  m->th = asin(a);
 512|  m->sin_th = a;
 513|  m->cos_th = dy/dx; ???
 514|
 515|  a = dy / dx; ???
 516|  m->fy = ;
 517|  m->sin_fy = sin(fy);
 518|  m->cos_fy = cos(fy);
 519|  m->sin_af = sin(af);
 520|  m->cos_af = cos(af);
 521|
 522|  m->af = af;
 523|#endif
 524|Errors_notSupport();
 525|m, dx, dy, dz, af;
 526|}
 527|
 528|
 529| 
 530|/***********************************************************************
 531|*  23. <<< [ThreeD_Dir_print] 方向の成分を表示する>>> 
 532|************************************************************************/
 533|#ifndef  ERRORS_CUT_DEBUG_TOOL
 534|void  ThreeD_Dir_print( ThreeD_Dir* m, const char* title )
 535|{
 536|  Errors_printf( "%s:ThreeD_Dir(%p):(%f,%f,%f:radian)(%f,%f,%f:degree)",
 537|    title, m,
 538|    m->th, m->fy, m->af,
 539|    m->th * 180 / 3.14, m->fy * 180 / 3.14, m->af * 180 / 3.14 );
 540|
 541|  Errors_printf( "%s:  (%f,%f,%f:sin)(%f,%f,%f:cos)",
 542|    title,
 543|    m->sin_th, m->sin_fy, m->sin_af,
 544|    m->cos_th, m->cos_fy, m->cos_af );
 545|}
 546|#endif
 547|
 548|
 549| 
 550|/*-----------------------------------------------------------------------*/
 551|/*  24. <<< ◆三次元ベクトル (ThreeD_Vect) >>>                               */ 
 552|/*-----------------------------------------------------------------------*/
 553|
 554|
 555| 
 556|/*************************************************************************
 557|*  25. <<< [ThreeD_Vect_chgToUnit] 単位ベクトルにする >>> 
 558|**************************************************************************/
 559|void  ThreeD_Vect_chgToUnit( ThreeD_Vect* m )
 560|{
 561|  double  len = ThreeD_Vect_getLen( m );
 562|  m->x /= len;  m->y /= len;  m->z /= len;
 563|}
 564|
 565|
 566| 
 567|/*************************************************************************
 568|*  26. <<< [ThreeD_Vect_getLen] ベクトルの長さ(|A|)>>> 
 569|**************************************************************************/
 570|double  ThreeD_Vect_getLen( ThreeD_Vect* a )
 571|{
 572|  #if ERRORS_DEBUG_FALSE
 573|    Errors_printf( "--- ThreeD_Vect_getLen" );
 574|    ThreeD_Vect_print( a, "" );
 575|    Errors_printf( "len^2 = %f", a->x * a->x + a->y * a->y + a->z * a->z );
 576|    Errors_printf( "sqrt = %f", sqrt( a->x * a->x + a->y * a->y + a->z * a->z ) );
 577|  #endif
 578|
 579|  return  sqrt( a->x * a->x + a->y * a->y + a->z * a->z );
 580|}
 581|
 582|
 583| 
 584|/*************************************************************************
 585|*  27. <<< [ThreeD_Vect_getDirVect] ベクトルの方向成分のベクトルを取得する >>> 
 586|*【機能】
 587|*・ベクトル in の dir 方向成分を out に格納します。
 588|*【補足】
 589|*・dir は、単位ベクトルを指定してください。
 590|**************************************************************************/
 591|void  ThreeD_Vect_getDirVect( ThreeD_Vect* in, ThreeD_Vect* dir,
 592|  ThreeD_Vect* out )
 593|{
 594|  double  dir_len;
 595|
 596|  #ifdef _CHECKER
 597|    if ( !MathX_equal( ThreeD_Vect_getLen( dir ), 1.0, 0.001) )  error();
 598|  #endif
 599|
 600|  dir_len = ThreeD_Vect_getDirLen( in, dir );
 601|  out->x = dir_len * dir->x;
 602|  out->y = dir_len * dir->y;
 603|  out->z = dir_len * dir->z;
 604|}
 605|
 606|
 607| 
 608|/*************************************************************************
 609|*  28. <<< [ThreeD_Vect_getDirLen] ベクトルの方向成分の長さを取得する >>> 
 610|*【補足】
 611|*・dir には、単位ベクトルを指定してください。
 612|*・_CHECKER マクロが定義されていないと、マクロになります
 613|**************************************************************************/
 614|#ifdef _CHECKER
 615|double  ThreeD_Vect_getDirLen( ThreeD_Vect* a, ThreeD_Vect* dir )
 616|{
 617|  #ifdef _CHECKER
 618|    if ( !MathX_equal( ThreeD_Vect_getLen( dir ), 1.0, 0.001) )  error();
 619|  #endif
 620|
 621|  return  a->x * dir->x + a->y * dir->y + a->z * dir->z;
 622|}
 623|#endif
 624|
 625|
 626| 
 627|/***********************************************************************	
 628|*  29. <<< [ThreeD_Vect_getCos] 2ベクトルのなす角度のcosを計算する >>> 
 629|*【引数】
 630|*  ・double  返り値;  2ベクトルのなす角度の cos
 631|*【内部補足】
 632|*・cosθ = (a・b)/(|a||b|) の公式から計算します。ただし、a,b はベクトル。
 633|************************************************************************/
 634|double  ThreeD_Vect_getCos( ThreeD_Vect* v1, ThreeD_Vect* v2 )
 635|{
 636|  ASSERT( ThreeD_Vect_getLen( v1 ) != 0.0 );
 637|  ASSERT( ThreeD_Vect_getLen( v2 ) != 0.0 );
 638|
 639|  return  ThreeD_Vect_getInnerProd( v1, v2 ) /
 640|           ( ThreeD_Vect_getLen( v1 ) * ThreeD_Vect_getLen( v2 ) );
 641|}
 642|
 643|
 644| 
 645|/*-------------------------------------------------------------------------*/
 646|/* 30. <<< ◆視線, 視点 (ThreeD_ViewL) ★>>>                                   */ 
 647|/*-------------------------------------------------------------------------*/
 648|
 649|
 650| 
 651|/***********************************************************************
 652|*  31. <<< [ThreeD_ViewL_initDef] デフォルトで初期化する >>> 
 653|************************************************************************/
 654|void  ThreeD_ViewL_initDef( ThreeD_ViewL* m )
 655|{
 656|  m->p.x = 0.0;
 657|  m->p.y = 0.0;
 658|  m->p.z = 0.0;
 659|  ThreeD_Dir_initDef( &m->dir );
 660|  m->diffV = 10.0;
 661|  m->diffV = 10.0;
 662|  m->diffU = 600.0;
 663|}
 664|
 665|
 666| 
 667|/***********************************************************************
 668|*  32. <<< [ThreeD_ViewL_init] 初期化する >>> 
 669|************************************************************************/
 670|void  ThreeD_ViewL_init( ThreeD_ViewL* m,
 671|  double x,  double y,  double z,
 672|  double th, double fy, double af,
 673|  double diffV, double diffC, double diffU )
 674|{
 675|  m->p.x = x;
 676|  m->p.y = y;
 677|  m->p.z = z;
 678|  ThreeD_Dir_init( &m->dir, th, fy, af );
 679|  m->diffV = diffV;
 680|  m->diffC = diffC;
 681|  m->diffU = diffU;
 682|}
 683|
 684|
 685| 
 686|/***********************************************************************
 687|*  33. <<< [ThreeD_ViewL_setXYZ] 視点の位置を設定する >>> 
 688|************************************************************************/
 689|void  ThreeD_ViewL_setXYZ( ThreeD_ViewL* m, double x, double y,
 690|  double z )
 691|{
 692|  ThreeD_XYZ_init( &m->p, x, y, z );
 693|}
 694|
 695| 
 696|/***********************************************************************
 697|*  34. <<< [ThreeD_ViewL_setDir] 視線の方向を設定する(角度指定)>>> 
 698|************************************************************************/
 699|void  ThreeD_ViewL_setDir( ThreeD_ViewL* m, double th, double fy,
 700|  double af )
 701|{
 702|  ThreeD_Dir_init( &m->dir, th, fy, af );
 703|}
 704|
 705| 
 706|/***********************************************************************
 707|*  35. <<< [ThreeD_ViewL_setDirAndMove] 視線の方向を設定する(角度&目標点指定)>>> 
 708|*【引数】
 709|*  ・double  th, fy, af;   角度
 710|*  ・double  tx, ty, tz;   目標点の座標
 711|*【補足】
 712|*・tx,ty,tz の点がスクリーンの中央に来るように視点を移動します。
 713|*  ↓次の図は無くしてしまいました (^^;
 714|*  
 715|************************************************************************/
 716|void  ThreeD_ViewL_setDirAndMove( ThreeD_ViewL* m,
 717|  double th, double fy,  double af,
 718|  double tx, double ty,  double tz )
 719|{
 720|#if 0
 721|  double  diff;
 722|  double  dx, dy, dz;
 723|
 724|  dx = tx - m->p.x;  dy = ty - m->p.y;  dz = tz - m->p.z;
 725|/*  diff = sqrt( dx*dx + dy*dy + dz*dz ); */
 726|
 727|/* 作成中 */
 728|#endif
 729|
 730|Errors_notSupport();
 731|m, th, fy, af, tx, ty, tz;
 732|}
 733| 
 734|/***********************************************************************
 735|*  36. <<< [ThreeD_ViewL_setTarget] 視線の方向を設定する(目標点指定) >>> 
 736|************************************************************************/
 737|void  ThreeD_ViewL_setTarget( ThreeD_ViewL* m, double x, double y,
 738|  double z, double af )
 739|{
 740|  ThreeD_Dir_init2( &m->dir,
 741|    x - m->p.x, y - m->p.y, z - m->p.z, af );
 742|}
 743|
 744| 
 745|/***********************************************************************
 746|*  37. <<< [ThreeD_ViewL_getUserViewP] ユーザ視点の座標を取得する >>> 
 747|************************************************************************/
 748|void  ThreeD_ViewL_getUserViewP( ThreeD_ViewL* m, ThreeD_XYZ* userViewP )
 749|{
 750|  ThreeD_XYZ  vect;
 751|
 752|  ThreeD_XYZ_init( &vect, 0, 0, -m->diffU );
 753|  ThreeD_XYZ_move( &m->p, &vect, &m->dir, userViewP );
 754|}
 755|
 756|
 757| 
 758|/***********************************************************************
 759|*  38. <<< [ThreeD_ViewL_move] 視点を移動する >>> 
 760|*【引数】
 761|*  ・double  dx,dy,dz;  移動量(視線方向をZ正方向とした差分値)
 762|************************************************************************/
 763|void  ThreeD_ViewL_move( ThreeD_ViewL* m,
 764|  double dx,  double dy,  double dz )
 765|{
 766|  ThreeD_XYZ  d;
 767|
 768|  d.x = dx;  d.y = dy;  d.z = dz;
 769|  ThreeD_XYZ_move( &m->p, &d, &m->dir, &m->p );
 770|}
 771|
 772|
 773| 
 774|/***********************************************************************
 775|*  39. <<< [ThreeD_ViewL_rot] 視線の角度を変える >>> 
 776|************************************************************************/
 777|void  ThreeD_ViewL_rot( ThreeD_ViewL* m,
 778|  double d_th,  double d_fy,  double d_af )
 779|{
 780|  ThreeD_Dir_init( &m->dir, m->dir.th + d_th,
 781|                   m->dir.fy + d_fy, m->dir.af + d_af );
 782|}
 783|
 784|
 785| 
 786|/***********************************************************************
 787|*  40. <<< [ThreeD_ViewL_initS] スクリーン位相で視線を指定して初期化する >>> 
 788|*【引数】
 789|*  ・double  ax;  スクリーン X軸方向の位相(Y軸回転)
 790|*  ・double  ay;  スクリーン Y軸方向の位相(X軸回転)
 791|************************************************************************/
 792|#if 0
 793|void  ThreeD_ViewL_initS( ThreeD_ViewL* m, double ax, double* fy2 )
 794|{
 795|}
 796|#endif
 797|
 798|
 799| 
 800|/**************************************************************************
 801|*  41. <<< [ThreeD_ViewL_print] パラメータを表示する >>> 
 802|***************************************************************************/
 803|#ifndef ERRORS_CUT_DEBUG_TOOL
 804|void  ThreeD_ViewL_print( ThreeD_ViewL* m, const char* title )
 805|{
 806|  Errors_printf( "%s:ThreeD_ViewL(%p):", title, m );
 807|  ThreeD_XYZ_print( &m->p, title );
 808|  ThreeD_Dir_print( &m->dir, title );
 809|  Errors_printf( "%s: diffV = %f, diffC = %f, diffU = %f",
 810|    title, m->diffV, m->diffC, m->diffU );
 811|}
 812|#endif
 813|
 814|
 815| 
 816|/*----------------------------------------------------------------------*/
 817|/*  42. <<< ◆直線 (ThreeD_Line) >>>                                        */ 
 818|/*----------------------------------------------------------------------*/
 819|
 820|
 821| 
 822|/*************************************************************************
 823|*  43. <<< [ThreeD_Line_init] 2点の座標から初期化する >>> 
 824|**************************************************************************/
 825|void  ThreeD_Line_init( ThreeD_Line* m, ThreeD_XYZ* p1, ThreeD_XYZ* p2 )
 826|{
 827|  double  dx = p2->x - p1->x;
 828|  double  dy = p2->y - p1->y;
 829|  double  dz = p2->z - p1->z;
 830|  double  dist = sqrt( dx*dx + dy*dy + dz*dz );
 831|
 832|  m->p1 = *p1;
 833|  m->xcos = dx / dist;
 834|  m->ycos = dy / dist;
 835|  m->zcos = dz / dist;
 836|}
 837|
 838|
 839| 
 840|/*----------------------------------------------------------------------*/
 841|/*  44. <<< ◆平面 (ThreeD_Surf) >>>                                        */ 
 842|/*----------------------------------------------------------------------*/
 843|
 844|
 845| 
 846|/**************************************************************************
 847|*  45. <<< [ThreeD_Surf_initByP3] 3点から平面を初期化する >>> 
 848|*【引数】
 849|*  ・ThreeD_XYZ  p[];    平面上にある3点の座標の配列の先頭アドレス
 850|*【補足】
 851|*・p の配列要素数は3です。
 852|*・3点の順番は、その3点からできる三角形を表から見て左回りに指定します。
 853|*・3点は1つの直線上に並ばないようにしてください。
 854|***************************************************************************/
 855|void  ThreeD_Surf_initByP3( ThreeD_Surf* m, ThreeD_XYZ p[] )
 856|{
 857|  double  w,w1,w2,w3;
 858|
 859|  w1 = p[0].y * (p[1].z - p[2].z)
 860|     + p[1].y * (p[2].z - p[0].z)
 861|     + p[2].y * (p[0].z - p[1].z);
 862|  w2 = p[0].z * (p[1].x - p[2].x)
 863|     + p[1].z * (p[2].x - p[0].x)
 864|     + p[2].z * (p[0].x - p[1].x);
 865|  w3 = p[0].x * (p[1].y - p[2].y)
 866|     + p[1].x * (p[2].y - p[0].y)
 867|     + p[2].x * (p[0].y - p[1].y);
 868|
 869|  w = w1*w1 + w2*w2 + w3*w3;
 870|  if ( w < ThreeD_err )  w = ThreeD_err;
 871|
 872|  w = sqrt( w );
 873|
 874|  m->a = w1/w;
 875|  m->b = w2/w;
 876|  m->c = w3/w;
 877|  m->d = - ( (m->a * p[0].x) + (m->b * p[0].y) +
 878|                (m->c * p[0].z) );
 879|}
 880|
 881|
 882| 
 883|/**************************************************************************
 884|*  46. <<< [ThreeD_Surf_initByP3_2] 3点から平面を初期化する >>> 
 885|*【引数】
 886|*  ・ThreeD_XYZ2  p[];    平面上にある3点の座標の配列の先頭アドレス
 887|*【補足】
 888|*・ThreeD_Surf_initByP3 との違いは、引数の型のみです。
 889|***************************************************************************/
 890|void  ThreeD_Surf_initByP3_2( ThreeD_Surf* m, ThreeD_XYZ2 p[] )
 891|{
 892|  float  w,w1,w2,w3;
 893|
 894|  w1 = p[0].y * (p[1].z - p[2].z)
 895|     + p[1].y * (p[2].z - p[0].z)
 896|     + p[2].y * (p[0].z - p[1].z);
 897|  w2 = p[0].z * (p[1].x - p[2].x)
 898|     + p[1].z * (p[2].x - p[0].x)
 899|     + p[2].z * (p[0].x - p[1].x);
 900|  w3 = p[0].x * (p[1].y - p[2].y)
 901|     + p[1].x * (p[2].y - p[0].y)
 902|     + p[2].x * (p[0].y - p[1].y);
 903|
 904|  w = w1*w1 + w2*w2 + w3*w3;
 905|  if ( w < (float)ThreeD_err )  w = (float)ThreeD_err;
 906|
 907|  w = (float)sqrt( w );
 908|
 909|  m->a = w1/w;
 910|  m->b = w2/w;
 911|  m->c = w3/w;
 912|  m->d = - ( (m->a * p[0].x) + (m->b * p[0].y) +
 913|                (m->c * p[0].z) );
 914|}
 915|
 916|
 917| 
 918|/**************************************************************************
 919|*  47. <<< [ThreeD_Surf_initByP3_3] 3点から平面を初期化する >>> 
 920|*【補足】
 921|*・ThreeD_Surf_initByP3 との違いは、引数の型のみです。
 922|***************************************************************************/
 923|void  ThreeD_Surf_initByP3_3( ThreeD_Surf* m,
 924|  double p0x, double p0y, double p0z,
 925|  double p1x, double p1y, double p1z,
 926|  double p2x, double p2y, double p2z )
 927|{
 928|  double  w,w1,w2,w3;
 929|
 930|  w1 = p0y * (p1z - p2z)
 931|     + p1y * (p2z - p0z)
 932|     + p2y * (p0z - p1z);
 933|  w2 = p0z * (p1x - p2x)
 934|     + p1z * (p2x - p0x)
 935|     + p2z * (p0x - p1x);
 936|  w3 = p0x * (p1y - p2y)
 937|     + p1x * (p2y - p0y)
 938|     + p2x * (p0y - p1y);
 939|
 940|  w = w1*w1 + w2*w2 + w3*w3;
 941|  if ( w < ThreeD_err )  w = ThreeD_err;
 942|
 943|  w = sqrt( w );
 944|
 945|  m->a = w1/w;
 946|  m->b = w2/w;
 947|  m->c = w3/w;
 948|  m->d = - ( (m->a * p0x) + (m->b * p0y) +
 949|                (m->c * p0z) );
 950|}
 951|
 952|
 953| 
 954|/**************************************************************************
 955|*  48. <<< [ThreeD_Surf_getZ] Z 軸に平行な直線と平面の交点を返す >>> 
 956|*【引数】
 957|*  ・double x,y;     Z 軸に平行な直線の (x,y) 座標
 958|*  ・double 返り値;  交点の Z 座標
 959|***************************************************************************/
 960|double  ThreeD_Surf_getZ( ThreeD_Surf* m, double x, double y )
 961|{
 962|  #ifdef _CHECKER
 963|    if ( m->c == 0.0 )  error();
 964|  #endif
 965|  return  -( m->a *x + m->b *y + m->d ) / m->c;
 966|}
 967|
 968|
 969| 
 970|/*************************************************************************
 971|*  49. <<< [ThreeD_Surf_getLineCross] 平面と直線の交点を求める >>> 
 972|*【引数】
 973|*  ・ThreeD_XYZ* out;    交点を格納するアドレス
 974|*【補足】
 975|*  
 976|**************************************************************************/
 977|void  ThreeD_Surf_getLineCross( ThreeD_Surf* surf, ThreeD_Line* line,
 978|  ThreeD_XYZ* out )
 979|{
 980|  double  dist = ThreeD_XYZ_getSurfDistanceL( &line->p1, surf, line );
 981|
 982|  out->x = line->xcos * dist + line->p1.x;
 983|  out->y = line->ycos * dist + line->p1.y;
 984|  out->z = line->zcos * dist + line->p1.z;
 985|}
 986|
 987|
 988| 
 989|/*************************************************************************
 990|*  50. <<< [ThreeD_Surf_cmpFront] 平面が表側かどうか判断する ★>>> 
 991|*【機能】
 992|*・ある視点 viewP から平面 m を見たとき、平面の表側かどうかを判断します。
 993|*【引数】
 994|*  ・ThreeD_XYZ* viewP;  視点座標
 995|*  ・int  返り値;         正の数 = 表、負の数 = 裏、0 = 平行
 996|*【補足】
 997|*・返り値が0の場合は、平面に viewP が含まれているため、表か裏か判断でき
 998|*  ない場合です。
 999|**************************************************************************/
1000|int  ThreeD_Surf_cmpFront( ThreeD_Surf* m, ThreeD_XYZ* viewP )
1001|{
1002|  return  (int)( (m->a * viewP->x) + (m->b * viewP->y) +
1003|                 (m->c * viewP->z) +  m->d );
1004|}
1005|
1006|
1007| 
1008|/**************************************************************************
1009|*  51. <<< [ThreeD_Surf_print] パラメータを表示する >>> 
1010|***************************************************************************/
1011|#ifndef ERRORS_CUT_DEBUG_TOOL
1012|void  ThreeD_Surf_print( ThreeD_Surf* m )
1013|{
1014|  Errors_printf( "%fx + %fy + %fz + %f = 0\n", m->a, m->b, m->c, m->d );
1015|}
1016|#endif
1017|
1018|
1019| 
1020|/*----------------------------------------------------------------------*/
1021|/*  52. <<< ◆ポリゴン (ThreeD_Poly) >>> 
1022|/*----------------------------------------------------------------------*/
1023|
1024|
1025| 
1026|/*************************************************************************
1027|*  53. <<< [ThreeD_Poly_init] ポリゴンを初期化する >>> 
1028|*【引数】
1029|*  (構造体を参照)
1030|**************************************************************************/
1031|void  ThreeD_Poly_init( ThreeD_Poly* m, ThreeD_XYZ* p_array, int n,
1032|  int color )
1033|{
1034|  m->p_array = p_array;
1035|  m->n = n;
1036|  ThreeD_Surf_initByP3( &m->surf, p_array );
1037|  m->color = color;
1038|}
1039|
1040|
1041| 
1042|/*************************************************************************
1043|*  54. <<< [ThreeD_Poly_initShadow] 影ポリゴンを初期化する ★>>> 
1044|*【機能】
1045|*・光源(点)light に対して、影付けポリゴン shadowing が、
1046|*  影映りポリゴン shadowed に映す、影ポリゴン m を初期化します。
1047|*  
1048|*【引数】
1049|*  ・ThreeD_Poly*  m;       影ポリゴン
1050|*  ・ThreeD_Poly*  shadowed;   影映りポリゴン
1051|*  ・ThreeD_Poly*  shadowing;  影付けポリゴン
1052|*  ・ThreeD_XYZ*   light;      光源(点)
1053|*  ・ThreeD_XYZ*   xyzs;       m の頂点を格納する領域の先頭アドレス
1054|*  ・size_t        xyzs_sizeof; xyzs のメモリサイズ
1055|*【補足】
1056|*・ポリゴンの影は複数のポリゴンに映るので、それぞれのポリゴンに映る
1057|*  影ポリゴンを作らないと正しく描画されません。
1058|*・1st step では影映りポリゴンからはみ出る仮の影ポリゴンが作成されます。
1059|*  2nd step では仮の影ポリゴンと影映りポリゴンの各辺の交点が追加され、
1060|*  3rd step では頂点をたどりながら最終的な影ポリゴンを決定します。
1061|*  
1062|*・2ポリゴンの関係において、以下の関係を考慮しています。
1063|*  ・内部に頂点を持つ場合、持たない場合
1064|*  ・1辺に対し、2つの交点を持つ場合
1065|*  ・頂点が他方のポリゴンに接する場合(凸型ポリゴンに限る)
1066|*  ・頂点が他方のポリゴンとの交点の場合
1067|*  ・頂点が他方のポリゴンの頂点と重なる場合
1068|*  ・交点を持たない場合
1069|*  
1070|**************************************************************************/
1071|void  ThreeD_Poly_initShadow( ThreeD_Poly* m, ThreeD_Poly* shadowed,
1072|  ThreeD_Poly* shadowing, ThreeD_XYZ* light,
1073|  ThreeD_XYZ* xyzs, size_t xyzs_sizeof )
1074|{
1075|  int  i;
1076|  ThreeD_Line  lightLine;  /* 光源(点)と影付けポリゴンの頂点を結ぶ直線 */
1077|  ThreeD_XYZ* xyzs_over = (ThreeD_XYZ*)((char*)xyzs + xyzs_sizeof);
1078|
1079|  /* 影ポリゴンの初期化 */
1080|  m->p_array = xyzs;
1081|  m->n = shadowing->n;
1082|  m->surf = shadowed->surf;
1083|  m->color = 0;
1084|
1085|  /* 影ポリゴンの頂点を求める */
1086|  for ( i = 0; i < shadowing->n && xyzs < xyzs_over; i++ ) {
1087|
1088|    /* lightLine を初期化 */
1089|    ThreeD_Line_init( &lightLine, light, &shadowing->p_array[i] );
1090|
1091|    /* lightLine と、影映りポリゴンを含む平面との、交点を xyzs に格納する */
1092|    ThreeD_Surf_getLineCross( &shadowed->surf, &lightLine, xyzs );
1093|    xyzs ++;
1094|  }
1095|}
1096|
1097|
1098| 
1099|#if 0
1100|/*************************************************************************
1101|*  55. <<< [ThreeD_Poly_initByFrontClip] セクショニングしたポリゴンに初期化する >>> 
1102|*【引数】
1103|*  ・ThreeD_XYZ*  p_array;   頂点座標を格納するアドレス
1104|*  ・int  n_max;             p_array に格納できる最大の頂点数
1105|*  ・ThreeD_Poly*  org;      セクショニングする前のポリゴン
1106|*  ・ThreeD_Surf*  sect;     セクショニング面
1107|*【補足】
1108|*・org ポリゴンから sect 面の表側にある部分を取り除いたポリゴンになります。
1109|**************************************************************************/
1110|void  ThreeD_Poly_initBySect( ThreeD_Poly* m, ThreeD_XYZ* p_array,
1111|  int n_max, ThreeD_Poly* org, ThreeD_Surf* clip )
1112|{
1113|  int  i;
1114|  int  cmp1, cmp2;
1115|
1116|  cmp1 = ThreeD_Surf_cmpFront( clip, base->p_array[i] );
1117|  cmp2 = ThreeD_Surf_cmpFront( clip, base->p_array[i+1] );
1118|  #error  now implementing
1119|}
1120|#endif
1121|
1122|
1123| 
1124|/*************************************************************************
1125|*  56. <<< [ThreeD_Poly_getCenter] ポリゴンの重心を取得する >>> 
1126|*【引数】
1127|*  ・ThreeD_XYZ* center;  ポリゴンの重心、三次元ワールド座標(出力)
1128|**************************************************************************/
1129|void  ThreeD_Poly_getCenter( ThreeD_Poly* m, ThreeD_XYZ* center )
1130|{
1131|  ThreeD_XYZ*  p;                                 /* ある頂点の座標 */
1132|  ThreeD_XYZ*  p_over = m->p_array + m->n;  /* 最後の次の頂点 */
1133|  double  x = 0.0, y = 0.0, z = 0.0;              /* 座標値の和 */
1134|
1135|  for ( p = m->p_array; p < p_over; p++ )
1136|    { x += p->x;  y += p->y;  z += p->z; }
1137|
1138|  center->x = x/m->n;  center->y = y/m->n;  center->z = z/m->n;
1139|}
1140|
1141|
1142| 
1143|/*************************************************************************
1144|*  57. <<< [ThreeD_Poly_cmpFront] ポリゴンが表側かどうか判断する >>> 
1145|*【補足】
1146|*(ThreeD_Surf_cmpFront 関数を参照してください)
1147|**************************************************************************/
1148|int  ThreeD_Poly_cmpFront( ThreeD_Poly* m, ThreeD_XYZ* viewP )
1149|{
1150|  return  ThreeD_Surf_cmpFront( &m->surf, viewP );
1151|}
1152|
1153|
1154| 
1155|/*************************************************************************
1156|*  58. <<< [ThreeD_Poly_getZVal] 指定したスクリーン座標の Z 値を返す ★>>> 
1157|*【機能】
1158|*・Z バッファに値を格納するために、スクリーン上のある点の Z 値を返します。
1159|*  ここで言う Z 値とは、視点からポリゴン上のある点までの距離のことです。
1160|*【引数】
1161|*  ・int  sx, sy;  スクリーン座標
1162|*  ・int  返り値;  Z 値、または INT_MAX
1163|*【補足】
1164|*・指定したスクリーン座標にポリゴンが無い場合、INT_MAX が返ります。
1165|**************************************************************************/
1166|#ifdef USES_SCALE
1167|#ifdef USES_TWOD
1168|int  ThreeD_Poly_getZVal( ThreeD_Poly* m, int sx, int sy,
1169|  ThreeD_ViewL* view, Scale* scale )
1170|{
1171|  ThreeD_XYZ   viewP;   /* ユーザ視点の座標・三次元ワールド座標 */
1172|  ThreeD_XYZ   scrP;    /* 投影面の座標・三次元ワールド座標 */
1173|  ThreeD_Line  line;    /* ユーザ視点から仮想面上の点をむすぶ直線 */
1174|  TwoD_XY    scrP2;     /* 投影面の座標・二次元ワールド座標 */
1175|  TwoD_Poly  poly2;     /* ポリゴン・二次元ワールド座標 */
1176|
1177|  static  TwoD_XY  poly2_ps[10];
1178|  #ifdef _CHECKER
1179|    if ( m->n > 10 )  error();  /* poly2_ps[] */
1180|  #endif
1181|
1182|  /* 二次元ワールド座標で、ポリゴンの内部でないなら INT_MAX を返す */
1183|  TwoD_XY_init( &scrP2, Scale_toLX( scale, sx ), Scale_toLY( scale, sy ) );
1184|  TwoD_Poly_initByThreeD( &poly2, poly2_ps, sizeof(poly2_ps), m, view );
1185|  if ( ! TwoD_XY_isInPoly( &scrP2, &poly2 ) )  return  INT_MAX;
1186|
1187|  /* 投影面の座標 scrP を設定する */
1188|  scrP.x = scrP2.x;
1189|  scrP.y = scrP2.y;
1190|  scrP.z = 0;
1191|  ThreeD_XYZ_get3D( &scrP, view, &scrP );
1192|
1193|  /* ユーザ視点 viewP を設定し、viewP と scrP をむすぶ直線 line を設定する */
1194|  ThreeD_ViewL_getUserViewP( view, &viewP );
1195|  ThreeD_Line_init( &line, &viewP, &scrP );
1196|
1197|  /* ユーザ視点 viewP からポリゴン m までの直線 line 上の長さを返す */
1198|  return  (int)ThreeD_XYZ_getSurfDistanceL( &viewP, &m->surf, &line );
1199|}
1200|#endif /* USES_TWOD */
1201|#endif /* USES_SCALE */
1202|
1203|
1204| 
1205|#ifdef USES_DRAW
1206|#ifdef USES_SCALE
1207|#ifdef USES_XORPAINT
1208|
1209|/*************************************************************************
1210|*  59. <<< [ThreeD_Poly_draw] ポリゴンを描画する >>> 
1211|*【補足】
1212|*・paint は、画面のサイズで初期化&クリアしてあること。そして、この関数から
1213|*  抜けると、paint のバッファにはポリゴンの図形(ごみ)が残ります。
1214|*・ポリゴンの色・模様は paint->paintPattern に設定しておいてください。
1215|**************************************************************************/
1216|void  ThreeD_Poly_draw( ThreeD_Poly* m, ThreeD_ViewL* view, Draw* draw,
1217|  Scale* scale, XorPaint* paint )
1218|{
1219|  ThreeD_XYZ*  p;                                 /* ある頂点の座標 */
1220|  ThreeD_XYZ*  p_over = m->p_array + m->n;  /* 最後の次の頂点 */
1221|  ThreeD_XYZ   pp;                        /* p の二次元ワールド座標 */
1222|  int  x, y;                                   /* p のスクリーン座標 */
1223|  int  x1, y1;                            /* 前の p のスクリーン座標 */
1224|  int  x0, y0;                          /* 最初の p のスクリーン座標 */
1225|
1226|  /* 最初の頂点 p のスクリーン座標 x0, y0 を取得する */
1227|  p = m->p_array;
1228|  ThreeD_XYZ_get2D( p, view, &pp );
1229|  x0 = x1 = (int)Scale_toGX( scale, pp.x );
1230|  y0 = y1 = (int)Scale_toGY( scale, pp.y );
1231|  p++;
1232|
1233|  /* 頂点をたどりながら、塗りつぶす領域を設定する */
1234|  for ( ; p < p_over; p++ ) {
1235|    ThreeD_XYZ_get2D( p, view, &pp );
1236|    x = (int)Scale_toGX( scale, pp.x );
1237|    y = (int)Scale_toGY( scale, pp.y );
1238|    XorPaint_setBound( paint, x1, y1, x, y );
1239|    x1 = x;  y1 = y;
1240|  }
1241|  XorPaint_setBound( paint, x1, y1, x0, y0 );
1242|
1243|  /* 塗りつぶす */
1244|  XorPaint_flushTo( paint, draw->drawScr, 0, 0 );
1245|}
1246|
1247|#endif  /* USES_XORPAINT */
1248|#endif  /* USES_SCALE */
1249|#endif  /* USES_DRAW */
1250|
1251|
1252| 
1253|#ifdef USES_DRAW
1254|#ifdef USES_SCALE
1255|#ifdef USES_XORPAINT
1256|
1257|/*************************************************************************
1258|*  60. <<< [ThreeD_Poly_draw2] 前面クリッピングしてポリゴンを描画する ★>>> 
1259|*【補足】
1260|*・前面クリッピングは、投影面に平行な前面クリッピング面 Z=-view->diffC より
1261|*  視点側をクリッピングすることです。
1262|*・前面クリッピングする以外は、ThreeD_Poly_draw 関数と同じです。
1263|**************************************************************************/
1264|void  ThreeD_Poly_draw2( ThreeD_Poly* m, ThreeD_ViewL* view, Draw* draw,
1265|  Scale* scale, XorPaint* paint )
1266|{
1267|  ThreeD_XYZ*  p;                                 /* ある頂点の座標 */
1268|  ThreeD_XYZ*  p_over = m->p_array + m->n;  /* 最後の次の頂点 */
1269|  ThreeD_XYZ   pp;                        /* p の二次元ワールド座標 */
1270|  ThreeD_XYZ   pp1;                  /* 前の p の二次元ワールド座標 */
1271|  ThreeD_XYZ   pp0;                /* 最初の p の二次元ワールド座標 */
1272|  int  x, y;                                  /* p のスクリーン座標 */
1273|  int  x1, y1;                     /* 前に描いた p のスクリーン座標 */
1274|  int  x0, y0;                   /* 最初に描いた p のスクリーン座標 */
1275|  bool  bExist;     /* 前面クリッピングされない最初の p が決まったか */
1276|
1277|  /* 最初の頂点 p のスクリーン座標 pp0 を取得する */
1278|  p = m->p_array;
1279|  ThreeD_XYZ_get2D( p, view, &pp0 );
1280|  if ( pp0.z >= -view->diffC ) {
1281|    x0 = x1 = (int)Scale_toGX( scale, pp0.x );
1282|    y0 = y1 = (int)Scale_toGY( scale, pp0.y );
1283|    bExist = true;
1284|  }
1285|  else
1286|    bExist = false;
1287|  pp1 = pp0;
1288|  p++;
1289|
1290|  /* 頂点をたどりながら、塗りつぶす領域を設定する */
1291|  for ( ; p < p_over; p++ ) {
1292|
1293|    /* 頂点 p のスクリーン座標 pp を取得する */
1294|    ThreeD_XYZ_get2D( p, view, &pp );
1295|
1296|    /* 前に描いた点から pp まで境界線を描画する、ただし ... */
1297|    /* [case1] pp1 も pp も前面クリッピングされないなら、そのまま描画する */
1298|    /* [case2] pp のみ前面クリッピングされる(入)なら、交点Aまでを描画する */
1299|    /* [case3] pp1 も pp も前面クリッピングされるなら、何もしない */
1300|    /* [case4] pp1 のみ前面クリッピングされた(出)なら、交点Aから */
1301|    /*         交点Bまでと、交点Bから pp までを描画する */
1302|    /*  */
1303|    if ( pp1.z >= -view->diffC || pp.z >= -view->diffC ) {
1304|      /* 前に描いた点から交点まで描画する [case2][case4] */
1305|      if ( pp.z < -view->diffC || pp1.z < -view->diffC ) {
1306|        ThreeD_XYZ_getZCross( &pp1, &pp, -view->diffC, &pp1 );
1307|        x = (int)Scale_toGX( scale, pp1.x );
1308|        y = (int)Scale_toGY( scale, pp1.y );
1309|        if ( bExist ) {
1310|          XorPaint_setBound( paint, x1, y1, x, y );
1311|        }
1312|        else {
1313|          x0 = x;  y0 = y;  bExist = true;
1314|        }
1315|        x1 = x;  y1 = y;
1316|      }
1317|      /* 前に描いた点から点 pp まで描画する [case1][case4] */
1318|      if ( pp.z >= -view->diffC ) {
1319|        x = (int)Scale_toGX( scale, pp.x );
1320|        y = (int)Scale_toGY( scale, pp.y );
1321|        XorPaint_setBound( paint, x1, y1, x, y );
1322|        x1 = x;  y1 = y;
1323|      }
1324|    }
1325|    pp1 = pp;
1326|  }
1327|  /* もし1本でも線が描画されていたら、閉じるように線を描画する */
1328|  /* もし、その線がクリッピング領域を超える場合、2本描画する */
1329|  if ( bExist ) {
1330|    /* 前に描いた点から最初に描いた点まで描画する [case1][case3] */
1331|    if ( (pp1.z - -view->diffC)*(pp0.z - -view->diffC ) >= 0 ) {
1332|      XorPaint_setBound( paint, x1, y1, x0, y0 );
1333|    }
1334|    /* 交点の両側に2本描画する [case2][case4] */
1335|    else {
1336|      ThreeD_XYZ_getZCross( &pp1, &pp0, -view->diffC, &pp );
1337|      x = (int)Scale_toGX( scale, pp.x );
1338|      y = (int)Scale_toGY( scale, pp.y );
1339|      XorPaint_setBound( paint, x1, y1, x, y );
1340|      XorPaint_setBound( paint, x0, y0, x, y );
1341|    }
1342|  }
1343|
1344|  /* 塗りつぶす */
1345|  XorPaint_flushTo( paint, draw->drawScr, 0, 0 );
1346|}
1347|
1348|#endif  /* USES_XORPAINT */
1349|#endif  /* USES_SCALE */
1350|#endif  /* USES_DRAW */
1351|
1352|
1353| 
1354|/*----------------------------------------------------------------------*/
1355|/*  61. <<< ◆影映りポリゴン (ThreeD_ShPoly) >>>                            */ 
1356|/*----------------------------------------------------------------------*/
1357|
1358|
1359| 
1360|/*************************************************************************
1361|*  62. <<< [ThreeD_ShPoly_init] 影映りポリゴンを初期化する >>> 
1362|*【補足】
1363|*・機能は、ThreeD_Poly_init 関数と同じです。
1364|*・影は ThreeD_ShPoly_shadowing 関数や ThreeD_ShPoly_shadowingAll 関数で
1365|*  付けます。
1366|**************************************************************************/
1367|void  ThreeD_ShPoly_init( ThreeD_ShPoly* m, ThreeD_XYZ* p_array, int n,
1368|  int color )
1369|{
1370|  ThreeD_Poly_init( &m->poly, p_array, n, color );
1371|  m->shadow[0] = NULL;  /*(まだ)影なし */
1372|  m->lightFlag = 0;  /* 「不明」という値 */
1373|}
1374|
1375|
1376| 
1377|#ifdef USES_ARRX
1378|/*************************************************************************
1379|*  63. <<< [ThreeD_ShPoly_shadowing] 影映りポリゴンに影ポリゴンを付ける >>> 
1380|*【機能】
1381|*・指定した影映りポリゴンに、ワールドにあるすべてのポリゴンが作る
1382|*  影ポリゴンを付けます。
1383|*【引数】
1384|*  ・ArrX*  shPolys;        ワールドにあるすべてのポリゴン(ThreeD_ShPoly 型)
1385|*  ・ThreeD_XYZ*  light;    光源(点)
1386|*  ・ArrX_Buf*  shadowBuf;  影ポリゴン・バッファ領域(ThreeD_Poly 型)
1387|*  ・ArrX_Buf*  xyzBuf      頂点・バッファ領域(ThreeD_XYZ 型)
1388|*【補足】
1389|*・光の位置が変わったりポリゴンが移動したら、影ポリゴンを付け直す必要が
1390|*  あります。
1391|*・これまで付いていた影ポリゴンは、失います。
1392|**************************************************************************/
1393|void  ThreeD_ShPoly_shadowing( ThreeD_ShPoly* m, ArrX* shPolys,
1394|  ThreeD_XYZ* light, ArrX_Buf* shadowBuf, ArrX_Buf* xyzBuf )
1395|{
1396|  ThreeD_ShPoly*  shPoly;  /* 影付けポリゴン */
1397|  ThreeD_ShPoly*  shPoly_over = shPolys->last;
1398|  ThreeD_Poly**  pNextShadow = &m->shadow[0];  /* 次の影ポリゴン */
1399|
1400|  /* 光源の方向を記録する */
1401|  m->lightFlag = ThreeD_Poly_cmpFront( &m->poly, light );
1402|
1403|  /* すべてのポリゴンを影付けポリゴンとして */
1404|  for ( shPoly = shPolys->first; shPoly < shPoly_over; shPoly++ ) {
1405|    ThreeD_XYZ  center;
1406|
1407|    ThreeD_Poly_getCenter( &shPoly->poly, &center );
1408|
1409|    /* もし、影付けポリゴンが光源の方向にあったら */
1410|    if ( m != shPoly &&
1411|        ThreeD_Poly_cmpFront( &m->poly, &center ) * m->lightFlag > 0 ) {
1412|
1413|      /* 影ポリゴンを付ける */
1414|      ThreeD_Poly*  shadow = ArrX_Buf_alloc( shadowBuf, ThreeD_Poly );
1415|      ThreeD_XYZ*  xyzs = ArrX_Buf_allocs( xyzBuf, ThreeD_XYZ,
1416|                                           shPoly->poly.n );
1417|      ThreeD_Poly_initShadow( shadow, &m->poly, &shPoly->poly, light,
1418|         xyzs, sizeof(ThreeD_XYZ) * shPoly->poly.n );
1419|      *pNextShadow = shadow;
1420|      pNextShadow ++;
1421|    }
1422|  }
1423|  *pNextShadow = NULL;
1424|}
1425|#endif  /* USES_ARRX */
1426|
1427|
1428| 
1429|#ifdef USES_DRAW
1430|#ifdef USES_SCALE
1431|#ifdef USES_XORPAINT
1432|#ifdef USES_ARRX
1433|#ifdef USES_MASK
1434|/*************************************************************************
1435|*  64. <<< [ThreeD_ShPoly_draw2] 影映りポリゴンを描画する >>> 
1436|*【補足】
1437|*・paint は、画面のサイズで初期化&クリアしてあること。そして、この関数から
1438|*  抜けると、paint のバッファにはポリゴンの図形(ごみ)が残ります。
1439|*・内部で ThreeD_Poly_draw2 関数を呼び出しているので、前面クリッピングが
1440|*  有効です。
1441|*・ポリゴンの色・模様は paint->paintPattern に設定しておいてください。
1442|**************************************************************************/
1443|void  ThreeD_ShPoly_draw2( ThreeD_ShPoly* m, ThreeD_ViewL* view, Draw* draw,
1444|  Scale* scale, XorPaint* paint )
1445|{
1446|  ThreeD_XYZ  viewP;
1447|
1448|  /* ユーザ視点を求める */
1449|  ThreeD_ViewL_getUserViewP( view, &viewP );
1450|
1451|  /* 影映りポリゴン(本体)を描画する */
1452|  ThreeD_Poly_draw2( &m->poly, view, draw, scale, paint );
1453|
1454|  /* もし、光源と視点が、ポリゴンに対して同じ方向なら、*/
1455|  if ( ThreeD_Poly_cmpFront( &m->poly, &viewP ) * m->lightFlag > 0 ) {
1456|    ThreeD_Poly**  pShadow;
1457|
1458|    /* すべての影ポリゴンを描画する */
1459|    for ( pShadow = m->shadow; *pShadow != NULL; pShadow++ ) {
1460|      XorPaint_clear( paint );
1461|      Mask_A_initByPlain( paint->paintPattern, 0 );
1462|      ThreeD_Poly_draw2( *pShadow, view, draw, scale, paint );
1463|    }
1464|  }
1465|}
1466|#endif  /* USES_MASK */
1467|#endif  /* USES_ARRX */
1468|#endif  /* USES_XORPAINT */
1469|#endif  /* USES_SCALE */
1470|#endif  /* USES_DRAW */
1471|
1472|
1473| 
1474|#ifdef USES_ARRX
1475|/*************************************************************************
1476|*  65. <<< [ThreeD_ShPoly_shadowingAll] すべての影映りポリゴンに影ポリゴンを付ける >>> 
1477|*【引数】
1478|*  ・ArrX*  shPolys;        ワールドにあるすべてのポリゴン(ThreeD_ShPoly 型)
1479|*  ・ThreeD_XYZ*  light;    光源(点)
1480|*【補足】
1481|*・光の位置が変わったりポリゴンが移動したら、影ポリゴンを付け直す必要が
1482|*  あります。
1483|*・これまで付いていた影ポリゴンは、失います。
1484|*・内部で影ポリゴンなどのバッファを用意しています。
1485|**************************************************************************/
1486|void  ThreeD_ShPoly_shadowingAll( ArrX* shPolys, ThreeD_XYZ* light )
1487|{
1488|  ArrX_Buf  shadowBuf;
1489|  static ThreeD_Poly  shadowBuf_mem[500];
1490|  ArrX_Buf  xyzBuf;
1491|  static ThreeD_Poly  xyzBuf_mem[1000];
1492|  ThreeD_ShPoly*  shPoly;
1493|  ThreeD_ShPoly*  shPoly_over = shPolys->last;
1494|
1495|  ArrX_Buf_init( &shadowBuf, shadowBuf_mem, sizeof(shadowBuf_mem) );
1496|  ArrX_Buf_init( &xyzBuf, xyzBuf_mem, sizeof(xyzBuf_mem) );
1497|
1498|  for ( shPoly = shPolys->first; shPoly < shPoly_over; shPoly++ ) {
1499|    ThreeD_ShPoly_shadowing( shPoly, shPolys, light, &shadowBuf, &xyzBuf );/*★*/
1500|  }
1501|}
1502|#endif  /* USES_ARRX */
1503|
1504|
1505| 
1506|/*----------------------------------------------------------------------*/
1507|/*  66. <<< ◆ソート用ポリゴン (ThreeD_PolyS) >>>                           */ 
1508|/*----------------------------------------------------------------------*/
1509|
1510|
1511| 
1512|#ifdef USES_DRAW
1513|#ifdef USES_SCALE
1514|#ifdef USES_XORPAINT
1515|#ifdef USES_ARRX
1516|#ifdef USES_MASK
1517|
1518|/*************************************************************************
1519|*  67. <<< [ThreeD_PolyS_draw] すべてのポリゴンを描画する(ソーティング)★>>> 
1520|*【機能】
1521|*・ソーティング、前面クリッピングして、全てのポリゴンを描画します。
1522|*【引数】
1523|*  ・ArrX*  polys;     ポリゴン ThreeD_PolyS 型の配列を ArrX_init したもの
1524|*  ・void**  sortBuf;  ソート用バッファ、void* 型の配列の先頭ポインタ
1525|*  ・size_t  sortBuf_sizeof;  sortBuf のメモリサイズ
1526|*【補足】
1527|*・polys と sortBuf の要素数は同じであること。
1528|*・paint は、画面のサイズで初期化&クリアしてあること。そして、この関数から
1529|*  抜けると、paint のバッファにはポリゴンの図形(ごみ)が残ります。
1530|**************************************************************************/
1531|void  ThreeD_PolyS_draw( ArrX* polys, void** sortBuf, size_t sortBuf_sizeof,
1532|  ThreeD_ViewL* view, Draw* draw, Scale* scale, XorPaint* paint )
1533|{
1534|  ArrX_Sort  sort;   /* ソート用配列 */
1535|  ArrX_Key   key;    /* キー */
1536|  ThreeD_XYZ  userViewP;  /* ユーザ視点の座標 */
1537|  ThreeD_XYZ  centerP;    /* ポリゴンの重心の座標 */
1538|  ThreeD_PolyS*  poly;    /* 処理中のポリゴン */
1539|  ThreeD_PolyS*  poly_over;
1540|
1541|  /* ソート用配列に格納 ArrX_Sort_pushPQ する */
1542|  {
1543|    ThreeD_ViewL_getUserViewP( view, &userViewP );
1544|    ArrX_Key_init( &key, OFFSET( poly, dist ), ArrX_Key_Double, ArrX_Key_Down );
1545|    ArrX_Sort_init( &sort, sortBuf, sortBuf_sizeof, &key );
1546|
1547|    /* ユーザ視点からポリゴンの重心までの距離を求め、ソート用配列に格納する */
1548|    poly_over = polys->last;
1549|    for ( poly = polys->first; poly < poly_over; poly++ ) {
1550|      ThreeD_Poly_getCenter( poly->poly, &centerP );
1551|      poly->dist = ThreeD_XYZ_getDistance( &centerP, &userViewP );
1552|      ArrX_Sort_pushPQ( &sort, poly );
1553|    }
1554|  }
1555|
1556|  /* ソート用配列から取り出しながら描画 ThreeD_Poly_draw2 する */
1557|  {
1558|    poly = ArrX_Sort_popPQ( &sort );
1559|    while ( poly != NULL ) {
1560|      XorPaint_clear( paint );
1561|      Mask_A_initByPlain( paint->paintPattern, poly->poly->color );
1562|      ThreeD_Poly_draw2( poly->poly, view, draw, scale, paint ); /*★*/
1563|      poly = ArrX_Sort_popPQ( &sort );
1564|    }
1565|  }
1566|}
1567|
1568|#endif  /* USES_MASK */
1569|#endif  /* USES_ARRX */
1570|#endif  /* USES_XORPAINT */
1571|#endif  /* USES_SCALE */
1572|#endif  /* USES_DRAW */
1573|
1574|
1575| 
1576|#ifdef USES_DRAW
1577|#ifdef USES_SCALE
1578|#ifdef USES_XORPAINT
1579|#ifdef USES_ARRX
1580|#ifdef USES_MASK
1581|
1582|/*************************************************************************
1583|*  68. <<< [ThreeD_PolyS_drawSh] すべての影映りポリゴンを描画する(ソーティング)>>> 
1584|*【補足】
1585|*・polys が ThreeD_ShPoly 型の配列である以外は、ThreeD_PolyS_draw 関数と
1586|*  同じです。
1587|**************************************************************************/
1588|void  ThreeD_PolyS_drawSh( ArrX* polys, void** sortBuf, size_t sortBuf_sizeof,
1589|  ThreeD_ViewL* view, Draw* draw, Scale* scale, XorPaint* paint )
1590|{
1591|  ArrX_Sort  sort;   /* ソート用配列 */
1592|  ArrX_Key   key;    /* キー */
1593|  ThreeD_XYZ  userViewP;  /* ユーザ視点の座標 */
1594|  ThreeD_XYZ  centerP;    /* ポリゴンの重心の座標 */
1595|  ThreeD_PolyS*  poly;    /* 処理中のポリゴン */
1596|  ThreeD_PolyS*  poly_over;
1597|
1598|  /* ソート用配列に格納 ArrX_Sort_pushPQ する */
1599|  {
1600|    ThreeD_ViewL_getUserViewP( view, &userViewP );
1601|    ArrX_Key_init( &key, OFFSET( poly, dist ), ArrX_Key_Double, ArrX_Key_Down );
1602|    ArrX_Sort_init( &sort, sortBuf, sortBuf_sizeof, &key );
1603|
1604|    /* ユーザ視点からポリゴンの重心までの距離を求め、ソート用配列に格納する */
1605|    poly_over = polys->last;
1606|    for ( poly = polys->first; poly < poly_over; poly++ ) {
1607|      ThreeD_Poly_getCenter( poly->poly, &centerP );
1608|      poly->dist = ThreeD_XYZ_getDistance( &centerP, &userViewP );
1609|      ArrX_Sort_pushPQ( &sort, poly );
1610|    }
1611|  }
1612|
1613|  /* ソート用配列から取り出しながら描画 ThreeD_Poly_draw2 する */
1614|  {
1615|    poly = ArrX_Sort_popPQ( &sort );
1616|    while ( poly != NULL ) {
1617|      XorPaint_clear( paint );
1618|      Mask_A_initByPlain( paint->paintPattern, poly->poly->color );
1619|      ThreeD_ShPoly_draw2( (ThreeD_ShPoly*)poly->poly,
1620|                           view, draw, scale, paint ); /*★*/
1621|      poly = ArrX_Sort_popPQ( &sort );
1622|    }
1623|  }
1624|}
1625|
1626|#endif  /* USES_MASK */
1627|#endif  /* USES_ARRX */
1628|#endif  /* USES_XORPAINT */
1629|#endif  /* USES_SCALE */
1630|#endif  /* USES_DRAW */
1631|
1632|
1633| 
1634|/*-----------------------------------------------------------------------*/
1635|/*  69. <<< ◆三次元空間内の二次元座標 (ThreeD_TwoD) >>>                     */ 
1636|/*-----------------------------------------------------------------------*/
1637|
1638|
1639| 
1640|/*************************************************************************
1641|*  70. <<< [ThreeD_TwoD_initByP3] 3点からなる平面を二次元座標として初期化する >>> 
1642|*【補足】
1643|*・X, Y 座標単位ベクトルは、次の図のように求めています。
1644|*   (y1, y0 が逆です[ミス])
1645|**************************************************************************/
1646|void  ThreeD_TwoD_initByP3( ThreeD_TwoD* m, ThreeD_XYZ p[] )
1647|{
1648|  ThreeD_Vect  y0;  /* Y 座標単位ベクトルの起点 */
1649|  ThreeD_Vect  y1;  /* Y 座標単位ベクトルの終点 */
1650|
1651|  /* X 座標単位ベクトルの初期化 */
1652|  ThreeD_Vect_initBy2XYZ( &m->x_coord, &p[1], &p[0] );
1653|  ThreeD_Vect_chgToUnit( &m->x_coord );
1654|
1655|  /* Y 座標単位ベクトルの初期化 */
1656|  ThreeD_Vect_initBy2XYZ( &y1, &p[2], &p[0] );
1657|  ThreeD_Vect_getDirVect( &y1, &m->x_coord, &y0 );
1658|  ThreeD_Vect_initBy2XYZ( &m->y_coord, &y1, &y0 ); /*★*/
1659|  ThreeD_Vect_chgToUnit( &m->y_coord );
1660|}
1661|
1662|
1663| 
1664|/*************************************************************************
1665|*  71. <<< [ThreeD_TwoD_print] 属性を表示する >>> 
1666|**************************************************************************/
1667|#ifndef ERRORS_CUT_DEBUG_TOOL
1668|void  ThreeD_TwoD_print( ThreeD_TwoD* m )
1669|{
1670|  ThreeD_Vect_print( &m->x_coord, "X" );
1671|  ThreeD_Vect_print( &m->y_coord, "Y" );
1672|}
1673|#endif
1674|
1675| 
1676|