LCOV - code coverage report
Current view: top level - addons/primitives - polyline.c (source / functions) Hit Total Coverage
Test: allegro_auto.info Lines: 174 182 95.6 %
Date: 2013-01-02 Functions: 14 15 93.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 54 88 61.4 %

           Branch data     Line data    Source code
       1                 :            : /*         ______   ___    ___
       2                 :            :  *        /\  _  \ /\_ \  /\_ \
       3                 :            :  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
       4                 :            :  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
       5                 :            :  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
       6                 :            :  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
       7                 :            :  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
       8                 :            :  *                                           /\____/
       9                 :            :  *                                           \_/__/
      10                 :            :  *
      11                 :            :  *      Polyline primitive.
      12                 :            :  *
      13                 :            :  *
      14                 :            :  *      By Michał Cichoń.
      15                 :            :  *
      16                 :            :  *      See readme.txt for copyright information.
      17                 :            :  */
      18                 :            : 
      19                 :            : #include "allegro5/allegro.h"
      20                 :            : #include "allegro5/allegro_primitives.h"
      21                 :            : #include "allegro5/internal/aintern_list.h"
      22                 :            : #include "allegro5/internal/aintern_prim.h"
      23                 :            : #include <float.h>
      24                 :            : #include <math.h>
      25                 :            : 
      26                 :            : 
      27                 :            : /*
      28                 :            :  * Computes direction, normal direction and the length of the segment.
      29                 :            :  */
      30                 :        544 : static float compute_direction_and_normal(const float* begin, const float* end, float* dir, float* normal)
      31                 :            : {
      32                 :            :    float length;
      33                 :            : 
      34                 :            :    /* Determine direction, normal direction and length of the line segment. */
      35                 :        544 :    dir[0] = end[0] - begin[0];
      36                 :        544 :    dir[1] = end[1] - begin[1];
      37                 :            : 
      38                 :        544 :    length = _al_prim_normalize(dir);
      39                 :            : 
      40                 :        544 :    normal[0] = -dir[1];
      41                 :        544 :    normal[1] =  dir[0];
      42                 :            : 
      43                 :        544 :    return length;
      44                 :            : }
      45                 :            : 
      46                 :            : /*
      47                 :            :  * Compute end cross points.
      48                 :            :  */
      49                 :         36 : static void compute_end_cross_points(const float* v0, const float* v1, float radius, float* p0, float* p1)
      50                 :            : {
      51                 :            :    float dir[2];
      52                 :            :    float normal[2];
      53                 :            :    /* XXX delete this parameter? */
      54                 :            :    (void)radius;
      55                 :            : 
      56                 :         36 :    compute_direction_and_normal(v0, v1, dir, normal);
      57                 :            : 
      58                 :         36 :    p0[0] = v1[0] + normal[0] * radius;
      59                 :         36 :    p0[1] = v1[1] + normal[1] * radius;
      60                 :         36 :    p1[0] = v1[0] - normal[0] * radius;
      61                 :         36 :    p1[1] = v1[1] - normal[1] * radius;
      62                 :         36 : }
      63                 :            : 
      64                 :            : /*
      65                 :            :  * Compute cross points.
      66                 :            :  */
      67                 :        248 : static void compute_cross_points(const float* v0, const float* v1, const float* v2, float radius,
      68                 :            :    float* l0, float* l1, float* r0, float* r1, float* out_middle, float* out_angle, float* out_miter_distance)
      69                 :            : {
      70                 :            :    float normal_0[2], normal_1[2];
      71                 :            :    float dir_0[2], dir_1[2];
      72                 :            :    float middle[2];
      73                 :            :    float diff[2];
      74                 :            :    float miter_distance;
      75                 :            :    float angle;
      76                 :            : 
      77                 :            :    /* We accept a few call cases. Filter out unsupported. */
      78 [ +  - ][ -  + ]:        248 :    ASSERT((NULL != v0 || NULL != v2) && (NULL != v1));
         [ #  # ][ #  # ]
                 [ #  # ]
      79                 :            : 
      80                 :            :    /* Compute directions. */
      81                 :        248 :    compute_direction_and_normal(v0, v1, dir_0, normal_0);
      82                 :        248 :    compute_direction_and_normal(v1, v2, dir_1, normal_1);
      83                 :            : 
      84                 :            :    /* Compute angle of deflection between segments. */
      85                 :        248 :    diff[0] =   dir_0[0] * dir_1[0] + dir_0[1] * dir_1[1];
      86                 :        248 :    diff[1] = -(dir_0[0] * dir_1[1] - dir_0[1] * dir_1[0]);
      87                 :            : 
      88 [ -  + ][ #  # ]:        248 :    angle = (diff[0] || diff[1]) ? atan2f(diff[1], diff[0]) : 0.0f;
      89                 :            : 
      90                 :            :    /* Calculate miter distance. */
      91         [ +  - ]:        248 :    miter_distance = angle != 0.0f ? radius / cosf(fabsf(angle) * 0.5f) : radius;
      92                 :            : 
      93                 :        248 :    middle[0] = normal_0[0] + normal_1[0];
      94                 :        248 :    middle[1] = normal_0[1] + normal_1[1];
      95                 :            : 
      96                 :        248 :    _al_prim_normalize(middle);
      97                 :            : 
      98                 :            :    /* Compute points. */
      99         [ +  + ]:        248 :    if (angle > 0.0f)
     100                 :            :    {
     101                 :        130 :       l0[0] = v1[0] + normal_0[0] * radius;
     102                 :        130 :       l0[1] = v1[1] + normal_0[1] * radius;
     103                 :        130 :       r0[0] = v1[0] + normal_1[0] * radius;
     104                 :        130 :       r0[1] = v1[1] + normal_1[1] * radius;
     105                 :            : 
     106                 :        130 :       l1[0] = r1[0] = v1[0] - middle[0] * miter_distance;
     107                 :        130 :       l1[1] = r1[1] = v1[1] - middle[1] * miter_distance;
     108                 :            :    }
     109                 :            :    else
     110                 :            :    {
     111                 :        118 :       middle[0] = -middle[0];
     112                 :        118 :       middle[1] = -middle[1];
     113                 :            : 
     114                 :        118 :       l1[0] = v1[0] - normal_0[0] * radius;
     115                 :        118 :       l1[1] = v1[1] - normal_0[1] * radius;
     116                 :        118 :       r1[0] = v1[0] - normal_1[0] * radius;
     117                 :        118 :       r1[1] = v1[1] - normal_1[1] * radius;
     118                 :            : 
     119                 :        118 :       l0[0] = r0[0] = v1[0] - middle[0] * miter_distance;
     120                 :        118 :       l0[1] = r0[1] = v1[1] - middle[1] * miter_distance;
     121                 :            :    }
     122                 :            : 
     123         [ +  + ]:        248 :    if (out_angle)
     124                 :        244 :       *out_angle = angle;
     125                 :            : 
     126         [ +  + ]:        248 :    if (out_miter_distance)
     127                 :        244 :       *out_miter_distance = miter_distance;
     128                 :            : 
     129         [ +  + ]:        248 :    if (out_middle)
     130                 :        244 :       memcpy(out_middle, middle, sizeof(float) * 2);
     131                 :        248 : }
     132                 :            : 
     133                 :            : /*
     134                 :            :  * Emits filled arc.
     135                 :            :  *
     136                 :            :  * Arc is defined by pivot point, radius, start and end angle.
     137                 :            :  * Starting and ending angle are wrapped to two pi range.
     138                 :            :  */
     139                 :         82 : static void emit_arc(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, float start, float end, float radius, int segments)
     140                 :            : {
     141                 :            :    float step, angle, arc;
     142                 :            :    float v0[2];
     143                 :            :    float v1[2];
     144                 :            :    int i;
     145                 :            : 
     146                 :            :    /* This is very small arc, we will draw nothing. */
     147         [ +  - ]:         82 :    if (fabsf(end - start) < 0.001f)
     148                 :         82 :       return;
     149                 :            : 
     150                 :            :    /* Make sure start both start angle is located in the
     151                 :            :     * range [0, 2 * pi) and end angle is greater than
     152                 :            :     * start angle.
     153                 :            :     */
     154                 :         82 :    start = fmodf(start, ALLEGRO_PI * 2.0f);
     155                 :         82 :    end   = fmodf(end,   ALLEGRO_PI * 2.0f);
     156         [ -  + ]:         82 :    if (end <= start)
     157                 :          0 :       end += ALLEGRO_PI * 2.0f;
     158                 :            : 
     159                 :         82 :    arc = end - start;
     160                 :            : 
     161                 :         82 :    segments = (int)(segments * arc / ALLEGRO_PI * 2.0f);
     162         [ -  + ]:         82 :    if (segments < 1)
     163                 :          0 :       segments = 1;
     164                 :            : 
     165                 :         82 :    step = arc / segments;
     166                 :            : 
     167                 :         82 :    angle = start;
     168                 :            : 
     169                 :         82 :    v0[0] = pivot[0] + cosf(angle) * radius;
     170                 :         82 :    v0[1] = pivot[1] + sinf(angle) * radius;
     171         [ +  + ]:       1632 :    for (i = 0; i < segments; ++i, angle += step)
     172                 :            :    {
     173                 :       1550 :       v1[0] = pivot[0] + cosf(angle + step) * radius;
     174                 :       1550 :       v1[1] = pivot[1] + sinf(angle + step) * radius;
     175                 :            : 
     176                 :       1550 :       _al_prim_cache_push_triangle(cache, v0, pivot, v1);
     177                 :            : 
     178                 :       1550 :       v0[0] = v1[0];
     179                 :       1550 :       v0[1] = v1[1];
     180                 :            :    }
     181                 :            : }
     182                 :            : 
     183                 :            : /*
     184                 :            :  * Emits square cap.
     185                 :            :  *
     186                 :            :  * Square cap is an rectangle with edges lengths equal to radius
     187                 :            :  * and double radius, first along direction second along normal
     188                 :            :  * direction.
     189                 :            :  */
     190                 :          4 : static void emit_square_end_cap(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* dir, const float* normal, float radius)
     191                 :            : {
     192                 :            :    /* Prepare all four vertices of the rectangle. */
     193                 :          4 :    float v0[2] = { pivot[0] + normal[0] * radius, pivot[1] + normal[1] * radius };
     194                 :          4 :    float v1[2] = { pivot[0] - normal[0] * radius, pivot[1] - normal[1] * radius };
     195                 :          4 :    float v2[2] = {       v0[0] + dir[0] * radius,       v0[1] + dir[1] * radius };
     196                 :          4 :    float v3[2] = {       v1[0] + dir[0] * radius,       v1[1] + dir[1] * radius };
     197                 :            : 
     198                 :            :    /* Emit. */
     199                 :          4 :    _al_prim_cache_push_triangle(cache, v0, v2, v3);
     200                 :          4 :    _al_prim_cache_push_triangle(cache, v0, v3, v1);
     201                 :          4 : }
     202                 :            : 
     203                 :            : /*
     204                 :            :  * Emits triangular cap.
     205                 :            :  */
     206                 :          4 : static void emit_triange_end_cap(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* dir, const float* normal, float radius)
     207                 :            : {
     208                 :            :    /* Prepare all four vertices of the rectangle. */
     209                 :          4 :    float v0[2] = { pivot[0] + normal[0] * radius, pivot[1] + normal[1] * radius };
     210                 :          4 :    float v1[2] = { pivot[0] - normal[0] * radius, pivot[1] - normal[1] * radius };
     211                 :          4 :    float v2[2] = { pivot[0] +    dir[0] * radius, pivot[1] +    dir[1] * radius };
     212                 :            : 
     213                 :            :    /* Emit. */
     214                 :          4 :    _al_prim_cache_push_triangle(cache, v0, v2, v1);
     215                 :          4 : }
     216                 :            : 
     217                 :            : /*
     218                 :            :  * Emits rounded cap.
     219                 :            :  */
     220                 :          4 : static void emit_round_end_cap(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* dir, const float* normal, float radius)
     221                 :            : {
     222                 :          4 :    float angle = atan2f(-normal[1], -normal[0]);
     223                 :            :    /* XXX delete these parameters? */
     224                 :            :    (void)dir;
     225                 :            :    (void)radius;
     226                 :            : 
     227                 :          4 :    emit_arc(cache, pivot, angle, angle + ALLEGRO_PI, radius, 16);
     228                 :          4 : }
     229                 :            : 
     230                 :            : /*
     231                 :            :  * Emits end cap.
     232                 :            :  *
     233                 :            :  * Direction of the end cap is defined by vector [v1 - v0]. p0 and p1 are starting
     234                 :            :  * and ending point of the cap. Both should be located on the circle with center
     235                 :            :  * in v1 and specified radius. p0 have to be located on the negative and p0 on the
     236                 :            :  * positive half plane defined by direction vector.
     237                 :            :  */
     238                 :         36 : static void emit_end_cap(ALLEGRO_PRIM_VERTEX_CACHE* cache, int cap_style, const float* v0, const float* v1, float radius)
     239                 :            : {
     240                 :            :    float dir[2];
     241                 :            :    float normal[2];
     242                 :            : 
     243                 :            :    /* Do do not want you to call this function for closed cap.
     244                 :            :     * It is special and there is nothing we can do with it there.
     245                 :            :     */
     246 [ -  + ][ #  # ]:         36 :    ASSERT(cap_style != ALLEGRO_LINE_CAP_CLOSED);
                 [ #  # ]
     247                 :            : 
     248                 :            :    /* There nothing we can do for this kind of ending cap. */
     249         [ +  + ]:         36 :    if (cap_style == ALLEGRO_LINE_CAP_NONE)
     250                 :         36 :       return;
     251                 :            : 
     252                 :            :    /* Compute normal and direction for our segment. */
     253                 :         12 :    compute_direction_and_normal(v0, v1, dir, normal);
     254                 :            : 
     255                 :            :    /* Emit vertices for cap. */
     256         [ +  + ]:         12 :    if (cap_style == ALLEGRO_LINE_CAP_SQUARE)
     257                 :          4 :       emit_square_end_cap(cache, v1, dir, normal, radius);
     258         [ +  + ]:          8 :    else if (cap_style == ALLEGRO_LINE_CAP_TRIANGLE)
     259                 :          4 :       emit_triange_end_cap(cache, v1, dir, normal, radius);
     260         [ +  - ]:          4 :    else if (cap_style == ALLEGRO_LINE_CAP_ROUND)
     261                 :          4 :       emit_round_end_cap(cache, v1, dir, normal, radius);
     262                 :            :    else {
     263                 :            : 
     264         [ #  # ]:         36 :       ASSERT("Unknown or unsupported style of ending cap." && false);
     265                 :            :    }
     266                 :            : }
     267                 :            : 
     268                 :            : /*
     269                 :            :  * Emits bevel join.
     270                 :            :  */
     271                 :            : static void emit_bevel_join(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* p0, const float* p1)
     272                 :            : {
     273                 :         20 :    _al_prim_cache_push_triangle(cache, pivot, p0, p1);
     274                 :            : }
     275                 :            : 
     276                 :            : /*
     277                 :            :  * Emits round join.
     278                 :            :  */
     279                 :         78 : static void emit_round_join(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* p0, const float* p1, float radius)
     280                 :            : {
     281                 :         78 :    float start = atan2f(p1[1] - pivot[1], p1[0] - pivot[0]);
     282                 :         78 :    float end   = atan2f(p0[1] - pivot[1], p0[0] - pivot[0]);
     283                 :            : 
     284         [ +  + ]:         78 :    if (end < start)
     285                 :         24 :       end += ALLEGRO_PI * 2.0f;
     286                 :            : 
     287                 :         78 :    emit_arc(cache, pivot, start, end, radius, 16);
     288                 :         78 : }
     289                 :            : 
     290                 :            : /*
     291                 :            :  * Emits miter join.
     292                 :            :  */
     293                 :         40 : static void emit_miter_join(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* p0, const float* p1,
     294                 :            :    float radius, const float* middle, float angle, float miter_distance, float max_miter_distance)
     295                 :            : {
     296                 :            :    /* XXX delete this parameter? */
     297                 :            :    (void)radius;
     298                 :            : 
     299         [ +  + ]:         40 :    if (miter_distance > max_miter_distance) {
     300                 :            : 
     301                 :         24 :       float normal[2] = { -middle[1], middle[0] };
     302                 :            : 
     303                 :         24 :       float offset = (miter_distance - max_miter_distance) * tanf((ALLEGRO_PI - fabsf(angle)) * 0.5f);
     304                 :            : 
     305                 :         48 :       float v0[2] = {
     306                 :         24 :          pivot[0] + middle[0] * max_miter_distance + normal[0] * offset,
     307                 :         24 :          pivot[1] + middle[1] * max_miter_distance + normal[1] * offset
     308                 :            :       };
     309                 :            : 
     310                 :         48 :       float v1[2] = {
     311                 :         24 :          pivot[0] + middle[0] * max_miter_distance - normal[0] * offset,
     312                 :         24 :          pivot[1] + middle[1] * max_miter_distance - normal[1] * offset
     313                 :            :       };
     314                 :            : 
     315                 :         24 :       _al_prim_cache_push_triangle(cache, pivot, v0, v1);
     316                 :         24 :       _al_prim_cache_push_triangle(cache, pivot, p0, v0);
     317                 :         24 :       _al_prim_cache_push_triangle(cache, pivot, p1, v1);
     318                 :            :    }
     319                 :            :    else {
     320                 :            : 
     321                 :         32 :       float miter[2] = {
     322                 :         16 :          pivot[0] + middle[0] * miter_distance,
     323                 :         16 :          pivot[1] + middle[1] * miter_distance,
     324                 :            :       };
     325                 :            : 
     326                 :         16 :       _al_prim_cache_push_triangle(cache, pivot, p0, miter);
     327                 :         16 :       _al_prim_cache_push_triangle(cache, pivot, miter, p1);
     328                 :            :    }
     329                 :         40 : }
     330                 :            : 
     331                 :            : 
     332                 :            : /* Emit join between segments.
     333                 :            :  */
     334                 :        244 : static void emit_join(ALLEGRO_PRIM_VERTEX_CACHE* cache, int join_style, const float* pivot,
     335                 :            :    const float* p0, const float* p1, float radius, const float* middle,
     336                 :            :    float angle, float miter_distance, float miter_limit)
     337                 :            : {
     338                 :            :    /* There is nothing to do for this type of join. */
     339         [ +  + ]:        244 :    if (join_style == ALLEGRO_LINE_JOIN_NONE)
     340                 :        244 :       return;
     341                 :            : 
     342         [ +  + ]:        138 :    if (join_style == ALLEGRO_LINE_JOIN_BEVEL)
     343                 :            :       emit_bevel_join(cache, pivot, p0, p1);
     344         [ +  + ]:        118 :    else if (join_style == ALLEGRO_LINE_JOIN_ROUND)
     345                 :         78 :       emit_round_join(cache, pivot, p0, p1, radius);
     346         [ +  - ]:         40 :    else if (join_style == ALLEGRO_LINE_JOIN_MITER)
     347                 :         40 :       emit_miter_join(cache, pivot, p0, p1, radius, middle, angle, miter_distance, miter_limit * radius);
     348                 :            :    else {
     349                 :            : 
     350         [ #  # ]:          0 :       ASSERT("Unknown or unsupported style of join." && false);
     351                 :            :    }
     352                 :            : }
     353                 :            : 
     354                 :         22 : static void emit_polyline(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* vertices, int vertex_stride, int vertex_count, int join_style, int cap_style, float thickness, float miter_limit)
     355                 :            : {
     356                 :            : # define VERTEX(index)  ((const float*)(((uint8_t*)vertices) + vertex_stride * ((vertex_count + (index)) % vertex_count)))
     357                 :            : 
     358                 :            :    float l0[2], l1[2];
     359                 :            :    float r0[2], r1[2];
     360                 :            :    float p0[2], p1[2];
     361                 :            :    float radius;
     362                 :            :    int steps;
     363                 :            :    int i;
     364                 :            : 
     365 [ -  + ][ #  # ]:         22 :    ASSERT(thickness > 0.0f);
                 [ #  # ]
     366                 :            : 
     367                 :            :    /* Discard invalid lines. */
     368         [ +  - ]:         22 :    if (vertex_count < 2)
     369                 :         22 :       return;
     370                 :            : 
     371                 :         22 :    radius = 0.5f * thickness;
     372                 :            : 
     373                 :            :    /* Single line cannot be closed. If user forgot to explicitly specify
     374                 :            :    * most desired alternative cap style, we just disable capping at all.
     375                 :            :    */
     376         [ -  + ]:         22 :    if (vertex_count == 2 && cap_style == ALLEGRO_LINE_CAP_CLOSED)
     377                 :          0 :       cap_style = ALLEGRO_LINE_CAP_NONE;
     378                 :            : 
     379                 :            :    /* Prepare initial set of vertices. */
     380         [ +  + ]:         22 :    if (cap_style != ALLEGRO_LINE_CAP_CLOSED)
     381                 :            :    {
     382                 :            :       /* We can emit ending caps right now.
     383                 :            :       *
     384                 :            :       * VERTEX(-2) and similar are safe, because it at this place
     385                 :            :       * it is guaranteed that there are at least two vertices
     386                 :            :       * in the buffer.
     387                 :            :       */
     388                 :         18 :       emit_end_cap(cache, cap_style,  VERTEX(1),  VERTEX(0), radius);
     389                 :         18 :       emit_end_cap(cache, cap_style, VERTEX(-2), VERTEX(-1), radius);
     390                 :            : 
     391                 :            :       /* Compute points on the left side of the very first segment. */
     392                 :         18 :       compute_end_cross_points(VERTEX(1), VERTEX(0), radius, p1, p0);
     393                 :            : 
     394                 :            :       /* For non-closed line we have N - 1 steps, but since we iterate
     395                 :            :       * from one, N is right value.
     396                 :            :       */
     397                 :         18 :       steps = vertex_count;
     398                 :            :    }
     399                 :            :    else
     400                 :            :    {
     401                 :            :       /* Compute points on the left side of the very first segment. */
     402                 :          4 :       compute_cross_points(VERTEX(-1), VERTEX(0), VERTEX(1), radius, l0, l1, p0, p1, NULL, NULL, NULL);
     403                 :            : 
     404                 :            :       /* Closed line use N steps, because last vertex have to be
     405                 :            :       * connected with first one.
     406                 :            :       */
     407                 :          4 :       steps = vertex_count + 1;
     408                 :            :    }
     409                 :            : 
     410                 :            :    /* Process segments. */
     411         [ +  + ]:        284 :    for (i = 1; i < steps; ++i)
     412                 :            :    {
     413                 :            :       /* Pick vertex and their neighbors. */
     414                 :        262 :       const float* v0 = VERTEX(i - 1);
     415                 :        262 :       const float* v1 = VERTEX(i);
     416                 :        262 :       const float* v2 = VERTEX(i + 1);
     417                 :            : 
     418                 :            :       /* Choose correct cross points. */
     419 [ +  + ][ +  + ]:        506 :       if ((cap_style == ALLEGRO_LINE_CAP_CLOSED) || (i < steps - 1)) {
     420                 :            : 
     421                 :            :          float middle[2];
     422                 :            :          float miter_distance;
     423                 :            :          float angle;
     424                 :            : 
     425                 :            :          /* Compute cross points. */
     426                 :        244 :          compute_cross_points(v0, v1, v2, radius, l0, l1, r0, r1, middle, &angle, &miter_distance);
     427                 :            : 
     428                 :            :          /* Emit join. */
     429         [ +  + ]:        244 :          if (angle >= 0.0f)
     430                 :        126 :             emit_join(cache, join_style, v1, l0, r0, radius, middle, angle, miter_distance, miter_limit);
     431                 :            :          else
     432                 :        118 :             emit_join(cache, join_style, v1, r1, l1, radius, middle, angle, miter_distance, miter_limit);
     433                 :            :       }
     434                 :            :       else
     435                 :         18 :          compute_end_cross_points(v0, v1, radius, l0, l1);
     436                 :            : 
     437                 :            :       /* Emit triangles. */
     438                 :        262 :       _al_prim_cache_push_triangle(cache, v0, v1, l1);
     439                 :        262 :       _al_prim_cache_push_triangle(cache, v0, l1, p1);
     440                 :        262 :       _al_prim_cache_push_triangle(cache, v0, p0, l0);
     441                 :        262 :       _al_prim_cache_push_triangle(cache, v0, l0, v1);
     442                 :            : 
     443                 :            :       /* Save current most right vertices. */
     444                 :        262 :       memcpy(p0, r0, sizeof(float) * 2);
     445                 :        262 :       memcpy(p1, r1, sizeof(float) * 2);
     446                 :            :    }
     447                 :            : 
     448                 :            : # undef VERTEX
     449                 :            : }
     450                 :            : 
     451                 :         24 : static void do_draw_polyline(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* vertices, int vertex_stride, int vertex_count, int join_style, int cap_style, ALLEGRO_COLOR color, float thickness, float miter_limit)
     452                 :            : {
     453         [ +  + ]:         24 :    if (thickness > 0.0f)
     454                 :            :    {
     455                 :         22 :       _al_prim_cache_init(cache, ALLEGRO_PRIM_VERTEX_CACHE_TRIANGLE, color);
     456                 :         22 :       emit_polyline(cache, vertices, vertex_stride, vertex_count, join_style, cap_style, thickness, miter_limit);
     457                 :         22 :       _al_prim_cache_term(cache);
     458                 :            :    }
     459                 :            :    else
     460                 :            :    {
     461                 :            : # define VERTEX(index)  ((const float*)(((uint8_t*)vertices) + vertex_stride * ((vertex_count + (index)) % vertex_count)))
     462                 :            : 
     463                 :            :       int i;
     464                 :            : 
     465                 :          2 :       _al_prim_cache_init(cache, ALLEGRO_PRIM_VERTEX_CACHE_LINE_STRIP, color);
     466                 :            : 
     467         [ +  + ]:         26 :       for (i = 0; i < vertex_count; ++i) {
     468                 :            : 
     469         [ -  + ]:         24 :          if (cache->size >= (ALLEGRO_VERTEX_CACHE_SIZE - 2))
     470                 :          0 :             _al_prim_cache_flush(cache);
     471                 :            : 
     472                 :         24 :          _al_prim_cache_push_point(cache, VERTEX(i));
     473                 :            :       }
     474                 :            : 
     475                 :          2 :       _al_prim_cache_term(cache);
     476                 :            : 
     477                 :            : # undef VERTEX
     478                 :            :    }
     479                 :         24 : }
     480                 :            : 
     481                 :            : /* Function: al_draw_polyline
     482                 :            :  */
     483                 :         24 : void al_draw_polyline(const float* vertices, int vertex_count,
     484                 :            :    ALLEGRO_LINE_JOIN join_style, ALLEGRO_LINE_CAP cap_style,
     485                 :            :    ALLEGRO_COLOR color, float thickness, float miter_limit)
     486                 :            : {
     487                 :            :    ALLEGRO_PRIM_VERTEX_CACHE cache;
     488                 :         24 :    do_draw_polyline(&cache, vertices, sizeof(float) * 2, vertex_count, join_style, cap_style, color, thickness, miter_limit);
     489                 :         24 : }
     490                 :            : 
     491                 :            : /* Function: al_draw_polyline_ex
     492                 :            :  */
     493                 :          0 : void al_draw_polyline_ex(const float* vertices, int vertex_stride,
     494                 :            :    int vertex_count, ALLEGRO_LINE_JOIN join_style, ALLEGRO_LINE_CAP cap_style,
     495                 :            :    ALLEGRO_COLOR color, float thickness, float miter_limit)
     496                 :            : {
     497                 :            :    ALLEGRO_PRIM_VERTEX_CACHE cache;
     498                 :          0 :    do_draw_polyline(&cache, vertices, vertex_stride, vertex_count, join_style, cap_style, color, thickness, miter_limit);
     499                 :          0 : }
     500                 :            : 
     501                 :            : /* vim: set sts=3 sw=3 et: */

Generated by: LCOV version 1.9