WORLD.PAS 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. Uses Crt,VGAE;
  2. Const
  3. cMax3DPoints = 3000;
  4. cMaxFaces = 7000;
  5. cMaxMVs = 6280;
  6. Type
  7. T3DPoint = Record
  8. x,y,z : Real;
  9. end;
  10. TFace = Record
  11. pn : Array[1..4] of Word;
  12. d : Byte;
  13. end;
  14. TPointsArray = Array[1..cMax3DPoints] of T3DPoint;
  15. TFacesArray = Array[1..cMaxFaces] of TFace;
  16. TSFArray = Array[1..cMaxFaces] of Word;
  17. TMA = Array[0..cMaxMVs] of Real;
  18. Var
  19. P : ^TPointsArray;
  20. F : ^TFacesArray;
  21. SF : ^TSFArray;
  22. MP,MF : Word;
  23. fMainExit : Boolean;
  24. Angle : Real;
  25. SinT,CosT : ^TMA;
  26. Function CosF(Angle:Real):Real;
  27. Var
  28. t : LongInt;
  29. begin
  30. t:=Trunc(Angle*1000);
  31. If t>cMaxMVs then t:=t-cMaxMVs;
  32. If t<0 then t:=t+cMaxMVs;
  33. CosF:=CosT^[t];
  34. end;
  35. Function SinF(Angle:Real):Real;
  36. Var
  37. t : LongInt;
  38. begin
  39. t:=Trunc(Angle*1000);
  40. If t>cMaxMVs then t:=t-cMaxMVs;
  41. If t<0 then t:=t+cMaxMVs;
  42. SinF:=SinT^[t];
  43. end;
  44. Procedure AddPoint(nx,ny,nz:Real);
  45. begin
  46. If MP+1>cMax3DPoints then Exit;
  47. Inc(MP);
  48. With P^[MP] do
  49. begin
  50. x:=nx;
  51. y:=ny;
  52. z:=nz;
  53. end;
  54. end;
  55. Procedure InsertPoint(pn:Word; nx,ny,nz:Real);
  56. begin
  57. If pn+1>cMax3DPoints then Exit;
  58. If pn>MP then MP:=pn;
  59. With P^[MP] do
  60. begin
  61. x:=nx;
  62. y:=ny;
  63. z:=nz;
  64. end;
  65. end;
  66. Procedure AddFace(np1,np2,np3,np4:Word; nd:Byte);
  67. begin
  68. If MF+1>cMaxFaces then Exit;
  69. Inc(MF);
  70. With F^[MF] do
  71. begin
  72. pn[1]:=np1;
  73. pn[2]:=np2;
  74. pn[3]:=np3;
  75. pn[4]:=np4;
  76. d:=nd;
  77. end;
  78. end;
  79. Procedure InsertFace(fn,np1,np2,np3,np4:Word; nd:Byte);
  80. begin
  81. If fn+1>cMaxFaces then Exit;
  82. If fn>MF then MF:=fn;
  83. With F^[MF] do
  84. begin
  85. pn[1]:=np1;
  86. pn[2]:=np2;
  87. pn[3]:=np3;
  88. pn[4]:=np4;
  89. d:=nd;
  90. end;
  91. end;
  92. Procedure Init;
  93. Var
  94. c : Word;
  95. begin
  96. Randomize;
  97. MP:=0;
  98. MF:=0;
  99. New(P);
  100. New(F);
  101. New(SF);
  102. New(CosT);
  103. New(SinT);
  104. For c:=0 to cMaxMVs do
  105. begin
  106. CosT^[c]:=Cos(c/1000);
  107. SinT^[c]:=Sin(c/1000);
  108. end;
  109. fMainExit:=False;
  110. InitVGA;
  111. ClearScreen(0);
  112. DrawScreen;
  113. end;
  114. Procedure Done;
  115. begin
  116. DoneVGA;
  117. Dispose(SinT);
  118. Dispose(CosT);
  119. Dispose(SF);
  120. Dispose(F);
  121. Dispose(P);
  122. end;
  123. Procedure RotateX(Var x,y,z:Real; Angle:Real);
  124. Var
  125. ty,tz : Real;
  126. begin
  127. ty:=y*CosF(Angle)+z*SinF(Angle);
  128. tz:=-y*SinF(Angle)+z*CosF(Angle);
  129. y:=ty;
  130. z:=tz;
  131. end;
  132. Procedure RotateY(Var x,y,z:Real; Angle:Real);
  133. Var
  134. tx,tz : Real;
  135. begin
  136. tx:=x*CosF(Angle)-z*SinF(Angle);
  137. tz:=x*SinF(Angle)+z*CosF(Angle);
  138. x:=tx;
  139. z:=tz;
  140. end;
  141. Procedure RotateZ(Var x,y,z:Real; Angle:Real);
  142. Var
  143. tx,ty : Real;
  144. begin
  145. tx:=x*CosF(Angle)+y*SinF(Angle);
  146. ty:=-x*SinF(Angle)+y*CosF(Angle);
  147. x:=tx;
  148. y:=ty;
  149. end;
  150. Function ProjectPoint(x,y,z:Real; Var sx,sy:Integer):Boolean;
  151. Var
  152. t : Real;
  153. begin
  154. ProjectPoint:=False;
  155. If z<=0 then Exit;
  156. t:=x*cMaxY/z;
  157. { If Abs(t)>cMaxX*2 then Exit;}
  158. If Abs(t)>cMaxX div 2 then Exit;
  159. {!} { Здесь нужно придумать правильные границы выхода за экран }
  160. { Что лучше: cMaxX*2 (рисовать с "запасом") или
  161. cMaxX div 2 (присекать любые попытки выхода за экран)? }
  162. sx:=160+Trunc(t);
  163. t:=y*cMaxY/z;
  164. { If Abs(t)>cMaxY*2 then Exit;}
  165. If Abs(t)>cMaxY div 2 then Exit;
  166. sy:=100+Trunc(t);
  167. ProjectPoint:=True;
  168. end;
  169. Procedure DrawPoints;
  170. Var
  171. c : Word;
  172. sx,sy : Integer;
  173. begin
  174. For c:=1 to MP do
  175. With P^[c] do
  176. If ProjectPoint(x,y,z,sx,sy) then PutPixel(sx,sy,15);
  177. end;
  178. Procedure DPolygon(x1,y1,x2,y2,x3,y3,x4,y4:Integer; d:Byte);
  179. begin
  180. Line(x1,y1,x2,y2,d);
  181. Line(x2,y2,x3,y3,d);
  182. Line(x3,y3,x4,y4,d);
  183. Line(x4,y4,x1,y1,d);
  184. end;
  185. Function CenterZ(fn:Word):Real;
  186. begin
  187. CenterZ:=(P^[F^[fn].pn[1]].z+P^[F^[fn].pn[2]].z+
  188. P^[F^[fn].pn[3]].z+P^[F^[fn].pn[4]].z)/4;
  189. end;
  190. Procedure SortFaces;
  191. Var
  192. c,w,t : Word;
  193. x1,y1,z1,x2,y2,z2 : Real;
  194. Procedure Sort(l,r:Integer);
  195. Var
  196. i,j : Integer;
  197. y : Word;
  198. x : Real;
  199. begin
  200. i:=l;
  201. j:=r;
  202. x:=CenterZ(SF^[(l+r) div 2]);
  203. Repeat
  204. While CenterZ(SF^[i])>x do i:=i+1;
  205. While x>CenterZ(SF^[j]) do j:=j-1;
  206. If i<=j then
  207. begin
  208. y:=SF^[i];
  209. SF^[i]:=SF^[j];
  210. SF^[j]:=y;
  211. i:=i+1;
  212. j:=j-1;
  213. end;
  214. Until i>j;
  215. If l<j then Sort(l,j);
  216. If i<r then Sort(i,r);
  217. end;
  218. begin
  219. For c:=1 to MF do SF^[c]:=c;
  220. Sort(1,MF);
  221. {!} { Может быть можно сделать сортировку еще быстрее? }
  222. { Здесь закоментирован метод сортировки пузырьком :)
  223. For c:=1 to MF do
  224. For w:=1 to MF do
  225. begin
  226. CenterXYZ(SF^[c],x1,y1,z1);
  227. CenterXYZ(SF^[w],x2,y2,z2);
  228. If z2<z1 then
  229. begin
  230. t:=SF^[c];
  231. SF^[c]:=SF^[w];
  232. SF^[w]:=t;
  233. end;
  234. end;
  235. }
  236. end;
  237. Procedure DrawFaces;
  238. Var
  239. c,w : Word;
  240. sx,sy : Array[1..4] of Integer;
  241. begin
  242. SortFaces;
  243. For c:=1 to MF do
  244. With F^[SF^[c]] do
  245. begin
  246. If (ProjectPoint(P^[pn[1]].x,P^[pn[1]].y,P^[pn[1]].z,sx[1],sy[1]) and
  247. ProjectPoint(P^[pn[2]].x,P^[pn[2]].y,P^[pn[2]].z,sx[2],sy[2]) and
  248. ProjectPoint(P^[pn[3]].x,P^[pn[3]].y,P^[pn[3]].z,sx[3],sy[3]) and
  249. ProjectPoint(P^[pn[4]].x,P^[pn[4]].y,P^[pn[4]].z,sx[4],sy[4])) then
  250. { Это, по крайней мере, не вешает/убивает задачу при выходе за экран
  251. DPolygon(sx[1],sy[1],sx[2],sy[2],sx[3],sy[3],sx[4],sy[4],d);
  252. }
  253. Polygon(sx[1],sy[1],sx[2],sy[2],sx[3],sy[3],sx[4],sy[4],d);
  254. end;
  255. end;
  256. Procedure MoveMap(Step:Real);
  257. Var
  258. c : Word;
  259. begin
  260. For c:=1 to MP do
  261. With P^[c] do z:=z+Step;
  262. end;
  263. Procedure RollMap(Step:Real);
  264. Var
  265. c : Word;
  266. begin
  267. For c:=1 to MP do
  268. With P^[c] do x:=x+Step;
  269. end;
  270. Procedure LiftMap(Step:Real);
  271. Var
  272. c : Word;
  273. begin
  274. For c:=1 to MP do
  275. With P^[c] do y:=y+Step;
  276. end;
  277. Procedure RotateXMap(Angle:Real);
  278. Var
  279. c : Word;
  280. begin
  281. For c:=1 to MP do
  282. With P^[c] do
  283. RotateX(x,y,z,Angle);
  284. end;
  285. Procedure RotateYMap(Angle:Real);
  286. Var
  287. c : Word;
  288. begin
  289. For c:=1 to MP do
  290. With P^[c] do RotateY(x,y,z,Angle);
  291. end;
  292. Procedure RotateZMap(Angle:Real);
  293. Var
  294. c : Word;
  295. begin
  296. For c:=1 to MP do
  297. With P^[c] do
  298. RotateZ(x,y,z,Angle);
  299. end;
  300. Procedure AddHut(tx,ty,tz,h,r:Real; c1,c2:Byte);
  301. Var
  302. a : Real;
  303. OMP : Word;
  304. begin
  305. a:=0;
  306. AddPoint(tx,ty-h*2,tz);
  307. OMP:=MP;
  308. AddPoint(tx+r*CosF(a),ty-h,tz-r*SinF(a));
  309. AddPoint(tx+r*CosF(a),ty,tz-r*SinF(a));
  310. Repeat
  311. a:=a+0.5;
  312. If a<=6.28 then
  313. begin
  314. AddPoint(tx+r*CosF(a),ty-h,tz-r*SinF(a));
  315. AddPoint(tx+r*CosF(a),ty,tz-r*SinF(a));
  316. AddFace(MP-3,MP-2,MP,MP-1,15+(MP-OMP) div 2);
  317. If ((MP-OMP) div 2) mod 2=0 then
  318. AddFace(MP-3,MP-1,OMP,OMP,c1) else
  319. AddFace(MP-3,MP-1,OMP,OMP,c2);
  320. end else
  321. begin
  322. AddFace(OMP+1,OMP+2,MP,MP-1,15+(MP-OMP) div 2);
  323. If ((MP-OMP) div 2) mod 2=0 then
  324. AddFace(MP-3,OMP+1,OMP,OMP,c1) else
  325. AddFace(MP-3,OMP+1,OMP,OMP,c2);
  326. end;
  327. Until a>6.28;
  328. end;
  329. Procedure Run;
  330. Var
  331. Key : Char;
  332. begin
  333. {
  334. InsertPoint(1,-50,-50,50);
  335. InsertPoint(2,50,-50,50);
  336. InsertPoint(3,50,50,50);
  337. InsertPoint(4,-50,50,50);
  338. InsertPoint(5,0,0,0);
  339. InsertPoint(6,-50,-50,0);
  340. InsertPoint(7,50,-50,0);
  341. InsertPoint(8,50,50,0);
  342. InsertPoint(9,-50,50,0);
  343. InsertFace(1,1,2,3,4,1);
  344. InsertFace(2,1,2,5,5,2);
  345. InsertFace(3,2,3,5,5,3);
  346. InsertFace(4,3,4,5,5,4);
  347. InsertFace(5,4,1,5,5,5);
  348. InsertFace(6,6,7,8,9,7);
  349. }
  350. AddHut(0,50,1000,Random(50)+100,Random(200)+200,2,10);
  351. AddHut(-1000,50,0,Random(50)+100,Random(200)+200,5,13);
  352. AddHut(1000,50,0,Random(50)+100,Random(200)+200,3,11);
  353. MoveMap(2000);
  354. LiftMap(700);
  355. Repeat
  356. ClearScreen(0);
  357. DrawFaces;
  358. { DrawPoints;}
  359. DrawScreen;
  360. If KeyPressed then
  361. begin
  362. Key:=ReadKey;
  363. Case UpCase(Key) of
  364. #0 : Case ReadKey of
  365. #75 : RotateYMap(-0.05);
  366. #77 : RotateYMap(0.05);
  367. #72 : RotateXMap(-0.05);
  368. #80 : RotateXMap(0.05);
  369. #68 : fMainExit:=True;
  370. end;
  371. 'A' : MoveMap(-20);
  372. 'Z' : MoveMap(20);
  373. 'I' : LiftMap(10);
  374. 'K' : LiftMap(-10);
  375. 'U' : RotateZMap(0.05);
  376. 'O' : RotateZMap(-0.05);
  377. 'J' : RollMap(10);
  378. 'L' : RollMap(-10);
  379. end;
  380. end;
  381. Until fMainExit;
  382. end;
  383. Begin
  384. Init;
  385. Run;
  386. Done;
  387. End.