Compare commits
10 Commits
ea282171fc
...
fcf3cced80
Author | SHA1 | Date | |
---|---|---|---|
fcf3cced80 | |||
dce6603c58 | |||
0b26e93322 | |||
1b121f1b90 | |||
5893615589 | |||
61d3ceff70 | |||
ec711d9c16 | |||
12d1f47abd | |||
7a092d28fe | |||
40c09c36a6 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
*.mpq
|
||||
.ccls-cache
|
||||
asset
|
||||
imgui.ini
|
||||
*.mpq
|
||||
|
27
LICENSE
27
LICENSE
@ -1,21 +1,18 @@
|
||||
MIT License
|
||||
Copyright 2018-2019 Alex Yatskov
|
||||
|
||||
Copyright (c) 2018 Alex Yatskov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
81
README.md
81
README.md
@ -1,55 +1,55 @@
|
||||
# Lazarus #
|
||||
# Lazarus
|
||||
|
||||
The Lazarus project aims to preserve [Diablo II](https://en.wikipedia.org/wiki/Diablo_II) by reimplementing the game
|
||||
engine in the Go programming language. Lazarus is a drop-in replacement for the original game executable; the user is
|
||||
responsible for supplying the game assets (namely the MPQ files) from the official game media.
|
||||
|
||||
![](https://foosoft.net/projects/lazarus/img/viewer.png)
|
||||
![](img/viewer.png)
|
||||
|
||||
## Building ##
|
||||
## Building
|
||||
|
||||
It is not currently possible to use `go get` to install all of the packages in the project in one step; some assembly is
|
||||
required. Follow the instructions below to set up a build environment from a fresh install of your 64-bit operating
|
||||
system of choice.
|
||||
|
||||
### Linux ###
|
||||
### Linux
|
||||
|
||||
Lazarus is primarily being developed on Fedora, but the required package names are also provided for Ubuntu.
|
||||
|
||||
1. Install the required packages (for [Fedora](https://getfedora.org/) users):
|
||||
```
|
||||
# sudo dnf install golang gcc-c++ cmake make git SDL2-devel mesa-libGL-devel zlib-devel bzip2-devel
|
||||
sudo dnf install golang gcc-c++ cmake make git SDL2-devel mesa-libGL-devel zlib-devel bzip2-devel
|
||||
```
|
||||
Install the required packages (for [Ubuntu](https://www.ubuntu.com/) users):
|
||||
```
|
||||
# sudo apt-get install golang g++ cmake make git libsdl2-dev libgl1-mesa-dev zlib1g-dev libbz2-dev
|
||||
sudo apt-get install golang g++ cmake make git libsdl2-dev libgl1-mesa-dev zlib1g-dev libbz2-dev
|
||||
```
|
||||
2. Build the [Dear ImGui](https://github.com/ocornut/imgui) wrapper package:
|
||||
```
|
||||
$ go get github.com/FooSoft/lazarus/platform/imgui
|
||||
go get github.com/FooSoft/lazarus/platform/imgui
|
||||
```
|
||||
Go will fetch the code, but Cgo will fail to link the [cimgui](https://github.com/cimgui/cimgui) wrapper;
|
||||
we need to configure and build it:
|
||||
```
|
||||
$ cd $GOPATH/src/github.com/FooSoft/lazarus/platform/imgui/cimgui
|
||||
$ cmake -DIMGUI_STATIC="yes" .
|
||||
$ make
|
||||
cd $GOPATH/src/github.com/FooSoft/lazarus/platform/imgui/cimgui
|
||||
cmake -DIMGUI_STATIC="yes" .
|
||||
make
|
||||
```
|
||||
You should now have a `cimgui.a` statically linked library in the `cimgui` directory.
|
||||
3. Build the [StormLib](http://zezula.net/en/mpq/stormlib.html) wrapper package:
|
||||
```
|
||||
$ go get github.com/FooSoft/lazarus/formats/mpq
|
||||
go get github.com/FooSoft/lazarus/formats/mpq
|
||||
```
|
||||
Go will fetch the code, but Cgo will fail to link the StormLib wrapper;
|
||||
we need to configure and build it:
|
||||
```
|
||||
$ cd $GOPATH/src/github.com/FooSoft/lazarus/formats/mpq/stormlib
|
||||
$ cmake .
|
||||
$ make
|
||||
cd $GOPATH/src/github.com/FooSoft/lazarus/formats/mpq/stormlib
|
||||
cmake .
|
||||
make
|
||||
```
|
||||
You should now have a `libstorm.a` statically linked library in the `stormlib` directory.
|
||||
|
||||
### Windows ###
|
||||
### Windows
|
||||
|
||||
Lazarus is only tested on Windows 10, but should in theory run on anything newer than Windows XP.
|
||||
|
||||
@ -57,47 +57,47 @@ Lazarus is only tested on Windows 10, but should in theory run on anything newer
|
||||
2. Download and the latest 64-bit EXE installer for MSYS2 from the [official homepage](https://www.msys2.org/); install to the default directory.
|
||||
3. Install the required packages (using the MSYS MinGW terminal):
|
||||
```
|
||||
$ pacman -S mingw-w64-x86_64-gcc cmake make git mingw-w64-x86_64-SDL2 zlib-devel libbz2-devel
|
||||
pacman -S mingw-w64-x86_64-gcc cmake make git mingw-w64-x86_64-SDL2 zlib-devel libbz2-devel
|
||||
```
|
||||
4. Add `C:\msys64\usr\bin` and `C:\msys64\mingw64\bin` to your system's `PATH` environment variable.
|
||||
5. Build the [Dear ImGui](https://github.com/ocornut/imgui) wrapper package (using the system command prompt):
|
||||
```
|
||||
$ go get github.com/FooSoft/lazarus/platform/imgui
|
||||
go get github.com/FooSoft/lazarus/platform/imgui
|
||||
```
|
||||
Go will fetch the code, but Cgo will fail to link the [cimgui](https://github.com/cimgui/cimgui) wrapper;
|
||||
we need to configure and build it:
|
||||
```
|
||||
$ cd %GOPATH%/src/github.com/FooSoft/lazarus/platform/imgui/cimgui
|
||||
$ cmake -DIMGUI_STATIC="yes" .
|
||||
$ make
|
||||
cd %GOPATH%/src/github.com/FooSoft/lazarus/platform/imgui/cimgui
|
||||
cmake -DIMGUI_STATIC="yes" .
|
||||
make
|
||||
```
|
||||
You should now have a `cimgui.a` statically linked library in the `cimgui` directory.
|
||||
6. Build the [StormLib](http://zezula.net/en/mpq/stormlib.html) wrapper package (using the system command prompt):
|
||||
```
|
||||
$ go get github.com/FooSoft/lazarus/formats/mpq
|
||||
go get github.com/FooSoft/lazarus/formats/mpq
|
||||
```
|
||||
Go will fetch the code, but Cgo will fail to link the StormLib wrapper;
|
||||
we need to configure and build it:
|
||||
```
|
||||
$ cd %GOPATH%/src/github.com/FooSoft/lazarus/formats/mpq/stormlib
|
||||
$ cmake .
|
||||
$ make
|
||||
cd %GOPATH%/src/github.com/FooSoft/lazarus/formats/mpq/stormlib
|
||||
cmake .
|
||||
make
|
||||
```
|
||||
You should now have a `libstorm.a` statically linked library in the `stormlib` directory.
|
||||
|
||||
## Tools ##
|
||||
## Tools
|
||||
|
||||
This project includes several tools which are used to demonstrate the capabilities of the engine as well as manipulate
|
||||
game data for debugging purposes. Make sure to perform the setup steps outlined in the "Building" section before
|
||||
installing these packages.
|
||||
|
||||
### `dc6` ###
|
||||
### `dc6`
|
||||
|
||||
Converts the frames of one or more DC6 animations to PNG files, using the provided palette file.
|
||||
|
||||
* Installation:
|
||||
```
|
||||
$ go get github.com/FooSoft/lazarus/tools/dc6
|
||||
go get github.com/FooSoft/lazarus/tools/dc6
|
||||
```
|
||||
* Usage:
|
||||
```
|
||||
@ -108,13 +108,13 @@ Converts the frames of one or more DC6 animations to PNG files, using the provid
|
||||
target directory (default ".")
|
||||
```
|
||||
|
||||
### `mpq` ###
|
||||
### `mpq`
|
||||
|
||||
Extracts the contents of one or more MPQ archives to a target directory, using an optional filter.
|
||||
|
||||
* Installation:
|
||||
```
|
||||
$ go get github.com/FooSoft/lazarus/tools/mpq
|
||||
go get github.com/FooSoft/lazarus/tools/mpq
|
||||
```
|
||||
* Usage:
|
||||
```
|
||||
@ -127,14 +127,14 @@ Extracts the contents of one or more MPQ archives to a target directory, using a
|
||||
target directory (default ".")
|
||||
```
|
||||
|
||||
### `viewer` ###
|
||||
### `viewer`
|
||||
|
||||
Displays the frames of DC6 animation files, using the provided palette file. A grayscale fallback palette is used if no
|
||||
palette is provided on the command line.
|
||||
|
||||
* Installation:
|
||||
```
|
||||
$ go get github.com/FooSoft/lazarus/tools/viewer
|
||||
go get github.com/FooSoft/lazarus/tools/viewer
|
||||
```
|
||||
* Usage:
|
||||
```
|
||||
@ -144,22 +144,3 @@ palette is provided on the command line.
|
||||
-palette string
|
||||
path to palette file
|
||||
```
|
||||
|
||||
## License ##
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
type Sprite struct {
|
||||
}
|
||||
|
||||
type bounds struct {
|
||||
type box struct {
|
||||
x1 int
|
||||
y1 int
|
||||
x2 int
|
||||
|
@ -2,6 +2,7 @@ package dcc
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/FooSoft/lazarus/streaming"
|
||||
)
|
||||
@ -19,13 +20,7 @@ type directionHeader struct {
|
||||
CodedBytesBits uint8
|
||||
}
|
||||
|
||||
type direction struct {
|
||||
header directionHeader
|
||||
frames []frame
|
||||
bounds bounds
|
||||
}
|
||||
|
||||
func readDirectionHeader(bitReader *streaming.BitReader) directionHeader {
|
||||
func readDirectionHeader(bitReader *streaming.BitReader) (*directionHeader, error) {
|
||||
var dirHead directionHeader
|
||||
|
||||
dirHead.CodedSize = uint32(bitReader.ReadUint(32))
|
||||
@ -39,73 +34,57 @@ func readDirectionHeader(bitReader *streaming.BitReader) directionHeader {
|
||||
dirHead.OptionalBytesBits = uint8(bitReader.ReadUint(4))
|
||||
dirHead.CodedBytesBits = uint8(bitReader.ReadUint(4))
|
||||
|
||||
return dirHead
|
||||
if err := bitReader.Error(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dirHead, nil
|
||||
}
|
||||
|
||||
func readDirection(reader io.ReadSeeker, fileHead fileHeader) (*direction, error) {
|
||||
bitReader := streaming.NewBitReader(reader)
|
||||
|
||||
dirHead := readDirectionHeader(bitReader)
|
||||
if err := bitReader.Error(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
frameHeads, err := readFrameHeaders(bitReader, fileHead, dirHead)
|
||||
dirHead, err := readDirectionHeader(bitReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var dirData direction
|
||||
for i, frameHead := range frameHeads {
|
||||
frameData := frame{
|
||||
header: frameHead,
|
||||
bounds: bounds{
|
||||
x1: int(frameHead.OffsetX),
|
||||
y1: int(frameHead.OffsetY) - int(frameHead.Height) + 1,
|
||||
x2: int(frameHead.OffsetX) + int(frameHead.Width),
|
||||
y2: int(frameHead.OffsetY) + 1,
|
||||
},
|
||||
frameHeads, dirBounds, err := readFrameHeaders(bitReader, fileHead, *dirHead)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dirData.frames = append(dirData.frames, frameData)
|
||||
|
||||
if i == 0 {
|
||||
dirData.bounds = frameData.bounds
|
||||
} else {
|
||||
if dirData.bounds.x1 > frameData.bounds.x1 {
|
||||
dirData.bounds.x1 = frameData.bounds.x1
|
||||
}
|
||||
if dirData.bounds.y1 > frameData.bounds.y1 {
|
||||
dirData.bounds.y1 = frameData.bounds.y1
|
||||
}
|
||||
if dirData.bounds.x2 < frameData.bounds.x2 {
|
||||
dirData.bounds.x2 = frameData.bounds.x2
|
||||
}
|
||||
if dirData.bounds.y2 < frameData.bounds.y2 {
|
||||
dirData.bounds.y2 = frameData.bounds.y2
|
||||
}
|
||||
}
|
||||
dirData := direction{bounds: dirBounds}
|
||||
for _, frameHead := range frameHeads {
|
||||
dirData.frames = append(dirData.frames, newFrame(frameHead, dirBounds))
|
||||
}
|
||||
|
||||
var entries []pixelBufferEntry
|
||||
|
||||
entries, err = decodeDirectionStage1(bitReader, &dirData, entries)
|
||||
entries, err = dirData.decodeStage1(bitReader, entries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
entries, err = decodeDirectionStage2(bitReader, &dirData, entries)
|
||||
entries, err = dirData.decodeStage2(bitReader, entries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Println(dirData.bounds)
|
||||
return &dirData, nil
|
||||
}
|
||||
|
||||
func decodeDirectionStage1(bitReader *streaming.BitReader, dirData *direction, entries []pixelBufferEntry) ([]pixelBufferEntry, error) {
|
||||
type direction struct {
|
||||
header directionHeader
|
||||
frames []frame
|
||||
bounds box
|
||||
}
|
||||
|
||||
func (d *direction) decodeStage1(bitReader *streaming.BitReader, entries []pixelBufferEntry) ([]pixelBufferEntry, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func decodeDirectionStage2(bitReader *streaming.BitReader, dirData *direction, entries []pixelBufferEntry) ([]pixelBufferEntry, error) {
|
||||
func (d *direction) decodeStage2(bitReader *streaming.BitReader, entries []pixelBufferEntry) ([]pixelBufferEntry, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -17,12 +17,7 @@ type frameHeader struct {
|
||||
FrameBottomUp bool
|
||||
}
|
||||
|
||||
type frame struct {
|
||||
header frameHeader
|
||||
bounds bounds
|
||||
}
|
||||
|
||||
func readFrameHeader(bitReader *streaming.BitReader, dirHead directionHeader) frameHeader {
|
||||
func readFrameHeader(bitReader *streaming.BitReader, dirHead directionHeader) (*frameHeader, error) {
|
||||
var frameHead frameHeader
|
||||
|
||||
frameHead.Variable0 = uint32(bitReader.ReadUintPacked(int(dirHead.Variable0Bits)))
|
||||
@ -34,13 +29,6 @@ func readFrameHeader(bitReader *streaming.BitReader, dirHead directionHeader) fr
|
||||
frameHead.CodedBytes = uint32(bitReader.ReadUintPacked(int(dirHead.CodedBytesBits)))
|
||||
frameHead.FrameBottomUp = bitReader.ReadBool()
|
||||
|
||||
return frameHead
|
||||
}
|
||||
|
||||
func readFrameHeaders(bitReader *streaming.BitReader, fileHead fileHeader, dirHead directionHeader) ([]frameHeader, error) {
|
||||
var frameHeads []frameHeader
|
||||
for i := 0; i < int(fileHead.FramesPerDir); i++ {
|
||||
frameHead := readFrameHeader(bitReader, dirHead)
|
||||
if err := bitReader.Error(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -57,8 +45,133 @@ func readFrameHeaders(bitReader *streaming.BitReader, fileHead fileHeader, dirHe
|
||||
return nil, errors.New("invalid frame dimensions")
|
||||
}
|
||||
|
||||
frameHeads = append(frameHeads, frameHead)
|
||||
return &frameHead, nil
|
||||
}
|
||||
|
||||
func (h *frameHeader) bounds() box {
|
||||
return box{
|
||||
x1: int(h.OffsetX),
|
||||
y1: int(h.OffsetY) - int(h.Height) + 1,
|
||||
x2: int(h.OffsetX) + int(h.Width),
|
||||
y2: int(h.OffsetY) + 1,
|
||||
}
|
||||
}
|
||||
|
||||
func readFrameHeaders(bitReader *streaming.BitReader, fileHead fileHeader, dirHead directionHeader) ([]frameHeader, box, error) {
|
||||
var (
|
||||
frameHeads []frameHeader
|
||||
boundsAll box
|
||||
)
|
||||
|
||||
for i := 0; i < int(fileHead.FramesPerDir); i++ {
|
||||
frameHead, err := readFrameHeader(bitReader, dirHead)
|
||||
if err != nil {
|
||||
return nil, box{}, err
|
||||
}
|
||||
|
||||
return frameHeads, nil
|
||||
bounds := frameHead.bounds()
|
||||
if i == 0 {
|
||||
boundsAll = bounds
|
||||
} else {
|
||||
if boundsAll.x1 > bounds.x1 {
|
||||
boundsAll.x1 = bounds.x1
|
||||
}
|
||||
if boundsAll.y1 > bounds.y1 {
|
||||
boundsAll.y1 = bounds.y1
|
||||
}
|
||||
if boundsAll.x2 < bounds.x2 {
|
||||
boundsAll.x2 = bounds.x2
|
||||
}
|
||||
if boundsAll.y2 < bounds.y2 {
|
||||
boundsAll.y2 = bounds.y2
|
||||
}
|
||||
}
|
||||
|
||||
frameHeads = append(frameHeads, *frameHead)
|
||||
}
|
||||
|
||||
return frameHeads, boundsAll, nil
|
||||
}
|
||||
|
||||
type frame struct {
|
||||
header frameHeader
|
||||
|
||||
nbCellsX int
|
||||
nbCellsY int
|
||||
dirOffsetX int
|
||||
dirOffsetY int
|
||||
|
||||
cellSameAsPrevious []bool
|
||||
cellWidths []int
|
||||
cellHeights []int
|
||||
|
||||
data []byte
|
||||
}
|
||||
|
||||
func newFrame(frameHead frameHeader, dirBounds box) frame {
|
||||
frameBounds := frameHead.bounds()
|
||||
|
||||
frameData := frame{
|
||||
header: frameHead,
|
||||
dirOffsetX: frameBounds.x1 - dirBounds.x1,
|
||||
dirOffsetY: frameBounds.y1 - dirBounds.y1,
|
||||
}
|
||||
|
||||
widthFirstColumn := 4 - frameData.dirOffsetX%4
|
||||
frameWidth := frameBounds.x2 - frameBounds.x1
|
||||
if frameWidth-widthFirstColumn <= 1 {
|
||||
frameData.nbCellsX = 1
|
||||
} else {
|
||||
temp := frameWidth - widthFirstColumn - 1
|
||||
frameData.nbCellsX = 2 + temp/4
|
||||
if temp%4 == 0 {
|
||||
frameData.nbCellsX--
|
||||
}
|
||||
}
|
||||
|
||||
heightFirstRow := 4 - frameData.dirOffsetY%4
|
||||
frameHeight := frameBounds.y2 - frameBounds.y1
|
||||
if frameHeight-heightFirstRow <= 1 {
|
||||
frameData.nbCellsY = 1
|
||||
} else {
|
||||
temp := frameHeight - heightFirstRow - 1
|
||||
frameData.nbCellsY = 2 + temp/4
|
||||
if temp%4 == 0 {
|
||||
frameData.nbCellsY--
|
||||
}
|
||||
}
|
||||
|
||||
frameData.cellWidths = make([]int, frameData.nbCellsX)
|
||||
for i := range frameData.cellWidths {
|
||||
frameData.cellWidths[i] = 4
|
||||
}
|
||||
|
||||
if frameData.nbCellsX == 1 {
|
||||
frameData.cellWidths[0] = frameWidth
|
||||
} else {
|
||||
frameData.cellWidths[0] = widthFirstColumn
|
||||
nbColumnsExcludingFirstAndLast := frameData.nbCellsX - 2
|
||||
widthExcludingFirstAndLastColumns := 4 * nbColumnsExcludingFirstAndLast
|
||||
frameData.cellWidths[frameData.nbCellsX-1] = frameWidth - (widthFirstColumn + widthExcludingFirstAndLastColumns)
|
||||
}
|
||||
|
||||
frameData.cellHeights = make([]int, frameData.nbCellsY)
|
||||
for i := range frameData.cellHeights {
|
||||
frameData.cellHeights[i] = 4
|
||||
}
|
||||
|
||||
if frameData.nbCellsY == 1 {
|
||||
frameData.cellHeights[0] = frameHeight
|
||||
} else {
|
||||
frameData.cellHeights[0] = heightFirstRow
|
||||
nbRowsExcludingFirstAndLast := frameData.nbCellsY - 2
|
||||
heightExcludingFirstAndLastRows := 4 * nbRowsExcludingFirstAndLast
|
||||
frameData.cellHeights[frameData.nbCellsY-1] = frameHeight - (heightFirstRow + heightExcludingFirstAndLastRows)
|
||||
}
|
||||
|
||||
frameData.cellSameAsPrevious = make([]bool, frameData.nbCellsX*frameData.nbCellsY)
|
||||
frameData.data = make([]byte, frameWidth*frameHeight)
|
||||
|
||||
return frameData
|
||||
|
||||
}
|
||||
|
BIN
img/viewer.png
Normal file
BIN
img/viewer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
@ -44,7 +44,7 @@ func FileMountArchive(mountPath, archivePath string) error {
|
||||
func FileUnmountArchive(mountPath string) error {
|
||||
archive, ok := fileState.mountPoints[mountPath]
|
||||
if !ok {
|
||||
return errors.New("file archive is nout mounted")
|
||||
return errors.New("file archive is not mounted")
|
||||
}
|
||||
|
||||
var paths []string
|
||||
|
Loading…
Reference in New Issue
Block a user