README.jp 93.1 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398
-------------------------------------------------------------------------------
===============================================================================
	Z Sort マイクロコードドキュメント
	
				Release 0.34
				Aug  4, 1998.
				Copyright by Nintendo, Co., Ltd. 1997-1998
				任天堂株式会社開発第 3 部    安本吉孝
===============================================================================
-------------------------------------------------------------------------------

 目次
	 1. ZSort マイクロコードとは

	 2. ZSort マイクロコードの機能
		2.1  ZSort による描画処理の流れ
		2.2  描画処理と算術演算処理

	 3. 描画処理
		3.1  描画可能な図形(ZObject)
		3.2  ZObject リストの処理
		3.3  Z ソート処理
		3.4  ZObject のデータ形式
			3.4.1  zShTri  構造体
			3.4.2  zShQuad 構造体
			3.4.3  zTxTri  構造体
			3.4.4  zTxQuad 構造体
			3.4.5  zNull   構造体
		3.5  RDPcmd パラメータによる RDP コマンドの制御
		3.6  画面クリアおよびその他の描画処理

	 4. 算術演算処理
		4.1  表示物体と算術演算
		4.2  DMEM 内の演算用ワークエリア
		4.3  GBI 一覧
		4.4  GBI の機能解説

	 5. その他の処理
		5.1  GBI 一覧
		5.2  GBI の機能解説

	 6. 他のマイクロコードとの互換性
		6.1  GBI について
		6.2  共通 GBI

	 7. CPU のサポートライブラリ

	 8. TASK マネージメント
		8.1  RSP 処理の実装手法
		8.2  2 タスク処理
		8.3  2 パス並列処理

	 9. 使用上の注意
		9.1  RSP から RDP へのコマンドの受け渡し
		9.2  自己ロード機能

	10. ZSort パッケージのインストール

	11. サンプルプログラム

	12. 変更履歴

	
===============================================================================
1. ZSort マイクロコードとは.
===============================================================================

  ZSort マイクロコードは, Nintendo64 (以下 N64) ハードウェア上で Z ソー
トによる隠面消去処理を行なうために開発されたものです. 画面上に表示する
べき図形の全てを画面の深さ順に整列させ, 奥のものから順に描画していくと
いう手法で画面を作成します.

  N64 には Z-Buffer 処理による隠面処理がハードウェアによってサポートさ
れています. Z-Buffer 法による隠面処理では 1 Pixel 毎に可視かどうかを判
定するので Z ソートと比べて描画される図形の前後関係を正確に表現できる
という利点がありますが, その反面 RAM のアクセスが増加してしまいます. Z 
ソートでは, Z-Buffer 程の前後関係の処理は出来ませんが 1 図形あたりの 
RAM へのアクセス量が減るため, 単位時間内に画面へ表示できる図形の量は 
Z-Buffer 法と比べて多くなります.

  この ZSort 法による利点は, RAM の帯域が改善されるため RDP の処理が軽
くなることです. 多くのアプリケーションでは RDP の処理にかかる時間がネッ
クとなり表示する図形の量に制限がかかっているのが現状であるため, このこ
とは朗報といえるでしょう. 

  ただし, ここで注意するべきことは RSP の処理はそれほど変わらないとい
うことです. RDP の処理は塗り潰す領域のサイズに応じて変化し, 特に小さな
領域の描画では, RSP の処理よりも RDP の処理の方が早く終わります. これ
は, 小さな描画領域がたくさんあって RSP の処理が終わるのを RDP が常に待っ
ているような状態では Z-Buffer でも ZSort でも, 処理能力は変わらないこ
とを意味します. ただし描画領域がある程度大きい場合には ZSort 法が有利
になります. ZSort マイクロコードは万能ではありません. 描画したい画面を
よくご考慮の上ご選択ください.


	
===============================================================================
2. ZSort マイクロコードの機能
===============================================================================

--------------------------------
2.1  ZSort による描画処理の流れ

  ZSort マイクロコードでは描画領域として 3 角形領域と 4 角形領域の他に 
RDP コマンドによる Texture Rectangle や Fill Rectangle をサポートして
います. こうして RDP によって描画される領域それぞれのことを本マニュア
ル上では ZObject と呼びます.

  ZSort マイクロコードでは 1 つの ZObject に対し, その描画領域を代表す
る 1 つの画面深度値を求めます. そして各 ZObject をその画面深度でソート
し, 画面の奥にある ZObject から順に描画することで隠面処理を行ないます.

  ZObject の描画のための処理の流れは以下のようになります.

	| モデル行列と透視変換行列等の乗算
	| モデル頂点の座標変換/透視変換/画面深度計算
	| 頂点が画面内にあるかどうかの判定
	| クリッピング/裏面判定
	| ZObject データの構築
	| ZObject リスト作成
	V ZObject リストの順に描画を行なう(描画処理)

  ここで ZObject を描画するためには ZObject をどのように描画するかとい
う情報をデータとして用意してやらなければなりません. 従来の Fast3D マイ
クロコードでは 3 角形の描画に Vertex 命令と Tri 命令を組み合わせていま
したが, ZSort マイクロコードでは ZObject 構造体を作ることで描画を行な
うの点が異なります.

  これらの全ての処理が ZSort マイクロコードで実装されているわけではあ
りません. ZSort マイクロコードが他のグラフィックマイクロコードと大きく
異なる点は, ZSort マイクロコードはそれだけでは動作しないという点で
す. CPU が描画に関する処理の一部を行なう必要があります.

  例えば, ZObject を画面の深さ順にソートする機能はマイクロコードとして
は実装されていません. ソート処理は CPU が行ないその結果を RSP に渡す必
要があるのです.

  最低でも, 以下の処理は CPU で行なう必要があります.

	- クリッピング/裏面判定
	- ZObject データの構築
	- ZObject リスト作成

  現在, ZSort マイクロコードで実装されている主な機能を以下にあげます.
これらの各処理は 1 つあるいは複数の GBI コマンドからなる Display List 
によって制御されます.

	+ モデル行列と透視変換行列等の乗算.
	+ モデル頂点の座標変換/透視変換/画面深度計算
	+ 頂点が画面内にあるかどうかのフラグ作成
	+ ZObject リストの順に描画を行なう(描画処理)

  当然ながら行列の乗算や座標変換などの処理(ここでは, 算術演算処理と呼
ぶ)については, CPU で処理することも可能です. プロセッサの空き状態に応
じて使い分けるのが良いでしょう. ただし, 以降では算術演算処理を RSP で
行なうことを前提にした説明を行ないます. CPU で算術処理を行なわれる場合
は, 後程説明する算術演算処理は参考資料としてお読み下さい.

----------------------------
2.2  描画処理と算術演算処理

  RSP で算術演算を行なう場合は通常, ZSort マイクロコードの処理は 2 パ
スの形になります. これは, 最後の ZObject の座標変換が終了しないと, Z 
ソートの完全な結果を得ることができないからです. このことは他のマイクロ
コードと異なりパイプライン的にデータを流していくことができないことを意
味します. 全ての ZObject の情報を一時的に保持する必要があるからです.

  ここでは座標変換にかかわる次の機能を算術演算処理と呼び, 第 1 パスで
処理します. これらの処理はあくまで *頂点の* 座標の変換です. ここでは 
ZObject の面としてのデータの作成は行ないません. 実際の ZObject の面デー
タは頂点座標変換結果から CPU が構成します. ご注意下さい.

	+ モデル行列と透視変換行列等の乗算.
	+ モデル頂点の座標変換/透視変換/画面深度計算
	+ 頂点が画面内にあるかどうかの判定

  次に ZSort 後の以下の処理を描画処理と呼び, 第 2 パスで処理します.

	+ ZObject リストの順に描画を行なう

  この ZObject リストとは, ZObject のデータを画面奥のものから順にリスト形式
によって連結した以下のようなチェーン状のデータ列のことです. Zobj 3 の 
X は終端を意味します.

       GBI       ZObj 1         ZObj 2         ZObj 3
       +-+     +------+-+     +------+-+     +------+-+
       |o----->| Data |o----->| Data |o----->| Data |X|
       +-+     +------+-+     +------+-+     +------+-+

  この ZObject リストは CPU が作成する必要があります. ZSort マイクロコー
ドでは, このリスト形式の ZObject リストをサポートしているため, ソート
処理に伴うデータの入れ替えコストを最小に抑えることができます. ソーティ
ング処理のアルゴリズムは, どのようなものを使用しても問題はありませ
ん. ちなみに本マイクロコードのサンプルプログラムでは, こうした ZObject 
リストを複数個, 作成することで Far 平面と Near 平面の間を 1024 段階に
分割したバケットソートを行なっています.

  以上をまとめると次のような処理の流れとなります.

    [CPU] 算術演算用 DisplayList 作成
               |
               V
    [RSP] 算術演算処理
               |
               V
    [CPU] ZObject データ作成 
          ZObject リスト(=描画用 DisplayList)作成(ZSort)
               |
               V
    [RSP/RDP] 描画処理

===============================================================================
3. 描画処理
===============================================================================

-----------------------------
3.1  描画可能な図形(ZObject)

  前章でも述べたように ZSort マイクロコードでは, ZObject という描画
領域ごとに描画を行ないます. ZObject の種類として以下があり, それぞれに
対応した構造体によってその描画パラメータが定義されます.

      zShTri   - スムースシェーディングされた 3 角形
      zShQuad  - スムースシェーディングされた 4 角形
      zTxTri   - テクスチャ付のスムースシェーディングされた 3 角形
      zTxQuad  - テクスチャ付のスムースシェーディングされた 4 角形
      zNull    - RDP コマンドを使用したその他の描画領域
                        (FillRectangle や TextureRectangle に使用)

  フラットシェーディングされた 3 角形 / 4 角形を描画する ZObject は用
意されていません. こうした図形を描画したい場合は, 全ての頂点に同じ色を
指定し描画してください. これは, マイクロコードのサイズの制限から全ての
図形をサポートできなかったからです. ご了承ください.

  マイクロコードではこのような単純な型の図形しかサポートしていませんが 
CPU 側のライブラリを工夫することで様々な型の図形を描画できます. 詳しく
はサンプルプログラムを参照してください.

--------------------------
3.2  ZObject リストの処理

  ZObject はリスト形式を取ることが出来るようにするため, その構造体の先
頭部に次の ZObject へのポインタデータおよび次の ZObject の種別 ID が格
納されています. 全ての ZObject 構造体の先頭 4bytes の領域はヘッダ領域
として予約されており, この 4bytes の値によって ZObject をリスト形式に
することができます.

       GBI コマンド
       +-+-+
       |o|X| g[s]SPZObject
       +|+-+
        |
        V
       +------+-+     +------+-+     +------+-+
       |ZObj 1|o----->|ZObj 2|o----->|ZObj 3|X|
       +------+-+     +------+-+     +------+-+

  GBI コマンド g[s]SPZObject でこのリストの先頭 ZObject (上図の場合は 
ZObj 1) へのポインタおよび ZObject 種別 ID を指定すれば, RSP はこのリ
ストを辿って順に描画処理を行ないます.

  GBI コマンド g[s]SPZObject には 0,1,2 個のリストを処理できます. すな
わち以下の 2 つの ZObject リスト A,B が 1 つの GBI で描画できるのです.

       GBI コマンド
       +-+-+
       |o|o| g[s]SPZObject
       +|+|+
        | |
        | V
        | +------+-+     +------+-+
        | |ZObj 4|o----->|ZObj 5|X|  ZObject リスト B
        | +------+-+     +------+-+
        V 
       +------+-+     +------+-+     +------+-+
       |ZObj 1|o----->|ZObj 2|o----->|ZObj 3|X|  ZObject リスト A
       +------+-+     +------+-+     +------+-+

  これは GBI コマンドのサイズは最低でも 8 bytes であり, これは 4 bytes 
であるポインタデータの 2 つ分に相当するからです. もし, 2 個未満の処理
リストを描画するときは, 空きの部分には終端値(=G_ZOBJ_NONE)を書き込んで
ください.

  この GBI コマンド g[s]SPZObject のデータフォーマットは, 以下の通りです. 
前半部と後半部が同じ形になっています. 

------------------------------------------------------------------------------
 * gSPZObject(Gfx *gp, u32 listA, u32 listB)

	listA	ZObject リンク A のリンクパラメータ =ZHDR(ListA, ZidA)
	listB	ZObject リンク B のリンクパラメータ =ZHDR(ListB, ZidB)

              31              3 2  0
              +----------------+----+
              |      ListA     |ZidA|
              +----------------+----+
              |      ListB     |ZidB|
              +----------------+----+

     ListA/ListB   ZObject リストへのポインタの bit31 から bit3 までの値
                   先頭 8 bits は 0x80 でなければならない. (通常は 0x80)
     ZidA/ZidB     ZObject リストの先頭の ZObject の種別 ID

  このデータ(32bit分) を設定するためのマクロとして,
ZHDR(pointer,type) が用意されています. 以下のように使用できます.

    gSPZObject(gfx, ZHDR(ptr_listA, ZH_SHTRI), ZHDR(ptr_listB, ZH_TXTRI));

  または, 処理リンク A または 処理リンク B のみを変更するために, 以下
のように直接値を代入しても構いません.

    *((u32 *)gfx) = ZHDR(ptr_listA, ZH_SHTRI);

  ここで ZH_xxxxx は ZObject の種別 ID で, 以下の 5 つの値を取ります.

      ZH_SHTRI   - スムースシェーディングされた 3 角形
      ZH_SHQUAD  - スムースシェーディングされた 4 角形
      ZH_TXTRI   - テクスチャマップおよびスムースシェーディングされた 3 角形
      ZH_TXQUAD  - テクスチャマップおよびスムースシェーディングされた 4 角形
      ZH_NULL    - RDP コマンドを使用したその他の描画領域

************************************************************************
 ここでは, gSPZObject のみの説明をしましたが, gsSPZObject も存在します. 
 以降の章にも GBI コマンドの説明が出てきますが, この GBI と同様に 
 gsSPZ*** の解説は省略します.
************************************************************************

------------------
3.3  Z ソート処理

  GBI コマンド g[s]SPZObject は ZObject の ZObject リストへのポインタ
と種別 ID を並べただけの構造なので, このコマンドを複数並べ配列とするこ
とで, 簡単に 3 つ以上の ZObject リストを処理することができます. 各 
ZObject リストに対し, 画面の深度のほぼ等しい ZObject をまとめて 
ZObject リストを作成し, 画面奥の ZObject リストから順に g[s]SPZObject 
によって並べることで, パケットソートを簡単に行なうことが可能です.

処理手順は以下の通りになります. ここでの例は, 各 ZObject の画面深度を 
1024 段階に分け処理を行ないます.

  (1) gSPZObject 用の配列の用意. 

     画面深度の 1 段階につき ZObject リスト 1 つを用意するため,
   gSPZObject の配列サイズとして 512 (=1024/2) コマンド必要となります. 
   この配列がそのまま, DL の一部となり, RSP に直接処理されるため,
   gSPZObject 配列の最後尾に gSPEndDisplayList を追加します. よって, 
   必要なサイズは 513(=512+1)コマンド分となります.

    |
    |    Gfx zarray[1024/2+1];
    |

  (2) 配列の初期化.

     配列の全ての要素に終端値 (G_ZOBJ_NONE = 0x80000000) を代入し, 配
   列を初期化します. 最後尾に EndDL を書き込みます. 以下図参照.

    |
    |    int  i;
    |    for (i = 0; i < 512; i ++){
    |        gSPZObject(zarray+i, G_ZOBJ_NONE, G_ZOBJ_NONE);
    |    }
    |    gSPEndDisplayList(zarray+512);
    |

            0     1     2     3    .....   510   511   512
         +-----+-----+-----+-----+--/ /--+-----+-----+-----+
  zarray |X |X |X |X |X |X |X |X | / /|X |X |X |X |X |EndDL|
         +-----+-----+-----+-----+/ /----+-----+-----+-----+

            X: 終端値 (=G_ZOBJ_NONE)


  (3) 各 ZObject の画面深度に応じた配列への登録.

     ZObject ごとに画面深度の計算を行ないます. RSP で各頂点における画
   面深度の値は計算できますが, ZObject においてどの値を画面深度として
   使用するかの決定はユーザー側に任されています. 画面深度として使用す
   る値の例として以下のような値があります.

     3 角形の ZObject における画面深度の例:
        + 3 頂点の視点からの距離の最小値.
        + 3 頂点の視点からの距離の最大値.
        + 3 頂点の視点からの距離の平均値.
        + 3 頂点の視点からの距離の最大値と最小値の中間値.
   
     * また視点からの距離の逆数を使用することもできます. サンプルプロ
       グラムでは逆数値の平均を使用しています.

     この値を 0 〜 1023 に正規化し, 登録する配列要素の番号にします.
   該当する配列の要素にもともと保存してあるポインタおよび ZObject 種別
   ID を登録する ZObject のヘッダ内に保管し, 該当する配列の要素へは
   ZObject 構造体データへのポインタおよび ZObject 種別 ID を書き込みま
   す.

    | 
    |    s32      zid;                      /* 登録する配列要素の番号 */
    |    zHeader *zhptr;                    /* ZObject へのポインタ   */
    |    u32      ztype;                    /* ZObject の種別 ID      */
    |    u32     *uzarray = (u32 *)zarray;
    |
    |    for ( each ZObject ){
    |        画面深度から zid を計算する;
    |        if (zid < 0)    zid = 0;              /* zid のクランプ   */
    |        if (zid > 1023) zid = 1023;
    |        zhptr->t.header = *(uzarray+zid);     /* 次の Node の設定 */
    |        *(uzarray+zid) = ZHDR(zhptr, ztype);  /* zarray への登録  */
    |    }
    | 

            0     1     2     3    .....   510   511   512
         +-----+-----+-----+-----+--/ /--+-----+-----+-----+
  zarray |X |X |X |X |o |X |X |X | / /|X |X |X |X |X |EndDL|
         +-----+-----+|----+-----+/ /----+-----+-----+-----+
                      |
                      V
                     +------+-+
                     |ZObj 1|X|
                     +------+-+

    この処理を全 ZObject に対して行ない, 出来た配列を gSPDisplayList 
で呼び出せば描画処理が出来ます. 

   gSPDisplayList(o)
                  |
          +-------+
          |
          V 0     1     2     3    .....   510   511   512
         +-----+-----+-----+-----+--/ /--+-----+-----+-----+
  zarray |X |o |X |X |o |X |X |X | / /|X |X |o |X |X |EndDL|
         +---|-+-----+|----+-----+/ /----+---|-+-----+-----+
             |        |                      |
             |        V                      V
             |       +------+-+             +------+-+
             |       |ZObj 5|o|             |ZObj 6|o|
             |       +------+|+             +------+|+
             |               |                      |
             V               V                      V
            +------+-+      +------+-+             +------+-+
            |ZObj 3|X|      |ZObj 4|o|             |ZObj 2|X|
            +------+-+      +------+|+             +------+-+
                                    |
                                    V
                                   +------+-+
                                   |ZObj 1|X|
                                   +------+-+

上の例の場合, ZObj 3 -> ZObj 5 -> ZObj 4 -> ZObj 1 -> ZObj 6 -> ZObj 2
の順で描画処理が行なわれます.


--------------------------
3.4  ZObject のデータ形式

  Z Sort マイクロコードがサポートする ZObject は 5 種類あり, それぞれ
を描画するための必要なデータは異なります. 以降では, それぞれの ZObject 
のデータを格納するための 5 種類の構造体について説明します.

---------------------
3.4.1  zShTri 構造体

  zShTri 構造体は, テクスチャなしのスムースシェード処理された 3 角形を
描画するためのデータ構造体です. その形状を指定するために以下のような 
zShVtx 型の頂点データを 3 組必要とします.

	-----------------------------------------------------------
	typedef struct  {
	  s16   x, y;		/* 頂点のスクリーン座標 (s10.2)  */
	  u8    r, g, b, a;	/* 頂点におけるカラー 各 0..255  */
	} zShVtx;
	-----------------------------------------------------------

  zShTri 構造体は以下のようなデータ形式をとります.

            +0          +4       +7
           +-----------+-----------+
           |    Hdr    |  RDP cmd  |
           +-----+-----+--+--+--+--+
        V0 |  X  |  Y  |R |G |B |A |
           +-----+-----+--+--+--+--+
        V1 |  X  |  Y  |R |G |B |A |
           +-----+-----+--+--+--+--+
        V2 |  X  |  Y  |R |G |B |A |
           +-----+-----+--+--+--+--+

	-------------------------------------------------------------
	typedef struct  {
	  zHeader       *header;	/* 次の ZObject の情報 */
	  Gfx           *rdpcmd1;	/* 前処理 DP コマンド  */
	  zShVtx        v[3];		/* 頂点データ          */
	} zShTri_t;
		
	typedef struct  {		/* ワードアクセス用構造体 */
	  zHeader       *header;
	  Gfx           *rdpcmd1;
	  u32           xy0, clr0;
	  u32           xy1, clr1;
	  u32           xy2, clr2;
	} zShTri_w;
	
	typedef union   {
	  zShTri_t      t;
	  zShTri_w      w;
	  u64           force_structure_alignment;
	} zShTri;
	-------------------------------------------------------------

  この構造体で指定された 3 頂点から成る 3 角形が描画されます. この際に
は 3 角形の裏表は考慮されません. 裏を向いていようが表を向いていようが
描画されてしまいます. 裏側を向いている 3 角形の描画をしたくない場合は,
ZObject データ作成時にCPU が裏表の判定をして, 表側を向いている ZObject 
のみを描画するようにしてください. この裏表の判定については他の多角形 
ZObject についても同様です.

  メンバー変数 header は ZObject がリスト構造で連なるときに, 次の 
ZObject へのポインタ等を保持します.

  メンバー変数 rdpcmd1 は現在の RDP の処理モードを変更するために使用し
ます. ZObject を描画する前に RDP へ送られる RDP コマンド DL 列をここへ
指定します. rdpcmd1 についての詳細は 3.5 項で説明します.

----------------------
3.4.2  zShQuad 構造体

  zShQuad 構造体は, テクスチャなしのスムースシェード処理された 4 角形
を描画するためのデータ構造体です. その形状を指定するために前項で説明し
た zShVtx 型の頂点データを 4 組必要とします.
  zShQuad では 3 角形 V0-V1-V2 と V1-V2-V3 の 2 つの 3 角形を描画する
ことで, 4 角形の描画を行ないます.

	V0+--------+V1
          |      /|
          |    /  |
          |  /    |
          |/      |
        V2+--------+V3

  zShQuad 構造体は以下のようなデータ形式をとります.

            +0          +4       +7
           +-----------+-----------+
           |    Hdr    |  RDP cmd  |
           +-----+-----+--+--+--+--+
        V0 |  X  |  Y  |R |G |B |A |
           +-----+-----+--+--+--+--+
        V1 |  X  |  Y  |R |G |B |A |
           +-----+-----+--+--+--+--+
        V2 |  X  |  Y  |R |G |B |A |
           +-----+-----+--+--+--+--+
        V3 |  X  |  Y  |R |G |B |A |
           +-----+-----+--+--+--+--+

	-------------------------------------------------------------
	typedef struct  {
	  zHeader       *header;	/* 次の ZObject の情報 */
	  Gfx           *rdpcmd1;	/* 前処理 DP コマンド  */
	  zShVtx        v[4];		/* 頂点データ          */
	} zShQuad_t;
		
	typedef struct  {		/* ワードアクセス用構造体 */
	  zHeader       *header;
	  Gfx           *rdpcmd1;
	  u32           xy0, clr0;
	  u32           xy1, clr1;
	  u32           xy2, clr2;
	  u32           xy3, clr3;
	} zShQuad_w;
	
	typedef union   {
	  zShQuad_t      t;
	  zShQuad_w      w;
	  u64           force_structure_alignment;
	} zShQuad;
	-------------------------------------------------------------

  同じ 4 角形を 1 つの zShQuad で描画する場合と 2 つの zShTri で描画す
る場合では必要なメモリに差があり, zShQuad の方が使用するメモリが少なく
て済むことが zShQuad を使用する大きなメリットでしょう.

  更に RDP での描画で有利になるように 4 角形の分割線を CPU で動的に変
更してやることで RDP の描画パフォーマンスが向上します. 具体的には, 対
角線 V0-V3 の Y 座標の差の絶対値 ABS(Y0-Y3) と V1-V2 の Y 座標の差の絶
対値 ABS(Y1-Y2) を比較し, 絶対値の小さい方の対角線に沿って 4 角形を 2 
つの 3 角形に分割描画するように ZObject のデータを入れ替えれば良いです.
以下のアルゴリズムを参考にしてください.

    |
    |   zShQuad  *zquad;
    |
    |   if (ABS(Y0-Y3) > ABS(Y1-Y2)){
    |       /* 対角線 V1-V2 で分割し, V0-V1-V2 と V1-V2-V3 に分割 */
    |       zquad->t.v[0] = V0;  zquad->t.v[1] = V1;
    |       zquad->t.v[2] = V2;  zquad->t.v[3] = V3;
    |   } else {
    |       /* 対角線 V0-V3 で分割し, V1-V0-V3 と V0-V3-V2 に分割 */
    |       zquad->t.v[0] = V1;  zquad->t.v[1] = V0;
    |       zquad->t.v[2] = V3;  zquad->t.v[3] = V2;
    |   }
    |

  ただしこのときは, どちらの対角線が分割線として選択されるか分からない
ので, どちらの対角線で分割されても問題が無いように, 指定された 4 頂点
は同一平面上になければなりません. またテクスチャ使用時あるいはスムース
シェード時には, テクスチャ座標値(s,t) あるいは カラー値(r,g,b,a) に矛
盾が生じないように値を設定する必要があります. (サンプルプログラム 
cubes-1 は良くない見本も含まれています ;-).)

  テクスチャマップ使用時について具体的に説明すると,
v0(x0,y0,z0,s0,t0), v1(x1,y1,z1,s1,t1), v2(x2,y2,z2,s2,t2),
v3(x3,y3,z3,s3,t3) において, ベクトル V1,V2,V3 を
        
   V1 = (v1 - v0), V2 = (v2 - v0), V3 = (v3 - v0)
        
と定義したときに, 
        
   V2 = a * V1 + b * V3
        
を満たす実係数 a, b が存在する必要があります. 幾何学的には s, t を含め
た 5 次元座標空間上において 4 頂点が同一平面上にあることが必要となりま
す.
        
  同様に smooth shading や lighting を使用する際には, カラー値(r,g,b)
または法線ベクトル(nx,ny,nz)について上記の関係を満たさなけばなりません.

  例えば以下の onetri における頂点データは Quadrangle には不向きです. 
        
  onetri/static.c:
        static Vtx shade_vtx[] =  {
        {        -64,  64, -5, 0, 0, 0,    0, 0xff,    0, 0xff  },
        {         64,  64, -5, 0, 0, 0,    0,    0,    0, 0xff  },
        {         64, -64, -5, 0, 0, 0,    0,    0, 0xff, 0xff  },
        {        -64, -64, -5, 0, 0, 0, 0xff,    0,    0, 0xff  },
        };                              ^^^^^^^^^^^^^^^^
                                                       この部分
  これが以下であれば問題はありません. 

        static Vtx shade_vtx[] =  {
        {        -64,  64, -5, 0, 0, 0,    0, 0xff,    0, 0xff  },
        {         64,  64, -5, 0, 0, 0,    0,    0,    0, 0xff  },
        {         64, -64, -5, 0, 0, 0,    0,    0, 0xff, 0xff  },
        {        -64, -64, -5, 0, 0, 0,    0, 0xff, 0xff, 0xff  },
        };                              ^^^^^^^^^^^^^^^^
        
  すなわち, 頂点間において値が連続的に変化する場合に注意を払う必要があ
るということです. このため頂点間においてカラー値が変化しない Flat
Shading については問題にはなりません.

  zShQuad でも他の ZObject と同様に 4 角形の裏表によるカリング処理は行
ないません. CPU が ZObject データを作成するときにこの判定をしてくださ
い.

  メンバー変数 header は ZObject がリスト構造で連なるときに, 次の 
ZObject へのポインタ等を保持します. もし次の ZObject が無い場合は,
G_ZOBJ_NONE を代入してください.

  メンバー変数 rdpcmd1 は現在の RDP の処理モードを変更するために使用し
ます. ZObject を描画する前に RDP へ送られる RDP コマンド列をここに指定
します. rdpcmd1 についての詳細は 3.5 項で説明します.

---------------------
3.4.3  zTxTri 構造体

  zTxTri 構造体は, テクスチャ付のスムースシェード処理された 3 角形を
描画するためのデータ構造体です. その形状を指定するために以下のような 
zTxVtx 型の頂点データを 3 組必要とします.

	----------------------------------------------------------------
	typedef struct  {
	  s16   x, y;		/* 頂点のスクリーン座標       (s10.2) */
	  u8    r, g, b, a;	/* 頂点におけるカラー 各 0..255       */
	  s16   s, t;		/* 頂点におけるテクスチャ座標 (s10.5) */
	  s32   invw;		/* テクスチャパースペクティブ補正処理
	                           パラメータ 1/W (s15.16)            
				   (視点からの距離の逆数に比例)       */
	} zTxVtx;
	----------------------------------------------------------------

  メンバー変数 invw は, 各頂点の座標値 (x,y,z,1) に MP 行列を乗じた後
の座標値 (X,Y,Z,W) の W から以下のように求めます. ただし perspNorm は 
guPerspective 関数で取得できる透視変換正規化パラメータです.

	invw = (1<<30)/(perspNorm * W);

  RDP はこの値を使用して, テクスチャのパースペクティブ補正を行ないます.
マイクロコードの算術演算処理 GBI ではこの値を透視変換と同時に求めるこ
とができます.

  zTxVtx 構造体は以下のようなデータ形式をとります.

            +0          +4          +8          +c       +f
           +-----------+-----------+-----------+-----------+
           |    Hdr    | RDP cmd 1 | RDP cmd 2 | RDP cmd 3 |
           +-----+-----+--+--+--+--+-----+-----+-----------+
        V0 |  X  |  Y  |R |G |B |A |  S  |  T  |   invW    |
           +-----+-----+--+--+--+--+-----+-----+-----------+
        V1 |  X  |  Y  |R |G |B |A |  S  |  T  |   invW    |
           +-----+-----+--+--+--+--+-----+-----+-----------+
        V2 |  X  |  Y  |R |G |B |A |  S  |  T  |   invW    |
           +-----+-----+--+--+--+--+-----+-----+-----------+

	-------------------------------------------------------------
	typedef struct  {
	  zHeader       *header;	/* 次の ZObject の情報  */
	  Gfx           *rdpcmd1;	/* 前処理 DP コマンド 1 */
	  Gfx           *rdpcmd2;	/* 前処理 DP コマンド 2 */
	  Gfx           *rdpcmd3;	/* 前処理 DP コマンド 3 */
	  zTxVtx        v[3];		/* 頂点データ           */
	} zTxTri_t;
	
	typedef struct  {		/* ワードアクセス用構造体 */
	  zHeader       *header;	
	  Gfx           *rdpcmd1;	
	  Gfx           *rdpcmd2;
	  Gfx           *rdpcmd3;
	  u32           xy0, clr0, st0, invw0;
	  u32           xy1, clr1, st1, invw1;
	  u32           xy2, clr2, st2, invw2;
	} zTxTri_w;
	
	typedef union   {
	  zTxTri_t      t;
	  zTxTri_w      w;
	  u64           force_structure_alignment;
	} zTxTri;
	-------------------------------------------------------------

  zTxTri でも他の ZObject と同様に 3 角形の裏表によるカリング処理は行
ないません. CPU が ZObject データを作成するときにこの判定をしてくださ
い.

  メンバー変数 header は ZObject がリスト構造で連なるときに, 次の 
ZObject へのポインタ等を保持します. もし次の ZObject が無い場合は,
G_ZOBJ_NONE を代入してください.

  メンバー変数 rdpcmd1,2,3 は現在の RDP の処理モードを変更したり, テク
スチャをロードするために使用します. ZObject を描画する前に RDP へ送ら
れる RDP コマンド DL 列 3 組をここに指定します. rdpcmd1,2,3 についての
詳細は 3.5 項で説明します.

----------------------
3.4.4  zTxQuad 構造体

  zTrQuad 構造体は, テクスチャ付のスムースシェード処理された 4 角形
を描画するためのデータ構造体です. その形状を指定するために前項で説明し
た zTxVtx 型の頂点データを 4 組必要とします.

  zTxQuad では 3 角形 V0-V1-V2 と V1-V2-V3 の 2 つの 3 角形を描画する
ことで, 4 角形の描画を行ないます.

	V0+--------+V1
          |      /|
          |    /  |
          |  /    |
          |/      |
        V2+--------+V3

  zTxVtx 構造体は以下のようなデータ形式をとります.

            +0          +4          +8          +c       +f
           +-----------+-----------+-----------+-----------+
           |    Hdr    | RDP cmd 1 | RDP cmd 2 | RDP cmd 3 |
           +-----+-----+--+--+--+--+-----+-----+-----------+
        V0 |  X  |  Y  |R |G |B |A |  S  |  T  |   invW    |
           +-----+-----+--+--+--+--+-----+-----+-----------+
        V1 |  X  |  Y  |R |G |B |A |  S  |  T  |   invW    |
           +-----+-----+--+--+--+--+-----+-----+-----------+
        V2 |  X  |  Y  |R |G |B |A |  S  |  T  |   invW    |
           +-----+-----+--+--+--+--+-----+-----+-----------+
        V3 |  X  |  Y  |R |G |B |A |  S  |  T  |   invW    |
           +-----+-----+--+--+--+--+-----+-----+-----------+

	-------------------------------------------------------------
	typedef struct  {
	  zHeader       *header;	/* 次の ZObject の情報  */
	  Gfx           *rdpcmd1;	/* 前処理 DP コマンド 1 */
	  Gfx           *rdpcmd2;	/* 前処理 DP コマンド 2 */
	  Gfx           *rdpcmd3;	/* 前処理 DP コマンド 3 */
	  zTxVtx        v[4];		/* 頂点データ           */
	} zTrQuad_t;
	
	typedef struct  {		/* ワードアクセス用構造体 */
	  zHeader       *header;	
	  Gfx           *rdpcmd1;	
	  Gfx           *rdpcmd2;
	  Gfx           *rdpcmd3;
	  u32           xy0, clr0, st0, invw0;
	  u32           xy1, clr1, st1, invw1;
	  u32           xy2, clr2, st2, invw2;
	  u32           xy3, clr3, st3, invw3;
	} zTrQuad_w;
	
	typedef union   {
	  zTrQuad_t      t;
	  zTrQuad_w      w;
	  u64           force_structure_alignment;
	} zTrQuad;
	-------------------------------------------------------------

  zTxQuad を使用するメリットおよび, パフォーマンスを引き出すための技法
については zShQuad についての説明を参考にしてください.

  zTxQuad でも他の ZObject と同様に 4 角形の裏表によるカリング処理は行
ないません. CPU が ZObject データを作成するときにこの判定をしてくださ
い.

  メンバー変数 header は ZObject がリスト構造で連なるときに, 次の 
ZObject へのポインタ等を保持します. もし次の ZObject が無い場合は,
G_ZOBJ_NONE を代入してください.

  メンバー変数 rdpcmd1,2,3 は現在の RDP の処理モードを変更したり, テク
スチャをロードするために使用します. ZObject を描画する前に RDP へ送ら
れる RDP コマンド DL 列 3 組をここに指定します. rdpcmd1,2,3 についての
詳細は 3.5 項で説明します.

--------------------
3.4.5  zNull 構造体

  zNull 構造体は, 3 角形や 4 角形というような, いわゆるポリゴンと呼ば
れる形状の描画を行なうためのものではなく, RDP に対し直接コマンドを送る
ことで描画される矩形領域 (FillRectangle, TextureRectangle) の描画のた
めに用意されたものです.

  実際は, 矩形領域を描画するためのコマンドだけでなく, どのような RDP 
コマンドでも設定可能です. よって Fog カラーや Primitive カラーを変更す
るだけで何も描画しないという ZObject も作成できます.

            +0          +4          +8          +c       +f
           +-----------+-----------+-----------+-----------+
           |    Hdr    | RDP cmd 1 | RDP cmd 2 | RDP cmd 3 |
           +-----------+-----------+-----------+-----------+
        
	-------------------------------------------------------------
	typedef struct  {
	  zHeader       *header;
	  Gfx           *rdpcmd1;
	  Gfx           *rdpcmd2;
	  Gfx           *rdpcmd3;
	} zNull_t;
	
	typedef union   {
	  zNull_t       t;
	  u64           force_structure_alignment;
	} zNull;
	-------------------------------------------------------------

  メンバー変数 header は ZObject がリスト構造で連なるときに, 次の 
ZObject へのポインタ等を保持します. もし次の ZObject が無い場合は,
G_ZOBJ_NONE を代入してください.

  メンバー変数 rdpcmd1,2,3 に RDP へ送る RDP コマンド列へのポインタを
指定します. これについての説明は, 3.5 項で説明します.

------------------------------------------------
3.5  RDPcmd パラメータによる RDP コマンドの制御

  ZObject の各構造体には, 1 つまたは 3 つの RDP Cmd 領域があります.
このメンバー変数で ZObject 描画中の RDP の状態を変更することができます.

  RDP の状態を変更するためには, GBI コマンドを羅列した専用の DL を使い
ます. このことを RDP コマンド列と呼びます. 

  RDP コマンド列には主に RDP の状態を制御するためのコマンドしか含むこ
とができません. すなわち, RDP コマンド列として使用可能な GBI には制限
があるのです. この RDP コマンド列と使用可能な GBI を以下に示します.
以下の表の GBI コマンドの動作は Fast3D 互換マイクロコードと同じです.
表記以外の GBI コマンドを RDP コマンド列として使用したときの動作は保証
しません.

       ---------------------------------------------------------
	RDP コマンド列に使用可能な GBI コマンド
       ---------------------------------------------------------
	gSPNoOp				gDPNoOp
	gSPEndDisplayList

	gDPFillRectangle
	gSPTextureRectangle		gSPTextureRectangleFlip

	gDPSetColorImage		gDPSetDepthImage
	gDPSetTextureImage		gDPSetScissor

	gDPSetFillColor			gDPSetEnvColor
	gDPSetFogColor			gDPSetBlendColor
	gDPSetPrimColor			gDPSetPrimDepth
	
	gDPSetCombineMode		gDPSetConvert
	gDPSetKeyR			gDPSetKeyGB

	gDPSetOtherMode
	gDPPipelineMode(*)		gDPSetCycleType(*)
	gSPSetTexturePersp(*)		gDPSetTextureDetail(*)
	gDPSetTextureLOD(*)		gDPSetTextureLUT(*)
	gDPSetTextureFilter(*)		gDPSetTextureConvert(*)
	gDPSetCombineKey(*)		gDPSetColorDither(*)
	gDPSetAlphaDither(*)		gDPSetAlphaCompare(*)
	gDPSetDepthSource(*)		gDPSetRenderMode(*)

	gDPSetTile			gDPSetTileSize

	gDPLoadBlock
	gDPLoadTextureBlock		gDPLoadTextureBlockS
	gDPLoadTextureBlock_4b		gDPLoadTextureBlock_4bS
	gDPLoadTextureBlockYuv		gDPLoadTextureBlockYuvS
	gDPLoadMultiBlock		gDPLoadMultiBlockS
	gDPLoadMultiBlock_4b		gDPLoadMultiBlock_4bS

	gDPLoadTile
	gDPLoadTextureTile		gDPLoadTextureTile_4b
	gDPLoadMultiTile		gDPLoadMultiTile_4b

	gDPLoadTLUT
	gDPLoadTLUT_pal16		gDPLoadTLUT_pal256

	gDPLoadSync			gDPPipeSync
	gDPTileSync			gDPFullSync
       ---------------------------------------------------------
	
  大きな注意点として, gSPSegment が使用できないことに注意してください.
gDPSetColorImage などにセグメントアドレスを使用することはできますが, 
その値の設定は RDP コマンド列ではできません. また gSPBranchDL や 
gSPDisplayList も使用できませんのでご注意ください. 

  rdpcmd1, rdpcmd2, rdpcmd3 の 3 つの RDP Cmd 領域は以下のように使われ
ることを想定しています.

    rdpcmd1: RDP のレンダリングモードの設定用.
    rdpcmd2: TMEM へのロード用 (主に TMEM 全体/ TMEM 前半部へのロード)
    rdpcmd3: TMEM へのロード補助用 (主に TLUT / TMEM 後半部へのロード)

  こうした想定のため, テクスチャなしの図形 (zShTri, zShQuad) の描画で
は rdpcmd1 だけを使用し, テクスチャありの図形 (zTxTri, zTxQuad) は, 3 
つ全てを指定できるようになっています.

  Z Sort マイクロコードの場合, Z Buffer 機能を使用したマイクロコードと
異なり, 画面深度順で描画されることになるため, 同じテクスチャを持つポリ
ゴンのみを連続して描画できません. このため, Z Sort マイクロコードでは, 
各 ZObject にテクスチャ情報を与える必要があります. ただし既に TMEM へ
ロードされているテクスチャと同じテクスチャをロードするという無駄を小さ
くするための機構を用意しています.

  これは直前に処理した RDP コマンド列へのポインタを記憶しておき, それ
と今回の ZObject で処理する RDP コマンド列へのポインタを比較し, 異なっ
ているときのみ RDP へ送るという処理です.

  マイクロコードは rdpcmd1,rdpcmd2,rdpcmd3 のそれぞれに対応した RDP コ
マンドポインタの記憶領域 (ここでは仮に rdpcmd1_save, rdpcmd2_save,
rdpcmd3_saveと呼びます) を DMEM 内に用意しています. 以下はそれぞれの処
理のアルゴリズムを C 言語風に記述したものです.

------------------------------------------------
 o zShTri, zShQuad の場合 (RDP Cmd 領域が 1 つ)

    |
    |    if (rdpcmd1 != rdpcmd1_save){
    |      rdpcmd1 で示される RDP コマンド列の処理;
    |      rdpcmd1_save = rdpcmd1;
    |    }
    |    ZObject の描画;
    |

      rdpcmd1 には通常, RenderMode の切り替え用の RDP コマンド列を設定
    します. 以下は rdpcmd1 に指定する RDP コマンド列のサンプルです.
      gsDPSetOtherMode は幾つかの DP モードの設定を一度に行なうための 
    GBI です. 沢山の RDP コマンドを 1 命令で処理することができるのでな
    るべくこのコマンドを使用する方が処理速度に関して有利です. 上記の 
    RDP コマンド列に使用できる GBI の表において (*) の印が付いているコ
    マンドは gDPSetOtherMode でまとめて処理可能です.

    |
    |#define OTHERMODE_A(cyc)  (G_CYC_##cyc##|G_PM_1PRIMITIVE|G_TP_PERSP|\
    |                           G_TD_CLAMP|G_TL_TILE|G_TT_NONE|G_TF_BILERP|\
    |                           G_TC_FILT|G_CK_NONE|G_CD_DISABLE|G_AD_DISABLE)
    |#define OTHERMODE_B(rm)   (G_AC_NONE|G_ZS_PRIM|G_RM_##rm##|G_RM_##rm##2)
    |
    |/*------ Shade Triangle モード切り替え ------*/
    |Gfx     modeShTri[] = {
    |  gsDPPipeSync(),
    |  gsDPSetOtherMode(OTHERMODE_A(1CYCLE), OTHERMODE_B(RA_OPA_SURF)),
    |  gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
    |  gsSPEndDisplayList(),
    |};
    |

------------------------------------------------
 o zTxTri, zTxQuad の場合 (RDP Cmd 領域が 3 つ)

    |
    |    if (rdpcmd1 != rdpcmd1_save){
    |      rdpcmd1_save = rdpcmd1;
    |      rdpcmd1 で示される RDP コマンド列の処理;
    |    }
    |    if (rdpcmd2 != rdpcmd2_save){
    |      rdpcmd2_save = rdpcmd2;
    |      rdpcmd2 で示される RDP コマンド列の処理;
    |    }
    |    if (rdpcmd3 != rdpcmd3_save){
    |      rdpcmd3_save = rdpcmd3;
    |      if (rdpcmd3 != NULL){
    |         rdpcmd3 で示される RDP コマンド列の処理;
    |      }
    |    }
    |

      rdpcmd1 には, zShTri, zShQuad と同様に, RenderMode の切り替え用
    の RDP コマンド列を設定します. 以下は rdpcmd1 に指定する RDP コマ
    ンド列のサンプルです. 4b CI テクスチャにおけるパレットの切り替え等
    もここに含めると良いでしょう.

    |
    |/*------ Textured Triangle モード切り替え ------*/
    |Gfx     modeTxTri1[] = {
    |  gsDPPipeSync(),
    |  gsDPSetOtherMode(OTHERMODE_A(1CYCLE), OTHERMODE_B(RA_OPA_SURF)),
    |  gsDPSetCombineMode(G_CC_MODULATERGB, G_CC_MODULATERGB),
    |  gsSPEndDisplayList(),
    |};
    |

      rdpcmd2 にはテクスチャロード用の RDP コマンドを設定します.
    以下は rdpcmd2 に指定する RDP コマンド列のサンプルです.

    |
    |Gfx     modeTxTri2[] = {
    |  gsDPPipeSync(),
    |  gsDPLoadTextureBlock(brick, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, 0,
    |                       G_TX_WRAP | G_TX_MIRROR, G_TX_WRAP | G_TX_MIRROR,
    |                       5, 5, G_TX_NOLOD, G_TX_NOLOD),
    |  gsSPEndDisplayList(),
    |};
    |

      rdpcmd3 も rdpcmd2 と同様に設定します. rdpcmd3 は TLUT のロード
    用として使用することを想定していますが, テクスチャのロード用として
    も使用できます.

      もし rdpcmd3 が必要ないならNULL(=0x00000000) を代入します. 
    このとき, rdpcmd3_save は NULL で *クリア* されますが, rdpcmd3 で
    示される RDP コマンドの処理は行ないません.

--------------------------------------
 o zNull の場合 (RDP Cmd 領域が 3 つ)

    |
    |    if (rdpcmd1 != NULL && rdpcmd1 != rdpcmd1_save){
    |      rdpcmd1_save = rdpcmd1;
    |      rdpcmd1 で示される RDP コマンド列の処理;
    |    }       
    |    if (rdpcmd2 != NULL && rdpcmd2 != rdpcmd2_save){
    |      rdpcmd2_save = rdpcmd2;
    |      rdpcmd2 で示される RDP コマンド列の処理;
    |    }       
    |    if (rdpcmd3 != NULL && rdpcmd3 != rdpcmd3_save){
    |      rdpcmd3_save = rdpcmd3;
    |      rdpcmd3 で示される RDP コマンド列の処理;
    |    }       
    |

      zNull に関しては特に想定していることはありません. ご自由にお使い
    下さい. 上記のアルゴリズムを見て判るように, rdpcmd に対して NULL
    (=0x00000000) を設定するとその RDP コマンドの処理をしません. この
    とき対応する rdpcmd_save の値は *保存* されます. (NULL 指定時に
    *保存* されることが, zTxTri, zTxQuad の rdpcmd3 の処理 (クリアされ
    る)と異なるのでご注意ください.)

--------------------------------------
3.6  画面クリアおよびその他の描画処理

  ZSort マイクロコードを使用する上で注意しなければならない点の 1 つに,
通常の DisplayList に直接 RDP コマンドを書き込むことができないことが挙
げられます.  これは, SP のコマンドの処理と DP のコマンドの処理とが内部
的に分れていることによります. これによりマイクロコードの命令数と処理速
度を稼いでいます.

  通常, 画面クリアなどの背景を塗り潰すような処理は, 全ての ZObject の
描画処理前に行なう必要があり, Fast3D 互換マイクロコードでは通常そうし
た GBI 列を static な領域に作成しておき, DisplayList 側から呼び出して
います.

  ZSort マイクロコードでは, 前述した画面クリアなどの DP の動作を制御す
るための RDP コマンド列を通常の DisplayList から呼び出すため, 以下の 
GBI コマンドが用意されています. この RDP コマンド列に使用可能な GBI コ
マンドには, ZObject の描画中に使用されるものと同じ制限があります. 前出
の表を参考にしてください. 具体的な使用例は, サンプルプログラム cubes-1 
を参照してください.

------------------------------------------------------------------------------
 * gSPZRdpCmd(Gfx *gp, Gfx *rdpcmd)

	rdpcmd	RDP コマンド列へのポインタ

	RDP コマンド列を処理する. ただし呼び出される RDP コマンドには
	制限がある. (3.5 項 RDP コマンド列に使用可能な GBI コマンドの表を参照)


	
===============================================================================
4. 算術演算処理
===============================================================================

-----------------------
4.1 表示物体と算術演算

  ZSort マイクロコードで描画可能な多角形は zShTri, zShQuad, zTxTri,
zTxQuad の 4 種類であることは前章で述べた通りです. 一見すると少ないよ
うに見えますが, これと算術演算を組み合わせると様々な描画方法ができるよ
うになります. 本マイクロコードで処理可能な演算の主なものは以下の 3 つ
です.

 ----------------------------------------------------------------
 (演算 A) --- gSPZMultMPMtx ---

    モデル座標頂点データ +
    MxP マトリクス       ==> スクリーン座標頂点データ

 ----------------------------------------------------------------
 (演算 B) --- gSPZLight / gSPZLightMaterial ---

    法線ベクトルデータ   +
    マテリアルデータ     +
    ライトデータ         +
    ModelView マトリクス ==> カラーデータ

 ----------------------------------------------------------------
 (演算 C) --- gSPZLight / gSPZLightMaterial ---

    法線ベクトルデータ   +
    視線(LookAt)データ   +
    ModelView マトリクス ==> テクスチャ座標(環境マップ)データ

 ----------------------------------------------------------------

  全ての多角形 ZObject において (演算 A) を行なってスクリーン座標頂点
データを求める必要があります. また, ライト処理を行なう場合には (演算 B)
を, 環境マップ処理を行なう場合には (演算 C) を行なう必要があります. 

  ただし, 上記の演算 A,B,C を行なう各 GBI (gSPZMultMPMtx, gSPZLight /
gSPZLightMaterial) はそれだけでは機能しません. 実際に演算を行なう GBI 
の前には頂点のデータと変換パラメータ(行列など)を用意して RSP の DMEM 
にロードする処理を行なう必要があり, また演算の後には演算結果を DMEM か
ら DRAM へ書き戻す必要があります. 

--------------------------------
4.2 DMEM 内の演算用ワークエリア

  ZSort マイクロコードには, RSP によって 3 次元モデル座標のスクリーン
座標系への変換処理やライティング計算やマトリクス演算を行なうために特化
された算術演算専用の GBI が用意されています. 

  この演算処理を *複数個組み合わせる* ことで ZObject をスクリーンに描
画するために必要な座標値やカラー値などの値を取得することになります.

  例えば, モデル座標をスクリーン座標に変換するには以下のような GBI コ
マンドを組み合わせて処理します.

 (1) gSPZViewport       VIEWPORT の設定をする.
 (2) gSPZPerspNormalize パース正規化係数を設定する.
 (3) gSPZSetMtx         PROJECTION 行列を DMEM 内のワークエリアにロード.
 (4) gSPZSetMtx         MODELVIEW  行列を DMEM 内のワークエリアにロード.
 (5) gSPZMtxCat         MODELVIEW 行列と PROJECTION 行列を乗算.
 (6) gSPZSetUMem        DRAM 内のモデル座標値を DMEM 内のワークエリアにロード.
 (7) gSPZMultMPMtx      モデル座標値をスクリーン座標値に変換.
 (8) gSPZGetUMem        スクリーン座標値を DRAM へ出力.

  ZSort マイクロコードでは算術演算処理において使用するためのワークエリ
アを DMEM 内に確保しています. ワークエリアにはマトリクス用と汎用の 2 
種類あり, それぞれ以下のような大きさとなっています. また汎用ワークエリ
アのことをユーザエリアと呼びます. 

	------------------------------------------
	o 汎用ワークエリア
	  (ユーザエリア)              計 2048Bytes
	------------------------------------------
	o マトリクス用のワークエリア  計  192Bytes
	      (内訳)  ModelView  用        64Bytes
	              Projection 用        64Bytes
	              M x P      用        64Bytes
	------------------------------------------

  ユーザエリアは 0 から 2047 番地まであり, これをどのように使うかは, 
アプリケーション作成者が任意に決めることができます.

  サンプルプログラム cubes-1 の libzsort では, 以下のようにユーザエリ
アを使っています. 領域が重なっていますが時系列的に異なるので問題ありま
せん. 参考にしてください.

  ------------------------------------------------------------------
  1200-1919: モデル座標値ソース保持用               (120 組保持可能)
     0-1919: スクリーン座標値計算結果保持用         (120 組保持可能)
     0- 383: 法線ベクトルソース保持用               (128 組保持可能)
   512-1023: マテリアルカラーソース保持用           (128 組保持可能)
   512-1023: ライティング計算結果保持用             (128 組保持可能)
  1024-1535: 環境テクスチャマップ座標計算結果保持用 (128 組保持可能)
  1920-2047: ライトデータ保持用
		(DEFUSE ライト 3 個 + AMBIENT 1 個 + 環境マップ)
  ------------------------------------------------------------------

  ユーザエリアはユーザが自由に割り振って使用することができますが, マト
リクス用のエリアはマトリクスデータを保持するために用意されたものなので
通常, 他の目的に使用するべきではありません. また番地を指定することで細
かな割り振りが可能なユーザエリアに対して, マトリクス用エリアは基本的に
その領域 ID (GZM_MMTX, GZM_PMTX, GZM_MPMTX) の内の 1 つを指定します.
ただしユーザエリアの先頭の 0〜63 番地 と 64〜127 番地をマトリクス用に
使用することは可能です. よって, マトリクス領域として以下のような 5 つ
を使用することができます. ただし, ModelView/Projection/MxP の各マトリ
クス領域の名称は理解を助けるために仮に名付けたもので, それぞれの領域に
機能上の違いはありません. 混乱を求めるなら, MxP マトリクス領域に 
ModelView マトリクスを代入して使用することも可能です.

	--------------------------------------------
	 GZM_MMTX	ModelView  マトリクス領域
	 GZM_PMTX	Projection マトリクス領域
	 GZM_MPMTX	M x P 用   マトリクス領域
	 GZM_USER0	ユーザエリア  0〜 63 番地
	 GZM_USER1	ユーザエリア 64〜127 番地
	--------------------------------------------

  算術演算用 GBI は Main DL, Sub DL のどちらでも動作しますが, Main DL 
と Sub DL 双方でユーザエリアを読み書きするようにしたときには注意が必要
です. Main DL と Sub DL とで並列処理を行なった場合, Main DL の GBI で
計算したデータを Sub DL の GBI が破壊してしまうといったことが起こり得
ます. このため, Main DL, Sub DL の双方でユーザエリアにアクセスすること
はお勧めしません. また, それほどメリットもないので, Main DL と Sub DL 
のどちらが算術演算を行なうかを固定する方がよいでしょう.

--------------
4.3  GBI 一覧

  算術演算用 GBI の一覧です.

    ----------------------------------------------------------------
    gSPZSetUMem		- ユーザエリアへデータを書き込む.
    gSPZGetUMem		- ユーザエリアのデータを読み出す.
    gSPZSetMtx		- マトリクスを書き込む.
    gSPZGetMtx		- マトリクスを読み出す.
    gSPZMtxCat		- マトリクスを乗ずる.
    gSPZMtxTrnsp3x3	- マトリクスの 3x3 要素を転置する.
    gSPZViewport	- VIEWPORT を設定する.
    gSPZMultMPMtx	- モデル座標値をスクリーン座標値に変換する.
    gSPZSetAmbient	- Ambient ライト(環境光)を書き込む.
    gSPZSetDefuse	- Defuse  ライト(拡散光)を書き込む.
    gSPZSetLookAt	- LookAt 構造体データを書き込む.
    gSPZXfmLights	- ライトパラメータの前処理を行なう.
    gSPZLight		- ライト計算を行なう.
    gSPZLightMaterial	- マテリアルを考慮したライト計算を行なう.
    gSPZMixS16		- s16 型の数値の補間を行なう.
    gSPZMixS8		- s8  型の数値の補間を行なう.
    gSPZMixU8		- u8  型の数値の補間を行なう.
    ----------------------------------------------------------------

--------------------
4.4  GBI の機能解説

  この項では算術演算用 GBI の解説をします. 

------------------------------------------------------------------------------
 * gSPZSetUMem(Gfx *gp, u32 umem, u32 size, u64 *adrs)

	umem	書き込み先のユーザエリアの番地 (0 〜 2040)
	size	書き込むサイズ (8 〜 2048)
	adrs	DRAM 上の書き込み元へのポインタ

	  ユーザエリアへデータを書き込む. umem, size は 8 の倍数でなけ
	ればいけません. また adrs は 8 Bytes 境界になければなりません.
	もし, 10 Bytes 分のデータが必要な場合は, 16 Bytes を指定します.

------------------------------------------------------------------------------
 * gSPZGetUMem(Gfx *gp, u32 umem, u32 size, u64 *adrs)

	umem	読み出し元のユーザエリアの番地 (0 〜 2040)
	size	読み出すサイズ (8 〜 2048)
	adrs	DRAM 上の読み出し先へのポインタ

	  ユーザエリアからデータを読み出す. umem, size は 8 の倍数でな
	ければいけません. また adrs は 8 バイト境界になければなりません.

------------------------------------------------------------------------------
 * gSPZSetMtx(Gfx *gp, u32 mid, Mtx *mptr)

	mid	書き込み先のマトリクス領域.
	mptr	DRAM 上の書き込み元へのポインタ.

	  マトリクス領域へ DRAM 上のマトリクスデータを書き込みます. 一
	般的に mid には GZM_MMTX, GZM_PMTX, GZM_MPMTX のうちの 1 つを
	指定します. ただし, ユーザエリアの先頭の 128Bytes 分を使用する
	ことも可能です. そのときは GZM_USER0, GZM_USER1 を指定します. 
	これによりユーザエリアの 0 〜 63 番地 と 64 〜 127 番地をマト
	リクス領域として使用できます.

------------------------------------------------------------------------------
 * gSPZGetMtx(Gfx *gp, u32 mid, Mtx *mptr)

	mid	読み出し元のマトリクス領域.
	mptr	DRAM 上の書き込み元へのポインタ.

	  マトリクス領域から DRAM 上へマトリクスデータを読み出します. 一
	般的に mid には GZM_MMTX, GZM_PMTX, GZM_MPMTX のうちの 1 つを
	指定します. ただし, ユーザエリアの先頭の 128Bytes 分を使用するこ
	とも可能です. そのときは GZM_USER0, GZM_USER1 を指定します. 
	これによりユーザエリアの 0 〜 63 番地 と 64 〜 127 番地をマト
	リクス領域として使用できます.

------------------------------------------------------------------------------
 * gSPZMtxCat(Gfx *gp, u32 mids, u32 midt, u32 midd)

	mids	マトリクス領域 S.
	midt	マトリクス領域 T.
	midd	マトリクス領域 D.
	
	  (マトリクス D) = (マトリクス S) x (マトリクス T) を計算します. 
	mids,midt,midd は一般的に GZM_MMTX, GZM_PMTX, GZM_MPMTX のうち
	の 1 つを指定します. ただし, ユーザエリアの先頭の 128Bytes 分
	を使用することも可能です. そのときは GZM_USER0, GZM_USER1 を指
	定します. これによりユーザエリアの 0 〜 63 番地 と 64 〜 127 
	番地をマトリクス領域として使用できます.

	  ただし, マトリクス T の領域と マトリクス D の領域は同じ場合
	には正常な動作は保証できません. S と D あるいは S と T は同じ
	領域でも問題はありません.

------------------------------------------------------------------------------
 * gSPZMtxTrnsp3x3(Gfx *gp, u32 mid)

	mid	転置させるマトリクス領域.
	
	  マトリクスの (x,y,z) の 3x3 の要素を転置させます.
	もし, マトリクスが回転行列である場合, 転置させた結果は元のマト
	リクスの逆回転を意味することになります. こうして転置されたマト
	リクスは, 主にライトの処理に使われます.

		|00 01 02 03|      |00 10 20 03|
		|10 11 12 13|  ->  |01 11 21 13|
		|20 21 22 23|      |02 12 22 23|
		|30 31 32 33|      |30 31 32 33|

	  mid には一般的に GZM_MMTX, GZM_PMTX, GZM_MPMTX のうちの 1 つ
	を指定します. ただし, ユーザエリアの先頭の 128Bytes 分を使用す
	ることも可能です. そのときは GZM_USER0, GZM_USER1 を指定します. 
	これによりユーザエリアの 0 〜 63 番地 と 64 〜 127 番地をマト
	リクス領域として使用できます.

------------------------------------------------------------------------------
 * gSPZViewPort(Gfx *gp, Vp *vp)

	vp	VIEWPORT データへのポインタ.

	  本 GBI は F3DEX 等における gSPViewPort GBI とほぼ同じで,
	VIEWPORT を設定するものですが, VIEWPORT データのパラメータに違
	いがあります. ZSort マイクロコードでは Vp 構造体のメンバ変数で
	ある vscale, vtrans の vscale[3] と vtrans[3] に Fog を制御す
	るためのパラメータを指定します. この指定のために以下のマクロを
	用意しています.

		vp->vp.vscale[3] = GZ_VIEWPORT_FOG_S(in, out);
		vp->vp.vtrans[3] = GZ_VIEWPORT_FOG_T(in, out);

			in:  Fog 開始距離
			out: Fog 終了距離		
	
	  また, 画面の上方を正の方向にするために vscale[1] の値には, 
	負の値を設定する必要があります. これにより, 右, 上, 手前が正の
	方向となります. (右手系)

	  具体的には, 視点からの距離 3000 から Fog を開始し, 距離 4000 
	で背景色と等しくなるという指定をするときは, 以下のように初期化
	します.

	Vp      viewport = {
	  SCREEN_WD*2, -SCREEN_HT*2, G_MAXZ/2, GZ_VIEWPORT_FOG_S(3000, 4000),
	  SCREEN_WD*2,  SCREEN_HT*2, G_MAXZ/2, GZ_VIEWPORT_FOG_T(3000, 4000),
	};

------------------------------------------------------------------------------
 * gSPZMultMPMtx(Gfx *gp, u32 mid, u32 src, u32 num, u32 dest)

	mid	MxP マトリクス.
	src	頂点のモデル座標値が格納されているユーザエリアの先頭番地
	num	処理する頂点数.
	dest	座標変換後の頂点のスクリーン座標値を格納するユーザエリア
	    	の先頭番地

	  ユーザエリアの src の位置におけるデータを 16bit の x,y,z 値
	とみなし mid で指定した 4x4 行列をかけ, その結果の (X,Y,Z,W) 
	を W=1 で正規化します. その後, 得られた座標に対して ViewPort 
	変換を行なうことでスクリーン座標値を取得します. またこのとき 
	FOG パラメータやクリッピング処理用フラグも計算し, それらのデー
	タをまとめて dest の位置へ出力します. その後 src に 6 を加算,
	dest に 16 を加算し次の頂点へ進みます. num 個の頂点を連続して
	処理します.

	  ここでの入力と出力の座標値のフォーマットは, ヘッダファイル 
	gzsort.h 内の zVtxSrc 構造体と zVtxDest 構造体で以下のように定
	義されています.
	
	-------------------------------------------------------------------
	  typedef struct  {
	    s16   x, y, z;	/* 頂点のモデル座標値 (s10.2)		*/
	  } zVtxSrc;		/* サイズ  6 Bytes			*/

	  typedef struct  {
	    s16   sx, sy;	/* 頂点のスクリーン座標値 (s10.2)	*/
	    s32   invw;		/* テクスチャパースペクティブ補正処理
				   パラメータ 1/W (s15.16)		*/
	    s16   xi, yi;	/* 正規化前の X,Y の値 (整数部のみ)	*/
	    u8    cc;		/* クリップ処理判定用フラグ		*/
	    u8    fog;		/* FOG 係数				*/
	    s16   wi;		/* W の値 (整数部のみ)			*/
	  } zVtxDest;		/* サイズ合計 16 Bytes			*/
	-------------------------------------------------------------------

	  zVtxSrc 構造体のサイズは 6Bytes なので gSPZSetUMem による 
	DMA 転送時には 8Bytes アライメントに対し特に注意しなければなり
	ません. 転送サイズが 8 の倍数にならないときには, 8 の倍数に 
	DMA 転送サイズを切り上げる必要があります.

	  zVtxDest 構造体のサイズは, 16Bytes なので 2048Bytes のユーザエ
	リア内には最大 128 個分の領域しか確保できません. よって num の範
	囲は 1 から 128 までです. (実際にはライト処理を行なったりするので
	これよりも少なくなることが多いです.) このとき dest の番地から 
	num*16 Bytes の領域が書換えられますが, num が 3 以下の場合は例
	外です. この場合 dest で指定した位置から 64 Bytes 分の領域が上
	書きされます. 例えば num が 3 で dest が 0 のときは, 0 〜 47 
	番地には変換後の正しい値が格納されますが, 48 〜 63 番地には, 
	意味のないデータが書き込まれます. このとき 48 〜 63 番地の元の
	値は破壊されてしまうので充分に注意する必要があります. この仕様
	は計算速度の向上のためやむを得ないものです.
	
	  この GBI のルーチンは基本的には以下のような手続きになってい
	ます. dest の出力によって未処理の src が上書きされないように注
	意すれば, src と dest の領域を重複させることが可能です. サンプ
	ルプログラムの cubes-1 の libzsort では src = 1200 〜 1919,
	dest = 0 〜 1919 として最大 120 個の頂点を処理できるようになっ
	ています.
	
		--------------------------------
		  for (i = 0; i < num; i ++){
			*dest = MultMP(*src);
			src  += 6;
			dest += 16;
		  }
		--------------------------------

	  メンバー変数 invw は, 各頂点の座標値 (x,y,z,1) に MxP 行列を
	乗じた後の座標値 (X,Y,Z,W) の W から以下のように求めます. この
	式から invW は視点からの距離の逆数に比例することが判ります. た
	だし perspNorm は gSPZPerspNormalize で設定した透視変換正規化
	パラメータです. 

		invw = (1<<30)/(perspNorm * W);
	
	  invW の値をそのまま ZObject の zTxTri/zTxQuad の設定に使用す
	ることができます.
	
	  guPerspective, guLookAt などを使用して MP マトリクスを作成し
	た場合, wi の値は通常, 視点からの距離を示します. この値を画面
	深度として選び Z Sort を行なうことも可能です.

	  また xi,yi は, 透視変換を行なう前の正規化されていない座標値
	です. この値は, 主にクリッピング処理に使われます. ZSort マイク
	ロコードではマイクロコードによるクリッピング処理はサポートされ
	ていません. ただし CPU プログラムで xi,yi,wi の値を使用してク
	リッピングを行なうことが出来ます. 詳しくは後程説明します.
	
	  クリップ処理判定用フラグ cc の値を調べることによって, その頂
	点が ViewPort (可視領域)内にあるかどうかを簡単に判定することが
	出来ます. 下は cc の各フラグの説明です.
	
	---------------------------------------------------------
	 GZ_CC_LEFT	X 座標が可視領域の Left   Plane よりも左
	 GZ_CC_RIGHT	X 座標が可視領域の Right  Plane よりも右
	 GZ_CC_TOP	Y 座標が可視領域の Top    Plane よりも上
	 GZ_CC_BOTTOM	Y 座標が可視領域の Bottom Plane よりも下
	 GZ_CC_NEAR	Z 座標が可視領域の Near   Plane よりも前
	 GZ_CC_FAR	Z 座標が可視領域の Far    Plane よりも奥
	---------------------------------------------------------

	  頂点 v0,v1,v2 からなる 3 角形が完全に画面外にあるかどうかを
	判定するときには以下のように各頂点の cc 値を AND し, その結果
	が 0 であるかどうかを調べます. 結果が 0 で無ければ, その 3 角
	形の全領域が 6 つのクリップ面の内の少なくとも 1 つに対して外側
	にあることになります. このときの 3 角形は画面外にあることにな
	るのでその時点で処理を打ち切ることができます.

		-------------------------------------------------
		 if (v0.cc & v1.cc & v2.cc){
		   3 角形は画面外にあるので処理を打ち切る;
		 }
		-------------------------------------------------

	  さらに 3 角形 v0,v1,v2 が Near Plane と交差しているかを判定
	したいときは, 3 角形が Near Plane 外にあるかどうかを上記の式で
	判定した後に, 以下のように OR 処理をすることで判定します. これ
	は, Near Plane でクリッピング処理を行なうかどうかの判定に使わ
	れます.

		-------------------------------------------------
		 if ((v0.cc | v1.cc | v2.cc) & GZ_CC_NEAR){
		   Near クリッピング処理を行なう;
		 }
		-------------------------------------------------
	
	  fog は FOG 処理を行なうときに使用します. fog の値を RGBA の A 
	の値として使用することで FOG 処理が可能です.  ZSort マイクロコー
	ドでは FOG の調節は ViewPort の Vp 構造体のパラメータで行ない
	ます. 詳しくは, サンプルプログラムを参照してください.

	  本 GBI で取得できる頂点データは実際には以下のように使用され
	ます. 実際に ZObject の各構造体に代入される数値は sx, sy, fog,
	invw の値ですが, invw あるいは wi の値が Z ソートを行なうため
	の画面深度の値として用いられます.

	------------------------------------------------------
	[ zShTri 構造体の場合 ]

	 zVtxDest	*v0, *v1, *v2;
	 zShTri		*shtri;

	 /* スクリーン座標の設定 */
	 shtri->t.v[0].x = v0->sx;  shtri->t.v[0].y = v0->sy;
	 shtri->t.v[1].x = v1->sx;  shtri->t.v[1].y = v1->sy;
	 shtri->t.v[2].x = v2->sx;  shtri->t.v[2].y = v2->sy;

	 /* 以下の設定は Fog を使うときのみ */
	 shtri->t.v[0].a = v0->fog;
	 shtri->t.v[1].a = v1->fog;
	 shtri->t.v[2].a = v2->fog;
	
	------------------------------------------------------
	[ zTxTri 構造体の場合 ]

	 zVtxDest	*v0, *v1, *v2;
	 zTxTri		*txtri;

	 /* スクリーン座標の設定 */
	 txtri->t.v[0].x = v0->sx; txtri->t.v[0].y = v0->sy;
	 txtri->t.v[1].x = v1->sx; txtri->t.v[1].y = v1->sy;
	 txtri->t.v[2].x = v2->sx; txtri->t.v[2].y = v2->sy;

	 /* テクスチャ補正パラメータの設定 */
	 txtri->t.v[0].invw = v0->invw;
	 txtri->t.v[1].invw = v1->invw;
	 txtri->t.v[2].invw = v2->invw;

	 /* 以下の設定は Fog を使うときのみ */
	 txtri->t.v[0].a = v0->fog;
	 txtri->t.v[1].a = v1->fog;
	 txtri->t.v[2].a = v2->fog;
	------------------------------------------------------

------------------------------------------------------------------------------
 * gSPZSetAmbient(Gfx *gp, u32 umem,          Ambient *ambient);
 * gSPZSetDefuse (Gfx *gp, u32 umem, u32 lid, Light   *defuse );

	umem	ライトデータ保持用領域の先頭番地.
	ambient	Ambient ライト構造体へのポインタ.
	lid	Defuse  ライトの番号 (0,1,....)
	defuse	Defuse  ライト構造体へのポインタ.
	
	  Ambient ライト(環境光)データまたは Defuse ライト(表面拡散光)
	データをユーザエリアに書き込みます. ライトデータ領域はユーザエ
	リア内に予め確保しておきます. そのサイズは, Defuse ライトの数
	および環境マップを行なうかどうかに依存し, 以下の式で計算できま
	す.

	(ライトデータ領域のサイズ) =
	    8 + 24 * (Defuse ライトの数) + ((環境マップを行なう)? 48 : 0));

	  サンプルプログラム cubes-1 の libzsort では Defuse ライトを 
	3 個と環境マップを使用しますので, ユーザエリア 1920 〜 2047 の 
	128Bytes をライト用として確保しています.

	  Ambient 構造体, Defuse 構造体の設定には, Fast3D のマクロを使
	用することができます. 以下は Defuse ライトが 2 個のときに 
	gdSPDefLights2 を使用して, ライトを設定する一例です.

	---------------------------------------------------------------
	 /*--- Light parameter ---*/
	 static Lights2 scene_light =
	 gdSPDefLights2( 0x20,0x20,0x20,		/* Ambient  */
		         0xe0,0xe0,0xe0,  0, 40,80,	/* Defuse 0 */
		         0x40,0x00,0x00,  0,-80,40 );	/* Defuse 1 */
	
	 /*--- Load light parameter ---*/
	 gSPZSetAmbient(gp++, 1920,    &scene_light.a);
	 gSPZSetDefuse (gp++, 1920, 0, &scene_light.l[0]);
	 gSPZSetDefuse (gp++, 1920, 1, &scene_light.l[1]);
	---------------------------------------------------------------

------------------------------------------------------------------------------
 * gSPZSetLookAt(Gfx *gp, u32 umem, u32 lnum, LookAt *lookat)

	umem	ライトデータ保持用領域の先頭番地.
	lnum	Defuse ライトの数
	lookat	LookAt 構造体へのポインタ.
	
	  環境マッピングのパラメータである LookAt 構造体データをライト
	データ領域に書き込みます. ライトデータ領域はユーザエリア内に予
	め確保しておきます. これについては gSPZSetAmbient/Defuse の説
	明を参照してください.

	  ZSort マイクロコードでは環境マップ処理において Fast3D 互換マ
	イクロコードであった TEX_GEN と TEX_GEN_LINEAR の処理モードの
	内, TEX_GEN_LINEAR はサポートされていません. 常に TEX_GEN の処
	理となります.

	  LookAt 構造体の設定には, OS の gu ライブラリ関数の,
	guLookAtReflect, guLookAtHilite 等が利用できますが, ZSort と一
	部異なる部分があります. これを修正するためのマクロ 
	guZFixLookAt が用意されていますので, ライブラリ関数で LookAt 
	を設定した後に guZFixLookAt で修正してください.

	  以下は Defuse ライトが 2 個のときに gdSPDefLights2 を使用し
	て, ライトを設定し, さらに guLookAtReflect で反射マップを行な
	うときのデータの書き込み処理です. 

	---------------------------------------------------------------
	 /*--- Light parameter ---*/
	 static Lights2 scene_light =
	 gdSPDefLights2( 0x20,0x20,0x20,		/* Ambient  */
		         0xe0,0xe0,0xe0,  0, 40,80,	/* Defuse 0 */
		         0x40,0x00,0x00,  0,-80,40 );	/* Defuse 1 */
	
	 /*--- Make reflection parameter ---*/
	 guLookAtReflect(&dynamicp->viewing, &dynamicp->lookat,
			 0, 0, 1000,  0, 0, 900,  0, 1, 0);
	 guZFixLookAt(&dynamicp->lookat);

	 /*--- Load light parameters ---*/
	 gSPZSetAmbient(gp++, 1920,    &scene_light.a);
	 gSPZSetDefuse (gp++, 1920, 0, &scene_light.l[0]);
	 gSPZSetDefuse (gp++, 1920, 1, &scene_light.l[1]);
	
	 /*--- Load reflection parameters ---*/
	 gSPZSetLookAt (gp++, 1920, 2, &dynamicp->lookat);
	---------------------------------------------------------------

	  guZFixLookAt は gzsort.h 内で以下のように定義されています.	

	---------------------------------------------------------------
	 #define guZFixLookAt(lp)        \
        	{ (lp)->l[1].l.col[1] = (lp)->l[1].l.colc[1] = 0x00; }
	---------------------------------------------------------------

	  これは, 2 つの要素を 0 クリアしているだけです. (gu ライブラ
	リでは 0x80 を代入してしまいます.) もしこれを毎回使用する無駄
	を無くしたいとお考えなら, libultra のサンプルプログラムのディ
	レクトリ下の libultra/gu にある OS の gu ライブラリ関数のソー
	スファイル (Partner 版ではライブラリとは別に配布している場合が
	あります) を参考に修正しライブラリ関数と置き換えてください.

------------------------------------------------------------------------------
 * gSPZXfmLights(gfx *gp, u32 mid, u32 lnum, u32 umem)

	mid	ModelView マトリクスの左上 3x3 要素を転置したマトリクス.
	lnum	処理するライト要素数.
	umem	ライトデータが保持されているユーザエリアの先頭番地

	  ライティングの前処理を行ないます. ライトデータあるいは 
	ModelView マトリクスの一方または両方が変更されてから,
	g*SPLight または g*SPLightMaterial が呼び出されるまでの間に本 
	GBI を呼び出さなければなりません. これによって, ライトデータが
	gSPZLight や gSPZLightMaterial によるライティング計算に使用で
	きるように前処理されます. 通常ライトデータが 1 シーン内で変更
	されることは稀なので, ModelView マトリクスが変更になったときに
	この GBI を呼び出せば良いでしょう.

	  本 GBI の実行には ModelView マトリクスの逆回転マトリクスが必
	要となります. 通常, これには ModelView マトリクスの左上 3x3 要
	素を転置したマトリクスを適用できます. (ある座標軸のみをスケー
	リングさせた場合などに陰影づけが少しおかしくなることがあります
	が, あまり気にならないことが多いのです.) この ModelView マトリ
	クスの転置は gSPZMtxTrnsp3x3 を使用します.
	
	  lnum の数は基本的には Defuse ライトの数となります. Ambient ラ
	イトは含みません. また ZSort マイクロコードでは, lnum を 0 に
	することはできません. Ambient ライトのみのライティング処理をし
	たいときは, 黒色 (RGB=0,0,0) の Defuse ライトを 1 つダミーで指
	定してください.

	  また, 環境マップを行なうときは擬似的に 2 つの Defuse ライトを
	使用します. ハイライトの表現やリフレクションの表現を行なう場合
	には環境マップ用パラメータをライト用パラメータ領域にロードし,
	lnum に (Defuse ライトの数 +2) を設定してください. ライトを使
	用せず (Defuse ライトなし)に, 環境マップのみを使用する場合には
	前述のダミーの Defuse ライトは必要ありません. lnum に 2 を指定
	して本 GBI を呼び出してください.

	  以下は ModelView マトリクスが変更になったときの処理例です.
	ライトデータ領域先頭は 1920 番地で, Defuse ライトが 2 個, 環境
	マップありの場合の処理です.

	-----------------------------------------------------
	 /*--- Set ModelView and MxP matrix ---*/
	 gSPZSetMtx(gp++, GZM_MMTX, &dynamicp->modeling[i]);
	 gSPZMtxCat(gp++, GZM_MMTX, GZM_PMTX, GZM_MPMTX);

	 /*--- Xfm light data ---*/
         gSPZMtxTrnsp3x3(gp++, GZM_MMTX);
         gSPZXfmLight(gp++, GZM_MMTX, 1920, 4);
	-----------------------------------------------------
	   
------------------------------------------------------------------------------
 * gSPZLight(Gfx *gp, u32 nsrc, u32 num, u32 cdest, u32 tdest)
 * gSPZLightMaterial(Gfx *gp,
                     u32 msrc, u32 nsrc, u32 num, u32 cdest, u32 tdest)

	msrc	マテリアルカラーデータ(頂点自体の色)が格納されているユー
		ザエリアの先頭番地
	nsrc	法線ベクトルデータが格納されているユーザエリアの先頭番地
	num	処理する法線ベクトルの数 (2 の倍数)
	cdest	ライト計算後の頂点のカラー値を格納するユーザエリアの先頭番地
	tdest	環境マップ計算後の頂点のテクスチャ座標値を格納するユーザ
		エリアの先頭番地

	  ユーザエリアの nsrc 番地からのデータを signed 8bit の法線ベク
	トル値 (nx,ny,nz) 値とみなし, それに gSPZXfmLight で指定した
	ライトパラメータを用いてライティング計算を行ないます. これによっ
	て法線ベクトルに対応するライトカラーを取得でき, このライトカラー
	と頂点自体の色であるマテリアルカラーとを各 r,g,b 要素毎に掛け
	合わせることで頂点のカラーを取得します. また a 要素はマテリア
	ルカラーの a 値がそのまま使用されます. こうして計算されたカラー
	値は, ユーザエリアの cdest 番地に格納されます.

	  gSPZLight の場合, マテリアルカラーとして (r,g,b,a) = (255,255,
	255,255) が使われます. これは Fast3D 系マイクロコードと同じ仕様
	で, ライトカラーで頂点の色付けを行なうことを意味します. また 
	gSPZLightMaterial の場合は, ユーザエリアの msrc 番地からのデー
	タを unsigned 8bit のカラーデータとして順に (r,g,b,a) として使
	います.

	  また, ライトデータとして LookAt 構造体データが設定してある場
	合には, ライティング計算と同時に環境マップ計算が行なわれます.
	計算結果として (S,T = 0.00 〜 32.00) までのテクスチャ座標値が
	ユーザエリアの tdest 番地に出力されます. もし, LookAt 構造体が
	設定してない場合でも tdest へは不定値が出力され, (num * 4) Bytes
	分の領域が破壊されますので注意してください.
	
	  こうして, cdest と tdest を出力した後, nsrc に 3, msrc,
	cdest,tdest に 4 が加算され, 次の頂点へ進みます. num 個の法線
	ベクトルを連続して処理しますが, num は偶数でなければいけません.
	num が奇数の場合, それを超える偶数(num+1)個のデータが cdest, 
	tdest へ出力されます. このとき num+1 個目の出力データの位置に
	は意味のないデータが出力されます. 

	  本 GBI での入力と出力のデータ値のフォーマットは, ヘッダファ
	イル gzsort.h 内の zNorm, zColor, zTxtr 各構造体として以下のよ
	うに定義されています.
	
	-----------------------------------------------------
	 typedef struct  {  s8   nx,ny,nz;       } zNorm;

	 typedef struct  {  u8   r, g, b, a;     } zColor_t;
	 typedef union   {
	   zColor_t      n;
	   u32           w;
	 } zColor;

	 typedef struct  {  s16  s, t;           } zTxtr_t;
	 typedef union   {
	   zTxtr_t       n;
	   u32           w;
	 } zTxtr;
	-----------------------------------------------------
	
	  また, 各構造体のサイズは 3 または 4Bytes なので gSPZSetUMem 
	による DMA 転送時には 8Bytes アライメントに対し特に注意しなけ
	ればなりません. また転送サイズが 8 の倍数にならないときには, 8 
	の倍数に DMA 転送サイズを切り上げる必要があります.
	
	  この GBI のルーチンは基本的には以下のような手続きになってい
	ます. cdest, tdest の出力によって未処理の nsrc, msrc が上書き
	されないように注意すれば, これらの領域を重複させることも可能です.

	---------------------------------------------------
	  for (i = 0; i < num; i ++){
		(*cdest,*tdest) = CalcLight(*nsrc,*msrc);
		nsrc  += 3;
		msrc  += 4;
		cdest += 4;
		tdest += 4;
	  }
	---------------------------------------------------

------------------------------------------------------------------------------
 * gSPZMixS16(Gfx *gp, u32 src1, u32 src2, u32 num, u16 factor)
 * gSPZMixS8 (Gfx *gp, u32 src1, u32 src2, u32 num, u16 factor)
 * gSPZMixU8 (Gfx *gp, u32 src1, u32 src2, u32 num, u16 factor)

	src1	補間されるデータが格納されているユーザエリアの先頭番地 1
		および補間結果が出力されるユーザエリアの先頭番地 (共通)
	src2	補間されるデータが格納されているユーザエリアの先頭番地 2
	num	データの数. (8 の倍数)
	factor	混ぜ合わせ係数 (u.15 フォーマット 0x0000 〜 0x7fff の値)

	  以下の数式で 2 つの数の線形補間を行ないます. 
	それぞれの GBI で s16, s8, u8 型のデータを扱います.

	(*src1) = (*src1)*factor + (*src2)*(1.0-factor);

	  gSPZMixS16 において src1, src2 を 16 Bytes 境界に合わせる必
	要があります. また gSPZMixS8,gSPZMixU8 において src1, src2 を
	8 Bytes 境界に合わせる必要があります.

	  num は 8 の倍数である必要があります. もし, 8 の倍数で無い値を
	指定した場合, 8 の倍数になるまで意味のないデータが src1 へ出力
	されます.


	
===============================================================================
5. その他の処理
===============================================================================

--------------
5.1  GBI 一覧

  その他の GBI の一覧です.

    ----------------------------------------------------------------
    gSPZSegment		- セグメントを設定する
    gSPZSetSubDL	- Sub DL を登録/起動する.
    gSPZLinkSubDL	- 未処理の Sub DL の処理を行なう.
    gSPZSendMessage	- CPU にメッセージを送る.
    gSPZWaitSignal	- CPU からのシグナルを待つ.
    ----------------------------------------------------------------

--------------------
5.2  GBI の機能解説

  この項ではその他の GBI の解説をします. 

------------------------------------------------------------------------------
 * gSPZSetSubDL(Gfx *gp, Gfx *subdl)

	subdl	Sub DL の先頭番地

	  Sub DL を登録します. この GBI は Main DL でしか処理できま
	せん. 既に Sub DL が起動しているのに 2 重に登録したときの動作
	は保証しません. gSPZLinkSubDL で既に登録している Sub DL の処理
	を完了させてから登録してください.

------------------------------------------------------------------------------
 * gSPZLinkSubDL(Gfx *gp)

	  処理の残っている Sub DL の処理を行ないます. この GBI は
	Main DL でしか処理できません. もし Sub DL が既に終了していたり,
	Sub DL が登録されていないときには何もしません.

------------------------------------------------------------------------------
 * gSPZSendMessage(Gfx *gp)

	  CPU へ SP_BREAK メッセージを送ります. これにより,
	DisplayList の実行状況が CPU 側で判るようになりました. 
	
	  もし DL の実行状況が判らない場合, CPU は処理が完了したかどう
	かの判断ができないため, RSP の処理が終了するまで (=RSP のメッ
	セージを受けるまで) 待つ必要があります.

		DisplayList
			| ZObject A の頂点計算
			| ZObject B の頂点計算
			| ZObject C の頂点計算
			V この時点で終了メッセージが CPU へ送られる.

	  もし本 GBI を使って以下のように DisplayList を用意すると, 
	CPU は ZObject 毎の頂点計算が終了したかどうかを知ることができ
	るため, 直ぐに ZObject の構築処理にかかることができます. 

		DisplayList
			| ZObject A の頂点計算
			| gSPZSendMessgae ------> メッセージが CPU へ送られる
			| ZObject B の頂点計算
			| gSPZSendMessage ------> メッセージが CPU へ送られる
			| ZObject C の頂点計算
			V gSPZSendMessage ------> メッセージが CPU へ送られる

	  実際にはメッセージを送る/受けることによるオーバーヘッドもあ
	るため, 上記のように ZObject 毎にメッセージを送るよりも複数の 
	ZObject 毎に送る方が良い場合があります. この調整はユーザ側が行
	なってください.

	  RSP から送られる SP_BREAK メッセージを CPU で受けるには通常
	のメッセージの受け渡しと同じように, メッセージキューを用います.
	SP_BREAK メッセージ用のメッセージキューを確保して, 
	osSetEventMesg で OS_EVENT_SP_BREAK と接続してください. また
	キューのサイズは DisplayList 中の gSPZSendMessage の数以上にし
	ておく方が安全ですが, これは強制ではありません. うまく
	SP_BREAK メッセージの数をコントロールできるならそれ以下でも問
	題ないでしょう.

	  従来のマイクロコードでは, この SP_BREAK メッセージは,
	rmonThread が使用しています. 元来このメッセージは GameShop
	DEBUGGER の使用時において, マイクロコードの BREAK POINT 処理を
	行なうために用意されたものです. 現状ではこの機能はそれほど使わ
	れていないと判断し, ユーザに解放することにしました. このため, 
	rmon Thread を使用しないときは何も問題はありませんが, rmon
	Thread を起動する場合, SP_BREAK メッセージキューを設定する処理
	は, rmonThread の作成/起動処理 (rmon Thread に osStartThread 
	を行なう) 以降に行なわねばなりません. この点ご注意ください.

------------------------------------------------------------------------------
 * gSPZWaitSignal(Gfx *gp, zSignal *sig, u32 param)

	sig	Signal バッファへのポインタ
	param	Signal 値. (u32)

	  CPU の Signal 値が param 値以上になるまで待機します. CPU に
	よる Signal 値の更新は RDRAM 上のバッファを介して行なわれるた
	め, アプリケーション側でこのバッファを用意する必要があります.
	本 GBI 実行中, RSP は CPU がバッファ上の Signal 値を書換えたか
	どうかを判定し, 書換えていた場合 RDRAM 上の Signal バッファを 
	DMEM へ DMA 転送し param と比較します.

	  CPU の Signal 値の書換え処理用のマクロとして以下を用意してあ
	ります.

	--------------------------------------------------------
	 GZ_SENDSIGNAL(zSignal *sig, u32 val)

	 sig	Signal バッファへのポインタ.
	 val	新しい Signal 値.

	   Signal 値を val に書換えた後, RSP に書換えが起こった
	 ことを通知する.
	--------------------------------------------------------

	  Signal 値は unsigned の 32 bit 変数なので, 最小値は 0
	となります. 
	
	  これまでのマイクロコードでは, Display List を完全に作成して
	から, それを RSP に渡しました. すなわち, Display List の作成が
	完全に終了するまで, RSP は処理ができなかったのです. しかし本 
	GBI を使用することによって完全な Display List が作成されていな
	くても, 作成した分だけを RSP に処理させることができるようにな
	ります. すなわち Display List の続きができるまで RSP を待たせ
	ておくことができるのです. この gSPZWaitSignal と前出の 
	gSPZSendMessage とを組合わせると CPU と RSP のプロセス間の単純
	な同期をとることができ, Display List の逐次処理に威力を発揮す
	ることになるでしょう.


	
===============================================================================
6. 他のマイクロコードとの互換性
===============================================================================

------------------
6.1  GBI について

  Z Sort マイクロコードは他の Fast3D 互換マイクロコードなどとの互換性
はありません. ただし, 今後 F3DEX 系マイクロコードと自己ロードによって
切り替えることができるように一部 GBI を共通化する予定です. 本章では共
通化されるであろう GBI について説明します.
 
  ここで説明されている GBI の名称は基本的に対応する F3DEX の GBI マク
ロの接頭語の gSP を gSPZ と変更したものになっています.

  Z Sort マイクロコードの GBI は, F3DEX GBI Level 2 のサブセットを内包
しています. この F3DEX GBI Level 2 とは, F3DEX マイクロコードにおける 
RSP の処理速度を上げるために現状の GBI を改造した新しい GBI セットで, 
今後のリリースの F3DEX マイクロコードに採用予定のものです. そのため,
F3DEX マイクロコード Ver 1.23 以前で採用されている GBI とバイナリレベ
ルでの互換性はありません. このため F3DEX マイクロコード系のマイクロコー
ドと自己ロードなどの処理を行なうことは難しくなっています.

  Z Sort マイクロコードは F3DEX GBI Level 2 を使用するため, Z Sort マ
イクロコードを使用するときは #define 文あるいは, コンパイルオプション -
D で F3DEX_GBI_2 を定義しなければなりません. 

  (注意: 現状では F3DEX_GBI も定義する必要があります.)


--------------
6.2  共通 GBI

    gSPZSegment         - セグメントを設定する.
    gSPZPerspNormalize	- パース補正値を設定する.


------------------------------------------------------------------------------
 * gSPZSegment(Gfx *gp, u32 seg, u32 base)

	seg	セグメント番号 (0 〜 15)
	base	セグメントベースアドレス.

	  セグメントの設定を行ないます. Main DL, Sub DL のどちらでも処
	理できますが, 同一セグメント番号に対して Main DL と Sub DL と
	で書換えを行なった場合, 並列起動したときなどにおいて不都合が起
	こることが予想されます. これを防ぐためにも, なるべく Main DL 
	と Sub DL において使用するセグメントが重ならないように注意する
	ことが望まれます.

------------------------------------------------------------------------------
 * gSPZPerspNormalize(Gfx *gp, u16 persp)

	persp	パース補正値

	  パース補正値を設定します. 本 GBI は F3DEX 等における 
	gSPPerspNormalize GBI と同じものです.


------------------------------------------------------------------------------

	この項未完成


	
===============================================================================
7.  CPU のサポートライブラリ
===============================================================================

  Z Sort マイクロコードでは, スクリーン上の頂点データから面データすな
わち ZObject のデータを構築する処理を CPU に依存しています. 算術演算処
理 GBI コマンドで 3D 座標上頂点をスクリーン座標上の頂点へ変換すること
はできますが, それらの頂点を接続して多角形を構成するのは CPU の役目で
す. その他にも CPU 側で行なわねばならない処理が幾つかあり, こうした処
理を行なうための CPU ライブラリを作成する必要があります. ここではライ
ブラリのサンプルとして, サンプルプログラム cubes-1 で使用しているライ
ブラリについて説明します.


	| モデル行列と透視変換行列等の乗算
	| モデル頂点の座標変換/透視変換/画面深度計算
	| 頂点が画面内にあるかどうかの判定
	| クリッピング/裏面判定
	| ZObject データの構築
	| ZObject リスト作成


	この項未完成

	
===============================================================================
8. TASK マネージメント
===============================================================================

------------------------
8.1 RSP 処理の実装手法

  RSP の処理が 2 パスに分れることは前項で述べました. ここではその実装
について説明します. 

  ここでは, 以下の 2 つの実装手法を想定しています.

    実装 A) 2 タスク処理
    実装 B) 2 パス並列処理

  詳細は次項から説明します. A,B それぞれに長所, 短所があるのでそれを充
分に理解した上で実装手法をお選び下さい.


-----------------
8.2  2タスク処理

  算術演算処理と描画処理を別タスクに分け, 順に起動するものです. 設定も
他のマイクロコードの起動方法と似ているので理解しやすい手法と言えるでしょ
う. ここでその概念を理解してください.

 ==== 実装 A ====

  最も単純な 2 タスク処理は以下のようになります.

    (1)    算術演算用の Display List の作成.
    (2)    RSP 第 1 タスク(算術演算用の Display List)を起動する.
    (3)    RSP は演算を行なう, CPU は RSP の終了まで待機.
    (4) a. 演算結果を使用した ZObject データの作成.
        b. ソーティングによる ZObject の処理リンクの作成.
        c. 描画処理用の Display List の作成.
    (5)    RSP 第 2 タスク(描画処理用の Display List)を起動する.
    (6)    RSP は描画計算を行なう. CPU は RDP の終了まで待機.
    (7)    RDP は描画を行なう.

  この手法は最も単純であるため理解しやすく, キー入力から画面の反応まで
の時間を短くしたい場合に有効です. また ZObject 用のデータを展開するた
めのバッファがシングルバッファで良いため確保するべきメモリ量も減ります.

  またこれは全ての実装手法について言えることですが, (4)a.b.c. の CPU 
で行なう ZObject の構成にはかなりの計算コストが必要となります. この部
分の実装の仕方で 1 フレームに描画可能な ZObject の数に差が出ます. もし
可能ならこの部分は C 言語ではなく *アセンブリ言語* で記述されることを
お勧めします.

  各処理における CPU と RSP, RDP の動作状態を以下に示します. 括弧内の
数字は上記の箇条書きの番号に対応します.

  フレーム                                               フレーム
    開始                                                   終了
      |                                                      |
  CPU |==(1)=>|==(2)=>|       |==(4)=>|==(5)=>|       |      |
  RSP |       |       |==(3)=>|       |       |==(6)=>|      |
  RDP |       |       |       |       |       |======(7)====>|
      |                                                      |

 ==== 実装 B ====

  実装 A の手法の問題の 1 つは, CPU と RSP が並列に動く箇所がないこと
でしょう. このため CPU と RSP の処理にそれぞれ *空き* が出来てしまいま
す.  ここでこの空きを少しでも解消するために (3) と (4) の処理をパイプ
ライン的に処理することを考えます. ここでは, あるまとまった数の ZObject 
データを作成するのに必要な頂点データが揃った時点で, その分の ZObject 
の作成を開始することにします. これをサポートするために ZSort マイクロ
コードでは, CPU へメッセージを送るための GBI コマンドが用意されていま
す. これを算術演算処理 GBI コマンドの途中に入れておけば, RSP はそのコ
マンド処理時に CPU へメッセージを送ります. CPU はそのメッセージを受信
することでそのメッセージ発生コマンド以前の算術演算処理が終了したことを
知ることができます.

  また RDP については, (1)-(5) まで何も動作していないことが判ります.
この処理では, RDP の空き時間が大きいため, 描画性能は低くなります.
RDP 処理時間を稼ぐためには, 主に画面クリアなどの RSP の演算処理を必要
としない描画処理を第 1 パス内で行なう方が良いのは言うまでもありません.

  あくまで一例ですが, こうした点を改良すると以下のようになるでしょう.

  フレーム                                          フレーム
    開始                                              終了
      |                                                 |
  CPU |==(1)=>|==(2)=>| ====(4)=>|==(5)=>|       |      |
  RSP |       |       |=(3)====> |       |==(6)=>|      |
  RDP |       |       |=(7)=>    |       |======(7)====>|
      |                                                 |

  第 3 段において各プロセッサは以下のような処理を行ないます.

  CPU: RSP が座標計算処理したデータから ZObject データを作成し, ソート
       する. また第 2 パス用の DL を作成する.
  RSP: 座標計算を行ない, あるまとまった数の ZObject データを作成するの
       に必要な頂点データが揃うごとに CPU へメッセージを送る.
  RDP: 主に画面クリアなどの RSP の演算処理を必要としない処理を行なう.

  この処理を行なうための処理系の実装は前述の処理系よりも複雑になります.
この処理の複雑さは次項の 2 パス並列処理の複雑さと大差がなく, こうした 
(3) と (4) の逐次処理によって得られるパフォーマンスは一般的にそれほど
大きくないため, キー入力の反応速度の遅延や, メモリ量の増加にこだわらな
い場合は他の方式を使用されることをお勧めします.

 ==== 実装 C ====

  キー入力の反応速度の遅延を容認できる場合は, 以下のような実装方法が考
えられます. これは (5),(6),(7) の処理を次フレームに持ち越した形になり
ます.
   
  フレーム                                フレーム
    開始                                    終了
      |                                       |
  CPU |==(5)=>|==(1)=>|==(2)=>|       |==(4)=>|
  RSP |       |====(6)======> |==(3)=>|       |
  RDP |       |==============(7)=========>|   |
      |                                       |

  この場合, キー入力に対する画面の反応までの時間が遅くなりますが, RDP 
の処理時間を長く取ることが可能となります.

  (6) が終了するまで (3),(4) の処理を待つ必要があるため, RSP における 
(6) の処理時間と CPU による (4) の処理時間は出来るだけ短くする必要があ
ります. FIFO バッファを大きくすると RDP の描画処理を RSP が待つことが
少なくなるため, 通常 (6) の時間が短くなり, この処理系のパフォーマンス
が上がります. ただし, 小さな ZObject が沢山登場するシーンでは RDP より 
RSP の方の処理が長くなり, RDP が RSP を待つようになるため, こうした場
合には FIFO バッファを大きくしてもパフォーマンスは上がりません. この場
合, (4) をアセンブル言語で実装することは前提となるでしょう. 

 ==== 実装 D ====

  実装 C において CPU 処理 (1),(2) が (6) よりもかなり早く終了する場合
には (3) の RSP の処理を (6) の終了まで待つ必要があります. この無駄を
無くすために (6) の描画 RSP TASK を yield 処理により停止させ, (3) の
演算 RSP TASK を起動し, (3) の処理終了後に (6) を再開させるという処理
を行なうことができます.

  この処理を行なうためには (3) の演算 TASK の flag に OS_TASK_SP_ONLY
を追加する必要があります. OS_TASK_SP_ONLY をセットして起動した ZSort
マイクロコードはコプロセッサモードで動作します. コプロセッサモードで
描画処理 GBI を使用した場合, RDP が正常に動作しませんのでご注意くださ
い.

  また (6) を Yield 処理で停止させ, (3) を起動している最中でも AUDIO 
TASK による Yield 要求は受け付けられます. これを可能とするためには (3)
と (6) の Yield バッファを別の領域にとる必要があります.

  フレーム                                フレーム
    開始                                    終了
      |                                       |
  CPU |==(5)=>|=(1)=>|=(2)=>|      |==(4)=>|  |
  RSP |       |====(6)=====>|=(3)=>|=(6)=>    |
  RDP |       |==============(7)===========>| |
      |                                       |

  実装の難易度とパフォーマンスを考えると, 実装 C か 実装 D が 2 タスク
処理の中では最もバランスが取れていると思います.

 ==== 実装 E ====

  もし (3) を RSP ではなく CPU で実装でき充分なパフォーマンスを得るこ
とが可能であるような稀な場合には, 全く問題なく並列に処理することが可能
です. 以下のようになります. ただし, (6) と (4) が重なる場合があるので,
ZObject のデータおよび DL をダブルバッファで処理する必要があります.

    開始                                    終了
      |                                       |
  CPU |==(5)=>|==(1)=>|==(2)=>|==(3)=>|==(4)=>|
  RSP |       |====(6)=============>|         |
  RDP |       |==============(7)=========>|   |
      |                                       |

  この実装でパフォーマンスが上がるかどうかは (3) の部分をどれだけ速く
処理できるかに依ります. もし可能なら (4) の部分と同様に (3) の部分のア
センブリ言語による実装を検討されることをお勧めします. 

----------------------
8.3  2 パス並列処理

  グラフィック処理において RDP の処理時間と RSP の処理時間が一致するこ
とは稀です. この差を埋めるために FIFO バッファが存在します. ここで RDP 
の処理時間が RSP の処理時間を上回った場合, FIFO バッファには未処理の 
RDP コマンドが貯まっていくことになります. この FIFO バッファのサイズも
有限であるため, この状態が長く続くと FIFO バッファが完全に埋まってしま
うことになります. 

  通常のマイクロコード (Fast3D,F3DEX系,S2DEX)において, こうした Buffer
FULL の場合, RSP は FIFO バッファに空きができるまで待機します. この状
態で RSP は RDP の処理を待っているだけで, その計算能力は無駄に消費され
ていることになります. 

  ZSort マイクロコードではこの無駄を無くすために RSP が RDP の処理を待っ
ている間に RDP に関与しない他の DL の処理(主に算術演算処理)を行なうこ
とができるようにしました. これによって擬似的に, 算術演算処理と描画処理
を 1 つのタスクにまとめて, 並列動作させることができます. これを 2 パス
並列処理と呼ぶことにします.

  この 2 パス並列処理において RSP の待ち時間内で処理される DL を Sub
Display List (Sub DL) と呼び, これに対して通常のマイクロコードと同様に
普通に処理される DL を Sub DL と区別するために Main DL と呼びます. Sub
DL は Main DL と同様に 18 段の DL スタックを専用に持っています.  Sub
DL は RSP が RDP の処理を待っている時に処理されるので, Sub DL で処理で
きる GBI コマンドは限られています. 当然ながら RDP を使用するコマンドは
実行できません. RSP のみを使用するコマンドだけが使用できます. もし RDP 
を使用する GBI コマンドを Sub DL に含めると誤動作しますのでご注意下さ
い. 具体的にどの GBI コマンドが Sub DL に使用できるかは後の章で説明し
ます. 算術演算用のコマンドが主に使用できます.

  実際の処理では, 常に RDP の処理時間が RSP の処理時間より長いというこ
とはなく, RDP の描画面積が小さければ上記の RSP の無駄な時間は無くなっ
てしまいます. この場合, Sub DL は Main DL で明示的に呼び出されるまで処
理されないことになります. 

  このマイクロコードの仕様では都合の悪い場合があることが予想されま
す. RDP の描画面積は描画するシーンによって変動するため, Sub DL を処理
できる RSP の待機時間は一定しません. CPU の ZObject 作成時間を確保する
ためにもある時間内に, RSP の算術演算を終わらせる必要があります.  この
ため, RSP の待機時間中以外にも, Sub DL の処理が行なわれることが望まし
いわけです.

  以上の理由から, RSP の待機時間以外にも, ある程度の ZObject を処理す
るたびに Sub DL 内の GBI コマンドを 1 つずつ起動するようなマイクロコー
ド gspZSort.pl.fifo.o (以下 ZSort.pl ucode と表記) を用意しました. こ
の Sub DL のコマンドが呼び出されるタイミングは, 描画している ZObject 
の種類によって異なりますが, 多角形の ZObject の場合, 2 個から 4 個の 
ZObject を描画するごとに 1 つの Sub DL コマンドが必ず処理されます.

  ZSort.pl に対して RSP の待機中のみ Sub DL の処理を行なう仕様のマイク
ロコードが gspZSort.fifo.o マイクロコード(以下 ZSort ucode と表記)です.

  ZSort.pl ucode では, こうした追加処理を行なうため, ZSort ucode より
オーバーヘッドが大きくなり, そのため ZSort ucode の方が ZSort.pl ucode
よりも RDP による描画処理性能は僅かながらも勝ります. この 2 種類のマイ
クロコードは, Sub DL の呼び出し割合の違いとそれに伴うオーバーヘッドが
生じる以外は同じものです. 状況に応じてお選びください.

  この 2 パス並列処理の実装は, 以下のようになるでしょう.
  ここでは (3) と (6) が並列に処理されています.

 ==== 実装 F ====

      フレーム                                   フレーム
        開始                                       終了
          |                                          |
  CPU ....|==(5)=>|=(1)=>|=(2)=>|      |==(4)===>|   |
  RSP Main|       |============(6)===========>|      |
       Sub|       |      |      |=(3)=>|      |      |
  RDP ....|       |==============(7)================>|
          |                                          |


===============================================================================
9. 使用上の注意
===============================================================================

-----------------------------------------
9.1  RSP から RDP へのコマンドの受け渡し

	この項未完成

--------------------
9.2  自己ロード機能

	この項未完成

	
===============================================================================
10. ZSort パッケージのインストール
===============================================================================

  ------------------------------------------------------------------------
     本章の記述は, ZSort マイクロコードが別パッケージで配布されている場合
   に関するもので, 既に N64 開発環境に本パッケージが含まれている場合はこ
   こに記載されている作業は必要ありません.
  ------------------------------------------------------------------------

+ インストール済みパッケージの確認

    本マイクロコードは, N64 開発環境 2.0I で動きます. 以下のパッケージが
  インストールされているかご確認下さい.
    もしインストールされていない場合は先にインストールしてください.
  ---------------------------------------------------------------------------
   ultra              - Ultra 64 Development Environment, 2.0I
  ---------------------------------------------------------------------------

+ IRIX 5.3 の場合

    Z Sort マイクロコードのパッケージは以下のような形式となっています.
  ---------------------------------------------------------------------------
   patchNuZST_mmddyy    (mmddyy はリリース日付)
  ---------------------------------------------------------------------------
   
    これを Software Manager または inst コマンドでインストールしてください.
    このパッチによって以下のファイルがインストールされます.
  ---------------------------------------------------------------------------
   /usr/src/PR/doc/gfxucode.ZSort/README.jp   本ファイル
   /usr/lib/PR/gspZSort.fifo.o      ZSort マイクロコード
   /usr/lib/PR/gspZSort.pl.fifo.o   ZSort マイクロコード(算術演算処理強化版)
   /usr/include/PR/gzsort.h	    ZSort 用インクルードファイル
   /usr/src/PR/demos/gzsort/*	    ZSort サンプルプログラム
  ---------------------------------------------------------------------------

 + PC Partner (Windows95/NT 版) の場合

    Z Sort マイクロコードのパッケージは以下のような形式となっています.
  ---------------------------------------------------------------------------
   ZSORTxxx.EXE		(xxx はリリース番号)
  ---------------------------------------------------------------------------

    このファイルは自己解凍形式になっています. 実行しますと, インストー
  ル先の入力を求めてきますので, ultra64 開発環境の ROOT ディレクトリを
  入力してください. Default は c:\ultra となっています. ここで指定した
  ディレクトリ下へ IRIX 版同様にファイルが展開されます.


===============================================================================
11. サンプルプログラム
===============================================================================

  サンプルプログラムは /usr/src/PR/gzsort/ 以下のディレクトリにインストー
ルされています.

o zonetri/
	  4 角形を一枚表示するものです. 最も単純な ZSort のアプリケーショ
	ンです.

o cubes-1/
	  ZSort マイクロコードを用いていろいろな種類のポリゴンを描画す
	るものです. 汎用の libzsort ライブラリを作成し, そこへデータを
	渡して描画しています. Near Clipping などの処理もライブラリ内で
	行なっています. 2 Pass 処理なのでパフォーマンスはあまりよくあ
	りません.
	  libzsort ライブラリのソースは, アセンブル言語で実装されるこ
	とを前提としているため, 若干 C 言語らしくない表記をしている部
	分があります. 


===============================================================================
12. 変更履歴
===============================================================================

10/09/97:
    Release 0.30 (beta 1)
	* 初版作成.

10/13/97:
    Release 0.31 (beta 1+)
	* サンプルプログラム zonetri を追加.
	* PC 版 (Windows95/NT) のサポート.

11/25/97:
    Release 0.32 (beta 2)
	* ドキュメントの修正.
	* gSPZWaitSignal/gSPZSendMessage GBI マクロの修正.
	* OS_TASK_SP_ONLY フラグを追加.

01/06/98:
    Release 0.33 (beta 2 for 2.0I)
	* N64 開発環境 2.0I 用に再パッケージしたもので機能的には 0.32 
	  と全く同じです.

08/04/98:
    Release 0.34
	* F3DEX2 等で使用されている最新の gbi.h ヘッダファイルと共に使う
	  とうまく動かないことの対処.

-------------------------------------------------------------------------------