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