I'm looking to render a line with a gradient from one colour to the other. I'm looking to use vanilla Allegro. I assume the best way would be to use do_line and calculate the colour value each iteration but I'm not so sure from there.
Anyone have any nice solutions?
Bresenhams's line drawing algorithm where you paint each pixel yourself in the gradient colors.
I've done it before using do_line, then stepping through the supplied coords and painting them accordingly. That's about as "Allegro friendly" as you can get.
Makes for some very nice effects.
This is how I did it. Looks fine.
1 | Notes: Color is a typedef of int |
2 | : GradientType indicates a horizontal or vertical gradient |
3 | void fillGradient( BITMAP * bmp, int x1, int y1, int x2, int y2, Color startColor, Color endColor, GradientType direction) |
4 | { |
5 | int numOfRedDivisions = getr( startColor ) - getr( endColor ); |
6 | int numOfGreenDivisions = getg( startColor ) - getg( endColor ); |
7 | int numOfBlueDivisions = getb( startColor ) - getb( endColor ); |
8 | |
9 | int divisions = 0; |
10 | switch( direction ) |
11 | { |
12 | case HORIZONTAL_GRADIENT: divisions = x2-x1 ; break; |
13 | case VERTICAL_GRADIENT: divisions = y2-y1 ; break; |
14 | } |
15 | |
16 | for(int i = 0; i < divisions; i++ ) |
17 | { |
18 | int r = getr( startColor ) - (int)floor( i * numOfRedDivisions / divisions ); |
19 | int g = getg( startColor ) - (int)floor( i * numOfGreenDivisions / divisions ); |
20 | int b = getb( startColor ) - (int)floor( i * numOfBlueDivisions / divisions ); |
21 | |
22 | |
23 | switch( direction ) |
24 | { |
25 | case HORIZONTAL_GRADIENT: drawLine( bmp, x1+i, y1, x1+i, y2, makecol(r, g, b) ); break; |
26 | case VERTICAL_GRADIENT: drawLine( bmp, x1, y1+i, x2, y1+i, makecol(r, g, b) ); break; |
27 | } |
28 | } |
29 | } |
30 | |
31 | void drawLine( BITMAP * bmp, int x1, int y1, int x2, int y2, Color color) |
32 | { |
33 | if( x1 == x2 ) |
34 | vline( bmp, x1, y1, y2, color ); |
35 | else |
36 | line( bmp, x1, y1, x2, y2, color ); |
37 | } |
http://edu.loviisa.fi/~jhalmen/projects/mapgen/spectrline.gif
A line drawn using a class of mine
Basicly it's just my own version of do_line(), without a callback. You initiate an object with a start coordinate and an end coordinate or a start coordinate and a direction. Then you call a step function, which updates members x and y, which you can read.
I'm still waiting for the OpenLayer plug
Greetings,
Heres a definable gradient class I did in Delphi a couple of years ago (you shouldnt have any problem understanding it since its not too different from C++). It lets you add points at a given position and define the colours.
------------------------------------------------------
1 | unit ColGrad; |
2 | |
3 | interface |
4 | |
5 | Uses Graphics; |
6 | |
7 | Type |
8 | TColArray = Record |
9 | Bytes : Array [0..3] Of Byte; |
10 | End; |
11 | |
12 | TGradientPoint = Class (TObject) |
13 | Protected |
14 | IColour : TColor; |
15 | IPosition : Single; |
16 | INext : TGradientPoint; |
17 | |
18 | Procedure ISetPosition (Pos : Single); |
19 | |
20 | Public |
21 | Constructor Create; Overload; Virtual; |
22 | Constructor Create (Col : TColor; Pos : Single); Overload; Virtual; |
23 | Destructor Destroy; Override; |
24 | |
25 | Property Colour : TColor Read IColour Write IColour; |
26 | Property Position : Single Read IPosition Write ISetPosition; |
27 | Property Next : TGradientPoint Read INext Write INext; |
28 | |
29 | End; |
30 | |
31 | TGradientPoints = Class (TObject) |
32 | Protected |
33 | IPoints : TGradientPoint; |
34 | ICount : LongInt; |
35 | |
36 | Function IGetPoint (PointIndex : LongInt) : TGradientPoint; |
37 | |
38 | Public |
39 | Constructor Create; Virtual; |
40 | Destructor Destroy; Override; |
41 | |
42 | Property Count : LongInt Read ICount; |
43 | Property Points [PointIndex : LongInt] : TGradientPoint Read IGetPoint; Default; |
44 | |
45 | Procedure Add (NewPoint : TGradientPoint); Virtual; |
46 | Procedure Delete (Point : TGradientPoint); Virtual; |
47 | Procedure Clear; Virtual; |
48 | |
49 | End; |
50 | |
51 | TColourGradient = Class (TObject) |
52 | Protected |
53 | IHighColour, ILowColour : TColor; |
54 | IPoints : TGradientPoints; |
55 | |
56 | Public |
57 | Constructor Create; Overload; Virtual; |
58 | Constructor Create (HiCol, LoCol : TColor); Overload; Virtual; |
59 | Destructor Destroy; Override; |
60 | |
61 | Property HighColour : TColor Read IHighColour Write IHighColour; |
62 | Property LowColour : TColor Read ILowColour Write ILowColour; |
63 | Property Points : TGradientPoints Read IPoints; |
64 | |
65 | Function ColourAtPosition (Pos : Single) : TColor; Virtual; |
66 | Procedure Copy (ToGrad : TColourGradient); Virtual; |
67 | |
68 | End; |
69 | |
70 | implementation |
71 | |
72 | Procedure TGradientPoint.ISetPosition (Pos : Single); |
73 | Begin |
74 | If Pos < 0 Then |
75 | IPosition := 0 |
76 | Else |
77 | If Pos > 1 Then |
78 | IPosition := 1 |
79 | Else |
80 | IPosition := Pos; |
81 | End; |
82 | |
83 | Constructor TGradientPoint.Create; |
84 | Begin |
85 | Inherited Create; |
86 | IColour := clGray; |
87 | IPosition := 0.5; |
88 | INext := NIL; |
89 | End; |
90 | |
91 | Constructor TGradientPoint.Create (Col : TColor; Pos : Single); |
92 | Begin |
93 | Inherited Create; |
94 | IColour := Col; |
95 | IPosition := Pos; |
96 | INext := NIL; |
97 | End; |
98 | |
99 | Destructor TGradientPoint.Destroy; |
100 | Begin |
101 | Inherited; |
102 | End; |
103 | |
104 | Function TGradientPoints.IGetPoint (PointIndex : LongInt) : TGradientPoint; |
105 | Var |
106 | Count : LongInt; |
107 | Current : TGradientPoint; |
108 | Begin |
109 | If PointIndex >= ICount Then |
110 | Result := NIL |
111 | Else |
112 | Begin |
113 | Current := IPoints; |
114 | For Count := 1 To PointIndex Do |
115 | Current := Current.Next; |
116 | Result := Current; |
117 | End; |
118 | End; |
119 | |
120 | Constructor TGradientPoints.Create; |
121 | Begin |
122 | Inherited Create; |
123 | IPoints := NIL; |
124 | ICount := 0; |
125 | End; |
126 | |
127 | Destructor TGradientPoints.Destroy; |
128 | Begin |
129 | Self.Clear; |
130 | Inherited; |
131 | End; |
132 | |
133 | Procedure TGradientPoints.Add (NewPoint : TGradientPoint); |
134 | Var |
135 | Current : TGradientPoint; |
136 | Begin |
137 | If IPoints = NIL Then |
138 | IPoints := NewPoint |
139 | Else |
140 | Begin |
141 | Current := IPoints; |
142 | While Current.Next <> NIL Do |
143 | Current := Current.Next; |
144 | Current.Next := NewPoint; |
145 | End; |
146 | ICount := ICount + 1; |
147 | End; |
148 | |
149 | Procedure TGradientPoints.Delete (Point : TGradientPoint); |
150 | Var |
151 | Current, Previous : TGradientPoint; |
152 | Found : Boolean; |
153 | Begin |
154 | If IPoints = Point Then |
155 | Begin |
156 | Previous := IPoints; |
157 | IPoints := IPoints.Next; |
158 | Previous.Free; |
159 | ICount := ICount - 1; |
160 | End |
161 | Else |
162 | Begin |
163 | Current := IPoints; |
164 | Found := False; |
165 | While (Current.Next <> NIL) And (Not (Found)) Do |
166 | Begin |
167 | If Current.Next = Point Then |
168 | Begin |
169 | Previous := Current.Next; |
170 | Current.Next := Current.Next.Next; |
171 | Previous.Free; |
172 | Found := True; |
173 | ICount := ICount - 1; |
174 | End |
175 | Else |
176 | Current := Current.Next; |
177 | End; |
178 | End; |
179 | End; |
180 | |
181 | Procedure TGradientPoints.Clear; |
182 | Var |
183 | Current, Previous : TGradientPoint; |
184 | Begin |
185 | Current := IPoints; |
186 | While Current <> NIL Do |
187 | Begin |
188 | Previous := Current; |
189 | Current := Current.Next; |
190 | Previous.Free; |
191 | End; |
192 | ICount := 0; |
193 | IPoints := NIL; |
194 | End; |
195 | |
196 | Constructor TColourGradient.Create; |
197 | Begin |
198 | Inherited Create; |
199 | ILowColour := clGray; |
200 | IHighColour := clGray; |
201 | IPoints := TGradientPoints.Create; |
202 | End; |
203 | |
204 | Constructor TColourGradient.Create (HiCol, LoCol : TColor); |
205 | Begin |
206 | Inherited Create; |
207 | IHighColour := HiCol; |
208 | ILowColour := LoCol; |
209 | IPoints := TGradientPoints.Create; |
210 | End; |
211 | |
212 | Destructor TColourGradient.Destroy; |
213 | Begin |
214 | IPoints.Free; |
215 | Inherited; |
216 | End; |
217 | |
218 | Function TColourGradient.ColourAtPosition (Pos : Single) : TColor; |
219 | Var |
220 | CurrentPoint : TGradientPoint; |
221 | HiPoint, LoPoint, MidPoint : Single; |
222 | HiCol, LoCol, ResCol : TColArray; |
223 | BytePos : Byte; |
224 | Begin |
225 | If Pos < 0 Then |
226 | Result := IHighColour |
227 | Else |
228 | If Pos > 1 Then |
229 | Result := ILowColour |
230 | Else |
231 | Begin |
232 | HiPoint := 0; |
233 | LoPoint := 1; |
234 | Move (IHighColour, HiCol, 4); |
235 | Move (ILowColour, LoCol, 4); |
236 | |
237 | CurrentPoint := IPoints [0]; |
238 | While CurrentPoint <> NIL Do |
239 | Begin |
240 | If (CurrentPoint.Position <= Pos) And |
241 | (CurrentPoint.Position >= HiPoint) Then |
242 | Begin |
243 | HiPoint := CurrentPoint.Position; |
244 | Move (CurrentPoint.Colour, HiCol, 4); |
245 | End; |
246 | CurrentPoint := CurrentPoint.Next; |
247 | End; |
248 | |
249 | CurrentPoint := IPoints [0]; |
250 | While CurrentPoint <> NIL Do |
251 | Begin |
252 | If (CurrentPoint.Position >= Pos) And |
253 | (CurrentPoint.Position <= LoPoint) Then |
254 | Begin |
255 | LoPoint := CurrentPoint.Position; |
256 | Move (CurrentPoint.Colour, LoCol, 4); |
257 | End; |
258 | CurrentPoint := CurrentPoint.Next; |
259 | End; |
260 | |
261 | If HiPoint = LoPoint Then |
262 | ResCol := LoCol |
263 | Else |
264 | Begin |
265 | MidPoint := (Pos - HiPoint) / (LoPoint - HiPoint); |
266 | For BytePos := 0 To 3 Do |
267 | Begin |
268 | HiPoint := HiCol.Bytes [BytePos]; |
269 | LoPoint := LoCol.Bytes [BytePos]; |
270 | ResCol.Bytes [BytePos] := Round (HiPoint + ((LoPoint - HiPoint) * MidPoint)); |
271 | End; |
272 | End; |
273 | |
274 | Move (ResCol, Result, 4); |
275 | End; |
276 | End; |
277 | |
278 | Procedure TColourGradient.Copy (ToGrad : TColourGradient); |
279 | Var |
280 | Current : TGradientPoint; |
281 | Begin |
282 | ToGrad.LowColour := ILowColour; |
283 | ToGrad.HighColour := IHighColour; |
284 | ToGrad.Points.Clear; |
285 | Current := IPoints [0]; |
286 | While Current <> NIL Do |
287 | Begin |
288 | ToGrad.Points.Add (TGradientPoint.Create (Current.Colour, Current.Position)); |
289 | Current := Current.Next; |
290 | End; |
291 | End; |
292 | |
293 | end. |
And Here it is in action :-
{"name":"recol2.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/9\/098e1eb81a1df741ab60947b023d8cbc.jpg","w":628,"h":489,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/9\/098e1eb81a1df741ab60947b023d8cbc"}