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