# HG changeset patch # User unC0Rr # Date 1726661451 -7200 # Node ID 7b8d96fc87995a21fe367ff31adf54347cb0717c # Parent 0caa3dfb3ba2c577f398747ab280674b360ac648 Remove old code diff -r 0caa3dfb3ba2 -r 7b8d96fc8799 hedgewars/CMakeLists.txt --- a/hedgewars/CMakeLists.txt Wed Sep 18 13:42:26 2024 +0200 +++ b/hedgewars/CMakeLists.txt Wed Sep 18 14:10:51 2024 +0200 @@ -78,12 +78,9 @@ adler32.pas uLandTemplates.pas uLandTexture.pas + uLandGenPerlin.pas uLandGraphics.pas uLandPainted.pas - uLandOutline.pas - uLandGenMaze.pas - uLandGenPerlin.pas - uLandGenTemplateBased.pas uLandUtils.pas #this is where dependency tracking becomes hard diff -r 0caa3dfb3ba2 -r 7b8d96fc8799 hedgewars/uLandGenMaze.pas --- a/hedgewars/uLandGenMaze.pas Wed Sep 18 13:42:26 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,547 +0,0 @@ -{$INCLUDE "options.inc"} - -unit uLandGenMaze; - -interface - -procedure GenMaze; - -implementation - -uses uRandom, uLandOutline, uLandTemplates, uVariables, uFloat, uConsts, - uLandGenTemplateBased, uUtils, uLandUtils; - -type direction = record x, y: LongInt; end; -const DIR_N: direction = (x: 0; y: -1); - DIR_E: direction = (x: 1; y: 0); - DIR_S: direction = (x: 0; y: 1); - DIR_W: direction = (x: -1; y: 0); - -operator = (const a, b: direction) c: Boolean; -begin - c := (a.x = b.x) and (a.y = b.y); -end; - -const small_cell_size = 128; - medium_cell_size = 192; - large_cell_size = 256; - braidness = 10; - -type - cell_t = record x,y : LongInt - end; - -var x, y : LongInt; - cellsize : LongInt; //selected by the user in the gui - seen_cells_x, seen_cells_y : LongInt; //number of cells that can be visited by the generator, that is every second cell in x and y direction. the cells between there are walls that will be removed when we move from one cell to another - num_edges_x, num_edges_y : LongInt; //number of resulting edges that need to be vertexificated - num_cells_x, num_cells_y : LongInt; //actual number of cells, depending on cell size - - - seen_list : array of array of LongInt; - xwalls : array of array of Boolean; - ywalls : array of array of Boolean; - x_edge_list : array of array of Boolean; - y_edge_list : array of array of Boolean; - maze : array of array of Boolean; - - pa : TPixAr; - num_vertices : LongInt; - off_y : LongInt; - num_steps : LongInt; - current_step : LongInt; - - step_done : array of Boolean; - - done : Boolean; - -{ last_cell : array 0..3 of record x, y :LongInt ; end; - came_from : array of array of record x, y: LongInt; end; - came_from_pos : array of LongInt; -} - last_cell : array of cell_t; - came_from : array of array of cell_t; - came_from_pos: array of LongInt; - - maze_inverted : Boolean; - -function when_seen(x: LongInt; y: LongInt): LongInt; -begin -if (x < 0) or (x >= seen_cells_x) or (y < 0) or (y >= seen_cells_y) then - when_seen := current_step -else - when_seen := seen_list[x, y]; -end; - -function is_x_edge(x, y: LongInt): Boolean; -begin -if (x < 0) or (x > num_edges_x) or (y < 0) or (y > num_cells_y) then - is_x_edge := false -else - is_x_edge := x_edge_list[x, y]; -end; - -function is_y_edge(x, y: LongInt): Boolean; -begin -if (x < 0) or (x > num_cells_x) or (y < 0) or (y > num_edges_y) then - is_y_edge := false -else - is_y_edge := y_edge_list[x, y]; -end; - -procedure see_cell; -var dir: direction; - tries: LongInt; - x, y: LongInt; - found_cell: Boolean; - next_dir_clockwise: Boolean; - -begin -x := last_cell[current_step].x; -y := last_cell[current_step].y; -seen_list[x, y] := current_step; -case GetRandom(4) of - 0: dir := DIR_N; - 1: dir := DIR_E; - 2: dir := DIR_S; - 3: dir := DIR_W; -end; -tries := 0; -found_cell := false; -if getrandom(2) = 1 then - next_dir_clockwise := true -else - next_dir_clockwise := false; - -while (tries < 5) and (not found_cell) do -begin - if when_seen(x + dir.x, y + dir.y) = current_step then //we are seeing ourselves, try another direction - begin - //we have already seen the target cell, decide if we should remove the wall anyway - //(or put a wall there if maze_inverted, but we are not doing that right now) - if (not maze_inverted) and (GetRandom(braidness) = 0) then - //or just warn that inverted+braid+indestructible terrain != good idea - begin - case dir.x of - - -1: - if x > 0 then - ywalls[x-1, y] := false; - 1: - if x < seen_cells_x - 1 then - ywalls[x, y] := false; - end; - case dir.y of - -1: - if y > 0 then - xwalls[x, y-1] := false; - 1: - if y < seen_cells_y - 1 then - xwalls[x, y] := false; - end; - end; - if next_dir_clockwise then - begin - if dir = DIR_N then - dir := DIR_E - else if dir = DIR_E then - dir := DIR_S - else if dir = DIR_S then - dir := DIR_W - else - dir := DIR_N; - end - else - begin - if dir = DIR_N then - dir := DIR_W - else if dir = DIR_E then - dir := DIR_N - else if dir = DIR_S then - dir := DIR_E - else - dir := DIR_S; - end - end - else if when_seen(x + dir.x, y + dir.y) = -1 then //cell was not seen yet, go there - begin - case dir.y of - -1: xwalls[x, y-1] := false; - 1: xwalls[x, y] := false; - end; - case dir.x of - -1: ywalls[x-1, y] := false; - 1: ywalls[x, y] := false; - end; - last_cell[current_step].x := x+dir.x; - last_cell[current_step].y := y+dir.y; - came_from_pos[current_step] := came_from_pos[current_step] + 1; - came_from[current_step, came_from_pos[current_step]].x := x; - came_from[current_step, came_from_pos[current_step]].y := y; - found_cell := true; - end - else //we are seeing someone else, quit - begin - step_done[current_step] := true; - found_cell := true; - end; - - tries := tries + 1; -end; -if not found_cell then - begin - last_cell[current_step].x := came_from[current_step, came_from_pos[current_step]].x; - last_cell[current_step].y := came_from[current_step, came_from_pos[current_step]].y; - came_from_pos[current_step] := came_from_pos[current_step] - 1; - - if came_from_pos[current_step] >= 0 then - see_cell() - - else - step_done[current_step] := true; - end; -end; - -procedure add_vertex(x, y: LongInt); -var tmp_x, tmp_y, nx, ny: LongInt; -begin - if x = NTPX then - begin - if pa.ar[num_vertices - 6].x = NTPX then - begin - num_vertices := num_vertices - 6; - end - else - begin - pa.ar[num_vertices].x := NTPX; - pa.ar[num_vertices].y := 0; - end - end - else - begin - if maze_inverted or (x mod 2 = 0) then - tmp_x := cellsize - else - tmp_x := cellsize * 2 div 3; - - if maze_inverted or (y mod 2 = 0) then - tmp_y := cellsize - else - tmp_y := cellsize * 2 div 3; - - nx:= (x-1)*cellsize + tmp_x; - ny:= (y-1)*cellsize + tmp_y + off_y; - - if num_vertices > 2 then - if ((pa.ar[num_vertices - 2].x = pa.ar[num_vertices - 1].x) and (pa.ar[num_vertices - 1].x = nx)) - or ((pa.ar[num_vertices - 2].y = pa.ar[num_vertices - 1].y) and (pa.ar[num_vertices - 1].y = ny)) - then - dec(num_vertices); - - pa.ar[num_vertices].x := nx; - pa.ar[num_vertices].y := ny; - end; - - num_vertices := num_vertices + 1; -end; - -procedure add_edge(x, y: LongInt; dir: direction); -var i: LongInt; -begin -if dir = DIR_N then - begin - dir := DIR_W - end -else if dir = DIR_E then - begin - dir := DIR_N - end -else if dir = DIR_S then - begin - dir := DIR_E - end -else - begin - dir := DIR_S; - end; - -for i := 0 to 3 do - begin - if dir = DIR_N then - dir := DIR_E - else if dir = DIR_E then - dir := DIR_S - else if dir = DIR_S then - dir := DIR_W - else - dir := DIR_N; - - if (dir = DIR_N) and is_x_edge(x, y) then - begin - x_edge_list[x, y] := false; - add_vertex(x+1, y); - add_edge(x, y-1, DIR_N); - break; - end; - - if (dir = DIR_E) and is_y_edge(x+1, y) then - begin - y_edge_list[x+1, y] := false; - add_vertex(x+2, y+1); - add_edge(x+1, y, DIR_E); - break; - end; - - if (dir = DIR_S) and is_x_edge(x, y+1) then - begin - x_edge_list[x, y+1] := false; - add_vertex(x+1, y+2); - add_edge(x, y+1, DIR_S); - break; - end; - - if (dir = DIR_W) and is_y_edge(x, y) then - begin - y_edge_list[x, y] := false; - add_vertex(x, y+1); - add_edge(x-1, y, DIR_W); - break; - end; - end; - -end; - -procedure GenMaze; -var i: Longword; -begin -case cTemplateFilter of - 0: begin - cellsize := small_cell_size; - maze_inverted := false; - minDistance:= max(cFeatureSize*8,32); - dabDiv:= 150; - end; - 1: begin - cellsize := medium_cell_size; - minDistance:= max(cFeatureSize*6,20); - maze_inverted := false; - dabDiv:= 100; - end; - 2: begin - cellsize := large_cell_size; - minDistance:= max(cFeatureSize*5,12); - maze_inverted := false; - dabDiv:= 90; - end; - 3: begin - cellsize := small_cell_size; - minDistance:= max(cFeatureSize*8,32); - maze_inverted := true; - dabDiv:= 130; - end; - 4: begin - cellsize := medium_cell_size; - minDistance:= max(cFeatureSize*6,20); - maze_inverted := true; - dabDiv:= 100; - end; - 5: begin - cellsize := large_cell_size; - minDistance:= max(cFeatureSize*5,12); - maze_inverted := true; - dabDiv:= 85; - end; - end; - -num_cells_x := LAND_WIDTH div cellsize; -if not odd(num_cells_x) then - num_cells_x := num_cells_x - 1; //needs to be odd - -num_cells_y := LAND_HEIGHT div cellsize; -if not odd(num_cells_y) then - num_cells_y := num_cells_y - 1; - -num_edges_x := num_cells_x - 1; -num_edges_y := num_cells_y - 1; - -seen_cells_x := num_cells_x div 2; -seen_cells_y := num_cells_y div 2; - -if maze_inverted then - num_steps := 3 //TODO randomize, between 3 and 5? -else - num_steps := 1; - -SetLength(step_done, num_steps); -SetLength(last_cell, num_steps); -SetLength(came_from_pos, num_steps); -SetLength(came_from, num_steps, num_cells_x*num_cells_y); - -done := false; - -for current_step := 0 to num_steps - 1 do - begin - step_done[current_step] := false; - came_from_pos[current_step] := 0; - end; - -current_step := 0; - - -SetLength(seen_list, seen_cells_x, seen_cells_y); -SetLength(xwalls, seen_cells_x, seen_cells_y - 1); -SetLength(ywalls, seen_cells_x - 1, seen_cells_y); -SetLength(x_edge_list, num_edges_x, num_cells_y); -SetLength(y_edge_list, num_cells_x, num_edges_y); -SetLength(maze, num_cells_x, num_cells_y); - - -num_vertices := 0; - -playHeight := num_cells_y * cellsize; -playWidth := num_cells_x * cellsize; -off_y := LAND_HEIGHT - playHeight; - -for x := 0 to playWidth do - for y := 0 to off_y - 1 do - LandSet(y, x, 0); - -for x := 0 to playWidth do - for y := off_y to LAND_HEIGHT - 1 do - LandSet(y, x, lfBasic); - -for y := 0 to num_cells_y - 1 do - for x := 0 to num_cells_x - 1 do - maze[x, y] := false; - -for x := 0 to seen_cells_x - 1 do - for y := 0 to seen_cells_y - 2 do - xwalls[x, y] := true; - -for x := 0 to seen_cells_x - 2 do - for y := 0 to seen_cells_y - 1 do - ywalls[x, y] := true; - -for x := 0 to seen_cells_x - 1 do - for y := 0 to seen_cells_y - 1 do - seen_list[x, y] := -1; - -for x := 0 to num_edges_x - 1 do - for y := 0 to num_cells_y - 1 do - x_edge_list[x, y] := false; - -for x := 0 to num_cells_x - 1 do - for y := 0 to num_edges_y - 1 do - y_edge_list[x, y] := false; - -for current_step := 0 to num_steps-1 do - begin - x := GetRandom(seen_cells_x - 1) div LongWord(num_steps); - last_cell[current_step].x := x + current_step * seen_cells_x div num_steps; - last_cell[current_step].y := GetRandom(seen_cells_y); -end; - -while not done do - begin - done := true; - for current_step := 0 to num_steps-1 do - begin - if not step_done[current_step] then - begin - see_cell; - done := false; - end; - end; - end; - -for x := 0 to seen_cells_x - 1 do - for y := 0 to seen_cells_y - 1 do - if seen_list[x, y] > -1 then - maze[(x+1)*2-1, (y+1)*2-1] := true; - -for x := 0 to seen_cells_x - 1 do - for y := 0 to seen_cells_y - 2 do - if not xwalls[x, y] then - maze[x*2 + 1, y*2 + 2] := true; - - -for x := 0 to seen_cells_x - 2 do - for y := 0 to seen_cells_y - 1 do - if not ywalls[x, y] then - maze[x*2 + 2, y*2 + 1] := true; - -for x := 0 to num_edges_x - 1 do - for y := 0 to num_cells_y - 1 do - if maze[x, y] xor maze[x+1, y] then - x_edge_list[x, y] := true - else - x_edge_list[x, y] := false; - -for x := 0 to num_cells_x - 1 do - for y := 0 to num_edges_y - 1 do - if maze[x, y] xor maze[x, y+1] then - y_edge_list[x, y] := true - else - y_edge_list[x, y] := false; - -for x := 0 to num_edges_x - 1 do - for y := 0 to num_cells_y - 1 do - if x_edge_list[x, y] then - begin - x_edge_list[x, y] := false; - add_vertex(x+1, y+1); - add_vertex(x+1, y); - add_edge(x, y-1, DIR_N); - add_vertex(NTPX, 0); - end; - -pa.count := num_vertices; - -leftX:= 0; -rightX:= playWidth; -topY:= off_y; - -// fill point -pa.ar[pa.Count].x:= 1; -pa.ar[pa.Count].y:= 1 + off_y; - -{ -for i:= 0 to pa.Count - 1 do - begin - system.writeln(pa.ar[i].x, ', ', pa.ar[i].y); - end; -} - -// divide while it divides -repeat - i:= pa.Count; - DivideEdges(1, pa) -until i = pa.Count; - -// make it smooth -BezierizeEdge(pa, _0_2); - -DrawEdge(pa, 0); - -if maze_inverted then - FillLand(1, 1 + off_y, 0, 0) -else - begin - x := 0; - while LandGet(cellsize div 2 + cellsize + off_y, x) = lfBasic do - x := x + 1; - while LandGet(cellsize div 2 + cellsize + off_y, x) = 0 do - x := x + 1; - FillLand(x+1, cellsize div 2 + cellsize + off_y, 0, 0); - end; - -MaxHedgehogs:= 32; -if (GameFlags and gfDisableGirders) <> 0 then - hasGirders:= false -else - hasGirders := true; - -hasBorder := false; -end; - -end. diff -r 0caa3dfb3ba2 -r 7b8d96fc8799 hedgewars/uLandGenPerlin.pas --- a/hedgewars/uLandGenPerlin.pas Wed Sep 18 13:42:26 2024 +0200 +++ b/hedgewars/uLandGenPerlin.pas Wed Sep 18 14:10:51 2024 +0200 @@ -9,7 +9,6 @@ uses uVariables , uConsts , uRandom - , uLandOutline // FillLand , uUtils , uLandUtils ; diff -r 0caa3dfb3ba2 -r 7b8d96fc8799 hedgewars/uLandGenTemplateBased.pas --- a/hedgewars/uLandGenTemplateBased.pas Wed Sep 18 13:42:26 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,383 +0,0 @@ -unit uLandGenTemplateBased; -interface - -uses uLandTemplates, uLandOutline; - -procedure GenTemplated(var Template: TEdgeTemplate); -procedure DivideEdges(fillPointsCount: LongWord; var pa: TPixAr); - -var minDistance, dabDiv: LongInt; // different details size - -implementation -uses {$IFDEF IPHONEOS}uTypes, {$ENDIF} uVariables, uConsts, uFloat, uLandUtils, uRandom, SDLh, math; - - -procedure SetPoints(var Template: TEdgeTemplate; var pa: TPixAr; fps: PPointArray); -var i: LongInt; -begin - with Template do - begin - pa.Count:= BasePointsCount; - for i:= 0 to pred(LongInt(pa.Count)) do - begin - pa.ar[i].x:= BasePoints^[i].x + LongInt(GetRandom(BasePoints^[i].w)); - if pa.ar[i].x <> NTPX then - pa.ar[i].x:= pa.ar[i].x + ((LAND_WIDTH - Template.TemplateWidth) div 2); - pa.ar[i].y:= BasePoints^[i].y + LongInt(GetRandom(BasePoints^[i].h)) + LAND_HEIGHT - LongInt(Template.TemplateHeight) - end; - - if canMirror then - if getrandom(2) = 0 then - begin - for i:= 0 to pred(BasePointsCount) do - if pa.ar[i].x <> NTPX then - pa.ar[i].x:= LAND_WIDTH - 1 - pa.ar[i].x; - for i:= 0 to pred(FillPointsCount) do - fps^[i].x:= LAND_WIDTH - 1 - fps^[i].x; - end; - -(* Experiment in making this option more useful - if ((not isNegative) and (cTemplateFilter = 4)) or - (canFlip and (getrandom(2) = 0)) then - begin - for i:= 0 to pred(BasePointsCount) do - begin - pa.ar[i].y:= LAND_HEIGHT - 1 - pa.ar[i].y + (LAND_HEIGHT - TemplateHeight) * 2; - if pa.ar[i].y > LAND_HEIGHT - 1 then - pa.ar[i].y:= LAND_HEIGHT - 1; - end; - for i:= 0 to pred(FillPointsCount) do - begin - FillPoints^[i].y:= LAND_HEIGHT - 1 - FillPoints^[i].y + (LAND_HEIGHT - TemplateHeight) * 2; - if FillPoints^[i].y > LAND_HEIGHT - 1 then - FillPoints^[i].y:= LAND_HEIGHT - 1; - end; - end; - end -*) -// template recycling. Pull these off the floor a bit - if (not isNegative) and (cTemplateFilter = 4) then - begin - for i:= 0 to pred(BasePointsCount) do - begin - dec(pa.ar[i].y, 100); - if pa.ar[i].y < 0 then - pa.ar[i].y:= 0; - end; - for i:= 0 to pred(FillPointsCount) do - begin - dec(fps^[i].y, 100); - if fps^[i].y < 0 then - fps^[i].y:= 0; - end; - end; - - if (canFlip and (getrandom(2) = 0)) then - begin - for i:= 0 to pred(BasePointsCount) do - pa.ar[i].y:= LAND_HEIGHT - 1 - pa.ar[i].y; - for i:= 0 to pred(FillPointsCount) do - fps^[i].y:= LAND_HEIGHT - 1 - fps^[i].y; - end; - end -end; - -procedure FindPoint(si: LongInt; fillPointsCount: LongWord; var newPoint: TPoint; var pa: TPixAr); -const mapBorderMargin = 40; -var p1, p2, p4, fp, mp: TPoint; - i, t1, t2, iy, ix, aqpb: LongInt; - a, b, p, q: LongInt; - dab, d, distL, distR: LongInt; -begin - // [p1, p2] is the segment we're trying to divide - p1:= pa.ar[si]; - p2:= pa.ar[si + 1]; - - if p2.x = NTPX then - // it is segment from last to first point, so need to find first point - begin - i:= si - 2; - while (i >= 0) and (pa.ar[i].x <> NTPX) do - dec(i); - p2:= pa.ar[i + 1] - end; - - // perpendicular vector - a:= p2.y - p1.y; - b:= p1.x - p2.x; - dab:= DistanceI(a, b).Round; - - // its middle point - mp.x:= (p1.x + p2.x) div 2; - mp.y:= (p1.y + p2.y) div 2; - - // don't process too short segments or those which are too close to map borders - if (p1.x = NTPX) - or (dab < minDistance * 3) - or (mp.x < leftX + mapBorderMargin) - or (mp.x > rightX - mapBorderMargin) - or (mp.y < topY + mapBorderMargin) - or (mp.y > LongInt(LAND_HEIGHT) - mapBorderMargin) - then - begin - newPoint:= p1; - exit; - end; - - // find distances to map borders - if a <> 0 then - begin - // left border - iy:= (leftX + mapBorderMargin - mp.x) * b div a + mp.y; - d:= DistanceI(mp.x - leftX - mapBorderMargin, mp.y - iy).Round; - t1:= a * (mp.x - mapBorderMargin) + b * (mp.y - iy); - if t1 > 0 then distL:= d else distR:= d; - - // right border - iy:= (rightX - mapBorderMargin - mp.x) * b div a + mp.y; - d:= DistanceI(mp.x - rightX + mapBorderMargin, mp.y - iy).Round; - if t1 > 0 then distR:= d else distL:= d; - end else - begin - distL:= LAND_WIDTH + LAND_HEIGHT; - distR:= distL; - end; - - if b <> 0 then - begin - // top border - ix:= (topY + mapBorderMargin - mp.y) * a div b + mp.x; - d:= DistanceI(mp.y - topY - mapBorderMargin, mp.x - ix).Round; - t2:= b * (mp.y - mapBorderMargin) + a * (mp.x - ix); - if t2 > 0 then distL:= min(d, distL) else distR:= min(d, distR); - - // bottom border - ix:= (LAND_HEIGHT - mapBorderMargin - mp.y) * a div b + mp.x; - d:= DistanceI(mp.y - LAND_HEIGHT + mapBorderMargin, mp.x - ix).Round; - if t2 > 0 then distR:= min(d, distR) else distL:= min(d, distL); - end; - - // now go through all other segments - fp:= pa.ar[0]; - for i:= 0 to LongInt(pa.Count) - 2 do - if pa.ar[i].x = NTPX then - fp:= pa.ar[i + 1] - else if (i <> si) then - begin - p4:= pa.ar[i + 1]; - if p4.x = NTPX then - p4:= fp; - - // check if it intersects - t1:= (mp.x - pa.ar[i].x) * b - a * (mp.y - pa.ar[i].y); - t2:= (mp.x - p4.x) * b - a * (mp.y - p4.y); - - if (t1 > 0) <> (t2 > 0) then // yes it does, hard arith follows - begin - p:= p4.x - pa.ar[i].x; - q:= p4.y - pa.ar[i].y; - aqpb:= a * q - p * b; - - if (aqpb <> 0) then - begin - // (ix; iy) is intersection point - iy:= (((Int64(pa.ar[i].x) - mp.x) * b + Int64(mp.y) * a) * q - Int64(pa.ar[i].y) * p * b) div aqpb; - if abs(b) > abs(q) then - ix:= (iy - mp.y) * a div b + mp.x - else - ix:= (iy - pa.ar[i].y) * p div q + pa.ar[i].x; - - d:= DistanceI(mp.y - iy, mp.x - ix).Round; - t1:= b * (mp.y - iy) + a * (mp.x - ix); - if t1 > 0 then distL:= min(d, distL) else distR:= min(d, distR); - end; - end; - end; - - // go through all points, including fill points - for i:= 0 to Pred(LongInt(pa.Count + fillPointsCount)) do - // if this point isn't on current segment - if (si <> i) and (i <> si + 1) and (pa.ar[i].x <> NTPX) then - begin - // also check intersection with rays through pa.ar[i] if this point is good - t1:= (p1.x - pa.ar[i].x) * b - a * (p1.y - pa.ar[i].y); - t2:= (p2.x - pa.ar[i].x) * b - a * (p2.y - pa.ar[i].y); - if (t1 > 0) <> (t2 > 0) then - begin - // ray from p1 - p:= pa.ar[i].x - p1.x; - q:= pa.ar[i].y - p1.y; - aqpb:= a * q - p * b; - - if (aqpb <> 0) then - begin - // (ix; iy) is intersection point - iy:= (((Int64(p1.x) - mp.x) * b + Int64(mp.y) * a) * q - Int64(p1.y) * p * b) div aqpb; - if abs(b) > abs(q) then - ix:= (iy - mp.y) * a div b + mp.x - else - ix:= (iy - p1.y) * p div q + p1.x; - - d:= DistanceI(mp.y - iy, mp.x - ix).Round; - t1:= b * (mp.y - iy) + a * (mp.x - ix); - if t1 > 0 then distL:= min(d, distL) else distR:= min(d, distR); - end; - - // and ray from p2 - p:= pa.ar[i].x - p2.x; - q:= pa.ar[i].y - p2.y; - aqpb:= a * q - p * b; - - if (aqpb <> 0) then - begin - // (ix; iy) is intersection point - iy:= (((Int64(p2.x) - mp.x) * b + Int64(mp.y) * a) * q - Int64(p2.y) * p * b) div aqpb; - if abs(b) > abs(q) then - ix:= (iy - mp.y) * a div b + mp.x - else - ix:= (iy - p2.y) * p div q + p2.x; - - d:= DistanceI(mp.y - iy, mp.x - ix).Round; - t2:= b * (mp.y - iy) + a * (mp.x - ix); - if t2 > 0 then distL:= min(d, distL) else distR:= min(d, distR); - end; - end; - end; - - // don't move new point for more than length of initial segment - // adjust/parametrize for more flat surfaces (try values 3/4, 1/2 of dab, or even 1/4) - d:= dab * 100 div dabDiv; - //d:= dab * (1 + abs(cFeatureSize - 8)) div 6; - //d:= dab * (14 + cFeatureSize) div 20; - if distL > d then distL:= d; - if distR > d then distR:= d; - - if distR + distL < minDistance * 2 + 10 then - begin - // limits are too narrow, just divide - newPoint.x:= mp.x; - newPoint.y:= mp.y; - end - else - begin - // select distance within [-distL; distR] - d:= -distL + minDistance + LongInt(GetRandom(distR + distL - minDistance * 2)); - //d:= distR - minDistance; - //d:= - distL + minDistance; - - // calculate new point - newPoint.x:= mp.x + a * d div dab; - newPoint.y:= mp.y + b * d div dab; - end; -end; - -procedure DivideEdges(fillPointsCount: LongWord; var pa: TPixAr); -var i, t: LongInt; - newPoint: TPoint; -begin - newPoint.x:= 0; - newPoint.y:= 0; - i:= 0; - - while i < LongInt(pa.Count) - 1 do - begin - FindPoint(i, fillPointsCount, newPoint, pa); - - if (newPoint.x <> pa.ar[i].x) or (newPoint.y <> pa.ar[i].y) then - begin - // point found, free a slot for it in array, don't forget to move appended fill points - for t:= pa.Count + fillPointsCount downto i + 2 do - pa.ar[t]:= pa.ar[t - 1]; - inc(pa.Count); - pa.ar[i + 1]:= newPoint; - inc(i) - end; - inc(i) - end; -end; - -procedure Distort2(var Template: TEdgeTemplate; fps: PPointArray; var pa: TPixAr); -var i: Longword; -begin - // append fill points to ensure distortion won't move them to other side of segment - for i:= 0 to pred(Template.FillPointsCount) do - begin - pa.ar[pa.Count + i].x:= fps^[i].x; - pa.ar[pa.Count + i].y:= fps^[i].y; - end; - - // divide while it divides - repeat - i:= pa.Count; - DivideEdges(Template.FillPointsCount, pa) - until i = pa.Count; - -{$IFDEF IPHONEOS} - if GameType <> gmtLandPreview then -{$ENDIF} - // make it smooth - BezierizeEdge(pa, _0_2); -end; - - -procedure GenTemplated(var Template: TEdgeTemplate); -var pa: TPixAr; - i: Longword; - y, x: Longword; - fps: TPointArray; -begin - fps:=Template.FillPoints^; - ResizeLand(Template.TemplateWidth, Template.TemplateHeight); - for y:= 0 to LAND_HEIGHT - 1 do - for x:= 0 to LAND_WIDTH - 1 do - LandSet(y, x, lfBasic); - - minDistance:= sqr(cFeatureSize) div 8 + 10; - //dabDiv:= getRandom(41)+60; - //dabDiv:= getRandom(31)+70; - dabDiv:= getRandom(21)+100; - MaxHedgehogs:= Template.MaxHedgehogs; - hasGirders:= Template.hasGirders; - playHeight:= Template.TemplateHeight; - playWidth:= Template.TemplateWidth; - leftX:= (LAND_WIDTH - playWidth) div 2; - rightX:= Pred(leftX + playWidth); - topY:= LAND_HEIGHT - playHeight; - - {$HINTS OFF} - SetPoints(Template, pa, @fps); - {$HINTS ON} - - Distort2(Template, @fps, pa); - - DrawEdge(pa, 0); - - with Template do - for i:= 0 to pred(FillPointsCount) do - with fps[i] do - FillLand(x, y, 0, 0); - - DrawEdge(pa, lfBasic); - - // HACK: force to only cavern even if a cavern map is invertable if cTemplateFilter = 4 ? - if (cTemplateFilter = 4) - or (Template.canInvert and (getrandom(2) = 0)) - or (not Template.canInvert and Template.isNegative) then - begin - hasBorder:= true; - for y:= 0 to LAND_HEIGHT - 1 do - for x:= 0 to LAND_WIDTH - 1 do - if (y < LongWord(topY)) or (x < LongWord(leftX)) or (x > LongWord(rightX)) then - LandSet(y, x, 0) - else - begin - if LandGet(y, x) = 0 then - LandSet(y, x, lfBasic) - else if LandGet(y, x) = lfBasic then - LandSet(y, x, 0); - end; - end; -end; - - -end. diff -r 0caa3dfb3ba2 -r 7b8d96fc8799 hedgewars/uLandOutline.pas --- a/hedgewars/uLandOutline.pas Wed Sep 18 13:42:26 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,182 +0,0 @@ -unit uLandOutline; - -interface - -uses uConsts, SDLh, uFloat; - -type TPixAr = record - Count: Longword; - ar: array[0..Pred(cMaxEdgePoints)] of TPoint; - end; - -procedure DrawEdge(var pa: TPixAr; value: Word); -procedure BezierizeEdge(var pa: TPixAr; Delta: hwFloat); - -implementation - -uses uLandGraphics, uDebug, uVariables, uLandTemplates; - - -var Stack: record - Count: Longword; - points: array[0..8192] of record - xl, xr, y, dir: LongInt; - end - end; - - -procedure Push(_xl, _xr, _y, _dir: LongInt); -begin - if checkFails(Stack.Count <= 8192, 'FillLand: stack overflow', true) then exit; - _y:= _y + _dir; - if (_y < 0) or (_y >= LAND_HEIGHT) then - exit; - with Stack.points[Stack.Count] do - begin - xl:= _xl; - xr:= _xr; - y:= _y; - dir:= _dir - end; - inc(Stack.Count) -end; - -procedure Pop(var _xl, _xr, _y, _dir: LongInt); -begin - dec(Stack.Count); - with Stack.points[Stack.Count] do - begin - _xl:= xl; - _xr:= xr; - _y:= y; - _dir:= dir - end -end; - -procedure DrawEdge(var pa: TPixAr; value: Word); -var i: LongInt; -begin - i:= 0; - with pa do - while i < LongInt(Count) - 1 do - if (ar[i + 1].X = NTPX) then - inc(i, 2) - else - begin - DrawLine(ar[i].x, ar[i].y, ar[i + 1].x, ar[i + 1].y, value); - inc(i) - end -end; - - -procedure Vector(p1, p2, p3: TPoint; var Vx, Vy: hwFloat); -var d1, d2, d: hwFloat; -begin - Vx:= int2hwFloat(p1.X - p3.X); - Vy:= int2hwFloat(p1.Y - p3.Y); - - d2:= Distance(Vx, Vy); - - if d2.QWordValue = 0 then - begin - Vx:= _0; - Vy:= _0 - end - else - begin - d:= DistanceI(p2.X - p1.X, p2.Y - p1.Y); - d1:= DistanceI(p2.X - p3.X, p2.Y - p3.Y); - - if d1 < d then - d:= d1; - if d2 < d then - d:= d2; - - d2:= d * _1div3 / d2; - - Vx:= Vx * d2; - Vy:= Vy * d2 - end -end; - -procedure AddLoopPoints(var pa, opa: TPixAr; StartI, EndI: LongInt; Delta: hwFloat); -var i, pi, ni: LongInt; - NVx, NVy, PVx, PVy: hwFloat; - x1, x2, y1, y2: LongInt; - tsq, tcb, t, r1, r2, r3, cx1, cx2, cy1, cy2: hwFloat; - X, Y: LongInt; -begin - if pa.Count < cMaxEdgePoints - 2 then - begin - pi:= EndI; - i:= StartI; - ni:= Succ(StartI); - {$HINTS OFF} - Vector(opa.ar[pi], opa.ar[i], opa.ar[ni], NVx, NVy); - {$HINTS ON} - repeat - i:= ni; - inc(pi); - if pi > EndI then - pi:= StartI; - inc(ni); - if ni > EndI then - ni:= StartI; - PVx:= NVx; - PVy:= NVy; - Vector(opa.ar[pi], opa.ar[i], opa.ar[ni], NVx, NVy); - - x1:= opa.ar[pi].x; - y1:= opa.ar[pi].y; - x2:= opa.ar[i].x; - y2:= opa.ar[i].y; - - cx1:= int2hwFloat(x1) - PVx; - cy1:= int2hwFloat(y1) - PVy; - cx2:= int2hwFloat(x2) + NVx; - cy2:= int2hwFloat(y2) + NVy; - t:= _0; - while (t.Round = 0) and (pa.Count < cMaxEdgePoints-2) do - begin - tsq:= t * t; - tcb:= tsq * t; - r1:= (_1 - t*3 + tsq*3 - tcb); - r2:= ( t*3 - tsq*6 + tcb*3); - r3:= ( tsq*3 - tcb*3); - X:= hwRound(r1 * x1 + r2 * cx1 + r3 * cx2 + tcb * x2); - Y:= hwRound(r1 * y1 + r2 * cy1 + r3 * cy2 + tcb * y2); - t:= t + Delta; - pa.ar[pa.Count].x:= X; - pa.ar[pa.Count].y:= Y; - inc(pa.Count); - //TryDo(pa.Count <= cMaxEdgePoints, 'Edge points overflow', true) - end; - until i = StartI; - end; - - pa.ar[pa.Count].x:= opa.ar[StartI].X; - pa.ar[pa.Count].y:= opa.ar[StartI].Y; - inc(pa.Count) -end; - -procedure BezierizeEdge(var pa: TPixAr; Delta: hwFloat); -var i, StartLoop: LongInt; - opa: TPixAr; -begin -opa:= pa; -pa.Count:= 0; -i:= 0; -StartLoop:= 0; -while (i < LongInt(opa.Count)) and (pa.Count < cMaxEdgePoints-1) do - if (opa.ar[i + 1].X = NTPX) then - begin - AddLoopPoints(pa, opa, StartLoop, i, Delta); - inc(i, 2); - StartLoop:= i; - pa.ar[pa.Count].X:= NTPX; - pa.ar[pa.Count].Y:= 0; - inc(pa.Count); - end else inc(i) -end; - -end.