amicube.pas 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. {
  2. Copyright (c) 2020 Karoly Balogh
  3. Rotating 3D cube in a Workbench window
  4. Example program for Free Pascal's Amiga bindings
  5. on legacy systems (OS1.x)
  6. This example program is in the Public Domain under the terms of
  7. Unlicense: http://unlicense.org/
  8. **********************************************************************}
  9. {$MEMORY 32768,4096}
  10. program amicube;
  11. uses
  12. exec, intuition, agraphics;
  13. type
  14. tvertex = record
  15. x: longint;
  16. y: longint;
  17. z: longint;
  18. pad: longint;
  19. end;
  20. const
  21. cube: array[0..7] of tvertex = (
  22. ( x: -1; y: -1; z: -1; pad: 0), // 0
  23. ( x: 1; y: -1; z: -1; pad: 0), // 1
  24. ( x: 1; y: 1; z: -1; pad: 0), // 2
  25. ( x: -1; y: 1; z: -1; pad: 0), // 3
  26. ( x: -1; y: -1; z: 1; pad: 0), // 4
  27. ( x: 1; y: -1; z: 1; pad: 0), // 5
  28. ( x: 1; y: 1; z: 1; pad: 0), // 6
  29. ( x: -1; y: 1; z: 1; pad: 0) // 7
  30. );
  31. type
  32. tface = record
  33. v1, v2, v3: longint;
  34. edge: longint;
  35. end;
  36. const
  37. faces: array[0..11] of tface = (
  38. ( v1: 0; v2: 2; v3: 1; edge: 6), // front
  39. ( v1: 2; v2: 0; v3: 3; edge: 6),
  40. ( v1: 0; v2: 1; v3: 4; edge: 5), // top
  41. ( v1: 1; v2: 5; v3: 4; edge: 3),
  42. ( v1: 3; v2: 0; v3: 7; edge: 5), // left
  43. ( v1: 0; v2: 4; v3: 7; edge: 3),
  44. ( v1: 1; v2: 2; v3: 5; edge: 5), // right
  45. ( v1: 1; v2: 6; v3: 5; edge: 6),
  46. ( v1: 2; v2: 3; v3: 6; edge: 5), // bottom
  47. ( v1: 3; v2: 7; v3: 6; edge: 3),
  48. ( v1: 4; v2: 5; v3: 6; edge: 3), // back
  49. ( v1: 6; v2: 7; v3: 4; edge: 3)
  50. );
  51. const
  52. sincos_table: array[0..255] of longint = (
  53. 0, 1608, 3216, 4821, 6424, 8022, 9616, 11204,
  54. 12785, 14359, 15924, 17479, 19024, 20557, 22078, 23586,
  55. 25079, 26557, 28020, 29465, 30893, 32302, 33692, 35061,
  56. 36409, 37736, 39039, 40319, 41575, 42806, 44011, 45189,
  57. 46340, 47464, 48558, 49624, 50659, 51664, 52638, 53580,
  58. 54490, 55367, 56211, 57021, 57797, 58537, 59243, 59913,
  59. 60546, 61144, 61704, 62227, 62713, 63161, 63571, 63943,
  60. 64276, 64570, 64826, 65042, 65219, 65357, 65456, 65515,
  61. 65535, 65515, 65456, 65357, 65219, 65042, 64826, 64570,
  62. 64276, 63943, 63571, 63161, 62713, 62227, 61704, 61144,
  63. 60546, 59913, 59243, 58537, 57797, 57021, 56211, 55367,
  64. 54490, 53580, 52638, 51664, 50659, 49624, 48558, 47464,
  65. 46340, 45189, 44011, 42806, 41575, 40319, 39039, 37736,
  66. 36409, 35061, 33692, 32302, 30893, 29465, 28020, 26557,
  67. 25079, 23586, 22078, 20557, 19024, 17479, 15924, 14359,
  68. 12785, 11204, 9616, 8022, 6424, 4821, 3216, 1608,
  69. 0, -1608, -3216, -4821, -6424, -8022, -9616,-11204,
  70. -12785,-14359,-15924,-17479,-19024,-20557,-22078,-23586,
  71. -25079,-26557,-28020,-29465,-30893,-32302,-33692,-35061,
  72. -36409,-37736,-39039,-40319,-41575,-42806,-44011,-45189,
  73. -46340,-47464,-48558,-49624,-50659,-51664,-52638,-53580,
  74. -54490,-55367,-56211,-57021,-57797,-58537,-59243,-59913,
  75. -60546,-61144,-61704,-62227,-62713,-63161,-63571,-63943,
  76. -64276,-64570,-64826,-65042,-65219,-65357,-65456,-65515,
  77. -65535,-65515,-65456,-65357,-65219,-65042,-64826,-64570,
  78. -64276,-63943,-63571,-63161,-62713,-62227,-61704,-61144,
  79. -60546,-59913,-59243,-58537,-57797,-57021,-56211,-55367,
  80. -54490,-53580,-52638,-51664,-50659,-49624,-48558,-47464,
  81. -46340,-45189,-44011,-42806,-41575,-40319,-39039,-37736,
  82. -36409,-35061,-33692,-32302,-30893,-29465,-28020,-26557,
  83. -25079,-23586,-22078,-20557,-19024,-17479,-15924,-14359,
  84. -12785,-11204, -9616, -8022, -6424, -4821, -3216, -1608
  85. );
  86. function sin(x: longint): longint; inline;
  87. begin
  88. sin:=sincos_table[x and 255];
  89. end;
  90. function cos(x: longint): longint; inline;
  91. begin
  92. cos:=sincos_table[(x + 64) and 255];
  93. end;
  94. function mulfp(a, b: longint): longint; inline;
  95. begin
  96. mulfp:=sarint64((int64(a) * b),16);
  97. end;
  98. function divfp(a, b: longint): longint;
  99. begin
  100. divfp:=(int64(a) shl 16) div b;
  101. end;
  102. procedure rotate_vertex(const v: tvertex; var vr: tvertex; xa, ya, za: longint);
  103. var
  104. x,y,z: longint;
  105. s,c: longint;
  106. begin
  107. s :=sin(ya);
  108. c :=cos(ya);
  109. x :=mulfp(c,v.x) - mulfp(s,v.z);
  110. z :=mulfp(s,v.x) + mulfp(c,v.z);
  111. if za <> 0 then
  112. begin
  113. vr.x:=mulfp(cos(za),x) + mulfp(sin(za),v.y);
  114. y :=mulfp(cos(za),v.y) - mulfp(sin(za),x);
  115. end
  116. else
  117. begin
  118. vr.x:=x;
  119. y:=v.y;
  120. end;
  121. vr.z:=mulfp(cos(xa),z) - mulfp(sin(xa),y);
  122. vr.y:=mulfp(sin(xa),z) + mulfp(cos(xa),y);
  123. end;
  124. procedure perspective_vertex(const v: tvertex; zc: longint; var xr,yr: longint);
  125. var
  126. rzc: longint;
  127. begin
  128. rzc:=divfp(1 shl 16,(v.z - zc));
  129. xr:=mulfp(mulfp(v.x,zc),rzc);
  130. yr:=mulfp(mulfp(v.y,zc),rzc);
  131. end;
  132. procedure init_cube;
  133. var
  134. i: longint;
  135. begin
  136. for i:=low(cube) to high(cube) do
  137. begin
  138. cube[i].x:=cube[i].x shl 16;
  139. cube[i].y:=cube[i].y shl 16;
  140. cube[i].z:=cube[i].z shl 16;
  141. end;
  142. end;
  143. const
  144. win_info: array[0..63] of char = '';
  145. var
  146. win: PWindow;
  147. const
  148. IDCMPS = IDCMP_CLOSEWINDOW or IDCMP_NEWSIZE or IDCMP_INTUITICKS;
  149. WFLGS = WFLG_DRAGBAR or WFLG_DEPTHGADGET or WFLG_CLOSEGADGET or WFLG_SIZEGADGET or WFLG_ACTIVATE or WFLG_NOCAREREFRESH;
  150. WINTITLE = 'FPC Amiga Cube';
  151. const
  152. winlayout: TNewWindow = (
  153. LeftEdge: 20;
  154. TopEdge: 20;
  155. Width: 240;
  156. Height: 150;
  157. DetailPen: 0;
  158. BlockPen: 1;
  159. IDCMPFlags: IDCMPS;
  160. Flags: WFLGS;
  161. FirstGadget: nil;
  162. CheckMark: nil;
  163. Title: WINTITLE;
  164. Screen: nil;
  165. BitMap: nil;
  166. MinWidth: 0;
  167. MinHeight: 0;
  168. MaxWidth: 320;
  169. MaxHeight: 200;
  170. WType: WBENCHSCREEN_F;
  171. );
  172. function open_win: PWindow;
  173. var
  174. newwin: TNewWindow;
  175. begin
  176. newwin:=winlayout;
  177. open_win:=OpenWindow(@newwin);
  178. end;
  179. function min(a, b: smallint): smallint;
  180. begin
  181. if a < b then
  182. min:=a
  183. else
  184. min:=b;
  185. end;
  186. procedure win_redraw(mx, my: longint);
  187. var
  188. sx,sy: string[16];
  189. i,cx,cy,vx,vy: longint;
  190. rcube: array[low(cube)..high(cube)] of tvertex;
  191. vr: tvertex;
  192. scale: longint;
  193. wx,wy,ww,wh: longint;
  194. begin
  195. wx:=win^.borderleft;
  196. ww:=win^.width-(win^.borderleft+win^.borderright);
  197. wy:=win^.bordertop;
  198. wh:=win^.height-(win^.bordertop+win^.borderbottom);
  199. scale:=(min(wh,ww) div 4) shl 16;
  200. cx:=wx + ww div 2;
  201. cy:=wy + wh div 2;
  202. for i:=low(cube) to high(cube) do
  203. begin
  204. rotate_vertex(cube[i],vr,-my,-mx,0);
  205. perspective_vertex(vr,3 shl 16,vx,vy);
  206. rcube[i].x:=cx + sarlongint(mulfp(vx,scale),16);
  207. rcube[i].y:=cy + sarlongint(mulfp(vy,scale div 2),16);
  208. // the div 2 part above is a hack, to make the cube look
  209. // less distorted on a 640x256 screen...
  210. end;
  211. str(mx,sx);
  212. str(my,sy);
  213. win_info:='Spinning... X:'+sx+' Y:'+sy;
  214. SetAPen(win^.rport,0);
  215. RectFill(win^.rport,wx,wy,wx+ww,wy+wh);
  216. SetAPen(win^.rport,1);
  217. gfxMove(win^.rport,wx+5,wy+10);
  218. gfxText(win^.rport, win_info, strlen(win_info));
  219. for i:=low(faces) to high(faces) do
  220. begin
  221. with faces[i] do
  222. begin
  223. if (edge and 1) > 0 then
  224. begin
  225. gfxMove(win^.rport,rcube[v1].x,rcube[v1].y);
  226. draw(win^.rport,rcube[v2].x,rcube[v2].y);
  227. end;
  228. if (edge and 2) > 0 then
  229. begin
  230. gfxMove(win^.rport,rcube[v2].x,rcube[v2].y);
  231. draw(win^.rport,rcube[v3].x,rcube[v3].y);
  232. end;
  233. if (edge and 4) > 0 then
  234. begin
  235. gfxMove(win^.rport,rcube[v3].x,rcube[v3].y);
  236. draw(win^.rport,rcube[v1].x,rcube[v1].y);
  237. end;
  238. end;
  239. end;
  240. end;
  241. procedure event_loop;
  242. var
  243. quit: boolean;
  244. IMsg: PIntuiMessage;
  245. //ICode: Word;
  246. //IQual: Word;
  247. IClass: LongWord;
  248. MouseX: LongInt;
  249. MouseY: LongInt;
  250. OldMouseX: LongInt;
  251. OldMouseY: LongInt;
  252. begin
  253. quit:=false;
  254. OldMouseX:=-1;
  255. OldMouseY:=-1;
  256. repeat
  257. IMsg:=PIntuiMessage(WaitPort(win^.UserPort));
  258. IMsg:=PIntuiMessage(GetMsg(win^.UserPort));
  259. while IMsg <> nil do
  260. begin
  261. //ICode:=IMsg^.Code;
  262. //IQual:=IMsg^.Qualifier;
  263. IClass:=IMsg^.iClass;
  264. MouseX:=IMsg^.MouseX;
  265. MouseY:=IMsg^.MouseY;
  266. ReplyMsg(PMessage(IMsg));
  267. case IClass of
  268. IDCMP_NEWSIZE:
  269. begin
  270. win_redraw(OldMouseX,OldMouseY);
  271. end;
  272. IDCMP_CLOSEWINDOW:
  273. begin
  274. quit:=true;
  275. end;
  276. IDCMP_INTUITICKS:
  277. begin
  278. if (MouseX <> OldMouseX) or (MouseY <> OldMouseY) then
  279. begin
  280. OldMouseX:=MouseX;
  281. OldMouseY:=MouseY;
  282. win_redraw(OldMouseX,OldMouseY);
  283. end;
  284. end;
  285. end;
  286. IMsg:=PIntuiMessage(GetMsg(win^.UserPort));
  287. end;
  288. until quit;
  289. end;
  290. begin
  291. init_cube;
  292. win:=open_win;
  293. if win <> nil then
  294. begin
  295. event_loop;
  296. CloseWindow(win);
  297. end;
  298. end.