You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

492 lines
17KB

  1. //
  2. // "$Id: glut.H 8623 2011-04-24 17:09:41Z AlbrechtS $"
  3. //
  4. // GLUT emulation header file for the Fast Light Tool Kit (FLTK).
  5. //
  6. // Copyright 1998-2011 by Bill Spitzak and others.
  7. //
  8. // This library is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU Library General Public
  10. // License as published by the Free Software Foundation; either
  11. // version 2 of the License, or (at your option) any later version.
  12. //
  13. // This library is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. // Library General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Library General Public
  19. // License along with this library; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. // USA.
  22. //
  23. // Please report all bugs and problems on the following page:
  24. //
  25. // http://www.fltk.org/str.php
  26. //
  27. // Emulation of GLUT using fltk.
  28. // GLUT is Copyright (c) Mark J. Kilgard, 1994, 1995, 1996:
  29. // "This program is freely distributable without licensing fees and is
  30. // provided without guarantee or warrantee expressed or implied. This
  31. // program is -not- in the public domain."
  32. // Although I have copied the GLUT API, none of my code is based on
  33. // any GLUT implementation details and is therefore covered by the LGPL.
  34. // Commented out lines indicate parts of GLUT that are not emulated.
  35. #ifndef Fl_glut_H
  36. # define Fl_glut_H
  37. # include "gl.h"
  38. # include "Fl.H"
  39. # include "Fl_Gl_Window.H"
  40. /**
  41. GLUT is emulated using this window class and these static variables
  42. (plus several more static variables hidden in glut_compatability.cxx):
  43. */
  44. class FL_EXPORT Fl_Glut_Window : public Fl_Gl_Window {
  45. void _init();
  46. int mouse_down;
  47. protected:
  48. void draw();
  49. void draw_overlay();
  50. int handle(int);
  51. public: // so the inline functions work
  52. int number;
  53. int menu[3];
  54. void make_current();
  55. void (*display)();
  56. void (*overlaydisplay)();
  57. void (*reshape)(int w, int h);
  58. void (*keyboard)(uchar, int x, int y);
  59. void (*mouse)(int b, int state, int x, int y);
  60. void (*motion)(int x, int y);
  61. void (*passivemotion)(int x, int y);
  62. void (*entry)(int);
  63. void (*visibility)(int);
  64. void (*special)(int, int x, int y);
  65. Fl_Glut_Window(int w, int h, const char *);
  66. Fl_Glut_Window(int x, int y, int w, int h, const char *);
  67. ~Fl_Glut_Window();
  68. };
  69. extern FL_EXPORT Fl_Glut_Window *glut_window; // the current window
  70. extern FL_EXPORT int glut_menu; // the current menu
  71. // function pointers that are not per-window:
  72. extern FL_EXPORT void (*glut_idle_function)();
  73. extern FL_EXPORT void (*glut_menustate_function)(int);
  74. extern FL_EXPORT void (*glut_menustatus_function)(int,int,int);
  75. ////////////////////////////////////////////////////////////////
  76. //# define GLUT_API_VERSION This does not match any version of GLUT exactly...
  77. FL_EXPORT void glutInit(int *argcp, char **argv); // creates first window
  78. FL_EXPORT void glutInitDisplayMode(unsigned int mode);
  79. // the FL_ symbols have the same value as the GLUT ones:
  80. # define GLUT_RGB FL_RGB
  81. # define GLUT_RGBA FL_RGB
  82. # define GLUT_INDEX FL_INDEX
  83. # define GLUT_SINGLE FL_SINGLE
  84. # define GLUT_DOUBLE FL_DOUBLE
  85. # define GLUT_ACCUM FL_ACCUM
  86. # define GLUT_ALPHA FL_ALPHA
  87. # define GLUT_DEPTH FL_DEPTH
  88. # define GLUT_STENCIL FL_STENCIL
  89. # define GLUT_MULTISAMPLE FL_MULTISAMPLE
  90. # define GLUT_STEREO FL_STEREO
  91. // # define GLUT_LUMINANCE 512
  92. FL_EXPORT void glutInitWindowPosition(int x, int y);
  93. FL_EXPORT void glutInitWindowSize(int w, int h);
  94. FL_EXPORT void glutMainLoop();
  95. FL_EXPORT int glutCreateWindow(char *title);
  96. FL_EXPORT int glutCreateWindow(const char *title);
  97. FL_EXPORT int glutCreateSubWindow(int win, int x, int y, int width, int height);
  98. FL_EXPORT void glutDestroyWindow(int win);
  99. inline void glutPostRedisplay() {glut_window->redraw();}
  100. FL_EXPORT void glutPostWindowRedisplay(int win);
  101. FL_EXPORT void glutSwapBuffers();
  102. inline int glutGetWindow() {return glut_window->number;}
  103. FL_EXPORT void glutSetWindow(int win);
  104. inline void glutSetWindowTitle(char *t) {glut_window->label(t);}
  105. inline void glutSetIconTitle(char *t) {glut_window->iconlabel(t);}
  106. inline void glutPositionWindow(int x, int y) {glut_window->position(x,y);}
  107. inline void glutReshapeWindow(int w, int h) {glut_window->size(w,h);}
  108. inline void glutPopWindow() {glut_window->show();}
  109. inline void glutPushWindow() { /* do nothing */ }
  110. inline void glutIconifyWindow() {glut_window->iconize();}
  111. inline void glutShowWindow() {glut_window->show();}
  112. inline void glutHideWindow() {glut_window->hide();}
  113. inline void glutFullScreen() {glut_window->fullscreen();}
  114. inline void glutSetCursor(Fl_Cursor cursor) {glut_window->cursor(cursor);}
  115. // notice that the numeric values are different than glut:
  116. # define GLUT_CURSOR_RIGHT_ARROW ((Fl_Cursor)2)
  117. # define GLUT_CURSOR_LEFT_ARROW ((Fl_Cursor)67)
  118. # define GLUT_CURSOR_INFO FL_CURSOR_HAND
  119. # define GLUT_CURSOR_DESTROY ((Fl_Cursor)45)
  120. # define GLUT_CURSOR_HELP FL_CURSOR_HELP
  121. # define GLUT_CURSOR_CYCLE ((Fl_Cursor)26)
  122. # define GLUT_CURSOR_SPRAY ((Fl_Cursor)63)
  123. # define GLUT_CURSOR_WAIT FL_CURSOR_WAIT
  124. # define GLUT_CURSOR_TEXT FL_CURSOR_INSERT
  125. # define GLUT_CURSOR_CROSSHAIR FL_CURSOR_CROSS
  126. # define GLUT_CURSOR_UP_DOWN FL_CURSOR_NS
  127. # define GLUT_CURSOR_LEFT_RIGHT FL_CURSOR_WE
  128. # define GLUT_CURSOR_TOP_SIDE FL_CURSOR_N
  129. # define GLUT_CURSOR_BOTTOM_SIDE FL_CURSOR_S
  130. # define GLUT_CURSOR_LEFT_SIDE FL_CURSOR_W
  131. # define GLUT_CURSOR_RIGHT_SIDE FL_CURSOR_E
  132. # define GLUT_CURSOR_TOP_LEFT_CORNER FL_CURSOR_NW
  133. # define GLUT_CURSOR_TOP_RIGHT_CORNER FL_CURSOR_NE
  134. # define GLUT_CURSOR_BOTTOM_RIGHT_CORNER FL_CURSOR_SE
  135. # define GLUT_CURSOR_BOTTOM_LEFT_CORNER FL_CURSOR_SW
  136. # define GLUT_CURSOR_INHERIT FL_CURSOR_DEFAULT
  137. # define GLUT_CURSOR_NONE FL_CURSOR_NONE
  138. # define GLUT_CURSOR_FULL_CROSSHAIR FL_CURSOR_CROSS
  139. inline void glutWarpPointer(int, int) { /* do nothing */ }
  140. inline void glutEstablishOverlay() {glut_window->make_overlay_current();}
  141. inline void glutRemoveOverlay() {glut_window->hide_overlay();}
  142. inline void glutUseLayer(GLenum layer) {
  143. layer ? glut_window->make_overlay_current() : glut_window->make_current();}
  144. enum {GLUT_NORMAL, GLUT_OVERLAY};
  145. inline void glutPostOverlayRedisplay() {glut_window->redraw_overlay();}
  146. inline void glutShowOverlay() {glut_window->redraw_overlay();}
  147. inline void glutHideOverlay() {glut_window->hide_overlay();}
  148. FL_EXPORT int glutCreateMenu(void (*)(int));
  149. FL_EXPORT void glutDestroyMenu(int menu);
  150. inline int glutGetMenu() {return glut_menu;}
  151. inline void glutSetMenu(int m) {glut_menu = m;}
  152. FL_EXPORT void glutAddMenuEntry(char *label, int value);
  153. FL_EXPORT void glutAddSubMenu(char *label, int submenu);
  154. FL_EXPORT void glutChangeToMenuEntry(int item, char *labela, int value);
  155. FL_EXPORT void glutChangeToSubMenu(int item, char *label, int submenu);
  156. FL_EXPORT void glutRemoveMenuItem(int item);
  157. inline void glutAttachMenu(int b) {glut_window->menu[b] = glut_menu;}
  158. inline void glutDetachMenu(int b) {glut_window->menu[b] = 0;}
  159. inline void glutDisplayFunc(void (*f)()) {glut_window->display = f;}
  160. inline void glutReshapeFunc(void (*f)(int w, int h)) {glut_window->reshape=f;}
  161. inline void glutKeyboardFunc(void (*f)(uchar key, int x, int y)) {
  162. glut_window->keyboard = f;}
  163. inline void glutMouseFunc(void (*f)(int b, int state, int x, int y)) {
  164. glut_window->mouse = f;}
  165. # define GLUT_LEFT_BUTTON 0
  166. # define GLUT_MIDDLE_BUTTON 1
  167. # define GLUT_RIGHT_BUTTON 2
  168. # define GLUT_DOWN 0
  169. # define GLUT_UP 1
  170. inline void glutMotionFunc(void (*f)(int x, int y)) {glut_window->motion= f;}
  171. inline void glutPassiveMotionFunc(void (*f)(int x, int y)) {
  172. glut_window->passivemotion= f;}
  173. inline void glutEntryFunc(void (*f)(int s)) {glut_window->entry = f;}
  174. enum {GLUT_LEFT, GLUT_ENTERED};
  175. inline void glutVisibilityFunc(void (*f)(int s)) {glut_window->visibility=f;}
  176. enum {GLUT_NOT_VISIBLE, GLUT_VISIBLE};
  177. FL_EXPORT void glutIdleFunc(void (*f)());
  178. // Warning: this cast may not work on all machines:
  179. inline void glutTimerFunc(unsigned int msec, void (*f)(int), int value) {
  180. Fl::add_timeout(msec*.001, (void (*)(void *))f, (void *)value);
  181. }
  182. inline void glutMenuStateFunc(void (*f)(int state)) {
  183. glut_menustate_function = f;}
  184. inline void glutMenuStatusFunc(void (*f)(int status, int x, int y)) {
  185. glut_menustatus_function = f;}
  186. enum {GLUT_MENU_NOT_IN_USE, GLUT_MENU_IN_USE};
  187. inline void glutSpecialFunc(void (*f)(int key, int x, int y)) {
  188. glut_window->special = f;}
  189. # define GLUT_KEY_F1 1
  190. # define GLUT_KEY_F2 2
  191. # define GLUT_KEY_F3 3
  192. # define GLUT_KEY_F4 4
  193. # define GLUT_KEY_F5 5
  194. # define GLUT_KEY_F6 6
  195. # define GLUT_KEY_F7 7
  196. # define GLUT_KEY_F8 8
  197. # define GLUT_KEY_F9 9
  198. # define GLUT_KEY_F10 10
  199. # define GLUT_KEY_F11 11
  200. # define GLUT_KEY_F12 12
  201. // WARNING: Different values than GLUT uses:
  202. # define GLUT_KEY_LEFT FL_Left
  203. # define GLUT_KEY_UP FL_Up
  204. # define GLUT_KEY_RIGHT FL_Right
  205. # define GLUT_KEY_DOWN FL_Down
  206. # define GLUT_KEY_PAGE_UP FL_Page_Up
  207. # define GLUT_KEY_PAGE_DOWN FL_Page_Down
  208. # define GLUT_KEY_HOME FL_Home
  209. # define GLUT_KEY_END FL_End
  210. # define GLUT_KEY_INSERT FL_Insert
  211. //inline void glutSpaceballMotionFunc(void (*)(int x, int y, int z));
  212. //inline void glutSpaceballRotateFunc(void (*)(int x, int y, int z));
  213. //inline void glutSpaceballButtonFunc(void (*)(int button, int state));
  214. //inline void glutButtonBoxFunc(void (*)(int button, int state));
  215. //inline void glutDialsFunc(void (*)(int dial, int value));
  216. //inline void glutTabletMotionFunc(void (*)(int x, int y));
  217. //inline void glutTabletButtonFunc(void (*)(int button, int state, int x, int y));
  218. inline void glutOverlayDisplayFunc(void (*f)()) {
  219. glut_window->overlaydisplay = f;}
  220. //inline void glutWindowStatusFunc(void (*)(int state));
  221. //enum {GLUT_HIDDEN, GLUT_FULLY_RETAINED, GLUT_PARTIALLY_RETAINED,
  222. // GLUT_FULLY_COVERED};
  223. //inline void glutSetColor(int, GLfloat red, GLfloat green, GLfloat blue);
  224. //inline GLfloat glutGetColor(int ndx, int component);
  225. //#define GLUT_RED 0
  226. //#define GLUT_GREEN 1
  227. //#define GLUT_BLUE 2
  228. //inline void glutCopyColormap(int win);
  229. // Warning: values are changed from GLUT!
  230. // Also relies on the GL_ symbols having values greater than 100
  231. FL_EXPORT int glutGet(GLenum type);
  232. enum {
  233. GLUT_RETURN_ZERO = 0,
  234. GLUT_WINDOW_X,
  235. GLUT_WINDOW_Y,
  236. GLUT_WINDOW_WIDTH,
  237. GLUT_WINDOW_HEIGHT,
  238. GLUT_WINDOW_PARENT,
  239. GLUT_SCREEN_WIDTH,
  240. GLUT_SCREEN_HEIGHT,
  241. GLUT_MENU_NUM_ITEMS,
  242. GLUT_DISPLAY_MODE_POSSIBLE,
  243. GLUT_INIT_WINDOW_X,
  244. GLUT_INIT_WINDOW_Y,
  245. GLUT_INIT_WINDOW_WIDTH,
  246. GLUT_INIT_WINDOW_HEIGHT,
  247. GLUT_INIT_DISPLAY_MODE,
  248. GLUT_WINDOW_BUFFER_SIZE,
  249. GLUT_VERSION
  250. //GLUT_WINDOW_NUM_CHILDREN,
  251. //GLUT_WINDOW_CURSOR,
  252. //GLUT_SCREEN_WIDTH_MM,
  253. //GLUT_SCREEN_HEIGHT_MM,
  254. //GLUT_ELAPSED_TIME,
  255. };
  256. # define GLUT_WINDOW_STENCIL_SIZE GL_STENCIL_BITS
  257. # define GLUT_WINDOW_DEPTH_SIZE GL_DEPTH_BITS
  258. # define GLUT_WINDOW_RED_SIZE GL_RED_BITS
  259. # define GLUT_WINDOW_GREEN_SIZE GL_GREEN_BITS
  260. # define GLUT_WINDOW_BLUE_SIZE GL_BLUE_BITS
  261. # define GLUT_WINDOW_ALPHA_SIZE GL_ALPHA_BITS
  262. # define GLUT_WINDOW_ACCUM_RED_SIZE GL_ACCUM_RED_BITS
  263. # define GLUT_WINDOW_ACCUM_GREEN_SIZE GL_ACCUM_GREEN_BITS
  264. # define GLUT_WINDOW_ACCUM_BLUE_SIZE GL_ACCUM_BLUE_BITS
  265. # define GLUT_WINDOW_ACCUM_ALPHA_SIZE GL_ACCUM_ALPHA_BITS
  266. # define GLUT_WINDOW_DOUBLEBUFFER GL_DOUBLEBUFFER
  267. # define GLUT_WINDOW_RGBA GL_RGBA
  268. # define GLUT_WINDOW_COLORMAP_SIZE GL_INDEX_BITS
  269. # ifdef GL_SAMPLES_SGIS
  270. # define GLUT_WINDOW_NUM_SAMPLES GL_SAMPLES_SGIS
  271. # else
  272. # define GLUT_WINDOW_NUM_SAMPLES GLUT_RETURN_ZERO
  273. # endif
  274. # define GLUT_WINDOW_STEREO GL_STEREO
  275. # define GLUT_HAS_KEYBOARD 600
  276. # define GLUT_HAS_MOUSE 601
  277. # define GLUT_HAS_SPACEBALL 602
  278. # define GLUT_HAS_DIAL_AND_BUTTON_BOX 603
  279. # define GLUT_HAS_TABLET 604
  280. # define GLUT_NUM_MOUSE_BUTTONS 605
  281. # define GLUT_NUM_SPACEBALL_BUTTONS 606
  282. # define GLUT_NUM_BUTTON_BOX_BUTTONS 607
  283. # define GLUT_NUM_DIALS 608
  284. # define GLUT_NUM_TABLET_BUTTONS 609
  285. FL_EXPORT int glutDeviceGet(GLenum type);
  286. // WARNING: these values are different than GLUT uses:
  287. # define GLUT_ACTIVE_SHIFT FL_SHIFT
  288. # define GLUT_ACTIVE_CTRL FL_CTRL
  289. # define GLUT_ACTIVE_ALT FL_ALT
  290. inline int glutGetModifiers() {return Fl::event_state() & (GLUT_ACTIVE_SHIFT | GLUT_ACTIVE_CTRL | GLUT_ACTIVE_ALT);}
  291. FL_EXPORT int glutLayerGet(GLenum);
  292. # define GLUT_OVERLAY_POSSIBLE 800
  293. //#define GLUT_LAYER_IN_USE 801
  294. //#define GLUT_HAS_OVERLAY 802
  295. # define GLUT_TRANSPARENT_INDEX 803
  296. # define GLUT_NORMAL_DAMAGED 804
  297. # define GLUT_OVERLAY_DAMAGED 805
  298. extern "C" {
  299. typedef void (*GLUTproc)();
  300. }
  301. FL_EXPORT GLUTproc glutGetProcAddress(const char *procName);
  302. //inline int glutVideoResizeGet(GLenum param);
  303. //#define GLUT_VIDEO_RESIZE_POSSIBLE 900
  304. //#define GLUT_VIDEO_RESIZE_IN_USE 901
  305. //#define GLUT_VIDEO_RESIZE_X_DELTA 902
  306. //#define GLUT_VIDEO_RESIZE_Y_DELTA 903
  307. //#define GLUT_VIDEO_RESIZE_WIDTH_DELTA 904
  308. //#define GLUT_VIDEO_RESIZE_HEIGHT_DELTA 905
  309. //#define GLUT_VIDEO_RESIZE_X 906
  310. //#define GLUT_VIDEO_RESIZE_Y 907
  311. //#define GLUT_VIDEO_RESIZE_WIDTH 908
  312. //#define GLUT_VIDEO_RESIZE_HEIGHT 909
  313. //inline void glutSetupVideoResizing();
  314. //inline void glutStopVideoResizing();
  315. //inline void glutVideoResize(int x, int y, int width, int height);
  316. //inline void glutVideoPan(int x, int y, int width, int height);
  317. // Font argument must be a void* for compatibility, so...
  318. /** fltk glut font/size attributes used in the glutXXX functions */
  319. struct Fl_Glut_Bitmap_Font {Fl_Font font; Fl_Fontsize size;};
  320. extern FL_EXPORT struct Fl_Glut_Bitmap_Font
  321. glutBitmap9By15, glutBitmap8By13, glutBitmapTimesRoman10,
  322. glutBitmapTimesRoman24, glutBitmapHelvetica10, glutBitmapHelvetica12,
  323. glutBitmapHelvetica18;
  324. # define GLUT_BITMAP_9_BY_15 (&glutBitmap9By15)
  325. # define GLUT_BITMAP_8_BY_13 (&glutBitmap8By13)
  326. # define GLUT_BITMAP_TIMES_ROMAN_10 (&glutBitmapTimesRoman10)
  327. # define GLUT_BITMAP_TIMES_ROMAN_24 (&glutBitmapTimesRoman24)
  328. # define GLUT_BITMAP_HELVETICA_10 (&glutBitmapHelvetica10)
  329. # define GLUT_BITMAP_HELVETICA_12 (&glutBitmapHelvetica12)
  330. # define GLUT_BITMAP_HELVETICA_18 (&glutBitmapHelvetica18)
  331. FL_EXPORT void glutBitmapCharacter(void *font, int character);
  332. FL_EXPORT int glutBitmapHeight(void *font);
  333. FL_EXPORT int glutBitmapLength(void *font, const unsigned char *string);
  334. FL_EXPORT void glutBitmapString(void *font, const unsigned char *string);
  335. FL_EXPORT int glutBitmapWidth(void *font, int character);
  336. FL_EXPORT int glutExtensionSupported(char *name);
  337. /* GLUT stroked font sub-API */
  338. struct Fl_Glut_StrokeVertex {
  339. GLfloat X, Y;
  340. };
  341. struct Fl_Glut_StrokeStrip {
  342. int Number;
  343. const Fl_Glut_StrokeVertex* Vertices;
  344. };
  345. struct Fl_Glut_StrokeChar {
  346. GLfloat Right;
  347. int Number;
  348. const Fl_Glut_StrokeStrip* Strips;
  349. };
  350. struct Fl_Glut_StrokeFont {
  351. char* Name; // The source font name
  352. int Quantity; // Number of chars in font
  353. GLfloat Height; // Height of the characters
  354. const Fl_Glut_StrokeChar** Characters;// The characters mapping
  355. };
  356. extern FL_EXPORT Fl_Glut_StrokeFont glutStrokeRoman;
  357. extern FL_EXPORT Fl_Glut_StrokeFont glutStrokeMonoRoman;
  358. # define GLUT_STROKE_ROMAN (&glutStrokeRoman)
  359. # define GLUT_STROKE_MONO_ROMAN (&glutStrokeMonoRoman)
  360. FL_EXPORT void glutStrokeCharacter(void *font, int character);
  361. FL_EXPORT GLfloat glutStrokeHeight(void *font);
  362. FL_EXPORT int glutStrokeLength(void *font, const unsigned char *string);
  363. FL_EXPORT void glutStrokeString(void *font, const unsigned char *string);
  364. FL_EXPORT int glutStrokeWidth(void *font, int character);
  365. /* GLUT pre-built models sub-API */
  366. FL_EXPORT void glutWireSphere(GLdouble radius, GLint slices, GLint stacks);
  367. FL_EXPORT void glutSolidSphere(GLdouble radius, GLint slices, GLint stacks);
  368. FL_EXPORT void glutWireCone(GLdouble base, GLdouble height, GLint slices, GLint stacks);
  369. FL_EXPORT void glutSolidCone(GLdouble base, GLdouble height, GLint slices, GLint stacks);
  370. FL_EXPORT void glutWireCube(GLdouble size);
  371. FL_EXPORT void glutSolidCube(GLdouble size);
  372. FL_EXPORT void glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings);
  373. FL_EXPORT void glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings);
  374. FL_EXPORT void glutWireDodecahedron();
  375. FL_EXPORT void glutSolidDodecahedron();
  376. FL_EXPORT void glutWireTeapot(GLdouble size);
  377. FL_EXPORT void glutSolidTeapot(GLdouble size);
  378. FL_EXPORT void glutWireOctahedron();
  379. FL_EXPORT void glutSolidOctahedron();
  380. FL_EXPORT void glutWireTetrahedron();
  381. FL_EXPORT void glutSolidTetrahedron();
  382. FL_EXPORT void glutWireIcosahedron();
  383. FL_EXPORT void glutSolidIcosahedron();
  384. #endif // !Fl_glut_H
  385. //
  386. // End of "$Id: glut.H 8623 2011-04-24 17:09:41Z AlbrechtS $".
  387. //