' ========================= ' Purpose of this program ' ========================= ' ' This is the CANVAS context. It provides a High Performance Canvas ' for demonstration drawing purposes. ' ' It can be used either with GLUT, ALLEGRO 5, SDL 1.2 or GLFW, and should ' use an OpenGL enabled graphics card for maximum performance. ' ' The top left of the created window has coordinate (0, 0). ' ' ========================= ' Documentation for the API ' ========================= ' ' BACKEND(type$) ' => Instead of autodetecting, force the canvas using SDL, GLUT, GLFW or ALLEGRO backend. Used for debug purposes. ' ' WINDOW(title$, xsize, ysize) ' => Create a window with canvas using a title, x size and y size ' ' FULLSCREEN ' => Create a full screen canvas using the current screen resolution ' ' PIXEL(x, y) ' => Put a pixel in the current color on position x, y ' ' LINE(xstart, ystart, xend, yend) ' => Draw a line from xstart, ystart to xend, yend ' ' SQUARE(x, y, xradius, yradius, fill) ' => Draw a square with center position at x, y and radius x radius y. ' ' OUTLINE(..., fill) ' => Draw a polygon with a variable amount of coordinates in x,y,x,y,... format. ' ' CIRCLE(x, y, xsize, ysize, fill) ' => Draw a circle with center position at x, y and radius x, y. ' ' ARC(x, y, xsize, ysize, start, end, fill) ' => Draw an arc with center position at x, y and radius x, y, start and end (degrees). ' ' TRIANGLE(x, y, base, height, fill) ' => Draw a triangle with center position at x, y and base/height. ' ' POLYGON(x, y, radius, sides, fill) ' => Draw a polygon with center position at x, y, a radius, and amount of sides. ' ' QBEZIER(xstart, ystart, bendx, bendy, xend, yend) ' => Draw a quadratic Bezier curve starting at (xstart, ystart), ending at (xend, yend) bended by (bendx, bendy) ' ' CBEZIER(xstart, ystart, bend1x, bend1y, bend2x, bend2y, xend, yend) ' => Draw a cubic Bezier curve starting at (xstart, ystart), ending at (xend, yend) bended by (bend1x, bend1y) and (bend2x, bend2y). ' ' PAINT(x, y) ' => Fill with current color starting and x, y ' ' FONTALIGN(x) ' => In case of scaling, align font centered (0 = default) or align font on x-position (1 = left). ' ' TEXTLEN(txt$) ' => Returns the length of the text in pixels. ' ' TEXT(txt$, x, y) ' => Put text txt$ and position x, y ' ' GETINK(x, y, mode) ' => Obtain color at position x,y. Mode values: 0=r 1=g 2=b 3=alpha, 4=RGBA 5=ABGR quadruple in one integer of 4 bytes ' ' FLIP(x) ' => Flip the image where x=0: horizontal x=1: vertical x=2: horizontal and vertical. Other values are ignored. ' ' GRID(x, y, w, h, hboxes, vboxes) ' => Create a grid at x, y topleft, with size w, h and amount of boxes hboxes, vboxes ' ' INK(r, g, b, a) ' => Set the color to r, g, b and use alpha a (all 0-255) ' ' PEN(x, yesno) ' => Set the width of the pixel to x (float value), and use anti-aliasing y/n ' ' ROTATION(angle) ' => Set the default rotation for LINE, CIRCLE, SQUARE, TRIANGLE, ARC, POLYGON, GRID, TEXT to (in degrees) ' ' SCALE(factor) ' => Set scaling for LINE, CIRCLE, SQUARE, TRIANGLE, ARC, POLYGON, GRID, TEXT to (float value) ' ' MOVE(angle, distance) ' => Move LINE, CIRCLE, SQUARE, TRIANGLE, ARC, POLYGON, GRID, TEXT pixels in the direction of . ' ' SYNC ' => Swap the background buffer to the canvas ' ' QUIT ' => Quit the canvas module ' ' CLS ' => Clear the screen in the last color set by INK ' ' CALLBACK(timeout, function) ' => Call function repeatedly after timeout of millisecs. Usable for moving pictures. ' ' WAITKEY ' => Wait for a key to be pressed, this will exit the program ' ' PENUP ' => Take the pen from the canvas ' ' PENDOWN ' => Put the pen back onto the canvas (default) ' ' PENXY(x, y) ' => Set the current x and y coordinate of the pen ' ' PENTYPE(type) ' => Set the type of pen drawing, 0 = line, 1 = arc ' ' TURNRIGHT(angle) ' => Rotate the direction of the pen to the right in degrees ' ' TURN(angle) / TURNLEFT(angle) ' => Rotate the direction of the pen to the left in degrees ' ' RESETANGLE ' => Put the angle of the turtle back to 90 ' ' DRAW(length) ' => Draw using the pen ' ' LOADFONT("file.jhf") ' => Load Hershey vector font in "James Hunt Format" - see http://www.whence.com/hershey-fonts/ ' ' MOUSE(n) ' => Query mouse state, n=0: xposition, n=1: yposition, n=2: button press, left button(1), middle(2), right(3), up(4), down(5) n=3: state, pressed(1) released(0) ' ' WIDTH / HEIGHT ' => Contain the width and height of the canvas ' ' REFRESH ' => Refresh rate of monitor ' ' =========================== ' License and release history ' =========================== ' ' The concept of the turtle drawing with friendly permission from Tomaaz: ' PENON, PENOFF, PENXY, TURNRIGHT, TURNLEFT, TURN, DRAW. ' ' (c) Peter van Eerten, September/June 2017 - MIT License. ' ' 1.0: Initial release. ' 1.1: Lower case functions, CLS can use last color set by INK. ' 1.2: Fixed alpha blending - thx forum member vovchik. Added SCALE. ' 1.3: Improved anti-aliasing - thx forum member vovchik. ' 1.4: Improved pixel rendering - thx forum member vovchik. ' 1.5: Improved SCALE. ' 1.6: Callback did not obey delay in timer (GLUT). ' 2.0: Added API for turtle handling based on Tomaaz turtle context. Added ARC primitive. CIRCLE and ARC now use radius instead of total size. ' 2.1: Added POLYGON, GRID, fixed crash in PAINT - thx forum member vovchik. ' 2.2: Fixed PAINT issue in 32bit. Improved ARC and CIRCLE. ' 2.3: Fixed TRIANGLE, POLYGON and GRID for rotation and scaling. Improved pixel rendering - thx forum member vovchik. ' 2.4: Improved global variable structure. CALLBACK automatically will use a SYNC after the user function was invoked. ' 2.5: Added support for scalable fonts in "jhf" format - thx forum member vovchik. ' 2.6: Fixed bug in GRID - thx forum member vovchik. ' 2.7: Added MOVE. ' 2.8: Added support for LibGLFW. ' 2.9: Small code improvements. Added GETINK - thx forum member vovchik. ' 2.10: Improved import logic. Improved GETINK - thx forum member vovchik. ' 2.11: Added OpenGL calls for importing images. ' 2.12: Callbacked function should start immediately and not wait for delay. ' 2.13: Added glPixelZoom for image flipping. ' 2.14: Added FLIP, QBEZIER and CBEZIER. ' 2.15: Improved FLIP so it works for plain images too. ' 2.16: More improvemens in FLIP so it works in any order. ' 2.17: POLYGON did not declare xpos,ypos variables locally. ' 2.18: Fixed passing float arguments to Check_Scale and Check_Rotation - thx forum member vovchik. ' 2.19: Casted arguments to 'float' type where necessary. Added GL functions to query driver. ' 2.20: Implemented support for MOUSE events. Call BACKEND to force backend. ' 2.21: Improved mouse support for GLUT. ' 2.22: Improved callback mechanism for GLFW. ' 2.23: Better casting of CIRCLE arguments prevents unexpected results. ' 2.24: Support for fullscreen canvas. ' 2.25: Enable multisampling also for Allegro, SDL, GLFW ' 2.26: Scaling should also apply to glDrawPixel ' 2.27: REFRESH contains refresh rate of current screen. ' 2.28: Added GL_RGB constant. ' 2.29: Support for mouse wheel (GLUT, SDL, GLFW). ' 2.30: Mouse wheel support for Allegro. ' 2.31: Added texture GL calls. ' 2.32: DRAW will move turtle even in when in PENUP mode, added TURN ' 2.33: Fixed bug in drawing turtle graphics. ' 2.34: TURN accepts float. ' 2.35: Fixed issue when using BACKEND in small letters. ' 2.36: Updated with XFree call and GL stuff. ' 2.37: Added GL_SCISSOR_TEST and glScissor for Nuklear backend. ' 2.38: Improved font rendering and scaling ' 2.39: Added FONTALIGN command for alignment of scaled text ' 2.40: Changed ARC so it actually draws an arc between degrees (breaks ARC API) ' 2.41: GLUT requires glutDisplayFunc() ' 2.42: Fixes in Allegro library, added default warning when compiled standalone. ' 2.43: Another fix in GLUT, needs glutSwapBuffers() before mainloop. ' 2.44: Added TEXTLEN function. ' 2.45: Improved mouse event handling. ' 2.46: Added OUTLINE directive. ' 2.47: Corrected some C-like variable names. '--------------------------------------------------------------------------------------------------------------------------------------------- ' Default message in case accidentally compiled as a standalone program IF BASENAME$(ME$) = "canvas" THEN PRINT "This is the canvas include file." PRAGMA INCLUDE ' Globals used by this context RECORD CANVAS LOCAL library$ LOCAL win TYPE void* LOCAL back_end, rotate, xsize, ysize, timerval, font_width, font_align, step, angle, flipping LOCAL pen_smooth, pen_active, pen_type LOCAL pen_size, scaling, pen_xpos, pen_ypos, pen_direction TYPE float LOCAL mbutton, mstate, mx, my TYPE int LOCAL (*callb)(void) TYPE void LOCAL font$[96] END RECORD ' Setting the stack size to 64Mb to allow recursive paint USEC struct rlimit rl; getrlimit (RLIMIT_STACK, &rl); rl.rlim_cur = RLIM_INFINITY; setrlimit (RLIMIT_STACK, &rl); ENDUSEC ' This is the "futurum.jhf" font from the hershey-font package. Their license requires that the following acknowledgements must be distributed with the font data: ' - The Hershey Fonts were originally created by Dr. A. V. Hershey while working at the U. S. National Bureau of Standards. ' - The format of the Font data in this distribution was originally created by James Hurt Cognition, Inc., 900 Technology Park Drive, Billerica, MA 01821 DATA " 1JZ" DATA " 24MXRFRTST RRFSFST RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY" DATA " 22I[NFMGMM RNGMM RNFOGMM RWFVGVM RWGVM RWFXGVM" DATA " 12H]SBLb RYBRb RLOZO RKUYU" DATA " 51I\\RBR_S_ RRBSBS_ RWIYIWGTFQFNGLILKMMNNVRWSXUXWWYTZQZOYNX RWIVHTGQGNHMIMKNMVQXSYUYWXYWZT[Q[NZLXNX RXXUZ" DATA " 32F^[FI[ RNFPHPJOLMMKMIKIIJGLFNFPGSHVHYG[F RWTUUTWTYV[X[ZZ[X[VYTWT" DATA " 49F_[NZO[P\\O\\N[MZMYNXPVUTXRZP[M[JZIXIUJSPORMSKSIRGPFNGMIMKNNPQUXWZZ[[[\\Z\\Y RM[KZJXJUKSMQ RMKNMVXXZZ[" DATA " 11NWSFRGRM RSGRM RSFTGRM" DATA " 20KYVBTDRGPKOPOTPYR]T`Vb RTDRHQKPPPTQYR\\T`" DATA " 20KYNBPDRGTKUPUTTYR]P`Nb RPDRHSKTPTTSYR\\P`" DATA " 39JZRFQGSQRR RRFRR RRFSGQQRR RMINIVOWO RMIWO RMIMJWNWO RWIVINOMO RWIMO RWIWJMNMO" DATA " 16F_RIRZSZ RRISISZ RJQ[Q[R RJQJR[R" DATA " 24MXTZS[R[QZQYRXSXTYT\\S^Q_ RRYRZSZSYRY RS[T\\ RTZS^" DATA " 3E_IR[R" DATA " 16MXRXQYQZR[S[TZTYSXRX RRYRZSZSYRY" DATA " 8G^[BIbJb R[B\\BJb" DATA " 42H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF ROGMJLOLRMWOZ RNYQZSZVY RUZWWXRXOWJUG RVHSGQGNH" DATA " 12H\\NJPISFS[ RNJNKPJRHR[S[" DATA " 34H\\LKLJMHNGPFTFVGWHXJXLWNUQL[ RLKMKMJNHPGTGVHWJWLVNTQK[ RLZYZY[ RK[Y[" DATA " 48H\\MFXFQO RMFMGWG RWFPO RQNSNVOXQYTYUXXVZS[P[MZLYKWLW RPOSOVPXS RTOWQXTXUWXTZ RXVVYSZPZMYLW ROZLX" DATA " 18H\\UIU[V[ RVFV[ RVFKVZV RUILV RLUZUZV" DATA " 53H\\MFLO RNGMN RMFWFWG RNGWG RMNPMSMVNXPYSYUXXVZS[P[MZLYKWLW RLOMOONSNVOXR RTNWPXSXUWXTZ RXVVYSZPZMYLW ROZLX" DATA " 62H\\VGWIXIWGTFRFOGMJLOLTMXOZR[S[VZXXYUYTXQVOSNRNOOMQ RWHTGRGOH RPGNJMOMTNXQZ RMVOYRZSZVYXV RTZWXXUXTWQTO RXSVPSOROOPMS RQONQMT" DATA " 12H\\KFYFO[ RKFKGXG RXFN[O[" DATA " 68H\\PFMGLILKMMNNPOTPVQWRXTXWWYTZPZMYLWLTMRNQPPTOVNWMXKXIWGTFPF RNGMIMKNMPNTOVPXRYTYWXYWZT[P[MZLYKWKTLRNPPOTNVMWKWIVG RWHTGPGMH RLXOZ RUZXX" DATA " 62H\\WPURRSQSNRLPKMKLLINGQFRFUGWIXMXRWWUZR[P[MZLXMXNZ RWMVPSR RWNUQRRQRNQLN RPRMPLMLLMIPG RLKNHQGRGUHWK RSGVIWMWRVWTZ RUYRZPZMY" DATA " 32MXRMQNQORPSPTOTNSMRM RRNROSOSNRN RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY" DATA " 40MXRMQNQORPSPTOTNSMRM RRNROSOSNRN RTZS[R[QZQYRXSXTYT\\S^Q_ RRYRZSZSYRY RS[T\\ RTZS^" DATA " 4F^ZIJRZ[" DATA " 16F_JM[M[N RJMJN[N RJU[U[V RJUJV[V" DATA " 4F^JIZRJ[" DATA " 58I\\LKLJMHNGQFTFWGXHYJYLXNWOUPRQ RLKMKMJNHQGTGWHXJXLWNUORP RMIPG RUGXI RXMTP RRPRTSTSP RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY" DATA " 56E`WNVLTKQKOLNMMPMSNUPVSVUUVS RQKOMNPNSOUPV RWKVSVUXVZV\\T]Q]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYZX RXKWSWUXV" DATA " 20H\\RFJ[ RRIK[J[ RRIY[Z[ RRFZ[ RMUWU RLVXV" DATA " 44H\\LFL[ RMGMZ RLFTFWGXHYJYMXOWPTQ RMGTGWHXJXMWOTP RMPTPWQXRYTYWXYWZT[L[ RMQTQWRXTXWWYTZMZ" DATA " 38H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZV RZKYKXIWHUGQGOHMKLNLSMVOYQZUZWYXXYVZV" DATA " 32H]LFL[ RMGMZ RLFSFVGXIYKZNZSYVXXVZS[L[ RMGSGVHWIXKYNYSXVWXVYSZMZ" DATA " 27I\\MFM[ RNGNZ RMFYF RNGYGYF RNPTPTQ RNQTQ RNZYZY[ RM[Y[" DATA " 21I[MFM[ RNGN[M[ RMFYF RNGYGYF RNPTPTQ RNQTQ" DATA " 44H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZVZRUR RZKYKXIWHUGQGOHNIMKLNLSMVNXOYQZUZWYXXYVYSUSUR" DATA " 22G]KFK[ RKFLFL[K[ RYFXFX[Y[ RYFY[ RLPXP RLQXQ" DATA " 8NWRFR[S[ RRFSFS[" DATA " 20J[VFVVUYSZQZOYNVMV RVFWFWVVYUZS[Q[OZNYMV" DATA " 22H]LFL[M[ RLFMFM[ RZFYFMR RZFMS RPOY[Z[ RQOZ[" DATA " 14IZMFM[ RMFNFNZ RNZYZY[ RM[Y[" DATA " 26F^JFJ[ RKKK[J[ RKKR[ RJFRX RZFRX RYKR[ RYKY[Z[ RZFZ[" DATA " 20G]KFK[ RLIL[K[ RLIY[ RKFXX RXFXX RXFYFY[" DATA " 40G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF RQGNHLKKNKSLVNYQZSZVYXVYSYNXKVHSGQG" DATA " 27H\\LFL[ RMGM[L[ RLFUFWGXHYJYMXOWPUQMQ RMGUGWHXJXMWOUPMP" DATA " 48G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF RQGNHLKKNKSLVNYQZSZVYXVYSYNXKVHSGQG RSXX]Y] RSXTXY]" DATA " 34H\\LFL[ RMGM[L[ RLFTFWGXHYJYMXOWPTQMQ RMGTGWHXJXMWOTPMP RRQX[Y[ RSQY[" DATA " 43H\\YIWGTFPFMGKIKKLMMNOOTQVRWSXUXXWYTZPZNYMXKX RYIWIVHTGPGMHLILKMMONTPVQXSYUYXWZT[P[MZKX" DATA " 15J[RGR[ RSGS[R[ RLFYFYG RLFLGYG" DATA " 24G]KFKULXNZQ[S[VZXXYUYF RKFLFLUMXNYQZSZVYWXXUXFYF" DATA " 14H\\JFR[ RJFKFRX RZFYFRX RZFR[" DATA " 26E_GFM[ RGFHFMX RRFMX RRIM[ RRIW[ RRFWX R]F\\FWX R]FW[" DATA " 16H\\KFX[Y[ RKFLFY[ RYFXFK[ RYFL[K[" DATA " 17I\\KFRPR[S[ RKFLFSP RZFYFRP RZFSPS[" DATA " 20H\\XFK[ RYFL[ RKFYF RKFKGXG RLZYZY[ RK[Y[" DATA " 12KYOBOb RPBPb ROBVB RObVb" DATA " 3KYKFY^" DATA " 12KYTBTb RUBUb RNBUB RNbUb" DATA " 8G]JTROZT RJTRPZT" DATA " 3H\\Hb\\b" DATA " 7LXPFUL RPFOGUL" DATA " 36H\\WMW[X[ RWMXMX[ RWPUNSMPMNNLPKSKULXNZP[S[UZWX RWPSNPNNOMPLSLUMXNYPZSZWX" DATA " 36H\\LFL[M[ RLFMFM[ RMPONQMTMVNXPYSYUXXVZT[Q[OZMX RMPQNTNVOWPXSXUWXVYTZQZMX" DATA " 32I[XPVNTMQMONMPLSLUMXOZQ[T[VZXX RXPWQVOTNQNOONPMSMUNXOYQZTZVYWWXX" DATA " 36H\\WFW[X[ RWFXFX[ RWPUNSMPMNNLPKSKULXNZP[S[UZWX RWPSNPNNOMPLSLUMXNYPZSZWX" DATA " 36I[MTXTXQWOVNTMQMONMPLSLUMXOZQ[T[VZXX RMSWSWQVOTNQNOONPMSMUNXOYQZTZVYWWXX" DATA " 24LZWFUFSGRJR[S[ RWFWGUGSH RTGSJS[ ROMVMVN ROMONVN" DATA " 48H\\XMWMW\\V_U`SaQaO`N_L_ RXMX\\W_UaSbPbNaL_ RWPUNSMPMNNLPKSKULXNZP[S[UZWX RWPSNPNNOMPLSLUMXNYPZSZWX" DATA " 25H\\LFL[M[ RLFMFM[ RMQPNRMUMWNXQX[ RMQPORNTNVOWQW[X[" DATA " 24NWRFQGQHRISITHTGSFRF RRGRHSHSGRG RRMR[S[ RRMSMS[" DATA " 24NWRFQGQHRISITHTGSFRF RRGRHSHSGRG RRMRbSb RRMSMSb" DATA " 22H[LFL[M[ RLFMFM[ RXMWMMW RXMMX RPTV[X[ RQSX[" DATA " 8NWRFR[S[ RRFSFS[" DATA " 42CbGMG[H[ RGMHMH[ RHQKNMMPMRNSQS[ RHQKOMNONQORQR[S[ RSQVNXM[M]N^Q^[ RSQVOXNZN\\O]Q][^[" DATA " 25H\\LML[M[ RLMMMM[ RMQPNRMUMWNXQX[ RMQPORNTNVOWQW[X[" DATA " 36I\\QMONMPLSLUMXOZQ[T[VZXXYUYSXPVNTMQM RQNOONPMSMUNXOYQZTZVYWXXUXSWPVOTNQN" DATA " 36H\\LMLbMb RLMMMMb RMPONQMTMVNXPYSYUXXVZT[Q[OZMX RMPQNTNVOWPXSXUWXVYTZQZMX" DATA " 36H\\WMWbXb RWMXMXb RWPUNSMPMNNLPKSKULXNZP[S[UZWX RWPSNPNNOMPLSLUMXNYPZSZWX" DATA " 21KYOMO[P[ ROMPMP[ RPSQPSNUMXM RPSQQSOUNXNXM" DATA " 50J[XPWNTMQMNNMPNRPSUUWV RVUWWWXVZ RWYTZQZNY ROZNXMX RXPWPVN RWOTNQNNO RONNPOR RNQPRUTWUXWXXWZT[Q[NZMX" DATA " 16MXRFR[S[ RRFSFS[ ROMVMVN ROMONVN" DATA " 25H\\LMLWMZO[R[TZWW RLMMMMWNYPZRZTYWW RWMW[X[ RWMXMX[" DATA " 14JZLMR[ RLMMMRY RXMWMRY RXMR[" DATA " 26F^IMN[ RIMJMNX RRMNX RRPN[ RRPV[ RRMVX R[MZMVX R[MV[" DATA " 16I[LMW[X[ RLMMMX[ RXMWML[ RXMM[L[" DATA " 17JZLMR[ RLMMMRY RXMWMRYNb RXMR[ObNb" DATA " 20I[VNL[ RXMNZ RLMXM RLMLNVN RNZXZX[ RL[X[" DATA " 4KYUBNRUb" DATA " 3NVRBRb" DATA " 4KYOBVROb" DATA " 24F^IUISJPLONOPPTSVTXTZS[Q RISJQLPNPPQTTVUXUZT[Q[O" DATA " 35JZJFJ[K[KFLFL[M[MFNFN[O[OFPFP[Q[QFRFR[S[SFTFT[U[UFVFV[W[WFXFX[Y[YFZFZ[" ' Needed to parse font data DEF FN CANVAS_Coord(x$) = ASC(x$)-ASC("R") CALL Read_Font_Data() ' Primitives available in small letters as well ALIAS "WINDOW" TO "window" ALIAS "FULLSCREEN" TO "fullscreen" ALIAS "PIXEL" TO "pixel" ALIAS "LINE" TO "line" ALIAS "CIRCLE" TO "circle" ALIAS "ARC" TO "arc" ALIAS "SQUARE" TO "square" ALIAS "TRIANGLE" TO "triangle" ALIAS "POLYGON" TO "polygon" ALIAS "PAINT" TO "paint" ALIAS "TEXT" TO "text" ALIAS "GRID" TO "grid" ALIAS "QBEZIER" TO "qbezier" ALIAS "CBEZIER" TO "cbezier" ALIAS "INK" TO "ink" ALIAS "PEN" TO "pen" ALIAS "ROTATION" TO "rotation" ALIAS "SCALE" TO "scale" ALIAS "MOVE" TO "move" ALIAS "GETINK" TO "getink" ALIAS "FLIP" TO "flip" ALIAS "SYNC" TO "sync" ALIAS "QUIT" TO "quit" ALIAS "CLS" TO "cls" ALIAS "CALLBACK" TO "callback" ALIAS "WAITKEY" TO "waitkey" ALIAS "PENDOWN" TO "pendown" ALIAS "PENUP" TO "penup" ALIAS "PENXY" TO "penxy" ALIAS "PENTYPE" TO "pentype" ALIAS "TURNRIGHT" TO "turnright" ALIAS "TURNLEFT" TO "turnleft" ALIAS "TURN" TO "turn" ALIAS "RESETANGLE" TO "resetangle" ALIAS "DRAW" TO "draw" ALIAS "LOADFONT" TO "loadfont" ALIAS "MOUSE" TO "mouse" 'ALIAS "WIDTH" TO "width" 'ALIAS "HEIGHT" TO "height" ALIAS "REFRESH" TO "refresh" ALIAS "BACKEND" TO "backend" ALIAS "OUTLINE" TO "outline" ' Default is 60 Hz REFRESH = 60 '------------------------------------------------------------------ SUB Read_Font_Data LOCAL x ' Get the fonts for OpenGL FOR x = 0 TO 95 READ CANVAS.font$[x] NEXT END SUB FUNCTION Import_X11_functions LOCAL lib$ LOCAL seq = -1 CATCH GOTO lib_import_retry lib$ = "libX11.so.0" LABEL lib_import_retry INCR seq IF seq > 100 THEN RETURN FALSE lib$ = LEFT$(lib$, INSTRREV(lib$, ".")) & STR$(seq) IMPORT "XOpenDisplay(char*)" FROM lib$ TYPE void* CATCH RESET IMPORT "XCloseDisplay(void*)" FROM lib$ TYPE int IMPORT "XDefaultRootWindow(void*)" FROM lib$ TYPE long IMPORT "XDefaultScreen(void*)" FROM lib$ TYPE int IMPORT "XDisplayWidth(void*,int)" FROM lib$ TYPE int IMPORT "XDisplayHeight(void*,int)" FROM lib$ TYPE int IMPORT "XFree(void*)" FROM lib$ TYPE int RETURN TRUE END FUNCTION FUNCTION Import_Xrandr_functions LOCAL lib$ LOCAL seq = -1 CATCH GOTO lib_import_retry lib$ = "libXrandr.so.0" LABEL lib_import_retry INCR seq IF seq > 100 THEN RETURN FALSE lib$ = LEFT$(lib$, INSTRREV(lib$, ".")) & STR$(seq) IMPORT "XRRGetScreenInfo(void*,long)" FROM lib$ TYPE void* CATCH RESET IMPORT "XRRConfigCurrentRate(void*)" FROM lib$ TYPE short RETURN TRUE END FUNCTION FUNCTION Import_GLUT_functions LOCAL lib$ LOCAL seq = -1 CATCH GOTO lib_import_retry lib$ = "libglut.so.0" LABEL lib_import_retry INCR seq IF seq > 100 THEN RETURN FALSE lib$ = LEFT$(lib$, INSTRREV(lib$, ".")) & STR$(seq) IMPORT "glutInit(int*,char**)" FROM lib$ TYPE void CATCH RESET IMPORT "glutInitDisplayMode(int)" FROM lib$ TYPE void IMPORT "glutInitWindowSize(int,int)" FROM lib$ TYPE void IMPORT "glutCreateWindow(char*)" FROM lib$ TYPE void* IMPORT "glutMainLoop(void)" FROM lib$ TYPE void IMPORT "glutMotionFunc(void*)" FROM lib$ TYPE void IMPORT "glutMouseFunc(void*)" FROM lib$ TYPE void IMPORT "glutReshapeFunc(void*)" FROM lib$ TYPE void IMPORT "glutPassiveMotionFunc(void*)" FROM lib$ TYPE void IMPORT "glutSwapBuffers(void)" FROM lib$ TYPE void IMPORT "glutKeyboardFunc(void*)" FROM lib$ TYPE void IMPORT "glutTimerFunc(int,void*,int)" FROM lib$ TYPE void IMPORT "glutDisplayFunc(void*)" FROM lib$ TYPE void CATCH GOTO GLUT_No_Fullscreen IMPORT "glutGameModeString(char*)" FROM lib$ TYPE void IMPORT "glutEnterGameMode(void)" FROM lib$ TYPE void CATCH RESET CANVAS.library$ = "GLUT" ' GLUT definitions CONST GLUT_RGBA = 0x0000 CONST GLUT_DOUBLE = 0x0002 CONST GLUT_ALPHA = 0x0008 CONST GLUT_MULTISAMPLE = 0x0080 CONST GLUT_DEPTH = 0x0010 CONST GLUT_LEFT_BUTTON = 0x0000 CONST GLUT_MIDDLE_BUTTON = 0x0001 CONST GLUT_RIGHT_BUTTON = 0x0002 CONST GLUT_DOWN = 0x0000 CONST GLUT_UP = 0x0001 RETURN TRUE LABEL GLUT_No_Mousewheel PRINT "Warning: your GLUT library does not support mouse wheel events." PROTO glutMouseWheelFunc RESUME LABEL GLUT_No_Fullscreen PRINT "Warning: your GLUT library does not support fullscreen." PROTO glutGameModeString PROTO glutEnterGameMode RESUME END FUNCTION FUNCTION Import_ALLEGRO_functions LOCAL lib$ LOCAL seq = -1 CATCH GOTO lib_import_retry lib$ = "liballegro.so.5.0" LABEL lib_import_retry INCR seq IF seq > 100 THEN RETURN FALSE lib$ = LEFT$(lib$, INSTRREV(lib$, ".")) & STR$(seq) IMPORT "al_install_system(int,void*)" FROM lib$ TYPE void CATCH RESET IMPORT "al_create_display(int,int)" FROM lib$ TYPE void* IMPORT "al_create_event_queue(void)" FROM lib$ TYPE void* IMPORT "al_create_timer(double)" FROM lib$ TYPE void* IMPORT "al_flip_display(void)" FROM lib$ TYPE void IMPORT "al_get_display_event_source(void*)" FROM lib$ TYPE void* IMPORT "al_get_keyboard_event_source(void)" FROM lib$ TYPE void* IMPORT "al_get_mouse_event_source(void)" FROM lib$ TYPE void* IMPORT "al_get_mouse_state(void*)" FROM lib$ TYPE void IMPORT "al_get_mouse_state_axis(void*,int)" FROM lib$ TYPE int IMPORT "al_get_timer_event_source(void*)" FROM lib$ TYPE void* IMPORT "al_install_keyboard(void)" FROM lib$ TYPE int IMPORT "al_install_mouse(void)" FROM lib$ TYPE int IMPORT "al_mouse_button_down(void*,int)" FROM lib$ TYPE int IMPORT "al_register_event_source(void*,void*)" FROM lib$ TYPE void IMPORT "al_set_new_display_flags(int)" FROM lib$ TYPE void IMPORT "al_set_new_display_option(int,int,int)" FROM lib$ TYPE void IMPORT "al_set_window_title(void*,char*)" FROM lib$ TYPE void IMPORT "al_set_target_bitmap(void*)" FROM lib$ TYPE void IMPORT "al_start_timer(void*)" FROM lib$ TYPE void IMPORT "al_wait_for_event(void*,long)" FROM lib$ TYPE void IMPORT "al_get_allegro_version(void)" FROM lib$ TYPE unsigned int CANVAS.library$ = "ALLEGRO" ' ALLEGRO definitions CONST ALLEGRO_WINDOWED = 1<<0 CONST ALLEGRO_FULLSCREEN = 1<<1 CONST ALLEGRO_OPENGL = 1<<2 CONST ALLEGRO_EVENT_MOUSE_AXES = 20 CONST ALLEGRO_EVENT_MOUSE_BUTTON_DOWN = 21 CONST ALLEGRO_EVENT_MOUSE_BUTTON_UP = 22 CONST ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY = 23 CONST ALLEGRO_EVENT_TIMER = 30 CONST ALLEGRO_EVENT_KEY_DOWN = 10 CONST ALLEGRO_EVENT_DISPLAY_CLOSE = 42 CONST ALLEGRO_SUGGEST = 2 CONST ALLEGRO_SAMPLE_BUFFERS = 17 CONST ALLEGRO_SAMPLES = 18 RETURN TRUE END FUNCTION FUNCTION Import_SDL_functions LOCAL lib$ LOCAL seq = -1 CATCH GOTO lib_import_retry lib$ = "libSDL-1.2.so.0" LABEL lib_import_retry INCR seq IF seq > 100 THEN RETURN FALSE lib$ = LEFT$(lib$, INSTRREV(lib$, ".")) & STR$(seq) IMPORT "SDL_Init(int)" FROM lib$ TYPE int CATCH RESET IMPORT "SDL_AddTimer(int,void*,void*)" FROM lib$ TYPE long IMPORT "SDL_GetError(void)" FROM lib$ TYPE char* ALIAS SDL_GetError$ IMPORT "SDL_GetMouseState(int*,int*)" FROM lib$ TYPE int IMPORT "SDL_GL_SetAttribute(int,int)" FROM lib$ TYPE int IMPORT "SDL_GL_SwapBuffers(void)" FROM lib$ TYPE void IMPORT "SDL_PushEvent(long)" FROM lib$ TYPE int IMPORT "SDL_Quit(void)" FROM lib$ TYPE void IMPORT "SDL_SetVideoMode(int,int,int,int)" FROM lib$ TYPE void* IMPORT "SDL_WaitEvent(long)" FROM lib$ TYPE int IMPORT "SDL_WM_SetCaption(char*,char*)" FROM lib$ TYPE void CANVAS.library$ = "SDL" ' SDL definitions CONST SDL_INIT_TIMER = 0x00000001 CONST SDL_INIT_VIDEO = 0x00000020 CONST SDL_OPENGL = 0x00000002 CONST SDL_FULLSCREEN = 0x80000000 CONST SDL_GL_RED_SIZE = 0 CONST SDL_GL_GREEN_SIZE = 1 CONST SDL_GL_BLUE_SIZE = 2 CONST SDL_GL_DOUBLEBUFFER = 5 CONST SDL_GL_DEPTH_SIZE = 6 CONST SDL_QUIT = 12 CONST SDL_KEYDOWN = 2 CONST SDL_MOUSEMOTION = 4 CONST SDL_MOUSEBUTTONDOWN = 5 CONST SDL_MOUSEBUTTONUP = 6 CONST SDL_GL_MULTISAMPLEBUFFERS = 13 CONST SDL_GL_MULTISAMPLESAMPLES = 14 RETURN TRUE ENDFUNCTION FUNCTION Import_GLFW_functions LOCAL lib$ LOCAL seq = -1 CATCH GOTO lib_import_retry lib$ = "libglfw.so.3.0" LABEL lib_import_retry INCR seq IF seq > 100 THEN RETURN FALSE lib$ = LEFT$(lib$, INSTRREV(lib$, ".")) & STR$(seq) IMPORT "glfwInit(void)" FROM lib$ TYPE int CATCH RESET IMPORT "glfwTerminate(void)" FROM lib$ TYPE void IMPORT "glfwCreateWindow(int,int,const char*,void*,void*)" FROM lib$ TYPE void* IMPORT "glfwSwapBuffers(void*)" FROM lib$ TYPE void IMPORT "glfwPollEvents(void)" FROM lib$ TYPE void IMPORT "glfwSetKeyCallback(void*,void*)" FROM lib$ TYPE void* IMPORT "glfwMakeContextCurrent(void*)" FROM lib$ TYPE void IMPORT "glfwSetWindowCloseCallback(void*,void*)" FROM lib$ TYPE void IMPORT "glfwSetCursorPosCallback(void*,void*)" FROM lib$ TYPE void IMPORT "glfwSetMouseButtonCallback(void*,void*)" FROM lib$ TYPE void IMPORT "glfwSetScrollCallback(void*,void*)" FROM lib$ TYPE void IMPORT "glfwDefaultWindowHints(void)" FROM lib$ TYPE void IMPORT "glfwGetPrimaryMonitor(void)" FROM lib$ TYPE void* IMPORT "glfwWindowHint(int,int)" FROM lib$ TYPE void CANVAS.library$ = "GLFW" CONST GLFW_MOUSE_BUTTON_LEFT = 0 CONST GLFW_MOUSE_BUTTON_MIDDLE = 2 CONST GLFW_MOUSE_BUTTON_RIGHT = 1 CONST GLFW_PRESS = 1 CONST GLFW_RELEASE = 0 CONST GLFW_RED_BITS = 0x00021001 CONST GLFW_GREEN_BITS = 0x00021002 CONST GLFW_BLUE_BITS = 0x00021003 CONST GLFW_DEPTH_BITS = 0x00021005 CONST GLFW_SAMPLES = 0x0002100D RETURN TRUE ENDFUNCTION FUNCTION Import_GL_functions LOCAL lib$ LOCAL seq = -1 CATCH GOTO lib_import_retry lib$ = "libGL.so.0" LABEL lib_import_retry INCR seq IF seq > 100 THEN RETURN FALSE lib$ = LEFT$(lib$, INSTRREV(lib$, ".")) & STR$(seq) IMPORT "glClear(int)" FROM lib$ TYPE void CATCH RESET IMPORT "glBegin(int)" FROM lib$ TYPE void IMPORT "glBitmap(int,int,float,float,float,float,long)" FROM lib$ TYPE void IMPORT "glBlendFunc(int,int)" FROM lib$ TYPE void IMPORT "glClearColor(float,float,float,float)" FROM lib$ TYPE void IMPORT "glColor4ub(char,char,char,char)" FROM lib$ TYPE void IMPORT "glDisable(int)" FROM lib$ TYPE void IMPORT "glDrawPixels(int,int,int,int,void*)" FROM lib$ TYPE void IMPORT "glEnable(int)" FROM lib$ TYPE void IMPORT "glIsEnabled(int)" FROM lib$ TYPE int IMPORT "glEnd(void)" FROM lib$ TYPE void IMPORT "glGetFloatv(int,float*)" FROM lib$ TYPE void IMPORT "glGetString(int)" FROM lib$ TYPE char* ALIAS glGetString$ IMPORT "glHint(int,int)" FROM lib$ TYPE void IMPORT "glLineWidth(float)" FROM lib$ TYPE void IMPORT "glLoadIdentity(void)" FROM lib$ TYPE void IMPORT "glMatrixMode(int)" FROM lib$ TYPE void IMPORT "glOrtho(double,double,double,double,double,double)" FROM lib$ TYPE void IMPORT "glPixelStorei(int,int)" FROM lib$ TYPE void IMPORT "glPixelZoom(float,float)" FROM lib$ TYPE void IMPORT "glPointSize(float)" FROM lib$ TYPE void IMPORT "glRasterPos2f(float,float)" FROM lib$ TYPE void IMPORT "glReadPixels(int,int,int,int,int,int,void*)" FROM lib$ TYPE void IMPORT "glRotatef(float,float,float,float)" FROM lib$ TYPE void IMPORT "glScalef(float,float,float)" FROM lib$ TYPE void IMPORT "glScissor(int,int,int,int)" FROM lib$ TYPE void IMPORT "glTranslatef(float,float,float)" FROM lib$ TYPE void IMPORT "glVertex2d(double,double)" FROM lib$ TYPE void IMPORT "glVertex2f(float,float)" FROM lib$ TYPE void IMPORT "glGenTextures(int,int*)" FROM lib$ TYPE void IMPORT "glDeleteTextures(int,int*)" FROM lib$ TYPE void IMPORT "glBindTexture(int,int)" FROM lib$ TYPE void IMPORT "glTexParameteri(int,int,int)" FROM lib$ TYPE void IMPORT "glTexImage2D(int,int,int,int,int,int,int,int,void*)" FROM lib$ TYPE void IMPORT "glTexCoord2f(float,float)" FROM lib$ TYPE void ' GL definitions CONST GL_POINTS = 0x0000 CONST GL_LINES = 0x0001 CONST GL_LINE_LOOP = 0x0002 CONST GL_LINE_STRIP = 0x0003 CONST GL_POLYGON = 0x0009 CONST GL_UNSIGNED_BYTE = 0x1401 CONST GL_MODELVIEW = 0x1700 CONST GL_PROJECTION = 0x1701 CONST GL_RGB = 0x1907 CONST GL_RGBA = 0x1908 CONST GL_BGRA = 0x80E1 CONST GL_COLOR_BUFFER_BIT = 0x00004000 CONST GL_DEPTH_BUFFER_BIT = 0x00000100 CONST GL_POINT_SMOOTH = 0x0B10 CONST GL_POINT_SIZE = 0x0B11 CONST GL_LINE_SMOOTH = 0x0B20 CONST GL_POLYGON_SMOOTH = 0x0B41 CONST GL_CURRENT_COLOR = 0x0B00 CONST GL_TRIANGLES = 0x0004 CONST GL_BLEND = 0x0BE2 CONST GL_SRC_ALPHA = 0x0302 CONST GL_ONE_MINUS_SRC_ALPHA = 0x0303 CONST GL_MULTISAMPLE = 0x809D CONST GL_NICEST = 0x1102 CONST GL_POINT_SMOOTH_HINT = 0x0C51 CONST GL_LINE_SMOOTH_HINT = 0x0C52 CONST GL_POLYGON_SMOOTH_HINT = 0x0C53 CONST GL_UNPACK_ROW_LENGTH = 0x0CF2 CONST GL_VENDOR = 0x1F00 CONST GL_RENDERER = 0x1F01 CONST GL_VERSION = 0x1F02 CONST GL_EXTENSIONS = 0x1F03 CONST GL_QUADS = 0x0007 CONST GL_TEXTURE_2D = 0x0DE1 CONST GL_TEXTURE_MAG_FILTER = 0x2800 CONST GL_TEXTURE_MIN_FILTER = 0x2801 CONST GL_LINEAR = 0x2601 CONST GL_STENCIL_TEST = 0x0B90 CONST GL_STENCIL_BUFFER_BIT = 0x00000400 CONST GL_STENCIL_INDEX = 0x1901 CONST GL_EQUAL = 0x0202 CONST GL_ALWAYS = 0x0207 CONST GL_NEVER = 0x0200 CONST GL_DEPTH_COMPONENT = 0x1902 CONST GL_KEEP = 0x1E00 CONST GL_REPLACE = 0x1E01 CONST GL_SCISSOR_TEST = 0x0C11 RETURN TRUE ENDFUNCTION '------------------------------------------------------------------ SUB DETECT_BACKEND ' Import functions from system and choose the one available IF NOT(Import_GLUT_functions()) THEN IF NOT(Import_ALLEGRO_functions()) THEN IF NOT(Import_SDL_functions()) THEN IF NOT(Import_GLFW_functions()) THEN PRINT "No GLUT or Allegro or SDL or GLFW library found! Canvas cannot be created." END 1 ENDIF ENDIF ENDIF ENDIF 'PRINT "Now using: ", CANVAS.library$ CANVAS.back_end = TRUE ENDSUB SUB BACKEND(type$) SELECT type$ CASE "GLUT" IF NOT(Import_GLUT_functions()) THEN PRINT "No GLUT library found! Canvas cannot be created." END 1 ENDIF CASE "SDL" IF NOT(Import_SDL_functions()) THEN PRINT "No SDL library found! Canvas cannot be created." END 1 ENDIF CASE "ALLEGRO" IF NOT(Import_ALLEGRO_functions()) THEN PRINT "No ALLEGRO library found! Canvas cannot be created." END 1 ENDIF CASE "GLFW" IF NOT(Import_GLFW_functions()) THEN PRINT "No GLFW library found! Canvas cannot be created." END 1 ENDIF DEFAULT PRINT "Incorrect backend specified! Please choose from GLUT, SDL, ALLEGRO or GLFW." END 1 ENDSELECT CANVAS.back_end = TRUE ENDSUB SUB INIT_CANVAS(int argc, char* argv[]) LOCAL dpy TYPE void* IF NOT(Import_X11_functions()) THEN PRINT "No X11 library found on this system! Canvas cannot be created." END 1 ENDIF ' Initialize IF CANVAS.library$ = "GLUT" THEN glutInit(&argc, argv) ELIF CANVAS.library$ = "ALLEGRO" THEN al_install_system(al_get_allegro_version(), atexit) al_install_keyboard() al_install_mouse() ELIF CANVAS.library$ = "SDL" THEN IF SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0 THEN PRINT SDL_GetError$() END 1 ENDIF ELIF CANVAS.library$ = "GLFW" THEN IF glfwInit() = 0 THEN PRINT "Error initiliazing GLFW." END 1 ENDIF ELSE PRINT "No suitable backend found." END 1 ENDIF dpy = XOpenDisplay(NULL) CANVAS.xsize = XDisplayWidth(dpy, XDefaultScreen(dpy)) CANVAS.ysize = XDisplayHeight(dpy, XDefaultScreen(dpy)) IF Import_Xrandr_functions() THEN REFRESH = XRRConfigCurrentRate(XRRGetScreenInfo(dpy, XDefaultRootWindow(dpy))) XCloseDisplay(dpy) ENDSUB SUB WINDOW(title$, xsize, ysize) IF NOT(CANVAS.back_end) THEN CALL DETECT_BACKEND() CALL INIT_CANVAS(0, NULL) IF CANVAS.library$ = "GLUT" THEN glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_MULTISAMPLE) glutInitWindowSize(xsize, ysize) CANVAS.win = glutCreateWindow(title$) ELIF CANVAS.library$ = "ALLEGRO" THEN al_set_new_display_flags(ALLEGRO_WINDOWED|ALLEGRO_OPENGL) al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, TRUE, ALLEGRO_SUGGEST) al_set_new_display_option(ALLEGRO_SAMPLES, 4, ALLEGRO_SUGGEST) CANVAS.win = al_create_display(xsize, ysize) al_set_window_title(CANVAS.win, title$) ELIF CANVAS.library$ = "SDL" THEN SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5) SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5) SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5) SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16) SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, TRUE) SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4) CANVAS.win = SDL_SetVideoMode(xsize, ysize, 16, SDL_OPENGL) IF CANVAS.win = 0 THEN PRINT SDL_GetError$() END 1 ENDIF SDL_WM_SetCaption(title$, NULL) ELSE glfwDefaultWindowHints() glfwWindowHint(GLFW_RED_BITS, 5) glfwWindowHint(GLFW_GREEN_BITS, 5) glfwWindowHint(GLFW_BLUE_BITS, 5) glfwWindowHint(GLFW_DEPTH_BITS, 16) glfwWindowHint(GLFW_SAMPLES, 4) CANVAS.win = glfwCreateWindow(xsize, ysize, title$, NULL, NULL) glfwMakeContextCurrent(CANVAS.win) ENDIF CANVAS.xsize = xsize CANVAS.ysize = ysize CALL Finalize_Window END SUB SUB FULLSCREEN IF NOT(CANVAS.back_end) THEN CALL DETECT_BACKEND() CALL INIT_CANVAS(0, NULL) IF CANVAS.library$ = "GLUT" THEN glutGameModeString(STR$(CANVAS.xsize) & "x" & STR$(CANVAS.ysize) & ":16@60") glutEnterGameMode() ELIF CANVAS.library$ = "ALLEGRO" THEN al_set_new_display_flags(ALLEGRO_FULLSCREEN|ALLEGRO_OPENGL) CANVAS.win = al_create_display(CANVAS.xsize, CANVAS.ysize) ELIF CANVAS.library$ = "SDL" THEN CANVAS.win = SDL_SetVideoMode(CANVAS.xsize, CANVAS.ysize, 16, SDL_OPENGL|SDL_FULLSCREEN) IF CANVAS.win = 0 THEN PRINT SDL_GetError$() END 1 ENDIF ELSE glfwDefaultWindowHints() CANVAS.win = glfwCreateWindow(CANVAS.xsize, CANVAS.ysize, "", glfwGetPrimaryMonitor(), NULL) glfwMakeContextCurrent(CANVAS.win) FI CALL Finalize_Window ENDSUB SUB Finalize_Window IF NOT(Import_GL_functions()) THEN PRINT "No OpenGL library found on this system! Canvas cannot be created." END 1 ENDIF ' Clear canvas glClearColor(1.0f, 1.0f, 1.0f, 0.0f) CALL CLS ' Enable alpha channel glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ' For anti aliasing (vovchik) glEnable(GL_MULTISAMPLE) ' Pixel rendering (vovchik) glHint(GL_POINT_SMOOTH_HINT, GL_NICEST) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST) ' Set default drawing color to black CALL INK(0,0,0,255) ' Pen on by default CANVAS.pen_active = 1 ' Default scaling CANVAS.scaling = 1.0 ' Set font width CANVAS.font_width = 16 ' Determines if the font should be centered (0) or left-aligned (1) when scaling is applied CANVAS.font_align = 0 ' No flipping CANVAS.flipping = 3 CONST WIDTH = CANVAS.xsize CONST HEIGHT = CANVAS.ysize END SUB SUB CLS glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT) END SUB SUB INK(unsigned char r, unsigned char g, unsigned char b, unsigned char alpha) glClearColor(r/255.0, g/255.0, b/255.0, alpha/255.0) glColor4ub(r, g, b, alpha) ENDSUB SUB PEN(size#, flag) CANVAS.pen_size = size# CANVAS.pen_smooth = flag IF flag THEN glEnable(GL_POINT_SMOOTH) glEnable(GL_LINE_SMOOTH) glEnable(GL_POLYGON_SMOOTH) ELSE glDisable(GL_POINT_SMOOTH) glDisable(GL_LINE_SMOOTH) glDisable(GL_POLYGON_SMOOTH) ENDIF glPointSize(size#) glLineWidth(size#) ENDSUB SUB PENDOWN CANVAS.pen_active = 1 END SUB SUB PENUP CANVAS.pen_active = 0 END SUB SUB PENXY(float xpos, float ypos) CANVAS.pen_xpos = xpos CANVAS.pen_ypos = ypos ENDSUB SUB PENTYPE(type) IF type < 0 OR type > 1 THEN type = 0 CANVAS.pen_type = type ENDSUB SUB TURNRIGHT(float angle) DECR CANVAS.pen_direction, angle WHILE CANVAS.pen_direction < 0 INCR CANVAS.pen_direction, 360 WEND ENDSUB SUB TURNLEFT(float angle) INCR CANVAS.pen_direction, angle WHILE CANVAS.pen_direction > 360 DECR CANVAS.pen_direction, 360 WEND ENDSUB SUB TURN(float angle) TURNRIGHT(angle) ENDSUB SUB RESETANGLE CANVAS.pen_direction = 90 ENDSUB SUB DRAW(float length) LOCAL x, y TYPE float LOCAL rotate IF CANVAS.pen_type = 0 THEN x = CANVAS.pen_xpos + COS(RAD(CANVAS.pen_direction))*length y = CANVAS.pen_ypos - SIN(RAD(CANVAS.pen_direction))*length IF CANVAS.pen_active THEN CALL LINE(CANVAS.pen_xpos, CANVAS.pen_ypos, x, y) CANVAS.pen_xpos = x CANVAS.pen_ypos = y ELIF CANVAS.pen_type = 1 THEN x = CANVAS.pen_xpos + COS(RAD(CANVAS.pen_direction))*(length/2) y = CANVAS.pen_ypos - SIN(RAD(CANVAS.pen_direction))*(length/2) rotate = CANVAS.rotate CANVAS.rotate = -CANVAS.pen_direction IF CANVAS.pen_active THEN CALL ARC(x, y, length/2, length/2, 0, 360, 0) CANVAS.rotate = rotate CANVAS.pen_xpos = CANVAS.pen_xpos + COS(RAD(CANVAS.pen_direction))*length CANVAS.pen_ypos = CANVAS.pen_ypos - SIN(RAD(CANVAS.pen_direction))*length ENDIF ENDSUB SUB Check_Move() LOCAL x, y x = INT(COS(RAD(CANVAS.angle))*CANVAS.step) y = INT(SIN(RAD(CANVAS.angle))*CANVAS.step) glTranslatef(x, y, 0) END SUB SUB MOVE(angle, step) CANVAS.angle = angle CANVAS.step = step ENDSUB SUB Check_Rotation(x, y, xs, ys) IF CANVAS.rotate <> 0 THEN glTranslatef(x+xs, y+ys, 0) glRotatef(CANVAS.rotate, 0, 0, 1) glTranslatef(-x-xs, -y-ys, 0) ENDIF END SUB SUB ROTATION(angle) CANVAS.rotate = angle ENDSUB SUB Check_Scale(x, y, xs, ys) glTranslatef(x+xs, y+ys, 0) glScalef(CANVAS.scaling, CANVAS.scaling, 1) glPixelZoom(CANVAS.scaling, CANVAS.scaling) glTranslatef(-x-xs, -y-ys, 0) END SUB SUB SCALE(factor#) CANVAS.scaling = factor# ENDSUB SUB Draw_Prepare glMatrixMode(GL_PROJECTION) glLoadIdentity SELECT CANVAS.flipping CASE 0 glScalef(-1.0, 1.0, 1.0) glPixelZoom(-1.0, 1.0) glRasterPos2f(-1.0, -1.0) CASE 1 glScalef(1.0, -1.0, 1.0) glPixelZoom(1.0, -1.0) glRasterPos2f(-1.0, -1.0) CASE 2 glScalef(-1.0, -1.0, 1.0) glPixelZoom(-1.0, -1.0) glRasterPos2f(-1.0, -1.0) ENDSELECT glOrtho(0, CANVAS.xsize, CANVAS.ysize, 0, 0, 1) glMatrixMode(GL_MODELVIEW) glLoadIdentity 'glTranslatef(0.375, 0.375, 0) END SUB SUB PIXEL(float x, float y) CALL Draw_Prepare glBegin(GL_POINTS) glVertex2f(x, y) glEnd END SUB SUB LINE(float xstart, float ystart, float xend, float yend) CALL Draw_Prepare CALL Check_Scale(xstart, ystart, ABS(xend-xstart)/2.0, ABS(yend-ystart)/2.0) CALL Check_Rotation(xstart, ystart, ABS(xend-xstart)/2.0, ABS(yend-ystart)/2.0) CALL Check_Move() glBegin(GL_LINES) glVertex2f(xstart, ystart) glVertex2f(xend, yend) glEnd ENDSUB SUB SQUARE(float x, float y, float xrad, float yrad, fill) CALL Draw_Prepare CALL Check_Scale(x-xrad, y-yrad, xrad, yrad) CALL Check_Rotation(x-xrad, y-yrad, xrad, yrad) CALL Check_Move() IF fill THEN glBegin(GL_POLYGON) ELSE glBegin(GL_LINE_LOOP) ENDIF glVertex2f(x-xrad, y-yrad) glVertex2f(x+xrad, y-yrad) glVertex2f(x+xrad, y+yrad) glVertex2f(x-xrad, y+yrad) glEnd ENDSUB SUB OUTLINE(VAR arg# SIZE total) LOCAL i IF total < 5 THEN PRINT "Error: outline needs at least 2 coordinate pairs." END 1 ENDIF CALL Draw_Prepare 'CALL Check_Scale(x-xrad, y-yrad, xrad, yrad) 'CALL Check_Rotation(x-xrad, y-yrad, xrad, yrad) CALL Check_Move() IF arg#[total-1] <> 0 THEN glBegin(GL_POLYGON) ELSE glBegin(GL_LINE_LOOP) ENDIF FOR i = 0 TO total-2 STEP 2 glVertex2d(arg#[i], arg#[i+1]) NEXT glEnd ENDSUB SUB CIRCLE(float x, float y, float xsize, float ysize, fill) LOCAL i, xt, yt TYPE float CALL Draw_Prepare CALL Check_Scale(x-xsize, y-ysize, xsize, ysize) CALL Check_Rotation(x-xsize, y-ysize, xsize, ysize) CALL Check_Move() IF fill THEN glBegin(GL_POLYGON) ELSE glBegin(GL_LINE_LOOP) END IF FOR i = 0 TO 360 xt = xsize*COS(RAD(i)) yt = ysize*SIN(RAD(i)) glVertex2f(x+xt, y+yt) NEXT glEnd ENDSUB SUB ARC(float x, float y, xrad, yrad, start, end, fill) LOCAL i LOCAL xt, yt TYPE float CALL Draw_Prepare CALL Check_Scale(x-xrad, y-yrad, xrad, yrad) CALL Check_Rotation(x-xrad, y-yrad, xrad, yrad) CALL Check_Move() IF fill THEN glBegin(GL_POLYGON) ELSE glBegin(GL_LINE_STRIP) END IF FOR i = start TO end xt = xrad*COS(RAD(i)) yt = yrad*SIN(RAD(i)) glVertex2f(x+xt, y+yt) NEXT glEnd ENDSUB SUB TRIANGLE(float x, float y, float base, float height, fill) CALL Draw_Prepare CALL Check_Scale(x-base, y-height, base, height) CALL Check_Rotation(x-base, y-height, base, height) CALL Check_Move() IF fill THEN glBegin(GL_TRIANGLES) ELSE glBegin(GL_LINE_LOOP) ENDIF glVertex2f(x-base/2, y+height/2) glVertex2f(x+base/2, y+height/2) glVertex2f(x, y-height/2) glEnd ENDSUB SUB POLYGON(float xorg, float yorg, radius, sides, fill) LOCAL i, rot, angle, xpos, ypos, length, x, y TYPE float CALL Draw_Prepare CALL Check_Scale(xorg-2*radius, yorg-2*radius, radius*2, radius*2) CALL Check_Rotation(xorg-2*radius, yorg-2*radius, radius*2, radius*2) CALL Check_Move() angle = 360.0 / sides length = SQR((POW(radius, 2) + POW(radius, 2)) - ((2 * radius * radius) * COS(RAD(angle)))) rot = -angle/2 xpos = xorg ypos = yorg - radius FOR i = 1 TO sides-1 x = xpos + COS(RAD(rot))*length y = ypos - SIN(RAD(rot))*length glBegin(GL_LINES) glVertex2f(xpos, ypos) glVertex2f(x, y) glEnd DECR rot, angle xpos = x ypos = y NEXT glBegin(GL_LINES) glVertex2f(x, y) glVertex2f(xorg, yorg-radius) glEnd IF fill THEN CALL PAINT(xorg, yorg) ENDSUB SUB GRID(float startx, float starty, float w, float h, hboxes, vboxes) LOCAL i, size_xbox, size_ybox TYPE float CALL Draw_Prepare CALL Check_Scale(startx-w/2, starty-h/2, w, h) CALL Check_Rotation(startx-w/2, starty-h/2, w, h) CALL Check_Move() size_xbox = w/hboxes size_ybox = h/vboxes FOR i = 0 TO hboxes glBegin(GL_LINES) glVertex2f(startx+i*size_xbox, starty) glVertex2f(startx+i*size_xbox, starty+h) glEnd NEXT FOR i = 0 TO vboxes glBegin(GL_LINES) glVertex2f(startx, starty+i*size_ybox) glVertex2f(startx+w, starty+i*size_ybox) glEnd NEXT ENDSUB SUB QBEZIER(float x_0, float y_0, float x_1, float y_1, float x_2, float y_2) LOCAL Ax, Ay, Bx, By, t TYPE float CALL Draw_Prepare CALL Check_Scale(x_0, y_0, ABS(x_2-x_0)/2.0, ABS(y_2-y_0)/2.0) CALL Check_Rotation(x_0, y_0, ABS(x_2-x_0)/2.0, ABS(y_2-y_0)/2.0) CALL Check_Move() Ax = x_0 : Ay = y_0 glBegin(GL_LINES) FOR t = 0 TO 1 STEP 0.01 Bx = POW((1-t), 2)*x_0 + 2*(1-t)*t*x_1 + POW(t,2)*x_2 By = POW((1-t), 2)*y_0 + 2*(1-t)*t*y_1 + POW(t,2)*y_2 glVertex2f(Ax, Ay) glVertex2f(Bx, By) Ax = Bx : Ay = By NEXT glEnd ENDSUB SUB CBEZIER(float x_0, float y_0, float x_1, float y_1, float x_2, float y_2, float x_3, float y_3) LOCAL Ax, Ay, Bx, By, t TYPE float CALL Draw_Prepare CALL Check_Scale(x_0, y_0, ABS(x_3-x_0)/2.0, ABS(y_3-y_0)/2.0) CALL Check_Rotation(x_0, y_0, ABS(x_3-x_0)/2.0, ABS(y_3-y_0)/2.0) CALL Check_Move() Ax = x_0 : Ay = y_0 glBegin(GL_LINES) FOR t = 0 TO 1 STEP 0.01 Bx = POW((1-t), 3)*x_0 + 3*POW((1-t), 2)*t*x_1 + 3*(1-t)*POW(t,2)*x_2 + POW(t,3)*x_3 By = POW((1-t), 3)*y_0 + 3*POW((1-t), 2)*t*y_1 + 3*(1-t)*POW(t,2)*y_2 + POW(t,3)*y_3 glVertex2f(Ax, Ay) glVertex2f(Bx, By) Ax = Bx : Ay = By NEXT glEnd ENDSUB SUB Fill_Area(unsigned int image[], unsigned int change, unsigned int cnew, x, y) LOCAL yreverse ' The memory block is y-reversed yreverse = CANVAS.ysize-y ' If coordinates are out of scope, exit function IF x < 0 OR x > CANVAS.xsize OR yreverse < 0 OR yreverse > CANVAS.ysize THEN EXIT SUB ' If current position is the same then change color IF image[yreverse*CANVAS.xsize+x] = change THEN image[yreverse*CANVAS.xsize+x] = cnew ELSE EXIT SUB FI ' Recursive call for all directions Fill_Area(image, change, cnew, x+1, y) Fill_Area(image, change, cnew, x-1, y) Fill_Area(image, change, cnew, x, y-1) Fill_Area(image, change, cnew, x, y+1) ENDSUB SUB PAINT(x, y) LOCAL image TYPE unsigned int ARRAY CANVAS.xsize*CANVAS.ysize LOCAL current, cnew TYPE unsigned int LOCAL color[4] TYPE float Draw_Prepare ' Disable current settings glDisable(GL_POINT_SMOOTH) glDisable(GL_LINE_SMOOTH) glDisable(GL_POLYGON_SMOOTH) ' Reset to size 1 glPointSize(1) ' We read 4 bytes RGBA canvas into a dynamic array of integers (4 byte size type) glReadPixels(0, 0, CANVAS.xsize, CANVAS.ysize, GL_RGBA, GL_UNSIGNED_BYTE, image) ' This is the current color to change current = image[(CANVAS.ysize-y)*CANVAS.xsize+x] ' Get the color set by INK glGetFloatv(GL_CURRENT_COLOR, color) cnew = (INT(color[3]*255) << 24) | (INT(color[2]*255) << 16) | (INT(color[1]*255) << 8) | INT(color[0]*255) ' Prevent we're painting an area which has this color already IF cnew <> current THEN ' Call the recursive paint function Fill_Area(image, current, cnew, x, y) ' Put the dynamic array of integers back to the canvas glDrawPixels(CANVAS.xsize, CANVAS.ysize, GL_RGBA, GL_UNSIGNED_BYTE, image) ENDIF ' Restore settings glPointSize(CANVAS.pen_size) glLineWidth(CANVAS.pen_size) IF CANVAS.pen_smooth THEN glEnable(GL_POINT_SMOOTH) glEnable(GL_LINE_SMOOTH) glEnable(GL_POLYGON_SMOOTH) ENDIF ENDSUB SUB LOADFONT(file$) LOCAL x LOCAL data$ LOCAL hershey_font TYPE FILE* IF FILEEXISTS(file$) THEN OPEN file$ FOR READING AS hershey_font FOR x = 0 TO 95 READLN data$ FROM hershey_font CANVAS.font$[x] = MID$(data$, 6) NEXT CLOSE FILE hershey_font ENDIF ENDSUB SUB FONTALIGN(align) ' Determines if the font should be centered (0) or aligned to xposition (1) when scaling is applied CANVAS.font_align = align ENDSUB FUNCTION TEXTLEN(txt$) LOCAL i LOCAL result TYPE float LOCAL letter$ FOR i = 1 TO LEN(txt$) letter$ = CANVAS.font$[ASC(MID$(txt$, i, 1) - 32)] ' Increase length with provided values INCR result, ABS(CANVAS_Coord(MID$(letter$, 4, 1)))*CANVAS.scaling INCR result, ABS(CANVAS_Coord(MID$(letter$, 5, 1)))*CANVAS.scaling NEXT RETURN result ENDFUNCTION SUB TEXT(txt$, x, y) LOCAL i, ptr, posx, posy, tox, toy LOCAL letter$ CALL Draw_Prepare IF CANVAS.font_align = 0 THEN CALL Check_Scale(x-LEN(txt$)*CANVAS.font_width/2, y-15, LEN(txt$)*CANVAS.font_width, 15) ELSE CALL Check_Scale(x-LEN(txt$)*CANVAS.font_width, y-15, LEN(txt$)*CANVAS.font_width, 15) ENDIF CALL Check_Rotation(x-LEN(txt$)*CANVAS.font_width/2, y-15, LEN(txt$)*CANVAS.font_width, 15) CALL Check_Move() FOR i = 1 TO LEN(txt$) letter$ = CANVAS.font$[ASC(MID$(txt$, i, 1) - 32)] ' Increase canvas position with left hand INCR x, ABS(CANVAS_Coord(MID$(letter$, 4, 1))) ' Get first coordinate pair posx = CANVAS_Coord(MID$(letter$, 6, 1)) + x posy = CANVAS_Coord(MID$(letter$, 7, 1)) + y ptr = 8 WHILE ptr < LEN(letter$) IF MID$(letter$, ptr, 2) = " R" THEN INCR ptr, 2 posx = CANVAS_Coord(MID$(letter$, ptr, 1)) + x posy = CANVAS_Coord(MID$(letter$, ptr+1, 1)) + y ELSE tox = CANVAS_Coord(MID$(letter$, ptr, 1)) + x toy = CANVAS_Coord(MID$(letter$, ptr+1, 1)) + y ' Draw with GL primitives to allow rotation and scaling glBegin(GL_LINES) glVertex2f(posx, posy) glVertex2f(tox, toy) glEnd posx = tox posy = toy ENDIF INCR ptr, 2 WEND ' Increase canvas position with right hand INCR x, ABS(CANVAS_Coord(MID$(letter$, 5, 1))) NEXT END SUB FUNCTION GETINK(x, y, int mode) LOCAL image TYPE unsigned int ARRAY CANVAS.xsize*CANVAS.ysize LOCAL current TYPE unsigned int LOCAL r, g, b, a TYPE unsigned int CALL Draw_Prepare ' We read 4 bytes RGBA canvas into a dynamic array of integers (4 byte size type) glReadPixels(0, 0, CANVAS.xsize, CANVAS.ysize, GL_RGBA, GL_UNSIGNED_BYTE, image) ' This is the current color current = image[(CANVAS.ysize - y) * CANVAS.xsize + x] r = current & 0xFF g = (current >> 8) & 0xFF b = (current >> 16) & 0xFF a = (current >> 24) & 0xFF SELECT mode CASE 0 RETURN r CASE 1 RETURN g CASE 2 RETURN b CASE 3 RETURN a CASE 4 current = ((r & 0x0ff) << 24) | ((g & 0x0ff) << 16) | ((b & 0x0ff) << 8) | (a & 0x0ff) RETURN current CASE 5 RETURN current END SELECT END FUNCTION SUB FLIP(flag) CANVAS.flipping = flag CALL Draw_Prepare ENDSUB FUNCTION MOUSE(which) LOCAL result LOCAL wheel = 0, cache = 0 TYPE static int ' Always catch mouse button events cache = CANVAS.mbutton SELECT which CASE 0 result = CANVAS.mx CASE 1 result = CANVAS.my CASE 2 IF cache = 4 OR cache = 5 THEN result = cache IF wheel < 4 THEN INCR wheel ELSE CANVAS.mstate = 0 wheel = 0 ENDIF ELSE result = CANVAS.mbutton ENDIF cache = 0 CASE 3 result = CANVAS.mstate ENDSELECT RETURN result END FUNCTION SUB SYNC IF CANVAS.library$ = "GLUT" THEN glutSwapBuffers() ELIF CANVAS.library$ = "ALLEGRO" THEN al_flip_display() ELIF CANVAS.library$ = "SDL" THEN SDL_GL_SwapBuffers() ELSE glfwSwapBuffers(CANVAS.win) ENDIF ENDSUB SUB QUIT IF CANVAS.library$ = "ALLEGRO" THEN al_set_target_bitmap(NULL) ELIF CANVAS.library$ = "SDL" THEN SDL_Quit() ELIF CANVAS.library$ = "GLFW" THEN glfwTerminate() ENDIF END 0 ENDSUB FUNCTION GLUT_Callback(int timeout) CALL (*CANVAS.callb)() CALL SYNC() glutTimerFunc(timeout, GLUT_Callback, timeout) RETURN TRUE ENDFUNCTION SUB GLUT_Mouse_But(int button, int state, int x, int y) SELECT button CASE GLUT_LEFT_BUTTON CANVAS.mbutton = 1 CASE GLUT_MIDDLE_BUTTON CANVAS.mbutton = 2 CASE GLUT_RIGHT_BUTTON CANVAS.mbutton = 3 CASE 3 CANVAS.mbutton = 4 state = GLUT_DOWN CASE 4 CANVAS.mbutton = 5 state = GLUT_DOWN END SELECT SELECT state CASE GLUT_DOWN CANVAS.mstate = 1 CASE GLUT_UP CANVAS.mstate = 0 ENDSELECT CANVAS.mx = x CANVAS.my = y ENDSUB SUB GLUT_Mouse_Pos(int x, int y) CANVAS.mx = x CANVAS.my = y ENDSUB SUB ALLEGRO_Mouse(void* state, int dz) IF al_mouse_button_down(state, 1) THEN CANVAS.mbutton = 1 CANVAS.mstate = 1 ELIF al_mouse_button_down(state, 2) THEN CANVAS.mbutton = 3 CANVAS.mstate = 1 ELIF al_mouse_button_down(state, 3) THEN CANVAS.mbutton = 2 CANVAS.mstate = 1 ELIF dz > 0 THEN CANVAS.mbutton = 4 CANVAS.mstate = 1 ELIF dz < 0 THEN CANVAS.mbutton = 5 CANVAS.mstate = 1 ELSE CANVAS.mstate = 0 ENDIF CANVAS.mx = al_get_mouse_state_axis(state, 0) CANVAS.my = al_get_mouse_state_axis(state, 1) ENDSUB SUB SDL_Mouse(button) LOCAL xpos, ypos TYPE int SDL_GetMouseState(&xpos, &ypos) SELECT button CASE 0 CANVAS.mstate = 0 CASE 257 CANVAS.mbutton = 1 CANVAS.mstate = 1 CASE 258 CANVAS.mbutton = 2 CANVAS.mstate = 1 CASE 259 CANVAS.mbutton = 3 CANVAS.mstate = 1 CASE 260 CANVAS.mbutton = 4 CANVAS.mstate = 1 CASE 261 CANVAS.mbutton = 5 CANVAS.mstate = 1 END SELECT CANVAS.mx = xpos CANVAS.my = ypos ENDSUB SUB GLFW_Mouse_Pos(void* window, double xpos, double ypos) CANVAS.mx = xpos CANVAS.my = ypos ENDSUB SUB GLFW_Mouse_But(void* window, int button, int action, int mods) SELECT button CASE GLFW_MOUSE_BUTTON_LEFT CANVAS.mbutton = 1 CASE GLFW_MOUSE_BUTTON_MIDDLE CANVAS.mbutton = 2 CASE GLFW_MOUSE_BUTTON_RIGHT CANVAS.mbutton = 3 END SELECT SELECT action CASE GLFW_PRESS CANVAS.mstate = 1 CASE GLFW_RELEASE CANVAS.mstate = 0 ENDSELECT ENDSUB SUB GLFW_Mouse_Scroll(void* window, double x, double y) SELECT y CASE 1 CANVAS.mbutton = 4 CANVAS.mstate = 1 CASE -1 CANVAS.mbutton = 5 CANVAS.mstate = 1 END SELECT END SUB FUNCTION SDL_Callback(int interval, void* param) RECORD SDL_event LOCAL types TYPE unsigned short LOCAL which TYPE unsigned short LOCAL state TYPE unsigned short END RECORD SDL_event.types = 0 SDL_PushEvent(ADDRESS(SDL_event)) RETURN interval ENDFUNCTION SUB CALLBACK(timeout, void* func) CANVAS.callb = func IF CANVAS.library$ = "GLUT" THEN CALL GLUT_Callback(timeout) ELIF CANVAS.library$ = "ALLEGRO" THEN CALL (*CANVAS.callb)() CALL SYNC() CANVAS.timerval = timeout ELIF CANVAS.library$ = "SDL" THEN CALL (*CANVAS.callb)() CALL SYNC() SDL_AddTimer(timeout, SDL_Callback, 0) ELSE CANVAS.timerval = timeout FI ENDSUB SUB WAITKEY RECORD SDL_event LOCAL types TYPE unsigned short LOCAL which TYPE unsigned short LOCAL state TYPE unsigned short END RECORD RECORD ALLEGRO_event LOCAL types TYPE unsigned int LOCAL other TYPE void* LOCAL header, structure TYPE void* LOCAL x, y, z, w TYPE int LOCAL dx, dy, dz, dw TYPE int LOCAL button TYPE int END RECORD LOCAL queue, altimer TYPE void* CALL SYNC() IF CANVAS.library$ = "GLUT" THEN glutKeyboardFunc(QUIT) glutDisplayFunc(SYNC) glutMouseFunc(GLUT_Mouse_But) glutMotionFunc(GLUT_Mouse_Pos) glutPassiveMotionFunc(GLUT_Mouse_Pos) glutSwapBuffers() glutMainLoop ELIF CANVAS.library$ = "ALLEGRO" THEN queue = al_create_event_queue() al_register_event_source(queue, al_get_display_event_source(CANVAS.win)) al_register_event_source(queue, al_get_keyboard_event_source()) al_register_event_source(queue, al_get_mouse_event_source()) IF CANVAS.timerval THEN altimer = al_create_timer(CANVAS.timerval/1000.0) al_register_event_source(queue, al_get_timer_event_source(altimer)) al_start_timer(altimer) ENDIF WHILE TRUE al_wait_for_event(queue, ADDRESS(ALLEGRO_event)) SELECT ALLEGRO_event.types CASE ALLEGRO_EVENT_TIMER CALL (*CANVAS.callb)() CALL SYNC() CASE ALLEGRO_EVENT_DISPLAY_CLOSE; CASE ALLEGRO_EVENT_KEY_DOWN QUIT DEFAULT al_get_mouse_state(ALLEGRO_event.other) CALL ALLEGRO_Mouse(ALLEGRO_event.other, ALLEGRO_event.dz) ENDSELECT WEND ELIF CANVAS.library$ = "SDL" THEN WHILE SDL_WaitEvent(ADDRESS(SDL_event)) SELECT SDL_event.types CASE SDL_QUIT; CASE SDL_KEYDOWN QUIT CASE SDL_MOUSEMOTION; CASE SDL_MOUSEBUTTONUP; CASE SDL_MOUSEBUTTONDOWN SDL_Mouse(SDL_event.which) CASE 0 CALL (*CANVAS.callb)() CALL SYNC() ENDSELECT WEND ELSE glfwSetCursorPosCallback(CANVAS.win, GLFW_Mouse_Pos) glfwSetMouseButtonCallback(CANVAS.win, GLFW_Mouse_But) glfwSetScrollCallback(CANVAS.win, GLFW_Mouse_Scroll) glfwSetKeyCallback(CANVAS.win, QUIT) glfwSetWindowCloseCallback(CANVAS.win, QUIT) WHILE TRUE glfwPollEvents() IF CANVAS.timerval THEN CALL (*CANVAS.callb)() CALL SYNC() SLEEP CANVAS.timerval ENDIF WEND ENDIF END SUB '------------------------------------------------------------------