http://wiki.spheredev.org/api.php?action=feedcontributions&user=Flying+Jester&feedformat=atomSpherical wiki - User contributions [en]2024-03-29T05:59:34ZUser contributionsMediaWiki 1.29.0http://wiki.spheredev.org/index.php?title=Key_codes&diff=9986Key codes2015-12-23T03:19:27Z<p>Flying Jester: </p>
<hr />
<div>This is a list of keycodes you can use in your scripts. Note that there are only two 'l's in KEY_SCROLLOCK.<br />
<br />
<pre>KEY_ESCAPE <br />
KEY_F1 <br />
KEY_F2 <br />
KEY_F3 <br />
KEY_F4 <br />
KEY_F5 <br />
KEY_F6 <br />
KEY_F7 <br />
KEY_F8 <br />
KEY_F9 <br />
KEY_F10 <br />
KEY_F11 <br />
KEY_F12 <br />
KEY_TILDE <br />
KEY_0 <br />
KEY_1 <br />
KEY_2 <br />
KEY_3 <br />
KEY_4 <br />
KEY_5 <br />
KEY_6 <br />
KEY_7 <br />
KEY_8 <br />
KEY_9 <br />
KEY_MINUS <br />
KEY_EQUALS <br />
KEY_BACKSPACE <br />
KEY_TAB <br />
KEY_A <br />
KEY_B <br />
KEY_C <br />
KEY_D <br />
KEY_E <br />
KEY_F <br />
KEY_G <br />
KEY_H <br />
KEY_I <br />
KEY_J <br />
KEY_K <br />
KEY_L <br />
KEY_M <br />
KEY_N <br />
KEY_O <br />
KEY_P <br />
KEY_Q <br />
KEY_R <br />
KEY_S <br />
KEY_T <br />
KEY_U <br />
KEY_V <br />
KEY_W <br />
KEY_X <br />
KEY_Y <br />
KEY_Z <br />
KEY_SHIFT <br />
KEY_CTRL <br />
KEY_ALT <br />
KEY_SPACE <br />
KEY_OPENBRACE <br />
KEY_CLOSEBRACE <br />
KEY_SEMICOLON <br />
KEY_APOSTROPHE <br />
KEY_COMMA <br />
KEY_PERIOD <br />
KEY_SLASH <br />
KEY_BACKSLASH <br />
KEY_ENTER <br />
KEY_INSERT <br />
KEY_DELETE <br />
KEY_HOME <br />
KEY_END <br />
KEY_PAGEUP <br />
KEY_PAGEDOWN <br />
KEY_UP <br />
KEY_RIGHT <br />
KEY_DOWN <br />
KEY_LEFT <br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK</pre></div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Developing_a_Sphere-compatible_engine&diff=1169Developing a Sphere-compatible engine2014-07-27T09:13:37Z<p>Flying Jester: /* Complete or in-progress */</p>
<hr />
<div>{{aside|Notice|This [[:Category:Tutorials|tutorial article]] is incomplete, but it is also important. Do not edit it unless you've been given permission, thanks.|note.svg}}<br />
<br />
This article aims to provide a checklist and resources for developing a JavaScript-powered game engine that is compatible with [[API:Functions|Sphere's JavaScript API]].<br />
<br />
__TOC__<br />
<br />
==Introduction==<br />
Throughout this article, the original Sphere implementation shall be referred to as "vanilla" Sphere and consisted of use of an older version of [https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey] as the JavaScript engine, the first-party [http://corona.sf.net Corona library] for the software implementation of video, and the first-party [http://audiere.sf.net Audiere library] for the audio driver. Input was mapped directly in software using whatever API was native to the OS in the case of the Windows and Linux versions of vanilla Sphere. The recent Mac OS X port of vanilla Sphere used SDL to handle all input and output while still using an older version of SpiderMonkey for JavaScript.<br />
<br />
Possible frameworks to implement Sphere:<br />
* JavaScript<br />
** V8<br />
** SpiderMonkey v1.8.5<br />
** Jurassic / IronJS / JavaScript.Net / Jint<br />
* Game Libraries<br />
** SDL<br />
** SFML<br />
* Graphics libraries<br />
** OpenGL<br />
** pixi.js / three.js<br />
** DirectX (DirectDraw)<br />
** hand-rolled software renderer.<br />
* Audio libraries<br />
** Audiere<br />
** Libsndfile<br />
** BASS<br />
** Irrklang<br />
** FMod<br />
<br />
<br />
(TODO: more)<br />
<br />
==Input==<br />
<br />
===SDL===<br />
If you want to use SDL, it will be helpful to set up an event filter to catch application close events. Since the main function that needs proper access to events is GetKey, you can disable mouse movement, mouse button, and key-up events so that the event queue will be filled with just keydown events. This simplifies the implementation of the GetKey function, as it is the only function that needs the queue to contain a specific kind of event. Be sure to pump or poll for events whenever input is requested. This also keeps the engine responsive during calls to getkey, and tending the event queue keeps the engine responsive in general.<br />
<br />
Keyboard state polling (as in IsKeyPressed()) can be handled with getting the keystate and comparing keysyms.<br />
<br />
===SFML===<br />
If you are using SFML, you need to handle the key pressed and released events. It's a good idea to use a static array for all of the keys, mouse, and joystick buttons. The array's index corresponds with a key, mouse, and joystick code with a true/false value indicating IsPressed. In order to support more than one joystick you may need to bump up that joystick array to a 2D array, where 'x' is the joystick id and 'y' is the button code.<br />
<br />
For the key queue, just use a queue data structure. Enqueue keys on the released state, and dequeue keys with [[API:GetKey|GetKey]].<br />
<br />
===Other input libraries===<br />
(TODO: list possible input handling libraries and gotchas)<br />
<br />
===Handling keyboard input notes===<br />
[[API:GetKey|GetKey]]() must be able to block the sphere engine. If the key queue is empty, go into a loop that just updates the game screen.<br />
<br />
(TODO: fill)<br />
<br />
====Key Constant Mapping====<br />
In SDL, SFML, and other game libraries, key code enumerations offered in source may differ from Sphere's. In order to map keys correctly you might need to implement a very large map that is basically a "this key" = "that key" list. Such a technique is optional if you already follow Sphere's key naming conventions, but what this will do is allow other Sphere engines to use those same codes if you saved a game with key mappings from vanilla Sphere.<br />
<br />
See Sphere's [[list of keycode constants]] for the official list, also at https://github.com/sphere-group/sphere/blob/v1.6/sphere/docs/development/keys.txt<br />
<br />
===Handling mouse input notes===<br />
(TODO)<br />
<br />
===Handling joystick input notes===<br />
(TODO)<br />
<br />
===Other input methods===<br />
(TODO)<br />
<br />
==Output==<br />
===Video===<br />
<br />
Blitting is a process that draws the image or surface to a screen's render target prior to flipping. In web based engines this is best emulated with a "draw queue". You fill the queue with what to draw prior to a frame and update it when you are ready.<br />
<br />
(TODO: more)<br />
(TODO: multi-monitor?)<br />
(TODO: touch-screen?)<br />
<br />
===Audio===<br />
<br />
====SFML====<br />
Audio is split between sounds and music. They have the same API, but music streams intrinsically.<br />
Volume however takes a range of 0 to 100. Treat that as a percent of the 0 to 255 range Sphere uses. You might need to cache the volume into a private variable and get set from that, making sure to set the underlying volume as a percent of whatever you used.<br />
<br />
==Sphere-format file loading==<br />
Sphere uses five custom file formats, all containing bitmap data in some form or another: [[API:Font|bitmap fonts]], [[API:Spriteset|spritesets]], [[API:WindowStyle|stylized window frames]], [[API:Map|maps]], and [[API:Map|map tilesets]]. Some of them have metadata interspersed with the bitmap data, others have a dedicated block that contains all the metadata for the file in one section regardless of the bitmap data. Maps in particular have the option of choosing to embed its tileset within its file or to point to an external tileset file. All have fixed size headers that are trivial to read. All integer values are stored in [[wikipedia:endianness#Little-endian|Intel order/little-endian]] and unless otherwise noted all pixel values are 32-bit and stored in the order RGBA.<br />
<br />
===Fonts===<br />
Pretty straight forward. Version 1 Sphere fonts only allow 8-bit grayscale pixels and are deprecated in favor of version 2 fonts. Version 2 fonts use bitmaps containing full 32-bit RGBA pixels. There are reserved bytes to be aware of, otherwise no metadata.<br />
<br />
===Spritesets===<br />
Three separate versions with separate loading behaviors. Much more complicated than fonts, some reserved bytes, lots of metadata. (TODO: expand)<br />
<br />
===WindowStyles===<br />
Two versions to handle. Some reserved bytes, some deprecated properties depending on version, small amount of metadata. (TODO: expand)<br />
<br />
===Maps===<br />
Lots of metadata, small amount of reserved bytes, can embed tilesets or refer to external tileset files. (TODO: expand)<br />
<br />
===Tilesets===<br />
Lots of metadata, small amount of reserved bytes, bitmap data is in one large block after header but before metadata. (TODO: expand)<br />
<br />
==The map engine==<br />
(TODO)<br />
<br />
===The MapEngine loop===<br />
(TODO)<br />
<br />
==Maintaining API compatibility==<br />
Sphere's original JavaScript API was written with a procedural mentality. JavaScript is a language with a powerful prototype-based inheritance system, so you may want to change Sphere's native objects such as the [[API:Color|Color object]] to allow variable creation via the ''new'' syntax; if you do this natively you must either write the equivalent loading function (in this case, [[API:CreateColor|CreateColor]]) as native code or in a scripted shim. The [[system scripts|system script]] [[Script:system/oldsphere.js|oldsphere.js]] is an example of such a shim, existing to maintain compatibility with projects written for pre-1.0 versions of Sphere. If you'd rather leave the original procedural-style loading functions but add the ability to create native Sphere objects with a working prototype constructor, visit [http://forums.spheredev.org/index.php/topic,69.0.html this forum thread] for information on doing it in script.<br />
<br />
===Compatibility with 1.5===<br />
(TODO)<br />
<br />
===Compatibility with 1.6 beta===<br />
(TODO)<br />
<br />
===Compatibility with 1.7 alpha===<br />
(TODO)<br />
<br />
===Backwards-compatibility with pre-1.5===<br />
(TODO)<br />
<br />
==List of Sphere-compatible engine implementations==<br />
===Complete or in-progress===<br />
{| class="wikitable sortable" width="100%"<br />
|+Complete or in-progress Sphere-compatible engines<br />
|-<br />
! scope="col"| Implementation<br />
! scope="col"| Operating System<br />
! scope="col"| Version<br />
! scope="col"| JS engine<br />
! scope="col"| Video driver<br />
! scope="col"| Audio driver<br />
! scope="col"| Input handler<br />
|-<br />
|vanilla Sphere<br/>[https://github.com/sphere-group/sphere source], [http://forums.spheredev.org/index.php/topic,155.0.html thread]<br />
|Win x86, OSX, Linux x86<br />
|stable: 1.5<br/>unstable: 1.6 beta 4<br/>inactive: 1.7 alpha<br />
|[https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey]<br />
|configurable<br />
|configurable<br />
|configurable<br />
|-<br />
|TurboSphere<br/>[https://github.com/FlyingJester/TurboSphere source], [http://forums.spheredev.org/index.php/topic,13.0.html thread]<br />
|Win x86/64, OSX, Linux x86/64, Solaris 10 amd64<br />
|0.4.0<br />
|[https://code.google.com/p/v8/ V8]<br />
|OpenGL via SDL2<br />
|BASS<br />
|SDL2<br />
|-<br />
|unnamed Sphere clone in SDL<br/>[https://github.com/postcasio/sphereclone source], [http://forums.spheredev.org/index.php/topic,72.0.html thread]<br />
|?<br />
|?<br />
|[https://code.google.com/p/v8/ V8]<br />
|SDL<br />
|SDL<br />
|SDL<br />
|-<br />
|sphere-sfml<br/>[https://github.com/Radnen/sphere-sfml source], [http://forums.spheredev.org/index.php/topic,137.0.html thread]<br />
|Win x86, OSX(?)<br />
|0.65 alpha<br />
|[http://jurassic.codeplex.com/ Jurassic]<br />
|OpenGL via SFML 2<br />
|libsndfile via SFML 2<br />
|SFML 2<br />
|-<br />
|web-sphere<br/>[https://github.com/sphere-group/web-sphere source], [http://forums.spheredev.org/index.php/topic,154.0.html thread]<br />
|Chrome, Firefox, and IE9+<br />
|[http://www.pixijs.com/ pixi.js] version: ?<br/>[http://threejs.org/ three.js] version: ?<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|}<br />
<br />
{{aside|Info|Although some engines are listed as compatible they will need a shim script to maintain compatibility with Sphere's API. For example, [[API:LoadImage|LoadImage]] may indeed return the correct [[API:image|image]] format by using a different API such as <tt>return new Image()</tt>.|template-info.svg}}<br />
<br />
===Discontinued or abandoned===<br />
(TODO)<br />
<br />
==See also==<br />
(TODO)<br />
<br />
[[Category:Tutorials]]</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Developing_a_Sphere-compatible_engine&diff=1168Developing a Sphere-compatible engine2014-07-27T09:10:48Z<p>Flying Jester: /* Complete or in-progress */</p>
<hr />
<div>{{aside|Notice|This [[:Category:Tutorials|tutorial article]] is incomplete, but it is also important. Do not edit it unless you've been given permission, thanks.|note.svg}}<br />
<br />
This article aims to provide a checklist and resources for developing a JavaScript-powered game engine that is compatible with [[API:Functions|Sphere's JavaScript API]].<br />
<br />
__TOC__<br />
<br />
==Introduction==<br />
Throughout this article, the original Sphere implementation shall be referred to as "vanilla" Sphere and consisted of use of an older version of [https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey] as the JavaScript engine, the first-party [http://corona.sf.net Corona library] for the software implementation of video, and the first-party [http://audiere.sf.net Audiere library] for the audio driver. Input was mapped directly in software using whatever API was native to the OS in the case of the Windows and Linux versions of vanilla Sphere. The recent Mac OS X port of vanilla Sphere used SDL to handle all input and output while still using an older version of SpiderMonkey for JavaScript.<br />
<br />
Possible frameworks to implement Sphere:<br />
* JavaScript<br />
** V8<br />
** SpiderMonkey v1.8.5<br />
** Jurassic / IronJS / JavaScript.Net / Jint<br />
* Game Libraries<br />
** SDL<br />
** SFML<br />
* Graphics libraries<br />
** OpenGL<br />
** pixi.js / three.js<br />
** DirectX (DirectDraw)<br />
** hand-rolled software renderer.<br />
* Audio libraries<br />
** Audiere<br />
** Libsndfile<br />
** BASS<br />
** Irrklang<br />
** FMod<br />
<br />
<br />
(TODO: more)<br />
<br />
==Input==<br />
<br />
===SDL===<br />
If you want to use SDL, it will be helpful to set up an event filter to catch application close events. Since the main function that needs proper access to events is GetKey, you can disable mouse movement, mouse button, and key-up events so that the event queue will be filled with just keydown events. This simplifies the implementation of the GetKey function, as it is the only function that needs the queue to contain a specific kind of event. Be sure to pump or poll for events whenever input is requested. This also keeps the engine responsive during calls to getkey, and tending the event queue keeps the engine responsive in general.<br />
<br />
Keyboard state polling (as in IsKeyPressed()) can be handled with getting the keystate and comparing keysyms.<br />
<br />
===SFML===<br />
If you are using SFML, you need to handle the key pressed and released events. It's a good idea to use a static array for all of the keys, mouse, and joystick buttons. The array's index corresponds with a key, mouse, and joystick code with a true/false value indicating IsPressed. In order to support more than one joystick you may need to bump up that joystick array to a 2D array, where 'x' is the joystick id and 'y' is the button code.<br />
<br />
For the key queue, just use a queue data structure. Enqueue keys on the released state, and dequeue keys with [[API:GetKey|GetKey]].<br />
<br />
===Other input libraries===<br />
(TODO: list possible input handling libraries and gotchas)<br />
<br />
===Handling keyboard input notes===<br />
[[API:GetKey|GetKey]]() must be able to block the sphere engine. If the key queue is empty, go into a loop that just updates the game screen.<br />
<br />
(TODO: fill)<br />
<br />
====Key Constant Mapping====<br />
In SDL, SFML, and other game libraries, key code enumerations offered in source may differ from Sphere's. In order to map keys correctly you might need to implement a very large map that is basically a "this key" = "that key" list. Such a technique is optional if you already follow Sphere's key naming conventions, but what this will do is allow other Sphere engines to use those same codes if you saved a game with key mappings from vanilla Sphere.<br />
<br />
See Sphere's [[list of keycode constants]] for the official list, also at https://github.com/sphere-group/sphere/blob/v1.6/sphere/docs/development/keys.txt<br />
<br />
===Handling mouse input notes===<br />
(TODO)<br />
<br />
===Handling joystick input notes===<br />
(TODO)<br />
<br />
===Other input methods===<br />
(TODO)<br />
<br />
==Output==<br />
===Video===<br />
<br />
Blitting is a process that draws the image or surface to a screen's render target prior to flipping. In web based engines this is best emulated with a "draw queue". You fill the queue with what to draw prior to a frame and update it when you are ready.<br />
<br />
(TODO: more)<br />
(TODO: multi-monitor?)<br />
(TODO: touch-screen?)<br />
<br />
===Audio===<br />
<br />
====SFML====<br />
Audio is split between sounds and music. They have the same API, but music streams intrinsically.<br />
Volume however takes a range of 0 to 100. Treat that as a percent of the 0 to 255 range Sphere uses. You might need to cache the volume into a private variable and get set from that, making sure to set the underlying volume as a percent of whatever you used.<br />
<br />
==Sphere-format file loading==<br />
Sphere uses five custom file formats, all containing bitmap data in some form or another: [[API:Font|bitmap fonts]], [[API:Spriteset|spritesets]], [[API:WindowStyle|stylized window frames]], [[API:Map|maps]], and [[API:Map|map tilesets]]. Some of them have metadata interspersed with the bitmap data, others have a dedicated block that contains all the metadata for the file in one section regardless of the bitmap data. Maps in particular have the option of choosing to embed its tileset within its file or to point to an external tileset file. All have fixed size headers that are trivial to read. All integer values are stored in [[wikipedia:endianness#Little-endian|Intel order/little-endian]] and unless otherwise noted all pixel values are 32-bit and stored in the order RGBA.<br />
<br />
===Fonts===<br />
Pretty straight forward. Version 1 Sphere fonts only allow 8-bit grayscale pixels and are deprecated in favor of version 2 fonts. Version 2 fonts use bitmaps containing full 32-bit RGBA pixels. There are reserved bytes to be aware of, otherwise no metadata.<br />
<br />
===Spritesets===<br />
Three separate versions with separate loading behaviors. Much more complicated than fonts, some reserved bytes, lots of metadata. (TODO: expand)<br />
<br />
===WindowStyles===<br />
Two versions to handle. Some reserved bytes, some deprecated properties depending on version, small amount of metadata. (TODO: expand)<br />
<br />
===Maps===<br />
Lots of metadata, small amount of reserved bytes, can embed tilesets or refer to external tileset files. (TODO: expand)<br />
<br />
===Tilesets===<br />
Lots of metadata, small amount of reserved bytes, bitmap data is in one large block after header but before metadata. (TODO: expand)<br />
<br />
==The map engine==<br />
(TODO)<br />
<br />
===The MapEngine loop===<br />
(TODO)<br />
<br />
==Maintaining API compatibility==<br />
Sphere's original JavaScript API was written with a procedural mentality. JavaScript is a language with a powerful prototype-based inheritance system, so you may want to change Sphere's native objects such as the [[API:Color|Color object]] to allow variable creation via the ''new'' syntax; if you do this natively you must either write the equivalent loading function (in this case, [[API:CreateColor|CreateColor]]) as native code or in a scripted shim. The [[system scripts|system script]] [[Script:system/oldsphere.js|oldsphere.js]] is an example of such a shim, existing to maintain compatibility with projects written for pre-1.0 versions of Sphere. If you'd rather leave the original procedural-style loading functions but add the ability to create native Sphere objects with a working prototype constructor, visit [http://forums.spheredev.org/index.php/topic,69.0.html this forum thread] for information on doing it in script.<br />
<br />
===Compatibility with 1.5===<br />
(TODO)<br />
<br />
===Compatibility with 1.6 beta===<br />
(TODO)<br />
<br />
===Compatibility with 1.7 alpha===<br />
(TODO)<br />
<br />
===Backwards-compatibility with pre-1.5===<br />
(TODO)<br />
<br />
==List of Sphere-compatible engine implementations==<br />
===Complete or in-progress===<br />
{| class="wikitable sortable" width="100%"<br />
|+Complete or in-progress Sphere-compatible engines<br />
|-<br />
! scope="col"| Implementation<br />
! scope="col"| Operating System<br />
! scope="col"| Version<br />
! scope="col"| JS engine<br />
! scope="col"| Video driver<br />
! scope="col"| Audio driver<br />
! scope="col"| Input handler<br />
|-<br />
|vanilla Sphere<br/>[https://github.com/sphere-group/sphere source], [http://forums.spheredev.org/index.php/topic,155.0.html thread]<br />
|Win x86, OSX, Linux x86<br />
|stable: 1.5<br/>unstable: 1.6 beta 4<br/>inactive: 1.7 alpha<br />
|[https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey]<br />
|configurable<br />
|configurable<br />
|configurable<br />
|-<br />
|TurboSphere<br/>[https://github.com/FlyingJester/TurboSphere source], [http://forums.spheredev.org/index.php/topic,13.0.html thread]<br />
|Win x86/64, OSX, Linux x86/64, Solaris 10 amd64<br />
|0.3.5a<br />
|[https://code.google.com/p/v8/ V8]<br />
|OpenGL via SDL2<br />
|BASS<br />
|SDL2<br />
|-<br />
|unnamed Sphere clone in SDL<br/>[https://github.com/postcasio/sphereclone source], [http://forums.spheredev.org/index.php/topic,72.0.html thread]<br />
|?<br />
|?<br />
|[https://code.google.com/p/v8/ V8]<br />
|SDL<br />
|SDL<br />
|SDL<br />
|-<br />
|sphere-sfml<br/>[https://github.com/Radnen/sphere-sfml source], [http://forums.spheredev.org/index.php/topic,137.0.html thread]<br />
|Win x86, OSX(?)<br />
|0.65 alpha<br />
|[http://jurassic.codeplex.com/ Jurassic]<br />
|OpenGL via SFML 2<br />
|libsndfile via SFML 2<br />
|SFML 2<br />
|-<br />
|web-sphere<br/>[https://github.com/sphere-group/web-sphere source], [http://forums.spheredev.org/index.php/topic,154.0.html thread]<br />
|Chrome, Firefox, and IE9+<br />
|[http://www.pixijs.com/ pixi.js] version: ?<br/>[http://threejs.org/ three.js] version: ?<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|}<br />
<br />
{{aside|Info|Although some engines are listed as compatible they will need a shim script to maintain compatibility with Sphere's API. For example, [[API:LoadImage|LoadImage]] may indeed return the correct [[API:image|image]] format by using a different API such as <tt>return new Image()</tt>.|template-info.svg}}<br />
<br />
===Discontinued or abandoned===<br />
(TODO)<br />
<br />
==See also==<br />
(TODO)<br />
<br />
[[Category:Tutorials]]</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/SpriteBatch_API&diff=1063User:Flying Jester/SpriteBatch API2013-11-25T19:30:11Z<p>Flying Jester: </p>
<hr />
<div>This page is draft of the SpriteBatch API for TurboSphere.<br />
<br />
==Variables==<br />
<br />
*POINT<br />
*LINE<br />
*TRIANGLE<br />
*RECTANGLE<br />
*POLYGON<br />
*CIRCLE<br />
*FILLED<br />
*OUTLINED<br />
*GRADIENT<br />
*OUTLINED_GRADIENT<br />
*BLIT<br />
*ROTATE_BLIT<br />
*ZOOM_BLIT<br />
*STRETCH_BLIT<br />
*TRANSFORM_BLIT<br />
<br />
==Objects==<br />
<br />
* SpriteBatch()<br />
:: Creates a new SpriteBatch object.<br />
<br />
==Functions==<br />
<br />
* spritebatch.addTexture(tex)<br />
:: Clones 'tex' into one of the spritebatch's buffers. 'tex' can be a Surface or Image. Any modifications to 'tex' after being cloned are not reflected by the copy in 'spritebatch'.<br />
<br />
* spritebatch.getImages()<br />
:: Returns an array of added [[API:Image|images]] or surfaces (which are converted to images by adding them to the spritebatch) held in the buffer(s) of 'spritebatch'. These can be blit to the screen.<br />
<br />
* spritebatch.pushTexture(tex, mode, ..., ['', [[API:Color|mask]]''])<br />
:: Pushes a texture drawing operation for 'spritebatch' to perform when it draws. 'tex' is the index of the texture to draw. 'mode' can be:<br />
<br />
*# BLIT<br />
*# ROTATE_BLIT<br />
*# ZOOM_BLIT<br />
*# STRETCH_BLIT<br />
*# TRANSFORM_BLIT<br />
<br />
:: Function signatures are:<br />
<br />
*#* spritebatch.pushTexture(tex, BLIT, x, y, ['', [[API:Color|mask]]''])<br />
*#* spritebatch.pushTexture(tex, ROTATE_BLIT, x, y, a ['', [[API:Color|mask]]''])<br />
*#* spritebatch.pushTexture(tex, ZOOM_BLIT, x, y, f ['', [[API:Color|mask]]''])<br />
*#* spritebatch.pushTexture(tex, STRETCH_BLIT, x, y, xf, yf ['', [[API:Color|mask]]''])<br />
*#* spritebatch.pushTexture(tex, TRANSFORM_BLIT, x1, y1, x2, y2, x3, y3, x4, y4 ['', [[API:Color|mask]]''])<br />
<br />
<br />
* spritebatch.insertTexture(index, tex, mode, ..., ['', [[API:Color|mask]]''])<br />
:: Same as pushTexture, but inserts operation at 'index' in the list of operations to perform.<br />
<br />
* spritebatch.pushPrimitiveOperation(primitive, type, ...)<br />
:: Adds a primitive operation to the list of operations 'spritebatch' will perform when draw() is called. Primitives can be<br />
<br />
*# POINT<br />
*# LINE<br />
*# TRIANGLE<br />
*# RECTANGLE<br />
*# POLYGON<br />
*# CIRCLE<br />
<br />
:: Types can be<br />
<br />
*# FILLED<br />
*# OUTLINED<br />
*# GRADIENT<br />
*# OUTLINED_GRADIENT<br />
<br />
:: Function signatures are:<br />
<br />
*#* spritebatch.addPrimitiveOperation(POINT, type, x, y, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(LINE, type, x1, y1, x2, y2, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(TRIANGLE, type, x1, y1, x2, y2, x3, y3, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(RECTANGLE, type, x, y, w, h [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(POLYGON, type, xs, ys, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(CIRCLE, type, x, y, r, [[API:Color|color]] ...)<br />
<br />
::'color' is defined by 'type'.<br />
<br />
*#* FILLED or OUTLINED: one color.<br />
*#* GRADIENT or OUTLINED_GRADIENT: one color argument for each vertex.<br />
<br />
* spritebatch.insertPrimitiveOperation(index, primitive, type, ...)<br />
:: Same as pushOperation, but inserts the operation at 'index' in the list.<br />
<br />
* spritebatch.popOperation()<br />
:: Removes the last operation from 'spritebatch'.<br />
<br />
* spritebatch.spliceOperation(index ['', num''])<br />
:: Removes operation at 'index'. If 'num' is specified, removes 'num' operations starting at 'index'. If 'index' is negative, it is treated as that many items from the end of the operation list. If 'num' is negative, 'num' operations preceding 'index' are removed.<br />
<br />
===Drawing Control===<br />
<br />
* spritebatch.draw()<br />
:: Draws 'spritebatch'. All operations in its list will be performed.<br />
<br />
* spritebatch.setOffset(x, y)<br />
::Specifies an offset for drawing 'spritebatch'.<br />
<br />
* spritebatch.setRotation(a)<br />
::Sets a rotation angle for 'spritebatch'<br />
<br />
* spritebatch.setScale(f)<br />
::Sets a scaling factor for 'spritebatch'</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/SpriteBatch_API&diff=1062User:Flying Jester/SpriteBatch API2013-11-25T19:29:09Z<p>Flying Jester: </p>
<hr />
<div>This page is draft of the SpriteBatch API for TurboSphere.<br />
<br />
==Variables==<br />
<br />
*POINT<br />
*LINE<br />
*TRIANGLE<br />
*RECTANGLE<br />
*POLYGON<br />
*CIRCLE<br />
*FILLED<br />
*OUTLINED<br />
*GRADIENT<br />
*OUTLINED_GRADIENT<br />
*BLIT<br />
*ROTATE_BLIT<br />
*ZOOM_BLIT<br />
*STRETCH_BLIT<br />
*TRANSFORM_BLIT<br />
<br />
==Objects==<br />
<br />
* SpriteBatch()<br />
:: Creates a new SpriteBatch object.<br />
<br />
* spritebatch.addTexture(tex)<br />
:: Clones 'tex' into one of the spritebatch's buffers. 'tex' can be a Surface or Image. Any modifications to 'tex' after being cloned are not reflected by the copy in 'spritebatch'.<br />
<br />
* spritebatch.getImages()<br />
:: Returns an array of added [[API:Image|images]] or surfaces (which are converted to images by adding them to the spritebatch) held in the buffer(s) of 'spritebatch'. These can be blit to the screen.<br />
<br />
* spritebatch.pushTexture(tex, mode, ..., ['', [[API:Color|mask]]''])<br />
:: Pushes a texture drawing operation for 'spritebatch' to perform when it draws. 'tex' is the index of the texture to draw. 'mode' can be:<br />
<br />
*# BLIT<br />
*# ROTATE_BLIT<br />
*# ZOOM_BLIT<br />
*# STRETCH_BLIT<br />
*# TRANSFORM_BLIT<br />
<br />
:: Function signatures are:<br />
<br />
*#* spritebatch.pushTexture(tex, BLIT, x, y, ['', [[API:Color|mask]]''])<br />
*#* spritebatch.pushTexture(tex, ROTATE_BLIT, x, y, a ['', [[API:Color|mask]]''])<br />
*#* spritebatch.pushTexture(tex, ZOOM_BLIT, x, y, f ['', [[API:Color|mask]]''])<br />
*#* spritebatch.pushTexture(tex, STRETCH_BLIT, x, y, xf, yf ['', [[API:Color|mask]]''])<br />
*#* spritebatch.pushTexture(tex, TRANSFORM_BLIT, x1, y1, x2, y2, x3, y3, x4, y4 ['', [[API:Color|mask]]''])<br />
<br />
<br />
* spritebatch.insertTexture(index, tex, mode, ..., ['', [[API:Color|mask]]''])<br />
:: Same as pushTexture, but inserts operation at 'index' in the list of operations to perform.<br />
<br />
* spritebatch.pushPrimitiveOperation(primitive, type, ...)<br />
:: Adds a primitive operation to the list of operations 'spritebatch' will perform when draw() is called. Primitives can be<br />
<br />
*# POINT<br />
*# LINE<br />
*# TRIANGLE<br />
*# RECTANGLE<br />
*# POLYGON<br />
*# CIRCLE<br />
<br />
:: Types can be<br />
<br />
*# FILLED<br />
*# OUTLINED<br />
*# GRADIENT<br />
*# OUTLINED_GRADIENT<br />
<br />
:: Function signatures are:<br />
<br />
*#* spritebatch.addPrimitiveOperation(POINT, type, x, y, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(LINE, type, x1, y1, x2, y2, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(TRIANGLE, type, x1, y1, x2, y2, x3, y3, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(RECTANGLE, type, x, y, w, h [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(POLYGON, type, xs, ys, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(CIRCLE, type, x, y, r, [[API:Color|color]] ...)<br />
<br />
::'color' is defined by 'type'.<br />
<br />
*#* FILLED or OUTLINED: one color.<br />
*#* GRADIENT or OUTLINED_GRADIENT: one color argument for each vertex.<br />
<br />
* spritebatch.insertPrimitiveOperation(index, primitive, type, ...)<br />
:: Same as pushOperation, but inserts the operation at 'index' in the list.<br />
<br />
* spritebatch.popOperation()<br />
:: Removes the last operation from 'spritebatch'.<br />
<br />
* spritebatch.spliceOperation(index ['', num''])<br />
:: Removes operation at 'index'. If 'num' is specified, removes 'num' operations starting at 'index'. If 'index' is negative, it is treated as that many items from the end of the operation list. If 'num' is negative, 'num' operations preceding 'index' are removed.<br />
<br />
==Functions==<br />
<br />
* spritebatch.draw()<br />
:: Draws 'spritebatch'. All operations in its list will be performed.<br />
<br />
* spritebatch.setOffset(x, y)<br />
::Specifies an offset for drawing 'spritebatch'.<br />
<br />
* spritebatch.setRotation(a)<br />
::Sets a rotation angle for 'spritebatch'<br />
<br />
* spritebatch.setScale(f)<br />
::Sets a scaling factor for 'spritebatch'</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/SpriteBatch_API&diff=1061User:Flying Jester/SpriteBatch API2013-11-25T04:04:12Z<p>Flying Jester: </p>
<hr />
<div>This page is draft of the SpriteBatch API for TurboSphere.<br />
<br />
==Variables==<br />
<br />
*POINT<br />
*LINE<br />
*TRIANGLE<br />
*RECTANGLE<br />
*POLYGON<br />
*CIRCLE<br />
*FILLED<br />
*OUTLINED<br />
*GRADIENT<br />
*OUTLINED_GRADIENT<br />
*BLIT<br />
*ROTATE_BLIT<br />
*ZOOM_BLIT<br />
*STRETCH_BLIT<br />
*TRANSFORM_BLIT<br />
<br />
==Objects==<br />
<br />
* SpriteBatch()<br />
:: Creates a new SpriteBatch object.<br />
<br />
* spritebatch.addTexture(tex)<br />
:: Clones 'tex' into one of the spritebatch's buffers. 'tex' can be a Surface or Image. Any modifications to 'tex' after being cloned are not reflected by the copy in 'spritebatch'.<br />
<br />
* spritebatch.getImages()<br />
:: Returns an array of added [[API:Image|images]] or surfaces (which are converted to images by adding them to the spritebatch) held in the buffer(s) of 'spritebatch'. These can be blit to the screen.<br />
<br />
* spritebatch.pushTexture(tex, mode, ..., ['', [[API:Color|mask]]''])<br />
:: Pushes a texture drawing operation for 'spritebatch' to perform when it draws. 'tex' is the index of the texture to draw. 'mode' can be:<br />
<br />
*# BLIT<br />
*# ROTATE_BLIT<br />
*# ZOOM_BLIT<br />
*# STRETCH_BLIT<br />
*# TRANSFORM_BLIT<br />
<br />
:: Function signatures are:<br />
<br />
*#* spritebatch.pushTexture(tex, BLIT, x, y, ['', [[API:Color|mask]]''])<br />
*#* spritebatch.pushTexture(tex, ROTATE_BLIT, x, y, a ['', [[API:Color|mask]]''])<br />
*#* spritebatch.pushTexture(tex, ZOOM_BLIT, x, y, f ['', [[API:Color|mask]]''])<br />
*#* spritebatch.pushTexture(tex, STRETCH_BLIT, x, y, xf, yf ['', [[API:Color|mask]]''])<br />
*#* spritebatch.pushTexture(tex, TRANSFORM_BLIT, x1, y1, x2, y2, x3, y3, x4, y4 ['', [[API:Color|mask]]''])<br />
<br />
<br />
* spritebatch.insertTexture(index, tex, mode, ..., ['', [[API:Color|mask]]''])<br />
:: Same as pushTexture, but inserts operation at 'index' in the list of operations to perform.<br />
<br />
* spritebatch.pushPrimitiveOperation(primitive, type, ...)<br />
:: Adds a primitive operation to the list of operations 'spritebatch' will perform when draw() is called. Primitives can be<br />
<br />
*# POINT<br />
*# LINE<br />
*# TRIANGLE<br />
*# RECTANGLE<br />
*# POLYGON<br />
*# CIRCLE<br />
<br />
:: Types can be<br />
<br />
*# FILLED<br />
*# OUTLINED<br />
*# GRADIENT<br />
*# OUTLINED_GRADIENT<br />
<br />
:: Function signatures are:<br />
<br />
*#* spritebatch.addPrimitiveOperation(POINT, type, x, y, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(LINE, type, x1, y1, x2, y2, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(TRIANGLE, type, x1, y1, x2, y2, x3, y3, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(RECTANGLE, type, x, y, w, h [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(POLYGON, type, xs, ys, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(CIRCLE, type, x, y, r, [[API:Color|color]] ...)<br />
<br />
::'color' is defined by 'type'.<br />
<br />
*#* FILLED or OUTLINED: one color.<br />
*#* GRADIENT or OUTLINED_GRADIENT: one color argument for each vertex.<br />
<br />
* spritebatch.insertPrimitiveOperation(index, primitive, type, ...)<br />
:: Same as pushOperation, but inserts the operation at 'index' in the list.<br />
<br />
* spritebatch.popOperation()<br />
:: Removes the last operation from 'spritebatch'.<br />
<br />
* spritebatch.spliceOperation(index ['', num''])<br />
:: Removes operation at 'index'. If 'num' is specified, removes 'num' operations starting at 'index'. If 'index' is negative, it is treated as that many items from the end of the operation list. If 'num' is negative, 'num' operations preceding 'index' are removed.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/SpriteBatch_API&diff=1060User:Flying Jester/SpriteBatch API2013-11-25T04:01:03Z<p>Flying Jester: </p>
<hr />
<div>This page is draft of the SpriteBatch API for TurboSphere.<br />
<br />
==Variables==<br />
<br />
*POINT<br />
*LINE<br />
*TRIANGLE<br />
*RECTANGLE<br />
*POLYGON<br />
*CIRCLE<br />
*FILLED<br />
*OUTLINED<br />
*GRADIENT<br />
*OUTLINED_GRADIENT<br />
*BLIT<br />
*ROTATE_BLIT<br />
*ZOOM_BLIT<br />
*STRETCH_BLIT<br />
*TRANSFORM_BLIT<br />
<br />
==Objects==<br />
<br />
* SpriteBatch()<br />
:: Creates a new SpriteBatch object.<br />
<br />
* spritebatch.addTexture(tex)<br />
:: Clones 'tex' into one of the spritebatch's buffers. 'tex' can be a Surface or Image. Any modifications to 'tex' after being cloned are not reflected by the copy in 'spritebatch'.<br />
<br />
* spritebatch.getImages()<br />
:: Returns an array of added [[API:Image|images]] or surfaces (which are converted to images by adding them to the spritebatch) held in the buffer(s) of 'spritebatch'. These can be blit to the screen.<br />
<br />
* spritebatch.pushTexture(tex, mode, ..., [', [[API:Color|mask]]'])<br />
:: Pushes a texture drawing operation for 'spritebatch' to perform when it draws. 'tex' is the index of the texture to draw. 'mode' can be:<br />
<br />
*# BLIT<br />
*# ROTATE_BLIT<br />
*# ZOOM_BLIT<br />
*# STRETCH_BLIT<br />
*# TRANSFORM_BLIT<br />
<br />
:: Function signatures are:<br />
<br />
*#* spritebatch.pushTexture(tex, BLIT, x, y, [', [[API:Color|mask]]'])<br />
*#* spritebatch.pushTexture(tex, ROTATE_BLIT, x, y, a [', [[API:Color|mask]]'])<br />
*#* spritebatch.pushTexture(tex, ZOOM_BLIT, x, y, f [', [[API:Color|mask]]'])<br />
*#* spritebatch.pushTexture(tex, STRETCH_BLIT, x, y, xf, yf [', [[API:Color|mask]]'])<br />
*#* spritebatch.pushTexture(tex, TRANSFORM_BLIT, x1, y1, x2, y2, x3, y3, x4, y4 [', [[API:Color|mask]]'])<br />
<br />
<br />
* spritebatch.insertTexture(index, tex, mode, ..., [', [[API:Color|mask]]'])<br />
:: Same as pushTexture, but inserts operation at 'index' in the list of operations to perform.<br />
<br />
* spritebatch.pushPrimitiveOperation(primitive, type, ...)<br />
:: Adds a primitive operation to the list of operations 'spritebatch' will perform when draw() is called. Primitives can be<br />
<br />
*# POINT<br />
*# LINE<br />
*# TRIANGLE<br />
*# RECTANGLE<br />
*# POLYGON<br />
*# CIRCLE<br />
<br />
:: Types can be<br />
<br />
*# FILLED<br />
*# OUTLINED<br />
*# GRADIENT<br />
*# OUTLINED_GRADIENT<br />
<br />
:: Function signatures are:<br />
<br />
*#* spritebatch.addPrimitiveOperation(POINT, type, x, y, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(LINE, type, x1, y1, x2, y2, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(TRIANGLE, type, x1, y1, x2, y2, x3, y3, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(RECTANGLE, type, x, y, w, h [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(POLYGON, type, xs, ys, [[API:Color|color]] ...)<br />
*#* spritebatch.addPrimitiveOperation(CIRCLE, type, x, y, r, [[API:Color|color]] ...)<br />
<br />
::'color' is defined by 'type'.<br />
<br />
*#* FILLED or OUTLINED: one color.<br />
*#* GRADIENT or OUTLINED_GRADIENT: one color argument for each vertex.<br />
<br />
* spritebatch.insertPrimitiveOperation(index, primitive, type, ...)<br />
:: Same as pushOperation, but inserts the operation at 'index' in the list.<br />
<br />
* spritebatch.popOperation()<br />
:: Removes the last operation from 'spritebatch'.<br />
<br />
* spritebatch.spliceOperation(index [', num'])<br />
:: Removes operation at 'index'. If 'num' is specified, removes 'num' operations starting at 'index'. If 'index' is negative, it is treated as that many items from the end of the operation list. If 'num' is negative, 'num' operations preceding 'index' are removed.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=1059User:Flying Jester/TurboSphere API2013-11-25T03:54:03Z<p>Flying Jester: /* Time Functions */</p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.5a. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
Note that while functions and objects are linked to by this page, all pages prefixed with 'API' refer to the Sphere versions of the objects and functions. The descriptions and examples for Sphere functions and objects are generally analogous to the TurboSphere versions, but not exactly the same.<br />
<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* EvaluateScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it if it has not been required previously.<br />
<br />
* RequireSystemScript(filename)<br />
:: Requires a script in the system/script directory.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
* Exit()<br />
:: Unconditionally exits the engine.<br />
<br />
* Abort(message)<br />
:: Aborts execution and displays 'message'.<br />
<br />
* GarbageCollect()<br />
:: Attempts to trigger garbage collection of the JS environment. This function is primarily kept for compatibility. Garbage collection may or may not actually take place when it is called.<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time. This does not affect any threaded operations, which continue to run.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
* SetClippingRectangle(x, y, w, h)<br />
:: Sets the clipping rectangle on the screen.<br />
<br />
* GetClippingRectangle()<br />
:: Returns an object with the properties x, y, w, h, that describes the current clipping rectangle of the screen.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported formats are BMP and TGA (with RLE compression). Some versions (particularly on Unix-like platforms) support saving to PNG.<br />
<br />
* GrabImage(x, y, w, h)<br />
::Returns a new image object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface(...)<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]]. If you plan on blitting a surface more than once, consider converting it to an image with surface.createImage().<br />
<br />
* surface.setAlpha(a)<br />
::Sets the alpha of the surface to 'a'.<br />
<br />
* surface.blitSurface(surface_object, x, y)<br />
:: Blits surface_object onto surface at x, y.<br />
<br />
* surface.cloneSection(x, y, w, h)<br />
:: Returns a surface object that contains the section of surface at x, y, and is w by h.<br />
<br />
* surface.setClippingRectangle(x, y, w, h)<br />
::Sets the clipping rectangle of the surface. Anything drawing operations that are outside the clipping rectangle are ignored.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface = new Surface(16, 16, new Color(255, 0, 0, 255)); //Create a red surface.<br />
<br />
surface.rectangle(0, 0, 16, 8, new Color(0, 0, 255, 255)); //Make the top half of the surface blue.<br />
<br />
surface.setClippingRectangle(8, 0, 8, 16); //Set the clipping rectangle of the surface to be the right half.<br />
<br />
surface.rectangle(0, 0, 16, 16, new Color(0, 255, 0, 255)); //Try and fill the rectangle with green. Only the right half will be changed!<br />
</syntaxhighlight><br />
<br />
::; The clipping rectangle can be reset as so:<br />
<syntaxhighlight><br />
surface.setCLippingRectangle(0, 0, surface.width, surface.height); //Set the clipping rectangle to be from 0, 0, to the edges.<br />
</syntaxhighlight><br />
<br />
* surface.getClippingRectangle()<br />
::Returns a JS object that represents the surface's clipping rectangle, with properties 'x', 'y', 'w', and 'h'.<br />
<br />
* surface.save(filename)<br />
::Saves 'surface' to 'filename' in the images directory. Extensions are not automatically appended to 'filename', the filename will be exactly as specified. Currently the only supported formats are BMP and TGA (with RLE compression). Some versions (particularly on Unix-like platforms) support saving to PNG.<br />
<br />
* GrabSurface(x, y, w, h)<br />
::Returns a new surface object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* surface.createImage()<br />
::Returns a new [[API:Image|image]] that has the same pixel properties as 'surface'. Use of this call should be limited so as to not waste processing time and graphics RAM.<br />
<br />
====Surface Pixel Access====<br />
<br />
* surface.setPixel(x, y, [[API:Color|color]])<br />
::Sets the pixel of 'surface' at 'x', 'y', to 'color'. No blending is performed.<br />
<br />
* surface.getPixel(x, y)<br />
::Returns the [[API:Color|color]] of the pixel at 'x', 'y', on 'surface'.<br />
<br />
====Surface Primitives====<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]])<br />
::Draws an outline of a circle on 'surface' of radius 'r', centered on 'x', 'y', of 'color'<br />
<br />
* surface.filledCircle(x, y, r, , [[API:Color|color]])<br />
::Draws a filled circle of 'color' on 'surface', centered on 'x', 'y', with a radius of 'r'.<br />
<br />
* surface.gradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h' on 'surface'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
====Surface Properties====<br />
<br />
* surface.width<br />
::Value contains the width of the surface.<br />
<br />
* surface.height<br />
::Value contains the height of the surface.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* GradientLine(x1, y1, x2, y2, [[API:Color|color1]], [[API:Color|color2]])<br />
:: Draws a line of from x1, y1, to x2, y2 fading between 'color1' and 'color2'.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* OutlinedRectangle(x, y, w, h, [[API:Color|color]] [, thickness])<br />
:: Draws an outline of a rectangle of 'color' width w and height h at x, y. The edges are drawn of 'thickness'. If thickness is not provided, it is one pixel.<br />
<br />
* Triangle(x1, y1, x2, y2, x3, y3, , [[API:Color|color]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', filled with 'color'.<br />
<br />
* GradientTriangle(x1, y1, x2, y2, x3, y3, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', fading between the colors.<br />
<br />
* Polygon(array, color)<br />
:: Draws a polygon described by array, filled with 'color'. The elements of 'array' must have x and y properties.<br />
<br />
* FilledCircle(x, y, rad, color)<br />
:: Draws a circle of radius 'rad' centered at 'x', 'y', filled with 'color'. Negative radii are treated as absolute values.<br />
<br />
* OutlinedCircle(x, y, rad, color)<br />
:: Draws an outline of a circle of radius 'rad' centered at 'x', 'y', with 'color'. Negative radii are treated as absolute values.<br />
<br />
*GradientCircle(x, y, rad, color1, color2)<br />
:: Draws a circle of radius 'rad' centered at 'x', 'y'. The color is faded from 'color1' at the center of the circle to 'color2' at the edges. Negative radii are treated as absolute values.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
* font.drawZoomedText(x, y, str, f)<br />
:: Draws 'str' using 'font' at 'x', 'y', zoomed by factor 'f'.<br />
<br />
* font.drawTextBox(x, y, w, h, y_offset, str)<br />
:: Draws 'str' using 'font' inside the box described by 'x', 'y', 'w', 'h', and offset vertically by 'y_offset'.<br />
<br />
* font.wordWrapString(str)<br />
:: Returns an array of strings, breaking up 'str' as though font.drawTextBox was called, and each element of the array is a line of text to be drawn.<br />
<br />
* font.getStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* font.getHeight()<br />
:: Returns the max height of the fonts characters.<br />
<br />
* font.setColorMask(color)<br />
:: Sets the mask of 'font'.<br />
<br />
* font.getColorMask()<br />
:: Returns the color mask of 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
* ttffont.drawZoomedText(x, y, f, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y', zoomed by factor of 'f'. A factor of 1.0 is normal sized.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
* DoesFileExist(filename)<br />
:: Checks if 'filename' exists.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'savefile1.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
==ByteArray Object==<br />
<br />
* ByteArray(size)<br />
:: Returns a [[API:ByteArray|ByteArray]] object of size 'size'. The ByteArray contains all zeros by defualt.<br />
::; Example:<br />
<syntaxhighlight><br />
var rawfile1 = new RawFile("save.raw");<br />
</syntaxhighlight><br />
<br />
* bytearray.concat([[API:ByteArray|bytes]])<br />
::Appends 'bytes' to the end of 'bytearray'.<br />
<br />
* bytearray.slice(start [, end])<br />
:: Returns a slice of the bytearray starting at 'start', and ending at 'end' or the end of the bytearray if end is omitted. If 'end' is a negative number, the end point is started from the end of the bytearray.<br />
<br />
===ByteArray Conversion===<br />
<br />
* CreateByteArrayFromString(str)<br />
::Returns a new [[API:ByteArray|ByteArray]] object from 'str'.<br />
<br />
* CreateStringFromByteArray([[API:ByteArray|bytes]])<br />
::Returns string from [[API:ByteArray|bytes]].<br />
<br />
==RawFile Object==<br />
<br />
* RawFile(filename)<br />
:: Returns a rawfile object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var rawfile1 = new RawFile("save.raw");<br />
</syntaxhighlight><br />
<br />
* rawfile.read(num)<br />
::Reads 'num' bytes from 'rawfile' as a [[API:ByteArray|ByteArray]].<br />
<br />
* rawfile.write([[API:ByteArray|bytes]])<br />
::Writes 'bytes' to 'rawfile'.<br />
<br />
* rawfile.close()<br />
::Closes 'rawfile'.<br />
<br />
* rawfile.getPosition()<br />
::Returns the current reading position of 'rawfile'.<br />
<br />
* rawfile.setPosition(pos)<br />
::Sets the current reading position of 'rawfile' to 'pos'.<br />
<br />
* rawfile.getSize()<br />
::Returns the size of 'rawfile'.<br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.<br />
<br />
=AudioBass=<br />
<br />
===Sound Object===<br />
<br />
* Sound(filename)<br />
::Creates a [[API:Sound|sound object]] from the file 'filename'. In 0.3.0 and later, all sounds are streamed by default.<br />
<br />
* sound.play([loop])<br />
::Plays the sound. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:Sound.stop|stop()]] is called. If the sound is already playing, it is restarted from the beginning.<br />
<br />
* sound.stop()<br />
::Stops playing a sound. The sound will be started from the beginning next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.pause()<br />
::Stops playing a sound. Playback will resume from the pausing point next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.getLength()<br />
::Returns the length of 'sound' in milliseconds.<br />
<br />
* sound.isPlaying()<br />
::Checks if the sound is currently playing.<br />
<br />
* sound.setVolume(vol)<br />
::Sets the volume of 'sound' to 'vol'. 'vol' must be a number between 0 (mute) and 255 (full volume).<br />
<br />
* sound.getVolume()<br />
::Returns the current volume of 'sound'.<br />
<br />
===SoundEffect Object===<br />
<br />
* SoundEffect(filename)<br />
::Creates a [[API:SoundEffect|soundeffect object]] from the file 'filename'.<br />
<br />
* soundeffect.play([loop])<br />
::Plays the soundeffect. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:SoundEffect.stop|stop()]] is called. A soundeffect may be played as many times simultaneously as desired.<br />
<br />
* soundeffect.stop()<br />
::Stops playing all instances of 'soundeffect'.<br />
<br />
* soundeffect.getLength()<br />
::Returns the length of 'soundeffect' in milliseconds.<br />
<br />
* soundeffect.isPlaying()<br />
::Checks if the soundeffect is currently playing.<br />
<br />
* soundeffect.setVolume(vol)<br />
::Sets the volume of 'soundeffect' to 'vol'. 'vol' must be a number between 0 (mute) and 255 (full volume). Affects all instances of 'soundeffect', including ones currently playing.<br />
<br />
* soundeffect.getVolume()<br />
::Returns the current volume of 'soundeffect'.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/SpriteBatch_API&diff=1058User:Flying Jester/SpriteBatch API2013-11-25T03:50:54Z<p>Flying Jester: Created page with "This page is draft of the SpriteBatch API for TurboSphere. ==Variables== *POINT *LINE *TRIANGLE *RECTANGLE *POLYGON *CIRCLE *FILLED *OUTLINED *GRADIENT *OUTLINED_GRADIENT *B..."</p>
<hr />
<div>This page is draft of the SpriteBatch API for TurboSphere.<br />
<br />
==Variables==<br />
<br />
*POINT<br />
*LINE<br />
*TRIANGLE<br />
*RECTANGLE<br />
*POLYGON<br />
*CIRCLE<br />
*FILLED<br />
*OUTLINED<br />
*GRADIENT<br />
*OUTLINED_GRADIENT<br />
*BLIT<br />
*ROTATE_BLIT<br />
*ZOOM_BLIT<br />
*STRETCH_BLIT<br />
*TRANSFORM_BLIT<br />
<br />
==Objects==<br />
<br />
* SpriteBatch()<br />
; Creates a new SpriteBatch object.<br />
<br />
* spritebatch.addTexture(tex)<br />
; Clones 'tex' into one of the spritebatch's buffers. 'tex' can be a Surface or Image. Any modifications to 'tex' after being cloned are not reflected by the copy in 'spritebatch'.<br />
<br />
* spritebatch.addOperation(primitive, type, ...)<br />
; Adds an operation to 'spritebatch'. Primitives can be<br />
<br />
*# POINT<br />
*# LINE<br />
*# TRIANGLE<br />
*# RECTANGLE<br />
*# POLYGON<br />
*# CIRCLE<br />
<br />
;Types can be<br />
<br />
*# FILLED<br />
*# OUTLINED<br />
*# GRADIENT<br />
*# OUTLINED_GRADIENT<br />
<br />
;Function signatures are:<br />
<br />
*#* spritebatch.addOperation(POINT, type, x, y, [[API:Color|color]] ...)<br />
*#* spritebatch.addOperation(LINE, type, x1, y1, x2, y2, [[API:Color|color]] ...)<br />
*#* spritebatch.addOperation(TRIANGLE, type, x1, y1, x2, y2, x3, y3, [[API:Color|color]] ...)<br />
*#* spritebatch.addOperation(RECTANGLE, type, x, y, w, h [[API:Color|color]] ...)<br />
*#* spritebatch.addOperation(POLYGON, type, xs, ys, [[API:Color|color]] ...)<br />
*#* spritebatch.addOperation(CIRCLE, type, x, y, r, [[API:Color|color]] ...)<br />
<br />
;'color' is defined by 'type'.<br />
<br />
*#* FILLED or OUTLINED: one color.<br />
*#* GRADIENT or OUTLINED_GRADIENT: one color argument for each vertex.<br />
<br />
* spritebatch.getImages()<br />
; Returns an array of added [[API:Image|images]] or surfaces (which are converted to images by adding them to the spritebatch) held in the buffer(s) of 'spritebatch'. These can be blit to the screen.<br />
<br />
* spritebatch.getOperations()<br />
; Returns an array of added drawing operations.<br />
<br />
* spritebatch.pushTexture(tex, mode, ..., [', [[API:Color|mask]]'])<br />
; Pushes a texture drawing operation for 'spritebatch' to perform when it draws. 'tex' is the index of the texture to draw. 'mode' can be:<br />
<br />
*# BLIT<br />
*# ROTATE_BLIT<br />
*# ZOOM_BLIT<br />
*# STRETCH_BLIT<br />
*# TRANSFORM_BLIT<br />
<br />
;Function signatures are:<br />
<br />
*#* spritebatch.pushTexture(tex, BLIT, x, y, [', [[API:Color|mask]]'])<br />
*#* spritebatch.pushTexture(tex, ROTATE_BLIT, x, y, a [', [[API:Color|mask]]'])<br />
*#* spritebatch.pushTexture(tex, ZOOM_BLIT, x, y, f [', [[API:Color|mask]]'])<br />
*#* spritebatch.pushTexture(tex, STRETCH_BLIT, x, y, xf, yf [', [[API:Color|mask]]'])<br />
*#* spritebatch.pushTexture(tex, TRANSFORM_BLIT, x1, y1, x2, y2, x3, y3, x4, y4 [', [[API:Color|mask]]'])</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester&diff=1057User:Flying Jester2013-11-20T20:42:42Z<p>Flying Jester: </p>
<hr />
<div>I am the Flying Jester. Of this, we can be sure. I've used Sphere since fall 2009, and have been making [[TurboSphere]] since late 2011.<br />
<br />
==TurboSphere==<br />
<br />
===Downloads===<br />
<br />
====Source====<br />
<br />
;[https://github.com/FlyingJester/TurboSphere github page]<br />
<br />
====Binaries====<br />
<br />
;[http://sourceforge.net/projects/turbosphere SourceForge page]<br />
;[http://flyingjesterentertainment.webs.com/TurboSphere.htm FJE Site]<br />
<br />
===Resources===<br />
<br />
;[[User:Flying Jester/TurboSphere API | TurboSphere API]]<br />
;[[User:Flying Jester/Making Plugins | Plugin Tutorial]]<br />
;[[User:Flying Jester/TurboSphere Plugin Roadmap | Plugin Manifest]]<br />
<br />
==Games==<br />
<br />
;[[Juggler]]<br />
;[[Juggler 2]]<br />
;[[Attack!]]<br />
<br />
==Frameworks==<br />
<br />
;[[Majestic Map Engine]]</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=1056User:Flying Jester/TurboSphere API2013-11-20T00:51:49Z<p>Flying Jester: </p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.5a. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
Note that while functions and objects are linked to by this page, all pages prefixed with 'API' refer to the Sphere versions of the objects and functions. The descriptions and examples for Sphere functions and objects are generally analogous to the TurboSphere versions, but not exactly the same.<br />
<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* EvaluateScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it if it has not been required previously.<br />
<br />
* RequireSystemScript(filename)<br />
:: Requires a script in the system/script directory.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
* Exit()<br />
:: Unconditionally exits the engine.<br />
<br />
* Abort(message)<br />
:: Aborts execution and displays 'message'.<br />
<br />
* GarbageCollect()<br />
:: Attempts to trigger garbage collection of the JS environment. This function is primarily kept for compatibility. Garbage collection may or may not actually take place when it is called.<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
* SetClippingRectangle(x, y, w, h)<br />
:: Sets the clipping rectangle on the screen.<br />
<br />
* GetClippingRectangle()<br />
:: Returns an object with the properties x, y, w, h, that describes the current clipping rectangle of the screen.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported formats are BMP and TGA (with RLE compression). Some versions (particularly on Unix-like platforms) support saving to PNG.<br />
<br />
* GrabImage(x, y, w, h)<br />
::Returns a new image object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface(...)<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]]. If you plan on blitting a surface more than once, consider converting it to an image with surface.createImage().<br />
<br />
* surface.setAlpha(a)<br />
::Sets the alpha of the surface to 'a'.<br />
<br />
* surface.blitSurface(surface_object, x, y)<br />
:: Blits surface_object onto surface at x, y.<br />
<br />
* surface.cloneSection(x, y, w, h)<br />
:: Returns a surface object that contains the section of surface at x, y, and is w by h.<br />
<br />
* surface.setClippingRectangle(x, y, w, h)<br />
::Sets the clipping rectangle of the surface. Anything drawing operations that are outside the clipping rectangle are ignored.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface = new Surface(16, 16, new Color(255, 0, 0, 255)); //Create a red surface.<br />
<br />
surface.rectangle(0, 0, 16, 8, new Color(0, 0, 255, 255)); //Make the top half of the surface blue.<br />
<br />
surface.setClippingRectangle(8, 0, 8, 16); //Set the clipping rectangle of the surface to be the right half.<br />
<br />
surface.rectangle(0, 0, 16, 16, new Color(0, 255, 0, 255)); //Try and fill the rectangle with green. Only the right half will be changed!<br />
</syntaxhighlight><br />
<br />
::; The clipping rectangle can be reset as so:<br />
<syntaxhighlight><br />
surface.setCLippingRectangle(0, 0, surface.width, surface.height); //Set the clipping rectangle to be from 0, 0, to the edges.<br />
</syntaxhighlight><br />
<br />
* surface.getClippingRectangle()<br />
::Returns a JS object that represents the surface's clipping rectangle, with properties 'x', 'y', 'w', and 'h'.<br />
<br />
* surface.save(filename)<br />
::Saves 'surface' to 'filename' in the images directory. Extensions are not automatically appended to 'filename', the filename will be exactly as specified. Currently the only supported formats are BMP and TGA (with RLE compression). Some versions (particularly on Unix-like platforms) support saving to PNG.<br />
<br />
* GrabSurface(x, y, w, h)<br />
::Returns a new surface object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* surface.createImage()<br />
::Returns a new [[API:Image|image]] that has the same pixel properties as 'surface'. Use of this call should be limited so as to not waste processing time and graphics RAM.<br />
<br />
====Surface Pixel Access====<br />
<br />
* surface.setPixel(x, y, [[API:Color|color]])<br />
::Sets the pixel of 'surface' at 'x', 'y', to 'color'. No blending is performed.<br />
<br />
* surface.getPixel(x, y)<br />
::Returns the [[API:Color|color]] of the pixel at 'x', 'y', on 'surface'.<br />
<br />
====Surface Primitives====<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]])<br />
::Draws an outline of a circle on 'surface' of radius 'r', centered on 'x', 'y', of 'color'<br />
<br />
* surface.filledCircle(x, y, r, , [[API:Color|color]])<br />
::Draws a filled circle of 'color' on 'surface', centered on 'x', 'y', with a radius of 'r'.<br />
<br />
* surface.gradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h' on 'surface'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
====Surface Properties====<br />
<br />
* surface.width<br />
::Value contains the width of the surface.<br />
<br />
* surface.height<br />
::Value contains the height of the surface.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* GradientLine(x1, y1, x2, y2, [[API:Color|color1]], [[API:Color|color2]])<br />
:: Draws a line of from x1, y1, to x2, y2 fading between 'color1' and 'color2'.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* OutlinedRectangle(x, y, w, h, [[API:Color|color]] [, thickness])<br />
:: Draws an outline of a rectangle of 'color' width w and height h at x, y. The edges are drawn of 'thickness'. If thickness is not provided, it is one pixel.<br />
<br />
* Triangle(x1, y1, x2, y2, x3, y3, , [[API:Color|color]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', filled with 'color'.<br />
<br />
* GradientTriangle(x1, y1, x2, y2, x3, y3, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', fading between the colors.<br />
<br />
* Polygon(array, color)<br />
:: Draws a polygon described by array, filled with 'color'. The elements of 'array' must have x and y properties.<br />
<br />
* FilledCircle(x, y, rad, color)<br />
:: Draws a circle of radius 'rad' centered at 'x', 'y', filled with 'color'. Negative radii are treated as absolute values.<br />
<br />
* OutlinedCircle(x, y, rad, color)<br />
:: Draws an outline of a circle of radius 'rad' centered at 'x', 'y', with 'color'. Negative radii are treated as absolute values.<br />
<br />
*GradientCircle(x, y, rad, color1, color2)<br />
:: Draws a circle of radius 'rad' centered at 'x', 'y'. The color is faded from 'color1' at the center of the circle to 'color2' at the edges. Negative radii are treated as absolute values.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
* font.drawZoomedText(x, y, str, f)<br />
:: Draws 'str' using 'font' at 'x', 'y', zoomed by factor 'f'.<br />
<br />
* font.drawTextBox(x, y, w, h, y_offset, str)<br />
:: Draws 'str' using 'font' inside the box described by 'x', 'y', 'w', 'h', and offset vertically by 'y_offset'.<br />
<br />
* font.wordWrapString(str)<br />
:: Returns an array of strings, breaking up 'str' as though font.drawTextBox was called, and each element of the array is a line of text to be drawn.<br />
<br />
* font.getStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* font.getHeight()<br />
:: Returns the max height of the fonts characters.<br />
<br />
* font.setColorMask(color)<br />
:: Sets the mask of 'font'.<br />
<br />
* font.getColorMask()<br />
:: Returns the color mask of 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
* ttffont.drawZoomedText(x, y, f, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y', zoomed by factor of 'f'. A factor of 1.0 is normal sized.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
* DoesFileExist(filename)<br />
:: Checks if 'filename' exists.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'savefile1.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
==ByteArray Object==<br />
<br />
* ByteArray(size)<br />
:: Returns a [[API:ByteArray|ByteArray]] object of size 'size'. The ByteArray contains all zeros by defualt.<br />
::; Example:<br />
<syntaxhighlight><br />
var rawfile1 = new RawFile("save.raw");<br />
</syntaxhighlight><br />
<br />
* bytearray.concat([[API:ByteArray|bytes]])<br />
::Appends 'bytes' to the end of 'bytearray'.<br />
<br />
* bytearray.slice(start [, end])<br />
:: Returns a slice of the bytearray starting at 'start', and ending at 'end' or the end of the bytearray if end is omitted. If 'end' is a negative number, the end point is started from the end of the bytearray.<br />
<br />
===ByteArray Conversion===<br />
<br />
* CreateByteArrayFromString(str)<br />
::Returns a new [[API:ByteArray|ByteArray]] object from 'str'.<br />
<br />
* CreateStringFromByteArray([[API:ByteArray|bytes]])<br />
::Returns string from [[API:ByteArray|bytes]].<br />
<br />
==RawFile Object==<br />
<br />
* RawFile(filename)<br />
:: Returns a rawfile object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var rawfile1 = new RawFile("save.raw");<br />
</syntaxhighlight><br />
<br />
* rawfile.read(num)<br />
::Reads 'num' bytes from 'rawfile' as a [[API:ByteArray|ByteArray]].<br />
<br />
* rawfile.write([[API:ByteArray|bytes]])<br />
::Writes 'bytes' to 'rawfile'.<br />
<br />
* rawfile.close()<br />
::Closes 'rawfile'.<br />
<br />
* rawfile.getPosition()<br />
::Returns the current reading position of 'rawfile'.<br />
<br />
* rawfile.setPosition(pos)<br />
::Sets the current reading position of 'rawfile' to 'pos'.<br />
<br />
* rawfile.getSize()<br />
::Returns the size of 'rawfile'.<br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.<br />
<br />
=AudioBass=<br />
<br />
===Sound Object===<br />
<br />
* Sound(filename)<br />
::Creates a [[API:Sound|sound object]] from the file 'filename'. In 0.3.0 and later, all sounds are streamed by default.<br />
<br />
* sound.play([loop])<br />
::Plays the sound. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:Sound.stop|stop()]] is called. If the sound is already playing, it is restarted from the beginning.<br />
<br />
* sound.stop()<br />
::Stops playing a sound. The sound will be started from the beginning next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.pause()<br />
::Stops playing a sound. Playback will resume from the pausing point next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.getLength()<br />
::Returns the length of 'sound' in milliseconds.<br />
<br />
* sound.isPlaying()<br />
::Checks if the sound is currently playing.<br />
<br />
* sound.setVolume(vol)<br />
::Sets the volume of 'sound' to 'vol'. 'vol' must be a number between 0 (mute) and 255 (full volume).<br />
<br />
* sound.getVolume()<br />
::Returns the current volume of 'sound'.<br />
<br />
===SoundEffect Object===<br />
<br />
* SoundEffect(filename)<br />
::Creates a [[API:SoundEffect|soundeffect object]] from the file 'filename'.<br />
<br />
* soundeffect.play([loop])<br />
::Plays the soundeffect. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:SoundEffect.stop|stop()]] is called. A soundeffect may be played as many times simultaneously as desired.<br />
<br />
* soundeffect.stop()<br />
::Stops playing all instances of 'soundeffect'.<br />
<br />
* soundeffect.getLength()<br />
::Returns the length of 'soundeffect' in milliseconds.<br />
<br />
* soundeffect.isPlaying()<br />
::Checks if the soundeffect is currently playing.<br />
<br />
* soundeffect.setVolume(vol)<br />
::Sets the volume of 'soundeffect' to 'vol'. 'vol' must be a number between 0 (mute) and 255 (full volume). Affects all instances of 'soundeffect', including ones currently playing.<br />
<br />
* soundeffect.getVolume()<br />
::Returns the current volume of 'soundeffect'.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester&diff=1055User:Flying Jester2013-11-20T00:28:08Z<p>Flying Jester: </p>
<hr />
<div>I am the Flying Jester. Of this, we can be sure. I've used Sphere since fall 2009, and have been making [[TurboSphere]] since late 2011.<br />
<br />
==TurboSphere==<br />
<br />
===Downloads===<br />
<br />
====Source====<br />
<br />
;[https://github.com/FlyingJester/TurboSphere github page]<br />
<br />
====Binaries====<br />
<br />
;[http://sourceforge.net/projects/turbosphere SourceForge page]<br />
;[http://flyingjesterentertainment.webs.com/TurboSphere FJE Site]<br />
<br />
===Resources===<br />
<br />
;[[User:Flying Jester/TurboSphere API]]<br />
;[[User:Flying Jester/Making Plugins]]<br />
;[[User:Flying Jester/TurboSphere Plugin Roadmap]]<br />
<br />
==Games==<br />
<br />
;[[Juggler]]<br />
;[[Juggler 2]]<br />
;[[Attack!]]<br />
<br />
==Frameworks==<br />
<br />
;[[Majestic Map Engine]]</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=1054User:Flying Jester/TurboSphere API2013-11-20T00:25:57Z<p>Flying Jester: /* BMPFontSDL */</p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.5a. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
Note that while functions and objects are linked to by this page, all pages prefixed with 'API' refer to the Sphere versions of the objects and functions. The descriptions and examples for Sphere functions and objects are generally analogous to the TurboSphere versions, but not exactly the same.<br />
<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* EvaluateScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it if it has not been required previously.<br />
<br />
* RequireSystemScript(filename)<br />
:: Requires a script in the system/script directory.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
* Exit()<br />
:: Unconditionally exits the engine.<br />
<br />
* Abort(message)<br />
:: Aborts execution and displays 'message'.<br />
<br />
* GarbageCollect()<br />
:: Attempts to trigger garbage collection of the JS environment. This function is primarily kept for compatibility. Garbage collection may or may not actually take place when it is called.<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
* SetClippingRectangle(x, y, w, h)<br />
:: Sets the clipping rectangle on the screen.<br />
<br />
* GetClippingRectangle()<br />
:: Returns an object with the properties x, y, w, h, that describes the current clipping rectangle of the screen.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported formats are BMP and TGA (with RLE compression). Some versions (particularly on Unix-like platforms) support saving to PNG.<br />
<br />
* GrabImage(x, y, w, h)<br />
::Returns a new image object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface(...)<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]]. If you plan on blitting a surface more than once, consider converting it to an image with surface.createImage().<br />
<br />
* surface.setAlpha(a)<br />
::Sets the alpha of the surface to 'a'.<br />
<br />
* surface.blitSurface(surface_object, x, y)<br />
:: Blits surface_object onto surface at x, y.<br />
<br />
* surface.cloneSection(x, y, w, h)<br />
:: Returns a surface object that contains the section of surface at x, y, and is w by h.<br />
<br />
* surface.setClippingRectangle(x, y, w, h)<br />
::Sets the clipping rectangle of the surface. Anything drawing operations that are outside the clipping rectangle are ignored.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface = new Surface(16, 16, new Color(255, 0, 0, 255)); //Create a red surface.<br />
<br />
surface.rectangle(0, 0, 16, 8, new Color(0, 0, 255, 255)); //Make the top half of the surface blue.<br />
<br />
surface.setClippingRectangle(8, 0, 8, 16); //Set the clipping rectangle of the surface to be the right half.<br />
<br />
surface.rectangle(0, 0, 16, 16, new Color(0, 255, 0, 255)); //Try and fill the rectangle with green. Only the right half will be changed!<br />
</syntaxhighlight><br />
<br />
::; The clipping rectangle can be reset as so:<br />
<syntaxhighlight><br />
surface.setCLippingRectangle(0, 0, surface.width, surface.height); //Set the clipping rectangle to be from 0, 0, to the edges.<br />
</syntaxhighlight><br />
<br />
* surface.getClippingRectangle()<br />
::Returns a JS object that represents the surface's clipping rectangle, with properties 'x', 'y', 'w', and 'h'.<br />
<br />
* surface.save(filename)<br />
::Saves 'surface' to 'filename' in the images directory. Extensions are not automatically appended to 'filename', the filename will be exactly as specified. Currently the only supported formats are BMP and TGA (with RLE compression). Some versions (particularly on Unix-like platforms) support saving to PNG.<br />
<br />
* GrabSurface(x, y, w, h)<br />
::Returns a new surface object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* surface.createImage()<br />
::Returns a new [[API:Image|image]] that has the same pixel properties as 'surface'. Use of this call should be limited so as to not waste processing time and graphics RAM.<br />
<br />
====Surface Pixel Access====<br />
<br />
* surface.setPixel(x, y, [[API:Color|color]])<br />
::Sets the pixel of 'surface' at 'x', 'y', to 'color'. No blending is performed.<br />
<br />
* surface.getPixel(x, y)<br />
::Returns the [[API:Color|color]] of the pixel at 'x', 'y', on 'surface'.<br />
<br />
====Surface Primitives====<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]])<br />
::Draws an outline of a circle on 'surface' of radius 'r', centered on 'x', 'y', of 'color'<br />
<br />
* surface.filledCircle(x, y, r, , [[API:Color|color]])<br />
::Draws a filled circle of 'color' on 'surface', centered on 'x', 'y', with a radius of 'r'.<br />
<br />
* surface.gradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h' on 'surface'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
====Surface Properties====<br />
<br />
* surface.width<br />
::Value contains the width of the surface.<br />
<br />
* surface.height<br />
::Value contains the height of the surface.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* GradientLine(x1, y1, x2, y2, [[API:Color|color1]], [[API:Color|color2]])<br />
:: Draws a line of from x1, y1, to x2, y2 fading between 'color1' and 'color2'.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* OutlinedRectangle(x, y, w, h, [[API:Color|color]] [, thickness])<br />
:: Draws an outline of a rectangle of 'color' width w and height h at x, y. The edges are drawn of 'thickness'. If thickness is not provided, it is one pixel.<br />
<br />
* Triangle(x1, y1, x2, y2, x3, y3, , [[API:Color|color]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', filled with 'color'.<br />
<br />
* GradientTriangle(x1, y1, x2, y2, x3, y3, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', fading between the colors.<br />
<br />
* Polygon(array, color)<br />
:: Draws a polygon described by array, filled with 'color'. The elements of 'array' must have x and y properties.<br />
<br />
* FilledCircle(x, y, rad, color)<br />
:: Draws a circle of radius 'rad' centered at 'x', 'y', filled with 'color'. Negative radii are treated as absolute values.<br />
<br />
* OutlinedCircle(x, y, rad, color)<br />
:: Draws an outline of a circle of radius 'rad' centered at 'x', 'y', with 'color'. Negative radii are treated as absolute values.<br />
<br />
*GradientCircle(x, y, rad, color1, color2)<br />
:: Draws a circle of radius 'rad' centered at 'x', 'y'. The color is faded from 'color1' at the center of the circle to 'color2' at the edges. Negative radii are treated as absolute values.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
* font.drawZoomedText(x, y, str, f)<br />
:: Draws 'str' using 'font' at 'x', 'y', zoomed by factor 'f'.<br />
<br />
* font.drawTextBox(x, y, w, h, y_offset, str)<br />
:: Draws 'str' using 'font' inside the box described by 'x', 'y', 'w', 'h', and offset vertically by 'y_offset'.<br />
<br />
* font.wordWrapString(str)<br />
:: Returns an array of strings, breaking up 'str' as though font.drawTextBox was called, and each element of the array is a line of text to be drawn.<br />
<br />
* font.getStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* font.getHeight()<br />
:: Returns the max height of the fonts characters.<br />
<br />
* font.setColorMask(color)<br />
:: Sets the mask of 'font'.<br />
<br />
* font.getColorMask()<br />
:: Returns the color mask of 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==JoyStick==<br />
<br />
===JoyStick Functions===<br />
* GetNumJoysticks()<br />
::Returns the number of usable joysticks connected to the computer.<br />
<br />
* GetJoystickName(jsnum)<br />
::Returns the name of joystick number 'jsnum'.<br />
<br />
* GetNumJoystickButtons(jsnum)<br />
::Returns the number of buttons on joystick number 'jsnum'.<br />
<br />
* GetNumJoystickAxes(jsnum)<br />
::Returns the number of axes on joystick number 'jsnum'.<br />
<br />
* IsJoystickButtonPressed(jsnum, button)<br />
::Checks whether or not button number 'button' is pressed on joystick number 'jsnum'.<br />
<br />
* GetJoystickAxis(jsnum, axis)<br />
::Returns the value for axis number 'axis' on joystick number 'jsnum'.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'savefile1.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.<br />
<br />
=AudioBass=<br />
<br />
===Sound Object===<br />
<br />
* Sound(filename)<br />
::Creates a [[API:Sound|sound object]] from the file 'filename'. In 0.3.0 and later, all sounds are streamed by default.<br />
<br />
* sound.play([loop])<br />
::Plays the sound. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:Sound.stop|stop()]] is called. If the sound is already playing, it is restarted from the beginning.<br />
<br />
* sound.stop()<br />
::Stops playing a sound. The sound will be started from the beginning next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.pause()<br />
::Stops playing a sound. Playback will resume from the pausing point next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.getLength()<br />
::Returns the length of 'sound' in milliseconds.<br />
<br />
* sound.isPlaying()<br />
::Checks if the sound is currently playing.<br />
<br />
* sound.setVolume(vol)<br />
::Sets the volume of 'sound' to 'vol'. 'vol' must be a number between 0 (mute) and 255 (full volume).<br />
<br />
* sound.getVolume()<br />
::Returns the current volume of 'sound'.<br />
<br />
===SoundEffect Object===<br />
<br />
* SoundEffect(filename)<br />
::Creates a [[API:SoundEffect|soundeffect object]] from the file 'filename'.<br />
<br />
* soundeffect.play([loop])<br />
::Plays the soundeffect. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:SoundEffect.stop|stop()]] is called. A soundeffect may be played as many times simultaneously as desired.<br />
<br />
* soundeffect.stop()<br />
::Stops playing all instances of 'soundeffect'.<br />
<br />
* soundeffect.getLength()<br />
::Returns the length of 'soundeffect' in milliseconds.<br />
<br />
* soundeffect.isPlaying()<br />
::Checks if the soundeffect is currently playing.<br />
<br />
* soundeffect.setVolume(vol)<br />
::Sets the volume of 'soundeffect' to 'vol'. 'vol' must be a number between 0 (mute) and 255 (full volume). Affects all instances of 'soundeffect', including ones currently playing.<br />
<br />
* soundeffect.getVolume()<br />
::Returns the current volume of 'soundeffect'.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=1053User:Flying Jester/TurboSphere API2013-11-20T00:19:39Z<p>Flying Jester: </p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.5a. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
Note that while functions and objects are linked to by this page, all pages prefixed with 'API' refer to the Sphere versions of the objects and functions. The descriptions and examples for Sphere functions and objects are generally analogous to the TurboSphere versions, but not exactly the same.<br />
<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* EvaluateScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it if it has not been required previously.<br />
<br />
* RequireSystemScript(filename)<br />
:: Requires a script in the system/script directory.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
* Exit()<br />
:: Unconditionally exits the engine.<br />
<br />
* Abort(message)<br />
:: Aborts execution and displays 'message'.<br />
<br />
* GarbageCollect()<br />
:: Attempts to trigger garbage collection of the JS environment. This function is primarily kept for compatibility. Garbage collection may or may not actually take place when it is called.<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
* SetClippingRectangle(x, y, w, h)<br />
:: Sets the clipping rectangle on the screen.<br />
<br />
* GetClippingRectangle()<br />
:: Returns an object with the properties x, y, w, h, that describes the current clipping rectangle of the screen.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported formats are BMP and TGA (with RLE compression). Some versions (particularly on Unix-like platforms) support saving to PNG.<br />
<br />
* GrabImage(x, y, w, h)<br />
::Returns a new image object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface(...)<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]]. If you plan on blitting a surface more than once, consider converting it to an image with surface.createImage().<br />
<br />
* surface.setAlpha(a)<br />
::Sets the alpha of the surface to 'a'.<br />
<br />
* surface.blitSurface(surface_object, x, y)<br />
:: Blits surface_object onto surface at x, y.<br />
<br />
* surface.cloneSection(x, y, w, h)<br />
:: Returns a surface object that contains the section of surface at x, y, and is w by h.<br />
<br />
* surface.setClippingRectangle(x, y, w, h)<br />
::Sets the clipping rectangle of the surface. Anything drawing operations that are outside the clipping rectangle are ignored.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface = new Surface(16, 16, new Color(255, 0, 0, 255)); //Create a red surface.<br />
<br />
surface.rectangle(0, 0, 16, 8, new Color(0, 0, 255, 255)); //Make the top half of the surface blue.<br />
<br />
surface.setClippingRectangle(8, 0, 8, 16); //Set the clipping rectangle of the surface to be the right half.<br />
<br />
surface.rectangle(0, 0, 16, 16, new Color(0, 255, 0, 255)); //Try and fill the rectangle with green. Only the right half will be changed!<br />
</syntaxhighlight><br />
<br />
::; The clipping rectangle can be reset as so:<br />
<syntaxhighlight><br />
surface.setCLippingRectangle(0, 0, surface.width, surface.height); //Set the clipping rectangle to be from 0, 0, to the edges.<br />
</syntaxhighlight><br />
<br />
* surface.getClippingRectangle()<br />
::Returns a JS object that represents the surface's clipping rectangle, with properties 'x', 'y', 'w', and 'h'.<br />
<br />
* surface.save(filename)<br />
::Saves 'surface' to 'filename' in the images directory. Extensions are not automatically appended to 'filename', the filename will be exactly as specified. Currently the only supported formats are BMP and TGA (with RLE compression). Some versions (particularly on Unix-like platforms) support saving to PNG.<br />
<br />
* GrabSurface(x, y, w, h)<br />
::Returns a new surface object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* surface.createImage()<br />
::Returns a new [[API:Image|image]] that has the same pixel properties as 'surface'. Use of this call should be limited so as to not waste processing time and graphics RAM.<br />
<br />
====Surface Pixel Access====<br />
<br />
* surface.setPixel(x, y, [[API:Color|color]])<br />
::Sets the pixel of 'surface' at 'x', 'y', to 'color'. No blending is performed.<br />
<br />
* surface.getPixel(x, y)<br />
::Returns the [[API:Color|color]] of the pixel at 'x', 'y', on 'surface'.<br />
<br />
====Surface Primitives====<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]])<br />
::Draws an outline of a circle on 'surface' of radius 'r', centered on 'x', 'y', of 'color'<br />
<br />
* surface.filledCircle(x, y, r, , [[API:Color|color]])<br />
::Draws a filled circle of 'color' on 'surface', centered on 'x', 'y', with a radius of 'r'.<br />
<br />
* surface.gradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h' on 'surface'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
====Surface Properties====<br />
<br />
* surface.width<br />
::Value contains the width of the surface.<br />
<br />
* surface.height<br />
::Value contains the height of the surface.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* GradientLine(x1, y1, x2, y2, [[API:Color|color1]], [[API:Color|color2]])<br />
:: Draws a line of from x1, y1, to x2, y2 fading between 'color1' and 'color2'.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* OutlinedRectangle(x, y, w, h, [[API:Color|color]] [, thickness])<br />
:: Draws an outline of a rectangle of 'color' width w and height h at x, y. The edges are drawn of 'thickness'. If thickness is not provided, it is one pixel.<br />
<br />
* Triangle(x1, y1, x2, y2, x3, y3, , [[API:Color|color]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', filled with 'color'.<br />
<br />
* GradientTriangle(x1, y1, x2, y2, x3, y3, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', fading between the colors.<br />
<br />
* Polygon(array, color)<br />
:: Draws a polygon described by array, filled with 'color'. The elements of 'array' must have x and y properties.<br />
<br />
* FilledCircle(x, y, rad, color)<br />
:: Draws a circle of radius 'rad' centered at 'x', 'y', filled with 'color'. Negative radii are treated as absolute values.<br />
<br />
* OutlinedCircle(x, y, rad, color)<br />
:: Draws an outline of a circle of radius 'rad' centered at 'x', 'y', with 'color'. Negative radii are treated as absolute values.<br />
<br />
*GradientCircle(x, y, rad, color1, color2)<br />
:: Draws a circle of radius 'rad' centered at 'x', 'y'. The color is faded from 'color1' at the center of the circle to 'color2' at the edges. Negative radii are treated as absolute values.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
* font.drawZoomedText(x, y, str, f)<br />
:: Draws 'str' using 'font' at 'x', 'y', zoomed by factor 'f'.<br />
<br />
* font.drawTextBox(x, y, w, h, y_offset, str)<br />
:: Draws 'str' using 'font' inside the box described by 'x', 'y', 'w', 'h', and offset vertically by 'y_offset'.<br />
<br />
* font.wordWrapString(str)<br />
:: Returns an array of strings, breaking up 'str' as though font.drawTextBox was called, and each element of the array is a line of text to be drawn.<br />
<br />
* font.getStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* font.setColorMask(color)<br />
:: Sets the mask of 'font'.<br />
<br />
* font.getColorMask()<br />
:: Returns the color mask of 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==JoyStick==<br />
<br />
===JoyStick Functions===<br />
* GetNumJoysticks()<br />
::Returns the number of usable joysticks connected to the computer.<br />
<br />
* GetJoystickName(jsnum)<br />
::Returns the name of joystick number 'jsnum'.<br />
<br />
* GetNumJoystickButtons(jsnum)<br />
::Returns the number of buttons on joystick number 'jsnum'.<br />
<br />
* GetNumJoystickAxes(jsnum)<br />
::Returns the number of axes on joystick number 'jsnum'.<br />
<br />
* IsJoystickButtonPressed(jsnum, button)<br />
::Checks whether or not button number 'button' is pressed on joystick number 'jsnum'.<br />
<br />
* GetJoystickAxis(jsnum, axis)<br />
::Returns the value for axis number 'axis' on joystick number 'jsnum'.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'savefile1.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.<br />
<br />
=AudioBass=<br />
<br />
===Sound Object===<br />
<br />
* Sound(filename)<br />
::Creates a [[API:Sound|sound object]] from the file 'filename'. In 0.3.0 and later, all sounds are streamed by default.<br />
<br />
* sound.play([loop])<br />
::Plays the sound. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:Sound.stop|stop()]] is called. If the sound is already playing, it is restarted from the beginning.<br />
<br />
* sound.stop()<br />
::Stops playing a sound. The sound will be started from the beginning next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.pause()<br />
::Stops playing a sound. Playback will resume from the pausing point next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.getLength()<br />
::Returns the length of 'sound' in milliseconds.<br />
<br />
* sound.isPlaying()<br />
::Checks if the sound is currently playing.<br />
<br />
* sound.setVolume(vol)<br />
::Sets the volume of 'sound' to 'vol'. 'vol' must be a number between 0 (mute) and 255 (full volume).<br />
<br />
* sound.getVolume()<br />
::Returns the current volume of 'sound'.<br />
<br />
===SoundEffect Object===<br />
<br />
* SoundEffect(filename)<br />
::Creates a [[API:SoundEffect|soundeffect object]] from the file 'filename'.<br />
<br />
* soundeffect.play([loop])<br />
::Plays the soundeffect. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:SoundEffect.stop|stop()]] is called. A soundeffect may be played as many times simultaneously as desired.<br />
<br />
* soundeffect.stop()<br />
::Stops playing all instances of 'soundeffect'.<br />
<br />
* soundeffect.getLength()<br />
::Returns the length of 'soundeffect' in milliseconds.<br />
<br />
* soundeffect.isPlaying()<br />
::Checks if the soundeffect is currently playing.<br />
<br />
* soundeffect.setVolume(vol)<br />
::Sets the volume of 'soundeffect' to 'vol'. 'vol' must be a number between 0 (mute) and 255 (full volume). Affects all instances of 'soundeffect', including ones currently playing.<br />
<br />
* soundeffect.getVolume()<br />
::Returns the current volume of 'soundeffect'.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Developing_a_Sphere-compatible_engine&diff=1051Developing a Sphere-compatible engine2013-10-31T00:14:10Z<p>Flying Jester: /* Complete or in-progress */</p>
<hr />
<div>{{aside|Notice|This [[:Category:Tutorials|tutorial article]] is incomplete, but it is also important. Do not edit it unless you've been given permission, thanks.|note.svg}}<br />
<br />
This article aims to provide a checklist and resources for developing a JavaScript-powered game engine that is compatible with [[API:Functions|Sphere's JavaScript API]].<br />
<br />
__TOC__<br />
<br />
==Introduction==<br />
Throughout this article, the original Sphere implementation shall be referred to as "vanilla" Sphere and consisted of use of an older version of [https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey] as the JavaScript engine, the first-party [http://corona.sf.net Corona library] for the software implementation of video, and the first-party [http://audiere.sf.net Audiere library] for the audio driver. Input was mapped directly in software using whatever API was native to the OS in the case of the Windows and Linux versions of vanilla Sphere. The recent Mac OS X port of vanilla Sphere used SDL to handle all input and output while still using an older version of SpiderMonkey for JavaScript.<br />
<br />
Possible frameworks to implement Sphere:<br />
* JavaScript<br />
** V8<br />
** SpiderMonkey v1.8.5<br />
** Jurassic / IronJS / JavaScript.Net / Jint<br />
* Game Libraries<br />
** SDL<br />
** SFML<br />
* Graphics libraries<br />
** OpenGL<br />
** pixi.js / three.js<br />
** DirectX (DirectDraw)<br />
** hand-rolled software renderer.<br />
* Audio libraries<br />
** Audiere<br />
** Libsndfile<br />
** BASS<br />
** Irrklang<br />
** FMod<br />
<br />
<br />
(TODO: more)<br />
<br />
==Input==<br />
<br />
===SDL===<br />
If you want to use SDL, it will be helpful to set up an event filter to catch application close events. Since the main function that needs proper access to events is GetKey, you can disable mouse movement, mouse button, and key-up events so that the event queue will be filled with just keydown events. This simplifies the implementation of the GetKey function, as it is the only function that needs the queue to contain a specific kind of event. Be sure to pump or poll for events whenever input is requested. This also keeps the engine responsive during calls to getkey, and tending the event queue keeps the engine responsive in general.<br />
<br />
Keyboard state polling (as in IsKeyPressed()) can be handled with getting the keystate and comparing keysyms.<br />
<br />
===SFML===<br />
If you are using SFML, you need to handle the key pressed and released events. It's a good idea to use a static array for all of the keys, mouse, and joystick buttons. The array's index corresponds with a key, mouse, and joystick code with a true/false value indicating IsPressed. In order to support more than one joystick you may need to bump up that joystick array to a 2D array, where 'x' is the joystick id and 'y' is the button code.<br />
<br />
For the key queue, just use a queue data structure. Enqueue keys on the released state, and dequeue keys with [[API:GetKey|GetKey]].<br />
<br />
===Other input libraries===<br />
(TODO: list possible input handling libraries and gotchas)<br />
<br />
===Handling keyboard input notes===<br />
[[API:GetKey|GetKey]]() must be able to block the sphere engine. If the key queue is empty, go into a loop that just updates the game screen.<br />
<br />
(TODO: fill)<br />
<br />
====Key Constant Mapping====<br />
In SDL, SFML, and other game libraries, key code enumerations offered in source may differ from Sphere's. In order to map keys correctly you might need to implement a very large map that is basically a "this key" = "that key" list. Such a technique is optional if you already follow Sphere's key naming conventions, but what this will do is allow other Sphere engines to use those same codes if you saved a game with key mappings from vanilla Sphere.<br />
<br />
See Sphere's [[list of keycode constants]] for the official list, also at https://github.com/sphere-group/sphere/blob/v1.6/sphere/docs/development/keys.txt<br />
<br />
===Handling mouse input notes===<br />
(TODO)<br />
<br />
===Handling joystick input notes===<br />
(TODO)<br />
<br />
===Other input methods===<br />
(TODO)<br />
<br />
==Output==<br />
===Video===<br />
<br />
Blitting is a process that draws the image or surface to a screen's render target prior to flipping. In web based engines this is best emulated with a "draw queue". You fill the queue with what to draw prior to a frame and update it when you are ready.<br />
<br />
(TODO: more)<br />
(TODO: multi-monitor?)<br />
(TODO: touch-screen?)<br />
<br />
===Audio===<br />
<br />
====SFML====<br />
Audio is split between sounds and music. They have the same API, but music streams intrinsically.<br />
Volume however takes a range of 0 to 100. Treat that as a percent of the 0 to 255 range Sphere uses. You might need to cache the volume into a private variable and get set from that, making sure to set the underlying volume as a percent of whatever you used.<br />
<br />
==Sphere-format file loading==<br />
Sphere uses five custom file formats, all containing bitmap data in some form or another: [[API:Font|bitmap fonts]], [[API:Spriteset|spritesets]], [[API:WindowStyle|stylized window frames]], [[API:Map|maps]], and [[API:Map|map tilesets]]. Some of them have metadata interspersed with the bitmap data, others have a dedicated block that contains all the metadata for the file in one section regardless of the bitmap data. Maps in particular have the option of choosing to embed its tileset within its file or to point to an external tileset file. All have fixed size headers that are trivial to read. All integer values are stored in [[wikipedia:endianness#Little-endian|Intel order/little-endian]] and unless otherwise noted all pixel values are 32-bit and stored in the order RGBA.<br />
<br />
===Fonts===<br />
Pretty straight forward. Version 1 Sphere fonts only allow 8-bit grayscale pixels and are deprecated in favor of version 2 fonts. Version 2 fonts use bitmaps containing full 32-bit RGBA pixels. There are reserved bytes to be aware of, otherwise no metadata.<br />
<br />
===Spritesets===<br />
Three separate versions with separate loading behaviors. Much more complicated than fonts, some reserved bytes, lots of metadata. (TODO: expand)<br />
<br />
===WindowStyles===<br />
Two versions to handle. Some reserved bytes, some deprecated properties depending on version, small amount of metadata. (TODO: expand)<br />
<br />
===Maps===<br />
Lots of metadata, small amount of reserved bytes, can embed tilesets or refer to external tileset files. (TODO: expand)<br />
<br />
===Tilesets===<br />
Lots of metadata, small amount of reserved bytes, bitmap data is in one large block after header but before metadata. (TODO: expand)<br />
<br />
==The map engine==<br />
(TODO)<br />
<br />
===The MapEngine loop===<br />
(TODO)<br />
<br />
==Maintaining API compatibility==<br />
Sphere's original JavaScript API was written with a procedural mentality. JavaScript is a language with a powerful prototype-based inheritance system, so you may want to change Sphere's native objects such as the [[API:Color|Color object]] to allow variable creation via the ''new'' syntax; if you do this natively you must either write the equivalent loading function (in this case, [[API:CreateColor|CreateColor]]) as native code or in a scripted shim. The [[system scripts|system script]] [[Script:system/oldsphere.js|oldsphere.js]] is an example of such a shim, existing to maintain compatibility with projects written for pre-1.0 versions of Sphere. If you'd rather leave the original procedural-style loading functions but add the ability to create native Sphere objects with a working prototype constructor, visit [http://forums.spheredev.org/index.php/topic,69.0.html this forum thread] for information on doing it in script.<br />
<br />
===Compatibility with 1.5===<br />
(TODO)<br />
<br />
===Compatibility with 1.6 beta===<br />
(TODO)<br />
<br />
===Compatibility with 1.7 alpha===<br />
(TODO)<br />
<br />
===Backwards-compatibility with pre-1.5===<br />
(TODO)<br />
<br />
==List of Sphere-compatible engine implementations==<br />
===Complete or in-progress===<br />
{| class="wikitable sortable" width="100%"<br />
|+Complete or in-progress Sphere-compatible engines<br />
|-<br />
! scope="col"| Implementation<br />
! scope="col"| Operating System<br />
! scope="col"| Version<br />
! scope="col"| JS engine<br />
! scope="col"| Video driver<br />
! scope="col"| Audio driver<br />
! scope="col"| Input handler<br />
|-<br />
|vanilla Sphere<br/>[https://github.com/sphere-group/sphere source], [http://forums.spheredev.org/index.php/topic,155.0.html thread]<br />
|Win x86, OSX, Linux x86<br />
|stable: 1.5<br/>unstable: 1.6 beta 4<br/>inactive: 1.7 alpha<br />
|[https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey]<br />
|configurable<br />
|configurable<br />
|configurable<br />
|-<br />
|TurboSphere<br/>[https://github.com/FlyingJester/TurboSphere source], [http://forums.spheredev.org/index.php/topic,13.0.html thread]<br />
|Win x86/64, OSX, Linux x86/64<br />
|0.3.5a<br />
|[https://code.google.com/p/v8/ V8]<br />
|OpenGL via SDL2<br />
|BASS<br />
|SDL2<br />
|-<br />
|unnamed Sphere clone in SDL<br/>[https://github.com/postcasio/sphereclone source], [http://forums.spheredev.org/index.php/topic,72.0.html thread]<br />
|?<br />
|?<br />
|[https://code.google.com/p/v8/ V8]<br />
|SDL<br />
|SDL<br />
|SDL<br />
|-<br />
|sphere-sfml<br/>[https://github.com/Radnen/sphere-sfml source], [http://forums.spheredev.org/index.php/topic,137.0.html thread]<br />
|Win x86, OSX(?)<br />
|0.65 alpha<br />
|[http://jurassic.codeplex.com/ Jurassic]<br />
|OpenGL via SFML 2<br />
|libsndfile via SFML 2<br />
|SFML 2<br />
|-<br />
|web-sphere<br/>[https://github.com/sphere-group/web-sphere source], [http://forums.spheredev.org/index.php/topic,154.0.html thread]<br />
|Chrome, Firefox, and IE9+<br />
|[http://www.pixijs.com/ pixi.js] version: ?<br/>[http://threejs.org/ three.js] version: ?<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|}<br />
<br />
{{aside|Info|Although some engines are listed as compatible they will need a shim script to maintain compatibility with Sphere's API. For example, [[API:LoadImage|LoadImage]] may indeed return the correct [[API:image|image]] format by using a different API such as <tt>return new Image()</tt>.|template-info.svg}}<br />
<br />
===Discontinued or abandoned===<br />
(TODO)<br />
<br />
==See also==<br />
(TODO)<br />
<br />
[[Category:Tutorials]]</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=1050User:Flying Jester/TurboSphere API2013-10-27T23:26:29Z<p>Flying Jester: </p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.5a. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
Note that while functions and objects are linked to by this page, all pages prefixed with 'API' refer to the Sphere versions of the objects and functions. The descriptions and examples for Sphere functions and objects are generally analogous to the TurboSphere versions, but not exactly the same.<br />
<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* EvaluateScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it if it has not been required previously.<br />
<br />
* RequireSystemScript(filename)<br />
:: Requires a script in the system/script directory.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
* Exit()<br />
:: Unconditionally exits the engine.<br />
<br />
* Abort(message)<br />
:: Aborts execution and displays 'message'.<br />
<br />
* GarbageCollect()<br />
:: Attempts to trigger garbage collection of the JS environment. This function is primarily kept for compatibility. Garbage collection may or may not actually take place when it is called.<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
* SetClippingRectangle(x, y, w, h)<br />
:: Sets the clipping rectangle on the screen.<br />
<br />
* GetClippingRectangle()<br />
:: Returns an object with the properties x, y, w, h, that describes the current clipping rectangle of the screen.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported format is BMP.<br />
<br />
* GrabImage(x, y, w, h)<br />
::Returns a new image object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface(...)<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]].<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]])<br />
::Draws an outline of a circle on 'surface' of radius 'r', centered on 'x', 'y', of 'color'<br />
<br />
* surface.filledCircle(x, y, r, , [[API:Color|color]])<br />
::Draws a filled circle of 'color' on 'surface', centered on 'x', 'y', with a radius of 'r'.<br />
<br />
* surface.gradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h' on 'surface'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* surface.setAlpha(a)<br />
::Sets the alpha of the surface to 'a'.<br />
<br />
* surface.blitSurface(surface_object, x, y)<br />
:: Blits surface_object onto surface at x, y.<br />
<br />
* surface.cloneSection(x, y, w, h)<br />
:: Returns a surface object that contains the section of surface at x, y, and is w by h.<br />
<br />
* surface.setClippingRectangle(x, y, w, h)<br />
::Sets the clipping rectangle of the surface. Anything drawing operations that are outside the clipping rectangle are ignored.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface = new Surface(16, 16, new Color(255, 0, 0, 255)); //Create a red surface.<br />
<br />
surface.rectangle(0, 0, 16, 8, new Color(0, 0, 255, 255)); //Make the top half of the surface blue.<br />
<br />
surface.setClippingRectangle(8, 0, 8, 16); //Set the clipping rectangle of the surface to be the right half.<br />
<br />
surface.rectangle(0, 0, 16, 16, new Color(0, 255, 0, 255)); //Try and fill the rectangle with green. Only the right half will be changed!<br />
</syntaxhighlight><br />
<br />
::; The clipping rectangle can be reset as so:<br />
<syntaxhighlight><br />
surface.setCLippingRectangle(0, 0, surface.width, surface.height); //Set the clipping rectangle to be from 0, 0, to the edges.<br />
</syntaxhighlight><br />
<br />
* surface.getClippingRectangle()<br />
::Returns a JS object that represents the surface's clipping rectangle, with properties 'x', 'y', 'w', and 'h'.<br />
<br />
* GrabSurface(x, y, w, h)<br />
::Returns a new surface object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* surface.width<br />
::Value contains the width of the surface.<br />
<br />
* surface.height<br />
::Value contains the height of the surface.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* GradientLine(x1, y1, x2, y2, [[API:Color|color1]], [[API:Color|color2]])<br />
:: Draws a line of from x1, y1, to x2, y2 fading between 'color1' and 'color2'.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* OutlinedRectangle(x, y, w, h, [[API:Color|color]] [, thickness])<br />
:: Draws an outline of a rectangle of 'color' width w and height h at x, y. The edges are drawn of 'thickness'. If thickness is not provided, it is one pixel.<br />
<br />
* Triangle(x1, y1, x2, y2, x3, y3, , [[API:Color|color]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', filled with 'color'.<br />
<br />
* GradientTriangle(x1, y1, x2, y2, x3, y3, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', fading between the colors.<br />
<br />
* Polygon(array, color)<br />
:: Draws a polygon described by array, filled with 'color'. The elements of 'array' must have x and y properties.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
* font.drawZoomedText(x, y, str, f)<br />
:: Draws 'str' using 'font' at 'x', 'y', zoomed by factor 'f'.<br />
<br />
* font.drawTextBox(x, y, w, h, y_offset, str)<br />
:: Draws 'str' using 'font' inside the box described by 'x', 'y', 'w', 'h', and offset vertically by 'y_offset'.<br />
<br />
* font.wordWrapString(str)<br />
:: Returns an array of strings, breaking up 'str' as though font.drawTextBox was called, and each element of the array is a line of text to be drawn.<br />
<br />
* font.getStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* font.setColorMask(color)<br />
:: Sets the mask of 'font'.<br />
<br />
* font.getColorMask()<br />
:: Returns the color mask of 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==JoyStick==<br />
<br />
===JoyStick Functions===<br />
* GetNumJoysticks()<br />
::Returns the number of usable joysticks connected to the computer.<br />
<br />
* GetJoystickName(jsnum)<br />
::Returns the name of joystick number 'jsnum'.<br />
<br />
* GetNumJoystickButtons(jsnum)<br />
::Returns the number of buttons on joystick number 'jsnum'.<br />
<br />
* GetNumJoystickAxes(jsnum)<br />
::Returns the number of axes on joystick number 'jsnum'.<br />
<br />
* IsJoystickButtonPressed(jsnum, button)<br />
::Checks whether or not button number 'button' is pressed on joystick number 'jsnum'.<br />
<br />
* GetJoystickAxis(jsnum, axis)<br />
::Returns the value for axis number 'axis' on joystick number 'jsnum'.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'savefile1.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.<br />
<br />
=AudioBass=<br />
<br />
===Sound Object===<br />
<br />
* Sound(filename)<br />
::Creates a [[API:Sound|sound object]] from the file 'filename'. In 0.3.0, all sounds are streamed, although this will not be the case in later releases.<br />
<br />
* sound.play([loop])<br />
::Plays the sound. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:Sound.stop|stop()]] is called. If the sound is already playing, it is restarted from the beginning.<br />
<br />
* sound.stop()<br />
::Stops playing a sound. The sound will be started from the beginning next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.pause()<br />
::Stops playing a sound. Playback will resume from the pausing point next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.getLength()<br />
::Returns the length of 'sound' in milliseconds.<br />
<br />
* sound.isPlaying()<br />
::Checks if the sound is currently playing.<br />
<br />
===SoundEffect Object===<br />
<br />
* SoundEffect(filename)<br />
::Creates a [[API:SoundEffect|soundeffect object]] from the file 'filename'.<br />
<br />
* soundeffect.play([loop])<br />
::Plays the soundeffect. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:SoundEffect.stop|stop()]] is called. A soundeffect may be played as many times simultaneously as desired.<br />
<br />
* soundeffect.stop()<br />
::Stops playing all instances of 'soundeffect'.<br />
<br />
* soundeffect.getLength()<br />
::Returns the length of 'soundeffect' in milliseconds.<br />
<br />
* soundeffect.isPlaying()<br />
::Checks if the soundeffect is currently playing.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Legacy:GetMouseY&diff=1033Legacy:GetMouseY2013-09-08T12:30:42Z<p>Flying Jester: Fixed link to GetMouseX in "See Also"</p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Returns the Y coordinate of the pixel the mouse is currently over in the game window or (in fullscreen) screen.<br />
<br />
__TOC__<br />
<br />
==Usage==<br />
{{Usage|returns=number|func=GetMouseY}}<br />
<br />
==Examples==<br />
Color the pixel on the screen that the mouse is currently on:<br />
<br />
<syntaxhighlight><br />
var Red = CreateColor(255, 0, 0, 255);<br />
Point(GetMouseX(), GetMouseY(), Red);<br />
</syntaxhighlight><br />
<br />
==Notes==<br />
Mouse coordinates will not be tracked when the mouse is out of the window.<br />
<br />
==See also==<br />
<br />
* [[API:GetMouseX|GetMouseX]]()<br />
* [[API:SetMousePosition|SetMousePosition]](x, y)</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Legacy:GetMouseX&diff=1032Legacy:GetMouseX2013-09-08T12:30:16Z<p>Flying Jester: Added Functions Category tag</p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Returns the X coordinate of the pixel the mouse is currently over in the game window or (in fullscreen) screen.<br />
<br />
__TOC__<br />
<br />
==Usage==<br />
{{Usage|returns=number|func=GetMouseX}}<br />
<br />
==Examples==<br />
Color the pixel on the screen that the mouse is currently on:<br />
<br />
<syntaxhighlight><br />
var Red = CreateColor(255, 0, 0, 255);<br />
Point(GetMouseX(), GetMouseY(), Red);<br />
</syntaxhighlight><br />
<br />
==Notes==<br />
Mouse coordinates will not be tracked when the mouse is out of the window.<br />
<br />
==See also==<br />
<br />
* [[API:GetMouseY|GetMouseY]]()<br />
* [[API:SetMousePosition|SetMousePosition]](x, y)</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Legacy:GetMouseY&diff=1031Legacy:GetMouseY2013-09-08T12:29:01Z<p>Flying Jester: Added Functions Category</p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Returns the Y coordinate of the pixel the mouse is currently over in the game window or (in fullscreen) screen.<br />
<br />
__TOC__<br />
<br />
==Usage==<br />
{{Usage|returns=number|func=GetMouseY}}<br />
<br />
==Examples==<br />
Color the pixel on the screen that the mouse is currently on:<br />
<br />
<syntaxhighlight><br />
var Red = CreateColor(255, 0, 0, 255);<br />
Point(GetMouseX(), GetMouseY(), Red);<br />
</syntaxhighlight><br />
<br />
==Notes==<br />
Mouse coordinates will not be tracked when the mouse is out of the window.<br />
<br />
==See also==<br />
<br />
* [[API:GetMouseY|GetMouseX]]()<br />
* [[API:SetMousePosition|SetMousePosition]](x, y)</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Legacy:GetMouseY&diff=1030Legacy:GetMouseY2013-09-08T12:27:27Z<p>Flying Jester: Created page with " Returns the Y coordinate of the pixel the mouse is currently over in the game window or (in fullscreen) screen. __TOC__ ==Usage== {{Usage|returns=number|func=GetMouseY}} ..."</p>
<hr />
<div><br />
<br />
Returns the Y coordinate of the pixel the mouse is currently over in the game window or (in fullscreen) screen.<br />
<br />
__TOC__<br />
<br />
==Usage==<br />
{{Usage|returns=number|func=GetMouseY}}<br />
<br />
==Examples==<br />
Color the pixel on the screen that the mouse is currently on:<br />
<br />
<syntaxhighlight><br />
var Red = CreateColor(255, 0, 0, 255);<br />
Point(GetMouseX(), GetMouseY(), Red);<br />
</syntaxhighlight><br />
<br />
==Notes==<br />
Mouse coordinates will not be tracked when the mouse is out of the window.<br />
<br />
==See also==<br />
<br />
* [[API:GetMouseY|GetMouseX]]()<br />
* [[API:SetMousePosition|SetMousePosition]](x, y)</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Legacy:GetMouseX&diff=1029Legacy:GetMouseX2013-09-08T12:26:39Z<p>Flying Jester: </p>
<hr />
<div><br />
<br />
Returns the X coordinate of the pixel the mouse is currently over in the game window or (in fullscreen) screen.<br />
<br />
__TOC__<br />
<br />
==Usage==<br />
{{Usage|returns=number|func=GetMouseX}}<br />
<br />
==Examples==<br />
Color the pixel on the screen that the mouse is currently on:<br />
<br />
<syntaxhighlight><br />
var Red = CreateColor(255, 0, 0, 255);<br />
Point(GetMouseX(), GetMouseY(), Red);<br />
</syntaxhighlight><br />
<br />
==Notes==<br />
Mouse coordinates will not be tracked when the mouse is out of the window.<br />
<br />
==See also==<br />
<br />
* [[API:GetMouseY|GetMouseY]]()<br />
* [[API:SetMousePosition|SetMousePosition]](x, y)</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Legacy:GetMouseX&diff=1028Legacy:GetMouseX2013-09-08T12:25:53Z<p>Flying Jester: </p>
<hr />
<div><br />
<br />
Returns the X coordinate of the pixel the mouse is currently over in the game window or (in fullscreen) screen.<br />
<br />
__TOC__<br />
<br />
==Usage==<br />
{{Usage|returns=X|func=GetMouseX}}<br />
<br />
==Examples==<br />
Color the pixel on the screen that the mouse is currently on:<br />
<br />
<syntaxhighlight><br />
var Red = CreateColor(255, 0, 0, 255);<br />
Point(GetMouseX(), GetMouseY(), Red);<br />
</syntaxhighlight><br />
<br />
==Notes==<br />
Mouse coordinates will not be tracked when the mouse is out of the window.<br />
<br />
==See also==<br />
<br />
* [[API:GetMouseY|GetMouseY]]()<br />
* [[API:SetMousePosition|SetMousePosition]](x, y)</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Legacy:GetMouseX&diff=1027Legacy:GetMouseX2013-09-08T12:20:13Z<p>Flying Jester: Created page with "{{subst:functemp}}"</p>
<hr />
<div><br />
<br />
{{{preamble}}}<br />
<br />
__TOC__<br />
<br />
==Usage==<br />
{{Usage|returns={{{returns}}}|object={{{object}}}|func={{{function}}}|params={{{params}}}}}<br />
<br />
* '''param1''' type. param1 description<br />
* '''param2''' type. param2 description<br />
* '''paramN''' type. paramN description<br />
<br />
==Examples==<br />
(examples with syntaxhighlighted code)<br />
<br />
==Notes==<br />
(notes)<br />
<br />
==See also==<br />
* see also<br />
* see also<br />
* see also<br />
* etc</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Legacy:Triangle&diff=1026Legacy:Triangle2013-09-08T12:16:17Z<p>Flying Jester: Created page with "Draws a triangle on the framebuffer. ==Usage== {{Usage|func=Tirangle|params=x1, y1, x2, y2, x3, y2, color}} * '''x1''' the X coordinate of the first vertex. * '''y1''' the ..."</p>
<hr />
<div>Draws a triangle on the framebuffer.<br />
<br />
==Usage==<br />
<br />
{{Usage|func=Tirangle|params=x1, y1, x2, y2, x3, y2, color}}<br />
<br />
* '''x1''' the X coordinate of the first vertex.<br />
* '''y1''' the Y coordinate of the first vertex.<br />
* '''x2''' the X coordinate of the second vertex.<br />
* '''y2''' the Y coordinate of the second vertex.<br />
* '''x3''' the X coordinate of the third vertex.<br />
* '''y3''' the Y coordinate of the third vertex.<br />
* '''color''' a [[API:Color|color object]] created with [[API:CreateColor|CreateColor]]<br />
<br />
==Notes==<br />
<br />
Remember that [[API:FlipScreen|FlipScreen]] must be called before any drawing is visible on the screen.<br />
<br />
==Examples==<br />
<br />
Draw a triangle on the screen:<br />
<br />
<syntaxhighlight><br />
var Red = CreateColor(255, 0, 0, 255);<br />
Triangle(16, 16, 32, 32, 16, 32, Red);<br />
</syntaxhighlight><br />
<br />
==See also==<br />
<br />
* Sphere [[API:Color|Color]] Object<br />
* [[API:CreateColor|CreateColor]](r, g, b, a)<br />
* [[API:GradientTriangle|GradientTriangle]](x1, x2, y1, y2, x3, y3, color1, color2, color3)<br />
* [[API:Rectangle|Rectangle]](x, y, w, h, color)<br />
* [[API:Point|Point]](x, y, color)<br />
<br />
{{API:Video/navbox}}</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_Plugin_Roadmap&diff=1025User:Flying Jester/TurboSphere Plugin Roadmap2013-09-08T11:46:09Z<p>Flying Jester: Created page with "This page describes the plans for the standard distribution TurboSphere plugins. It includes the breakdown of which functions belong in which plugins, the interaction of certa..."</p>
<hr />
<div>This page describes the plans for the standard distribution TurboSphere plugins. It includes the breakdown of which functions belong in which plugins, the interaction of certain plugins, and the categorization of the plugins.<br />
<br />
===Forward===<br />
The TurboSphere game engine is composed of the engine binary (turbosphere or turbosphere.exe), several support libraries (graphicalg.dll, graphiccommon.dll, configmanager.dll t5.dll, or libgraphicalg.so, libgraphiccommon.so, libconfigmanager.so, libt5.so), and a set of plugins, which are shared libraries. <br />
<br />
The engine opens games. The supporting libraries provide functionality to the engine and plugins. The plugins provide script-side functionality, and implementation-specific functionality to other plugins for use by script.<br />
<br />
The engine contains functionality to parse command line parameters to open a game folder, sgm, or tsgm file, the functionality to enumerate, load, and close plugins, and sets up the standard V8 JS environment.<br />
<br />
The component libraries contain functionality and definitions useful for both the engine and plugins. graphiccommon contains the definition of a color object (represented as a TS_Color in the TurboSphere source, and a [[API:Color|Color]] in script). graphicalg contains basic algorithmic structures (TS_Point, TS_Segment) that are used to pass basic information from the engine to a plugin or from a plugin to a plugin in a standard way. This library may one day also hold A* pathfinding, functions for linear approximation of circles, etc., that should be standardized between plugins. configmanager holds the functions and structures to set and get a games configuration, list of default directories, and the functions to open and execute a script. <br />
<br />
T5 is a separate, though first-party, project from TurboSphere. T5 reads in ini-style files (with the addition of support for sections), and provides an api for reading and writing said files. It also contains cross-platform functions for determining if a path is a file or folder, and cross-platform functions to read in any file and return a standard C string that holds the files contents. T5 is the recommended way to read or write any config files for a plugin or the engine, as this provides a unified format (including any quirks that may not have been found yet) for TurboSphere configuration files.<br />
<br />
==Summary of Standard Plugins==<br />
<br />
There are currently (September 8, 2013; TS version 0.3.2rc) 10 standard plugins. They are:<br />
<br />
* audioBASS<br />
* bmpfontGL<br />
* getkeystring<br />
* graphicSDL_GL_threaded<br />
* inputSDL<br />
* mapengineGL<br />
* networkTS<br />
* scriptfsT5<br />
* ttffontGL<br />
* windowstyleGL<br />
<br />
They are categorized as follows:<br />
<br />
===audioBASS===<br />
<br />
Contains Audio functions. <br />
<br />
Adds support for the following file types:<br />
<br />
* wav<br />
* ogg<br />
* mp1<br />
* mp2<br />
* mp3<br />
* aiff<br />
* flac<br />
* midi<br />
* mod<br />
* xm<br />
* it<br />
* s3m<br />
* mtm<br />
* sf2<br />
<br />
Audio Support is provided by the BASS shared library. Midi and SF2 is added by BASSmidi shared library, a BASS plugin. AudioBASS is designed for sound file opening, seeking, playback, and soundfont selection.<br />
<br />
Any soundchip emulation is beyond the scope of this plugin.<br />
<br />
Sound recording and sound file modification is beyond the scope of this plugin.<br />
<br />
===bmpfontGL===<br />
<br />
Contains functions to open Sphere rfn fonts, modify and save rfn fonts, and draw string using rfn fonts to the screen. Graphics interface is through OpenGL, font opening and manipulation is provided by SDL.<br />
<br />
Adds support for the following file types:<br />
<br />
* rfn<br />
<br />
Any support for TTF Fonts, other formats of bitmap-style fonts, and the conversion between any rfn and any other format of font, is beyond the scope of this plugin.<br />
<br />
This plugin relies on a graphics plugin that is OpenGL compatible being used.<br />
<br />
This plugin requires that whichever plugin supplies the [[API:Surface|Surface]] JS object type to script also export through C-linkage the function TS_SDL_GL_MakeV8SurfaceHandleFromPixels.<br />
This plugin requires that whichever plugin supplies the [[API:Image|Image]] JS object type to script also export through C-linkage the function TS_SDL_GL_MakeV8ImageHandleFromGLTexture.<br />
<br />
In the future, this plugin may export through C-linkage a facility to draw arbitrary text to the screen at given coordinates (i.e., for an as-of-yet unimplemented error reporting plugin).<br />
<br />
===getkeystring===<br />
<br />
Contains the function GetKeyString, which converts a keycode to a string. This plugin is a test plugin, especially for new plugin API changes.<br />
<br />
Adds support for no file types.<br />
<br />
Any function except for GetKeyString is beyond the scope of this plugin.<br />
<br />
===graphicSDL_GL_threaded===<br />
<br />
Contains functions for controlling the screen or game window, opening, modifying, and saving images, creating surfaces, creating and modifying colors, drawing graphics primitives.<br />
<br />
Adds support for the following file types:<br />
<br />
* bmp<br />
* png<br />
* tiff<br />
* tga<br />
* gif<br />
* jpeg<br />
* pcx<br />
* pbm<br />
* lbm<br />
* pnm<br />
* xcf<br />
* xpm<br />
* xv<br />
<br />
===inputSDL===<br />
<br />
Contains functions for getting input from keyboard, mouse (including mousewheel), and gamepad/joystick.<br />
<br />
Adds support for no file types.<br />
<br />
Functions for low level access to any hardware, networking, and filesystem access is beyond the scope of this plugin.<br />
<br />
===mapengineGL===<br />
<br />
Contains functions for loading rmp maps, rts tilesets, and rss spritesets, running and controlling a Sphere-compatible map engine, creating modifying and deleting persons, entities, zones, and also saving maps, tilesets, spritesets, obstruction handling, and all other functions relating to the original Sphere map engine.<br />
<br />
Adds support for the following file types:<br />
<br />
* rss<br />
* rts<br />
* rmp<br />
<br />
Pathfinding is beyond the scope of this plugin.<br />
<br />
===networkTS===<br />
<br />
Contains functions for connecting to or hosting connections over a network via IPv4, IPv6, and IPX, sending and receiving data over a network, and getting the local machine's address and hostname.<br />
<br />
Adds support for no file types.<br />
<br />
Non-OSI networking and networking using other protocol stacks including AppleTalk is beyond the scope of this plugin.<br />
<br />
===scriptfsT5===<br />
<br />
Contains functions for accessing, modifying, saving, listing, and deleting INI-style files and rawfiles, and supplying MD5 hashes of files, strings, and ByteArrays. Provides structures for INI-style files, ByteArrays, and raw binary files.<br />
<br />
Adds support for opening and saving any file, which are represented as binary data.<br />
<br />
===ttffontGL===<br />
<br />
Contains functions for opening and drawing text to the screen using TrueType, OpenType, and Type-1 fonts.<br />
<br />
Adds support for the following file types:<br />
<br />
* ttf<br />
* otf<br />
* pfb<br />
* pfm<br />
* afm<br />
* pfa<br />
* ofm<br />
<br />
Modifying or saving any of the supported file types is beyond the scope of this plugin. <br />
<br />
===windowstyleGL===<br />
<br />
Contains functions for opening and displaying rws windowstyles.<br />
<br />
Support for modifying and saving rws windowstyles is planned, but currently not implemented.<br />
<br />
Adds support for the following file types:<br />
<br />
* rws<br />
<br />
==What Belongs in a Standard Plugin==<br />
<br />
The standard set of plugins are designed to, when used all together, provide a Sphere 1.5-like set of functions for use in script. Several features exists already extending this functionality, including TTF font support. Generally, all standard plugins should supply a collection of Sphere 1.5 or 1.6 functions, all falling into a logical category. <br />
<br />
==Which Plugins are High Priority==<br />
<br />
Beyond this, all TurboSphere plugins can be categorized as atomic or extensive. Atomic plugins have functionality that could not be recreated given a Sphere 1.5-like environment if they were missing. The atomic plugins are scriptfsT5, networkTS, audioBASS, graphicSDL_GL_threaded, and inputSDL. Although some functions in these plugins could be emulated in script, many can not. On the other hand, given both scriptfsT5 and graphicSDL_GL_threaded one could write scripts to open rfn fonts, rws windowstyles, theoretically ttf fonts, the entire map engine, and getkeystring.<br />
<br />
The plugins which are highest priority are these atomic plugins. Within this, all functions that cannot be recreated in script within these plugins are a higher priority than other functions.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=1024User:Flying Jester/TurboSphere API2013-09-08T11:45:37Z<p>Flying Jester: </p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.0. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
Note that while functions and objects are linked to by this page, all pages prefixed with 'API' refer to the Sphere versions of the objects and functions. The descriptions and examples for Sphere functions and objects are generally analogous to the TurboSphere versions, but not exactly the same.<br />
<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* SetTitle(title)<br />
:: Sets the title of the game window.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported format is BMP.<br />
<br />
* GrabImage(x, y, w, h)<br />
::Returns a new image object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface(...)<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]].<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]])<br />
::Draws an outline of a circle on 'surface' of radius 'r', centered on 'x', 'y', of 'color'<br />
<br />
* surface.filledCircle(x, y, r, , [[API:Color|color]])<br />
::Draws a filled circle of 'color' on 'surface', centered on 'x', 'y', with a radius of 'r'.<br />
<br />
* surface.gradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h' on 'surface'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* surface.setAlpha(a)<br />
::Sets the alpha of the surface to 'a'.<br />
<br />
* surface.setClippingRectangle(x, y, w, h)<br />
::Sets the clipping rectangle of the surface. Anything drawing operations that are outside the clipping rectangle are ignored.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface = new Surface(16, 16, new Color(255, 0, 0, 255)); //Create a red surface.<br />
<br />
surface.rectangle(0, 0, 16, 8, new Color(0, 0, 255, 255)); //Make the top half of the surface blue.<br />
<br />
surface.setCLippingRectangle(8, 0, 8, 16); //Set the clipping rectangle of the surface to be the right half.<br />
<br />
surface.rectangle(0, 0, 16, 16, new Color(0, 255, 0, 255)); //Try and fill the rectangle with green. Only the right half will be changed!<br />
</syntaxhighlight><br />
<br />
::; The clipping rectangle can be reset as so:<br />
<syntaxhighlight><br />
surface.setCLippingRectangle(0, 0, surface.width, surface.height); //Set the clipping rectangle to be from 0, 0, to the edges.<br />
</syntaxhighlight><br />
<br />
* surface.getCLippingRectangle()<br />
::Returns a JS object that represents the surface's clipping rectangle, with properties 'x', 'y', 'w', and 'h'.<br />
<br />
* GrabSurface(x, y, w, h)<br />
::Returns a new surface object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* surface.width<br />
::Value contains the width of the surface.<br />
<br />
* surface.height<br />
::Value contains the height of the surface.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* GradientLine(x1, y1, x2, y2, [[API:Color|color1]], [[API:Color|color2]])<br />
:: Draws a line of from x1, y1, to x2, y2 fading between 'color1' and 'color2'.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* OutlinedRectangle(x, y, w, h, [[API:Color|color]] [, thickness])<br />
:: Draws an outline of a rectangle of 'color' width w and height h at x, y. The edges are drawn of 'thickness'. If thickness is not provided, it is one pixel.<br />
<br />
* Triangle(x1, y1, x2, y2, x3, y3, , [[API:Color|color]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', filled with 'color'.<br />
<br />
* GradientTriangle(x1, y1, x2, y2, x3, y3, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', fading between the colors.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
*font.gatStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==JoyStick==<br />
<br />
===JoyStick Functions===<br />
* GetNumJoysticks()<br />
::Returns the number of usable joysticks connected to the computer.<br />
<br />
* GetJoystickName(jsnum)<br />
::Returns the name of joystick number 'jsnum'.<br />
<br />
* GetNumJoystickButtons(jsnum)<br />
::Returns the number of buttons on joystick number 'jsnum'.<br />
<br />
* GetNumJoystickAxes(jsnum)<br />
::Returns the number of axes on joystick number 'jsnum'.<br />
<br />
* IsJoystickButtonPressed(jsnum, button)<br />
::Checks whether or not button number 'button' is pressed on joystick number 'jsnum'.<br />
<br />
* GetJoystickAxis(jsnum, axis)<br />
::Returns the value for axis number 'axis' on joystick number 'jsnum'.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'savefile1.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.<br />
<br />
=AudioBass=<br />
<br />
===Sound Object===<br />
<br />
* Sound(filename)<br />
::Creates a [[API:Sound|sound object]] from the file 'filename'. In 0.3.0, all sounds are streamed, although this will not be the case in later releases.<br />
<br />
* sound.play([loop])<br />
::Plays the sound. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:Sound.stop|stop()]] is called. If the sound is already playing, it is restarted from the beginning.<br />
<br />
* sound.stop()<br />
::Stops playing a sound. The sound will be started from the beginning next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.pause()<br />
::Stops playing a sound. Playback will resume from the pausing point next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.getLength()<br />
::Returns the length of 'sound' in milliseconds.<br />
<br />
* sound.isPlaying()<br />
::Checks if the sound is currently playing.<br />
<br />
===SoundEffect Object===<br />
<br />
* SoundEffect(filename)<br />
::Creates a [[API:SoundEffect|soundeffect object]] from the file 'filename'.<br />
<br />
* soundeffect.play([loop])<br />
::Plays the soundeffect. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:SoundEffect.stop|stop()]] is called. A soundeffect may be played as many times simultaneously as desired.<br />
<br />
* soundeffect.stop()<br />
::Stops playing all instances of 'soundeffect'.<br />
<br />
* soundeffect.getLength()<br />
::Returns the length of 'soundeffect' in milliseconds.<br />
<br />
* soundeffect.isPlaying()<br />
::Checks if the soundeffect is currently playing.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Developing_a_Sphere-compatible_engine&diff=996Developing a Sphere-compatible engine2013-07-27T10:15:36Z<p>Flying Jester: Added SDL input section.</p>
<hr />
<div>{{aside|Notice|This [[:Category:Tutorials|tutorial article]] is incomplete, but it is also important. Do not edit it unless you've been given permission, thanks.|note.svg}}<br />
<br />
This article aims to provide a checklist and resources for developing a JavaScript-powered game engine that is compatible with [[API:Functions|Sphere's JavaScript API]].<br />
<br />
__TOC__<br />
<br />
==Introduction==<br />
Throughout this article, the original Sphere implementation shall be referred to as "vanilla" Sphere and consisted of use of an older version of [https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey] as the JavaScript engine, the first-party [http://corona.sf.net Corona library] for the software implementation of video, and the first-party [http://audiere.sf.net Audiere library] for the audio driver. Input was mapped directly in software using whatever API was native to the OS in the case of the Windows and Linux versions of vanilla Sphere. The recent Mac OS X port of vanilla Sphere used SDL to handle all input and output while still using an older version of SpiderMonkey for JavaScript.<br />
<br />
Possible frameworks to implement Sphere:<br />
* JavaScript<br />
** V8<br />
** SpiderMonkey v1.8.5<br />
** Jurassic / IronJS / JavaScript.Net / Jint<br />
* Game Libraries<br />
** SDL<br />
** SFML<br />
* Graphics libraries<br />
** OpenGL<br />
** pixi.js / three.js<br />
** DirectX (DirectDraw)<br />
** hand-rolled software renderer.<br />
* Audio libraries<br />
** Audiere<br />
** Libsndfile<br />
** BASS<br />
** Irrklang<br />
** FMod<br />
<br />
<br />
(TODO: more)<br />
<br />
==Input==<br />
<br />
===SDL===<br />
If you want to use SDL, it will be helpful to set up an event filter to catch application close events. Since the main function that needs proper access to events is GetKey, you can disable mouse movement, mouse button, and key-up events so that the event queue will be filled with just keydown events. This simplifies the implementation of the GetKey function, as it is the only function that needs the queue to contain a specific kind of event. Be sure to pump or poll for events whenever input is requested. This also keeps the engine responsive during calls to getkey, and tending the event queue keeps the engine responsive in general.<br />
<br />
Keyboard state polling (as in IsKeyPressed()) can be handled with getting the keystate and comparing keysyms.<br />
<br />
===SFML===<br />
If you are using SFML, you need to handle the key pressed and released events. It's a good idea to use a static array for all of the keys, mouse, and joystick buttons. The array's index corresponds with a key, mouse, and joystick code with a true/false value indicating IsPressed. In order to support more than one joystick you may need to bump up that joystick array to a 2D array, where 'x' is the joystick id and 'y' is the button code.<br />
<br />
For the key queue, just use a queue data structure. Enqueue keys on the released state, and dequeue keys with [[API:GetKey|GetKey]].<br />
<br />
===Other input libraries===<br />
(TODO: list possible input handling libraries and gotchas)<br />
<br />
===Handling keyboard input notes===<br />
[[API:GetKey|GetKey]]() must be able to block the sphere engine. If the key queue is empty, go into a loop that just updates the game screen.<br />
<br />
(TODO: fill)<br />
<br />
====Key Constant Mapping====<br />
In SDL, SFML, and other game libraries, key code enumerations offered in source may differ from Sphere's. In order to map keys correctly you might need to implement a very large map that is basically a "this key" = "that key" list. Such a technique is optional if you already follow Sphere's key naming conventions, but what this will do is allow other Sphere engines to use those same codes if you saved a game with key mappings from vanilla Sphere.<br />
<br />
See Sphere's [[list of keycode constants]] for the official list, also at https://github.com/sphere-group/sphere/blob/v1.6/sphere/docs/development/keys.txt<br />
<br />
===Handling mouse input notes===<br />
(TODO)<br />
<br />
===Handling joystick input notes===<br />
(TODO)<br />
<br />
===Other input methods===<br />
(TODO)<br />
<br />
==Output==<br />
===Video===<br />
<br />
Blitting is a process that draws the image or surface to a screen's render target prior to flipping. In web based engines this is best emulated with a "draw queue". You fill the queue with what to draw prior to a frame and update it when you are ready.<br />
<br />
(TODO: more)<br />
(TODO: multi-monitor?)<br />
(TODO: touch-screen?)<br />
<br />
===Audio===<br />
<br />
====SFML====<br />
Audio is split between sounds and music. They have the same API, but music streams intrinsically.<br />
Volume however takes a range of 0 to 100. Treat that as a percent of the 0 to 255 range Sphere uses. You might need to cache the volume into a private variable and get set from that, making sure to set the underlying volume as a percent of whatever you used.<br />
<br />
==Sphere-format file loading==<br />
Sphere uses five custom file formats, all containing bitmap data in some form or another: [[API:Font|bitmap fonts]], [[API:Spriteset|spritesets]], [[API:WindowStyle|stylized window frames]], [[API:Map|maps]], and [[API:Map|map tilesets]]. Some of them have metadata interspersed with the bitmap data, others have a dedicated block that contains all the metadata for the file in one section regardless of the bitmap data. Maps in particular have the option of choosing to embed its tileset within its file or to point to an external tileset file. All have fixed size headers that are trivial to read. All integer values are stored in [[wikipedia:endianness#Little-endian|Intel order/little-endian]] and unless otherwise noted all pixel values are 32-bit and stored in the order RGBA.<br />
<br />
===Fonts===<br />
Pretty straight forward. Version 1 Sphere fonts only allow 8-bit grayscale pixels and are deprecated in favor of version 2 fonts. Version 2 fonts use bitmaps containing full 32-bit RGBA pixels. There are reserved bytes to be aware of, otherwise no metadata.<br />
<br />
===Spritesets===<br />
Three separate versions with separate loading behaviors. Much more complicated than fonts, some reserved bytes, lots of metadata. (TODO: expand)<br />
<br />
===WindowStyles===<br />
Two versions to handle. Some reserved bytes, some deprecated properties depending on version, small amount of metadata. (TODO: expand)<br />
<br />
===Maps===<br />
Lots of metadata, small amount of reserved bytes, can embed tilesets or refer to external tileset files. (TODO: expand)<br />
<br />
===Tilesets===<br />
Lots of metadata, small amount of reserved bytes, bitmap data is in one large block after header but before metadata. (TODO: expand)<br />
<br />
==The map engine==<br />
(TODO)<br />
<br />
===The MapEngine loop===<br />
(TODO)<br />
<br />
==Maintaining API compatibility==<br />
Sphere's original JavaScript API was written with a procedural mentality. JavaScript is a language with a powerful prototype-based inheritance system, so you may want to change Sphere's native objects such as the [[API:Color|Color object]] to allow variable creation via the ''new'' syntax; if you do this natively you must either write the equivalent loading function (in this case, [[API:CreateColor|CreateColor]]) as native code or in a scripted shim. The [[system scripts|system script]] [[Script:system/oldsphere.js|oldsphere.js]] is an example of such a shim, existing to maintain compatibility with projects written for pre-1.0 versions of Sphere. If you'd rather leave the original procedural-style loading functions but add the ability to create native Sphere objects with a working prototype constructor, visit [http://forums.spheredev.org/index.php/topic,69.0.html this forum thread] for information on doing it in script.<br />
<br />
===Compatibility with 1.5===<br />
(TODO)<br />
<br />
===Compatibility with 1.6 beta===<br />
(TODO)<br />
<br />
===Compatibility with 1.7 alpha===<br />
(TODO)<br />
<br />
===Backwards-compatibility with pre-1.5===<br />
(TODO)<br />
<br />
==List of Sphere-compatible engine implementations==<br />
===Complete or in-progress===<br />
{| class="wikitable sortable" width="100%"<br />
|+Complete or in-progress Sphere-compatible engines<br />
|-<br />
! scope="col"| Implementation<br />
! scope="col"| Operating System<br />
! scope="col"| Version<br />
! scope="col"| JS engine<br />
! scope="col"| Video driver<br />
! scope="col"| Audio driver<br />
! scope="col"| Input handler<br />
|-<br />
|vanilla Sphere<br/>[https://github.com/sphere-group/sphere source], [http://forums.spheredev.org/index.php/topic,155.0.html thread]<br />
|Win x86, OSX, Linux x86<br />
|stable: 1.5<br/>unstable: 1.6 beta 4<br/>inactive: 1.7 alpha<br />
|[https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey]<br />
|configurable<br />
|configurable<br />
|configurable<br />
|-<br />
|TurboSphere<br/>[https://github.com/FlyingJester/TurboSphere source], [http://forums.spheredev.org/index.php/topic,13.0.html thread]<br />
|Win x86/64, OSX, Linux x86/64<br />
|0.3.0<br />
|[https://code.google.com/p/v8/ V8]<br />
|OpenGL via SDL2<br />
|BASS<br />
|SDL2<br />
|-<br />
|unnamed Sphere clone in SDL<br/>[https://github.com/postcasio/sphereclone source], [http://forums.spheredev.org/index.php/topic,72.0.html thread]<br />
|?<br />
|?<br />
|[https://code.google.com/p/v8/ V8]<br />
|SDL<br />
|SDL<br />
|SDL<br />
|-<br />
|sphere-sfml<br/>[https://github.com/Radnen/sphere-sfml source], [http://forums.spheredev.org/index.php/topic,137.0.html thread]<br />
|Win x86, OSX(?)<br />
|0.65 alpha<br />
|[http://jurassic.codeplex.com/ Jurassic]<br />
|OpenGL via SFML 2<br />
|libsndfile via SFML 2<br />
|SFML 2<br />
|-<br />
|web-sphere<br/>[https://github.com/sphere-group/web-sphere source], [http://forums.spheredev.org/index.php/topic,154.0.html thread]<br />
|Chrome, Firefox, and IE9+<br />
|[http://www.pixijs.com/ pixi.js] version: ?<br/>[http://threejs.org/ three.js] version: ?<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|}<br />
<br />
{{aside|Info|Although some engines are listed as compatible they will need a shim script to maintain compatibility with Sphere's API. For example, [[API:LoadImage|LoadImage]] may indeed return the correct [[API:image|image]] format by using a different API such as <tt>return new Image()</tt>.|template-info.svg}}<br />
<br />
===Discontinued or abandoned===<br />
(TODO)<br />
<br />
==See also==<br />
(TODO)<br />
<br />
[[Category:Tutorials]]</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Developing_a_Sphere-compatible_engine&diff=985Developing a Sphere-compatible engine2013-07-18T03:41:05Z<p>Flying Jester: /* Complete or in-progress */</p>
<hr />
<div>{{aside|Notice|This [[:Category:Tutorials|tutorial article]] is incomplete, but it is also important. Do not edit it unless you've been given permission, thanks.|note.svg}}<br />
<br />
This article aims to provide a checklist and resources for developing a JavaScript-powered game engine that is compatible with [[API:Functions|Sphere's JavaScript API]].<br />
<br />
__TOC__<br />
<br />
==Introduction==<br />
Throughout this article, the original Sphere implementation shall be referred to as "vanilla" Sphere and consisted of use of an older version of [https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey] as the JavaScript engine, the first-party [http://corona.sf.net Corona library] for the software implementation of video, and the first-party [http://audiere.sf.net Audiere library] for the audio driver. Input was mapped directly in software using whatever API was native to the OS in the case of the Windows and Linux versions of vanilla Sphere. The recent Mac OS X port of vanilla Sphere used SDL to handle all input and output while still using an older version of SpiderMonkey for JavaScript.<br />
<br />
Possible frameworks to implement Sphere:<br />
* JavaScript<br />
** V8<br />
** SpiderMonkey v1.8.5<br />
** Jurassic / IronJS / JavaScript.Net / Jint<br />
* Game Libraries<br />
** SDL<br />
** SFML<br />
* Graphics libraries<br />
** OpenGL<br />
** pixi.js / three.js<br />
** DirectX (DirectDraw)<br />
** hand-rolled software renderer.<br />
* Audio libraries<br />
** Audiere<br />
** Libsndfile<br />
** BASS<br />
** Irrklang<br />
** FMod<br />
<br />
<br />
(TODO: more)<br />
<br />
==Input==<br />
<br />
GetKey() must be able to block the sphere engine. If your key queue is zero, go into a loop that just updates the game screen.<br />
<br />
=== SFML ===<br />
If you are using SFML, you need to handle the key pressed and released events. It's a good idea to use a static array for all of the keys, mouse, and joystick buttons. The array's index corresponds with a key, mouse, and joystick code with a true/false value indicating IsPressed. In order to support more than one joystick you may need to bump up that joystick array to a 2D array, where 'x' is the joystick id and 'y' is the button code.<br />
<br />
For the key queue, just use a queue data structure. Enqueue keys on the released state, and dequeue keys with GetKey.<br />
<br />
=== Key Constant Mapping ===<br />
<br />
In SDL, SFML, and other game libraries the key codes may differ from Sphere's. In order to get the correct key mapping you might need to implement a very large structure that says "this key" = "that key". This does not have to happen as it is optional so long as you keep to the same key naming conventions. What this will do is fix it so that if you saved a game with key mappings from vanilla sphere, other sphere engines can use those same codes.<br />
<br />
See key constants: (<tt>KEY_ESCAPE = 1, KEY_F1 = 2,</tt> ... etc).<br />
<br />
https://github.com/sphere-group/sphere/blob/v1.6/sphere/docs/development/keys.txt<br />
<br />
<br />
(keyboard, mouse, joystick, touch-screen?)<br />
<br />
==Output==<br />
===Video===<br />
<br />
Blitting is a process that draws the image or surface to a screen's render target prior to flipping. In web based engines this is best emulated with a "draw queue". You fill the queue with what to draw prior to a frame and update it when you are ready.<br />
<br />
(TODO: more)<br />
(TODO: multi-monitor?)<br />
(TODO: touch-screen?)<br />
<br />
===Audio===<br />
<br />
====SFML====<br />
Audio is split between sounds and music. They have the same API, but music streams intrinsically.<br />
Volume however takes a range of 0 to 100. Treat that as a percent of the 0 to 255 range Sphere uses. You might need to cache the volume into a private variable and get set from that, making sure to set the underlying volume as a percent of whatever you used.<br />
<br />
==The map engine==<br />
(TODO)<br />
<br />
===The MapEngine loop===<br />
(TODO)<br />
<br />
==Maintaining API compatibility==<br />
Sphere's original JavaScript API was written with a procedural mentality. JavaScript is a language with a powerful prototype-based inheritance system, so you may want to change Sphere's native objects such as the [[API:Color|Color object]] to allow variable creation via the ''new'' syntax; if you do this natively you must either write the equivalent loading function (in this case, [[API:CreateColor|CreateColor]]) as native code or in a scripted shim. The [[system scripts|system script]] [[Script:system/oldsphere.js|oldsphere.js]] is an example of such a shim, existing to maintain compatibility with projects written for pre-1.0 versions of Sphere. If you'd rather leave the original procedural-style loading functions but add the ability to create native Sphere objects with a working prototype constructor, visit [http://forums.spheredev.org/index.php/topic,69.0.html this forum thread] for information on doing it in script.<br />
<br />
===Compatibility with 1.5===<br />
(TODO)<br />
<br />
===Compatibility with 1.6 beta===<br />
(TODO)<br />
<br />
===Compatibility with 1.7 alpha===<br />
(TODO)<br />
<br />
===Backwards-compatibility with pre-1.5===<br />
(TODO)<br />
<br />
==List of Sphere-compatible engine implementations==<br />
===Complete or in-progress===<br />
{| class="wikitable sortable" width="100%"<br />
|+Complete or in-progress Sphere-compatible engines<br />
|-<br />
! scope="col"| Implementation<br />
! scope="col"| Version<br />
! scope="col"| JS engine<br />
! scope="col"| Video driver<br />
! scope="col"| Audio driver<br />
! scope="col"| Input handler<br />
! scope="col"| Links<br />
|-<br />
|vanilla Sphere<br />
|stable: 1.5<br/>unstable: 1.6 beta 4<br/>inactive: 1.7 alpha<br />
|[https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey]<br />
|configurable<br />
|configurable<br />
|configurable<br />
|[https://github.com/sphere-group/sphere source]<br/>[http://forums.spheredev.org/index.php/topic,155.0.html thread]<br />
|-<br />
|TurboSphere<br />
|0.3.0<br />
|[https://code.google.com/p/v8/ V8]<br />
|OpenGL via SDL2<br />
|BASS<br />
|SDL2<br />
|[https://github.com/FlyingJester/TurboSphere source]<br/>[http://forums.spheredev.org/index.php/topic,13.0.html thread]<br />
|-<br />
|unnamed Sphere clone in SDL<br />
|?<br />
|[https://code.google.com/p/v8/ V8]<br />
|SDL<br />
|SDL<br />
|SDL<br />
|[https://github.com/postcasio/sphereclone source]<br/>[http://forums.spheredev.org/index.php/topic,72.0.html thread]<br />
|-<br />
|sphere-sfml<br />
|?<br />
|[http://jurassic.codeplex.com/ Jurassic]<br />
|OpenGL via SFML<br />
|libsndfile via SFML<br />
|SFML<br />
|[https://github.com/Radnen/sphere-sfml source]<br/>[http://forums.spheredev.org/index.php/topic,137.0.html thread]<br />
|-<br />
|web-sphere<br />
|[http://www.pixijs.com/ pixi.js] version: ?<br/>[http://threejs.org/ three.js] version: ?<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|[https://github.com/sphere-group/web-sphere source]<br/>[http://forums.spheredev.org/index.php/topic,154.0.html thread]<br />
|}<br />
<br />
(!) Although some engines are listed as compatible they will need a shim script to maintain compatibility with Sphere's API. For example, [[API:LoadImage|LoadImage]] may indeed return the correct [[API:image|image]] format by using a different API such as <tt>return new Image()</tt>.<br />
<br />
===Discontinued or abandoned===<br />
(TODO)<br />
<br />
==See also==<br />
(TODO)<br />
<br />
[[Category:Tutorials]]</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Developing_a_Sphere-compatible_engine&diff=984Developing a Sphere-compatible engine2013-07-18T03:38:11Z<p>Flying Jester: </p>
<hr />
<div>{{aside|Notice|This [[:Category:Tutorials|tutorial article]] is incomplete, but it is also important. Do not edit it unless you've been given permission, thanks.|note.svg}}<br />
<br />
This article aims to provide a checklist and resources for developing a JavaScript-powered game engine that is compatible with [[API:Functions|Sphere's JavaScript API]].<br />
<br />
__TOC__<br />
<br />
==Introduction==<br />
Throughout this article, the original Sphere implementation shall be referred to as "vanilla" Sphere and consisted of use of an older version of [https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey] as the JavaScript engine, the first-party [http://corona.sf.net Corona library] for the software implementation of video, and the first-party [http://audiere.sf.net Audiere library] for the audio driver. Input was mapped directly in software using whatever API was native to the OS in the case of the Windows and Linux versions of vanilla Sphere. The recent Mac OS X port of vanilla Sphere used SDL to handle all input and output while still using an older version of SpiderMonkey for JavaScript.<br />
<br />
Possible frameworks to implement Sphere:<br />
* JavaScript<br />
** V8<br />
** SpiderMonkey v1.8.5<br />
** Jurassic / IronJS / JavaScript.Net / Jint<br />
* Game Libraries<br />
** SDL<br />
** SFML<br />
* Graphics libraries<br />
** OpenGL<br />
** pixi.js / three.js<br />
** DirectX (DirectDraw)<br />
** hand-rolled software renderer.<br />
* Audio libraries<br />
** Audiere<br />
** Libsndfile<br />
** BASS<br />
** Irrklang<br />
** FMod<br />
<br />
<br />
(TODO: more)<br />
<br />
==Input==<br />
<br />
GetKey() must be able to block the sphere engine. If your key queue is zero, go into a loop that just updates the game screen.<br />
<br />
=== SFML ===<br />
If you are using SFML, you need to handle the key pressed and released events. It's a good idea to use a static array for all of the keys, mouse, and joystick buttons. The array's index corresponds with a key, mouse, and joystick code with a true/false value indicating IsPressed. In order to support more than one joystick you may need to bump up that joystick array to a 2D array, where 'x' is the joystick id and 'y' is the button code.<br />
<br />
For the key queue, just use a queue data structure. Enqueue keys on the released state, and dequeue keys with GetKey.<br />
<br />
=== Key Constant Mapping ===<br />
<br />
In SDL, SFML, and other game libraries the key codes may differ from Sphere's. In order to get the correct key mapping you might need to implement a very large structure that says "this key" = "that key". This does not have to happen as it is optional so long as you keep to the same key naming conventions. What this will do is fix it so that if you saved a game with key mappings from vanilla sphere, other sphere engines can use those same codes.<br />
<br />
See key constants: (<tt>KEY_ESCAPE = 1, KEY_F1 = 2,</tt> ... etc).<br />
<br />
https://github.com/sphere-group/sphere/blob/v1.6/sphere/docs/development/keys.txt<br />
<br />
<br />
(keyboard, mouse, joystick, touch-screen?)<br />
<br />
==Output==<br />
===Video===<br />
<br />
Blitting is a process that draws the image or surface to a screen's render target prior to flipping. In web based engines this is best emulated with a "draw queue". You fill the queue with what to draw prior to a frame and update it when you are ready.<br />
<br />
(TODO: more)<br />
(TODO: multi-monitor?)<br />
(TODO: touch-screen?)<br />
<br />
===Audio===<br />
<br />
====SFML====<br />
Audio is split between sounds and music. They have the same API, but music streams intrinsically.<br />
Volume however takes a range of 0 to 100. Treat that as a percent of the 0 to 255 range Sphere uses. You might need to cache the volume into a private variable and get set from that, making sure to set the underlying volume as a percent of whatever you used.<br />
<br />
==The map engine==<br />
(TODO)<br />
<br />
===The MapEngine loop===<br />
(TODO)<br />
<br />
==Maintaining API compatibility==<br />
Sphere's original JavaScript API was written with a procedural mentality. JavaScript is a language with a powerful prototype-based inheritance system, so you may want to change Sphere's native objects such as the [[API:Color|Color object]] to allow variable creation via the ''new'' syntax; if you do this natively you must either write the equivalent loading function (in this case, [[API:CreateColor|CreateColor]]) as native code or in a scripted shim. The [[system scripts|system script]] [[Script:system/oldsphere.js|oldsphere.js]] is an example of such a shim, existing to maintain compatibility with projects written for pre-1.0 versions of Sphere. If you'd rather leave the original procedural-style loading functions but add the ability to create native Sphere objects with a working prototype constructor, visit [http://forums.spheredev.org/index.php/topic,69.0.html this forum thread] for information on doing it in script.<br />
<br />
===Compatibility with 1.5===<br />
(TODO)<br />
<br />
===Compatibility with 1.6 beta===<br />
(TODO)<br />
<br />
===Compatibility with 1.7 alpha===<br />
(TODO)<br />
<br />
===Backwards-compatibility with pre-1.5===<br />
(TODO)<br />
<br />
==List of Sphere-compatible engine implementations==<br />
===Complete or in-progress===<br />
{| class="wikitable sortable" width="100%"<br />
|+Complete or in-progress Sphere-compatible engines<br />
|-<br />
! scope="col"| Implementation<br />
! scope="col"| Version<br />
! scope="col"| JS engine<br />
! scope="col"| Video driver<br />
! scope="col"| Audio driver<br />
! scope="col"| Input handler<br />
! scope="col"| Links<br />
|-<br />
|vanilla Sphere<br />
|stable: 1.5<br/>unstable: 1.6 beta 4<br/>inactive: 1.7 alpha<br />
|[https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey]<br />
|configurable<br />
|configurable<br />
|configurable<br />
|[https://github.com/sphere-group/sphere source]<br/>[http://forums.spheredev.org/index.php/topic,155.0.html thread]<br />
|-<br />
|TurboSphere<br />
|0.3.0<br />
|[https://code.google.com/p/v8/ V8]<br />
|SDL2<br />
|BASS<br />
|SDL2<br />
|[https://github.com/FlyingJester/TurboSphere source]<br/>[http://forums.spheredev.org/index.php/topic,13.0.html thread]<br />
|-<br />
|unnamed Sphere clone in SDL<br />
|?<br />
|[https://code.google.com/p/v8/ V8]<br />
|SDL<br />
|SDL<br />
|SDL<br />
|[https://github.com/postcasio/sphereclone source]<br/>[http://forums.spheredev.org/index.php/topic,72.0.html thread]<br />
|-<br />
|sphere-sfml<br />
|?<br />
|[http://jurassic.codeplex.com/ Jurassic]<br />
|OpenGL via SFML<br />
|libsndfile via SFML<br />
|SFML<br />
|[https://github.com/Radnen/sphere-sfml source]<br/>[http://forums.spheredev.org/index.php/topic,137.0.html thread]<br />
|-<br />
|web-sphere<br />
|[http://www.pixijs.com/ pixi.js] version: ?<br/>[http://threejs.org/ three.js] version: ?<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|[https://github.com/sphere-group/web-sphere source]<br/>[http://forums.spheredev.org/index.php/topic,154.0.html thread]<br />
|}<br />
<br />
(!) Although some engines are listed as compatible they will need a shim script to maintain compatibility with Sphere's API. For example, [[API:LoadImage|LoadImage]] may indeed return the correct [[API:image|image]] format by using a different API such as <tt>return new Image()</tt>.<br />
<br />
===Discontinued or abandoned===<br />
(TODO)<br />
<br />
==See also==<br />
(TODO)<br />
<br />
[[Category:Tutorials]]</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=847User:Flying Jester/TurboSphere API2013-06-16T01:31:49Z<p>Flying Jester: /* File Object */</p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.0. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
Note that while functions and objects are linked to by this page, all pages prefixed with 'API' refer to the Sphere versions of the objects and functions. The descriptions and examples for Sphere functions and objects are generally analogous to the TurboSphere versions, but not exactly the same.<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* SetTitle(title)<br />
:: Sets the title of the game window.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported format is BMP.<br />
<br />
* GrabImage(x, y, w, h)<br />
::Returns a new image object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface(...)<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]].<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]])<br />
::Draws an outline of a circle on 'surface' of radius 'r', centered on 'x', 'y', of 'color'<br />
<br />
* surface.filledCircle(x, y, r, , [[API:Color|color]])<br />
::Draws a filled circle of 'color' on 'surface', centered on 'x', 'y', with a radius of 'r'.<br />
<br />
* surface.gradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h' on 'surface'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* surface.setAlpha(a)<br />
::Sets the alpha of the surface to 'a'.<br />
<br />
* surface.setClippingRectangle(x, y, w, h)<br />
::Sets the clipping rectangle of the surface. Anything drawing operations that are outside the clipping rectangle are ignored.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface = new Surface(16, 16, new Color(255, 0, 0, 255)); //Create a red surface.<br />
<br />
surface.rectangle(0, 0, 16, 8, new Color(0, 0, 255, 255)); //Make the top half of the surface blue.<br />
<br />
surface.setCLippingRectangle(8, 0, 8, 16); //Set the clipping rectangle of the surface to be the right half.<br />
<br />
surface.rectangle(0, 0, 16, 16, new Color(0, 255, 0, 255)); //Try and fill the rectangle with green. Only the right half will be changed!<br />
</syntaxhighlight><br />
<br />
::; The clipping rectangle can be reset as so:<br />
<syntaxhighlight><br />
surface.setCLippingRectangle(0, 0, surface.width, surface.height); //Set the clipping rectangle to be from 0, 0, to the edges.<br />
</syntaxhighlight><br />
<br />
* surface.getCLippingRectangle()<br />
::Returns a JS object that represents the surface's clipping rectangle, with properties 'x', 'y', 'w', and 'h'.<br />
<br />
* GrabSurface(x, y, w, h)<br />
::Returns a new surface object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* surface.width<br />
::Value contains the width of the surface.<br />
<br />
* surface.height<br />
::Value contains the height of the surface.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* GradientLine(x1, y1, x2, y2, [[API:Color|color1]], [[API:Color|color2]])<br />
:: Draws a line of from x1, y1, to x2, y2 fading between 'color1' and 'color2'.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* OutlinedRectangle(x, y, w, h, [[API:Color|color]] [, thickness])<br />
:: Draws an outline of a rectangle of 'color' width w and height h at x, y. The edges are drawn of 'thickness'. If thickness is not provided, it is one pixel.<br />
<br />
* Triangle(x1, y1, x2, y2, x3, y3, , [[API:Color|color]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', filled with 'color'.<br />
<br />
* GradientTriangle(x1, y1, x2, y2, x3, y3, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', fading between the colors.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
*font.gatStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==JoyStick==<br />
<br />
===JoyStick Functions===<br />
* GetNumJoysticks()<br />
::Returns the number of usable joysticks connected to the computer.<br />
<br />
* GetJoystickName(jsnum)<br />
::Returns the name of joystick number 'jsnum'.<br />
<br />
* GetNumJoystickButtons(jsnum)<br />
::Returns the number of buttons on joystick number 'jsnum'.<br />
<br />
* GetNumJoystickAxes(jsnum)<br />
::Returns the number of axes on joystick number 'jsnum'.<br />
<br />
* IsJoystickButtonPressed(jsnum, button)<br />
::Checks whether or not button number 'button' is pressed on joystick number 'jsnum'.<br />
<br />
* GetJoystickAxis(jsnum, axis)<br />
::Returns the value for axis number 'axis' on joystick number 'jsnum'.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'savefile1.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.<br />
<br />
=AudioBass=<br />
<br />
===Sound Object===<br />
<br />
* Sound(filename)<br />
::Creates a [[API:Sound|sound object]] from the file 'filename'. In 0.3.0, all sounds are streamed, although this will not be the case in later releases.<br />
<br />
* sound.play([loop])<br />
::Plays the sound. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:Sound.stop|stop()]] is called. If the sound is already playing, it is restarted from the beginning.<br />
<br />
* sound.stop()<br />
::Stops playing a sound. The sound will be started from the beginning next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.pause()<br />
::Stops playing a sound. Playback will resume from the pausing point next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.getLength()<br />
::Returns the length of 'sound' in milliseconds.<br />
<br />
* sound.isPlaying()<br />
::Checks if the sound is currently playing.<br />
<br />
===SoundEffect Object===<br />
<br />
* SoundEffect(filename)<br />
::Creates a [[API:SoundEffect|soundeffect object]] from the file 'filename'.<br />
<br />
* soundeffect.play([loop])<br />
::Plays the soundeffect. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:SoundEffect.stop|stop()]] is called. A soundeffect may be played as many times simultaneously as desired.<br />
<br />
* soundeffect.stop()<br />
::Stops playing all instances of 'soundeffect'.<br />
<br />
* soundeffect.getLength()<br />
::Returns the length of 'soundeffect' in milliseconds.<br />
<br />
* soundeffect.isPlaying()<br />
::Checks if the soundeffect is currently playing.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=846User:Flying Jester/TurboSphere API2013-06-16T01:29:30Z<p>Flying Jester: </p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.0. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
Note that while functions and objects are linked to by this page, all pages prefixed with 'API' refer to the Sphere versions of the objects and functions. The descriptions and examples for Sphere functions and objects are generally analogous to the TurboSphere versions, but not exactly the same.<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* SetTitle(title)<br />
:: Sets the title of the game window.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported format is BMP.<br />
<br />
* GrabImage(x, y, w, h)<br />
::Returns a new image object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface(...)<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]].<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]])<br />
::Draws an outline of a circle on 'surface' of radius 'r', centered on 'x', 'y', of 'color'<br />
<br />
* surface.filledCircle(x, y, r, , [[API:Color|color]])<br />
::Draws a filled circle of 'color' on 'surface', centered on 'x', 'y', with a radius of 'r'.<br />
<br />
* surface.gradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h' on 'surface'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* surface.setAlpha(a)<br />
::Sets the alpha of the surface to 'a'.<br />
<br />
* surface.setClippingRectangle(x, y, w, h)<br />
::Sets the clipping rectangle of the surface. Anything drawing operations that are outside the clipping rectangle are ignored.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface = new Surface(16, 16, new Color(255, 0, 0, 255)); //Create a red surface.<br />
<br />
surface.rectangle(0, 0, 16, 8, new Color(0, 0, 255, 255)); //Make the top half of the surface blue.<br />
<br />
surface.setCLippingRectangle(8, 0, 8, 16); //Set the clipping rectangle of the surface to be the right half.<br />
<br />
surface.rectangle(0, 0, 16, 16, new Color(0, 255, 0, 255)); //Try and fill the rectangle with green. Only the right half will be changed!<br />
</syntaxhighlight><br />
<br />
::; The clipping rectangle can be reset as so:<br />
<syntaxhighlight><br />
surface.setCLippingRectangle(0, 0, surface.width, surface.height); //Set the clipping rectangle to be from 0, 0, to the edges.<br />
</syntaxhighlight><br />
<br />
* surface.getCLippingRectangle()<br />
::Returns a JS object that represents the surface's clipping rectangle, with properties 'x', 'y', 'w', and 'h'.<br />
<br />
* GrabSurface(x, y, w, h)<br />
::Returns a new surface object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* surface.width<br />
::Value contains the width of the surface.<br />
<br />
* surface.height<br />
::Value contains the height of the surface.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* GradientLine(x1, y1, x2, y2, [[API:Color|color1]], [[API:Color|color2]])<br />
:: Draws a line of from x1, y1, to x2, y2 fading between 'color1' and 'color2'.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* OutlinedRectangle(x, y, w, h, [[API:Color|color]] [, thickness])<br />
:: Draws an outline of a rectangle of 'color' width w and height h at x, y. The edges are drawn of 'thickness'. If thickness is not provided, it is one pixel.<br />
<br />
* Triangle(x1, y1, x2, y2, x3, y3, , [[API:Color|color]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', filled with 'color'.<br />
<br />
* GradientTriangle(x1, y1, x2, y2, x3, y3, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', fading between the colors.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
*font.gatStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==JoyStick==<br />
<br />
===JoyStick Functions===<br />
* GetNumJoysticks()<br />
::Returns the number of usable joysticks connected to the computer.<br />
<br />
* GetJoystickName(jsnum)<br />
::Returns the name of joystick number 'jsnum'.<br />
<br />
* GetNumJoystickButtons(jsnum)<br />
::Returns the number of buttons on joystick number 'jsnum'.<br />
<br />
* GetNumJoystickAxes(jsnum)<br />
::Returns the number of axes on joystick number 'jsnum'.<br />
<br />
* IsJoystickButtonPressed(jsnum, button)<br />
::Checks whether or not button number 'button' is pressed on joystick number 'jsnum'.<br />
<br />
* GetJoystickAxis(jsnum, axis)<br />
::Returns the value for axis number 'axis' on joystick number 'jsnum'.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'newfile.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.<br />
<br />
=AudioBass=<br />
<br />
===Sound Object===<br />
<br />
* Sound(filename)<br />
::Creates a [[API:Sound|sound object]] from the file 'filename'. In 0.3.0, all sounds are streamed, although this will not be the case in later releases.<br />
<br />
* sound.play([loop])<br />
::Plays the sound. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:Sound.stop|stop()]] is called. If the sound is already playing, it is restarted from the beginning.<br />
<br />
* sound.stop()<br />
::Stops playing a sound. The sound will be started from the beginning next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.pause()<br />
::Stops playing a sound. Playback will resume from the pausing point next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.getLength()<br />
::Returns the length of 'sound' in milliseconds.<br />
<br />
* sound.isPlaying()<br />
::Checks if the sound is currently playing.<br />
<br />
===SoundEffect Object===<br />
<br />
* SoundEffect(filename)<br />
::Creates a [[API:SoundEffect|soundeffect object]] from the file 'filename'.<br />
<br />
* soundeffect.play([loop])<br />
::Plays the soundeffect. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:SoundEffect.stop|stop()]] is called. A soundeffect may be played as many times simultaneously as desired.<br />
<br />
* soundeffect.stop()<br />
::Stops playing all instances of 'soundeffect'.<br />
<br />
* soundeffect.getLength()<br />
::Returns the length of 'soundeffect' in milliseconds.<br />
<br />
* soundeffect.isPlaying()<br />
::Checks if the soundeffect is currently playing.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=845User:Flying Jester/TurboSphere API2013-06-16T01:25:43Z<p>Flying Jester: </p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.0. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* SetTitle(title)<br />
:: Sets the title of the game window.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported format is BMP.<br />
<br />
* GrabImage(x, y, w, h)<br />
::Returns a new image object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface(...)<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]].<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]])<br />
::Draws an outline of a circle on 'surface' of radius 'r', centered on 'x', 'y', of 'color'<br />
<br />
* surface.filledCircle(x, y, r, , [[API:Color|color]])<br />
::Draws a filled circle of 'color' on 'surface', centered on 'x', 'y', with a radius of 'r'.<br />
<br />
* surface.gradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h' on 'surface'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* surface.setAlpha(a)<br />
::Sets the alpha of the surface to 'a'.<br />
<br />
* surface.setClippingRectangle(x, y, w, h)<br />
::Sets the clipping rectangle of the surface. Anything drawing operations that are outside the clipping rectangle are ignored.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface = new Surface(16, 16, new Color(255, 0, 0, 255)); //Create a red surface.<br />
<br />
surface.rectangle(0, 0, 16, 8, new Color(0, 0, 255, 255)); //Make the top half of the surface blue.<br />
<br />
surface.setCLippingRectangle(8, 0, 8, 16); //Set the clipping rectangle of the surface to be the right half.<br />
<br />
surface.rectangle(0, 0, 16, 16, new Color(0, 255, 0, 255)); //Try and fill the rectangle with green. Only the right half will be changed!<br />
</syntaxhighlight><br />
<br />
::; The clipping rectangle can be reset as so:<br />
<syntaxhighlight><br />
surface.setCLippingRectangle(0, 0, surface.width, surface.height); //Set the clipping rectangle to be from 0, 0, to the edges.<br />
</syntaxhighlight><br />
<br />
* surface.getCLippingRectangle()<br />
::Returns a JS object that represents the surface's clipping rectangle, with properties 'x', 'y', 'w', and 'h'.<br />
<br />
* GrabSurface(x, y, w, h)<br />
::Returns a new surface object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* surface.width<br />
::Value contains the width of the surface.<br />
<br />
* surface.height<br />
::Value contains the height of the surface.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* GradientLine(x1, y1, x2, y2, [[API:Color|color1]], [[API:Color|color2]])<br />
:: Draws a line of from x1, y1, to x2, y2 fading between 'color1' and 'color2'.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* OutlinedRectangle(x, y, w, h, [[API:Color|color]] [, thickness])<br />
:: Draws an outline of a rectangle of 'color' width w and height h at x, y. The edges are drawn of 'thickness'. If thickness is not provided, it is one pixel.<br />
<br />
* Triangle(x1, y1, x2, y2, x3, y3, , [[API:Color|color]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', filled with 'color'.<br />
<br />
* GradientTriangle(x1, y1, x2, y2, x3, y3, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', fading between the colors.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
*font.gatStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==JoyStick==<br />
<br />
===JoyStick Functions===<br />
* GetNumJoysticks()<br />
::Returns the number of usable joysticks connected to the computer.<br />
<br />
* GetJoystickName(jsnum)<br />
::Returns the name of joystick number 'jsnum'.<br />
<br />
* GetNumJoystickButtons(jsnum)<br />
::Returns the number of buttons on joystick number 'jsnum'.<br />
<br />
* GetNumJoystickAxes(jsnum)<br />
::Returns the number of axes on joystick number 'jsnum'.<br />
<br />
* IsJoystickButtonPressed(jsnum, button)<br />
::Checks whether or not button number 'button' is pressed on joystick number 'jsnum'.<br />
<br />
* GetJoystickAxis(jsnum, axis)<br />
::Returns the value for axis number 'axis' on joystick number 'jsnum'.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'newfile.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.<br />
<br />
=AudioBass=<br />
<br />
===Sound Object===<br />
<br />
* Sound(filename)<br />
::Creates a [[API:Sound|sound object]] from the file 'filename'. In 0.3.0, all sounds are streamed, although this will not be the case in later releases.<br />
<br />
* sound.play([loop])<br />
::Plays the sound. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:Sound.stop|stop()]] is called. If the sound is already playing, it is restarted from the beginning.<br />
<br />
* sound.stop()<br />
::Stops playing a sound. The sound will be started from the beginning next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.pause()<br />
::Stops playing a sound. Playback will resume from the pausing point next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.getLength()<br />
::Returns the length of 'sound' in milliseconds.<br />
<br />
* sound.isPlaying()<br />
::Checks if the sound is currently playing.<br />
<br />
===SoundEffect Object===<br />
<br />
* SoundEffect(filename)<br />
::Creates a [[API:SoundEffect|soundeffect object]] from the file 'filename'.<br />
<br />
* soundeffect.play([loop])<br />
::Plays the soundeffect. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:SoundEffect.stop|stop()]] is called. A soundeffect may be played as many times simultaneously as desired.<br />
<br />
* soundeffect.stop()<br />
::Stops playing all instances of 'soundeffect'.<br />
<br />
* soundeffect.getLength()<br />
::Returns the length of 'soundeffect' in milliseconds.<br />
<br />
* soundeffect.isPlaying()<br />
::Checks if the soundeffect is currently playing.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=844User:Flying Jester/TurboSphere API2013-06-16T01:25:11Z<p>Flying Jester: </p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.0. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* SetTitle(title)<br />
:: Sets the title of the game window.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported format is BMP.<br />
<br />
* GrabImage(x, y, w, h)<br />
::Returns a new image object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface(...)<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]].<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]])<br />
::Draws an outline of a circle on 'surface' of radius 'r', centered on 'x', 'y', of 'color'<br />
<br />
* surface.filledCircle(x, y, r, , [[API:Color|color]])<br />
::Draws a filled circle of 'color' on 'surface', centered on 'x', 'y', with a radius of 'r'.<br />
<br />
* surface.gradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h' on 'surface'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* surface.setAlpha(a)<br />
::Sets the alpha of the surface to 'a'.<br />
<br />
* surface.setClippingRectangle(x, y, w, h)<br />
::Sets the clipping rectangle of the surface. Anything drawing operations that are outside the clipping rectangle are ignored.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface = new Surface(16, 16, new Color(255, 0, 0, 255)); //Create a red surface.<br />
<br />
surface.rectangle(0, 0, 16, 8, new Color(0, 0, 255, 255)); //Make the top half of the surface blue.<br />
<br />
surface.setCLippingRectangle(8, 0, 8, 16); //Set the clipping rectangle of the surface to be the right half.<br />
<br />
surface.rectangle(0, 0, 16, 16, new Color(0, 255, 0, 255)); //Try and fill the rectangle with green. Only the right half will be changed!<br />
</syntaxhighlight><br />
<br />
::; The clipping rectangle can be reset as so:<br />
<syntaxhighlight><br />
surface.setCLippingRectangle(0, 0, surface.width, surface.height); //Set the clipping rectangle to be from 0, 0, to the edges.<br />
</syntaxhighlight><br />
<br />
* surface.getCLippingRectangle()<br />
::Returns a JS object that represents the surface's clipping rectangle, with properties 'x', 'y', 'w', and 'h'.<br />
<br />
* GrabSurface(x, y, w, h)<br />
::Returns a new surface object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* surface.width<br />
::Value contains the width of the surface.<br />
<br />
* surface.height<br />
::Value contains the height of the surface.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* GradientLine(x1, y1, x2, y2, [[API:Color|color1]], [[API:Color|color2]])<br />
:: Draws a line of from x1, y1, to x2, y2 fading between 'color1' and 'color2'.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* OutlinedRectangle(x, y, w, h, [[API:Color|color]] [, thickness])<br />
:: Draws an outline of a rectangle of 'color' width w and height h at x, y. The edges are drawn of 'thickness'. If thickness is not provided, it is one pixel.<br />
<br />
* Triangle(x1, y1, x2, y2, x3, y3, , [[API:Color|color]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', filled with 'color'.<br />
<br />
* GradientTriangle(x1, y1, x2, y2, x3, y3, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', fading between the colors.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
*font.gatStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==JoyStick==<br />
<br />
===JoyStick Functions===<br />
* GetNumJoysticks()<br />
::Returns the number of usable joysticks connected to the computer.<br />
<br />
* GetJoystickName(jsnum)<br />
::Returns the name of joystick number 'jsnum'.<br />
<br />
* GetNumJoystickButtons(jsnum)<br />
::Returns the number of buttons on joystick number 'jsnum'.<br />
<br />
* GetNumJoystickAxes(jsnum)<br />
::Returns the number of axes on joystick number 'jsnum'.<br />
<br />
* IsJoystickButtonPressed(jsnum, button)<br />
::Checks whether or not button number 'button' is pressed on joystick number 'jsnum'.<br />
<br />
* GetJoystickAxis(jsnum, axis)<br />
::Returns the value for axis number 'axis' on joystick number 'jsnum'.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'newfile.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.<br />
<br />
=audioBass=<br />
<br />
===Sound Object===<br />
<br />
* Sound(filename)<br />
::Creates a [[API:Sound|sound object]] from the file 'filename'. In 0.3.0, all sounds are streamed, although this will not be the case in later releases.<br />
<br />
* sound.play([loop])<br />
::Plays the sound. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:Sound.stop|stop()]] is called. If the sound is already playing, it is restarted from the beginning.<br />
<br />
* sound.stop()<br />
::Stops playing a sound. The sound will be started from the beginning next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.pause()<br />
::Stops playing a sound. Playback will resume from the pausing point next time [[API:Sound.play|play()]] is called.<br />
<br />
* sound.getLength()<br />
::Returns the length of 'sound' in milliseconds.<br />
<br />
* sound.isPlaying()<br />
::Checks if the sound is currently playing.<br />
<br />
===SoundEffect Object===<br />
<br />
* SoundEffect(filename)<br />
::Creates a [[API:SoundEffect|soundeffect object]] from the file 'filename'.<br />
<br />
* soundeffect.play([loop])<br />
::Plays the soundeffect. If 'loop' is false or no parameter is given, the sound is played once. If 'loop' is true then the sound is played until [[API:SoundEffect.stop|stop()]] is called. A soundeffect may be played as many times simultaneously as desired.<br />
<br />
* soundeffect.stop()<br />
::Stops playing all instances of 'soundeffect'.<br />
<br />
* soundeffect.getLength()<br />
::Returns the length of 'soundeffect' in milliseconds.<br />
<br />
* soundeffect.isPlaying()<br />
::Checks if the soundeffect is currently playing.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=843User:Flying Jester/TurboSphere API2013-06-15T02:46:47Z<p>Flying Jester: </p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.0. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* SetTitle(title)<br />
:: Sets the title of the game window.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported format is BMP.<br />
<br />
* GrabImage(x, y, w, h)<br />
::Returns a new image object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface(...)<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]].<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]])<br />
::Draws an outline of a circle on 'surface' of radius 'r', centered on 'x', 'y', of 'color'<br />
<br />
* surface.filledCircle(x, y, r, , [[API:Color|color]])<br />
::Draws a filled circle of 'color' on 'surface', centered on 'x', 'y', with a radius of 'r'.<br />
<br />
* surface.gradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h' on 'surface'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* surface.setAlpha(a)<br />
::Sets the alpha of the surface to 'a'.<br />
<br />
* surface.setClippingRectangle(x, y, w, h)<br />
::Sets the clipping rectangle of the surface. Anything drawing operations that are outside the clipping rectangle are ignored.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface = new Surface(16, 16, new Color(255, 0, 0, 255)); //Create a red surface.<br />
<br />
surface.rectangle(0, 0, 16, 8, new Color(0, 0, 255, 255)); //Make the top half of the surface blue.<br />
<br />
surface.setCLippingRectangle(8, 0, 8, 16); //Set the clipping rectangle of the surface to be the right half.<br />
<br />
surface.rectangle(0, 0, 16, 16, new Color(0, 255, 0, 255)); //Try and fill the rectangle with green. Only the right half will be changed!<br />
</syntaxhighlight><br />
<br />
::; The clipping rectangle can be reset as so:<br />
<syntaxhighlight><br />
surface.setCLippingRectangle(0, 0, surface.width, surface.height); //Set the clipping rectangle to be from 0, 0, to the edges.<br />
</syntaxhighlight><br />
<br />
* surface.getCLippingRectangle()<br />
::Returns a JS object that represents the surface's clipping rectangle, with properties 'x', 'y', 'w', and 'h'.<br />
<br />
* GrabSurface(x, y, w, h)<br />
::Returns a new surface object containing the contents of the screen in the specified area. Contents of the screen are cleared by [[API:FlipScreen|FlipScreen]] calls, so something must have been drawn in the specified are since the last call to FlipScreen for the surface to contain anything but black.<br />
<br />
* surface.width<br />
::Value contains the width of the surface.<br />
<br />
* surface.height<br />
::Value contains the height of the surface.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* GradientLine(x1, y1, x2, y2, [[API:Color|color1]], [[API:Color|color2]])<br />
:: Draws a line of from x1, y1, to x2, y2 fading between 'color1' and 'color2'.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* OutlinedRectangle(x, y, w, h, [[API:Color|color]] [, thickness])<br />
:: Draws an outline of a rectangle of 'color' width w and height h at x, y. The edges are drawn of 'thickness'. If thickness is not provided, it is one pixel.<br />
<br />
* Triangle(x1, y1, x2, y2, x3, y3, , [[API:Color|color]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', filled with 'color'.<br />
<br />
* GradientTriangle(x1, y1, x2, y2, x3, y3, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]])<br />
::Draws a triangle with vertices 'x1', 'y1', 'x2', 'y2', 'x3', 'y3', fading between the colors.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
*font.gatStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==JoyStick==<br />
<br />
===JoyStick Functions===<br />
* GetNumJoysticks()<br />
::Returns the number of usable joysticks connected to the computer.<br />
<br />
* GetJoystickName(jsnum)<br />
::Returns the name of joystick number 'jsnum'.<br />
<br />
* GetNumJoystickButtons(jsnum)<br />
::Returns the number of buttons on joystick number 'jsnum'.<br />
<br />
* GetNumJoystickAxes(jsnum)<br />
::Returns the number of axes on joystick number 'jsnum'.<br />
<br />
* IsJoystickButtonPressed(jsnum, button)<br />
::Checks whether or not button number 'button' is pressed on joystick number 'jsnum'.<br />
<br />
* GetJoystickAxis(jsnum, axis)<br />
::Returns the value for axis number 'axis' on joystick number 'jsnum'.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'newfile.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=842User:Flying Jester/TurboSphere API2013-06-15T02:34:35Z<p>Flying Jester: </p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.0. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* SetTitle(title)<br />
:: Sets the title of the game window.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported format is BMP.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface(...)<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]].<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]])<br />
::Draws an outline of a circle on 'surface' of radius 'r', centered on 'x', 'y', of 'color'<br />
<br />
* surface.filledCircle(x, y, r, , [[API:Color|color]])<br />
::Draws a filled circle of 'color' on 'surface', centered on 'x', 'y', with a radius of 'r'.<br />
<br />
* surface.gradientRectangle(x, y, w, h, [[API:Color|color1]], [[API:Color|color2]], [[API:Color|color3]], [[API:Color|color4]])<br />
::Draws a rectangle at 'x', 'y', of width 'w' and height 'h' on 'surface'. The corners are color (clockwise from the upper left) by the colors, and the colors are faded into each other in the rectangle.<br />
<br />
* surface.setAlpha(a)<br />
::Sets the alpha of the surface to 'a'.<br />
<br />
* surface.setClippingRectangle(x, y, w, h)<br />
::Sets the clipping rectangle of the surface. Anything drawing operations that are outside the clipping rectangle are ignored.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface = new Surface(16, 16, new Color(255, 0, 0, 255)); //Create a red surface.<br />
<br />
surface.rectangle(0, 0, 16, 8, new Color(0, 0, 255, 255)); //Make the top half of the surface blue.<br />
<br />
surface.setCLippingRectangle(8, 0, 8, 16); //Set the clipping rectangle of the surface to be the right half.<br />
<br />
surface.rectangle(0, 0, 16, 16, new Color(0, 255, 0, 255)); //Try and fill the rectangle with green. Only the right half will be changed!<br />
</syntaxhighlight><br />
<br />
::; The clipping rectangle can be reset as so:<br />
<syntaxhighlight><br />
surface.setCLippingRectangle(0, 0, surface.width, surface.height); //Set the clipping rectangle to be from 0, 0, to the edges.<br />
</syntaxhighlight><br />
<br />
* surface.getCLippingRectangle()<br />
::Returns a JS object that represents the surface's clipping rectangle, with properties 'x', 'y', 'w', and 'h'.<br />
<br />
* surface.width<br />
::Value contains the width of the surface.<br />
<br />
* surface.height<br />
::Value contains the height of the surface.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, c1, c2, c3, c4)<br />
:: Draws a rectangle at x, y, with a width of w and a height of h. The color is faded from c1 to c4 around the corners, moving clockwise from the upper left corner.<br />
<br />
* FilledCircle(x, y, r, [[API:Color|color]])<br />
::Draws a circle of radius r centered at x, y, filled with 'color'.<br />
<br />
* OutlinedCircle(x, y, r, [[API:Color|color]]<br />
::Draws an outline of a circle of radius r centered at x, y with 'color'.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
*font.gatStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'newfile.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=841User:Flying Jester/TurboSphere API2013-06-15T02:24:32Z<p>Flying Jester: </p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.0. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* SetTitle(title)<br />
:: Sets the title of the game window.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.blitMask(x, y, [[API:Color|color]])<br />
::Blits the image to the screen at 'x', 'y', and tinted by 'color'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.zoomBlitMask(x, y, f, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.stretchBlitMask(x, y, hf, vf, [[API:Color|color]])<br />
::Blits the image to the screen with the upper left corner at 'x', 'y', and tinted by 'color'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.rotateBlitMask(x, y, r, [[API:Color|color]])<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation), and tinted by 'color'.<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.transformBlitMask(x1, y1, x2, y2, x3, y3, x4, y4, [[API:Color|color]])<br />
::blits the image with corners at each x and y coordinate, and tinted by 'color'. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported format is BMP.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
===Surfaces===<br />
<br />
* Surface<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface.blit(x, y)<br />
:: Blits the surface at 'x', 'y'. [[API:Surface|Surfaces]] are slower to blit than [[API:Image|images]].<br />
<br />
* surface.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on the surface at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface.line(x1, y1, x2, y2, [[API:Color|color]])<br />
::Draws a line from 'x1', 'y1', to 'x2', 'y2' of 'color'.<br />
<br />
* surface.outlinedCircle(x, y, r, [[API:Color|color]]<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, c1, c2, c3, c4)<br />
:: Draws a rectangle at x, y, with a width of w and a height of h. The color is faded from c1 to c4 around the corners, moving clockwise from the upper left corner.<br />
<br />
* FilledCircle(x, y, r, [[API:Color|color]])<br />
::Draws a circle of radius r centered at x, y, filled with 'color'.<br />
<br />
* OutlinedCircle(x, y, r, [[API:Color|color]]<br />
::Draws an outline of a circle of radius r centered at x, y with 'color'.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
*font.gatStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'newfile.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=840User:Flying Jester/TurboSphere API2013-06-15T02:17:11Z<p>Flying Jester: </p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.3.0. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* SetTitle(title)<br />
:: Sets the title of the game window.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* image.blit(x, y)<br />
::Blits the image to the screen at 'x', 'y'.<br />
<br />
* image.zoomBlit(x, y, f)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image dimensions are scaled by 'f'. 1.0 is a normal blit, 2.0 doubles the size, 0.5 is half size, etc.<br />
<br />
* image.stretchBlit(x, y, hf, vf)<br />
::Blits the image to the screen with the upper left corner at 'x', 'y'. The image's horizontal dimension scaled by 'hf', and the vertical dimension by 'vf'.<br />
<br />
* image.rotateBlit(x, y, r)<br />
::Blits the image centered at 'x', 'y', rotated by 'r' radians (0 is no rotation).<br />
<br />
* image.transformBlit(x1, y1, x2, y2, x3, y3, x4, y4)<br />
::blits the image with corners at each x and y coordinate. The corners are numbered as so, upper left: 1, upper right: 2, lower right: 3, lower left: 4.<br />
<br />
* image.createSurface()<br />
::Returns a surface object with the same dimensions and pixel data as 'image'.<br />
<br />
* image.clone()<br />
::Returns a copy of the image.<br />
<br />
* image.save(filename)<br />
::Saves a copy of the image as 'filename'. Currently the only supported format is BMP.<br />
<br />
* image.width<br />
::Value contains the image's width.<br />
<br />
* image.height<br />
::Value contains the image's height.<br />
<br />
* Surface<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface_or_image.getPixel(x, y)<br />
:: Returns a [[API:Color|color]] object of the color of the Surface or Image at 'x', 'y'.<br />
<br />
* surface_or_image.setPixel.(x, y, [[API:Color|color]])<br />
:: Sets the color of the pixel x, y of surface_or_image to 'color'.<br />
<br />
* surface_or_image.rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle on surface_or_image at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface_or_image.zoomBlit(x, y, f)<br />
:: Blits surface_or_image at x, y, zoomed by factor f. A factor of 1 is the same as a normal blit.<br />
<br />
:: As of 0.2.2a, the surface is imperfectly drawn at factors not divisible by 1/2.<br />
<br />
* surface_or_image.stretchBlit(x, y, hf, vh)<br />
:: Blits surface_or_image at x, y, with a horizontal scaling factor of hf and a vertical scaling factor of vf. Factors of 1 are the same as a normal blit.<br />
<br />
<br />
* surface.blitSurface(surface_or_image_object, x, y)<br />
:: Blits surface_or_image_object onto surface_or_image at x, y.<br />
<br />
* GetSystemArrow()<br />
:: Returns an image of the system arrow. The image used is set in system/system.ini.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[API:Color|color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* Point(x, y, [[API:Color|color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[API:Color|color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, c1, c2, c3, c4)<br />
:: Draws a rectangle at x, y, with a width of w and a height of h. The color is faded from c1 to c4 around the corners, moving clockwise from the upper left corner.<br />
<br />
* FilledCircle(x, y, r, [[API:Color|color]])<br />
::Draws a circle of radius r centered at x, y, filled with 'color'.<br />
<br />
* OutlinedCircle(x, y, r, [[API:Color|color]]<br />
::Draws an outline of a circle of radius r centered at x, y with 'color'.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
*font.gatStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'newfile.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Legacy:HashFromFile&diff=351Legacy:HashFromFile2013-03-27T02:50:56Z<p>Flying Jester: Created page with "Generates an MD5 hash of a file, like a fingerprint that only changes if the file changes. =Usage= ::''string'' HashFromFile(''filename''); * '''filename''' String. A path ..."</p>
<hr />
<div>Generates an MD5 hash of a file, like a fingerprint that only changes if the file changes.<br />
<br />
=Usage=<br />
<br />
::''string'' HashFromFile(''filename'');<br />
<br />
* '''filename''' String. A path relative to the current game's other/ directory (".." to backtrack), specifying the file to generate the MD5 hash of.<br />
* '''string''' is returned, containing the 128-bit MD5 fingerprint in the form of hexadecimal digits (32 chars long). <br />
<br />
<br />
=Examples=<br />
<br />
<syntaxhighlight><br />
function game()<br />
{<br />
// Defaults to directory 'game_name/other/'<br />
var file1 = "my_file_a.txt";<br />
var file2 = "my_file_b.txt";<br />
<br />
if (HashFromFile(file1) == HashFromFile(file2))<br />
Abort("Heh, " + file1 + " and " + file2 + " are identical!\n");<br />
else<br />
Abort(file1 + " and " + file2 + " are different.\n");<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
The above example will compare two files, not by comparing their contents against each other, but by computing and comparing their hashes. The game will then state whether the files are equivalent or not.<br />
<br />
<br />
=Notes=<br />
<br />
* The return value of this function is a 32-character (128-bit) hexadecimal representation of the MD5 'fingerprint' of the data. The Sphere implementation follows the RSA reference implementation of RFC 1321, which means that it produces the same output MD5 as Unix md5 utilities. <br />
<br />
* The same sequence of bytes in the ByteArray will always produce the same MD5 hash sequence. This can be used to verify if a file has been corrupted or tampered with, or to check, say, if files online are different to the version on the local machine, indicating that an update is in order. <br />
<br />
* The MD5 algorithm is a one-way hashing algorithm: this means that it is easy to make from source data, but difficult (but not impossible) to find the source data given the MD5 sum. <br />
<br />
* To find the MD5 of just a byte array, use the HashByteArray() function. <br />
<br />
* To generate MD5 hashes of files outside the others/ directory, use one of the following prefixes, followed by the desired path:<br />
** '~/' or '../' to access the game's base directory.<br />
** '/common/' to access files from '/Sphere/common/', a directory that can be shared by all games. <br />
<br />
<br />
See also<br />
<br />
* [[HashByteArray]]()<br />
* [[Abort]]() <br />
<br />
* [http://www.ietf.org/rfc/rfc1321.txt[RFC 1321]] MD5 algorithm</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Legacy:Image/zoomBlit&diff=350Legacy:Image/zoomBlit2013-03-27T02:44:21Z<p>Flying Jester: </p>
<hr />
<div>Draw the image onto the screen with zooming.<br />
<br />
=Usage=<br />
::''image''.zoomBlit(''x'', ''y'', ''factor'');<br />
<br />
* '''image''' Sphere [[Image]] object. The image to draw on screen.<br />
* '''x''' number. The x coordinate of the top-left corner of the drawn image.<br />
* '''y''' number. The y coordinate of the top-left corner of the drawn image.<br />
* '''factor''' number, floating-point. The amount of zooming applied. factor == 1 causes no zoom, 0 < factor < 1 causes the image to shrink, factor > 1 causes the image to enlarge. <br />
<br />
<br />
=Examples=<br />
<br />
This simple game will take an image and zoom it so that it is stretched to fit the screen.<br />
<br />
<syntaxhighlight><br />
function game()<br />
{<br />
var w = GetScreenWidth();<br />
var h = GetScreenHeight();<br />
var img = LoadImage("my_test_image.png");<br />
<br />
// Calculate by how much to zoom.<br />
var factor = Math.min(w / img.width, h / img.height);<br />
<br />
img.zoomBlit(0, 0, factor);<br />
<br />
FlipScreen();<br />
GetKey();<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
<br />
=Notes=<br />
<br />
* [[Image.transformBlit]]() can also be used to achieve zooming, by picking the corner points manually. <br />
<br />
<br />
=See also=<br />
<br />
* Sphere [[Image]] object <br />
<br />
* [[Image.blit]]()<br />
* [[Image.transformBlit]]()<br />
* [[Image.transformBlitMask]]()<br />
<br />
* [[FlipScreen]]()<br />
* [[GetKey]]()<br />
* [[GetScreenHeight]]()<br />
* [[GetScreenWidth]]()<br />
* [[LoadImage]]()</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Legacy:Image/blit&diff=349Legacy:Image/blit2013-03-27T02:44:00Z<p>Flying Jester: Created page with "Draw the image onto the screen. =Usage= ::''image''.blit(''x'', ''y''); * '''image''' Sphere Image object. The image to draw on screen. * '''x''' number. The x coordinat..."</p>
<hr />
<div>Draw the image onto the screen.<br />
<br />
=Usage=<br />
::''image''.blit(''x'', ''y'');<br />
<br />
* '''image''' Sphere [[Image]] object. The image to draw on screen.<br />
* '''x''' number. The x coordinate of the top-left corner of the drawn image.<br />
* '''y''' number. The y coordinate of the top-left corner of the drawn image.<br />
<br />
=Examples=<br />
<br />
This simple game will take an image and blit it onto the screen..<br />
<br />
<syntaxhighlight><br />
function game()<br />
{<br />
var w = GetScreenWidth();<br />
var h = GetScreenHeight();<br />
var img = LoadImage("my_test_image.png");<br />
<br />
//Blit the image.<br />
img.blit(16, 16);<br />
<br />
FlipScreen();<br />
GetKey();<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
<br />
=Notes=<br />
<br />
* [[Image.blitMask]]() can also be used to blit an image to the screen, but with a tinting color. <br />
<br />
<br />
=See also=<br />
<br />
* Sphere [[Image]] object <br />
<br />
* [[Image.blitMask]]()<br />
<br />
* [[FlipScreen]]()<br />
* [[GetKey]]()<br />
* [[GetScreenHeight]]()<br />
* [[GetScreenWidth]]()<br />
* [[LoadImage]]()</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Legacy:Image/zoomBlit&diff=348Legacy:Image/zoomBlit2013-03-27T02:40:47Z<p>Flying Jester: Created page with "Draw the image onto the screen with zooming. =Usage= ::''image''.zoomBlit(''x'', ''y'', ''factor''); * '''image''' Sphere Image object. The image to draw on screen. * ''..."</p>
<hr />
<div>Draw the image onto the screen with zooming.<br />
<br />
=Usage=<br />
::''image''.zoomBlit(''x'', ''y'', ''factor'');<br />
<br />
* '''image''' Sphere [[Image]] object. The image to draw on screen.<br />
* '''x''' number. The x coordinate of the top-left corner of the drawn image.<br />
* '''y''' number. The y coordinate of the top-left corner of the drawn image.<br />
* '''factor''' number, floating-point. The amount of zooming applied. factor == 1 causes no zoom, 0 < factor < 1 causes the image to shrink, factor > 1 causes the image to enlarge. <br />
<br />
<br />
=Examples=<br />
<br />
This simple game will take an image and zoom it so that it is stretched to fit the screen.<br />
<br />
<syntaxhighlight><br />
function game()<br />
{<br />
var w = GetScreenWidth();<br />
var h = GetScreenHeight();<br />
var img = LoadImage("my_test_image.png");<br />
<br />
// Calculate by how much to zoom.<br />
var factor = Math.min(w / img.width, h / img.height);<br />
<br />
img.zoomBlit(0, 0, factor);<br />
<br />
FlipScreen();<br />
GetKey();<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
<br />
=Notes=<br />
<br />
* [[Image.transformBlit()]] can also be used to achieve zooming, by picking the corner points manually. <br />
<br />
<br />
=See also=<br />
<br />
* Sphere [[Image]] object <br />
<br />
* [[Image.blit]]()<br />
* [[Image.transformBlit]]()<br />
* [[Image.transformBlitMask]]()<br />
<br />
* [[FlipScreen]]()<br />
* [[GetKey]]()<br />
* [[GetScreenHeight]]()<br />
* [[GetScreenWidth]]()<br />
* [[LoadImage]]()</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=347User:Flying Jester/TurboSphere API2013-03-26T07:15:47Z<p>Flying Jester: </p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.2.1. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* SetClippingRectangle(x, y, w, h)<br />
:: Sets the clipping rectangle of the screen.<br />
<br />
* GetClippingRectangle()<br />
:: Returns and object with properties x, y, w, and h, that represents the clipping rectangle of the screen.<br />
<br />
* SetTitle(title)<br />
:: Sets the title of the game window.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
* SetResolution(w, h)<br />
:: Sets the game window's resolution to w, h.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Surfaces and Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* Surface<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface_or_image.getPixel(x, y)<br />
:: Returns a [[color]] object of the color of the Surface or Image at 'x', 'y'.<br />
<br />
* surface_or_image.setPixel.(x, y, [[color]])<br />
:: Sets the color of the pixel x, y of surface_or_image to 'color'.<br />
<br />
* surface_or_image.rectangle(x, y, w, h, [[color]])<br />
:: Draws a rectangle on surface_or_image at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface_or_image.zoomBlit(x, y, f)<br />
:: Blits surface_or_image at x, y, zoomed by factor f. A factor of 1 is the same as a normal blit.<br />
<br />
:: As of 0.2.2a, the surface is imperfectly drawn at factors not divisible by 1/2.<br />
<br />
* surface_or_image.stretchBlit(x, y, hf, vh)<br />
:: Blits surface_or_image at x, y, with a horizontal scaling factor of hf and a vertical scaling factor of vf. Factors of 1 are the same as a normal blit.<br />
<br />
<br />
* surface_or_image.blitSurface(surface_or_image_object, x, y)<br />
:: Blits surface_or_image_object onto surface_or_image at x, y.<br />
<br />
* GetSystemArrow()<br />
:: Returns an image of the system arrow. The image used is set in system/system.ini.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* Point(x, y, [[color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, c1, c2, c3, c4)<br />
:: Draws a rectangle at x, y, with a width of w and a height of h. The color is faded from c1 to c4 around the corners, moving clockwise from the upper left corner.<br />
<br />
* FilledCircle(x, y, r, [[color]])<br />
::Draws a circle of radius r centered at x, y, filled with 'color'.<br />
<br />
* OutlinedCircle(x, y, r, [[color]]<br />
::Draws an outline of a circle of radius r centered at x, y with 'color'.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
*font.gatStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
==File Object==<br />
<br />
* File(filename)<br />
:: Returns a file object of 'filename'. If the file doesn't exist, it creates it.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("save");<br />
</syntaxhighlight><br />
<br />
* file.read(key, default)<br />
:: Gets the value assigned to 'key' from 'file'. If 'key' does not exist, it creates it with the value 'default'.<br />
<br />
* file.write(key, value)<br />
:: Writes 'value' and assigns it to 'key' in file. If the key already existed, it overwrites it.<br />
<br />
* file.flush()<br />
:: Flushes changes to file, in case you don't want wait. Normally changes are flushed in a timely manner, and whenever the file is closed.<br />
<br />
* file.close()<br />
:: Closes the handle to 'file', and flushes changes. 'file' can then be assigned a new value and used again.<br />
::; Example:<br />
<syntaxhighlight><br />
var file1 = new File("savefile1.save"); //create the file 'newfile.save' in the save directory.<br />
<br />
file1.write("Lives", "3"); //write a value to the file.<br />
<br />
file1.flush();<br />
file1.close(); //Close the file.<br />
<br />
//...<br />
<br />
file1 = new File("savefile2.save"); //create another save file.<br />
<br />
<br />
file1.write("Lives", "5"); //write a value to the file. Everyone knows the second save file is the best one.<br />
<br />
file1.flush();<br />
file1.close(); //Close the second file.<br />
</syntaxhighlight><br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/TurboSphere_API&diff=346User:Flying Jester/TurboSphere API2013-03-26T03:20:23Z<p>Flying Jester: Created page with "This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.2.1. It is sorted by which plugin the function is provided by, and contains list..."</p>
<hr />
<div>This page documents the TurboSphere API. Currently, it is up to date for TurboSphere version 0.2.1. It is sorted by which plugin the function is provided by, and contains lists for all the plugins included with the standard TurboSphere distribution.<br />
<br />
__TOC__<br />
<br />
=Engine Functions=<br />
<br />
* RequireScript(filename)<br />
:: Compiles the indicated script and executes it.<br />
<br />
* GetVersion()<br />
:: Returns a number representation of the version of TurboSphere. Until TurboSphere 1.0, this number does not have a fixed meaning.<br />
<br />
* GetVersionString()<br />
:: Returns a string representation of the version of TurboSphere. This number also represents the versions of all the default plugins (they all share this same version number). For example: "0.2.2a"<br />
<br />
===Time Functions===<br />
<br />
* GetTime()<br />
:: Returns the number of milliseconds passed since a set point in time.<br />
<br />
* Delay(ms)<br />
:: Idles the engine for 'ms' seconds. This cedes CPU time to other programs, and allows TurboSphere to use less than 100% of available CPU time.<br />
<br />
=GraphicSDL Functions=<br />
<br />
===Screen Control===<br />
<br />
* FlipScreen()<br />
:: Draws the framebuffer to the screen. You must call this before anything you blit or draw will be visible.<br />
<br />
* SetClippingRectangle(x, y, w, h)<br />
:: Sets the clipping rectangle of the screen.<br />
<br />
* GetClippingRectangle()<br />
:: Returns and object with properties x, y, w, and h, that represents the clipping rectangle of the screen.<br />
<br />
* SetTitle(title)<br />
:: Sets the title of the game window.<br />
<br />
* GetScreenHeight()<br />
:: Returns the height of the game window in pixels.<br />
<br />
* GetScreenWidth()<br />
:: Returns the width of the game window in pixels.<br />
<br />
* SetResolution(w, h)<br />
:: Sets the game window's resolution to w, h.<br />
<br />
===Colors===<br />
<br />
* Color(r, g, b [, a])<br />
:: Creates a color object with the specified values. Alpha is optional.<br />
::; Example:<br />
<syntaxhighlight><br />
var Red = new Color(255, 0, 0); //Red's alpha channel defaults to 255.<br />
var NoColor = new Color(0, 0, 0, 0); //Fully transparent!<br />
</syntaxhighlight><br />
<br />
===Surfaces and Images===<br />
<br />
* Image(...)<br />
:: Creates an image object that is held in video memory and handled by graphics hardware, if possible.<br />
::; Example:<br />
<syntaxhighlight><br />
var image1 = new Image("imagefile.png"); //Creates an Image of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var image2 = new Image(16, 16, new Color(255, 0, 0, 255)); //Creates an Image of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* Surface<br />
:: Creates a surface object that is held in system memory and modified in software. Surfaces are faster than Images to modify (ie, with surface.setPixel or surface.rectangle), but slower to blit to the screen. Blits of surfaces onto images or images onto surfaces are much slower than blitting images onto images or surfaces onto surfaces.<br />
::; Example:<br />
<syntaxhighlight><br />
var surface1 = new Surface("imagefile.png"); //Creates a Surface of the file imagefile.png in the images folder.<br />
<br />
//or...<br />
<br />
var surface2 = new Surface(16, 16, new Color(255, 0, 0, 255)); //Creates a Surface of size 16 by 16 pixels filled with a red color.<br />
<br />
</syntaxhighlight><br />
<br />
* surface_or_image.getPixel(x, y)<br />
:: Returns a [[color]] object of the color of the Surface or Image at 'x', 'y'.<br />
<br />
* surface_or_image.setPixel.(x, y, [[color]])<br />
:: Sets the color of the pixel x, y of surface_or_image to 'color'.<br />
<br />
* surface_or_image.rectangle(x, y, w, h, [[color]])<br />
:: Draws a rectangle on surface_or_image at 'x', 'y', of width 'w' and height 'h' and fills it with 'color'.<br />
<br />
* surface_or_image.zoomBlit(x, y, f)<br />
:: Blits surface_or_image at x, y, zoomed by factor f. A factor of 1 is the same as a normal blit.<br />
<br />
:: As of 0.2.2a, the surface is imperfectly drawn at factors not divisible by 1/2.<br />
<br />
* surface_or_image.stretchBlit(x, y, hf, vh)<br />
:: Blits surface_or_image at x, y, with a horizontal scaling factor of hf and a vertical scaling factor of vf. Factors of 1 are the same as a normal blit.<br />
<br />
<br />
* surface_or_image.blitSurface(surface_or_image_object, x, y)<br />
:: Blits surface_or_image_object onto surface_or_image at x, y.<br />
<br />
* GetSystemArrow()<br />
:: Returns an image of the system arrow. The image used is set in system/system.ini.<br />
<br />
===Graphics Primitives===<br />
<br />
* Line(x1, y1, x2, y2, [[color]])<br />
:: Draws a line of 'color' from x1, y1, to x2, y2.<br />
<br />
* Point(x, y, [[color]])<br />
:: Draws a point of 'color' at x, y.<br />
<br />
* Rectangle(x, y, w, h, [[color]])<br />
:: Draws a rectangle of 'color' width w and height h at x, y.<br />
<br />
* GradientRectangle(x, y, w, h, c1, c2, c3, c4)<br />
:: Draws a rectangle at x, y, with a width of w and a height of h. The color is faded from c1 to c4 around the corners, moving clockwise from the upper left corner.<br />
<br />
* FilledCircle(x, y, r, [[color]])<br />
::Draws a circle of radius r centered at x, y, filled with 'color'.<br />
<br />
* OutlinedCircle(x, y, r, [[color]]<br />
::Draws an outline of a circle of radius r centered at x, y with 'color'.<br />
<br />
=BMPFontSDL=<br />
<br />
* Font(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var font1 = new Font("arial.rfn"); //font1 is a font object based on the font arial.rfn in the fonts folder.<br />
var font2 = new Font("../../system/system.rfn"); //Opens the system rfn font. The actual; system font is not guaranteed to be this particular file.<br />
</syntaxhighlight><br />
<br />
* font.drawText(x, y, str)<br />
:: Draws 'str' using 'font' at 'x', 'y'.<br />
<br />
*font.gatStringWidth(str)<br />
:: Returns the width of 'str' as drawn by 'font'.<br />
<br />
* GetSystemFont()<br />
:: Returns a Font object representing the system font. The system font can be specified in the system/system.ini file, but by default is system/system.rfn.<br />
<br />
=TTFFontSDL=<br />
<br />
* TTFFont(filename)<br />
:: Creates a bmpfont object of the sphere rfn file 'filename' from the fonts folder.<br />
<syntaxhighlight><br />
var ttffont1 = new TTFFont("DejaVuSans.ttf"); //ttffont1 is a ttffont object based on the True Type font DejaVuSans.ttf in the fonts folder.<br />
</syntaxhighlight><br />
<br />
* ttffont.drawText(x, y, str)<br />
:: Draws 'str' using 'ttffont' at 'x', 'y'.<br />
<br />
=InputSDL=<br />
<br />
==KeyBoard==<br />
<br />
===Key Constants===<br />
<br />
:The following variables are defined for use as key constants:<br />
<syntaxhighlight><br />
KEY_ENTER<br />
KEY_A<br />
KEY_B<br />
KEY_C<br />
KEY_D<br />
KEY_E<br />
KEY_F<br />
KEY_G<br />
KEY_H<br />
KEY_I<br />
KEY_J<br />
KEY_K<br />
KEY_L<br />
KEY_M<br />
KEY_N<br />
KEY_O<br />
KEY_P<br />
KEY_Q<br />
KEY_R<br />
KEY_S<br />
KEY_T<br />
KEY_U<br />
KEY_V<br />
KEY_W<br />
KEY_X<br />
KEY_Y<br />
KEY_Z<br />
KEY_TAB<br />
KEY_ESCAPE<br />
KEY_F1<br />
KEY_F2<br />
KEY_F3<br />
KEY_F4<br />
KEY_F5<br />
KEY_F6<br />
KEY_F7<br />
KEY_F8<br />
KEY_F9<br />
KEY_F10<br />
KEY_F11<br />
KEY_F12<br />
KEY_F13<br />
KEY_F14<br />
KEY_F15<br />
KEY_TILDE<br />
KEY_0<br />
KEY_1<br />
KEY_2<br />
KEY_3<br />
KEY_4<br />
KEY_5<br />
KEY_6<br />
KEY_7<br />
KEY_8<br />
KEY_9<br />
KEY_MINUS<br />
KEY_EQUALS<br />
KEY_BACKSPACE<br />
KEY_SHIFT<br />
KEY_RSHIFT<br />
KEY_CAPSLOCK<br />
KEY_NUMLOCK<br />
KEY_SCROLLOCK<br />
KEY_CTRL<br />
KEY_RCTRL<br />
KEY_ALT<br />
KEY_RALT<br />
KEY_SPACE<br />
KEY_OPENBRACE<br />
KEY_CLOSEBRACE<br />
KEY_SEMICOLON<br />
KEY_APOSTROPHE<br />
KEY_COMMA<br />
KEY_PERIOD<br />
KEY_SLASH<br />
KEY_BACKSLASH<br />
KEY_INSERT<br />
KEY_DELETE<br />
KEY_HOME<br />
KEY_END<br />
KEY_PAGEUP<br />
KEY_PAGEDOWN<br />
KEY_UP<br />
KEY_RIGHT<br />
KEY_DOWN<br />
KEY_LEFT<br />
KEY_NUM_0<br />
KEY_NUM_1<br />
KEY_NUM_2<br />
KEY_NUM_3<br />
KEY_NUM_4<br />
KEY_NUM_5<br />
KEY_NUM_6<br />
KEY_NUM_7<br />
KEY_NUM_8<br />
KEY_NUM_9<br />
KEY_NUM_PERIOD<br />
KEY_NUM_DIVIDE<br />
KEY_NUM_MULTIPLY<br />
KEY_NUM_MINUS<br />
KEY_NUM_EQUALS<br />
KEY_RMETA<br />
KEY_LMETA<br />
KEY_RSUPER<br />
KEY_LSUPER<br />
KEY_BREAK<br />
KEY_MENU<br />
KEY_POWER<br />
KEY_EURO<br />
</syntaxhighlight><br />
Note that not all keys are available on all keyboards.<br />
<br />
===Keyboard Functions===<br />
<br />
* IsKeyPressed(key)<br />
:: Checks whether or not 'key', as expressed by a key constant, is pressed.<br />
<br />
* IsAnyKeyPressed()<br />
:: Returns true if any key is pressed, false if not.<br />
<br />
* GetKey()<br />
:: Returns a key from the key buffer. If no keys are available, waits until one is.<br />
<br />
* AreKeysLeft()<br />
:: Checks whether there are keys in the key buffer.<br />
<br />
==Mouse==<br />
<br />
===Mouse Button Constants===<br />
<br />
:The following mouse button constants are defined:<br />
<syntaxhighlight><br />
MOUSE_LEFT<br />
MOUSE_RIGHT<br />
MOUSE_MIDDLE<br />
MOUSE_SUP<br />
MOUSE_SDOWN<br />
</syntaxhighlight><br />
<br />
===Mouse Functions===<br />
<br />
* GetMouseX()<br />
:: Returns the X coordinate of the mouse in the window.<br />
<br />
* GetMouseY()<br />
:: Returns the Y coordinate of the mouse in the window.<br />
<br />
* IsMouseButtonPressed(button)<br />
:: Checks whether or not 'button', as expressed by a mouse button constant, is pressed.<br />
<br />
==JoyStick Functions==<br />
<br />
===Joystick Management===<br />
<br />
* GetNumJoysticks()<br />
:: Returns the number of available joysticks.<br />
<br />
* GetJoystickName(n)<br />
:: Returns the name of joystick number 'n'.<br />
<br />
===Joystick Access===<br />
<br />
* GetNumJoystickButtons(n)<br />
:: Returns the number of buttons on joystick number 'n'.<br />
<br />
* GetNumJoystickAxes(n)<br />
:: Returns the number of axes (ie, analog stick axes, analog triggers, throttles) on joystick number 'n'.<br />
<br />
* IsJoystickButtonPressed(jsNum, buttonNum)<br />
:: Checks whether or not button number 'buttonNum' is pressed on joystick number 'jsNum'.<br />
<br />
* GetJoystickAxis(jsNum, axisNum)<br />
:: Returns the position of axis number 'axisNum' on joystick number 'jsNum', between -32768 and 32767.<br />
<br />
=ScriptFS=<br />
<br />
==FileSystem Function==<br />
<br />
* GetFileList(directory)<br />
:: Returns an array of filenames in the given directory. The base directory is the save directory, but you can use '..' to go up levels. There is no sandboxing, and you can access the entire filesystem of the computer with this function.<br />
<br />
* RemoveFile(filename)<br />
:: Deletes the file 'filename'.<br />
<br />
=WindowStylesSDL=<br />
<br />
* WindowStyle(filename)<br />
:: Creates a WindowStyle from 'filename' in the windowstyles directory.<br />
::;Example:<br />
<syntaxhighlight><br />
var ws1 = new WindowStyle("my_windowstyle.rws");<br />
</syntaxhighlight><br />
<br />
* windowstyle.drawWindow(x, y, w, h)<br />
:: Draws 'windowstyle' at 'x', 'y', with a width of 'w' and a height of 'h'.<br />
<br />
=GetKeyString=<br />
<br />
* getkeystring(key [, shift])<br />
:: Returns an ascii character that represents the key constant 'key'. If 'shift' is true, then it the character is represented as though the shift key is pressed.</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=Sphere&diff=345Sphere2013-03-25T23:57:51Z<p>Flying Jester: </p>
<hr />
<div>__NOTOC__<br />
<br />
Sphere is a cross platform, open source computer program designed primarily to make role-playing games (RPGs) similar to those found on the SNES and Sega Genesis consoles. Sphere was originally coded by [http://chadaustin.me Chad Austin]. When making a game with Sphere, most things are scripted using the [http://developer.mozilla.org/en/docs/JavaScript JavaScript] language (though very early versions used its own Spherescript language) with special functions and objects for maps, spritesets, images and other resources.<br />
<br />
Though Sphere was designed to make RPGs, because of the flexibility of a scripting language it can be used to make almost any other type of game.<br />
<br />
Recent versions of Sphere also support basic 3D graphics functions using the OpenGL video driver. However, it is more complicated to use than the 2D graphics functions and is still in early stages.<br />
<br />
==Screenshots==<br />
''updated screenshots to come''<br />
<br />
==Download==<br />
''updated download links to come''<br />
<br />
==External links==<br />
* http://sphere.sourceforge.net/ - The original official Sphere website (needs maintenance)<br />
* http://github.com/sphere-group - Sphere development on GitHub<br />
* http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference - Mozilla's official JavaScript reference<br />
* http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide - Mozilla's JavaScript guide</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/Making_Plugins&diff=212User:Flying Jester/Making Plugins2013-03-21T02:20:10Z<p>Flying Jester: /* Getting Started */</p>
<hr />
<div>[[Category:Tutorials]]<br />
This is a tutorial/guide for making a plugin for TurboSphere. At the moment (about 03/25/2013) it is made with TurboSphere 0.2.1 (or 0.2.0) in mind.<br />
<br />
==Forward==<br />
<br />
Before we begin, I have to preface this. If you know nothing of C or C++, and don't plan on learning it, you probably will not be able to make a plugin. And if you are making a plugin before TurboSphere 1.0 is released, you may end up with a plugin that won't work with the first official release of TurboSphere. The API probably won't change too much between then and now, though, so this should at least get you up and running with the basics.<br />
<br />
Here I cover making a plugin that works for GCC-style toolchains (GCC, Clang, MingW, etc.), and MSVC style (MSVC cl.exe and DMC cl.exe) compilers. TurboSphere has traditionally been for Linux *and* Windows, 32 and 64 bit, after all, and I highly recommend at least making an attempt at cross compatibility.<br />
<br />
==Getting Started==<br />
<br />
Personally, I write plugins in C++. I know that is easy. It shouldn't be too hard to write it in C, either. But, I do know a C++ shim is necessary for any language other than C++, since to interface with V8 you need access to the C++ template library. If you know of another language that can interface directly with C++ STL libraries, go ahead and try to use that. I'd like to hear about it! :)<br />
<br />
I'm going to assume you are using the "plugin.h" file that is included with the TurboSphere source (plugins/common/plugins.h). I used this to make all the plugins included with TurboSphere. It might not be the best way to do this, but it's the set of tools I worked out from my years of making TurboSphere.<br />
<br />
If you look at windowstyleSDL, you can see a nice example of using plugins.h. But for one learn better with examples and explanations, so let's have a look at some example code explained.<br />
<br />
First, the header file. It uses preprocessor defines to ensure the plugin works both with the GCC on Linux and MSVC on Windows. I don't have an Intel Mac (V8 requires an x86, ARM, or MIPS CPU, so my old PPC Macs aren't going to work), so this would likely need a little something more to work on Mac.<br />
<br />
<syntaxhighlight lang="cpp"><br />
//windowstyleSDL.h:<br />
#ifndef WINDOWSTYLE_HEAD<br />
#define WINDOWSTYLE_HEAD<br />
<br />
#ifdef _WIN32<br />
#define WS_EXPORT __declspec(dllexport)<br />
<br />
#define CCALL __cdecl<br />
<br />
#endif<br />
#ifndef _WIN32<br />
#define CCALL <br />
#define WS_EXPORT extern "C"<br />
#endif<br />
<br />
#ifdef _WIN32<br />
extern "C" {<br />
#endif<br />
WS_EXPORT void CCALL Close(void);<br />
WS_EXPORT initFunction CCALL Init(void);<br />
WS_EXPORT int CCALL GetNumFunctions(void);<br />
WS_EXPORT functionArray CCALL GetFunctions(void);<br />
WS_EXPORT nameArray CCALL GetFunctionNames(void);<br />
WS_EXPORT int CCALL GetNumVariables(void);<br />
WS_EXPORT v8FunctionArray CCALL GetVariables(void);<br />
WS_EXPORT nameArray CCALL GetVariableNames(void);<br />
<br />
#ifdef _WIN32<br />
}<br />
#endif<br />
<br />
#endif<br />
</syntaxhighlight><br />
<br />
Here we forward declares the mandatory functions of a plugin. The macros ensure it will compile and present the proper symbols for runtime loading on to TurboSphere on both Linux using the GCC and Windows with the MSVC.<br />
<br />
Now on to the main windowstyleSDL.cpp file:<br />
<br />
<syntaxhighlight lang="cpp"><br />
#include "../common/plugin.h"<br />
#include "windowstyleSDL.h"<br />
<br />
//This will be explained later.<br />
#define NUMFUNCS 2<br />
<br />
//forward declare C++ functions to be bound to JS<br />
v8Function LoadWindowStyle(V8ARGS);<br />
v8Function GetSystemWindowStyle(V8ARGS);<br />
<br />
//declare pointers to functions that will be passed to the engine to be bound<br />
void* LoadWindowStylePointer = V8FUNCPOINTER(LoadWindowStyle);<br />
void* GetSystemWindowStylePointer = V8FUNCPOINTER(GetSystemWindowStyle);<br />
<br />
</syntaxhighlight><br />
<br />
This is the start of windowstyle.cpp. Here, we include plugin.h, we forward declare the functions to be exposed to script, and then void pointers that point to the functions. That last part will be useful later.<br />
<br />
<syntaxhighlight lang="cpp"><br />
initFunction Init(){<br />
//Initialize the JS-side object templates<br />
INIT_OBJECT_TEMPLATES(WindowStyle);<br />
ADD_TO_PROTO(WindowStyle, "drawWindow", TS_WSdrawWindow);<br />
<br />
//return plugin's name to the engine.<br />
return (char *)"windowstyleSDL";<br />
}<br />
</syntaxhighlight><br />
<br />
Here we define the Init function. Every plugin must have an exposed Init function. This is called by TurboSphere for two reasons. The simple use is that it tells TurboSphere the plugin's name. It is guaranteed to be called before anything else. With this in mind, what are those other macros being called? the INIT_OBJECT_TEMPLATES and ADD_TO_PROTO? Well, let's look at one more function before we talk about that:<br />
<br />
<syntaxhighlight lang="cpp"><br />
void Close(){<br />
//Dispose of JS-side templates.<br />
CLOSE_OBJECT_TEMPLATES(WindowStyle);<br />
}<br />
</syntaxhighlight><br />
<br />
OK, this is the Close function. It's to be called when we are done with the plugin, and it will definitely be called after each call to Init before Init is called again. We can't be sure that Close will be called--what if TurboSphere hard-crashes? But we always do our best to call it before TurboSphere quits.<br />
<br />
So there's another macro. CLOSE_OBJECT_TEMPLATES. Well, unsurprisingly, that is the counterpart to INIT_OBJECT_TEMPLATES. They automate the process of making templates for binding C++ objects to JS. You can check out the details in the plugins.h file, but if you don't want to know the details just let it be. So far only one function in all of TurboSphere and the default plugins needs more knowhow than this, and in that case it wasn't necessary to not do it that way anyway.<br />
<br />
Both macros are passed a name, WindowStyle. This isn't defined before, as the macros define several objects using that name. Just pass them all the same name for the same object type, and it will work. The INIT_OBJECT_TEMPLATES macro creates the templates to create, wrap, and modify the prototypes of C++ to JS-side objects. The second macro, ADD_TO_PROTO, is an example of the latter. It binds the C++ function TS_WSdrawWindow to the JS_side object type that WindowStyle defines, and gives it the JS-side name drawWindow (windowstyle_object.drawWindow()). The CLOSE_OBJECT_TEMPLATES macro undefines the object template defined by WindowStyle, which cleans things out in JS (and gives back a bit of memory, ideally, although it doesn't actually work out this way for sure; V8 plays it fast and loose with memory when it thinks it can trade memory for speed).<br />
<br />
Let's have a look at the remaining mandatory functions of a plugin.<br />
<br />
<syntaxhighlight lang="cpp"><br />
int GetNumFunctions(){<br />
return NUMFUNCS;<br />
}<br />
<br />
int GetNumVariables(){<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
These functions return the number of variables and functions to be exposed to script. windowstyleSDL does not define any variables for script, but I will go over how that is done later anyway. For the moment, suffice it to say that it is simpler than exposing functions.<br />
<br />
<syntaxhighlight lang="cpp"><br />
//to simplify numbering functions and names.<br />
int numerate(bool reset){<br />
static int i = 0;<br />
if(reset) {<br />
i = 0;<br />
return 0;<br />
}<br />
i++;<br />
return i-1;<br />
}<br />
<br />
functionArray GetFunctions(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
functionArray funcs = (functionArray)calloc(NUMFUNCS, sizeof(void*));<br />
<br />
funcs[numerate(false)] = LoadWindowStylePointer;<br />
funcs[numerate(false)] = GetSystemWindowStylePointer;<br />
//return array of function pointers to to the engine.<br />
return funcs;<br />
}<br />
</syntaxhighlight><br />
<br />
The first function is just to simplify numbering the elements of arrays. You don't need to use it, but I found it quite useful when writing the inputSDL function which has well over a hundred variables defined (one for each key on a keyboard and several for mouse buttons).<br />
<br />
The second function is necessary, though. First we reset the numeration function to zero. Then we define the array of functions to be exposed. This is where those void pointers to the functions that will be exposed to V8 come in handy.<br />
<br />
On a side note: GCC gets a little angry at all this, throwing a warning since you aren't supposed to play with void pointers this way, but as far as I know you can do this on any compiler and it will work out. If you were really worried about warnings (instead of actual definite problems--don't think I don't take warnings eriously, give me minute!), you could probably pass them simply as pointers to the V8 functions, as they will be cast as void pointers in TurboSphere. But in that case you are just masking any problems! The compiler won't complain because the cast is made in between two binaries, and it can't see what is happening. If this is really a problem, then the compiler will give you an error--but only if it can see what you are doing. And yes, I could cast them as v8Function's on the TurboSphere side, but because of the...fluidity of JavaScript, there are some things that can be functions that you would then not be able to pass through to TurboSphere as such (JS can be wily beast, and is very much <br />
not like C++ when it comes to letting you pass of something as something else). I don't want to limit anything here just because the functionality is in a plugin, so I do it this way. [/sidenote]<br />
<br />
So, what about a GetVariables function?<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8FunctionArray GetVariables(){<br />
return NULL;<br />
}<br />
</syntaxhighlight><br />
<br />
If you have no variables, you can just return NULL. The function won't even be called by TurboSphere, anyway. And even if it was, NULL is an acceptable value; you can't read from an empty array, so it doesn't matter what the address of it is, and it has no data! It's what calloc would have returned had you told it to give you an array of zero size, too.<br />
<br />
I actually do have something to say about this when there are variables, so let's assume we had four variables to define. Let's say their names are SOME_NAME, VERSION, CONSTANT1 and CONSTANT2, in that order, just for sake of explanation. The function would then look like this<br />
<br />
<syntaxhighlight lang="cpp"><br />
//theoretical GetVariables<br />
v8FunctionArray GetVariables(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
nameArray varnames = (nameArray)calloc(NUMVARS, sizeof(v8Function));<br />
funcnames[numerate(false)] = v8::String::New("This Is A Name!"); //SOME_NAME<br />
funcnames[numerate(false)] = v8::Number::New(1.5); //VERSION<br />
funcnames[numerate(false)] = v8::Integer::New(0); //CONSTANT1<br />
funcnames[numerate(false)] = v8::Integer::New(1); //CONSTANT2<br />
return varnames;<br />
}<br />
</syntaxhighlight><br />
<br />
Here's an example of V8 and JS being very fluid with things; anything that can be a function can also be variable, and we use v8Function as the type for variables. The only time the opposite would not be true is when you deal with constructors that are strongly tied to the templates for JS-side objects. I'm not doing things that way, and in several cases multiple functions can be used as constructors for a single type, and V8 won't let me tell it there are two constructors for a single JS-side type (they bind slightly different kinds of objects on the C++ side). In any case, these are a few of the types you could pass back as variables.<br />
<br />
So, let's get on with what is actually a part of windowstyleSDL!<br />
<br />
<syntaxhighlight lang="cpp"><br />
nameArray GetFunctionNames(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
nameArray funcnames = (nameArray)calloc(NUMFUNCS, sizeof(functionName));<br />
<br />
funcnames[numerate(false)] = (functionName)"WindowStyle";<br />
funcnames[numerate(false)] = (functionName)"GetSystemWindowStyle";<br />
//return array of c-string function names to the engine.<br />
return funcnames;<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
This is much like the GetFunctions function, but in this case, since the names are hardcoded right there, we just tell the compiler to think of them as the type functionName (aka const char*, GCC throws a warning if you don't cast them this way, but unlike before it makes no difference to me if they are cast that way or not, so I do to limit the number of warnings when compiling), and be on our merry way. The names of variables are defined the same way, except the function would be called GetVariableNames, and we would use the type variableName instead of functionName (both are const char*, but why use a type like functionName with a misleading name? GetVariables notwithstanding!).<br />
<br />
And unsurprisingly<br />
<br />
<syntaxhighlight lang="cpp"><br />
nameArray GetVariableNames(){<br />
return NULL;<br />
}<br />
</syntaxhighlight><br />
<br />
Same deal here as with GetVariables. <br />
<br />
So that's it! Technically, this is everything you *need* for a plugin. If you defined GetNumFunctions to return 0, and GetFunctions and getFunctionNames to return NULL this would be perfectly functional (although totally useless) plugin. But you probably want your plugin to do something, right? <br />
<br />
Well, let's look at a single function that can be used by V8. There are a whole lot ways to do this, I might add, but this is how I've been doing it. If you want to do it a different way, be my guest.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function TestFunction(V8ARGS){<br />
return v8::Integer::New(42)<br />
}<br />
</syntaxhighlight><br />
<br />
Well, it doesn't do much. But if you passed a pointer to this function as one of the elements returned by GetFunctions, and then in JS called whatever name you gave it as a function, it would return 42 in JS. But, that's simple. In fact, you might well have been able to figure out most of that from what I went over in the theoretical GetVariables function. Let's look deeper.<br />
<br />
What if you want to deal with arguments? That's pretty simple, and it lets me show off some nice macros in plugin.h.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function ArgsTestFunction(V8ARGS){<br />
if(args.Length()<1){<br />
THROWERROR("ArgsTestFunction Error: Called with no arguments.");<br />
}<br />
CHECK_ARG_INT(0, "ArgsTestFunction Error: Argument 0 is not an integer.");<br />
<br />
int i = args[0]->IntegerValue();<br />
<br />
if(i==0){<br />
return v8::Integer::New(42);<br />
}<br />
else {<br />
return v8::String::New("That number was not 0!");<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
In this case, we have to deal with arguments. I have one thing that I cannot stress enough about arguments.<br />
<br />
Programmers are stupid and lazy. Even you, my friend, even me. So we can count on them passing garbage to our functions. I know I pass garbage to functions all the time, and even if they are really good programmers and rarely make that kind of mistake, these checks are useful for telling you where things went wrong. If you ever plan on using your own plugin, you will thank yourself for adding as many checks as possible.<br />
<br />
The first one is the check for the numebr of args. You could just as easily default to something, but this a good example of the THROWERROR macro, a paper thin wrapper around returning a v8::ThrowException function. It throws a JS-side exception with the text you give. It can be caught by script as well, which is a *good* *thing*. I recommend you put the function name into the error message. And I highly recommend you give some explanation for why the exception happened at all. Don't be shy about being specific, either.<br />
<br />
Simpler to do (with the help of plugin.h) is the check of parameter types. There exist several macros to check them for you:<br />
<br />
* CHECK_ARG_INT<br />
* CHECK_ARG_STR<br />
* CHECK_ARG_OBJ<br />
* CHECK_ARG_BOOL<br />
* CHECK_ARG_ARRAY<br />
<br />
Bear in mind that JS is a wily language when it comes to data validation. If you are using the OBJ or ARRAY checks, you might either rule out valid values or include values you don't want to. But the explanation of such things is beyond the scope here.<br />
<br />
These macros check the argument specified in the first parameter (here 0, the first arg), and throw the error specified in the second parameter if it is not the right type. Bear in mind, this doens't mean that it couldn't be cast to the right type, just that it isn't right now. Generally I would err on the side of throwing out edge-case-correct values than accepting bad values that seem like they might be OK. Better to throw a JS exception than to either make V8 die (which is ugly and won't tell you as much about what went wrong), or pass garbage into a C++ or C function, which can quite easily cause crashes. It can cause hard crashes, and we really don't want hard crashes. We really, really don't want them. Anytime you can stop one from happening, I'd really like you too. Every time a user has to use a task manager to close TurboSphere, they think that anyone who had a hand in making it, the game they are playing with it, or any plugins they use, are bad programmers. And this right here, this is where most <br />
crashes come from.<br />
<br />
So next we need to make the argument, which is a V8 type, into a C/C++ type. First, ask yourself, are you sure that only the correct type of value could have gotten to this cast (no really, this is important)? Good. There are a few easy ways to do this:<br />
<br />
<syntaxhighlight lang="cpp"><br />
int x = args[i]->IntegerValue();<br />
int x = args[i]->Int32Value();<br />
</syntaxhighlight><br />
<br />
Bear in mind that you will get some weirdness with this when you try to compile on both 32-bit and 64-bit architectures. IntegerValue returns a 64-bit integer, and Int32Value returns a 32-bit integer. You could avoid compiler warnings by using a fixed with type (int64_t), or by using some ugly preprocessor stuff. My recommendation is just to only go with 64-bits, but I know I'm not in charge of what word-length users' computers are, so just listen to your compiler of choice's warnings for what to do. If it doesn't complain, then don't worry about it--but bear in mind that TurboSphere will, one day somewhat soon, be 64-bit only, and possibly only able to load 64-bit plugins. At least think about making your code 64-bit safe if you want your plugin to stick around.<br />
<br />
<syntaxhighlight lang="cpp"><br />
bool x = args[i]->BooleanValue();<br />
</syntaxhighlight><br />
<br />
That one's pretty simple.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8::String::Utf8Value str(args[i]);<br />
//Which is completed with<br />
const char *cstr = *str;<br />
</syntaxhighlight><br />
<br />
Well, that's pretty much it for that. This is really more a V8 section than a TurboSphere plugin section, but the fact is TurboSphere is strongly linked to V8, so this is important. And plus, I want to help you avoid the pitfalls I fell into when I started out.<br />
<br />
So what else can we do? The part that gave me the most trouble, and is hard to figure out, and lacks good examples on the web, is using some JS-side types that you define yourself. That's what those object template macros were there for. Let's use them.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function LoadWindowStyle(V8ARGS) {<br />
if(args.Length()<1){<br />
return v8::ThrowException(v8::String::New("LoadWindowStyle Error: Called with no arguments."));<br />
}<br />
CHECK_ARG_STR(0, "LoadWindowStyle Error: Arg 0 is not a string.");<br />
<br />
BEGIN_OBJECT_WRAP_CODE<br />
<br />
TS_WindowStyle *ws = NULL;<br />
<br />
v8::String::Utf8Value str(args[0]);<br />
const char *wsname = *str;<br />
<br />
SDL_RWops *wstest = SDL_RWFromFile(string(TS_dirs.windowstyle).append(wsname).c_str(), "rb");<br />
if(!wstest){<br />
SDL_RWclose(wstest);<br />
THROWERROR(string("LoadWindowStyle Error: Could not load windowstyle ").append(wsname).c_str());<br />
}<br />
SDL_RWclose(wstest);<br />
<br />
ws = new TS_WindowStyle(string(TS_dirs.windowstyle).append(wsname).c_str());<br />
<br />
if(!ws){<br />
SDL_RWclose(wstest);<br />
THROWERROR(string("LoadWindowStyle Error: Could not load windowstyle ").append(wsname).c_str());<br />
}<br />
<br />
END_OBJECT_WRAP_CODE(WindowStyle, ws);<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
Don't worry about the TS_WindowStyle stuff. Just suffice it to say that it is a C++ type, which constructs an C++ object from a given file. I left a lot of that stuff in the example, because it is validation code, and that is important to have. You can pass any string to this function, and even though it will not throw an exception at the CHECK_ARG_STR line, it will still throw an error that it could not open the file. So we know the file exists. And even then, if we can't read the file for whatever reason (likely it's not a valid file for this object to read), we still throw an error instead of passing back an empty or broken object.<br />
<br />
I will admit right here that I lied. Most of the work to wrap objects for JS is hidden behind the BEGIN_OBJECT_WRAP_CODE and END_OBJECT_WRAP_CODE macros.<br />
<br />
So let's get to the meat of the function. BEGIN_OBJECT_WRAP_CODE is a macro that sets up for END_OBJECT_WRAP_CODE. You have to use the former if you use the latter. Note that END_OBJECT_WRAP_CODE uses the same name, WindowStyle, as INIT_OBJECT_TEMPLATES and ADD_TO_PROTO did. That's important. Because of that, the object has ready made templates for V8, and the prototype has the member drawWindow already attached. The END_OBJECT_CODE does one more thing, too. It sets up a finalizer for the object. Without this, the memory from the C++ side object is leaked.<br />
<br />
<syntaxhighlight lang="cpp"><br />
void TS_WindowStyleFinalizer(v8::Persistent<v8::Value> object, void* parameter) {<br />
TS_WindowStyle* ws = (TS_WindowStyle*)parameter;<br />
delete ws;<br />
object.Clear();<br />
object.Dispose();<br />
}<br />
</syntaxhighlight><br />
<br />
The naming of this function is rough edge I still haven't worked out for plugin.h. It must be TS_[name_passed_to_other_macros]Finalizer. I haven't worked out a better way to deal with this yet. Simply put, a finalizer object is called when the object it was attached to (in this case using the END_OBJECT_WRAP_CODE function). The JS object is passed as object, and a pointer to the C++-side object is passed as parameter. In this case, I just call delete on ws, since it was allocated with new. Do what you please to dispose of your C++ object. <br />
<br />
I also like to clear my JS objects before disposing of them. The simple answer to why is that this unambiguously means that all objects it references are no longer referenced by it from the garbage collector's perspective (even though Dispose does this too), since the object can't reference anything if it has been cleared.<br />
<br />
That should be enough to start off with. Feel free to point out any incorrect info you notice, ask questions, or stuff like that.<br />
<br />
--FlyingJester</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/Making_Plugins&diff=211User:Flying Jester/Making Plugins2013-03-21T02:18:02Z<p>Flying Jester: /* Getting Started */</p>
<hr />
<div>[[Category:Tutorials]]<br />
This is a tutorial/guide for making a plugin for TurboSphere. At the moment (about 03/25/2013) it is made with TurboSphere 0.2.1 (or 0.2.0) in mind.<br />
<br />
==Forward==<br />
<br />
Before we begin, I have to preface this. If you know nothing of C or C++, and don't plan on learning it, you probably will not be able to make a plugin. And if you are making a plugin before TurboSphere 1.0 is released, you may end up with a plugin that won't work with the first official release of TurboSphere. The API probably won't change too much between then and now, though, so this should at least get you up and running with the basics.<br />
<br />
Here I cover making a plugin that works for GCC-style toolchains (GCC, Clang, MingW, etc.), and MSVC style (MSVC cl.exe and DMC cl.exe) compilers. TurboSphere has traditionally been for Linux *and* Windows, 32 and 64 bit, after all, and I highly recommend at least making an attempt at cross compatibility.<br />
<br />
==Getting Started==<br />
<br />
Personally, I write plugins in C++. I know that is easy. It shouldn't be too hard to write it in C, either. But, I do know a C++ shim is necessary for any language other than C++, since to interface with V8 you need access to the C++ template library. If you know of another language that can interface directly with C++ STL libraries, go ahead and try to use that. I'd like to hear about it! :)<br />
<br />
I'm going to assume you are using the "plugin.h" file that is included with the TurboSphere source (plugins/common/plugins.h). I used this to make all the plugins included with TurboSphere. It might not be the best way to do this, but it's the set of tools I worked out from my years of making TurboSphere.<br />
<br />
If you look at windowstyleSDL, you can see a nice example of using plugins.h. But for one learn better with examples and explanations, so let's have a look at some example code explained.<br />
<br />
First, the header file. It uses preprocessor defines to ensure the plugin works both with the GCC on Linux and MSVC on Windows. I don't have an Intel Mac (V8 requires an x86, ARM, or MIPS CPU, so my old PPC Macs aren't going to work), so this would likely need a little something more to work on Mac.<br />
<br />
<syntaxhighlight lang="cpp"><br />
//windowstyleSDL.h:<br />
#ifndef WINDOWSTYLE_HEAD<br />
#define WINDOWSTYLE_HEAD<br />
<br />
#ifdef _WIN32<br />
#define WS_EXPORT __declspec(dllexport)<br />
<br />
#define CCALL __cdecl<br />
<br />
#endif<br />
#ifndef _WIN32<br />
#define CCALL <br />
#define WS_EXPORT extern "C"<br />
#endif<br />
<br />
#ifdef _WIN32<br />
extern "C" {<br />
#endif<br />
WS_EXPORT void CCALL Close(void);<br />
WS_EXPORT initFunction CCALL Init(void);<br />
WS_EXPORT int CCALL GetNumFunctions(void);<br />
WS_EXPORT functionArray CCALL GetFunctions(void);<br />
WS_EXPORT nameArray CCALL GetFunctionNames(void);<br />
WS_EXPORT int CCALL GetNumVariables(void);<br />
WS_EXPORT v8FunctionArray CCALL GetVariables(void);<br />
WS_EXPORT nameArray CCALL GetVariableNames(void);<br />
<br />
#ifdef _WIN32<br />
}<br />
#endif<br />
<br />
#endif<br />
</syntaxhighlight><br />
<br />
Now on to the main windowstyleSDL.cpp file:<br />
<br />
<syntaxhighlight lang="cpp"><br />
#include "../common/plugin.h"<br />
#include "windowstyleSDL.h"<br />
<br />
//This will be explained later.<br />
#define NUMFUNCS 2<br />
<br />
//forward declare C++ functions to be bound to JS<br />
v8Function LoadWindowStyle(V8ARGS);<br />
v8Function GetSystemWindowStyle(V8ARGS);<br />
<br />
//declare pointers to functions that will be passed to the engine to be bound<br />
void* LoadWindowStylePointer = V8FUNCPOINTER(LoadWindowStyle);<br />
void* GetSystemWindowStylePointer = V8FUNCPOINTER(GetSystemWindowStyle);<br />
<br />
</syntaxhighlight><br />
<br />
This is the start of windowstyle.cpp. Here, we include plugin.h, we forward declare the functions to be exposed to script, and then void pointers that point to the functions. That last part will be useful later.<br />
<br />
It also forward declares the mandatory functions of a plugin. In this case they only have linkage for GCC-style compilation, though. I'll add in how it's done with the Microsoft Visual C++ compiler at a later date.<br />
<br />
<syntaxhighlight lang="cpp"><br />
initFunction Init(){<br />
//Initialize the JS-side object templates<br />
INIT_OBJECT_TEMPLATES(WindowStyle);<br />
ADD_TO_PROTO(WindowStyle, "drawWindow", TS_WSdrawWindow);<br />
<br />
//return plugin's name to the engine.<br />
return (char *)"windowstyleSDL";<br />
}<br />
</syntaxhighlight><br />
<br />
Here we define the Init function. Every plugin must have an exposed Init function. This is called by TurboSphere for two reasons. The simple use is that it tells TurboSphere the plugin's name. It is guaranteed to be called before anything else. With this in mind, what are those other macros being called? the INIT_OBJECT_TEMPLATES and ADD_TO_PROTO? Well, let's look at one more function before we talk about that:<br />
<br />
<syntaxhighlight lang="cpp"><br />
void Close(){<br />
//Dispose of JS-side templates.<br />
CLOSE_OBJECT_TEMPLATES(WindowStyle);<br />
}<br />
</syntaxhighlight><br />
<br />
OK, this is the Close function. It's to be called when we are done with the plugin, and it will definitely be called after each call to Init before Init is called again. We can't be sure that Close will be called--what if TurboSphere hard-crashes? But we always do our best to call it before TurboSphere quits.<br />
<br />
So there's another macro. CLOSE_OBJECT_TEMPLATES. Well, unsurprisingly, that is the counterpart to INIT_OBJECT_TEMPLATES. They automate the process of making templates for binding C++ objects to JS. You can check out the details in the plugins.h file, but if you don't want to know the details just let it be. So far only one function in all of TurboSphere and the default plugins needs more knowhow than this, and in that case it wasn't necessary to not do it that way anyway.<br />
<br />
Both macros are passed a name, WindowStyle. This isn't defined before, as the macros define several objects using that name. Just pass them all the same name for the same object type, and it will work. The INIT_OBJECT_TEMPLATES macro creates the templates to create, wrap, and modify the prototypes of C++ to JS-side objects. The second macro, ADD_TO_PROTO, is an example of the latter. It binds the C++ function TS_WSdrawWindow to the JS_side object type that WindowStyle defines, and gives it the JS-side name drawWindow (windowstyle_object.drawWindow()). The CLOSE_OBJECT_TEMPLATES macro undefines the object template defined by WindowStyle, which cleans things out in JS (and gives back a bit of memory, ideally, although it doesn't actually work out this way for sure; V8 plays it fast and loose with memory when it thinks it can trade memory for speed).<br />
<br />
Let's have a look at the remaining mandatory functions of a plugin.<br />
<br />
<syntaxhighlight lang="cpp"><br />
int GetNumFunctions(){<br />
return NUMFUNCS;<br />
}<br />
<br />
int GetNumVariables(){<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
These functions return the number of variables and functions to be exposed to script. windowstyleSDL does not define any variables for script, but I will go over how that is done later anyway. For the moment, suffice it to say that it is simpler than exposing functions.<br />
<br />
<syntaxhighlight lang="cpp"><br />
//to simplify numbering functions and names.<br />
int numerate(bool reset){<br />
static int i = 0;<br />
if(reset) {<br />
i = 0;<br />
return 0;<br />
}<br />
i++;<br />
return i-1;<br />
}<br />
<br />
functionArray GetFunctions(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
functionArray funcs = (functionArray)calloc(NUMFUNCS, sizeof(void*));<br />
<br />
funcs[numerate(false)] = LoadWindowStylePointer;<br />
funcs[numerate(false)] = GetSystemWindowStylePointer;<br />
//return array of function pointers to to the engine.<br />
return funcs;<br />
}<br />
</syntaxhighlight><br />
<br />
The first function is just to simplify numbering the elements of arrays. You don't need to use it, but I found it quite useful when writing the inputSDL function which has well over a hundred variables defined (one for each key on a keyboard and several for mouse buttons).<br />
<br />
The second function is necessary, though. First we reset the numeration function to zero. Then we define the array of functions to be exposed. This is where those void pointers to the functions that will be exposed to V8 come in handy.<br />
<br />
On a side note: GCC gets a little angry at all this, throwing a warning since you aren't supposed to play with void pointers this way, but as far as I know you can do this on any compiler and it will work out. If you were really worried about warnings (instead of actual definite problems--don't think I don't take warnings eriously, give me minute!), you could probably pass them simply as pointers to the V8 functions, as they will be cast as void pointers in TurboSphere. But in that case you are just masking any problems! The compiler won't complain because the cast is made in between two binaries, and it can't see what is happening. If this is really a problem, then the compiler will give you an error--but only if it can see what you are doing. And yes, I could cast them as v8Function's on the TurboSphere side, but because of the...fluidity of JavaScript, there are some things that can be functions that you would then not be able to pass through to TurboSphere as such (JS can be wily beast, and is very much <br />
not like C++ when it comes to letting you pass of something as something else). I don't want to limit anything here just because the functionality is in a plugin, so I do it this way. [/sidenote]<br />
<br />
So, what about a GetVariables function?<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8FunctionArray GetVariables(){<br />
return NULL;<br />
}<br />
</syntaxhighlight><br />
<br />
If you have no variables, you can just return NULL. The function won't even be called by TurboSphere, anyway. And even if it was, NULL is an acceptable value; you can't read from an empty array, so it doesn't matter what the address of it is, and it has no data! It's what calloc would have returned had you told it to give you an array of zero size, too.<br />
<br />
I actually do have something to say about this when there are variables, so let's assume we had four variables to define. Let's say their names are SOME_NAME, VERSION, CONSTANT1 and CONSTANT2, in that order, just for sake of explanation. The function would then look like this<br />
<br />
<syntaxhighlight lang="cpp"><br />
//theoretical GetVariables<br />
v8FunctionArray GetVariables(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
nameArray varnames = (nameArray)calloc(NUMVARS, sizeof(v8Function));<br />
funcnames[numerate(false)] = v8::String::New("This Is A Name!"); //SOME_NAME<br />
funcnames[numerate(false)] = v8::Number::New(1.5); //VERSION<br />
funcnames[numerate(false)] = v8::Integer::New(0); //CONSTANT1<br />
funcnames[numerate(false)] = v8::Integer::New(1); //CONSTANT2<br />
return varnames;<br />
}<br />
</syntaxhighlight><br />
<br />
Here's an example of V8 and JS being very fluid with things; anything that can be a function can also be variable, and we use v8Function as the type for variables. The only time the opposite would not be true is when you deal with constructors that are strongly tied to the templates for JS-side objects. I'm not doing things that way, and in several cases multiple functions can be used as constructors for a single type, and V8 won't let me tell it there are two constructors for a single JS-side type (they bind slightly different kinds of objects on the C++ side). In any case, these are a few of the types you could pass back as variables.<br />
<br />
So, let's get on with what is actually a part of windowstyleSDL!<br />
<br />
<syntaxhighlight lang="cpp"><br />
nameArray GetFunctionNames(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
nameArray funcnames = (nameArray)calloc(NUMFUNCS, sizeof(functionName));<br />
<br />
funcnames[numerate(false)] = (functionName)"WindowStyle";<br />
funcnames[numerate(false)] = (functionName)"GetSystemWindowStyle";<br />
//return array of c-string function names to the engine.<br />
return funcnames;<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
This is much like the GetFunctions function, but in this case, since the names are hardcoded right there, we just tell the compiler to think of them as the type functionName (aka const char*, GCC throws a warning if you don't cast them this way, but unlike before it makes no difference to me if they are cast that way or not, so I do to limit the number of warnings when compiling), and be on our merry way. The names of variables are defined the same way, except the function would be called GetVariableNames, and we would use the type variableName instead of functionName (both are const char*, but why use a type like functionName with a misleading name? GetVariables notwithstanding!).<br />
<br />
And unsurprisingly<br />
<br />
<syntaxhighlight lang="cpp"><br />
nameArray GetVariableNames(){<br />
return NULL;<br />
}<br />
</syntaxhighlight><br />
<br />
Same deal here as with GetVariables. <br />
<br />
So that's it! Technically, this is everything you *need* for a plugin. If you defined GetNumFunctions to return 0, and GetFunctions and getFunctionNames to return NULL this would be perfectly functional (although totally useless) plugin. But you probably want your plugin to do something, right? <br />
<br />
Well, let's look at a single function that can be used by V8. There are a whole lot ways to do this, I might add, but this is how I've been doing it. If you want to do it a different way, be my guest.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function TestFunction(V8ARGS){<br />
return v8::Integer::New(42)<br />
}<br />
</syntaxhighlight><br />
<br />
Well, it doesn't do much. But if you passed a pointer to this function as one of the elements returned by GetFunctions, and then in JS called whatever name you gave it as a function, it would return 42 in JS. But, that's simple. In fact, you might well have been able to figure out most of that from what I went over in the theoretical GetVariables function. Let's look deeper.<br />
<br />
What if you want to deal with arguments? That's pretty simple, and it lets me show off some nice macros in plugin.h.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function ArgsTestFunction(V8ARGS){<br />
if(args.Length()<1){<br />
THROWERROR("ArgsTestFunction Error: Called with no arguments.");<br />
}<br />
CHECK_ARG_INT(0, "ArgsTestFunction Error: Argument 0 is not an integer.");<br />
<br />
int i = args[0]->IntegerValue();<br />
<br />
if(i==0){<br />
return v8::Integer::New(42);<br />
}<br />
else {<br />
return v8::String::New("That number was not 0!");<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
In this case, we have to deal with arguments. I have one thing that I cannot stress enough about arguments.<br />
<br />
Programmers are stupid and lazy. Even you, my friend, even me. So we can count on them passing garbage to our functions. I know I pass garbage to functions all the time, and even if they are really good programmers and rarely make that kind of mistake, these checks are useful for telling you where things went wrong. If you ever plan on using your own plugin, you will thank yourself for adding as many checks as possible.<br />
<br />
The first one is the check for the numebr of args. You could just as easily default to something, but this a good example of the THROWERROR macro, a paper thin wrapper around returning a v8::ThrowException function. It throws a JS-side exception with the text you give. It can be caught by script as well, which is a *good* *thing*. I recommend you put the function name into the error message. And I highly recommend you give some explanation for why the exception happened at all. Don't be shy about being specific, either.<br />
<br />
Simpler to do (with the help of plugin.h) is the check of parameter types. There exist several macros to check them for you:<br />
<br />
* CHECK_ARG_INT<br />
* CHECK_ARG_STR<br />
* CHECK_ARG_OBJ<br />
* CHECK_ARG_BOOL<br />
* CHECK_ARG_ARRAY<br />
<br />
Bear in mind that JS is a wily language when it comes to data validation. If you are using the OBJ or ARRAY checks, you might either rule out valid values or include values you don't want to. But the explanation of such things is beyond the scope here.<br />
<br />
These macros check the argument specified in the first parameter (here 0, the first arg), and throw the error specified in the second parameter if it is not the right type. Bear in mind, this doens't mean that it couldn't be cast to the right type, just that it isn't right now. Generally I would err on the side of throwing out edge-case-correct values than accepting bad values that seem like they might be OK. Better to throw a JS exception than to either make V8 die (which is ugly and won't tell you as much about what went wrong), or pass garbage into a C++ or C function, which can quite easily cause crashes. It can cause hard crashes, and we really don't want hard crashes. We really, really don't want them. Anytime you can stop one from happening, I'd really like you too. Every time a user has to use a task manager to close TurboSphere, they think that anyone who had a hand in making it, the game they are playing with it, or any plugins they use, are bad programmers. And this right here, this is where most <br />
crashes come from.<br />
<br />
So next we need to make the argument, which is a V8 type, into a C/C++ type. First, ask yourself, are you sure that only the correct type of value could have gotten to this cast (no really, this is important)? Good. There are a few easy ways to do this:<br />
<br />
<syntaxhighlight lang="cpp"><br />
int x = args[i]->IntegerValue();<br />
int x = args[i]->Int32Value();<br />
</syntaxhighlight><br />
<br />
Bear in mind that you will get some weirdness with this when you try to compile on both 32-bit and 64-bit architectures. IntegerValue returns a 64-bit integer, and Int32Value returns a 32-bit integer. You could avoid compiler warnings by using a fixed with type (int64_t), or by using some ugly preprocessor stuff. My recommendation is just to only go with 64-bits, but I know I'm not in charge of what word-length users' computers are, so just listen to your compiler of choice's warnings for what to do. If it doesn't complain, then don't worry about it--but bear in mind that TurboSphere will, one day somewhat soon, be 64-bit only, and possibly only able to load 64-bit plugins. At least think about making your code 64-bit safe if you want your plugin to stick around.<br />
<br />
<syntaxhighlight lang="cpp"><br />
bool x = args[i]->BooleanValue();<br />
</syntaxhighlight><br />
<br />
That one's pretty simple.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8::String::Utf8Value str(args[i]);<br />
//Which is completed with<br />
const char *cstr = *str;<br />
</syntaxhighlight><br />
<br />
Well, that's pretty much it for that. This is really more a V8 section than a TurboSphere plugin section, but the fact is TurboSphere is strongly linked to V8, so this is important. And plus, I want to help you avoid the pitfalls I fell into when I started out.<br />
<br />
So what else can we do? The part that gave me the most trouble, and is hard to figure out, and lacks good examples on the web, is using some JS-side types that you define yourself. That's what those object template macros were there for. Let's use them.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function LoadWindowStyle(V8ARGS) {<br />
if(args.Length()<1){<br />
return v8::ThrowException(v8::String::New("LoadWindowStyle Error: Called with no arguments."));<br />
}<br />
CHECK_ARG_STR(0, "LoadWindowStyle Error: Arg 0 is not a string.");<br />
<br />
BEGIN_OBJECT_WRAP_CODE<br />
<br />
TS_WindowStyle *ws = NULL;<br />
<br />
v8::String::Utf8Value str(args[0]);<br />
const char *wsname = *str;<br />
<br />
SDL_RWops *wstest = SDL_RWFromFile(string(TS_dirs.windowstyle).append(wsname).c_str(), "rb");<br />
if(!wstest){<br />
SDL_RWclose(wstest);<br />
THROWERROR(string("LoadWindowStyle Error: Could not load windowstyle ").append(wsname).c_str());<br />
}<br />
SDL_RWclose(wstest);<br />
<br />
ws = new TS_WindowStyle(string(TS_dirs.windowstyle).append(wsname).c_str());<br />
<br />
if(!ws){<br />
SDL_RWclose(wstest);<br />
THROWERROR(string("LoadWindowStyle Error: Could not load windowstyle ").append(wsname).c_str());<br />
}<br />
<br />
END_OBJECT_WRAP_CODE(WindowStyle, ws);<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
Don't worry about the TS_WindowStyle stuff. Just suffice it to say that it is a C++ type, which constructs an C++ object from a given file. I left a lot of that stuff in the example, because it is validation code, and that is important to have. You can pass any string to this function, and even though it will not throw an exception at the CHECK_ARG_STR line, it will still throw an error that it could not open the file. So we know the file exists. And even then, if we can't read the file for whatever reason (likely it's not a valid file for this object to read), we still throw an error instead of passing back an empty or broken object.<br />
<br />
I will admit right here that I lied. Most of the work to wrap objects for JS is hidden behind the BEGIN_OBJECT_WRAP_CODE and END_OBJECT_WRAP_CODE macros.<br />
<br />
So let's get to the meat of the function. BEGIN_OBJECT_WRAP_CODE is a macro that sets up for END_OBJECT_WRAP_CODE. You have to use the former if you use the latter. Note that END_OBJECT_WRAP_CODE uses the same name, WindowStyle, as INIT_OBJECT_TEMPLATES and ADD_TO_PROTO did. That's important. Because of that, the object has ready made templates for V8, and the prototype has the member drawWindow already attached. The END_OBJECT_CODE does one more thing, too. It sets up a finalizer for the object. Without this, the memory from the C++ side object is leaked.<br />
<br />
<syntaxhighlight lang="cpp"><br />
void TS_WindowStyleFinalizer(v8::Persistent<v8::Value> object, void* parameter) {<br />
TS_WindowStyle* ws = (TS_WindowStyle*)parameter;<br />
delete ws;<br />
object.Clear();<br />
object.Dispose();<br />
}<br />
</syntaxhighlight><br />
<br />
The naming of this function is rough edge I still haven't worked out for plugin.h. It must be TS_[name_passed_to_other_macros]Finalizer. I haven't worked out a better way to deal with this yet. Simply put, a finalizer object is called when the object it was attached to (in this case using the END_OBJECT_WRAP_CODE function). The JS object is passed as object, and a pointer to the C++-side object is passed as parameter. In this case, I just call delete on ws, since it was allocated with new. Do what you please to dispose of your C++ object. <br />
<br />
I also like to clear my JS objects before disposing of them. The simple answer to why is that this unambiguously means that all objects it references are no longer referenced by it from the garbage collector's perspective (even though Dispose does this too), since the object can't reference anything if it has been cleared.<br />
<br />
That should be enough to start off with. Feel free to point out any incorrect info you notice, ask questions, or stuff like that.<br />
<br />
--FlyingJester</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/Making_Plugins&diff=210User:Flying Jester/Making Plugins2013-03-21T02:17:27Z<p>Flying Jester: /* Getting Started */</p>
<hr />
<div>[[Category:Tutorials]]<br />
This is a tutorial/guide for making a plugin for TurboSphere. At the moment (about 03/25/2013) it is made with TurboSphere 0.2.1 (or 0.2.0) in mind.<br />
<br />
==Forward==<br />
<br />
Before we begin, I have to preface this. If you know nothing of C or C++, and don't plan on learning it, you probably will not be able to make a plugin. And if you are making a plugin before TurboSphere 1.0 is released, you may end up with a plugin that won't work with the first official release of TurboSphere. The API probably won't change too much between then and now, though, so this should at least get you up and running with the basics.<br />
<br />
Here I cover making a plugin that works for GCC-style toolchains (GCC, Clang, MingW, etc.), and MSVC style (MSVC cl.exe and DMC cl.exe) compilers. TurboSphere has traditionally been for Linux *and* Windows, 32 and 64 bit, after all, and I highly recommend at least making an attempt at cross compatibility.<br />
<br />
==Getting Started==<br />
<br />
Personally, I write plugins in C++. I know that is easy. It shouldn't be too hard to write it in C, either. But, I do know a C++ shim is necessary for any language other than C++, since to interface with V8 you need access to the C++ template library. If you know of another language that can interface directly with C++ STL libraries, go ahead and try to use that. I'd like to hear about it! :)<br />
<br />
I'm going to assume you are using the "plugin.h" file that is included with the TurboSphere source (plugins/common/plugins.h). I used this to make all the plugins included with TurboSphere. It might not be the best way to do this, but it's the set of tools I worked out from my years of making TurboSphere.<br />
<br />
If you look at windowstyleSDL, you can see a nice example of using plugins.h. But for one learn better with examples and explanations, so let's have a look at some example code explained.<br />
<br />
First, the header file. It uses preprocessor defines to ensure the plugin works both with the GCC on Linux and MSVC on Windows. I don't have an Intel Mac (V8 requires an x86, ARM, or MIPS CPU, so my old PPC Macs aren't going to work), so this would likely need a little something more to work on Mac.<br />
<br />
<syntaxhighlight lang="cpp"><br />
//windowstyleSDL.h:<br />
#ifndef WINDOWSTYLE_HEAD<br />
#define WINDOWSTYLE_HEAD<br />
<br />
#ifdef _WIN32<br />
#define WS_EXPORT __declspec(dllexport)<br />
<br />
#define CCALL __cdecl<br />
<br />
#endif<br />
#ifndef _WIN32<br />
#define CCALL <br />
#define WS_EXPORT extern "C"<br />
#endif<br />
<br />
#ifdef _WIN32<br />
extern "C" {<br />
#endif<br />
WS_EXPORT void CCALL Close(void);<br />
WS_EXPORT initFunction CCALL Init(void);<br />
WS_EXPORT int CCALL GetNumFunctions(void);<br />
WS_EXPORT functionArray CCALL GetFunctions(void);<br />
WS_EXPORT nameArray CCALL GetFunctionNames(void);<br />
WS_EXPORT int CCALL GetNumVariables(void);<br />
WS_EXPORT v8FunctionArray CCALL GetVariables(void);<br />
WS_EXPORT nameArray CCALL GetVariableNames(void);<br />
<br />
#ifdef _WIN32<br />
}<br />
#endif<br />
<br />
#endif<br />
</syntaxhighlight><br />
<br />
Now on to the main windowstyleSDL.cpp file:<br />
<br />
<syntaxhighlight lang="cpp"><br />
#include "../common/plugin.h"<br />
#include "windowstyleSDL.h"<br />
<br />
//This will be explained later.<br />
#define NUMFUNCS 2<br />
<br />
//forward declare C++ functions to be bound to JS<br />
v8Function LoadWindowStyle(V8ARGS);<br />
v8Function GetSystemWindowStyle(V8ARGS);<br />
<br />
//declare pointers to functions that will be passed to the engine to be bound<br />
void* LoadWindowStylePointer = V8FUNCPOINTER(LoadWindowStyle));<br />
void* GetSystemWindowStylePointer = V8FUNCPOINTER(GetSystemWindowStyle));<br />
<br />
</syntaxhighlight><br />
<br />
This is the start of windowstyle.cpp. Here, we include plugin.h, we forward declare the functions to be exposed to script, and then void pointers that point to the functions. That last part will be useful later.<br />
<br />
It also forward declares the mandatory functions of a plugin. In this case they only have linkage for GCC-style compilation, though. I'll add in how it's done with the Microsoft Visual C++ compiler at a later date.<br />
<br />
<syntaxhighlight lang="cpp"><br />
initFunction Init(){<br />
//Initialize the JS-side object templates<br />
INIT_OBJECT_TEMPLATES(WindowStyle);<br />
ADD_TO_PROTO(WindowStyle, "drawWindow", TS_WSdrawWindow);<br />
<br />
//return plugin's name to the engine.<br />
return (char *)"windowstyleSDL";<br />
}<br />
</syntaxhighlight><br />
<br />
Here we define the Init function. Every plugin must have an exposed Init function. This is called by TurboSphere for two reasons. The simple use is that it tells TurboSphere the plugin's name. It is guaranteed to be called before anything else. With this in mind, what are those other macros being called? the INIT_OBJECT_TEMPLATES and ADD_TO_PROTO? Well, let's look at one more function before we talk about that:<br />
<br />
<syntaxhighlight lang="cpp"><br />
void Close(){<br />
//Dispose of JS-side templates.<br />
CLOSE_OBJECT_TEMPLATES(WindowStyle);<br />
}<br />
</syntaxhighlight><br />
<br />
OK, this is the Close function. It's to be called when we are done with the plugin, and it will definitely be called after each call to Init before Init is called again. We can't be sure that Close will be called--what if TurboSphere hard-crashes? But we always do our best to call it before TurboSphere quits.<br />
<br />
So there's another macro. CLOSE_OBJECT_TEMPLATES. Well, unsurprisingly, that is the counterpart to INIT_OBJECT_TEMPLATES. They automate the process of making templates for binding C++ objects to JS. You can check out the details in the plugins.h file, but if you don't want to know the details just let it be. So far only one function in all of TurboSphere and the default plugins needs more knowhow than this, and in that case it wasn't necessary to not do it that way anyway.<br />
<br />
Both macros are passed a name, WindowStyle. This isn't defined before, as the macros define several objects using that name. Just pass them all the same name for the same object type, and it will work. The INIT_OBJECT_TEMPLATES macro creates the templates to create, wrap, and modify the prototypes of C++ to JS-side objects. The second macro, ADD_TO_PROTO, is an example of the latter. It binds the C++ function TS_WSdrawWindow to the JS_side object type that WindowStyle defines, and gives it the JS-side name drawWindow (windowstyle_object.drawWindow()). The CLOSE_OBJECT_TEMPLATES macro undefines the object template defined by WindowStyle, which cleans things out in JS (and gives back a bit of memory, ideally, although it doesn't actually work out this way for sure; V8 plays it fast and loose with memory when it thinks it can trade memory for speed).<br />
<br />
Let's have a look at the remaining mandatory functions of a plugin.<br />
<br />
<syntaxhighlight lang="cpp"><br />
int GetNumFunctions(){<br />
return NUMFUNCS;<br />
}<br />
<br />
int GetNumVariables(){<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
These functions return the number of variables and functions to be exposed to script. windowstyleSDL does not define any variables for script, but I will go over how that is done later anyway. For the moment, suffice it to say that it is simpler than exposing functions.<br />
<br />
<syntaxhighlight lang="cpp"><br />
//to simplify numbering functions and names.<br />
int numerate(bool reset){<br />
static int i = 0;<br />
if(reset) {<br />
i = 0;<br />
return 0;<br />
}<br />
i++;<br />
return i-1;<br />
}<br />
<br />
functionArray GetFunctions(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
functionArray funcs = (functionArray)calloc(NUMFUNCS, sizeof(void*));<br />
<br />
funcs[numerate(false)] = LoadWindowStylePointer;<br />
funcs[numerate(false)] = GetSystemWindowStylePointer;<br />
//return array of function pointers to to the engine.<br />
return funcs;<br />
}<br />
</syntaxhighlight><br />
<br />
The first function is just to simplify numbering the elements of arrays. You don't need to use it, but I found it quite useful when writing the inputSDL function which has well over a hundred variables defined (one for each key on a keyboard and several for mouse buttons).<br />
<br />
The second function is necessary, though. First we reset the numeration function to zero. Then we define the array of functions to be exposed. This is where those void pointers to the functions that will be exposed to V8 come in handy.<br />
<br />
On a side note: GCC gets a little angry at all this, throwing a warning since you aren't supposed to play with void pointers this way, but as far as I know you can do this on any compiler and it will work out. If you were really worried about warnings (instead of actual definite problems--don't think I don't take warnings eriously, give me minute!), you could probably pass them simply as pointers to the V8 functions, as they will be cast as void pointers in TurboSphere. But in that case you are just masking any problems! The compiler won't complain because the cast is made in between two binaries, and it can't see what is happening. If this is really a problem, then the compiler will give you an error--but only if it can see what you are doing. And yes, I could cast them as v8Function's on the TurboSphere side, but because of the...fluidity of JavaScript, there are some things that can be functions that you would then not be able to pass through to TurboSphere as such (JS can be wily beast, and is very much <br />
not like C++ when it comes to letting you pass of something as something else). I don't want to limit anything here just because the functionality is in a plugin, so I do it this way. [/sidenote]<br />
<br />
So, what about a GetVariables function?<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8FunctionArray GetVariables(){<br />
return NULL;<br />
}<br />
</syntaxhighlight><br />
<br />
If you have no variables, you can just return NULL. The function won't even be called by TurboSphere, anyway. And even if it was, NULL is an acceptable value; you can't read from an empty array, so it doesn't matter what the address of it is, and it has no data! It's what calloc would have returned had you told it to give you an array of zero size, too.<br />
<br />
I actually do have something to say about this when there are variables, so let's assume we had four variables to define. Let's say their names are SOME_NAME, VERSION, CONSTANT1 and CONSTANT2, in that order, just for sake of explanation. The function would then look like this<br />
<br />
<syntaxhighlight lang="cpp"><br />
//theoretical GetVariables<br />
v8FunctionArray GetVariables(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
nameArray varnames = (nameArray)calloc(NUMVARS, sizeof(v8Function));<br />
funcnames[numerate(false)] = v8::String::New("This Is A Name!"); //SOME_NAME<br />
funcnames[numerate(false)] = v8::Number::New(1.5); //VERSION<br />
funcnames[numerate(false)] = v8::Integer::New(0); //CONSTANT1<br />
funcnames[numerate(false)] = v8::Integer::New(1); //CONSTANT2<br />
return varnames;<br />
}<br />
</syntaxhighlight><br />
<br />
Here's an example of V8 and JS being very fluid with things; anything that can be a function can also be variable, and we use v8Function as the type for variables. The only time the opposite would not be true is when you deal with constructors that are strongly tied to the templates for JS-side objects. I'm not doing things that way, and in several cases multiple functions can be used as constructors for a single type, and V8 won't let me tell it there are two constructors for a single JS-side type (they bind slightly different kinds of objects on the C++ side). In any case, these are a few of the types you could pass back as variables.<br />
<br />
So, let's get on with what is actually a part of windowstyleSDL!<br />
<br />
<syntaxhighlight lang="cpp"><br />
nameArray GetFunctionNames(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
nameArray funcnames = (nameArray)calloc(NUMFUNCS, sizeof(functionName));<br />
<br />
funcnames[numerate(false)] = (functionName)"WindowStyle";<br />
funcnames[numerate(false)] = (functionName)"GetSystemWindowStyle";<br />
//return array of c-string function names to the engine.<br />
return funcnames;<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
This is much like the GetFunctions function, but in this case, since the names are hardcoded right there, we just tell the compiler to think of them as the type functionName (aka const char*, GCC throws a warning if you don't cast them this way, but unlike before it makes no difference to me if they are cast that way or not, so I do to limit the number of warnings when compiling), and be on our merry way. The names of variables are defined the same way, except the function would be called GetVariableNames, and we would use the type variableName instead of functionName (both are const char*, but why use a type like functionName with a misleading name? GetVariables notwithstanding!).<br />
<br />
And unsurprisingly<br />
<br />
<syntaxhighlight lang="cpp"><br />
nameArray GetVariableNames(){<br />
return NULL;<br />
}<br />
</syntaxhighlight><br />
<br />
Same deal here as with GetVariables. <br />
<br />
So that's it! Technically, this is everything you *need* for a plugin. If you defined GetNumFunctions to return 0, and GetFunctions and getFunctionNames to return NULL this would be perfectly functional (although totally useless) plugin. But you probably want your plugin to do something, right? <br />
<br />
Well, let's look at a single function that can be used by V8. There are a whole lot ways to do this, I might add, but this is how I've been doing it. If you want to do it a different way, be my guest.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function TestFunction(V8ARGS){<br />
return v8::Integer::New(42)<br />
}<br />
</syntaxhighlight><br />
<br />
Well, it doesn't do much. But if you passed a pointer to this function as one of the elements returned by GetFunctions, and then in JS called whatever name you gave it as a function, it would return 42 in JS. But, that's simple. In fact, you might well have been able to figure out most of that from what I went over in the theoretical GetVariables function. Let's look deeper.<br />
<br />
What if you want to deal with arguments? That's pretty simple, and it lets me show off some nice macros in plugin.h.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function ArgsTestFunction(V8ARGS){<br />
if(args.Length()<1){<br />
THROWERROR("ArgsTestFunction Error: Called with no arguments.");<br />
}<br />
CHECK_ARG_INT(0, "ArgsTestFunction Error: Argument 0 is not an integer.");<br />
<br />
int i = args[0]->IntegerValue();<br />
<br />
if(i==0){<br />
return v8::Integer::New(42);<br />
}<br />
else {<br />
return v8::String::New("That number was not 0!");<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
In this case, we have to deal with arguments. I have one thing that I cannot stress enough about arguments.<br />
<br />
Programmers are stupid and lazy. Even you, my friend, even me. So we can count on them passing garbage to our functions. I know I pass garbage to functions all the time, and even if they are really good programmers and rarely make that kind of mistake, these checks are useful for telling you where things went wrong. If you ever plan on using your own plugin, you will thank yourself for adding as many checks as possible.<br />
<br />
The first one is the check for the numebr of args. You could just as easily default to something, but this a good example of the THROWERROR macro, a paper thin wrapper around returning a v8::ThrowException function. It throws a JS-side exception with the text you give. It can be caught by script as well, which is a *good* *thing*. I recommend you put the function name into the error message. And I highly recommend you give some explanation for why the exception happened at all. Don't be shy about being specific, either.<br />
<br />
Simpler to do (with the help of plugin.h) is the check of parameter types. There exist several macros to check them for you:<br />
<br />
* CHECK_ARG_INT<br />
* CHECK_ARG_STR<br />
* CHECK_ARG_OBJ<br />
* CHECK_ARG_BOOL<br />
* CHECK_ARG_ARRAY<br />
<br />
Bear in mind that JS is a wily language when it comes to data validation. If you are using the OBJ or ARRAY checks, you might either rule out valid values or include values you don't want to. But the explanation of such things is beyond the scope here.<br />
<br />
These macros check the argument specified in the first parameter (here 0, the first arg), and throw the error specified in the second parameter if it is not the right type. Bear in mind, this doens't mean that it couldn't be cast to the right type, just that it isn't right now. Generally I would err on the side of throwing out edge-case-correct values than accepting bad values that seem like they might be OK. Better to throw a JS exception than to either make V8 die (which is ugly and won't tell you as much about what went wrong), or pass garbage into a C++ or C function, which can quite easily cause crashes. It can cause hard crashes, and we really don't want hard crashes. We really, really don't want them. Anytime you can stop one from happening, I'd really like you too. Every time a user has to use a task manager to close TurboSphere, they think that anyone who had a hand in making it, the game they are playing with it, or any plugins they use, are bad programmers. And this right here, this is where most <br />
crashes come from.<br />
<br />
So next we need to make the argument, which is a V8 type, into a C/C++ type. First, ask yourself, are you sure that only the correct type of value could have gotten to this cast (no really, this is important)? Good. There are a few easy ways to do this:<br />
<br />
<syntaxhighlight lang="cpp"><br />
int x = args[i]->IntegerValue();<br />
int x = args[i]->Int32Value();<br />
</syntaxhighlight><br />
<br />
Bear in mind that you will get some weirdness with this when you try to compile on both 32-bit and 64-bit architectures. IntegerValue returns a 64-bit integer, and Int32Value returns a 32-bit integer. You could avoid compiler warnings by using a fixed with type (int64_t), or by using some ugly preprocessor stuff. My recommendation is just to only go with 64-bits, but I know I'm not in charge of what word-length users' computers are, so just listen to your compiler of choice's warnings for what to do. If it doesn't complain, then don't worry about it--but bear in mind that TurboSphere will, one day somewhat soon, be 64-bit only, and possibly only able to load 64-bit plugins. At least think about making your code 64-bit safe if you want your plugin to stick around.<br />
<br />
<syntaxhighlight lang="cpp"><br />
bool x = args[i]->BooleanValue();<br />
</syntaxhighlight><br />
<br />
That one's pretty simple.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8::String::Utf8Value str(args[i]);<br />
//Which is completed with<br />
const char *cstr = *str;<br />
</syntaxhighlight><br />
<br />
Well, that's pretty much it for that. This is really more a V8 section than a TurboSphere plugin section, but the fact is TurboSphere is strongly linked to V8, so this is important. And plus, I want to help you avoid the pitfalls I fell into when I started out.<br />
<br />
So what else can we do? The part that gave me the most trouble, and is hard to figure out, and lacks good examples on the web, is using some JS-side types that you define yourself. That's what those object template macros were there for. Let's use them.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function LoadWindowStyle(V8ARGS) {<br />
if(args.Length()<1){<br />
return v8::ThrowException(v8::String::New("LoadWindowStyle Error: Called with no arguments."));<br />
}<br />
CHECK_ARG_STR(0, "LoadWindowStyle Error: Arg 0 is not a string.");<br />
<br />
BEGIN_OBJECT_WRAP_CODE<br />
<br />
TS_WindowStyle *ws = NULL;<br />
<br />
v8::String::Utf8Value str(args[0]);<br />
const char *wsname = *str;<br />
<br />
SDL_RWops *wstest = SDL_RWFromFile(string(TS_dirs.windowstyle).append(wsname).c_str(), "rb");<br />
if(!wstest){<br />
SDL_RWclose(wstest);<br />
THROWERROR(string("LoadWindowStyle Error: Could not load windowstyle ").append(wsname).c_str());<br />
}<br />
SDL_RWclose(wstest);<br />
<br />
ws = new TS_WindowStyle(string(TS_dirs.windowstyle).append(wsname).c_str());<br />
<br />
if(!ws){<br />
SDL_RWclose(wstest);<br />
THROWERROR(string("LoadWindowStyle Error: Could not load windowstyle ").append(wsname).c_str());<br />
}<br />
<br />
END_OBJECT_WRAP_CODE(WindowStyle, ws);<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
Don't worry about the TS_WindowStyle stuff. Just suffice it to say that it is a C++ type, which constructs an C++ object from a given file. I left a lot of that stuff in the example, because it is validation code, and that is important to have. You can pass any string to this function, and even though it will not throw an exception at the CHECK_ARG_STR line, it will still throw an error that it could not open the file. So we know the file exists. And even then, if we can't read the file for whatever reason (likely it's not a valid file for this object to read), we still throw an error instead of passing back an empty or broken object.<br />
<br />
I will admit right here that I lied. Most of the work to wrap objects for JS is hidden behind the BEGIN_OBJECT_WRAP_CODE and END_OBJECT_WRAP_CODE macros.<br />
<br />
So let's get to the meat of the function. BEGIN_OBJECT_WRAP_CODE is a macro that sets up for END_OBJECT_WRAP_CODE. You have to use the former if you use the latter. Note that END_OBJECT_WRAP_CODE uses the same name, WindowStyle, as INIT_OBJECT_TEMPLATES and ADD_TO_PROTO did. That's important. Because of that, the object has ready made templates for V8, and the prototype has the member drawWindow already attached. The END_OBJECT_CODE does one more thing, too. It sets up a finalizer for the object. Without this, the memory from the C++ side object is leaked.<br />
<br />
<syntaxhighlight lang="cpp"><br />
void TS_WindowStyleFinalizer(v8::Persistent<v8::Value> object, void* parameter) {<br />
TS_WindowStyle* ws = (TS_WindowStyle*)parameter;<br />
delete ws;<br />
object.Clear();<br />
object.Dispose();<br />
}<br />
</syntaxhighlight><br />
<br />
The naming of this function is rough edge I still haven't worked out for plugin.h. It must be TS_[name_passed_to_other_macros]Finalizer. I haven't worked out a better way to deal with this yet. Simply put, a finalizer object is called when the object it was attached to (in this case using the END_OBJECT_WRAP_CODE function). The JS object is passed as object, and a pointer to the C++-side object is passed as parameter. In this case, I just call delete on ws, since it was allocated with new. Do what you please to dispose of your C++ object. <br />
<br />
I also like to clear my JS objects before disposing of them. The simple answer to why is that this unambiguously means that all objects it references are no longer referenced by it from the garbage collector's perspective (even though Dispose does this too), since the object can't reference anything if it has been cleared.<br />
<br />
That should be enough to start off with. Feel free to point out any incorrect info you notice, ask questions, or stuff like that.<br />
<br />
--FlyingJester</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/Making_Plugins&diff=209User:Flying Jester/Making Plugins2013-03-21T02:16:27Z<p>Flying Jester: /* Forward */</p>
<hr />
<div>[[Category:Tutorials]]<br />
This is a tutorial/guide for making a plugin for TurboSphere. At the moment (about 03/25/2013) it is made with TurboSphere 0.2.1 (or 0.2.0) in mind.<br />
<br />
==Forward==<br />
<br />
Before we begin, I have to preface this. If you know nothing of C or C++, and don't plan on learning it, you probably will not be able to make a plugin. And if you are making a plugin before TurboSphere 1.0 is released, you may end up with a plugin that won't work with the first official release of TurboSphere. The API probably won't change too much between then and now, though, so this should at least get you up and running with the basics.<br />
<br />
Here I cover making a plugin that works for GCC-style toolchains (GCC, Clang, MingW, etc.), and MSVC style (MSVC cl.exe and DMC cl.exe) compilers. TurboSphere has traditionally been for Linux *and* Windows, 32 and 64 bit, after all, and I highly recommend at least making an attempt at cross compatibility.<br />
<br />
==Getting Started==<br />
<br />
Personally, I write plugins in C++. I know that is easy. It shouldn't be too hard to write it in C, either. But, I do know a C++ shim is necessary for any language other than C++, since to interface with V8 you need access to the C++ template library. If you know of another language that can interface directly with C++ STL libraries, go ahead and try to use that. I'd like to hear about it! :)<br />
<br />
I'm going to assume you are using the "plugin.h" file that is included with the TurboSphere source (plugins/common/plugins.h). I used this to make all the plugins included with TurboSphere. It might not be the best way to do this, but it's the set of tools I worked out from my years of making TurboSphere.<br />
<br />
If you look at windowstyleSDL, you can see a nice example of using plugins.h. But for one learn better with examples and explanations, so let's have a look at some example code explained.<br />
<br />
First, the header file. It uses preprocessor defines to ensure the plugin works both with the GCC on Linux and MSVC on Windows. I don't have an Intel Mac (V8 requires an x86, ARM, or MIPS CPU, so my old PPC Macs aren't going to work), so this would likely need a little something more to work on Mac.<br />
<br />
<syntaxhighlight lang="cpp"><br />
//windowstyleSDL.h:<br />
#ifndef WINDOWSTYLE_HEAD<br />
#define WINDOWSTYLE_HEAD<br />
<br />
#ifdef _WIN32<br />
#define WS_EXPORT __declspec(dllexport)<br />
<br />
#define CCALL __cdecl<br />
<br />
#endif<br />
#ifndef _WIN32<br />
#define CCALL <br />
#define WS_EXPORT extern "C"<br />
#endif<br />
<br />
#ifdef _WIN32<br />
extern "C" {<br />
#endif<br />
WS_EXPORT void Close(void);<br />
WS_EXPORT initFunction Init(void);<br />
WS_EXPORT int GetNumFunctions(void);<br />
WS_EXPORT functionArray GetFunctions(void);<br />
WS_EXPORT nameArray GetFunctionNames(void);<br />
WS_EXPORT int GetNumVariables(void);<br />
WS_EXPORT v8FunctionArray GetVariables(void);<br />
WS_EXPORT nameArray GetVariableNames(void);<br />
<br />
#ifdef _WIN32<br />
}<br />
#endif<br />
<br />
#endif<br />
</syntaxhighlight><br />
<br />
Now on to the main windowstyleSDL.cpp file:<br />
<br />
<syntaxhighlight lang="cpp"><br />
#include "../common/plugin.h"<br />
#include "windowstyleSDL.h"<br />
<br />
//This will be explained later.<br />
#define NUMFUNCS 2<br />
<br />
//forward declare C++ functions to be bound to JS<br />
v8Function LoadWindowStyle(V8ARGS);<br />
v8Function GetSystemWindowStyle(V8ARGS);<br />
<br />
//declare pointers to functions that will be passed to the engine to be bound<br />
void* LoadWindowStylePointer = V8FUNCPOINTER(LoadWindowStyle));<br />
void* GetSystemWindowStylePointer = V8FUNCPOINTER(GetSystemWindowStyle));<br />
<br />
</syntaxhighlight><br />
<br />
This is the start of windowstyle.cpp. Here, we include plugin.h, we forward declare the functions to be exposed to script, and then void pointers that point to the functions. That last part will be useful later.<br />
<br />
It also forward declares the mandatory functions of a plugin. In this case they only have linkage for GCC-style compilation, though. I'll add in how it's done with the Microsoft Visual C++ compiler at a later date.<br />
<br />
<syntaxhighlight lang="cpp"><br />
initFunction Init(){<br />
//Initialize the JS-side object templates<br />
INIT_OBJECT_TEMPLATES(WindowStyle);<br />
ADD_TO_PROTO(WindowStyle, "drawWindow", TS_WSdrawWindow);<br />
<br />
//return plugin's name to the engine.<br />
return (char *)"windowstyleSDL";<br />
}<br />
</syntaxhighlight><br />
<br />
Here we define the Init function. Every plugin must have an exposed Init function. This is called by TurboSphere for two reasons. The simple use is that it tells TurboSphere the plugin's name. It is guaranteed to be called before anything else. With this in mind, what are those other macros being called? the INIT_OBJECT_TEMPLATES and ADD_TO_PROTO? Well, let's look at one more function before we talk about that:<br />
<br />
<syntaxhighlight lang="cpp"><br />
void Close(){<br />
//Dispose of JS-side templates.<br />
CLOSE_OBJECT_TEMPLATES(WindowStyle);<br />
}<br />
</syntaxhighlight><br />
<br />
OK, this is the Close function. It's to be called when we are done with the plugin, and it will definitely be called after each call to Init before Init is called again. We can't be sure that Close will be called--what if TurboSphere hard-crashes? But we always do our best to call it before TurboSphere quits.<br />
<br />
So there's another macro. CLOSE_OBJECT_TEMPLATES. Well, unsurprisingly, that is the counterpart to INIT_OBJECT_TEMPLATES. They automate the process of making templates for binding C++ objects to JS. You can check out the details in the plugins.h file, but if you don't want to know the details just let it be. So far only one function in all of TurboSphere and the default plugins needs more knowhow than this, and in that case it wasn't necessary to not do it that way anyway.<br />
<br />
Both macros are passed a name, WindowStyle. This isn't defined before, as the macros define several objects using that name. Just pass them all the same name for the same object type, and it will work. The INIT_OBJECT_TEMPLATES macro creates the templates to create, wrap, and modify the prototypes of C++ to JS-side objects. The second macro, ADD_TO_PROTO, is an example of the latter. It binds the C++ function TS_WSdrawWindow to the JS_side object type that WindowStyle defines, and gives it the JS-side name drawWindow (windowstyle_object.drawWindow()). The CLOSE_OBJECT_TEMPLATES macro undefines the object template defined by WindowStyle, which cleans things out in JS (and gives back a bit of memory, ideally, although it doesn't actually work out this way for sure; V8 plays it fast and loose with memory when it thinks it can trade memory for speed).<br />
<br />
Let's have a look at the remaining mandatory functions of a plugin.<br />
<br />
<syntaxhighlight lang="cpp"><br />
int GetNumFunctions(){<br />
return NUMFUNCS;<br />
}<br />
<br />
int GetNumVariables(){<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
These functions return the number of variables and functions to be exposed to script. windowstyleSDL does not define any variables for script, but I will go over how that is done later anyway. For the moment, suffice it to say that it is simpler than exposing functions.<br />
<br />
<syntaxhighlight lang="cpp"><br />
//to simplify numbering functions and names.<br />
int numerate(bool reset){<br />
static int i = 0;<br />
if(reset) {<br />
i = 0;<br />
return 0;<br />
}<br />
i++;<br />
return i-1;<br />
}<br />
<br />
functionArray GetFunctions(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
functionArray funcs = (functionArray)calloc(NUMFUNCS, sizeof(void*));<br />
<br />
funcs[numerate(false)] = LoadWindowStylePointer;<br />
funcs[numerate(false)] = GetSystemWindowStylePointer;<br />
//return array of function pointers to to the engine.<br />
return funcs;<br />
}<br />
</syntaxhighlight><br />
<br />
The first function is just to simplify numbering the elements of arrays. You don't need to use it, but I found it quite useful when writing the inputSDL function which has well over a hundred variables defined (one for each key on a keyboard and several for mouse buttons).<br />
<br />
The second function is necessary, though. First we reset the numeration function to zero. Then we define the array of functions to be exposed. This is where those void pointers to the functions that will be exposed to V8 come in handy.<br />
<br />
On a side note: GCC gets a little angry at all this, throwing a warning since you aren't supposed to play with void pointers this way, but as far as I know you can do this on any compiler and it will work out. If you were really worried about warnings (instead of actual definite problems--don't think I don't take warnings eriously, give me minute!), you could probably pass them simply as pointers to the V8 functions, as they will be cast as void pointers in TurboSphere. But in that case you are just masking any problems! The compiler won't complain because the cast is made in between two binaries, and it can't see what is happening. If this is really a problem, then the compiler will give you an error--but only if it can see what you are doing. And yes, I could cast them as v8Function's on the TurboSphere side, but because of the...fluidity of JavaScript, there are some things that can be functions that you would then not be able to pass through to TurboSphere as such (JS can be wily beast, and is very much <br />
not like C++ when it comes to letting you pass of something as something else). I don't want to limit anything here just because the functionality is in a plugin, so I do it this way. [/sidenote]<br />
<br />
So, what about a GetVariables function?<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8FunctionArray GetVariables(){<br />
return NULL;<br />
}<br />
</syntaxhighlight><br />
<br />
If you have no variables, you can just return NULL. The function won't even be called by TurboSphere, anyway. And even if it was, NULL is an acceptable value; you can't read from an empty array, so it doesn't matter what the address of it is, and it has no data! It's what calloc would have returned had you told it to give you an array of zero size, too.<br />
<br />
I actually do have something to say about this when there are variables, so let's assume we had four variables to define. Let's say their names are SOME_NAME, VERSION, CONSTANT1 and CONSTANT2, in that order, just for sake of explanation. The function would then look like this<br />
<br />
<syntaxhighlight lang="cpp"><br />
//theoretical GetVariables<br />
v8FunctionArray GetVariables(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
nameArray varnames = (nameArray)calloc(NUMVARS, sizeof(v8Function));<br />
funcnames[numerate(false)] = v8::String::New("This Is A Name!"); //SOME_NAME<br />
funcnames[numerate(false)] = v8::Number::New(1.5); //VERSION<br />
funcnames[numerate(false)] = v8::Integer::New(0); //CONSTANT1<br />
funcnames[numerate(false)] = v8::Integer::New(1); //CONSTANT2<br />
return varnames;<br />
}<br />
</syntaxhighlight><br />
<br />
Here's an example of V8 and JS being very fluid with things; anything that can be a function can also be variable, and we use v8Function as the type for variables. The only time the opposite would not be true is when you deal with constructors that are strongly tied to the templates for JS-side objects. I'm not doing things that way, and in several cases multiple functions can be used as constructors for a single type, and V8 won't let me tell it there are two constructors for a single JS-side type (they bind slightly different kinds of objects on the C++ side). In any case, these are a few of the types you could pass back as variables.<br />
<br />
So, let's get on with what is actually a part of windowstyleSDL!<br />
<br />
<syntaxhighlight lang="cpp"><br />
nameArray GetFunctionNames(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
nameArray funcnames = (nameArray)calloc(NUMFUNCS, sizeof(functionName));<br />
<br />
funcnames[numerate(false)] = (functionName)"WindowStyle";<br />
funcnames[numerate(false)] = (functionName)"GetSystemWindowStyle";<br />
//return array of c-string function names to the engine.<br />
return funcnames;<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
This is much like the GetFunctions function, but in this case, since the names are hardcoded right there, we just tell the compiler to think of them as the type functionName (aka const char*, GCC throws a warning if you don't cast them this way, but unlike before it makes no difference to me if they are cast that way or not, so I do to limit the number of warnings when compiling), and be on our merry way. The names of variables are defined the same way, except the function would be called GetVariableNames, and we would use the type variableName instead of functionName (both are const char*, but why use a type like functionName with a misleading name? GetVariables notwithstanding!).<br />
<br />
And unsurprisingly<br />
<br />
<syntaxhighlight lang="cpp"><br />
nameArray GetVariableNames(){<br />
return NULL;<br />
}<br />
</syntaxhighlight><br />
<br />
Same deal here as with GetVariables. <br />
<br />
So that's it! Technically, this is everything you *need* for a plugin. If you defined GetNumFunctions to return 0, and GetFunctions and getFunctionNames to return NULL this would be perfectly functional (although totally useless) plugin. But you probably want your plugin to do something, right? <br />
<br />
Well, let's look at a single function that can be used by V8. There are a whole lot ways to do this, I might add, but this is how I've been doing it. If you want to do it a different way, be my guest.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function TestFunction(V8ARGS){<br />
return v8::Integer::New(42)<br />
}<br />
</syntaxhighlight><br />
<br />
Well, it doesn't do much. But if you passed a pointer to this function as one of the elements returned by GetFunctions, and then in JS called whatever name you gave it as a function, it would return 42 in JS. But, that's simple. In fact, you might well have been able to figure out most of that from what I went over in the theoretical GetVariables function. Let's look deeper.<br />
<br />
What if you want to deal with arguments? That's pretty simple, and it lets me show off some nice macros in plugin.h.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function ArgsTestFunction(V8ARGS){<br />
if(args.Length()<1){<br />
THROWERROR("ArgsTestFunction Error: Called with no arguments.");<br />
}<br />
CHECK_ARG_INT(0, "ArgsTestFunction Error: Argument 0 is not an integer.");<br />
<br />
int i = args[0]->IntegerValue();<br />
<br />
if(i==0){<br />
return v8::Integer::New(42);<br />
}<br />
else {<br />
return v8::String::New("That number was not 0!");<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
In this case, we have to deal with arguments. I have one thing that I cannot stress enough about arguments.<br />
<br />
Programmers are stupid and lazy. Even you, my friend, even me. So we can count on them passing garbage to our functions. I know I pass garbage to functions all the time, and even if they are really good programmers and rarely make that kind of mistake, these checks are useful for telling you where things went wrong. If you ever plan on using your own plugin, you will thank yourself for adding as many checks as possible.<br />
<br />
The first one is the check for the numebr of args. You could just as easily default to something, but this a good example of the THROWERROR macro, a paper thin wrapper around returning a v8::ThrowException function. It throws a JS-side exception with the text you give. It can be caught by script as well, which is a *good* *thing*. I recommend you put the function name into the error message. And I highly recommend you give some explanation for why the exception happened at all. Don't be shy about being specific, either.<br />
<br />
Simpler to do (with the help of plugin.h) is the check of parameter types. There exist several macros to check them for you:<br />
<br />
* CHECK_ARG_INT<br />
* CHECK_ARG_STR<br />
* CHECK_ARG_OBJ<br />
* CHECK_ARG_BOOL<br />
* CHECK_ARG_ARRAY<br />
<br />
Bear in mind that JS is a wily language when it comes to data validation. If you are using the OBJ or ARRAY checks, you might either rule out valid values or include values you don't want to. But the explanation of such things is beyond the scope here.<br />
<br />
These macros check the argument specified in the first parameter (here 0, the first arg), and throw the error specified in the second parameter if it is not the right type. Bear in mind, this doens't mean that it couldn't be cast to the right type, just that it isn't right now. Generally I would err on the side of throwing out edge-case-correct values than accepting bad values that seem like they might be OK. Better to throw a JS exception than to either make V8 die (which is ugly and won't tell you as much about what went wrong), or pass garbage into a C++ or C function, which can quite easily cause crashes. It can cause hard crashes, and we really don't want hard crashes. We really, really don't want them. Anytime you can stop one from happening, I'd really like you too. Every time a user has to use a task manager to close TurboSphere, they think that anyone who had a hand in making it, the game they are playing with it, or any plugins they use, are bad programmers. And this right here, this is where most <br />
crashes come from.<br />
<br />
So next we need to make the argument, which is a V8 type, into a C/C++ type. First, ask yourself, are you sure that only the correct type of value could have gotten to this cast (no really, this is important)? Good. There are a few easy ways to do this:<br />
<br />
<syntaxhighlight lang="cpp"><br />
int x = args[i]->IntegerValue();<br />
int x = args[i]->Int32Value();<br />
</syntaxhighlight><br />
<br />
Bear in mind that you will get some weirdness with this when you try to compile on both 32-bit and 64-bit architectures. IntegerValue returns a 64-bit integer, and Int32Value returns a 32-bit integer. You could avoid compiler warnings by using a fixed with type (int64_t), or by using some ugly preprocessor stuff. My recommendation is just to only go with 64-bits, but I know I'm not in charge of what word-length users' computers are, so just listen to your compiler of choice's warnings for what to do. If it doesn't complain, then don't worry about it--but bear in mind that TurboSphere will, one day somewhat soon, be 64-bit only, and possibly only able to load 64-bit plugins. At least think about making your code 64-bit safe if you want your plugin to stick around.<br />
<br />
<syntaxhighlight lang="cpp"><br />
bool x = args[i]->BooleanValue();<br />
</syntaxhighlight><br />
<br />
That one's pretty simple.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8::String::Utf8Value str(args[i]);<br />
//Which is completed with<br />
const char *cstr = *str;<br />
</syntaxhighlight><br />
<br />
Well, that's pretty much it for that. This is really more a V8 section than a TurboSphere plugin section, but the fact is TurboSphere is strongly linked to V8, so this is important. And plus, I want to help you avoid the pitfalls I fell into when I started out.<br />
<br />
So what else can we do? The part that gave me the most trouble, and is hard to figure out, and lacks good examples on the web, is using some JS-side types that you define yourself. That's what those object template macros were there for. Let's use them.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function LoadWindowStyle(V8ARGS) {<br />
if(args.Length()<1){<br />
return v8::ThrowException(v8::String::New("LoadWindowStyle Error: Called with no arguments."));<br />
}<br />
CHECK_ARG_STR(0, "LoadWindowStyle Error: Arg 0 is not a string.");<br />
<br />
BEGIN_OBJECT_WRAP_CODE<br />
<br />
TS_WindowStyle *ws = NULL;<br />
<br />
v8::String::Utf8Value str(args[0]);<br />
const char *wsname = *str;<br />
<br />
SDL_RWops *wstest = SDL_RWFromFile(string(TS_dirs.windowstyle).append(wsname).c_str(), "rb");<br />
if(!wstest){<br />
SDL_RWclose(wstest);<br />
THROWERROR(string("LoadWindowStyle Error: Could not load windowstyle ").append(wsname).c_str());<br />
}<br />
SDL_RWclose(wstest);<br />
<br />
ws = new TS_WindowStyle(string(TS_dirs.windowstyle).append(wsname).c_str());<br />
<br />
if(!ws){<br />
SDL_RWclose(wstest);<br />
THROWERROR(string("LoadWindowStyle Error: Could not load windowstyle ").append(wsname).c_str());<br />
}<br />
<br />
END_OBJECT_WRAP_CODE(WindowStyle, ws);<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
Don't worry about the TS_WindowStyle stuff. Just suffice it to say that it is a C++ type, which constructs an C++ object from a given file. I left a lot of that stuff in the example, because it is validation code, and that is important to have. You can pass any string to this function, and even though it will not throw an exception at the CHECK_ARG_STR line, it will still throw an error that it could not open the file. So we know the file exists. And even then, if we can't read the file for whatever reason (likely it's not a valid file for this object to read), we still throw an error instead of passing back an empty or broken object.<br />
<br />
I will admit right here that I lied. Most of the work to wrap objects for JS is hidden behind the BEGIN_OBJECT_WRAP_CODE and END_OBJECT_WRAP_CODE macros.<br />
<br />
So let's get to the meat of the function. BEGIN_OBJECT_WRAP_CODE is a macro that sets up for END_OBJECT_WRAP_CODE. You have to use the former if you use the latter. Note that END_OBJECT_WRAP_CODE uses the same name, WindowStyle, as INIT_OBJECT_TEMPLATES and ADD_TO_PROTO did. That's important. Because of that, the object has ready made templates for V8, and the prototype has the member drawWindow already attached. The END_OBJECT_CODE does one more thing, too. It sets up a finalizer for the object. Without this, the memory from the C++ side object is leaked.<br />
<br />
<syntaxhighlight lang="cpp"><br />
void TS_WindowStyleFinalizer(v8::Persistent<v8::Value> object, void* parameter) {<br />
TS_WindowStyle* ws = (TS_WindowStyle*)parameter;<br />
delete ws;<br />
object.Clear();<br />
object.Dispose();<br />
}<br />
</syntaxhighlight><br />
<br />
The naming of this function is rough edge I still haven't worked out for plugin.h. It must be TS_[name_passed_to_other_macros]Finalizer. I haven't worked out a better way to deal with this yet. Simply put, a finalizer object is called when the object it was attached to (in this case using the END_OBJECT_WRAP_CODE function). The JS object is passed as object, and a pointer to the C++-side object is passed as parameter. In this case, I just call delete on ws, since it was allocated with new. Do what you please to dispose of your C++ object. <br />
<br />
I also like to clear my JS objects before disposing of them. The simple answer to why is that this unambiguously means that all objects it references are no longer referenced by it from the garbage collector's perspective (even though Dispose does this too), since the object can't reference anything if it has been cleared.<br />
<br />
That should be enough to start off with. Feel free to point out any incorrect info you notice, ask questions, or stuff like that.<br />
<br />
--FlyingJester</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/Making_Plugins&diff=208User:Flying Jester/Making Plugins2013-03-21T02:13:56Z<p>Flying Jester: /* Getting Started */</p>
<hr />
<div>[[Category:Tutorials]]<br />
This is a tutorial/guide for making a plugin for TurboSphere. At the moment (about 03/25/2013) it is made with TurboSphere 0.2.1 (or 0.2.0) in mind.<br />
<br />
==Forward==<br />
<br />
Before we begin, I have to preface this. If you know nothing of C or C++, and don't plan on learning it, you probably will not be able to make a plugin. And if you are making a plugin before TurboSphere 1.0 is released, you may end up with a plugin that won't work with the first official release of TurboSphere. The API probably won't change too much between then and now, though.<br />
<br />
Also, at the moment, I only cover making a plugin that works for GCC-style toolchains (GCC, Clang, MingW, etc.). This is useful, and even when I add the Microsoft Visual C++ information, I recommend adding preprocessor macros to make it work on all platforms. TurboSphere has traditionally been for Linux *and* Windows, 32 and 64 bit, after all.<br />
<br />
==Getting Started==<br />
<br />
Personally, I write plugins in C++. I know that is easy. It shouldn't be too hard to write it in C, either. But, I do know a C++ shim is necessary for any language other than C++, since to interface with V8 you need access to the C++ template library. If you know of another language that can interface directly with C++ STL libraries, go ahead and try to use that. I'd like to hear about it! :)<br />
<br />
I'm going to assume you are using the "plugin.h" file that is included with the TurboSphere source (plugins/common/plugins.h). I used this to make all the plugins included with TurboSphere. It might not be the best way to do this, but it's the set of tools I worked out from my years of making TurboSphere.<br />
<br />
If you look at windowstyleSDL, you can see a nice example of using plugins.h. But for one learn better with examples and explanations, so let's have a look at some example code explained.<br />
<br />
First, the header file. It uses preprocessor defines to ensure the plugin works both with the GCC on Linux and MSVC on Windows. I don't have an Intel Mac (V8 requires an x86, ARM, or MIPS CPU, so my old PPC Macs aren't going to work), so this would likely need a little something more to work on Mac.<br />
<br />
<syntaxhighlight lang="cpp"><br />
//windowstyleSDL.h:<br />
#ifndef WINDOWSTYLE_HEAD<br />
#define WINDOWSTYLE_HEAD<br />
<br />
#ifdef _WIN32<br />
#define WS_EXPORT __declspec(dllexport)<br />
<br />
#define CCALL __cdecl<br />
<br />
#endif<br />
#ifndef _WIN32<br />
#define CCALL <br />
#define WS_EXPORT extern "C"<br />
#endif<br />
<br />
#ifdef _WIN32<br />
extern "C" {<br />
#endif<br />
WS_EXPORT void Close(void);<br />
WS_EXPORT initFunction Init(void);<br />
WS_EXPORT int GetNumFunctions(void);<br />
WS_EXPORT functionArray GetFunctions(void);<br />
WS_EXPORT nameArray GetFunctionNames(void);<br />
WS_EXPORT int GetNumVariables(void);<br />
WS_EXPORT v8FunctionArray GetVariables(void);<br />
WS_EXPORT nameArray GetVariableNames(void);<br />
<br />
#ifdef _WIN32<br />
}<br />
#endif<br />
<br />
#endif<br />
</syntaxhighlight><br />
<br />
Now on to the main windowstyleSDL.cpp file:<br />
<br />
<syntaxhighlight lang="cpp"><br />
#include "../common/plugin.h"<br />
#include "windowstyleSDL.h"<br />
<br />
//This will be explained later.<br />
#define NUMFUNCS 2<br />
<br />
//forward declare C++ functions to be bound to JS<br />
v8Function LoadWindowStyle(V8ARGS);<br />
v8Function GetSystemWindowStyle(V8ARGS);<br />
<br />
//declare pointers to functions that will be passed to the engine to be bound<br />
void* LoadWindowStylePointer = V8FUNCPOINTER(LoadWindowStyle));<br />
void* GetSystemWindowStylePointer = V8FUNCPOINTER(GetSystemWindowStyle));<br />
<br />
</syntaxhighlight><br />
<br />
This is the start of windowstyle.cpp. Here, we include plugin.h, we forward declare the functions to be exposed to script, and then void pointers that point to the functions. That last part will be useful later.<br />
<br />
It also forward declares the mandatory functions of a plugin. In this case they only have linkage for GCC-style compilation, though. I'll add in how it's done with the Microsoft Visual C++ compiler at a later date.<br />
<br />
<syntaxhighlight lang="cpp"><br />
initFunction Init(){<br />
//Initialize the JS-side object templates<br />
INIT_OBJECT_TEMPLATES(WindowStyle);<br />
ADD_TO_PROTO(WindowStyle, "drawWindow", TS_WSdrawWindow);<br />
<br />
//return plugin's name to the engine.<br />
return (char *)"windowstyleSDL";<br />
}<br />
</syntaxhighlight><br />
<br />
Here we define the Init function. Every plugin must have an exposed Init function. This is called by TurboSphere for two reasons. The simple use is that it tells TurboSphere the plugin's name. It is guaranteed to be called before anything else. With this in mind, what are those other macros being called? the INIT_OBJECT_TEMPLATES and ADD_TO_PROTO? Well, let's look at one more function before we talk about that:<br />
<br />
<syntaxhighlight lang="cpp"><br />
void Close(){<br />
//Dispose of JS-side templates.<br />
CLOSE_OBJECT_TEMPLATES(WindowStyle);<br />
}<br />
</syntaxhighlight><br />
<br />
OK, this is the Close function. It's to be called when we are done with the plugin, and it will definitely be called after each call to Init before Init is called again. We can't be sure that Close will be called--what if TurboSphere hard-crashes? But we always do our best to call it before TurboSphere quits.<br />
<br />
So there's another macro. CLOSE_OBJECT_TEMPLATES. Well, unsurprisingly, that is the counterpart to INIT_OBJECT_TEMPLATES. They automate the process of making templates for binding C++ objects to JS. You can check out the details in the plugins.h file, but if you don't want to know the details just let it be. So far only one function in all of TurboSphere and the default plugins needs more knowhow than this, and in that case it wasn't necessary to not do it that way anyway.<br />
<br />
Both macros are passed a name, WindowStyle. This isn't defined before, as the macros define several objects using that name. Just pass them all the same name for the same object type, and it will work. The INIT_OBJECT_TEMPLATES macro creates the templates to create, wrap, and modify the prototypes of C++ to JS-side objects. The second macro, ADD_TO_PROTO, is an example of the latter. It binds the C++ function TS_WSdrawWindow to the JS_side object type that WindowStyle defines, and gives it the JS-side name drawWindow (windowstyle_object.drawWindow()). The CLOSE_OBJECT_TEMPLATES macro undefines the object template defined by WindowStyle, which cleans things out in JS (and gives back a bit of memory, ideally, although it doesn't actually work out this way for sure; V8 plays it fast and loose with memory when it thinks it can trade memory for speed).<br />
<br />
Let's have a look at the remaining mandatory functions of a plugin.<br />
<br />
<syntaxhighlight lang="cpp"><br />
int GetNumFunctions(){<br />
return NUMFUNCS;<br />
}<br />
<br />
int GetNumVariables(){<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
These functions return the number of variables and functions to be exposed to script. windowstyleSDL does not define any variables for script, but I will go over how that is done later anyway. For the moment, suffice it to say that it is simpler than exposing functions.<br />
<br />
<syntaxhighlight lang="cpp"><br />
//to simplify numbering functions and names.<br />
int numerate(bool reset){<br />
static int i = 0;<br />
if(reset) {<br />
i = 0;<br />
return 0;<br />
}<br />
i++;<br />
return i-1;<br />
}<br />
<br />
functionArray GetFunctions(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
functionArray funcs = (functionArray)calloc(NUMFUNCS, sizeof(void*));<br />
<br />
funcs[numerate(false)] = LoadWindowStylePointer;<br />
funcs[numerate(false)] = GetSystemWindowStylePointer;<br />
//return array of function pointers to to the engine.<br />
return funcs;<br />
}<br />
</syntaxhighlight><br />
<br />
The first function is just to simplify numbering the elements of arrays. You don't need to use it, but I found it quite useful when writing the inputSDL function which has well over a hundred variables defined (one for each key on a keyboard and several for mouse buttons).<br />
<br />
The second function is necessary, though. First we reset the numeration function to zero. Then we define the array of functions to be exposed. This is where those void pointers to the functions that will be exposed to V8 come in handy.<br />
<br />
On a side note: GCC gets a little angry at all this, throwing a warning since you aren't supposed to play with void pointers this way, but as far as I know you can do this on any compiler and it will work out. If you were really worried about warnings (instead of actual definite problems--don't think I don't take warnings eriously, give me minute!), you could probably pass them simply as pointers to the V8 functions, as they will be cast as void pointers in TurboSphere. But in that case you are just masking any problems! The compiler won't complain because the cast is made in between two binaries, and it can't see what is happening. If this is really a problem, then the compiler will give you an error--but only if it can see what you are doing. And yes, I could cast them as v8Function's on the TurboSphere side, but because of the...fluidity of JavaScript, there are some things that can be functions that you would then not be able to pass through to TurboSphere as such (JS can be wily beast, and is very much <br />
not like C++ when it comes to letting you pass of something as something else). I don't want to limit anything here just because the functionality is in a plugin, so I do it this way. [/sidenote]<br />
<br />
So, what about a GetVariables function?<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8FunctionArray GetVariables(){<br />
return NULL;<br />
}<br />
</syntaxhighlight><br />
<br />
If you have no variables, you can just return NULL. The function won't even be called by TurboSphere, anyway. And even if it was, NULL is an acceptable value; you can't read from an empty array, so it doesn't matter what the address of it is, and it has no data! It's what calloc would have returned had you told it to give you an array of zero size, too.<br />
<br />
I actually do have something to say about this when there are variables, so let's assume we had four variables to define. Let's say their names are SOME_NAME, VERSION, CONSTANT1 and CONSTANT2, in that order, just for sake of explanation. The function would then look like this<br />
<br />
<syntaxhighlight lang="cpp"><br />
//theoretical GetVariables<br />
v8FunctionArray GetVariables(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
nameArray varnames = (nameArray)calloc(NUMVARS, sizeof(v8Function));<br />
funcnames[numerate(false)] = v8::String::New("This Is A Name!"); //SOME_NAME<br />
funcnames[numerate(false)] = v8::Number::New(1.5); //VERSION<br />
funcnames[numerate(false)] = v8::Integer::New(0); //CONSTANT1<br />
funcnames[numerate(false)] = v8::Integer::New(1); //CONSTANT2<br />
return varnames;<br />
}<br />
</syntaxhighlight><br />
<br />
Here's an example of V8 and JS being very fluid with things; anything that can be a function can also be variable, and we use v8Function as the type for variables. The only time the opposite would not be true is when you deal with constructors that are strongly tied to the templates for JS-side objects. I'm not doing things that way, and in several cases multiple functions can be used as constructors for a single type, and V8 won't let me tell it there are two constructors for a single JS-side type (they bind slightly different kinds of objects on the C++ side). In any case, these are a few of the types you could pass back as variables.<br />
<br />
So, let's get on with what is actually a part of windowstyleSDL!<br />
<br />
<syntaxhighlight lang="cpp"><br />
nameArray GetFunctionNames(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
nameArray funcnames = (nameArray)calloc(NUMFUNCS, sizeof(functionName));<br />
<br />
funcnames[numerate(false)] = (functionName)"WindowStyle";<br />
funcnames[numerate(false)] = (functionName)"GetSystemWindowStyle";<br />
//return array of c-string function names to the engine.<br />
return funcnames;<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
This is much like the GetFunctions function, but in this case, since the names are hardcoded right there, we just tell the compiler to think of them as the type functionName (aka const char*, GCC throws a warning if you don't cast them this way, but unlike before it makes no difference to me if they are cast that way or not, so I do to limit the number of warnings when compiling), and be on our merry way. The names of variables are defined the same way, except the function would be called GetVariableNames, and we would use the type variableName instead of functionName (both are const char*, but why use a type like functionName with a misleading name? GetVariables notwithstanding!).<br />
<br />
And unsurprisingly<br />
<br />
<syntaxhighlight lang="cpp"><br />
nameArray GetVariableNames(){<br />
return NULL;<br />
}<br />
</syntaxhighlight><br />
<br />
Same deal here as with GetVariables. <br />
<br />
So that's it! Technically, this is everything you *need* for a plugin. If you defined GetNumFunctions to return 0, and GetFunctions and getFunctionNames to return NULL this would be perfectly functional (although totally useless) plugin. But you probably want your plugin to do something, right? <br />
<br />
Well, let's look at a single function that can be used by V8. There are a whole lot ways to do this, I might add, but this is how I've been doing it. If you want to do it a different way, be my guest.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function TestFunction(V8ARGS){<br />
return v8::Integer::New(42)<br />
}<br />
</syntaxhighlight><br />
<br />
Well, it doesn't do much. But if you passed a pointer to this function as one of the elements returned by GetFunctions, and then in JS called whatever name you gave it as a function, it would return 42 in JS. But, that's simple. In fact, you might well have been able to figure out most of that from what I went over in the theoretical GetVariables function. Let's look deeper.<br />
<br />
What if you want to deal with arguments? That's pretty simple, and it lets me show off some nice macros in plugin.h.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function ArgsTestFunction(V8ARGS){<br />
if(args.Length()<1){<br />
THROWERROR("ArgsTestFunction Error: Called with no arguments.");<br />
}<br />
CHECK_ARG_INT(0, "ArgsTestFunction Error: Argument 0 is not an integer.");<br />
<br />
int i = args[0]->IntegerValue();<br />
<br />
if(i==0){<br />
return v8::Integer::New(42);<br />
}<br />
else {<br />
return v8::String::New("That number was not 0!");<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
In this case, we have to deal with arguments. I have one thing that I cannot stress enough about arguments.<br />
<br />
Programmers are stupid and lazy. Even you, my friend, even me. So we can count on them passing garbage to our functions. I know I pass garbage to functions all the time, and even if they are really good programmers and rarely make that kind of mistake, these checks are useful for telling you where things went wrong. If you ever plan on using your own plugin, you will thank yourself for adding as many checks as possible.<br />
<br />
The first one is the check for the numebr of args. You could just as easily default to something, but this a good example of the THROWERROR macro, a paper thin wrapper around returning a v8::ThrowException function. It throws a JS-side exception with the text you give. It can be caught by script as well, which is a *good* *thing*. I recommend you put the function name into the error message. And I highly recommend you give some explanation for why the exception happened at all. Don't be shy about being specific, either.<br />
<br />
Simpler to do (with the help of plugin.h) is the check of parameter types. There exist several macros to check them for you:<br />
<br />
* CHECK_ARG_INT<br />
* CHECK_ARG_STR<br />
* CHECK_ARG_OBJ<br />
* CHECK_ARG_BOOL<br />
* CHECK_ARG_ARRAY<br />
<br />
Bear in mind that JS is a wily language when it comes to data validation. If you are using the OBJ or ARRAY checks, you might either rule out valid values or include values you don't want to. But the explanation of such things is beyond the scope here.<br />
<br />
These macros check the argument specified in the first parameter (here 0, the first arg), and throw the error specified in the second parameter if it is not the right type. Bear in mind, this doens't mean that it couldn't be cast to the right type, just that it isn't right now. Generally I would err on the side of throwing out edge-case-correct values than accepting bad values that seem like they might be OK. Better to throw a JS exception than to either make V8 die (which is ugly and won't tell you as much about what went wrong), or pass garbage into a C++ or C function, which can quite easily cause crashes. It can cause hard crashes, and we really don't want hard crashes. We really, really don't want them. Anytime you can stop one from happening, I'd really like you too. Every time a user has to use a task manager to close TurboSphere, they think that anyone who had a hand in making it, the game they are playing with it, or any plugins they use, are bad programmers. And this right here, this is where most <br />
crashes come from.<br />
<br />
So next we need to make the argument, which is a V8 type, into a C/C++ type. First, ask yourself, are you sure that only the correct type of value could have gotten to this cast (no really, this is important)? Good. There are a few easy ways to do this:<br />
<br />
<syntaxhighlight lang="cpp"><br />
int x = args[i]->IntegerValue();<br />
int x = args[i]->Int32Value();<br />
</syntaxhighlight><br />
<br />
Bear in mind that you will get some weirdness with this when you try to compile on both 32-bit and 64-bit architectures. IntegerValue returns a 64-bit integer, and Int32Value returns a 32-bit integer. You could avoid compiler warnings by using a fixed with type (int64_t), or by using some ugly preprocessor stuff. My recommendation is just to only go with 64-bits, but I know I'm not in charge of what word-length users' computers are, so just listen to your compiler of choice's warnings for what to do. If it doesn't complain, then don't worry about it--but bear in mind that TurboSphere will, one day somewhat soon, be 64-bit only, and possibly only able to load 64-bit plugins. At least think about making your code 64-bit safe if you want your plugin to stick around.<br />
<br />
<syntaxhighlight lang="cpp"><br />
bool x = args[i]->BooleanValue();<br />
</syntaxhighlight><br />
<br />
That one's pretty simple.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8::String::Utf8Value str(args[i]);<br />
//Which is completed with<br />
const char *cstr = *str;<br />
</syntaxhighlight><br />
<br />
Well, that's pretty much it for that. This is really more a V8 section than a TurboSphere plugin section, but the fact is TurboSphere is strongly linked to V8, so this is important. And plus, I want to help you avoid the pitfalls I fell into when I started out.<br />
<br />
So what else can we do? The part that gave me the most trouble, and is hard to figure out, and lacks good examples on the web, is using some JS-side types that you define yourself. That's what those object template macros were there for. Let's use them.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function LoadWindowStyle(V8ARGS) {<br />
if(args.Length()<1){<br />
return v8::ThrowException(v8::String::New("LoadWindowStyle Error: Called with no arguments."));<br />
}<br />
CHECK_ARG_STR(0, "LoadWindowStyle Error: Arg 0 is not a string.");<br />
<br />
BEGIN_OBJECT_WRAP_CODE<br />
<br />
TS_WindowStyle *ws = NULL;<br />
<br />
v8::String::Utf8Value str(args[0]);<br />
const char *wsname = *str;<br />
<br />
SDL_RWops *wstest = SDL_RWFromFile(string(TS_dirs.windowstyle).append(wsname).c_str(), "rb");<br />
if(!wstest){<br />
SDL_RWclose(wstest);<br />
THROWERROR(string("LoadWindowStyle Error: Could not load windowstyle ").append(wsname).c_str());<br />
}<br />
SDL_RWclose(wstest);<br />
<br />
ws = new TS_WindowStyle(string(TS_dirs.windowstyle).append(wsname).c_str());<br />
<br />
if(!ws){<br />
SDL_RWclose(wstest);<br />
THROWERROR(string("LoadWindowStyle Error: Could not load windowstyle ").append(wsname).c_str());<br />
}<br />
<br />
END_OBJECT_WRAP_CODE(WindowStyle, ws);<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
Don't worry about the TS_WindowStyle stuff. Just suffice it to say that it is a C++ type, which constructs an C++ object from a given file. I left a lot of that stuff in the example, because it is validation code, and that is important to have. You can pass any string to this function, and even though it will not throw an exception at the CHECK_ARG_STR line, it will still throw an error that it could not open the file. So we know the file exists. And even then, if we can't read the file for whatever reason (likely it's not a valid file for this object to read), we still throw an error instead of passing back an empty or broken object.<br />
<br />
I will admit right here that I lied. Most of the work to wrap objects for JS is hidden behind the BEGIN_OBJECT_WRAP_CODE and END_OBJECT_WRAP_CODE macros.<br />
<br />
So let's get to the meat of the function. BEGIN_OBJECT_WRAP_CODE is a macro that sets up for END_OBJECT_WRAP_CODE. You have to use the former if you use the latter. Note that END_OBJECT_WRAP_CODE uses the same name, WindowStyle, as INIT_OBJECT_TEMPLATES and ADD_TO_PROTO did. That's important. Because of that, the object has ready made templates for V8, and the prototype has the member drawWindow already attached. The END_OBJECT_CODE does one more thing, too. It sets up a finalizer for the object. Without this, the memory from the C++ side object is leaked.<br />
<br />
<syntaxhighlight lang="cpp"><br />
void TS_WindowStyleFinalizer(v8::Persistent<v8::Value> object, void* parameter) {<br />
TS_WindowStyle* ws = (TS_WindowStyle*)parameter;<br />
delete ws;<br />
object.Clear();<br />
object.Dispose();<br />
}<br />
</syntaxhighlight><br />
<br />
The naming of this function is rough edge I still haven't worked out for plugin.h. It must be TS_[name_passed_to_other_macros]Finalizer. I haven't worked out a better way to deal with this yet. Simply put, a finalizer object is called when the object it was attached to (in this case using the END_OBJECT_WRAP_CODE function). The JS object is passed as object, and a pointer to the C++-side object is passed as parameter. In this case, I just call delete on ws, since it was allocated with new. Do what you please to dispose of your C++ object. <br />
<br />
I also like to clear my JS objects before disposing of them. The simple answer to why is that this unambiguously means that all objects it references are no longer referenced by it from the garbage collector's perspective (even though Dispose does this too), since the object can't reference anything if it has been cleared.<br />
<br />
That should be enough to start off with. Feel free to point out any incorrect info you notice, ask questions, or stuff like that.<br />
<br />
--FlyingJester</div>Flying Jesterhttp://wiki.spheredev.org/index.php?title=User:Flying_Jester/Making_Plugins&diff=128User:Flying Jester/Making Plugins2013-03-18T22:52:55Z<p>Flying Jester: Created page with "Category:Tutorials This is a tutorial/guide for making a plugin for TurboSphere. At the moment (about 03/25/2013) it is made with TurboSphere 0.2.1 (or 0.2.0) in mind. ==..."</p>
<hr />
<div>[[Category:Tutorials]]<br />
This is a tutorial/guide for making a plugin for TurboSphere. At the moment (about 03/25/2013) it is made with TurboSphere 0.2.1 (or 0.2.0) in mind.<br />
<br />
==Forward==<br />
<br />
Before we begin, I have to preface this. If you know nothing of C or C++, and don't plan on learning it, you probably will not be able to make a plugin. And if you are making a plugin before TurboSphere 1.0 is released, you may end up with a plugin that won't work with the first official release of TurboSphere. The API probably won't change too much between then and now, though.<br />
<br />
Also, at the moment, I only cover making a plugin that works for GCC-style toolchains (GCC, Clang, MingW, etc.). This is useful, and even when I add the Microsoft Visual C++ information, I recommend adding preprocessor macros to make it work on all platforms. TurboSphere has traditionally been for Linux *and* Windows, 32 and 64 bit, after all.<br />
<br />
==Getting Started==<br />
<br />
Personally, I write plugins in C++. I know that is easy. It shouldn't be too hard to write it in C, either. But, I do know a C++ shim is necessary for any language other than C++, since to interface with V8 you need access to the C++ template library. If you know of another language that can interface directly with C++ STL libraries, go ahead and try to use that. I'd like to hear about it! :)<br />
<br />
I'm going to assume you are using the "plugin.h" file that is included with the TurboSphere source (plugins/common/plugins.h). I used this to make all the plugins included with TurboSphere. It might not be the best way to do this, but it's the set of tools I worked out from my years of making TurboSphere.<br />
<br />
If you look at windowstyleSDL, you can see a nice example of using plugins.h. But for one learn better with examples and explanations, so let's have a look at some example code explained.<br />
<br />
<syntaxhighlight lang="cpp"><br />
#include "../common/plugin.h"<br />
<br />
//decare plugin functions to have C-linkage. This would be different in Windows, especially with MSVC.<br />
extern "C" void Close(void);<br />
extern "C" initFunction Init(void);<br />
extern "C" int GetNumFunctions(void);<br />
extern "C" functionArray GetFunctions(void);<br />
extern "C" nameArray GetFunctionNames(void);<br />
extern "C" int GetNumVariables(void);<br />
extern "C" v8FunctionArray GetVariables(void);<br />
extern "C" nameArray GetVariableNames(void);<br />
<br />
//This will be explained later.<br />
#define NUMFUNCS 2<br />
<br />
//forward declare C++ functions to be bound to JS<br />
v8Function LoadWindowStyle(V8ARGS);<br />
v8Function GetSystemWindowStyle(V8ARGS);<br />
<br />
//declare pointers to functions that will be passed to the engine to be bound<br />
void* LoadWindowStylePointer = V8FUNCPOINTER(LoadWindowStyle));<br />
void* GetSystemWindowStylePointer = V8FUNCPOINTER(GetSystemWindowStyle));<br />
<br />
</syntaxhighlight><br />
<br />
This is the start of windowstyle.cpp. Here, we include plugin.h, we forward declare the functions to be exposed to script, and then void pointers that point to the functions. That last part will be useful later.<br />
<br />
It also forward declares the mandatory functions of a plugin. In this case they only have linkage for GCC-style compilation, though. I'll add in how it's done with the Microsoft Visual C++ compiler at a later date.<br />
<br />
<syntaxhighlight lang="cpp"><br />
initFunction Init(){<br />
//Initialize the JS-side object templates<br />
INIT_OBJECT_TEMPLATES(WindowStyle);<br />
ADD_TO_PROTO(WindowStyle, "drawWindow", TS_WSdrawWindow);<br />
<br />
//return plugin's name to the engine.<br />
return (char *)"windowstyleSDL";<br />
}<br />
</syntaxhighlight><br />
<br />
Here we define the Init function. Every plugin must have an exposed Init function. This is called by TurboSphere for two reasons. The simple use is that it tells TurboSphere the plugin's name. It is guaranteed to be called before anything else. With this in mind, what are those other macros being called? the INIT_OBJECT_TEMPLATES and ADD_TO_PROTO? Well, let's look at one more function before we talk about that:<br />
<br />
<syntaxhighlight lang="cpp"><br />
void Close(){<br />
//Dispose of JS-side templates.<br />
CLOSE_OBJECT_TEMPLATES(WindowStyle);<br />
}<br />
</syntaxhighlight><br />
<br />
OK, this is the Close function. It's to be called when we are done with the plugin, and it will definitely be called after each call to Init before Init is called again. We can't be sure that Close will be called--what if TurboSphere hard-crashes? But we always do our best to call it before TurboSphere quits.<br />
<br />
So there's another macro. CLOSE_OBJECT_TEMPLATES. Well, unsurprisingly, that is the counterpart to INIT_OBJECT_TEMPLATES. They automate the process of making templates for binding C++ objects to JS. You can check out the details in the plugins.h file, but if you don't want to know the details just let it be. So far only one function in all of TurboSphere and the default plugins needs more knowhow than this, and in that case it wasn't necessary to not do it that way anyway.<br />
<br />
Both macros are passed a name, WindowStyle. This isn't defined before, as the macros define several objects using that name. Just pass them all the same name for the same object type, and it will work. The INIT_OBJECT_TEMPLATES macro creates the templates to create, wrap, and modify the prototypes of C++ to JS-side objects. The second macro, ADD_TO_PROTO, is an example of the latter. It binds the C++ function TS_WSdrawWindow to the JS_side object type that WindowStyle defines, and gives it the JS-side name drawWindow (windowstyle_object.drawWindow()). The CLOSE_OBJECT_TEMPLATES macro undefines the object template defined by WindowStyle, which cleans things out in JS (and gives back a bit of memory, ideally, although it doesn't actually work out this way for sure; V8 plays it fast and loose with memory when it thinks it can trade memory for speed).<br />
<br />
Let's have a look at the remaining mandatory functions of a plugin.<br />
<br />
<syntaxhighlight lang="cpp"><br />
int GetNumFunctions(){<br />
return NUMFUNCS;<br />
}<br />
<br />
int GetNumVariables(){<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
These functions return the number of variables and functions to be exposed to script. windowstyleSDL does not define any variables for script, but I will go over how that is done later anyway. For the moment, suffice it to say that it is simpler than exposing functions.<br />
<br />
<syntaxhighlight lang="cpp"><br />
//to simplify numbering functions and names.<br />
int numerate(bool reset){<br />
static int i = 0;<br />
if(reset) {<br />
i = 0;<br />
return 0;<br />
}<br />
i++;<br />
return i-1;<br />
}<br />
<br />
functionArray GetFunctions(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
functionArray funcs = (functionArray)calloc(NUMFUNCS, sizeof(void*));<br />
<br />
funcs[numerate(false)] = LoadWindowStylePointer;<br />
funcs[numerate(false)] = GetSystemWindowStylePointer;<br />
//return array of function pointers to to the engine.<br />
return funcs;<br />
}<br />
</syntaxhighlight><br />
<br />
The first function is just to simplify numbering the elements of arrays. You don't need to use it, but I found it quite useful when writing the inputSDL function which has well over a hundred variables defined (one for each key on a keyboard and several for mouse buttons).<br />
<br />
The second function is necessary, though. First we reset the numeration function to zero. Then we define the array of functions to be exposed. This is where those void pointers to the functions that will be exposed to V8 come in handy.<br />
<br />
On a side note: GCC gets a little angry at all this, throwing a warning since you aren't supposed to play with void pointers this way, but as far as I know you can do this on any compiler and it will work out. If you were really worried about warnings (instead of actual definite problems--don't think I don't take warnings eriously, give me minute!), you could probably pass them simply as pointers to the V8 functions, as they will be cast as void pointers in TurboSphere. But in that case you are just masking any problems! The compiler won't complain because the cast is made in between two binaries, and it can't see what is happening. If this is really a problem, then the compiler will give you an error--but only if it can see what you are doing. And yes, I could cast them as v8Function's on the TurboSphere side, but because of the...fluidity of JavaScript, there are some things that can be functions that you would then not be able to pass through to TurboSphere as such (JS can be wily beast, and is very much <br />
not like C++ when it comes to letting you pass of something as something else). I don't want to limit anything here just because the functionality is in a plugin, so I do it this way. [/sidenote]<br />
<br />
So, what about a GetVariables function?<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8FunctionArray GetVariables(){<br />
return NULL;<br />
}<br />
</syntaxhighlight><br />
<br />
If you have no variables, you can just return NULL. The function won't even be called by TurboSphere, anyway. And even if it was, NULL is an acceptable value; you can't read from an empty array, so it doesn't matter what the address of it is, and it has no data! It's what calloc would have returned had you told it to give you an array of zero size, too.<br />
<br />
I actually do have something to say about this when there are variables, so let's assume we had four variables to define. Let's say their names are SOME_NAME, VERSION, CONSTANT1 and CONSTANT2, in that order, just for sake of explanation. The function would then look like this<br />
<br />
<syntaxhighlight lang="cpp"><br />
//theoretical GetVariables<br />
v8FunctionArray GetVariables(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
nameArray varnames = (nameArray)calloc(NUMVARS, sizeof(v8Function));<br />
funcnames[numerate(false)] = v8::String::New("This Is A Name!"); //SOME_NAME<br />
funcnames[numerate(false)] = v8::Number::New(1.5); //VERSION<br />
funcnames[numerate(false)] = v8::Integer::New(0); //CONSTANT1<br />
funcnames[numerate(false)] = v8::Integer::New(1); //CONSTANT2<br />
return varnames;<br />
}<br />
</syntaxhighlight><br />
<br />
Here's an example of V8 and JS being very fluid with things; anything that can be a function can also be variable, and we use v8Function as the type for variables. The only time the opposite would not be true is when you deal with constructors that are strongly tied to the templates for JS-side objects. I'm not doing things that way, and in several cases multiple functions can be used as constructors for a single type, and V8 won't let me tell it there are two constructors for a single JS-side type (they bind slightly different kinds of objects on the C++ side). In any case, these are a few of the types you could pass back as variables.<br />
<br />
So, let's get on with what is actually a part of windowstyleSDL!<br />
<br />
<syntaxhighlight lang="cpp"><br />
nameArray GetFunctionNames(){<br />
//reset numeration function to 0.<br />
numerate(true);<br />
<br />
nameArray funcnames = (nameArray)calloc(NUMFUNCS, sizeof(functionName));<br />
<br />
funcnames[numerate(false)] = (functionName)"WindowStyle";<br />
funcnames[numerate(false)] = (functionName)"GetSystemWindowStyle";<br />
//return array of c-string function names to the engine.<br />
return funcnames;<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
This is much like the GetFunctions function, but in this case, since the names are hardcoded right there, we just tell the compiler to think of them as the type functionName (aka const char*, GCC throws a warning if you don't cast them this way, but unlike before it makes no difference to me if they are cast that way or not, so I do to limit the number of warnings when compiling), and be on our merry way. The names of variables are defined the same way, except the function would be called GetVariableNames, and we would use the type variableName instead of functionName (both are const char*, but why use a type like functionName with a misleading name? GetVariables notwithstanding!).<br />
<br />
And unsurprisingly<br />
<br />
<syntaxhighlight lang="cpp"><br />
nameArray GetVariableNames(){<br />
return NULL;<br />
}<br />
</syntaxhighlight><br />
<br />
Same deal here as with GetVariables. <br />
<br />
So that's it! Technically, this is everything you *need* for a plugin. If you defined GetNumFunctions to return 0, and GetFunctions and getFunctionNames to return NULL this would be perfectly functional (although totally useless) plugin. But you probably want your plugin to do something, right? <br />
<br />
Well, let's look at a single function that can be used by V8. There are a whole lot ways to do this, I might add, but this is how I've been doing it. If you want to do it a different way, be my guest.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function TestFunction(V8ARGS){<br />
return v8::Integer::New(42)<br />
}<br />
</syntaxhighlight><br />
<br />
Well, it doesn't do much. But if you passed a pointer to this function as one of the elements returned by GetFunctions, and then in JS called whatever name you gave it as a function, it would return 42 in JS. But, that's simple. In fact, you might well have been able to figure out most of that from what I went over in the theoretical GetVariables function. Let's look deeper.<br />
<br />
What if you want to deal with arguments? That's pretty simple, and it lets me show off some nice macros in plugin.h.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function ArgsTestFunction(V8ARGS){<br />
if(args.Length()<1){<br />
THROWERROR("ArgsTestFunction Error: Called with no arguments.");<br />
}<br />
CHECK_ARG_INT(0, "ArgsTestFunction Error: Argument 0 is not an integer.");<br />
<br />
int i = args[0]->IntegerValue();<br />
<br />
if(i==0){<br />
return v8::Integer::New(42);<br />
}<br />
else {<br />
return v8::String::New("That number was not 0!");<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
In this case, we have to deal with arguments. I have one thing that I cannot stress enough about arguments.<br />
<br />
Programmers are stupid and lazy. Even you, my friend, even me. So we can count on them passing garbage to our functions. I know I pass garbage to functions all the time, and even if they are really good programmers and rarely make that kind of mistake, these checks are useful for telling you where things went wrong. If you ever plan on using your own plugin, you will thank yourself for adding as many checks as possible.<br />
<br />
The first one is the check for the numebr of args. You could just as easily default to something, but this a good example of the THROWERROR macro, a paper thin wrapper around returning a v8::ThrowException function. It throws a JS-side exception with the text you give. It can be caught by script as well, which is a *good* *thing*. I recommend you put the function name into the error message. And I highly recommend you give some explanation for why the exception happened at all. Don't be shy about being specific, either.<br />
<br />
Simpler to do (with the help of plugin.h) is the check of parameter types. There exist several macros to check them for you:<br />
<br />
* CHECK_ARG_INT<br />
* CHECK_ARG_STR<br />
* CHECK_ARG_OBJ<br />
* CHECK_ARG_BOOL<br />
* CHECK_ARG_ARRAY<br />
<br />
Bear in mind that JS is a wily language when it comes to data validation. If you are using the OBJ or ARRAY checks, you might either rule out valid values or include values you don't want to. But the explanation of such things is beyond the scope here.<br />
<br />
These macros check the argument specified in the first parameter (here 0, the first arg), and throw the error specified in the second parameter if it is not the right type. Bear in mind, this doens't mean that it couldn't be cast to the right type, just that it isn't right now. Generally I would err on the side of throwing out edge-case-correct values than accepting bad values that seem like they might be OK. Better to throw a JS exception than to either make V8 die (which is ugly and won't tell you as much about what went wrong), or pass garbage into a C++ or C function, which can quite easily cause crashes. It can cause hard crashes, and we really don't want hard crashes. We really, really don't want them. Anytime you can stop one from happening, I'd really like you too. Every time a user has to use a task manager to close TurboSphere, they think that anyone who had a hand in making it, the game they are playing with it, or any plugins they use, are bad programmers. And this right here, this is where most <br />
crashes come from.<br />
<br />
So next we need to make the argument, which is a V8 type, into a C/C++ type. First, ask yourself, are you sure that only the correct type of value could have gotten to this cast (no really, this is important)? Good. There are a few easy ways to do this:<br />
<br />
<syntaxhighlight lang="cpp"><br />
int x = args[i]->IntegerValue();<br />
int x = args[i]->Int32Value();<br />
</syntaxhighlight><br />
<br />
Bear in mind that you will get some weirdness with this when you try to compile on both 32-bit and 64-bit architectures. IntegerValue returns a 64-bit integer, and Int32Value returns a 32-bit integer. You could avoid compiler warnings by using a fixed with type (int64_t), or by using some ugly preprocessor stuff. My recommendation is just to only go with 64-bits, but I know I'm not in charge of what word-length users' computers are, so just listen to your compiler of choice's warnings for what to do. If it doesn't complain, then don't worry about it--but bear in mind that TurboSphere will, one day somewhat soon, be 64-bit only, and possibly only able to load 64-bit plugins. At least think about making your code 64-bit safe if you want your plugin to stick around.<br />
<br />
<syntaxhighlight lang="cpp"><br />
bool x = args[i]->BooleanValue();<br />
</syntaxhighlight><br />
<br />
That one's pretty simple.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8::String::Utf8Value str(args[i]);<br />
//Which is completed with<br />
const char *cstr = *str;<br />
</syntaxhighlight><br />
<br />
Well, that's pretty much it for that. This is really more a V8 section than a TurboSphere plugin section, but the fact is TurboSphere is strongly linked to V8, so this is important. And plus, I want to help you avoid the pitfalls I fell into when I started out.<br />
<br />
So what else can we do? The part that gave me the most trouble, and is hard to figure out, and lacks good examples on the web, is using some JS-side types that you define yourself. That's what those object template macros were there for. Let's use them.<br />
<br />
<syntaxhighlight lang="cpp"><br />
v8Function LoadWindowStyle(V8ARGS) {<br />
if(args.Length()<1){<br />
return v8::ThrowException(v8::String::New("LoadWindowStyle Error: Called with no arguments."));<br />
}<br />
CHECK_ARG_STR(0, "LoadWindowStyle Error: Arg 0 is not a string.");<br />
<br />
BEGIN_OBJECT_WRAP_CODE<br />
<br />
TS_WindowStyle *ws = NULL;<br />
<br />
v8::String::Utf8Value str(args[0]);<br />
const char *wsname = *str;<br />
<br />
SDL_RWops *wstest = SDL_RWFromFile(string(TS_dirs.windowstyle).append(wsname).c_str(), "rb");<br />
if(!wstest){<br />
SDL_RWclose(wstest);<br />
THROWERROR(string("LoadWindowStyle Error: Could not load windowstyle ").append(wsname).c_str());<br />
}<br />
SDL_RWclose(wstest);<br />
<br />
ws = new TS_WindowStyle(string(TS_dirs.windowstyle).append(wsname).c_str());<br />
<br />
if(!ws){<br />
SDL_RWclose(wstest);<br />
THROWERROR(string("LoadWindowStyle Error: Could not load windowstyle ").append(wsname).c_str());<br />
}<br />
<br />
END_OBJECT_WRAP_CODE(WindowStyle, ws);<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
Don't worry about the TS_WindowStyle stuff. Just suffice it to say that it is a C++ type, which constructs an C++ object from a given file. I left a lot of that stuff in the example, because it is validation code, and that is important to have. You can pass any string to this function, and even though it will not throw an exception at the CHECK_ARG_STR line, it will still throw an error that it could not open the file. So we know the file exists. And even then, if we can't read the file for whatever reason (likely it's not a valid file for this object to read), we still throw an error instead of passing back an empty or broken object.<br />
<br />
I will admit right here that I lied. Most of the work to wrap objects for JS is hidden behind the BEGIN_OBJECT_WRAP_CODE and END_OBJECT_WRAP_CODE macros.<br />
<br />
So let's get to the meat of the function. BEGIN_OBJECT_WRAP_CODE is a macro that sets up for END_OBJECT_WRAP_CODE. You have to use the former if you use the latter. Note that END_OBJECT_WRAP_CODE uses the same name, WindowStyle, as INIT_OBJECT_TEMPLATES and ADD_TO_PROTO did. That's important. Because of that, the object has ready made templates for V8, and the prototype has the member drawWindow already attached. The END_OBJECT_CODE does one more thing, too. It sets up a finalizer for the object. Without this, the memory from the C++ side object is leaked.<br />
<br />
<syntaxhighlight lang="cpp"><br />
void TS_WindowStyleFinalizer(v8::Persistent<v8::Value> object, void* parameter) {<br />
TS_WindowStyle* ws = (TS_WindowStyle*)parameter;<br />
delete ws;<br />
object.Clear();<br />
object.Dispose();<br />
}<br />
</syntaxhighlight><br />
<br />
The naming of this function is rough edge I still haven't worked out for plugin.h. It must be TS_[name_passed_to_other_macros]Finalizer. I haven't worked out a better way to deal with this yet. Simply put, a finalizer object is called when the object it was attached to (in this case using the END_OBJECT_WRAP_CODE function). The JS object is passed as object, and a pointer to the C++-side object is passed as parameter. In this case, I just call delete on ws, since it was allocated with new. Do what you please to dispose of your C++ object. <br />
<br />
I also like to clear my JS objects before disposing of them. The simple answer to why is that this unambiguously means that all objects it references are no longer referenced by it from the garbage collector's perspective (even though Dispose does this too), since the object can't reference anything if it has been cleared.<br />
<br />
That should be enough to start off with. Feel free to point out any incorrect info you notice, ask questions, or stuff like that.<br />
<br />
--FlyingJester</div>Flying Jester