1 /*
2 * Cogl
3 *
4 * A Low Level GPU Graphics and Utilities API
5 *
6 * Copyright (C) 2007,2008,2009 Intel Corporation.
7 *
8 * Permission is hereby granted, free of charge, to any person
9 * obtaining a copy of this software and associated documentation
10 * files (the "Software"), to deal in the Software without
11 * restriction, including without limitation the rights to use, copy,
12 * modify, merge, publish, distribute, sublicense, and/or sell copies
13 * of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 *
28 *
29 */
30
31 #ifdef HAVE_CONFIG_H
32 #include "cogl-config.h"
33 #endif
34
35 #include "math.h"
36
37 #include "cogl-util.h"
38 #include "cogl-spans.h"
39
40 void
_cogl_span_iter_update(CoglSpanIter * iter)41 _cogl_span_iter_update (CoglSpanIter *iter)
42 {
43 /* Pick current span */
44 iter->span = &iter->spans[iter->index];
45
46 /* Offset next position by span size */
47 iter->next_pos = iter->pos + iter->span->size - iter->span->waste;
48
49 /* Check if span intersects the area to cover */
50 if (iter->next_pos <= iter->cover_start ||
51 iter->pos >= iter->cover_end)
52 {
53 /* Intersection undefined */
54 iter->intersects = FALSE;
55 return;
56 }
57
58 iter->intersects = TRUE;
59
60 /* Clip start position to coverage area */
61 if (iter->pos < iter->cover_start)
62 iter->intersect_start = iter->cover_start;
63 else
64 iter->intersect_start = iter->pos;
65
66 /* Clip end position to coverage area */
67 if (iter->next_pos > iter->cover_end)
68 iter->intersect_end = iter->cover_end;
69 else
70 iter->intersect_end = iter->next_pos;
71 }
72
73 void
_cogl_span_iter_begin(CoglSpanIter * iter,const CoglSpan * spans,int n_spans,float normalize_factor,float cover_start,float cover_end,CoglPipelineWrapMode wrap_mode)74 _cogl_span_iter_begin (CoglSpanIter *iter,
75 const CoglSpan *spans,
76 int n_spans,
77 float normalize_factor,
78 float cover_start,
79 float cover_end,
80 CoglPipelineWrapMode wrap_mode)
81 {
82 /* XXX: If CLAMP_TO_EDGE needs to be emulated then it needs to be
83 * done at a higher level than here... */
84 _COGL_RETURN_IF_FAIL (wrap_mode == COGL_PIPELINE_WRAP_MODE_REPEAT ||
85 wrap_mode == COGL_PIPELINE_WRAP_MODE_MIRRORED_REPEAT);
86
87 iter->span = NULL;
88
89 iter->spans = spans;
90 iter->n_spans = n_spans;
91
92 /* We always iterate in a positive direction from the origin. If
93 * iter->flipped == TRUE that means whoever is using this API should
94 * interpreted the current span as extending in the opposite direction. I.e.
95 * it extends to the left if iterating the X axis, or up if the Y axis. */
96 if (cover_start > cover_end)
97 {
98 float tmp = cover_start;
99 cover_start = cover_end;
100 cover_end = tmp;
101 iter->flipped = TRUE;
102 }
103 else
104 iter->flipped = FALSE;
105
106 /* The texture spans cover the normalized texture coordinate space ranging
107 * from [0,1] but to help support repeating of sliced textures we allow
108 * iteration of any range so we need to relate the start of the range to the
109 * nearest point equivalent to 0.
110 */
111 if (normalize_factor != 1.0)
112 {
113 float cover_start_normalized = cover_start / normalize_factor;
114 iter->origin = floorf (cover_start_normalized) * normalize_factor;
115 }
116 else
117 iter->origin = floorf (cover_start);
118
119 iter->wrap_mode = wrap_mode;
120
121 if (wrap_mode == COGL_PIPELINE_WRAP_MODE_REPEAT)
122 iter->index = 0;
123 else if (wrap_mode == COGL_PIPELINE_WRAP_MODE_MIRRORED_REPEAT)
124 {
125 if ((int)iter->origin % 2)
126 {
127 iter->index = iter->n_spans - 1;
128 iter->mirror_direction = -1;
129 iter->flipped = !iter->flipped;
130 }
131 else
132 {
133 iter->index = 0;
134 iter->mirror_direction = 1;
135 }
136 }
137 else
138 g_warn_if_reached ();
139
140 iter->cover_start = cover_start;
141 iter->cover_end = cover_end;
142 iter->pos = iter->origin;
143
144 /* Update intersection */
145 _cogl_span_iter_update (iter);
146
147 while (iter->next_pos <= iter->cover_start)
148 _cogl_span_iter_next (iter);
149 }
150
151 void
_cogl_span_iter_next(CoglSpanIter * iter)152 _cogl_span_iter_next (CoglSpanIter *iter)
153 {
154 /* Move current position */
155 iter->pos = iter->next_pos;
156
157 if (iter->wrap_mode == COGL_PIPELINE_WRAP_MODE_REPEAT)
158 iter->index = (iter->index + 1) % iter->n_spans;
159 else if (iter->wrap_mode == COGL_PIPELINE_WRAP_MODE_MIRRORED_REPEAT)
160 {
161 iter->index += iter->mirror_direction;
162 if (iter->index == iter->n_spans || iter->index == -1)
163 {
164 iter->mirror_direction = -iter->mirror_direction;
165 iter->index += iter->mirror_direction;
166 iter->flipped = !iter->flipped;
167 }
168 }
169 else
170 g_warn_if_reached ();
171
172 /* Update intersection */
173 _cogl_span_iter_update (iter);
174 }
175
176 CoglBool
_cogl_span_iter_end(CoglSpanIter * iter)177 _cogl_span_iter_end (CoglSpanIter *iter)
178 {
179 /* End reached when whole area covered */
180 return iter->pos >= iter->cover_end;
181 }
182
183
184