123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715 |
- unit fHTFpackD;
- interface
- uses
- Winapi.Windows,
- System.SysUtils,
- System.Classes,
- System.Actions,
- System.Math,
- System.ImageList,
- Vcl.Graphics,
- Vcl.Controls,
- Vcl.Forms,
- Vcl.Dialogs,
- ValEdit,
- Vcl.Grids,
- Vcl.Menus,
- Vcl.StdCtrls,
- Vcl.ComCtrls,
- Vcl.ToolWin,
- Vcl.ExtCtrls,
- Vcl.ActnList,
- Vcl.ImgList,
- GLS.HeightTileFileHDS;
- type
- TSrc = record
- fs: TFileStream;
- x, y, w, h: Integer;
- format: Integer;
- FlipRotate: Integer;
- end;
- PSrc = ^TSrc;
- TMainForm = class(TForm)
- MainMenu: TMainMenu;
- StringGrid: TStringGrid;
- File1: TMenuItem;
- ActionList: TActionList;
- ImageList: TImageList;
- ACOpen: TAction;
- ACSave: TAction;
- ACExit: TAction;
- Open1: TMenuItem;
- Save1: TMenuItem;
- N1: TMenuItem;
- Exit1: TMenuItem;
- Panel1: TPanel;
- Label1: TLabel;
- Label2: TLabel;
- EDHTFName: TEdit;
- EDDEMPath: TEdit;
- BUDEMPath: TButton;
- BUPickHTF: TButton;
- ToolBar: TToolBar;
- ToolButton1: TToolButton;
- ToolButton2: TToolButton;
- ToolButton3: TToolButton;
- DEMs1: TMenuItem;
- ACNewDEM: TAction;
- ACRemoveDEM: TAction;
- ToolButton4: TToolButton;
- ToolButton5: TToolButton;
- AddDEMsource1: TMenuItem;
- RemoveDEMsource1: TMenuItem;
- SDHTF: TSaveDialog;
- PopupMenu: TPopupMenu;
- AddDEMsource2: TMenuItem;
- RemoveDEMsource2: TMenuItem;
- MIAbout: TMenuItem;
- CBType: TComboBox;
- CBFile: TComboBox;
- Label3: TLabel;
- EDSizeX: TEdit;
- EDSizeY: TEdit;
- Label4: TLabel;
- Label5: TLabel;
- EDDefaultZ: TEdit;
- ODTerrainPack: TOpenDialog;
- SDTerrainPack: TSaveDialog;
- ToolButton6: TToolButton;
- ACProcess: TAction;
- ToolButton7: TToolButton;
- N2: TMenuItem;
- Process1: TMenuItem;
- PanelFoot: TPanel;
- ProgressBar: TProgressBar;
- EDTileSize: TEdit;
- Label6: TLabel;
- ToolButton8: TToolButton;
- ACViewer: TAction;
- N3: TMenuItem;
- HTFViewer1: TMenuItem;
- ToolButton9: TToolButton;
- ODPath: TOpenDialog;
- Label7: TLabel;
- EDTileOverlap: TEdit;
- Label8: TLabel;
- EDZFilter: TEdit;
- Label9: TLabel;
- EDZScale: TEdit;
- CBWholeOnly: TCheckBox;
- CBFlipRotate: TComboBox;
- procedure ACExitExecute(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- procedure BUDEMPathClick(Sender: TObject);
- procedure BUPickHTFClick(Sender: TObject);
- procedure MIAboutClick(Sender: TObject);
- procedure ActionListUpdate(Action: TBasicAction; var Handled: Boolean);
- procedure ACNewDEMExecute(Sender: TObject);
- procedure ACRemoveDEMExecute(Sender: TObject);
- procedure StringGridSelectCell(Sender: TObject; ACol, ARow: Integer;
- var CanSelect: Boolean);
- procedure CBTypeChange(Sender: TObject);
- procedure ACSaveExecute(Sender: TObject);
- procedure ACOpenExecute(Sender: TObject);
- procedure EDDEMPathChange(Sender: TObject);
- procedure FormDestroy(Sender: TObject);
- procedure EDDefaultZChange(Sender: TObject);
- procedure ACProcessExecute(Sender: TObject);
- procedure ACViewerExecute(Sender: TObject);
- procedure EDZFilterChange(Sender: TObject);
- procedure EDZScaleChange(Sender: TObject);
- private
- sources: array of TSrc;
- defaultZ: SmallInt;
- filterZ: SmallInt;
- zScale: Single;
- procedure Parse;
- procedure Cleanup;
- procedure SrcExtractFlip(src: PSrc; relX, relY, len: Integer;
- dest: PSmallInt);
- procedure SrcExtract(src: PSrc; relX, relY, len: Integer; dest: PSmallInt;
- DiagFlip: Boolean = false);
- procedure WorldExtract(x, y, len: Integer; dest: PSmallInt);
- public
- end;
- var
- MainForm: TMainForm;
- implementation
- uses
- fViewerD;
- {$R *.dfm}
- procedure TMainForm.FormCreate(Sender: TObject);
- var
- i: Integer;
- begin
- with ActionList do
- for i := 0 to ActionCount - 1 do
- with TAction(Actions[i]) do
- Hint := Caption;
- with StringGrid do
- begin
- Cells[0, 0] := 'File Name';
- ColWidths[0] := 140;
- Cells[1, 0] := 'World Offset';
- ColWidths[1] := 80;
- Cells[2, 0] := 'Size (rotated)';
- ColWidths[2] := 80;
- Cells[3, 0] := 'Data type';
- ColWidths[3] := 120;
- Cells[4, 0] := 'Flip and Rotate';
- ColWidths[4] := 110;
- Row := 0;
- end;
- zScale := 1;
- end;
- procedure TMainForm.FormDestroy(Sender: TObject);
- begin
- Cleanup;
- end;
- procedure TMainForm.ACExitExecute(Sender: TObject);
- begin
- Close;
- end;
- procedure TMainForm.BUDEMPathClick(Sender: TObject);
- begin
- ODPath.InitialDir := EDDEMPath.Text;
- ODPath.FileName := EDDEMPath.Text + 'pick a dummy.file';
- if ODPath.Execute then
- EDDEMPath.Text := ExtractFilePath(ODPath.FileName);
- end;
- procedure TMainForm.BUPickHTFClick(Sender: TObject);
- begin
- SDHTF.FileName := EDHTFName.Text;
- if SDHTF.Execute then
- EDHTFName.Text := SDHTF.FileName;
- end;
- procedure TMainForm.MIAboutClick(Sender: TObject);
- begin
- ShowMessage(Caption + #13#10#13#10 + 'HTF Generation Utility'#13#10 +
- 'Part of GLScene library.'#13#10#13#10 + 'http://glscene.org');
- end;
- procedure TMainForm.ActionListUpdate(Action: TBasicAction;
- var Handled: Boolean);
- begin
- ACRemoveDEM.Enabled := (StringGrid.RowCount > 2);
- end;
- procedure TMainForm.ACNewDEMExecute(Sender: TObject);
- begin
- StringGrid.RowCount := StringGrid.RowCount + 1;
- end;
- procedure TMainForm.ACRemoveDEMExecute(Sender: TObject);
- var
- i: Integer;
- begin
- with StringGrid do
- begin
- i := Row;
- if i < RowCount - 1 then
- begin
- while i < RowCount - 1 do
- begin
- Rows[i] := Rows[i + 1];
- Inc(i);
- end;
- end
- else
- Row := i - 1;
- RowCount := RowCount - 1;
- end;
- end;
- procedure TMainForm.StringGridSelectCell(Sender: TObject; ACol, ARow: Integer;
- var CanSelect: Boolean);
- procedure SetCB(const cb: TComboBox);
- var
- r: TRect;
- i: Integer;
- begin
- r := StringGrid.CellRect(ACol, ARow);
- cb.Left := r.Left + StringGrid.Left;
- cb.Top := r.Top + StringGrid.Top;
- cb.Width := r.Right + 1 - r.Left;
- i := cb.Items.IndexOf(StringGrid.Cells[ACol, ARow]);
- if i >= 0 then
- cb.ItemIndex := i
- else
- cb.Text := StringGrid.Cells[ACol, ARow];
- if Visible then
- cb.SetFocus;
- end;
- begin
- if ARow > 0 then
- begin
- if ACol = 0 then
- begin
- CBFile.Visible := True;
- SetCB(CBFile);
- end
- else
- CBFile.Visible := false;
- if ACol = 3 then
- begin
- CBType.Visible := True;
- SetCB(CBType);
- end
- else
- CBType.Visible := false;
- if ACol = 4 then
- begin
- CBFlipRotate.Visible := True;
- SetCB(CBFlipRotate);
- end
- else
- CBFlipRotate.Visible := false;
- CanSelect := True;
- end;
- end;
- procedure TMainForm.CBTypeChange(Sender: TObject);
- begin
- with StringGrid do
- Cells[Col, Row] := (Sender as TComboBox).Text;
- end;
- procedure TMainForm.ACSaveExecute(Sender: TObject);
- var
- i: Integer;
- sl, sg: TStringList;
- begin
- if SDTerrainPack.Execute then
- begin
- sl := TStringList.Create;
- with sl do
- begin
- Values['HTFName'] := EDHTFName.Text;
- Values['WorldSizeX'] := EDSizeX.Text;
- Values['WorldSizeY'] := EDSizeY.Text;
- Values['TileSize'] := EDTileSize.Text;
- Values['TileOverlap'] := EDTileOverlap.Text;
- Values['DefaultZ'] := EDDefaultZ.Text;
- Values['FilterZ'] := EDZFilter.Text;
- Values['ZScale'] := EDZScale.Text;
- Values['DEMPath'] := EDDEMPath.Text;
- Values['WholeTiles'] := IntToStr(Integer(CBWholeOnly.Checked));
- sg := TStringList.Create;
- for i := 1 to StringGrid.RowCount - 1 do
- sg.Add(StringGrid.Rows[i].CommaText);
- Values['DEMs'] := sg.CommaText;
- sg.Free;
- end;
- sl.SaveToFile(SDTerrainPack.FileName);
- sl.Free;
- end;
- end;
- procedure TMainForm.ACOpenExecute(Sender: TObject);
- var
- i: Integer;
- sl, sg: TStringList;
- begin
- if ODTerrainPack.Execute then
- begin
- sl := TStringList.Create;
- sl.LoadFromFile(ODTerrainPack.FileName);
- with sl do
- begin
- EDHTFName.Text := Values['HTFName'];
- EDSizeX.Text := Values['WorldSizeX'];
- EDSizeY.Text := Values['WorldSizeY'];
- EDTileSize.Text := Values['TileSize'];
- EDTileOverlap.Text := Values['TileOverlap'];
- EDDefaultZ.Text := Values['DefaultZ'];
- EDZFilter.Text := Values['FilterZ'];
- EDZScale.Text := Values['ZScale'];
- EDDEMPath.Text := Values['DEMPath'];
- CBWholeOnly.Checked := (Values['WholeTiles'] = '1');
- sg := TStringList.Create;
- sg.CommaText := Values['DEMs'];
- StringGrid.RowCount := sg.Count + 1;
- for i := 0 to sg.Count - 1 do
- StringGrid.Rows[i + 1].CommaText := sg[i];
- sg.Free;
- end;
- sl.Free;
- SDTerrainPack.FileName := ODTerrainPack.FileName;
- end;
- end;
- procedure TMainForm.EDDEMPathChange(Sender: TObject);
- var
- f: TSearchRec;
- r: Integer;
- begin
- CBFile.Items.Clear;
- r := FindFirst(EDDEMPath.Text + '\*.*', faAnyFile, f);
- while r = 0 do
- begin
- if (f.Attr and faDirectory) = 0 then
- CBFile.Items.Add(f.Name);
- r := FindNext(f);
- end;
- FindClose(f);
- end;
- procedure TMainForm.EDDefaultZChange(Sender: TObject);
- begin
- defaultZ := StrToIntDef(EDDefaultZ.Text, 0);
- if EDZFilter.Text = '' then
- filterZ := defaultZ;
- end;
- procedure TMainForm.EDZFilterChange(Sender: TObject);
- begin
- filterZ := StrToIntDef(EDZFilter.Text, defaultZ);
- end;
- procedure TMainForm.EDZScaleChange(Sender: TObject);
- begin
- zScale := StrToFloatDef(EDZScale.Text, 1.0);
- end;
- procedure TMainForm.Parse;
- var
- i, p: Integer;
- Row: TStrings;
- begin
- Cleanup;
- SetLength(sources, StringGrid.RowCount - 1);
- for i := 0 to High(sources) do
- begin
- Row := StringGrid.Rows[i + 1];
- sources[i].fs := TFileStream.Create(EDDEMPath.Text + '\' + Row[0],
- fmOpenRead + fmShareDenyNone);
- p := Pos(',', Row[1]);
- sources[i].x := StrToInt(Copy(Row[1], 1, p - 1));
- sources[i].y := StrToInt(Copy(Row[1], p + 1, MaxInt));
- p := Pos('x', Row[2]);
- sources[i].w := StrToInt(Copy(Row[2], 1, p - 1));
- sources[i].h := StrToInt(Copy(Row[2], p + 1, MaxInt));
- sources[i].format := CBType.Items.IndexOf(Row[3]); // File format
- sources[i].FlipRotate := CBFlipRotate.Items.IndexOf(Row[4]);
- // Flip and Rotate
- end;
- end;
- procedure TMainForm.Cleanup;
- var
- i: Integer;
- begin
- for i := 0 to High(sources) do
- sources[i].fs.Free;
- SetLength(sources, 0);
- end;
- procedure TMainForm.SrcExtractFlip(src: PSrc; relX, relY, len: Integer;
- dest: PSmallInt);
- var
- i: Integer;
- val: SmallInt;
- begin
- if src.FlipRotate <= 0 then
- SrcExtract(src, relX, relY, len, dest) // None
- else
- begin
- for i := 0 to len - 1 do
- begin
- case src.FlipRotate of
- // 0 : SrcExtract(src,relX, relY+i,1,@val); //No change ( )
- 1:
- SrcExtract(src, src.w - (relX + i), relY, 1, @val);
- // H-Flip (Flip)
- 2:
- SrcExtract(src, relY, src.w - (relX + i), 1, @val, True);
- // DiagFlip + H-Flip (90deg)
- 3:
- SrcExtract(src, src.w - (relX + i), src.h - relY, 1, @val);
- // H-Flip + V-Flip (180deg)
- 4:
- SrcExtract(src, src.h - relY, (relX + i), 1, @val, True);
- // DiagFlip + V-Flip (270deg)
- 5:
- SrcExtract(src, src.h - relY, src.w - (relX + i), 1, @val, True);
- // DiagFlip + V-Flip + H-Flip (Flip-90deg)
- 6:
- SrcExtract(src, relX + i, src.h - relY, 1, @val);
- // V-FLIP (Flip-180deg)
- 7:
- SrcExtract(src, relY, relX + i, 1, @val, True);
- // DiagFlip (Flip-270deg)
- end;
- PSmallIntArray(dest)[i] := val;
- end;
- end;
- end;
- procedure TMainForm.SrcExtract(src: PSrc; relX, relY, len: Integer;
- dest: PSmallInt; DiagFlip: Boolean = false);
- var
- i, c: Integer;
- wd: Word;
- buf: array of Single;
- bmp: TBitmap;
- rw: Integer; // rotated width
- begin
- if DiagFlip then
- rw := src.h
- else
- rw := src.w;
- with src^ do
- begin
- case format of
- 0:
- begin // 16bits Intel
- fs.Position := (relX + relY * rw) * 2;
- fs.Read(dest^, len * 2);
- end;
- 1:
- begin // 16bits unsigned Intel
- fs.Position := (relX + relY * rw) * 2;
- fs.Read(dest^, len * 2);
- for i := 0 to len - 1 do
- begin
- wd := PWord(Integer(dest) + i * 2)^;
- PSmallInt(Integer(dest) + i * 2)^ := Integer(wd) - 32768;
- end;
- end;
- 2:
- begin // 16bits non-Intel
- fs.Position := (relX + relY * rw) * 2;
- fs.Read(dest^, len * 2);
- for i := 0 to len - 1 do
- begin
- wd := PWord(Integer(dest) + i * 2)^;
- PWord(Integer(dest) + i * 2)^ := ((wd and 255) shl 8) + (wd shr 8);
- end;
- end;
- 3:
- begin // VTP's BT single
- fs.Position := (relX + relY * rw) * 4 + 256;
- SetLength(buf, len);
- fs.Read(buf[0], len * 4);
- for i := 0 to len - 1 do
- PSmallInt(Integer(dest) + i * 2)^ := Round(buf[i]);
- end;
- 4:
- begin // windows BMP
- bmp := TBitmap.Create;
- try
- fs.Position := 0;
- bmp.LoadFromStream(fs);
- if DiagFlip then
- rw := bmp.Width
- else
- rw := bmp.Height;
- for i := 0 to len - 1 do
- begin
- c := bmp.Canvas.Pixels[relX + i, rw - relY - 1];
- PSmallInt(Integer(dest) + i * 2)^ := (GetGValue(c) - 128) shl 7;
- end;
- finally
- bmp.Free;
- end;
- end;
- 5:
- begin // 32bits FP Intel
- fs.Position := (relX + relY * rw) * 4;
- SetLength(buf, len);
- fs.Read(buf[0], len * 4);
- for i := 0 to len - 1 do
- PSmallInt(Integer(dest) + i * 2)^ := Round((buf[i] - 0.5) * 32000);
- end;
- 6:
- begin // DTED
- fs.Position := 3434 + (relX + relY * rw) * 2 + (relY * 12);
- fs.Read(dest^, len * 2);
- for i := 0 to len - 1 do
- begin
- wd := PWord(Integer(dest) + i * 2)^;
- PWord(Integer(dest) + i * 2)^ := ((wd and 255) shl 8) + (wd shr 8);
- end;
- end;
- end;
- end;
- end;
- procedure TMainForm.WorldExtract(x, y, len: Integer; dest: PSmallInt);
- var
- i, n, rx, ry: Integer;
- src: PSrc;
- begin
- while len > 0 do
- begin
- src := nil;
- for i := 0 to High(sources) do
- begin
- if (sources[i].x <= x) and (sources[i].y <= y) and
- (x < sources[i].x + sources[i].w) and (y < sources[i].y + sources[i].h)
- then
- begin
- src := @sources[i];
- Break;
- end;
- end;
- if Assigned(src) then
- begin
- rx := x - src.x;
- ry := y - src.y;
- n := len;
- if rx + n > src.w then
- n := src.w - rx;
- SrcExtractFlip(src, rx, ry, n, dest);
- if filterZ <> defaultZ then
- begin
- for i := 0 to n - 1 do
- if PSmallIntArray(dest)[i] = filterZ then
- PSmallIntArray(dest)[i] := defaultZ;
- end;
- if zScale <> 1 then
- begin
- for i := 0 to n - 1 do
- PSmallIntArray(dest)[i] := Round(PSmallIntArray(dest)[i] * zScale);
- end;
- Dec(len, n);
- Inc(dest, n);
- Inc(x, n);
- end
- else
- begin
- dest^ := defaultZ;
- Inc(dest);
- Dec(len);
- Inc(x);
- end;
- end;
- end;
- procedure TMainForm.ACProcessExecute(Sender: TObject);
- var
- x, y, wx, wy, ts, tx, ty, i, j, overlap: Integer;
- n, maxN: Cardinal;
- htf: TGLHeightTileFile;
- buf: array of SmallInt;
- f: file of Byte;
- begin
- Screen.Cursor := crHourGlass;
- wx := StrToInt(EDSizeX.Text);
- wy := StrToInt(EDSizeY.Text);
- ts := StrToInt(EDTileSize.Text);
- overlap := StrToInt(EDTileOverlap.Text);
- Parse;
- SetLength(buf, ts * ts);
- htf := TGLHeightTileFile.CreateNew(EDHTFName.Text, wx, wy, ts);
- htf.defaultZ := defaultZ;
- ProgressBar.Max := 1000;
- maxN := Ceil(wx / ts) * Ceil(wy / ts);
- n := 0;
- ProgressBar.Position := 0;
- y := 0;
- while y < wy do
- begin
- ty := wy + overlap - y;
- if ty > ts then
- ty := ts;
- x := 0;
- while x < wx do
- begin
- tx := wx + overlap - x;
- if (not CBWholeOnly.Checked) or ((tx >= ts) and ((wy - y) >= ts)) then
- begin
- if tx > ts then
- tx := ts;
- for i := 0 to ty - 1 do
- begin
- WorldExtract(x, y + i, tx, @buf[i * ts]);
- if overlap > 0 then
- begin
- for j := tx to ts - 1 do
- buf[i * ts + j] := buf[i * ts + tx - 1];
- end
- else
- begin
- for j := tx to ts - 1 do
- buf[i * ts + j] := defaultZ;
- end;
- end;
- if overlap > 0 then
- begin
- for i := ty to ts - 1 do
- for j := 0 to ts - 1 do
- buf[i * ts + j] := buf[(i - 1) * ts + j];
- end
- else
- begin
- for i := ty to ts - 1 do
- for j := 0 to ts - 1 do
- buf[i * ts + j] := defaultZ;
- end;
- htf.CompressTile(x, y, ts, ts, @buf[0]);
- end;
- Inc(x, ts - overlap);
- Inc(n);
- ProgressBar.Position := (n * 1000) div maxN;
- if (n and 15) = 0 then
- begin
- Application.ProcessMessages;
- end;
- end;
- Inc(y, ts - overlap);
- end;
- htf.Free;
- Cleanup;
- Screen.Cursor := crDefault;
- AssignFile(f, EDHTFName.Text);
- Reset(f);
- i := FileSize(f);
- CloseFile(f);
- ShowMessage('HTF file created.'#13#10#13#10 + IntToStr(i) +
- ' bytes in file'#13#10 + '(' + IntToStr(wx * wy * 2) + ' raw bytes)');
- end;
- procedure TMainForm.ACViewerExecute(Sender: TObject);
- var
- viewer: TViewerForm;
- begin
- viewer := TViewerForm.Create(nil);
- try
- viewer.htf := TGLHeightTileFile.Create(EDHTFName.Text); // R
- viewer.Caption := 'HTFViewer - ' + ExtractFileName(EDHTFName.Text); // R
- viewer.ShowModal;
- finally
- viewer.Free;
- end;
- end;
- end.
|