hedgewars/uLand.pas
changeset 365 a26cec847dd7
parent 364 52cb4d6f84b7
child 367 bc3c3edc5ce1
equal deleted inserted replaced
364:52cb4d6f84b7 365:a26cec847dd7
    50 s:= '{'+inttostr(dig[0])+':'
    50 s:= '{'+inttostr(dig[0])+':'
    51        +inttostr(dig[1])+':'
    51        +inttostr(dig[1])+':'
    52        +inttostr(dig[2])+':'
    52        +inttostr(dig[2])+':'
    53        +inttostr(dig[3])+':'
    53        +inttostr(dig[3])+':'
    54        +inttostr(dig[4])+'}';
    54        +inttostr(dig[4])+'}';
    55 SendIPC('M' + s)
    55 //SendIPC('M' + s)
    56 end;
    56 end;
    57 
    57 
    58 procedure DrawLine(X1, Y1, X2, Y2: integer; Color: Longword);
    58 procedure DrawLine(X1, Y1, X2, Y2: integer; Color: Longword);
    59 var
    59 var
    60   eX, eY, dX, dY: integer;
    60   eX, eY, dX, dY: integer;
   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;
   392          
   368          
   393      if canMirror then
   369      if canMirror then
   394         if getrandom(2) = 0 then
   370         if getrandom(2) = 0 then
   395            begin
   371            begin
   396            for i:= 0 to pred(BasePointsCount) do
   372            for i:= 0 to pred(BasePointsCount) do
       
   373              if pa.ar[i].x <> NTPX then
   397                pa.ar[i].x:= 2047 - pa.ar[i].x;
   374                pa.ar[i].x:= 2047 - pa.ar[i].x;
   398            for i:= 0 to pred(FillPointsCount) do
   375            for i:= 0 to pred(FillPointsCount) do
   399                FillPoints^[i].x:= 2047 - FillPoints^[i].x;
   376                FillPoints^[i].x:= 2047 - FillPoints^[i].x;
   400            end;
   377            end;
   401 
   378 
   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)))