Skip to content

Commit 085e050

Browse files
committed
feat: Tool Resource Editor
Added a simple Simba resource editor to help view, understand and edit resource files with GUI. It's a bit slow at certain things because Simba is not optimized for the things this tool does.
1 parent 164ebd5 commit 085e050

File tree

5 files changed

+233
-3
lines changed

5 files changed

+233
-3
lines changed

tools/framerecorder.simba

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
(*
2-
# Frame Recorder
2+
(Frame Recorder)=
3+
# Tool: Frame Recorder
34
Simple utility for recording frame sequences at a specified FPS.
45
Useful for creating frame sequences for {ref}`videoplayer` or debugging.
56

tools/map_debugger.simba

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
(*
2+
(Map Debugger)=
23
# Tool: Map Debugger
34
Tool to visually debug {ref}`TRSMap` with the {ref}`Map Debugger` tool.
45
*)

tools/resource_editor.simba

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
(*
2+
(Resource Editor)=
3+
# Tool: Resource Editor
4+
Tool to inspect and edit resource files created by Simba's `TResourceWriter`:
5+
6+
```{figure} ../../images/resource_editor.png
7+
```
8+
9+
These files usually end in a `.bin` extension and are an optimized way to store
10+
multiple compressed files for Simba to read from.
11+
12+
This tool is also a little bit slow at doing certain things like loading the
13+
files bytes, adding and removing files/images because Simba is not optimized for
14+
what this tool does.
15+
*)
16+
{$I WaspLib/osrs.simba}
17+
18+
var
19+
HEX_TABLE: TStringArray;
20+
function ToString(constref value: TByteArray): String; override;
21+
var
22+
i: Integer;
23+
begin
24+
for i := 0 to High(value)-1 do
25+
Result += HEX_TABLE[value[i]] + ' ';
26+
Result += HEX_TABLE[value[High(value)]];
27+
end;
28+
29+
30+
type
31+
TResourceEditor = record
32+
Form: TLazForm;
33+
FileList: TLazListBox;
34+
Reader: TResourceReader;
35+
Dialog: TLazOpenDialog;
36+
FileData: TLazMemo;
37+
FileImage: TImageBox;
38+
SelectedResource, CompressionAlgo, CompressedSize, Uncompressed: TLazEdit;
39+
end;
40+
41+
{$H-}
42+
procedure TResourceEditor.OnOpenClick(sender: TLazObject);
43+
begin
44+
if not Self.Dialog.Execute() then
45+
Exit;
46+
47+
Self.FileList.Items.BeginUpdate();
48+
Self.FileList.Clear();
49+
Self.FileList.ItemIndex := -1;
50+
try
51+
Self.Reader := new TResourceReader(Self.Dialog.FileName);
52+
Self.SelectedResource.Text := Self.Dialog.FileName;
53+
Self.FileList.Items.AddStrings(Self.Reader.Names);
54+
except
55+
Self.SelectedResource.Text := '';
56+
finally
57+
Self.FileList.Items.EndUpdate();
58+
end;
59+
end;
60+
61+
procedure TResourceEditor.OnAddFileClick(sender: TLazObject);
62+
var
63+
writer: TResourceWriter;
64+
name: String;
65+
i: Integer;
66+
data: TByteArray;
67+
begin
68+
if not Self.Dialog.Execute() then
69+
Exit;
70+
71+
writer := new TResourceWriter();
72+
for i := 0 to Self.Reader.Count-1 do
73+
begin
74+
data := Self.Reader.Load(i);
75+
writer.Add(Self.Reader.Name[i], @data[0], Length(data));
76+
end;
77+
78+
data := FileReadBytes(Self.Dialog.FileName);
79+
name := PathExtractName(Self.Dialog.FileName);
80+
writer.Add(name, @data[0], Length(data));
81+
82+
Self.Reader.Unload();
83+
Self.Reader.Destroy();
84+
FileDelete(Self.SelectedResource.Text);
85+
writer.Save(Self.SelectedResource.Text);
86+
Self.Reader := new TResourceReader(Self.SelectedResource.Text);
87+
Self.FileList.Items.Add(name);
88+
Self.FileList.ItemIndex := Self.FileList.Count-1;
89+
end;
90+
91+
procedure TResourceEditor.OnAddImageClick(sender: TLazObject);
92+
var
93+
writer: TResourceWriter;
94+
name: String;
95+
i: Integer;
96+
data: TByteArray;
97+
img: TImage;
98+
begin
99+
if not Self.Dialog.Execute() then
100+
Exit;
101+
102+
writer := new TResourceWriter();
103+
for i := 0 to Self.Reader.Count-1 do
104+
begin
105+
data := Self.Reader.Load(i);
106+
writer.Add(Self.Reader.Name[i], @data[0], Length(data));
107+
end;
108+
109+
img := new TImage(Self.Dialog.FileName);
110+
name := PathExtractName(Self.Dialog.FileName);
111+
writer.AddImage(name, img);
112+
113+
Self.Reader.Unload();
114+
Self.Reader.Destroy();
115+
FileDelete(Self.SelectedResource.Text);
116+
writer.Save(Self.SelectedResource.Text);
117+
Self.Reader := new TResourceReader(Self.SelectedResource.Text);
118+
Self.FileList.Items.Add(name);
119+
Self.FileList.ItemIndex := Self.FileList.Count-1;
120+
end;
121+
122+
procedure TResourceEditor.OnRemoveClick(sender: TLazObject);
123+
var
124+
idx, i: Integer;
125+
writer: TResourceWriter;
126+
data: TByteArray;
127+
begin
128+
idx := Self.FileList.ItemIndex;
129+
if idx < 0 then Exit;
130+
131+
Self.FileList.Items.Delete(idx);
132+
writer := new TResourceWriter();
133+
134+
for i := 0 to Self.Reader.Count-1 do
135+
begin
136+
if i = idx then Continue;
137+
data := Self.Reader.Load(i);
138+
writer.Add(Self.Reader.Name[i], @data[0], Length(data));
139+
end;
140+
141+
Self.Reader.Unload();
142+
Self.Reader.Destroy();
143+
FileDelete(Self.SelectedResource.Text);
144+
writer.Save(Self.SelectedResource.Text);
145+
Self.Reader := new TResourceReader(Self.SelectedResource.Text);
146+
end;
147+
148+
procedure TResourceEditor.OnSelectionChange(sender: TLazObject; user: Boolean);
149+
var
150+
i: Integer;
151+
data: TByteArray;
152+
begin
153+
i := TLazListBox(sender).ItemIndex;
154+
try
155+
Self.FileImage.SetImage(Self.Reader.LoadImage(i));
156+
except
157+
end;
158+
159+
data := Self.Reader.Load(i);
160+
161+
Self.FileData.Text := ToStr(data);
162+
163+
case Self.Reader.CompressAlgo[i] of
164+
0: Self.CompressionAlgo.Text := 'None';
165+
1: Self.CompressionAlgo.Text := 'SynLZ';
166+
2: Self.CompressionAlgo.Text := 'RleSynLZ';
167+
end;
168+
169+
Self.CompressedSize.Text := ToStr(Self.Reader.CompressedSize[i]);
170+
Self.Uncompressed.Text := ToStr(Self.Reader.UncompressedSize[i]);
171+
end;
172+
{$H+}
173+
174+
var
175+
Editor: TResourceEditor;
176+
openBtn, addFileBtn, addImgBtn, removeBtn: TLazButton;
177+
i: Integer;
178+
begin
179+
for i := 0 to 255 do
180+
HEX_TABLE += IntToHex(i, 2);
181+
Editor.Dialog := TLazOpenDialog.Create(nil);
182+
Editor.Dialog.Width := 600;
183+
Editor.Dialog.Height := 800;
184+
Editor.Dialog.DefaultExt := '.bin';
185+
Editor.Dialog.InitialDir := Map.Loader.CacheDir;
186+
Editor.Dialog.Options := [ELazOpenFileOptions.ShowHelp, ELazOpenFileOptions.ExtensionDifferent, ELazOpenFileOptions.FileMustExist];
187+
188+
Editor.Form := TLazForm.Create();
189+
Editor.Form.Caption := 'Resource Editor';
190+
Editor.Form.Height := 600;
191+
Editor.Form.Width := 800;
192+
Editor.Form.Position := ELazFormPosition.ScreenCenter;
193+
194+
Editor.FileList := TLazListBox.CreateEx(Editor.Form, 'Compressed files:', 'Files stored in the resource file.', 20, 60, 220, Editor.Form.Height - 120);
195+
Editor.FileList.OnSelectionChange := @Editor.OnSelectionChange;
196+
197+
openBtn := TLazButton.CreateEx(Editor.Form, 'Open .bin file', 'Open a resource file.', Editor.Form.Width div 2 - 120, Editor.FileList.Top + 20, 200);
198+
openBtn.OnClick := @Editor.OnOpenClick;
199+
200+
Editor.SelectedResource := TLazEdit.CreateEx(Editor.Form, 'Selected resource:', 'Name of the currently selected resource file.', openBtn.Left, openBtn.Bottom + 20, 200);
201+
Editor.SelectedResource.ReadOnly := True;
202+
203+
addFileBtn := TLazButton.CreateEx(Editor.Form, 'Add file', 'Adds and compresses a file into the resource file.', Editor.SelectedResource.Left, Editor.SelectedResource.Bottom + 80, 200);
204+
addFileBtn.OnClick := @Editor.OnAddFileClick;
205+
206+
addImgBtn := TLazButton.CreateEx(Editor.Form, 'Add image', 'Adds and compresses an image into the resource file.', addFileBtn.Left, addFileBtn.Bottom + 10, 200);
207+
addImgBtn.OnClick := @Editor.OnAddImageClick;
208+
209+
removeBtn := TLazButton.CreateEx(Editor.Form, 'Remove selected', 'Removes the selected file from the resource file.', addImgBtn.Left, addImgBtn.Bottom + 10, 200);
210+
removeBtn.OnClick := @Editor.OnRemoveClick;
211+
212+
Editor.CompressionAlgo := TLazEdit.CreateEx(Editor.Form, 'Compression algorithm:', 'Compression algorithm used on this file', removeBtn.Left, removeBtn.Bottom + 80, 200);
213+
Editor.CompressionAlgo.ReadOnly := True;
214+
215+
Editor.CompressedSize := TLazEdit.CreateEx(Editor.Form, 'Compressed size:', 'Compressed file size', Editor.CompressionAlgo.Left, Editor.CompressionAlgo.Bottom + 20, 200);
216+
Editor.CompressedSize.ReadOnly := True;
217+
218+
Editor.Uncompressed := TLazEdit.CreateEx(Editor.Form, 'Original size:', 'Original file size', Editor.CompressedSize.Left, Editor.CompressedSize.Bottom + 20, 200);
219+
Editor.Uncompressed.ReadOnly := True;
220+
221+
Editor.FileImage := TImageBox.CreateEx(Editor.Form, 'Image viewer:', 'View the file data as a TImage', Editor.Form.Width - 280, 60, 260, 260);
222+
Editor.FileData := TLazMemo.CreateEx(Editor.Form, 'File data:', 'View the file bytes', Editor.FileImage.Left, Editor.FileImage.Bottom + 20, 260, 200);
223+
Editor.FileData.Font.Name := 'Courier New';
224+
Editor.FileData.ReadOnly := True;
225+
226+
Editor.Form.ShowModal();
227+
end.

tools/videoplayer.simba

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
(*
2-
# VideoPlayer
2+
(Video Player)=
3+
# Tool: Video Player
34
Displays image sequences rapidly to create smooth motion, like a flipbook.
45
Works with image frame sequences (not video files) and provides interactive controls.
56

wasplib-docs

0 commit comments

Comments
 (0)