Esempio n. 1
0
/*
 * Emits square cap.
 *
 * Square cap is an rectangle with edges lengths equal to radius
 * and double radius, first along direction second along normal
 * direction.
 */
static void emit_square_end_cap(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* dir, const float* normal, float radius)
{
   /* Prepare all four vertices of the rectangle. */
   float v0[2] = { pivot[0] + normal[0] * radius, pivot[1] + normal[1] * radius };
   float v1[2] = { pivot[0] - normal[0] * radius, pivot[1] - normal[1] * radius };
   float v2[2] = {       v0[0] + dir[0] * radius,       v0[1] + dir[1] * radius };
   float v3[2] = {       v1[0] + dir[0] * radius,       v1[1] + dir[1] * radius };

   /* Emit. */
   _al_prim_cache_push_triangle(cache, v0, v2, v3);
   _al_prim_cache_push_triangle(cache, v0, v3, v1);
}
Esempio n. 2
0
static void polygon_push_triangle_callback(int i0, int i1, int i2, void* user_data)
{
   ALLEGRO_PRIM_VERTEX_CACHE* cache = (ALLEGRO_PRIM_VERTEX_CACHE*)user_data;

   const float* vertices = (const float*)cache->user_data;

   const float* v0 = vertices + (i0 * 2);
   const float* v1 = vertices + (i1 * 2);
   const float* v2 = vertices + (i2 * 2);

   _al_prim_cache_push_triangle(cache, v0, v1, v2);
}
Esempio n. 3
0
/*
 * Emits miter join.
 */
static void emit_miter_join(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* p0, const float* p1,
   float radius, const float* middle, float angle, float miter_distance, float max_miter_distance)
{
   /* XXX delete this parameter? */
   (void)radius;

   if (miter_distance > max_miter_distance) {

      float normal[2] = { -middle[1], middle[0] };

      float offset = (miter_distance - max_miter_distance) * tanf((ALLEGRO_PI - fabsf(angle)) * 0.5f);

      float v0[2] = {
         pivot[0] + middle[0] * max_miter_distance + normal[0] * offset,
         pivot[1] + middle[1] * max_miter_distance + normal[1] * offset
      };

      float v1[2] = {
         pivot[0] + middle[0] * max_miter_distance - normal[0] * offset,
         pivot[1] + middle[1] * max_miter_distance - normal[1] * offset
      };

      _al_prim_cache_push_triangle(cache, pivot, v0, v1);
      _al_prim_cache_push_triangle(cache, pivot, p0, v0);
      _al_prim_cache_push_triangle(cache, pivot, p1, v1);
   }
   else {

      float miter[2] = {
         pivot[0] + middle[0] * miter_distance,
         pivot[1] + middle[1] * miter_distance,
      };

      _al_prim_cache_push_triangle(cache, pivot, p0, miter);
      _al_prim_cache_push_triangle(cache, pivot, miter, p1);
   }
}
Esempio n. 4
0
/*
 * Emits filled arc.
 *
 * Arc is defined by pivot point, radius, start and end angle.
 * Starting and ending angle are wrapped to two pi range.
 */
static void emit_arc(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, float start, float end, float radius, int segments)
{
   float step, angle, arc;
   float v0[2];
   float v1[2];
   int i;

   /* This is very small arc, we will draw nothing. */
   if (fabsf(end - start) < 0.001f)
      return;

   /* Make sure start both start angle is located in the
    * range [0, 2 * pi) and end angle is greater than
    * start angle.
    */
   start = fmodf(start, ALLEGRO_PI * 2.0f);
   end   = fmodf(end,   ALLEGRO_PI * 2.0f);
   if (end <= start)
      end += ALLEGRO_PI * 2.0f;

   arc = end - start;

   segments = (int)(segments * arc / ALLEGRO_PI * 2.0f);
   if (segments < 1)
      segments = 1;

   step = arc / segments;

   angle = start;

   v0[0] = pivot[0] + cosf(angle) * radius;
   v0[1] = pivot[1] + sinf(angle) * radius;
   for (i = 0; i < segments; ++i, angle += step)
   {
      v1[0] = pivot[0] + cosf(angle + step) * radius;
      v1[1] = pivot[1] + sinf(angle + step) * radius;

      _al_prim_cache_push_triangle(cache, v0, pivot, v1);

      v0[0] = v1[0];
      v0[1] = v1[1];
   }
}
Esempio n. 5
0
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)
{
# define VERTEX(index)  ((const float*)(((uint8_t*)vertices) + vertex_stride * ((vertex_count + (index)) % vertex_count)))

   float l0[2], l1[2];
   float r0[2], r1[2];
   float p0[2], p1[2];
   float radius;
   int steps;
   int i;

   ASSERT(thickness > 0.0f);

   /* Discard invalid lines. */
   if (vertex_count < 2)
      return;

   radius = 0.5f * thickness;

   /* Single line cannot be closed. If user forgot to explicitly specify
   * most desired alternative cap style, we just disable capping at all.
   */
   if (vertex_count == 2 && cap_style == ALLEGRO_LINE_CAP_CLOSED)
      cap_style = ALLEGRO_LINE_CAP_NONE;

   /* Prepare initial set of vertices. */
   if (cap_style != ALLEGRO_LINE_CAP_CLOSED)
   {
      /* We can emit ending caps right now.
      *
      * VERTEX(-2) and similar are safe, because it at this place
      * it is guaranteed that there are at least two vertices
      * in the buffer.
      */
      emit_end_cap(cache, cap_style,  VERTEX(1),  VERTEX(0), radius);
      emit_end_cap(cache, cap_style, VERTEX(-2), VERTEX(-1), radius);

      /* Compute points on the left side of the very first segment. */
      compute_end_cross_points(VERTEX(1), VERTEX(0), radius, p1, p0);

      /* For non-closed line we have N - 1 steps, but since we iterate
      * from one, N is right value.
      */
      steps = vertex_count;
   }
   else
   {
      /* Compute points on the left side of the very first segment. */
      compute_cross_points(VERTEX(-1), VERTEX(0), VERTEX(1), radius, l0, l1, p0, p1, NULL, NULL, NULL);

      /* Closed line use N steps, because last vertex have to be
      * connected with first one.
      */
      steps = vertex_count + 1;
   }

   /* Process segments. */
   for (i = 1; i < steps; ++i)
   {
      /* Pick vertex and their neighbors. */
      const float* v0 = VERTEX(i - 1);
      const float* v1 = VERTEX(i);
      const float* v2 = VERTEX(i + 1);

      /* Choose correct cross points. */
      if ((cap_style == ALLEGRO_LINE_CAP_CLOSED) || (i < steps - 1)) {

         float middle[2];
         float miter_distance;
         float angle;

         /* Compute cross points. */
         compute_cross_points(v0, v1, v2, radius, l0, l1, r0, r1, middle, &angle, &miter_distance);

         /* Emit join. */
         if (angle >= 0.0f)
            emit_join(cache, join_style, v1, l0, r0, radius, middle, angle, miter_distance, miter_limit);
         else
            emit_join(cache, join_style, v1, r1, l1, radius, middle, angle, miter_distance, miter_limit);
      }
      else
         compute_end_cross_points(v0, v1, radius, l0, l1);

      /* Emit triangles. */
      _al_prim_cache_push_triangle(cache, v0, v1, l1);
      _al_prim_cache_push_triangle(cache, v0, l1, p1);
      _al_prim_cache_push_triangle(cache, v0, p0, l0);
      _al_prim_cache_push_triangle(cache, v0, l0, v1);

      /* Save current most right vertices. */
      memcpy(p0, r0, sizeof(float) * 2);
      memcpy(p1, r1, sizeof(float) * 2);
   }

# undef VERTEX
}
Esempio n. 6
0
/*
 * Emits bevel join.
 */
static void emit_bevel_join(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* pivot, const float* p0, const float* p1)
{
   _al_prim_cache_push_triangle(cache, pivot, p0, p1);
}