105 if ((x and $FFFFF800) = 0) and ((y and $FFFFFC00) = 0) then |
105 if ((x and $FFFFF800) = 0) and ((y and $FFFFFC00) = 0) then |
106 Land[y, x]:= Color; |
106 Land[y, x]:= Color; |
107 end |
107 end |
108 end; |
108 end; |
109 |
109 |
110 procedure DrawBezierEdge(var pa: TPixAr; Color: Longword); |
110 procedure DrawEdge(var pa: TPixAr; Color: Longword); |
111 const dT: hwFloat = (isNegative: false; QWordValue: 85899346); |
111 var i: integer; |
112 var x, y, i, px, py: integer; |
112 begin |
113 tx, ty, vx, vy, vlen, t: hwFloat; |
113 i:= 0; |
114 r1, r2, r3, r4: hwFloat; |
|
115 x1, y1, x2, y2, cx1, cy1, cx2, cy2, tsq, tcb: hwFloat; |
|
116 begin |
|
117 vx:= 0; |
|
118 vy:= 0; |
|
119 with pa do |
114 with pa do |
120 for i:= 0 to Count-2 do |
115 while i < integer(Count) - 1 do |
121 begin |
116 if (ar[i + 1].X = NTPX) then inc(i, 2) |
122 vlen:= Distance(ar[i + 1].x - ar[i].X, ar[i + 1].y - ar[i].y); |
117 else begin |
123 t:= Distance(ar[i + 1].x - ar[i + 2].X,ar[i + 1].y - ar[i + 2].y); |
118 DrawLine(ar[i].x, ar[i].y, ar[i + 1].x, ar[i + 1].y, Color); |
124 if t<vlen then vlen:= t; |
119 inc(i) |
125 vlen:= vlen * _1div3; |
120 end |
126 tx:= ar[i+2].X - ar[i].X; |
121 end; |
127 ty:= ar[i+2].y - ar[i].y; |
122 |
128 t:= Distance(tx, ty); |
123 procedure Vector(p1, p2, p3: TPoint; var Vx, Vy: hwFloat); |
129 if t.QWordValue = 0 then |
124 var d1, d2, d: hwFloat; |
130 begin |
125 begin |
131 tx:= -tx * 10000; |
126 Vx:= p1.X - p3.X; |
132 ty:= -ty * 10000; |
127 Vy:= p1.Y - p3.Y; |
133 end else |
128 d:= Distance(p2.X - p1.X, p2.Y - p1.Y); |
134 begin |
129 d1:= Distance(p2.X - p3.X, p2.Y - p3.Y); |
135 t:= 1/t; |
130 d2:= Distance(Vx, Vy); |
136 tx:= -tx * t; |
131 if d1 < d then d:= d1; |
137 ty:= -ty * t; |
132 if d2 < d then d:= d2; |
138 end; |
133 d:= d * _1div3; |
139 t:= vlen; |
134 if d2.QWordValue = 0 then |
140 tx:= tx * t; |
135 begin |
141 ty:= ty * t; |
136 Vx:= 0; |
142 x1:= ar[i].x; |
137 Vy:= 0 |
143 y1:= ar[i].y; |
138 end else |
144 x2:= ar[i + 1].x; |
139 begin |
145 y2:= ar[i + 1].y; |
140 d2:= 1 / d2; |
146 cx1:= ar[i].X + hwRound(vx); |
141 Vx:= Vx * d2; |
147 cy1:= ar[i].y + hwRound(vy); |
142 Vy:= Vy * d2; |
148 cx2:= ar[i+1].X + hwRound(tx); |
143 |
149 cy2:= ar[i+1].y + hwRound(ty); |
144 Vx:= Vx * d; |
150 vx:= -tx; |
145 Vy:= Vy * d |
151 vy:= -ty; |
146 end |
152 px:= hwRound(x1); |
147 end; |
153 py:= hwRound(y1); |
148 |
154 t:= dT; |
149 procedure AddLoopPoints(var pa, opa: TPixAr; StartI, EndI: integer; Delta: hwFloat); |
155 while t.Round = 0 do |
150 var i, pi, ni: integer; |
156 begin |
151 NVx, NVy, PVx, PVy: hwFloat; |
157 tsq:= t * t; |
152 x1, x2, y1, y2, cx1, cx2, cy1, cy2: hwFloat; |
158 tcb:= tsq * t; |
153 tsq, tcb, t, r1, r2, r3, r4: hwFloat; |
159 r1:= (1 - 3*t + 3*tsq - tcb) * x1; |
154 X, Y: integer; |
160 r2:= ( 3*t - 6*tsq + 3*tcb) * cx1; |
155 begin |
161 r3:= ( 3*tsq - 3*tcb) * cx2; |
156 pi:= EndI; |
162 r4:= ( tcb) * x2; |
157 i:= StartI; |
163 X:= hwRound(r1 + r2 + r3 + r4); |
158 ni:= Succ(StartI); |
164 r1:= (1 - 3*t + 3*tsq - tcb) * y1; |
159 Vector(opa.ar[pi], opa.ar[i], opa.ar[ni], NVx, NVy); |
165 r2:= ( 3*t - 6*tsq + 3*tcb) * cy1; |
160 repeat |
166 r3:= ( 3*tsq - 3*tcb) * cy2; |
161 inc(pi); |
167 r4:= ( tcb) * y2; |
162 if pi > EndI then pi:= StartI; |
168 Y:= hwRound(r1 + r2 + r3 + r4); |
163 inc(i); |
169 t:= t + dT; |
164 if i > EndI then i:= StartI; |
170 DrawLine(px, py, x, y, Color); |
165 inc(ni); |
171 px:= x; |
166 if ni > EndI then ni:= StartI; |
172 py:= y |
167 PVx:= NVx; |
173 end; |
168 PVy:= NVy; |
174 DrawLine(px, py, hwRound(x2), hwRound(y2), Color) |
169 Vector(opa.ar[pi], opa.ar[i], opa.ar[ni], NVx, NVy); |
175 end; |
170 |
176 end; |
171 x1:= opa.ar[pi].x; |
177 |
172 y1:= opa.ar[pi].y; |
178 procedure BezierizeEdge(var pa: TPixAr; Delta: hwFloat); |
173 x2:= opa.ar[i].x; |
179 var x, y, i: integer; |
174 y2:= opa.ar[i].y; |
180 tx, ty, vx, vy, vlen, t: hwFloat; |
175 cx1:= x1 - PVx; |
181 r1, r2, r3, r4: hwFloat; |
176 cy1:= y1 - PVy; |
182 x1, y1, x2, y2, cx1, cy1, cx2, cy2, tsq, tcb: hwFloat; |
177 cx2:= x2 + NVx; |
183 opa: TPixAr; |
178 cy2:= y2 + NVy; |
184 begin |
|
185 opa:= pa; |
|
186 pa.Count:= 0; |
|
187 vx:= 0; |
|
188 vy:= 0; |
|
189 with opa do |
|
190 for i:= 0 to Count-2 do |
|
191 begin |
|
192 vlen:= Distance(ar[i + 1].x - ar[i].X, ar[i + 1].y - ar[i].y); |
|
193 t:= Distance(ar[i + 1].x - ar[i + 2].X,ar[i + 1].y - ar[i + 2].y); |
|
194 if t<vlen then vlen:= t; |
|
195 vlen:= vlen * _1div3; |
|
196 tx:= ar[i+2].X - ar[i].X; |
|
197 ty:= ar[i+2].y - ar[i].y; |
|
198 t:= Distance(tx, ty); |
|
199 if t.QWordValue = 0 then |
|
200 begin |
|
201 tx:= -tx * 100000; |
|
202 ty:= -ty * 100000; |
|
203 end else |
|
204 begin |
|
205 t:= 1/t; |
|
206 tx:= -tx * t; |
|
207 ty:= -ty * t; |
|
208 end; |
|
209 t:= vlen; |
|
210 tx:= tx*t; |
|
211 ty:= ty*t; |
|
212 x1:= ar[i].x; |
|
213 y1:= ar[i].y; |
|
214 x2:= ar[i + 1].x; |
|
215 y2:= ar[i + 1].y; |
|
216 cx1:= ar[i].X + hwRound(vx); |
|
217 cy1:= ar[i].y + hwRound(vy); |
|
218 cx2:= ar[i+1].X + hwRound(tx); |
|
219 cy2:= ar[i+1].y + hwRound(ty); |
|
220 vx:= -tx; |
|
221 vy:= -ty; |
|
222 t:= 0; |
179 t:= 0; |
223 while t.Round = 0 do |
180 while t.Round = 0 do |
224 begin |
181 begin |
225 tsq:= t * t; |
182 tsq:= t * t; |
226 tcb:= tsq * t; |
183 tcb:= tsq * t; |
238 pa.ar[pa.Count].x:= X; |
195 pa.ar[pa.Count].x:= X; |
239 pa.ar[pa.Count].y:= Y; |
196 pa.ar[pa.Count].y:= Y; |
240 inc(pa.Count); |
197 inc(pa.Count); |
241 TryDo(pa.Count <= cMaxEdgePoints, 'Edge points overflow', true) |
198 TryDo(pa.Count <= cMaxEdgePoints, 'Edge points overflow', true) |
242 end; |
199 end; |
243 end; |
200 until i = StartI; |
244 pa.ar[pa.Count].x:= opa.ar[Pred(opa.Count)].X; |
201 pa.ar[pa.Count].x:= opa.ar[StartI].X; |
245 pa.ar[pa.Count].y:= opa.ar[Pred(opa.Count)].Y; |
202 pa.ar[pa.Count].y:= opa.ar[StartI].Y; |
246 inc(pa.Count) |
203 inc(pa.Count) |
|
204 end; |
|
205 |
|
206 procedure BezierizeEdge(var pa: TPixAr; Delta: hwFloat); |
|
207 var x, y, i, StartLoop: integer; |
|
208 opa: TPixAr; |
|
209 begin |
|
210 opa:= pa; |
|
211 pa.Count:= 0; |
|
212 i:= 0; |
|
213 StartLoop:= 0; |
|
214 while i < integer(opa.Count) do |
|
215 if (opa.ar[i + 1].X = NTPX) then |
|
216 begin |
|
217 AddLoopPoints(pa, opa, StartLoop, i, Delta); |
|
218 inc(i, 2); |
|
219 StartLoop:= i; |
|
220 pa.ar[pa.Count].X:= NTPX; |
|
221 inc(pa.Count); |
|
222 end else inc(i) |
247 end; |
223 end; |
248 |
224 |
249 procedure FillLand(x, y: integer); |
225 procedure FillLand(x, y: integer); |
250 var Stack: record |
226 var Stack: record |
251 Count: Longword; |
227 Count: Longword; |
407 for i:= 0 to pred(FillPointsCount) do |
384 for i:= 0 to pred(FillPointsCount) do |
408 FillPoints^[i].y:= 1023 - FillPoints^[i].y; |
385 FillPoints^[i].y:= 1023 - FillPoints^[i].y; |
409 end; |
386 end; |
410 end |
387 end |
411 end; |
388 end; |
412 (* |
389 |
413 procedure NormalizePoints(var pa: TPixAr); |
390 procedure RandomizePoints(var pa: TPixAr; MaxRad: integer); |
414 const brd = 32; |
|
415 var isUP: boolean; // HACK: transform for Y should be exact as one for X |
|
416 Left, Right, Top, Bottom, |
|
417 OWidth, Width, OHeight, Height, |
|
418 OLeft: integer; |
|
419 i: integer; |
|
420 begin |
|
421 TryDo((pa.ar[0].y < 0) or (pa.ar[0].y > 1023), 'Bad land generated', true); |
|
422 TryDo((pa.ar[Pred(pa.Count)].y < 0) or (pa.ar[Pred(pa.Count)].y > 1023), 'Bad land generated', true); |
|
423 isUP:= pa.ar[0].y > 0; |
|
424 Left:= 1023; |
|
425 Right:= Left; |
|
426 Top:= pa.ar[0].y; |
|
427 Bottom:= Top; |
|
428 |
|
429 for i:= 1 to Pred(pa.Count) do |
|
430 with pa.ar[i] do |
|
431 begin |
|
432 if (y and $FFFFFC00) = 0 then |
|
433 if x < Left then Left:= x else |
|
434 if x > Right then Right:= x; |
|
435 if y < Top then Top:= y else |
|
436 if y > Bottom then Bottom:= y |
|
437 end; |
|
438 |
|
439 if (Left < brd) or (Right > 2047 - brd) then |
|
440 begin |
|
441 OLeft:= Left; |
|
442 OWidth:= Right - OLeft; |
|
443 if Left < brd then Left:= brd; |
|
444 if Right > 2047 - brd then Right:= 2047 - brd; |
|
445 Width:= Right - Left; |
|
446 for i:= 0 to Pred(pa.Count) do |
|
447 with pa.ar[i] do |
|
448 x:= round((x - OLeft) * Width div OWidth + Left) |
|
449 end; |
|
450 |
|
451 if isUp then // FIXME: remove hack |
|
452 if Top < brd then |
|
453 begin |
|
454 OHeight:= 1023 - Top; |
|
455 Height:= 1023 - brd; |
|
456 for i:= 0 to Pred(pa.Count) do |
|
457 with pa.ar[i] do |
|
458 y:= round((y - 1023) * Height div OHeight + 1023) |
|
459 end; |
|
460 end;*) |
|
461 |
|
462 procedure RandomizePoints(var pa: TPixAr); |
|
463 const cEdge = 55; |
391 const cEdge = 55; |
464 cMinDist = 14; |
392 cMinDist = 0; |
465 var radz: array[0..Pred(cMaxEdgePoints)] of integer; |
393 var radz: array[0..Pred(cMaxEdgePoints)] of integer; |
466 i, k, dist: integer; |
394 i, k, dist: integer; |
467 begin |
395 begin |
468 radz[0]:= 0; |
396 radz[0]:= 0; |
469 for i:= 0 to Pred(pa.Count) do |
397 for i:= 0 to Pred(pa.Count) do |
470 with pa.ar[i] do |
398 with pa.ar[i] do |
471 begin |
399 if x <> NTPX then |
472 radz[i]:= Min(Max(x - cEdge, 0), Max(2048 - cEdge - x, 0)); |
400 begin |
473 radz[i]:= Min(radz[i], Min(Max(y - cEdge, 0), Max(1024 - cEdge - y, 0))); |
401 radz[i]:= Min(Max(x - cEdge, 0), Max(2048 - cEdge - x, 0)); |
474 if radz[i] > 0 then |
402 radz[i]:= Min(radz[i], Min(Max(y - cEdge, 0), Max(1024 - cEdge - y, 0))); |
475 for k:= 0 to Pred(i) do |
403 if radz[i] > 0 then |
476 begin |
404 for k:= 0 to Pred(i) do |
477 dist:= Min(Max(abs(x - pa.ar[k].x), abs(y - pa.ar[k].y)), 50); |
|
478 if radz[k] >= dist then |
|
479 begin |
405 begin |
480 radz[k]:= Max(0, dist - cMinDist * 2); |
406 dist:= Min(Max(abs(x - pa.ar[k].x), abs(y - pa.ar[k].y)), MaxRad); |
481 radz[i]:= Min(dist - radz[k], radz[i]) |
407 radz[k]:= Max(0, Min((dist - cMinDist) div 2, radz[k])); |
482 end; |
408 radz[i]:= Max(0, Min(dist - radz[k] - cMinDist, radz[i])) |
483 radz[i]:= Min(radz[i], dist) |
409 end |
484 end |
410 end; |
485 end; |
|
486 |
411 |
487 for i:= 0 to Pred(pa.Count) do |
412 for i:= 0 to Pred(pa.Count) do |
488 with pa.ar[i] do |
413 with pa.ar[i] do |
489 if ((x and $FFFFF800) = 0) and ((y and $FFFFFC00) = 0) then |
414 if ((x and $FFFFF800) = 0) and ((y and $FFFFFC00) = 0) then |
490 begin |
415 begin |
491 x:= x + integer(GetRandom(radz[i] * 2 + 1)) - radz[i]; |
416 x:= x + integer(GetRandom(7) - 3) * (radz[i] * 5 div 7) div 3; |
492 y:= y + integer(GetRandom(radz[i] * 2 + 1)) - radz[i] |
417 y:= y + integer(GetRandom(7) - 3) * (radz[i] * 5 div 7) div 3 |
493 end |
418 end |
494 end; |
419 end; |
495 |
420 |
496 |
421 |
497 procedure GenBlank(var Template: TEdgeTemplate); |
422 procedure GenBlank(var Template: TEdgeTemplate); |
503 for x:= 0 to 2047 do |
428 for x:= 0 to 2047 do |
504 Land[y, x]:= COLOR_LAND; |
429 Land[y, x]:= COLOR_LAND; |
505 |
430 |
506 SetPoints(Template, pa); |
431 SetPoints(Template, pa); |
507 BezierizeEdge(pa, _1div3); |
432 BezierizeEdge(pa, _1div3); |
508 for i:= 0 to Pred(Template.RandPassesCount) do RandomizePoints(pa); |
433 for i:= 0 to Pred(Template.RandPassesCount) do RandomizePoints(pa, 1000); |
509 //NormalizePoints(pa); |
434 BezierizeEdge(pa, _1div3); |
510 |
435 RandomizePoints(pa, 1000); |
511 DrawBezierEdge(pa, 0); |
436 BezierizeEdge(pa, _0_1); |
|
437 |
|
438 DrawEdge(pa, 0); |
512 |
439 |
513 with Template do |
440 with Template do |
514 for i:= 0 to pred(FillPointsCount) do |
441 for i:= 0 to pred(FillPointsCount) do |
515 with FillPoints^[i] do |
442 with FillPoints^[i] do |
516 FillLand(x, y); |
443 FillLand(x, y); |
517 |
444 |
518 DrawBezierEdge(pa, COLOR_LAND) |
445 DrawEdge(pa, COLOR_LAND) |
519 end; |
446 end; |
520 |
447 |
521 function SelectTemplate: integer; |
448 function SelectTemplate: integer; |
522 begin |
449 begin |
523 SelectTemplate:= getrandom(Succ(High(EdgeTemplates))) |
450 SelectTemplate:= getrandom(Succ(High(EdgeTemplates))) |