gemcube.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. {
  2. Copyright (c) 2017 Karoly Balogh
  3. Rotating 3D cube in a GEM window
  4. Example program for Free Pascal's Atari TOS bindings
  5. This example program is in the Public Domain under the terms of
  6. Unlicense: http://unlicense.org/
  7. **********************************************************************}
  8. {$APPTYPE GUI}
  9. {$MODESWITCH OUT+}
  10. {$WARN 3124 OFF}
  11. {$WARN 4055 OFF}
  12. program gemcube;
  13. uses
  14. aes, vdi;
  15. type
  16. tvertex = record
  17. x: longint;
  18. y: longint;
  19. z: longint;
  20. end;
  21. const
  22. cube: array[0..7] of tvertex = (
  23. ( x: -1; y: -1; z: -1; ), // 0
  24. ( x: 1; y: -1; z: -1; ), // 1
  25. ( x: 1; y: 1; z: -1; ), // 2
  26. ( x: -1; y: 1; z: -1; ), // 3
  27. ( x: -1; y: -1; z: 1; ), // 4
  28. ( x: 1; y: -1; z: 1; ), // 5
  29. ( x: 1; y: 1; z: 1; ), // 6
  30. ( x: -1; y: 1; z: 1; ) // 7
  31. );
  32. type
  33. tface = record
  34. v1, v2, v3: longint;
  35. edge: longint;
  36. end;
  37. const
  38. faces: array[0..11] of tface = (
  39. ( v1: 0; v2: 2; v3: 1; edge: 6), // front
  40. ( v1: 2; v2: 0; v3: 3; edge: 6),
  41. ( v1: 0; v2: 1; v3: 4; edge: 5), // top
  42. ( v1: 1; v2: 5; v3: 4; edge: 3),
  43. ( v1: 3; v2: 0; v3: 7; edge: 5), // left
  44. ( v1: 0; v2: 4; v3: 7; edge: 3),
  45. ( v1: 1; v2: 2; v3: 5; edge: 5), // right
  46. ( v1: 1; v2: 6; v3: 5; edge: 6),
  47. ( v1: 2; v2: 3; v3: 6; edge: 5), // bottom
  48. ( v1: 3; v2: 7; v3: 6; edge: 3),
  49. ( v1: 4; v2: 5; v3: 6; edge: 3), // back
  50. ( v1: 6; v2: 7; v3: 4; edge: 3)
  51. );
  52. const
  53. sincos_table: array[0..255] of longint = (
  54. 0, 1608, 3216, 4821, 6424, 8022, 9616, 11204,
  55. 12785, 14359, 15924, 17479, 19024, 20557, 22078, 23586,
  56. 25079, 26557, 28020, 29465, 30893, 32302, 33692, 35061,
  57. 36409, 37736, 39039, 40319, 41575, 42806, 44011, 45189,
  58. 46340, 47464, 48558, 49624, 50659, 51664, 52638, 53580,
  59. 54490, 55367, 56211, 57021, 57797, 58537, 59243, 59913,
  60. 60546, 61144, 61704, 62227, 62713, 63161, 63571, 63943,
  61. 64276, 64570, 64826, 65042, 65219, 65357, 65456, 65515,
  62. 65535, 65515, 65456, 65357, 65219, 65042, 64826, 64570,
  63. 64276, 63943, 63571, 63161, 62713, 62227, 61704, 61144,
  64. 60546, 59913, 59243, 58537, 57797, 57021, 56211, 55367,
  65. 54490, 53580, 52638, 51664, 50659, 49624, 48558, 47464,
  66. 46340, 45189, 44011, 42806, 41575, 40319, 39039, 37736,
  67. 36409, 35061, 33692, 32302, 30893, 29465, 28020, 26557,
  68. 25079, 23586, 22078, 20557, 19024, 17479, 15924, 14359,
  69. 12785, 11204, 9616, 8022, 6424, 4821, 3216, 1608,
  70. 0, -1608, -3216, -4821, -6424, -8022, -9616,-11204,
  71. -12785,-14359,-15924,-17479,-19024,-20557,-22078,-23586,
  72. -25079,-26557,-28020,-29465,-30893,-32302,-33692,-35061,
  73. -36409,-37736,-39039,-40319,-41575,-42806,-44011,-45189,
  74. -46340,-47464,-48558,-49624,-50659,-51664,-52638,-53580,
  75. -54490,-55367,-56211,-57021,-57797,-58537,-59243,-59913,
  76. -60546,-61144,-61704,-62227,-62713,-63161,-63571,-63943,
  77. -64276,-64570,-64826,-65042,-65219,-65357,-65456,-65515,
  78. -65535,-65515,-65456,-65357,-65219,-65042,-64826,-64570,
  79. -64276,-63943,-63571,-63161,-62713,-62227,-61704,-61144,
  80. -60546,-59913,-59243,-58537,-57797,-57021,-56211,-55367,
  81. -54490,-53580,-52638,-51664,-50659,-49624,-48558,-47464,
  82. -46340,-45189,-44011,-42806,-41575,-40319,-39039,-37736,
  83. -36409,-35061,-33692,-32302,-30893,-29465,-28020,-26557,
  84. -25079,-23586,-22078,-20557,-19024,-17479,-15924,-14359,
  85. -12785,-11204, -9616, -8022, -6424, -4821, -3216, -1608
  86. );
  87. function sin(x: longint): longint; inline;
  88. begin
  89. sin:=sincos_table[x and 255];
  90. end;
  91. function cos(x: longint): longint; inline;
  92. begin
  93. cos:=sincos_table[(x + 64) and 255];
  94. end;
  95. function mulfp(a, b: longint): longint; inline;
  96. begin
  97. mulfp:=sarint64((int64(a) * b),16);
  98. end;
  99. function divfp(a, b: longint): longint;
  100. begin
  101. divfp:=(int64(a) shl 16) div b;
  102. end;
  103. procedure rotate_vertex(const v: tvertex; out vr: tvertex; xa, ya, za: longint);
  104. var
  105. x,y,z: longint;
  106. s,c: longint;
  107. begin
  108. s :=sin(ya);
  109. c :=cos(ya);
  110. x :=mulfp(c,v.x) - mulfp(s,v.z);
  111. z :=mulfp(s,v.x) + mulfp(c,v.z);
  112. if za <> 0 then
  113. begin
  114. vr.x:=mulfp(cos(za),x) + mulfp(sin(za),v.y);
  115. y :=mulfp(cos(za),v.y) - mulfp(sin(za),x);
  116. end
  117. else
  118. begin
  119. vr.x:=x;
  120. y:=v.y;
  121. end;
  122. vr.z:=mulfp(cos(xa),z) - mulfp(sin(xa),y);
  123. vr.y:=mulfp(sin(xa),z) + mulfp(cos(xa),y);
  124. end;
  125. procedure perspective_vertex(const v: tvertex; zc: longint; out xr,yr: longint);
  126. var
  127. rzc: longint;
  128. begin
  129. rzc:=divfp(1 shl 16,(v.z - zc));
  130. xr:=mulfp(mulfp(v.x,zc),rzc);
  131. yr:=mulfp(mulfp(v.y,zc),rzc);
  132. end;
  133. procedure init_cube;
  134. var
  135. i: longint;
  136. begin
  137. for i:=low(cube) to high(cube) do
  138. begin
  139. cube[i].x:=cube[i].x shl 16;
  140. cube[i].y:=cube[i].y shl 16;
  141. cube[i].z:=cube[i].z shl 16;
  142. end;
  143. end;
  144. const
  145. win_info: array[0..63] of AnsiChar = '';
  146. var
  147. appl_h: smallint;
  148. win_h: smallint;
  149. win_name: PAnsiChar;
  150. vdi_h: smallint;
  151. mx, my: smallint;
  152. const
  153. WIN_KIND = NAME or INFO or CLOSER or MOVER or SIZER or FULLER;
  154. function open_vwk: smallint;
  155. var
  156. work_in: array[0..16] of smallint;
  157. work_out: array[0..64] of smallint;
  158. dummy, i: smallint;
  159. handle: smallint;
  160. xyarray: array[0..3] of smallint;
  161. begin
  162. handle:=graf_handle(@dummy,@dummy,@dummy,@dummy);
  163. for i:=0 to 9 do work_in[i]:=1;
  164. work_in[10]:=2;
  165. v_opnvwk(@work_in, @handle, @work_out);
  166. xyarray[0]:=0;
  167. xyarray[1]:=0;
  168. xyarray[2]:=work_out[0];
  169. xyarray[3]:=work_out[1];
  170. vs_clip(handle,1,@xyarray);
  171. open_vwk:=handle;
  172. end;
  173. function wind_get_grect(wh, what: smallint; rect: PGRECT): boolean;
  174. begin
  175. wind_get_grect:=wind_get(wh, what, @rect^.x, @rect^.y, @rect^.w, @rect^.h)<>0;
  176. end;
  177. function open_win: smallint;
  178. var
  179. handle: smallint;
  180. dim: TGRECT;
  181. begin
  182. handle:=wind_create(WIN_KIND, 0, 0, 0, 0);
  183. win_name:='FPC GEM Cube';
  184. wind_set(handle, WF_NAME, hi(ptruint(win_name)), lo(ptruint(win_name)), 0, 0);
  185. win_info:='Spinning...';
  186. wind_set(handle, WF_INFO, hi(ptruint(@win_info)), lo(ptruint(@win_info)), 0, 0);
  187. wind_get_grect(0, WF_WORKXYWH, @dim);
  188. dim.x:=dim.x + (dim.w div 20);
  189. dim.y:=dim.y + (dim.h div 20);
  190. dim.w:=dim.w - (dim.w div 20) * 2;
  191. dim.h:=dim.h - (dim.h div 20) * 2;
  192. wind_open(handle, dim.x, dim.y, dim.w, dim.h);
  193. open_win:=handle;
  194. end;
  195. procedure wind_set_grect(wh: smallint; rect: PGRECT);
  196. var
  197. fsrect: TGRECT;
  198. begin
  199. if rect = nil then
  200. begin
  201. wind_get_grect(0, WF_WORKXYWH, @fsrect);
  202. rect:=@fsrect;
  203. end;
  204. wind_set(wh,WF_CURRXYWH,rect^.x,rect^.y,rect^.w,rect^.h);
  205. end;
  206. function min(a, b: smallint): smallint;
  207. begin
  208. if a < b then
  209. min:=a
  210. else
  211. min:=b;
  212. end;
  213. function max(a, b: smallint): smallint;
  214. begin
  215. if a > b then
  216. max:=a
  217. else
  218. max:=b;
  219. end;
  220. procedure draw_line(x1,y1,x2,y2: smallint);
  221. var
  222. xyarray: array[0..7] of smallint;
  223. begin
  224. xyarray[0]:=x1;
  225. xyarray[1]:=y1;
  226. xyarray[2]:=x2;
  227. xyarray[3]:=y2;
  228. v_pline(vdi_h,2,@xyarray);
  229. end;
  230. function rc_intersect(p1: PGRECT; p2: PGRECT): boolean;
  231. var
  232. tx, ty, tw, th: smallint;
  233. begin
  234. tw:=min(p2^.x+p2^.w, p1^.x+p1^.w);
  235. th:=min(p2^.y+p2^.h, p1^.y+p1^.h);
  236. tx:=max(p2^.x, p1^.x);
  237. ty:=max(p2^.y, p1^.y);
  238. p2^.x:=tx;
  239. p2^.y:=ty;
  240. p2^.w:=tw-tx;
  241. p2^.h:=th-ty;
  242. rc_intersect:=(tw > tx) and (th > ty);
  243. end;
  244. procedure wind_redraw(wh: smallint; rect: PGRECT);
  245. var
  246. i,cx,cy,vx,vy: longint;
  247. xyarray: array[0..7] of smallint;
  248. rcube: array[low(cube)..high(cube)] of tvertex;
  249. wrect: TGRECT;
  250. vr: tvertex;
  251. scale: longint;
  252. begin
  253. wind_update(BEG_UPDATE);
  254. v_hide_c(vdi_h);
  255. wind_get_grect(wh,WF_FIRSTXYWH,@wrect);
  256. while (wrect.w<>0) and (wrect.h<>0) do
  257. begin
  258. if rc_intersect(rect,@wrect) then
  259. begin
  260. xyarray[0]:=wrect.x;
  261. xyarray[1]:=wrect.y;
  262. xyarray[2]:=wrect.x+wrect.w-1;
  263. xyarray[3]:=wrect.y+wrect.h-1;
  264. vs_clip(vdi_h, 1, @xyarray);
  265. vsf_color(vdi_h,WHITE);
  266. v_bar(vdi_h,@xyarray);
  267. wind_get_grect(win_h,WF_WORKXYWH,@wrect);
  268. scale:=(min(wrect.h,wrect.w) div 5) shl 16;
  269. cx:=wrect.x + wrect.w div 2;
  270. cy:=wrect.y + wrect.h div 2;
  271. for i:=low(cube) to high(cube) do
  272. begin
  273. rotate_vertex(cube[i],vr,-my,-mx,0);
  274. perspective_vertex(vr,3 shl 16,vx,vy);
  275. rcube[i].x:=cx + sarlongint(mulfp(vx,scale),16);
  276. rcube[i].y:=cy + sarlongint(mulfp(vy,scale),16);
  277. end;
  278. vsl_color(vdi_h,RED);
  279. for i:=low(faces) to high(faces) do
  280. begin
  281. if (faces[i].edge and 1) > 0 then
  282. draw_line(rcube[faces[i].v1].x,rcube[faces[i].v1].y,
  283. rcube[faces[i].v2].x,rcube[faces[i].v2].y);
  284. if (faces[i].edge and 2) > 0 then
  285. draw_line(rcube[faces[i].v2].x,rcube[faces[i].v2].y,
  286. rcube[faces[i].v3].x,rcube[faces[i].v3].y);
  287. if (faces[i].edge and 4) > 0 then
  288. draw_line(rcube[faces[i].v3].x,rcube[faces[i].v3].y,
  289. rcube[faces[i].v1].x,rcube[faces[i].v1].y);
  290. end;
  291. end;
  292. wind_get_grect(wh,WF_NEXTXYWH,@wrect);
  293. end;
  294. v_show_c(vdi_h,0);
  295. wind_update(END_UPDATE);
  296. end;
  297. procedure event_loop;
  298. var
  299. msg_buf: array[0..7] of smallint;
  300. sx,sy: string[16];
  301. nmx,nmy: smallint;
  302. dummy: smallint;
  303. e: smallint;
  304. begin
  305. graf_mouse(ARROW, nil);
  306. repeat
  307. dummy:=0;
  308. e:=evnt_multi(MU_TIMER or MU_MESAG,dummy,dummy,dummy,
  309. dummy,dummy,dummy,dummy,dummy,
  310. dummy,dummy,dummy,dummy,dummy,
  311. @msg_buf,
  312. 50,0,
  313. @dummy,@dummy,@dummy,@dummy,
  314. @dummy,@dummy);
  315. if e = MU_TIMER then
  316. begin
  317. graf_mkstate(@nmx,@nmy,@dummy,@dummy);
  318. if (nmx <> mx) or (nmy <> my) then
  319. begin
  320. mx:=nmx;
  321. my:=nmy;
  322. str(mx,sx);
  323. str(my,sy);
  324. win_info:='Spinning... X:'+sx+' Y:'+sy;
  325. wind_set(win_h, WF_INFO, hi(ptruint(@win_info)), lo(ptruint(@win_info)), 0, 0);
  326. wind_get_grect(win_h, WF_WORKXYWH, PGRECT(@msg_buf[4]));
  327. msg_buf[0]:=WM_REDRAW;
  328. msg_buf[1]:=appl_h;
  329. msg_buf[2]:=0;
  330. msg_buf[3]:=win_h;
  331. appl_write(appl_h, sizeof(msg_buf), @msg_buf);
  332. end;
  333. end;
  334. if e = MU_MESAG then
  335. case msg_buf[0] of
  336. WM_CLOSED:
  337. break;
  338. WM_REDRAW:
  339. wind_redraw(win_h,PGRECT(@msg_buf[4]));
  340. WM_MOVED,
  341. WM_SIZED:
  342. wind_set_grect(win_h,PGRECT(@msg_buf[4]));
  343. WM_FULLED:
  344. wind_set_grect(win_h,nil);
  345. WM_TOPPED,WM_NEWTOP:
  346. wind_set(win_h,WF_TOP,0,0,0,0);
  347. end;
  348. until false;
  349. end;
  350. begin
  351. appl_h:=appl_init;
  352. init_cube;
  353. vdi_h:=open_vwk;
  354. win_h:=open_win;
  355. event_loop;
  356. wind_close(win_h);
  357. wind_delete(win_h);
  358. v_clsvwk(vdi_h);
  359. appl_exit;
  360. end.