1 /*
2 Ming, an SWF output library
3 Copyright (C) 2002 Opaque Industries - http://www.opaque.net/
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /* $Id$ */
21
22 #include <stdlib.h>
23 #include <math.h>
24
25 #include "libming.h"
26 #include "matrix.h"
27 #include "gradient.h"
28
29 #include "libming.h"
30
31 struct gradientEntry
32 {
33 byte ratio;
34 byte r;
35 byte g;
36 byte b;
37 byte a;
38 };
39
40 struct SWFGradient_s
41 {
42 int spreadMode;
43 int interpolationMode;
44 struct gradientEntry entries[15];
45 int nGrads;
46 float focalPoint;
47 int isFocalGradient;
48 };
49
50
51 SWFGradient
newSWFGradient()52 newSWFGradient()
53 {
54 SWFGradient gradient = (SWFGradient) malloc(sizeof(struct SWFGradient_s));
55 gradient->spreadMode = 0;
56 gradient->interpolationMode = 0;
57 gradient->nGrads = 0;
58 gradient->isFocalGradient = 0;
59 return gradient;
60 }
61
62 /*
63 * set gradient spread mode
64 * SWF8 allows to set different spread modes:
65 * SWF_GRADIENT_PAD (default)
66 * SWF_GRADIENT_REFLECT
67 * SWF_GRADIENT_REPEAT
68 */
SWFGradient_setSpreadMode(SWFGradient gradient,GradientSpreadMode mode)69 void SWFGradient_setSpreadMode(SWFGradient gradient, GradientSpreadMode mode)
70 {
71 gradient->spreadMode = mode;
72 }
73
74 /*
75 * set gradient interpolation mode
76 * SWF8 allows to set different interpolation modes:
77 * SWF_GRADIENT_NORMAL (default)
78 * SWF_GRADIENT_LINEAR
79 */
SWFGradient_setInterpolationMode(SWFGradient gradient,GradientInterpolationMode mode)80 void SWFGradient_setInterpolationMode(SWFGradient gradient, GradientInterpolationMode mode)
81 {
82 gradient->interpolationMode = mode;
83 }
84
85 /*
86 * creates a radial gradient with focal point
87 * valid focalPoint value range is -1.0 ... 1.0
88 * where -1.0 means the focal point is close to the left border of
89 * the radial gradient circle; 0.0 is in the center and 1.0 is close
90 * to the right border.
91 */
SWFGradient_setFocalPoint(SWFGradient gradient,float focalPoint)92 void SWFGradient_setFocalPoint(SWFGradient gradient, float focalPoint)
93 {
94 gradient->isFocalGradient = 1;
95 if(focalPoint < -1.0) focalPoint = -1.0;
96 if(focalPoint > 1.0) focalPoint = 1.0;
97 gradient->focalPoint = focalPoint;
98 }
99
SWFGradient_isFocalGradient(SWFGradient gradient)100 int SWFGradient_isFocalGradient(SWFGradient gradient)
101 {
102 return gradient->isFocalGradient;
103 }
104
105 void
destroySWFGradient(SWFGradient gradient)106 destroySWFGradient(SWFGradient gradient)
107 {
108 free(gradient);
109 }
110
111 /*
112 * add a gradient control point
113 * The ratio defines the position of the control point
114 * and RGBA defines its color.
115 * SWF <= 7 allows up to 8 control points
116 * SWF >= 8 allows up to 15 control points
117 *
118 * The ration parameter is a float and must be in a range
119 * between [0.0 ... 1.0].
120 *
121 * In order to use SWF8 gradient features you need to set
122 * SWFShapes version to SWF_SHAPE4. Use SWFShape_useVersion()
123 * and friends.
124 */
125 void
SWFGradient_addEntry(SWFGradient gradient,float ratio,byte r,byte g,byte b,byte a)126 SWFGradient_addEntry(SWFGradient gradient,
127 float ratio, byte r, byte g, byte b, byte a)
128 {
129 int nGrads = gradient->nGrads;
130
131 if ( nGrads == 15 )
132 return;
133
134 gradient->entries[nGrads].ratio = (byte)floor(255*ratio);
135 gradient->entries[nGrads].r = r;
136 gradient->entries[nGrads].g = g;
137 gradient->entries[nGrads].b = b;
138 gradient->entries[nGrads].a = a;
139
140 ++gradient->nGrads;
141 }
142
143 void
SWFOutput_writeGradientAsFilter(SWFOutput out,SWFGradient gradient)144 SWFOutput_writeGradientAsFilter(SWFOutput out, SWFGradient gradient)
145 {
146 int i;
147 int nGrads = gradient->nGrads;
148
149 if(nGrads > 8)
150 {
151 SWF_warn("Can't write more than 8 control points for filter gradients\n");
152 nGrads = 8;
153 }
154
155 SWFOutput_writeUInt8(out, nGrads); /* only 1-8 allowed */
156
157 for ( i=0; i<nGrads; ++i )
158 {
159 SWFOutput_writeUInt8(out, gradient->entries[i].r);
160 SWFOutput_writeUInt8(out, gradient->entries[i].g);
161 SWFOutput_writeUInt8(out, gradient->entries[i].b);
162 SWFOutput_writeUInt8(out, gradient->entries[i].a);
163 }
164
165 for ( i=0; i<nGrads; ++i )
166 SWFOutput_writeUInt8(out, gradient->entries[i].ratio);
167
168 }
169
170 #define GRADIENT_SIZE 32768.0
171
172 void
SWFGradientMatrix_update(SWFMatrix matrix,SWFRect bounds)173 SWFGradientMatrix_update(SWFMatrix matrix, SWFRect bounds)
174 {
175 int w, h;
176 float scaleX, scaleY;
177 SWFMatrix tmp;
178 if(bounds == NULL)
179 return;
180
181 w = SWFRect_getWidth(bounds);
182 h = SWFRect_getHeight(bounds);
183 scaleX = w / GRADIENT_SIZE;
184 scaleY = h / GRADIENT_SIZE;
185
186 /* update matrix translation first, to be realtive to the gradient's
187 * coordinate system. */
188 SWFMatrix_moveTo(matrix, SWFMatrix_getTranslateX(matrix) / scaleX,
189 SWFMatrix_getTranslateY(matrix) / scaleY);
190
191 tmp = newSWFMatrix(scaleX, 0, 0, scaleY, bounds->minX + w/2, bounds->minY + h/2);
192 /* temporary matrix scales gradient to given bounds and centers it. */
193 /* all transformations done by the user are "applied" on the tmp matrix */
194 /* matrix = matrix * tmp -> "matrix is followed by tmp" */
195 SWFMatrix_multiply(matrix, tmp);
196 destroySWFMatrix(tmp);
197 }
198
199
200 void
SWFOutput_writeGradient(SWFOutput out,SWFGradient gradient,SWFBlocktype shapeType)201 SWFOutput_writeGradient(SWFOutput out, SWFGradient gradient, SWFBlocktype shapeType)
202 {
203 int i;
204 int nGrads = gradient->nGrads;
205
206 if(shapeType == SWF_DEFINESHAPE4)
207 {
208 byte flags ;
209 nGrads = min(nGrads, 15);
210 flags = nGrads;
211 flags |= (0x3 & gradient->interpolationMode) << 4;
212 flags |= (0x3 & gradient->spreadMode) << 6;
213 SWFOutput_writeUInt8(out, flags); /* only 1-15 allowed */
214 }
215 else
216 {
217 nGrads = min(nGrads, 8);
218 SWFOutput_writeUInt8(out, nGrads); /* only 1-8 allowed */
219 }
220
221 for ( i=0; i<nGrads; ++i )
222 {
223 SWFOutput_writeUInt8(out, gradient->entries[i].ratio);
224 SWFOutput_writeUInt8(out, gradient->entries[i].r);
225 SWFOutput_writeUInt8(out, gradient->entries[i].g);
226 SWFOutput_writeUInt8(out, gradient->entries[i].b);
227
228 if ( shapeType >= SWF_DEFINESHAPE3 )
229 SWFOutput_writeUInt8(out, gradient->entries[i].a);
230 }
231
232 if(shapeType == SWF_DEFINESHAPE4 && gradient->isFocalGradient)
233 SWFOutput_writeFixed8(out, gradient->focalPoint);
234 }
235
236
237 void
SWFOutput_writeMorphGradient(SWFOutput out,SWFGradient gradient1,SWFGradient gradient2)238 SWFOutput_writeMorphGradient(SWFOutput out,
239 SWFGradient gradient1, SWFGradient gradient2)
240 {
241 int i;
242 int nGrads = min(min(gradient1->nGrads, gradient2->nGrads), 8);
243
244 SWFOutput_writeUInt8(out, nGrads); /* only 1-8 allowed */
245
246 for ( i=0; i<nGrads; ++i )
247 {
248 SWFOutput_writeUInt8(out, gradient1->entries[i].ratio);
249 SWFOutput_writeUInt8(out, gradient1->entries[i].r);
250 SWFOutput_writeUInt8(out, gradient1->entries[i].g);
251 SWFOutput_writeUInt8(out, gradient1->entries[i].b);
252 SWFOutput_writeUInt8(out, gradient1->entries[i].a);
253 SWFOutput_writeUInt8(out, gradient2->entries[i].ratio);
254 SWFOutput_writeUInt8(out, gradient2->entries[i].r);
255 SWFOutput_writeUInt8(out, gradient2->entries[i].g);
256 SWFOutput_writeUInt8(out, gradient2->entries[i].b);
257 SWFOutput_writeUInt8(out, gradient2->entries[i].a);
258 }
259 }
260
261
262 /*
263 * Local variables:
264 * tab-width: 2
265 * c-basic-offset: 2
266 * End:
267 */
268