summaryrefslogtreecommitdiff
path: root/src/gallium/auxiliary/util/u_split_prim.h
blob: 5afb7d9a920406fbe17c32c1d774bb659f0bacbd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/* Originally written by Ben Skeggs for the nv50 driver*/

#ifndef U_SPLIT_PRIM_H
#define U_SPLIT_PRIM_H

#include "pipe/p_defines.h"
#include "pipe/p_compiler.h"

#include "util/u_debug.h"

struct util_split_prim {
   void *priv;
   void (*emit)(void *priv, unsigned start, unsigned count);
   void (*edge)(void *priv, boolean enabled);

   unsigned mode;
   unsigned start;
   unsigned p_start;
   unsigned p_end;

   uint repeat_first:1;
   uint close_first:1;
   uint edgeflag_off:1;
};

static inline void
util_split_prim_init(struct util_split_prim *s,
                  unsigned mode, unsigned start, unsigned count)
{
   if (mode == PIPE_PRIM_LINE_LOOP) {
      s->mode = PIPE_PRIM_LINE_STRIP;
      s->close_first = 1;
   } else {
      s->mode = mode;
      s->close_first = 0;
   }
   s->start = start;
   s->p_start = start;
   s->p_end = start + count;
   s->edgeflag_off = 0;
   s->repeat_first = 0;
}

static inline boolean
util_split_prim_next(struct util_split_prim *s, unsigned max_verts)
{
   int repeat = 0;

   if (s->repeat_first) {
      s->emit(s->priv, s->start, 1);
      max_verts--;
      if (s->edgeflag_off) {
         s->edge(s->priv, TRUE);
         s->edgeflag_off = FALSE;
      }
   }

   if ((s->p_end - s->p_start) + s->close_first <= max_verts) {
      s->emit(s->priv, s->p_start, s->p_end - s->p_start);
      if (s->close_first)
         s->emit(s->priv, s->start, 1);
      return TRUE;
   }

   switch (s->mode) {
   case PIPE_PRIM_LINES:
      max_verts &= ~1;
      break;
   case PIPE_PRIM_LINE_STRIP:
      repeat = 1;
      break;
   case PIPE_PRIM_POLYGON:
      max_verts--;
      s->emit(s->priv, s->p_start, max_verts);
      s->edge(s->priv, FALSE);
      s->emit(s->priv, s->p_start + max_verts, 1);
      s->p_start += max_verts;
      s->repeat_first = TRUE;
      s->edgeflag_off = TRUE;
      return FALSE;
   case PIPE_PRIM_TRIANGLES:
      max_verts = max_verts - (max_verts % 3);
      break;
   case PIPE_PRIM_TRIANGLE_STRIP:
      /* to ensure winding stays correct, always split
       * on an even number of generated triangles
       */
      max_verts = max_verts & ~1;
      repeat = 2;
      break;
   case PIPE_PRIM_TRIANGLE_FAN:
      s->repeat_first = TRUE;
      repeat = 1;
      break;
   case PIPE_PRIM_QUADS:
      max_verts &= ~3;
      break;
   case PIPE_PRIM_QUAD_STRIP:
      max_verts &= ~1;
      repeat = 2;
      break;
   case PIPE_PRIM_POINTS:
      break;
   default:
      /* TODO: implement adjacency primitives */
      assert(0);
   }

   s->emit (s->priv, s->p_start, max_verts);
   s->p_start += (max_verts - repeat);
   return FALSE;
}

#endif /* U_SPLIT_PRIM_H */