Advertisement
GeeckoDev

glib2d_font.c

Apr 25th, 2015
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.98 KB | None | 0 0
  1. /*
  2.  * gLib2D_font
  3.  *
  4.  * This program is free software: you can redistribute it and/or modify
  5.  * it under the terms of the GNU Lesser General Public License as published by
  6.  * the Free Software Foundation, either version 3 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU Lesser General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU Lesser General Public License
  15.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16.  *
  17.  * If you find any bug, contact me at <geecko.dev@free.fr>
  18.  */
  19.  
  20. #include "glib2d_font.h"
  21.  
  22. typedef struct
  23. {
  24.   char *text;
  25.   float x, y;
  26.   float rot, rot_sin, rot_cos;
  27.   float scale;
  28.   g2dColor color;
  29.   g2dColor shadow_color;
  30.   g2dAlpha alpha;
  31. } Object;
  32.  
  33. typedef struct
  34. {
  35.   Object obj;
  36.   g2dCoord_Mode obj_coord_mode;
  37. } Context;
  38.  
  39. static bool init = false;
  40. static Context *ctx = NULL;
  41.  
  42. // * Main functions *
  43.  
  44. void g2dFontInit()
  45. {
  46.   TTF_Init();
  47.  
  48.   init = true;
  49. }
  50.  
  51. void g2dFontTerm()
  52. {
  53.   TTF_Quit();
  54.  
  55.   init = false;
  56. }
  57.  
  58. g2dFont *g2dFontLoad(char *path, int pt)
  59. {
  60.   g2dFont *font;
  61.   TTF_Font *ttf;
  62.  
  63.   /* Try to open the font */
  64.   ttf = TTF_OpenFont(path, pt);
  65.   if (!ttf)
  66.     return NULL;
  67.  
  68.   /* Allocate */
  69.   font = malloc(sizeof(g2dFont));
  70.   if (!font)
  71.     return NULL;
  72.  
  73.   /* Initialize */
  74.   font->ttf = ttf;
  75.   for (i = 0; i < GLYPH_CACHE_SIZE; i++)
  76.     font->glyph_cache[i] = NULL;
  77.  
  78.   return font;
  79. }
  80.  
  81. void g2dFontFree(g2dFont *font)
  82. {
  83.   if (!font)
  84.     return;
  85.  
  86.   TTF_CloseFont(font->ttf);
  87.  
  88.   free(font);
  89. }
  90.  
  91. void g2dFontBegin()
  92. {
  93.   if (!init)
  94.     return;
  95.  
  96.   obj_list_size = 0;
  97.   obj_list = (Object*)realloc(obj_list,MALLOC_STEP * sizeof(Object));
  98.  
  99.   obj_use_z = false;
  100.   obj_use_blend = false;
  101.   obj_use_rot = false;
  102.   obj_use_int = false;
  103.   obj_colors_count = 0;
  104.   g2dReset();
  105.  
  106.   obj_begin = true;
  107. }
  108.  
  109.  
  110. void _g2dEndRects()
  111. {
  112.   glBegin(GL_TRIANGLES);
  113.  
  114.   // Add each object
  115.   int i;
  116.   for (i=0; i<obj_list_size; i+=1)
  117.   {
  118.     _g2dSetVertex(i,0,0);
  119.     _g2dSetVertex(i,1,0);
  120.     _g2dSetVertex(i,0,1);
  121.     _g2dSetVertex(i,0,1);
  122.     _g2dSetVertex(i,1,0);
  123.     _g2dSetVertex(i,1,1);
  124.   }
  125.  
  126.   // Then put it in the display list.
  127.   glEnd();
  128. }
  129.  
  130.  
  131. void _g2dEndLines()
  132. {
  133.   glBegin(obj_line_strip ? GL_LINE_STRIP : GL_LINES);
  134.  
  135.   // Add each object
  136.   int i;
  137.   if (obj_line_strip)
  138.   {
  139.     _g2dSetVertex(0,0,0);
  140.     for (i=1; i<obj_list_size; i+=1)
  141.     {
  142.       _g2dSetVertex(i,0,0);
  143.     }
  144.   }
  145.   else
  146.   {
  147.     for (i=0; i+1<obj_list_size; i+=2)
  148.     {
  149.       _g2dSetVertex(i  ,0,0);
  150.       _g2dSetVertex(i+1,0,0);
  151.     }
  152.   }
  153.  
  154.   // Then put it in the display list.
  155.   glEnd();
  156. }
  157.  
  158.  
  159. void _g2dEndQuads()
  160. {
  161.   glBegin(GL_TRIANGLES);
  162.  
  163.   // Add each object
  164.   int i;
  165.   for (i=0; i+3<obj_list_size; i+=4)
  166.   {
  167.     _g2dSetVertex(i  ,0,0);
  168.     _g2dSetVertex(i+1,1,0);
  169.     _g2dSetVertex(i+3,0,1);
  170.     _g2dSetVertex(i+3,0,1);
  171.     _g2dSetVertex(i+1,1,0);
  172.     _g2dSetVertex(i+2,1,1);
  173.   }
  174.  
  175.   // Then put it in the display list.
  176.   glEnd();
  177. }
  178.  
  179.  
  180. void _g2dEndPoints()
  181. {
  182.   glBegin(GL_POINTS);
  183.  
  184.   // Add each object
  185.   int i;
  186.   for (i=0; i<obj_list_size; i+=1)
  187.   {
  188.     _g2dSetVertex(i,0,0);
  189.   }
  190.  
  191.   // Then put it in the display list.
  192.   glEnd();
  193. }
  194.  
  195.  
  196. void g2dEnd()
  197. {
  198.   if (!obj_begin || obj_list_size <= 0)
  199.   {
  200.     obj_begin = false;
  201.     return;
  202.   }
  203.  
  204.   // Manage extensions
  205.   if (obj_use_z)          glEnable(GL_DEPTH_TEST);
  206.   else                    glDisable(GL_DEPTH_TEST);
  207.   if (obj_use_blend)      glEnable(GL_BLEND);
  208.   else                    glDisable(GL_BLEND);
  209.   if (obj_tex == NULL)    glDisable(GL_TEXTURE_2D);
  210.   else
  211.   {
  212.     glEnable(GL_TEXTURE_2D);
  213.     glBindTexture(GL_TEXTURE_2D,obj_tex->id);
  214.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
  215.                     obj_use_tex_linear ? GL_LINEAR : GL_NEAREST);
  216.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,
  217.                     obj_use_tex_linear ? GL_LINEAR : GL_NEAREST);
  218.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  219.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  220.   }
  221.  
  222.   switch (obj_type)
  223.   {
  224.     case RECTS:  _g2dEndRects();  break;
  225.     case LINES:  _g2dEndLines();  break;
  226.     case QUADS:  _g2dEndQuads();  break;
  227.     case POINTS: _g2dEndPoints(); break;
  228.   }
  229.  
  230.   glColor3f(1.f,1.f,1.f);
  231.   glEnable(GL_BLEND);
  232.  
  233.   obj_begin = false;
  234.   if (obj_use_z) zclear = true;
  235. }
  236.  
  237.  
  238. void g2dReset()
  239. {
  240.   g2dResetCoord();
  241.   g2dResetScale();
  242.   g2dResetColor();
  243.   g2dResetAlpha();
  244.   g2dResetRotation();
  245.   g2dResetCrop();
  246.   g2dResetTex();
  247. }
  248.  
  249.  
  250. void g2dFlip(g2dFlip_Mode mode)
  251. {
  252.   if (scissor) g2dResetScissor();
  253.  
  254.   glFinish();
  255.   SDL_GL_SwapWindow(window);
  256.  
  257.   start = false;
  258. }
  259.  
  260.  
  261. void g2dAdd()
  262. {
  263.   if (!obj_begin) return;
  264.   if (obj.scale_w == 0 || obj.scale_h == 0) return;
  265.  
  266.   if (!(obj_list_size % MALLOC_STEP))
  267.   {
  268.     obj_list = realloc(obj_list,(obj_list_size+MALLOC_STEP) * sizeof(Object));
  269.   }
  270.  
  271.   obj_list_size++;
  272.   obj.rot_x = obj.x;
  273.   obj.rot_y = obj.y;
  274.   CURRENT_OBJ = obj;
  275.  
  276.   // Coord mode stuff
  277.   CURRENT_OBJ.x -= (obj_coord_mode == G2D_UP_RIGHT ||
  278.                     obj_coord_mode == G2D_DOWN_RIGHT ?
  279.                     CURRENT_OBJ.scale_w :
  280.                    (obj_coord_mode == G2D_CENTER ?
  281.                     CURRENT_OBJ.scale_w/2 : 0));
  282.   CURRENT_OBJ.y -= (obj_coord_mode == G2D_DOWN_LEFT ||
  283.                     obj_coord_mode == G2D_DOWN_RIGHT ?
  284.                     CURRENT_OBJ.scale_h :
  285.                    (obj_coord_mode == G2D_CENTER ?
  286.                     CURRENT_OBJ.scale_h/2 : 0));
  287.  
  288.   // Alpha stuff
  289.   CURRENT_OBJ.color = G2D_MODULATE(CURRENT_OBJ.color,255,obj.alpha);
  290. }
  291.  
  292.  
  293. void g2dPush()
  294. {
  295.   if (transform_stack_size >= TRANSFORM_STACK_MAX) return;
  296.   transform_stack_size++;
  297.   CURRENT_TRANSFORM.x = obj.x;
  298.   CURRENT_TRANSFORM.y = obj.y;
  299.   CURRENT_TRANSFORM.z = obj.z;
  300.   CURRENT_TRANSFORM.rot = obj.rot;
  301.   CURRENT_TRANSFORM.rot_sin = obj.rot_sin;
  302.   CURRENT_TRANSFORM.rot_cos = obj.rot_cos;
  303.   CURRENT_TRANSFORM.scale_w = obj.scale_w;
  304.   CURRENT_TRANSFORM.scale_h = obj.scale_h;
  305. }
  306.  
  307.  
  308. void g2dPop()
  309. {
  310.   if (transform_stack_size <= 0) return;
  311.   obj.x = CURRENT_TRANSFORM.x;
  312.   obj.y = CURRENT_TRANSFORM.y;
  313.   obj.z = CURRENT_TRANSFORM.z;
  314.   obj.rot = CURRENT_TRANSFORM.rot;
  315.   obj.rot_sin = CURRENT_TRANSFORM.rot_sin;
  316.   obj.rot_cos = CURRENT_TRANSFORM.rot_cos;
  317.   obj.scale_w = CURRENT_TRANSFORM.scale_w;
  318.   obj.scale_h = CURRENT_TRANSFORM.scale_h;
  319.   if (obj.rot != 0.f) obj_use_rot = true;
  320.   if (obj.z != 0.f) obj_use_z = true;
  321.   transform_stack_size--;
  322. }
  323.  
  324. // * Coord functions *
  325.  
  326. void g2dResetCoord()
  327. {
  328.   obj_coord_mode = DEFAULT_COORD_MODE;
  329.   obj.x = DEFAULT_X;
  330.   obj.y = DEFAULT_Y;
  331.   obj.z = DEFAULT_Z;
  332. }
  333.  
  334.  
  335. void g2dSetCoordMode(g2dCoord_Mode mode)
  336. {
  337.   if (mode > G2D_CENTER) return;
  338.   obj_coord_mode = mode;
  339. }
  340.  
  341.  
  342. void g2dGetCoordXYZ(float* x, float* y, float* z)
  343. {
  344.   if (x != NULL) *x = obj.x;
  345.   if (y != NULL) *y = obj.y;
  346.   if (z != NULL) *z = obj.z;
  347. }
  348.  
  349.  
  350. void g2dSetCoordXY(float x, float y)
  351. {
  352.   obj.x = x * global_scale;
  353.   obj.y = y * global_scale;
  354.   obj.z = 0.f;
  355. }
  356.  
  357.  
  358. void g2dSetCoordXYZ(float x, float y, float z)
  359. {
  360.   obj.x = x * global_scale;
  361.   obj.y = y * global_scale;
  362.   obj.z = z * global_scale;
  363.   if (z != 0.f) obj_use_z = true;
  364. }
  365.  
  366.  
  367. void g2dSetCoordXYRelative(float x, float y)
  368. {
  369.   float inc_x = x, inc_y = y;
  370.   if (obj.rot_cos != 1.f)
  371.   {
  372.     inc_x = -obj.rot_sin*y + obj.rot_cos*x;
  373.     inc_y =  obj.rot_cos*y + obj.rot_sin*x;
  374.   }
  375.   obj.x += inc_x * global_scale;
  376.   obj.y += inc_y * global_scale;
  377. }
  378.  
  379.  
  380. void g2dSetCoordXYZRelative(float x, float y, float z)
  381. {
  382.   g2dSetCoordXYRelative(x,y);
  383.   obj.z += z * global_scale;
  384.   if (z != 0.f) obj_use_z = true;
  385. }
  386.  
  387.  
  388. void g2dSetCoordInteger(bool use)
  389. {
  390.   obj_use_int = use;
  391. }
  392.  
  393. // * Scale functions *
  394.  
  395. void g2dResetGlobalScale()
  396. {
  397.   global_scale = 1.f;
  398. }
  399.  
  400.  
  401. void g2dResetScale()
  402. {
  403.   if (obj_tex == NULL)
  404.   {
  405.     obj.scale_w = DEFAULT_SIZE;
  406.     obj.scale_h = DEFAULT_SIZE;
  407.   }
  408.   else
  409.   {
  410.     obj.scale_w = obj_tex->w;
  411.     obj.scale_h = obj_tex->h;
  412.   }
  413.  
  414.   obj.scale_w *= global_scale;
  415.   obj.scale_h *= global_scale;
  416. }
  417.  
  418.  
  419. void g2dGetGlobalScale(float* scale)
  420. {
  421.   if (scale != NULL) *scale = global_scale;
  422. }
  423.  
  424.  
  425. void g2dGetScaleWH(float* w, float* h)
  426. {
  427.   if (w != NULL) *w = obj.scale_w;
  428.   if (h != NULL) *h = obj.scale_h;
  429. }
  430.  
  431.  
  432. void g2dSetGlobalScale(float scale)
  433. {
  434.   global_scale = scale;
  435. }
  436.  
  437.  
  438. void g2dSetScale(float w, float h)
  439. {
  440.   g2dResetScale();
  441.   g2dSetScaleRelative(w,h);
  442. }
  443.  
  444.  
  445. void g2dSetScaleWH(float w, float h)
  446. {
  447.   obj.scale_w = w * global_scale;
  448.   obj.scale_h = h * global_scale;
  449.   // A trick to prevent an unexpected behavior when mirroring with GU_SPRITES.
  450.   if (obj.scale_w < 0 || obj.scale_h < 0) obj_use_rot = true;
  451. }
  452.  
  453.  
  454. void g2dSetScaleRelative(float w, float h)
  455. {
  456.   obj.scale_w *= w;
  457.   obj.scale_h *= h;
  458.  
  459.   if (obj.scale_w < 0 || obj.scale_h < 0) obj_use_rot = true;
  460. }
  461.  
  462.  
  463. void g2dSetScaleWHRelative(float w, float h)
  464. {
  465.   obj.scale_w += w * global_scale;
  466.   obj.scale_h += h * global_scale;
  467.  
  468.   if (obj.scale_w < 0 || obj.scale_h < 0) obj_use_rot = true;
  469. }
  470.  
  471. // * Color functions *
  472.  
  473. void g2dResetColor()
  474. {
  475.   obj.color = DEFAULT_COLOR;
  476. }
  477.  
  478.  
  479. void g2dResetAlpha()
  480. {
  481.   obj.alpha = DEFAULT_ALPHA;
  482. }
  483.  
  484.  
  485. void g2dGetAlpha(g2dAlpha* alpha)
  486. {
  487.   if (alpha != NULL) *alpha = obj.alpha;
  488. }
  489.  
  490.  
  491. void g2dSetColor(g2dColor color)
  492. {
  493.   obj.color = color;
  494.   if (G2D_GET_A(obj.color) < 255) obj_use_blend = true;
  495. }
  496.  
  497.  
  498. void g2dSetAlpha(g2dAlpha alpha)
  499. {
  500.   if (alpha < 0) alpha = 0;
  501.   if (alpha > 255) alpha = 255;
  502.   obj.alpha = alpha;
  503.   if (obj.alpha < 255) obj_use_blend = true;
  504. }
  505.  
  506.  
  507. void g2dSetAlphaRelative(int alpha)
  508. {
  509.   g2dSetAlpha(obj.alpha + alpha);
  510. }
  511.  
  512. // * Rotations functions *
  513.  
  514. void g2dResetRotation()
  515. {
  516.   obj.rot = 0.f;
  517.   obj.rot_sin = 0.f;
  518.   obj.rot_cos = 1.f;
  519. }
  520.  
  521.  
  522. void g2dGetRotationRad(float* radians)
  523. {
  524.   if (radians != NULL) *radians = obj.rot;
  525. }
  526.  
  527.  
  528. void g2dGetRotation(float* degrees)
  529. {
  530.   if (degrees != NULL) *degrees = obj.rot * M_180_PI;
  531. }
  532.  
  533.  
  534. void g2dSetRotationRad(float radians)
  535. {
  536.   if (radians == obj.rot) return;
  537.   obj.rot = radians;
  538.   obj.rot_sin = sinf(radians);
  539.   obj.rot_cos = cosf(radians);
  540.   if (radians != 0.f) obj_use_rot = true;
  541. }
  542.  
  543.  
  544. void g2dSetRotation(float degrees)
  545. {
  546.   g2dSetRotationRad(degrees * M_PI_180);
  547. }
  548.  
  549.  
  550. void g2dSetRotationRadRelative(float radians)
  551. {
  552.   g2dSetRotationRad(obj.rot + radians);
  553. }
  554.  
  555.  
  556. void g2dSetRotationRelative(float degrees)
  557. {
  558.   g2dSetRotationRadRelative(degrees * M_PI_180);
  559. }
  560.  
  561. // * Crop functions *
  562.  
  563. void g2dResetCrop()
  564. {
  565.   if (obj_tex == NULL) return;
  566.   obj.crop_x = 0;
  567.   obj.crop_y = 0;
  568.   obj.crop_w = obj_tex->w;
  569.   obj.crop_h = obj_tex->h;
  570. }
  571.  
  572.  
  573. void g2dGetCropXY(int* x, int* y)
  574. {
  575.   if (obj_tex == NULL) return;
  576.   if (x != NULL) *x = obj.crop_x;
  577.   if (y != NULL) *y = obj.crop_y;
  578. }
  579.  
  580.  
  581. void g2dGetCropWH(int* w, int* h)
  582. {
  583.   if (obj_tex == NULL) return;
  584.   if (w != NULL) *w = obj.crop_w;
  585.   if (h != NULL) *h = obj.crop_h;
  586. }
  587.  
  588.  
  589. void g2dSetCropXY(int x, int y)
  590. {
  591.   if (obj_tex == NULL) return;
  592.   obj.crop_x = x;
  593.   obj.crop_y = y;
  594. }
  595.  
  596.  
  597. void g2dSetCropWH(int w, int h)
  598. {
  599.   if (obj_tex == NULL) return;
  600.   obj.crop_w = w;
  601.   obj.crop_h = h;
  602. }
  603.  
  604.  
  605. void g2dSetCropXYRelative(int x, int y)
  606. {
  607.   if (obj_tex == NULL) return;
  608.   g2dSetCropXY(obj.crop_x + x, obj.crop_y + y);
  609. }
  610.  
  611.  
  612. void g2dSetCropWHRelative(int w, int h)
  613. {
  614.   if (obj_tex == NULL) return;
  615.   g2dSetCropWH(obj.crop_w + w, obj.crop_h + h);
  616. }
  617.  
  618. // * Texture functions *
  619.  
  620. void g2dResetTex()
  621. {
  622.   if (obj_tex == NULL) return;
  623.   obj_use_tex_repeat = false;
  624.   obj_use_tex_linear = true;
  625.   if (obj_tex->can_blend) obj_use_blend = true;
  626. }
  627.  
  628.  
  629. void g2dSetTexRepeat(bool use)
  630. {
  631.   if (obj_tex == NULL) return;
  632.   obj_use_tex_repeat = use;
  633. }
  634.  
  635.  
  636. void g2dSetTexBlend(bool use)
  637. {
  638.   if (obj_tex == NULL) return;
  639.   if (!obj_tex->can_blend) return;
  640.   obj_use_blend = use;
  641. }
  642.  
  643.  
  644. void g2dSetTexLinear(bool use)
  645. {
  646.   if (obj_tex == NULL) return;
  647.   obj_use_tex_linear = use;
  648. }
  649.  
  650. // * Texture management *
  651.  
  652. void g2dTexFree(g2dImage** tex)
  653. {
  654.   if (tex == NULL) return;
  655.   if (*tex == NULL) return;
  656.   glDeleteTextures(1,&(*tex)->id);
  657.   free(*tex);
  658.   *tex = NULL;
  659. }
  660.  
  661. static g2dImage* _g2dTexFromSDLSurface(SDL_Surface* surface)
  662. {
  663.   SDL_Surface *gl_surface = NULL;
  664.  
  665.   if (!surface) return NULL;
  666.   if (!start) _g2dStart();
  667.  
  668.   g2dImage* tex = (g2dImage*)malloc(sizeof(g2dImage));
  669.   if (!tex) return NULL;
  670.  
  671.   SDL_PixelFormat format = *(surface->format);
  672.   format.BitsPerPixel = 32;
  673.   format.BytesPerPixel = 4;
  674.   format.Rmask = 0x000000ff;
  675.   format.Gmask = 0x0000ff00;
  676.   format.Bmask = 0x00ff0000;
  677.   format.Amask = 0xff000000;
  678.  
  679.   gl_surface = SDL_ConvertSurface(surface,&format,0);
  680.   tex->w = gl_surface->w;
  681.   tex->h = gl_surface->h;
  682.   tex->can_blend = 1;
  683.  
  684.   glGenTextures(1, &tex->id);
  685.   glBindTexture(GL_TEXTURE_2D, tex->id);
  686.   glTexImage2D(GL_TEXTURE_2D, 0, 4, gl_surface->w,
  687.                gl_surface->h, 0, GL_RGBA,GL_UNSIGNED_BYTE,
  688.                gl_surface->pixels);
  689.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  690.   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  691.  
  692.   SDL_FreeSurface(gl_surface);
  693.   SDL_FreeSurface(surface);
  694.  
  695.   return tex;
  696. }
  697.  
  698. g2dImage* g2dTexLoad(char path[], g2dTex_Mode mode)
  699. {
  700.   if (!path) return NULL;
  701.  
  702.   return _g2dTexFromSDLSurface(IMG_Load(path));
  703. }
  704.  
  705. g2dImage* g2dTexFromFont(TTF_Font* font, char text[], g2dColor color)
  706. {
  707.   if (!font) return NULL;
  708.  
  709.   SDL_Color sdl_color;
  710.   sdl_color.r = G2D_GET_R(color);
  711.   sdl_color.g = G2D_GET_G(color);
  712.   sdl_color.b = G2D_GET_B(color);
  713.  
  714.   return _g2dTexFromSDLSurface(TTF_RenderUTF8_Blended(font, text, sdl_color));
  715. }
  716.  
  717. // * Scissor functions *
  718.  
  719. void g2dResetScissor()
  720. {
  721.   g2dSetScissor(0,0,G2D_SCR_W,G2D_SCR_H);
  722.   scissor = false;
  723. }
  724.  
  725.  
  726. void g2dSetScissor(int x, int y, int w, int h)
  727. {
  728.   glScissor(x,G2D_SCR_H-y-h,w,h);
  729.   scissor = true;
  730. }
  731.  
  732. // EOF
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement