├── .github
└── workflows
│ └── build.yaml
├── .gitignore
├── .idea
├── .gitignore
├── modules.xml
├── pobfrontend.iml
└── vcs.xml
├── Info.plist
├── Info.plist.sh
├── LICENSE
├── Makefile
├── Makefile.linux
├── README.md
├── editLuaCurlMakefile.sh
├── editPathOfBuildingBuild.sh
├── fonts
├── Bitstream Vera License.txt
├── LiberationSans-Bold.ttf
├── LiberationSans-Regular.ttf
├── SIL Open Font License.txt
└── VeraMono.ttf
├── main.cpp
├── main.h
├── meson.build
├── mesonInstaller.sh
├── pobLogo.icns
├── pobWrapper.sh
├── pobwindow.hpp
└── subscript.hpp
/.github/workflows/build.yaml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | pull_request:
7 | branches: [ "master" ]
8 | schedule:
9 | - cron: '30 13 * * *'
10 |
11 | jobs:
12 | build:
13 |
14 | runs-on: macos-12
15 |
16 | steps:
17 | - uses: actions/checkout@v3
18 | - run: brew install make ninja
19 | - run: make tools
20 | - run: make clean
21 | - run: make
22 | - run: zip -r PathOfBuilding.zip PathOfBuilding.app
23 |
24 | # Based on https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter
25 | - id: get-version
26 | run: |
27 | version=$(sed -n 's/^.*number="\([0-9.]*\)".*$/\1/p' PathOfBuilding/manifest.xml)
28 | echo "VERSION=$version" >> "$GITHUB_OUTPUT"
29 | - name: Upload MacOS artifacts into Github
30 | uses: ncipollo/release-action@v1
31 | with:
32 | artifacts: "PathOfBuilding.zip"
33 | token: ${{ secrets.GITHUB_TOKEN }}
34 | allowUpdates: true
35 | tag: v${{ steps.get-version.outputs.VERSION }}
36 | if: github.ref == 'refs/heads/master'
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lcurl.so
2 | Lua-cURLv3
3 | /PathOfBuilding
4 | /PathOfBuildingBuild
5 | /PathOfBuilding.app
6 | /PathOfBuilding.*
7 | .DS_Store
8 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/pobfrontend.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleExecutable
6 | PathOfBuilding
7 | CFBundleGetInfoString
8 | Created by Qt/QMake
9 | CFBundleIconFile
10 | pobLogo.icns
11 | CFBundleIdentifier
12 | com.yourcompany.PathOfBuilding
13 | CFBundleName
14 | PathOfBuilding
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | LSMinimumSystemVersion
22 | 10.11
23 | NOTE
24 | This file was generated by Qt/QMake.
25 | NSPrincipalClass
26 | NSApplication
27 | NSHighResolutionCapable
28 |
29 | NSSupportsAutomaticGraphicsSwitching
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Info.plist.sh:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleExecutable
6 | pobWrapper.sh
7 | CFBundleGetInfoString
8 | Created by Qt/QMake
9 | CFBundleIconFile
10 | pobLogo.icns
11 | CFBundleIdentifier
12 | com.yourcompany.PathOfBuilding
13 | CFBundleName
14 | PathOfBuilding
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | LSMinimumSystemVersion
22 | 10.11
23 | NOTE
24 | This file was generated by Qt/QMake.
25 | NSPrincipalClass
26 | NSApplication
27 | NSHighResolutionCapable
28 |
29 | NSSupportsAutomaticGraphicsSwitching
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Phil Roberts
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | DIR := ${CURDIR}
2 | export PATH := /usr/local/opt/qt@5/bin:$(PATH)
3 | # Some users on old versions of MacOS 10.13 run into the error:
4 | # dyld: cannot load 'PathOfBuilding' (load command 0x80000034 is unknown)
5 | #
6 | # It looks like 0x80000034 is associated with the fixup_chains optimization
7 | # that improves startup time:
8 | # https://www.emergetools.com/blog/posts/iOS15LaunchTime
9 | #
10 | # For compatibility, we disable that using the flag from this thread:
11 | # https://github.com/python/cpython/issues/97524
12 | export LDFLAGS := -L/usr/local/opt/qt@5/lib -Wl,-no_fixup_chains
13 | export CPPFLAGS := -I/usr/local/opt/qt@5/include
14 | export PKG_CONFIG_PATH := /usr/local/opt/qt@5/lib/pkgconfig
15 |
16 | all: frontend pob
17 | pushd build; \
18 | ninja install; \
19 | popd; \
20 | macdeployqt ${DIR}/PathOfBuilding.app; \
21 | cp ${DIR}/Info.plist.sh ${DIR}/PathOfBuilding.app/Contents/Info.plist; \
22 | echo 'Finished'
23 |
24 | pob: load_pob luacurl frontend
25 | rm -rf PathOfBuildingBuild; \
26 | cp -rf PathOfBuilding PathOfBuildingBuild; \
27 | pushd PathOfBuildingBuild; \
28 | bash ../editPathOfBuildingBuild.sh; \
29 | popd
30 |
31 | frontend:
32 | arch=x86_64 meson -Dbuildtype=release --prefix=${DIR}/PathOfBuilding.app --bindir=Contents/MacOS build
33 |
34 | # We checkout the latest version.
35 | load_pob:
36 | git clone https://github.com/PathOfBuildingCommunity/PathOfBuilding.git; \
37 | pushd PathOfBuilding; \
38 | git fetch; \
39 | git add . && git reset --hard HEAD && git checkout $$(git describe --tags $$(git rev-list --tags --max-count=1)); \
40 | popd
41 |
42 | luacurl:
43 | git clone --depth 1 https://github.com/Lua-cURL/Lua-cURLv3.git; \
44 | bash editLuaCurlMakefile.sh; \
45 | pushd Lua-cURLv3; \
46 | make; \
47 | mv lcurl.so ../lcurl.so; \
48 | popd
49 |
50 | # curl is used since mesonInstaller.sh copies over the shared library dylib
51 | # dylibbundler is used to copy over dylibs that lcurl.so uses
52 | tools:
53 | arch --x86_64 brew install qt@5 luajit zlib meson curl dylibbundler gcc@12
54 |
55 | # We don't usually modify the PathOfBuilding directory, so there's rarely a
56 | # need to delete it. We separate it out to a separate task.
57 | fullyclean: clean
58 | rm -rf PathOfBuilding
59 |
60 | clean:
61 | rm -rf PathOfBuildingBuild PathOfBuilding.app Lua-cURLv3 lcurl.so build
62 |
--------------------------------------------------------------------------------
/Makefile.linux:
--------------------------------------------------------------------------------
1 | DIR := ${CURDIR}
2 | SHELL = /bin/bash
3 |
4 | all: frontend pob
5 | pushd build; \
6 | ninja; \
7 | popd; \
8 | mv build/PathOfBuilding PathOfBuilding/src; \
9 | echo 'Finished'
10 |
11 | pob: load_pob luacurl frontend
12 | pushd PathOfBuilding; \
13 | unzip runtime-win32.zip lua/xml.lua lua/base64.lua lua/sha1.lua; \
14 | mv lua/*.lua src/; \
15 | rmdir lua; \
16 | cp ../lcurl.so src/; \
17 | popd
18 |
19 | frontend:
20 | meson -Dbuildtype=release build
21 |
22 | load_pob:
23 | git clone --depth 1 https://github.com/PathOfBuildingCommunity/PathOfBuilding.git; \
24 | pushd PathOfBuilding; \
25 | rm -rf .git; \
26 | popd
27 |
28 | luacurl:
29 | git clone --depth 1 https://github.com/Lua-cURL/Lua-cURLv3.git; \
30 | pushd Lua-cURLv3; \
31 | sed -i -e's/\?= lua/\?= luajit/' Makefile; \
32 | make; \
33 | mv lcurl.so ../lcurl.so; \
34 | popd
35 |
36 | tools: qt lua zlib meson
37 |
38 | qt:
39 | sudo apt -y install qt5-default; \
40 | sudo apt -y install qtcreator
41 |
42 | lua:
43 | sudo apt -y install luajit; \
44 | sudo apt -y install libluajit-5.1-dev
45 |
46 | zlib:
47 | sudo apt -y install zlib1g; \
48 | sudo apt -y install zlib1g-dev
49 |
50 | meson:
51 | sudo apt -y install meson
52 |
53 | clean:
54 | rm -rf PathOfBuilding Lua-cURLv3 lcurl.so build
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | PoBFrontend
2 | ===========
3 |
4 | A cross-platform [Path of Building](https://github.com/Openarl/PathOfBuilding) driver.
5 |
6 | Building
7 | --------
8 |
9 | ### Steps to build an x86_64 binary on M1 Macs
10 |
11 | Before starting, you need to install Homebrew for x86_64.
12 |
13 | 1. Install Rosetta if you haven't via `softwareupdate --install-rosetta`
14 | 2. Run the [Homebrew installation command](https://docs.brew.sh/Installation),
15 | but prepend `arch --x86_64`. The command will be `arch --x86_64 bash -c ...`
16 | 3. Create a `~/.intelbrew` file with these contents:
17 | ```sh
18 | eval "$(/usr/local/bin/brew shellenv)"
19 | alias brew='arch --x86_64 /usr/local/bin/brew'
20 | ```
21 | 4. Include it to update your environment variables by running `. ~/.intelbrew`
22 | 5. Edit Homebrew to fetch packages for Ventura (10.13), since the Qt package
23 | for Sonoma (10.14) breaks compatibility with libc++: see [this error](https://www.pathofexile.com/forum/view-thread/3009944/page/34#:~:text=__ZTVNSt3__13pmr25monotonic_buffer_resourceE)
24 |
25 | ```sh
26 | vim /usr/local/Homebrew/Library/Homebrew/brew.sh
27 | # Edit the file to comment out the version and hardcode it:
28 | # #HOMEBREW_MACOS_VERSION="$(/usr/bin/sw_vers -productVersion)"
29 | # HOMEBREW_MACOS_VERSION="12.0.0"
30 |
31 | # Run this only once after installing Homebrew to install dependencies
32 | make tools
33 |
34 | # Build the entire app
35 | export PATH="/usr/local/opt/qt@5/bin:$PATH"
36 | make
37 |
38 | # Optionally sign it for distribution
39 | make sign
40 | ```
41 |
42 | ### Dependencies:
43 |
44 | - Qt5
45 | - luajit
46 | - zlib
47 | - opengl
48 | - lua-curl (see below)
49 | - Bitstream-Vera and Liberation TTF fonts. Will work without these but most likely look terrible.
50 |
51 | ### Build dependencies:
52 |
53 | - meson
54 | - pkg-config
55 | - ninja (optional, can tell meson to generate makefiles if you prefer)
56 |
57 | ### Ensuring old versions of Mac are compatible:
58 |
59 | By default, the built lcurl.so links to the local version of cURL. Old
60 | versions of cURL on old Macs may be too old to include the relevant functions and run into this error:
61 |
62 | ```
63 | Error loading main script: error loading module 'lcurl.safe' from file './lcurl.so':
64 | dlopen(./lcurl.so, 6): Symbol not found: _curl_easy_option_by_id
65 | Referenced from: ./lcurl.so (which was built for Mac OS X 13.0)
66 | Expected in: /usr/lib/libcurl.4.dylib
67 | ```
68 |
69 | To try to fix this issue, we include the libcurl.4.dylib in our app
70 | using dylibbundler.
71 |
72 | We change it in mesonInstaller.sh based on https://stackoverflow.com/a/38709580/319066
73 |
74 | - `otool -L lcurl.so` can be used to debug the paths.
75 | - `install_name_tool ...` is used to change the paths behind the scenes, but
76 | dylibbundler does all the work for us.
77 |
78 | ## Old manual steps to build:
79 |
80 | ### Build Lua-Curl:
81 |
82 | You need to build [Lua-Curl](https://github.com/Lua-cURL/Lua-cURLv3) for luajit.
83 |
84 | Edit the Lua-Curl Makefile:
85 |
86 | ```diff
87 | @@ -7,7 +7,7 @@ DESTDIR ?= /
88 | PKG_CONFIG ?= pkg-config
89 | INSTALL ?= install
90 | RM ?= rm
91 | -LUA_IMPL ?= lua
92 | +LUA_IMPL ?= luajit
93 | CC ?= $(MAC_ENV) gcc
94 |
95 | LUA_VERSION = $(shell $(PKG_CONFIG) --print-provides --silence-errors $(LUA_IMPL))
96 | ```
97 |
98 | Run make. You should get `lcurl.so`.
99 |
100 | ### Get the PoBFrontend sources:
101 |
102 | `git clone https://github.com/philroberts/pobfrontend.git`
103 |
104 | ### Build:
105 |
106 | ```bash
107 | meson -Dbuildtype=release pobfrontend build
108 | cd build
109 | ninja
110 | ```
111 |
112 | Run the thing:
113 |
114 | ```bash
115 | cd /path/to/PathOfBuilding # <- a pathofbuilding git clone
116 | for f in tree*.zip; do unzip $f;done # <- use the provided tree data because reasons
117 | unzip runtime-win32.zip lua/xml.lua lua/base64.lua lua/sha1.lua
118 | mv lua/*.lua .
119 | rmdir lua
120 | cp /path/to/lcurl.so . # our lcurl.so from earlier
121 | /path/to/build/pobfrontend
122 | ```
123 |
124 | You can adjust the font size up or down with a command line argument:
125 |
126 | ```bash
127 | pobfrontend -2
128 | ```
129 |
130 | ### Notes:
131 |
132 | I have the following edit in my PathOfBuilding clone, stops it from saving builds even when I tell it not to:
133 |
134 | ```diff
135 | --- a/Modules/Build.lua
136 | +++ b/Modules/Build.lua
137 | @@ -599,7 +599,7 @@ function buildMode:CanExit(mode)
138 | end
139 |
140 | function buildMode:Shutdown()
141 | - if launch.devMode and self.targetVersion and not self.abortSave then
142 | + if false then --launch.devMode and self.targetVersion and not self.abortSave then
143 | if self.dbFileName then
144 | self:SaveDBFile()
145 | elseif self.unsaved then
146 | ```
147 |
148 | ###### OS X
149 |
150 | On mac you need to invoke meson with some extra flags, per the luajit documentation:
151 |
152 | ```bash
153 | LDFLAGS="-pagezero_size 10000 -image_base 100000000" meson pobfrontend build
154 | ```
155 |
156 |
157 |
--------------------------------------------------------------------------------
/editLuaCurlMakefile.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | pushd Lua-cURLv3
3 |
4 | # We only replace `lua` with `luajit` once
5 | sed -i '' 's/?= lua$/?= luajit/' Makefile
6 | # We use pkg-config to find the right path for curl libraries
7 | sed -i '' 's@shell .* --libs libcurl@shell PKG_CONFIG_PATH=$$(arch --x86_64 brew --prefix --installed curl)/lib/pkgconfig $(PKG_CONFIG) --libs libcurl@' Makefile
8 | # We use the Homebrew installed GCC and build for x86_64 to ensure we build the
9 | # x86_64 library, even on ARM systems
10 | sed -i '' 's@?= \$(MAC_ENV) gcc$@ = \$(MAC_ENV) arch=x86_64 gcc-12@' Makefile
11 | # We target only MacOS 10.8 or later; otherwise, we get an error. We get an
12 | # error for targeting <10.5 and a warning for <10.8
13 | sed -i '' "s@MACOSX_DEPLOYMENT_TARGET='10.3'@MACOSX_DEPLOYMENT_TARGET='10.8'@" Makefile
14 |
15 | # Some users on old versions of MacOS 10.13 run into the error:
16 | # dyld: cannot load 'PathOfBuilding' (load command 0x80000034 is unknown)
17 | #
18 | # It looks like 0x80000034 is associated with the fixup_chains optimization
19 | # that improves startup time:
20 | # https://www.emergetools.com/blog/posts/iOS15LaunchTime
21 | #
22 | # For compatibility, we disable that using the flag from this thread:
23 | # https://github.com/python/cpython/issues/97524
24 | if ! grep -q "LDFLAGS =" Makefile; then
25 | sed -i '' '/LIBS =/a\
26 | LDFLAGS = -Wl,-no_fixup_chains
27 | ' Makefile
28 | fi
29 | popd
30 |
--------------------------------------------------------------------------------
/editPathOfBuildingBuild.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
3 |
4 | # We remove the `launch.devMode or` to ensure the user's builds are stored not in
5 | # the binary, but within their user directory
6 | sed -i '' 's/if launch.devMode or .*then/if false then/' src/Modules/Main.lua
7 | # Remove the dev-mode notice
8 | sed -i '' 's/if launch.devMode and GetTime.*then/if false then/' src/Modules/Main.lua
9 |
10 | # Remove SSL checks. This fixes a weird problem where cURL doesn't find the
11 | # certificates on M1 Macs. The risk is really low, since the information this
12 | # transfers isn't really sensitive
13 | SED_COMMAND='s/(easy:setopt_url\(.*\))$/\1; easy:setopt(curl.OPT_SSL_VERIFYPEER, false)/'
14 | sed -E -i '' "$SED_COMMAND" src/Launch.lua
15 | sed -E -i '' "$SED_COMMAND" src/Classes/PassiveTree.lua
16 | sed -E -i '' "$SED_COMMAND" src/Classes/TradeQueryGenerator.lua
17 | sed -E -i '' "$SED_COMMAND" src/Classes/TreeTab.lua
18 | sed -E -i '' "$SED_COMMAND" src/Modules/BuildSiteTools.lua
19 | # Do not remove SSL for LaunchInstall and Update as that's more sensitive, but
20 | # also unused.
21 |
22 | # Add nil checks for grantedEffect. Without it, we got an error on 2023-12-18:
23 | # "Error loading main script: Data/Uniques/Special/Generated.lua:239 attempt
24 | # to index local 'grantedEffect' (a nil value)
25 | # ModParser.lua got a similar error
26 | sed -i '' 's/if grantedEffect.support/if grantedEffect ~= nil and grantedEffect.support/' src/Data/Uniques/Special/Generated.lua
27 | sed -i '' 's/if not grantedEffect.hidden/if grantedEffect ~= nil and not grantedEffect.hidden/' src/Modules/ModParser.lua
28 |
29 | # Run remaining setup
30 | unzip runtime-win32.zip lua/xml.lua lua/base64.lua lua/sha1.lua
31 | mv lua/*.lua .
32 | rmdir lua
33 | cp ../lcurl.so .
34 | mv src/* .
35 | rmdir src
36 |
--------------------------------------------------------------------------------
/fonts/Bitstream Vera License.txt:
--------------------------------------------------------------------------------
1 | Bitstream Vera Fonts Copyright
2 |
3 | The fonts have a generous copyright, allowing derivative works (as
4 | long as "Bitstream" or "Vera" are not in the names), and full
5 | redistribution (so long as they are not *sold* by themselves). They
6 | can be be bundled, redistributed and sold with any software.
7 |
8 | The fonts are distributed under the following copyright:
9 |
10 | Copyright
11 | =========
12 |
13 | Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
14 | Vera is a trademark of Bitstream, Inc.
15 |
16 | Permission is hereby granted, free of charge, to any person obtaining
17 | a copy of the fonts accompanying this license ("Fonts") and associated
18 | documentation files (the "Font Software"), to reproduce and distribute
19 | the Font Software, including without limitation the rights to use,
20 | copy, merge, publish, distribute, and/or sell copies of the Font
21 | Software, and to permit persons to whom the Font Software is furnished
22 | to do so, subject to the following conditions:
23 |
24 | The above copyright and trademark notices and this permission notice
25 | shall be included in all copies of one or more of the Font Software
26 | typefaces.
27 |
28 | The Font Software may be modified, altered, or added to, and in
29 | particular the designs of glyphs or characters in the Fonts may be
30 | modified and additional glyphs or characters may be added to the
31 | Fonts, only if the fonts are renamed to names not containing either
32 | the words "Bitstream" or the word "Vera".
33 |
34 | This License becomes null and void to the extent applicable to Fonts
35 | or Font Software that has been modified and is distributed under the
36 | "Bitstream Vera" names.
37 |
38 | The Font Software may be sold as part of a larger software package but
39 | no copy of one or more of the Font Software typefaces may be sold by
40 | itself.
41 |
42 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
43 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
44 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
45 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
46 | BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
47 | OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
48 | OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
49 | OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
50 | SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
51 |
52 | Except as contained in this notice, the names of Gnome, the Gnome
53 | Foundation, and Bitstream Inc., shall not be used in advertising or
54 | otherwise to promote the sale, use or other dealings in this Font
55 | Software without prior written authorization from the Gnome Foundation
56 | or Bitstream Inc., respectively. For further information, contact:
57 | fonts at gnome dot org.
58 |
59 | Copyright FAQ
60 | =============
61 |
62 | 1. I don't understand the resale restriction... What gives?
63 |
64 | Bitstream is giving away these fonts, but wishes to ensure its
65 | competitors can't just drop the fonts as is into a font sale system
66 | and sell them as is. It seems fair that if Bitstream can't make money
67 | from the Bitstream Vera fonts, their competitors should not be able to
68 | do so either. You can sell the fonts as part of any software package,
69 | however.
70 |
71 | 2. I want to package these fonts separately for distribution and
72 | sale as part of a larger software package or system. Can I do so?
73 |
74 | Yes. A RPM or Debian package is a "larger software package" to begin
75 | with, and you aren't selling them independently by themselves.
76 | See 1. above.
77 |
78 | 3. Are derivative works allowed?
79 | Yes!
80 |
81 | 4. Can I change or add to the font(s)?
82 | Yes, but you must change the name(s) of the font(s).
83 |
84 | 5. Under what terms are derivative works allowed?
85 |
86 | You must change the name(s) of the fonts. This is to ensure the
87 | quality of the fonts, both to protect Bitstream and Gnome. We want to
88 | ensure that if an application has opened a font specifically of these
89 | names, it gets what it expects (though of course, using fontconfig,
90 | substitutions could still could have occurred during font
91 | opening). You must include the Bitstream copyright. Additional
92 | copyrights can be added, as per copyright law. Happy Font Hacking!
93 |
94 | 6. If I have improvements for Bitstream Vera, is it possible they might get
95 | adopted in future versions?
96 |
97 | Yes. The contract between the Gnome Foundation and Bitstream has
98 | provisions for working with Bitstream to ensure quality additions to
99 | the Bitstream Vera font family. Please contact us if you have such
100 | additions. Note, that in general, we will want such additions for the
101 | entire family, not just a single font, and that you'll have to keep
102 | both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
103 | glyphs to the font, they must be stylistically in keeping with Vera's
104 | design. Vera cannot become a "ransom note" font. Jim Lyles will be
105 | providing a document describing the design elements used in Vera, as a
106 | guide and aid for people interested in contributing to Vera.
107 |
108 | 7. I want to sell a software package that uses these fonts: Can I do so?
109 |
110 | Sure. Bundle the fonts with your software and sell your software
111 | with the fonts. That is the intent of the copyright.
112 |
113 | 8. If applications have built the names "Bitstream Vera" into them,
114 | can I override this somehow to use fonts of my choosing?
115 |
116 | This depends on exact details of the software. Most open source
117 | systems and software (e.g., Gnome, KDE, etc.) are now converting to
118 | use fontconfig (see www.fontconfig.org) to handle font configuration,
119 | selection and substitution; it has provisions for overriding font
120 | names and subsituting alternatives. An example is provided by the
121 | supplied local.conf file, which chooses the family Bitstream Vera for
122 | "sans", "serif" and "monospace". Other software (e.g., the XFree86
123 | core server) has other mechanisms for font substitution.
--------------------------------------------------------------------------------
/fonts/LiberationSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsource/pobfrontend/f0b601b07915b10878f9ec5eb5e9334265692476/fonts/LiberationSans-Bold.ttf
--------------------------------------------------------------------------------
/fonts/LiberationSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsource/pobfrontend/f0b601b07915b10878f9ec5eb5e9334265692476/fonts/LiberationSans-Regular.ttf
--------------------------------------------------------------------------------
/fonts/SIL Open Font License.txt:
--------------------------------------------------------------------------------
1 | Digitized data copyright (c) 2010 Google Corporation
2 | with Reserved Font Arimo, Tinos and Cousine.
3 | Copyright (c) 2012 Red Hat, Inc.
4 | with Reserved Font Name Liberation.
5 |
6 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
7 | This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
8 |
9 | -----------------------------------------------------------
10 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
11 | -----------------------------------------------------------
12 |
13 | PREAMBLE
14 | The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
15 |
16 | The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
17 |
18 | DEFINITIONS
19 | "Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
20 |
21 | "Reserved Font Name" refers to any names specified as such after the copyright statement(s).
22 |
23 | "Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
24 |
25 | "Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
26 |
27 | "Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
28 |
29 | PERMISSION & CONDITIONS
30 | Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
31 |
32 | 1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
33 |
34 | 2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
35 |
36 | 3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
37 |
38 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
39 |
40 | 5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
41 |
42 | TERMINATION
43 | This license becomes null and void if any of the above conditions are not met.
44 |
45 | DISCLAIMER
46 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
--------------------------------------------------------------------------------
/fonts/VeraMono.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsource/pobfrontend/f0b601b07915b10878f9ec5eb5e9334265692476/fonts/VeraMono.ttf
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 |
11 | #include
12 | #include
13 | #include
14 | #include "main.h"
15 | #include "pobwindow.hpp"
16 | #include "subscript.hpp"
17 | #include
18 | #include
19 |
20 | lua_State *L;
21 |
22 | int dscount;
23 |
24 | POBWindow *pobwindow;
25 |
26 | QRegularExpression colourCodes{R"((\^x.{6})|(\^\d))"};
27 |
28 | void pushCallback(const char* name) {
29 | lua_getfield(L, LUA_REGISTRYINDEX, "uicallbacks");
30 | lua_getfield(L, -1, "MainObject");
31 | lua_remove(L, -2);
32 | lua_getfield(L, -1, name);
33 | lua_insert(L, -2);
34 | }
35 |
36 | void POBWindow::triggerUpdate() {
37 | if (isActive()) {
38 | update();
39 | }
40 | }
41 |
42 | void POBWindow::initializeGL() {
43 | QImage wimg{1, 1, QImage::Format_Mono};
44 | wimg.fill(1);
45 | white.reset(new QOpenGLTexture(wimg));
46 | glClearColor(0.0, 0.0, 0.0, 1.0);
47 | glEnable(GL_TEXTURE_2D);
48 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
49 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
50 | // glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
51 | // glDisable(GL_LIGHTING);
52 | glDepthMask(GL_FALSE);
53 | glDisable(GL_DEPTH_TEST);
54 | glDisable(GL_ALPHA_TEST);
55 | // glAlphaFunc(GL_GREATER, 0);
56 | glEnable(GL_BLEND);
57 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
58 | }
59 |
60 | void POBWindow::resizeGL(int w, int h) {
61 | width = w;
62 | height = h;
63 | }
64 |
65 | void POBWindow::paintGL() {
66 | isDrawing = true;
67 | glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
68 | glColor4f(0, 0, 0, 0);
69 |
70 | for (auto& layer : layers) {
71 | layer.second.clear();
72 | }
73 | dscount = 0;
74 | curLayer = 0;
75 | curSubLayer = 0;
76 |
77 | pushCallback("OnFrame");
78 | int result = lua_pcall(L, 1, 0, 0);
79 | if (result != 0) {
80 | lua_error(L);
81 | }
82 |
83 | if (dscount > pobwindow->stringCache.maxCost()) {
84 | pobwindow->stringCache.setMaxCost(dscount);
85 | }
86 |
87 | for (auto& layer : layers) {
88 | for (auto& cmd : layer.second) {
89 | cmd->execute();
90 | }
91 | }
92 | isDrawing = false;
93 | }
94 |
95 | void POBWindow::subScriptFinished() {
96 | bool clean = true;
97 | for (int i = 0;i < subScriptList.size();i++) {
98 | if (subScriptList[i].get()) {
99 | clean = false;
100 | if (subScriptList[i]->isFinished()) {
101 | subScriptList[i]->onSubFinished(L, i);
102 | subScriptList[i].reset();
103 | }
104 | }
105 | }
106 | if (clean) {
107 | subScriptList.clear();
108 | }
109 | }
110 |
111 | void POBWindow::mouseMoveEvent(QMouseEvent *event) {
112 | update();
113 | }
114 |
115 | void pushMouseString(QMouseEvent *event) {
116 | switch (event->button()) {
117 | case Qt::LeftButton:
118 | lua_pushstring(L, "LEFTBUTTON");
119 | break;
120 | case Qt::RightButton:
121 | lua_pushstring(L, "RIGHTBUTTON");
122 | break;
123 | case Qt::MiddleButton:
124 | lua_pushstring(L, "MIDDLEBUTTON");
125 | break;
126 | default:
127 | std::cout << "MOUSE STRING? " << event->button() << std::endl;
128 | }
129 | }
130 |
131 | void POBWindow::mousePressEvent(QMouseEvent *event) {
132 | pushCallback("OnKeyDown");
133 | pushMouseString(event);
134 | lua_pushboolean(L, false);
135 | int result = lua_pcall(L, 3, 0, 0);
136 | if (result != 0) {
137 | lua_error(L);
138 | }
139 | }
140 |
141 | void POBWindow::mouseReleaseEvent(QMouseEvent *event) {
142 | pushCallback("OnKeyUp");
143 | pushMouseString(event);
144 | int result = lua_pcall(L, 2, 0, 0);
145 | if (result != 0) {
146 | lua_error(L);
147 | }
148 | }
149 |
150 | void POBWindow::mouseDoubleClickEvent(QMouseEvent *event) {
151 | pushCallback("OnKeyDown");
152 | pushMouseString(event);
153 | lua_pushboolean(L, true);
154 | int result = lua_pcall(L, 3, 0, 0);
155 | if (result != 0) {
156 | lua_error(L);
157 | }
158 | }
159 |
160 | void POBWindow::wheelEvent(QWheelEvent *event) {
161 | pushCallback("OnKeyUp");
162 | if (event->angleDelta().y() > 0) {
163 | lua_pushstring(L, "WHEELUP");
164 | } else if (event->angleDelta().y() < 0) {
165 | lua_pushstring(L, "WHEELDOWN");
166 | } else {
167 | return;
168 | }
169 | lua_pushboolean(L, false);
170 | int result = lua_pcall(L, 3, 0, 0);
171 | if (result != 0) {
172 | lua_error(L);
173 | }
174 | }
175 |
176 | bool pushKeyString(int keycode) {
177 | switch (keycode) {
178 | case Qt::Key_Escape:
179 | lua_pushstring(L, "ESCAPE");
180 | break;
181 | case Qt::Key_Tab:
182 | lua_pushstring(L, "TAB");
183 | break;
184 | case Qt::Key_Return:
185 | case Qt::Key_Enter:
186 | lua_pushstring(L, "RETURN");
187 | break;
188 | case Qt::Key_Backspace:
189 | lua_pushstring(L, "BACK");
190 | break;
191 | case Qt::Key_Delete:
192 | lua_pushstring(L, "DELETE");
193 | break;
194 | case Qt::Key_Home:
195 | lua_pushstring(L, "HOME");
196 | break;
197 | case Qt::Key_End:
198 | lua_pushstring(L, "END");
199 | break;
200 | case Qt::Key_Up:
201 | lua_pushstring(L, "UP");
202 | break;
203 | case Qt::Key_Down:
204 | lua_pushstring(L, "DOWN");
205 | break;
206 | case Qt::Key_Left:
207 | lua_pushstring(L, "LEFT");
208 | break;
209 | case Qt::Key_Right:
210 | lua_pushstring(L, "RIGHT");
211 | break;
212 | case Qt::Key_PageUp:
213 | lua_pushstring(L, "PAGEUP");
214 | break;
215 | case Qt::Key_PageDown:
216 | lua_pushstring(L, "PAGEDOWN");
217 | break;
218 | case Qt::Key_F6:
219 | lua_pushstring(L, "F6");
220 | break;
221 | default:
222 | return false;
223 | }
224 | return true;
225 | }
226 |
227 | void POBWindow::keyPressEvent(QKeyEvent *event) {
228 | pushCallback("OnKeyDown");
229 | if (!pushKeyString(event->key())) {
230 | if (event->key() >= ' ' && event->key() <= '~') {
231 | char s[2];
232 | if (event->key() >= 'A' && event->key() <= 'Z' && !(QGuiApplication::keyboardModifiers() & Qt::ShiftModifier)) {
233 | s[0] = event->key() + 32;
234 | } else {
235 | s[0] = event->key();
236 | }
237 | s[1] = 0;
238 | if (!(QGuiApplication::keyboardModifiers() & Qt::ControlModifier)) {
239 | lua_pop(L, 2);
240 | pushCallback("OnChar");
241 | }
242 | lua_pushstring(L, s);
243 | } else {
244 | lua_pushstring(L, "ASDF");
245 | //std::cout << "UNHANDLED KEYDOWN" << std::endl;
246 | }
247 | }
248 | lua_pushboolean(L, false);
249 | int result = lua_pcall(L, 3, 0, 0);
250 | if (result != 0) {
251 | lua_error(L);
252 | }
253 | }
254 |
255 | void POBWindow::keyReleaseEvent(QKeyEvent *event) {
256 | pushCallback("OnKeyUp");
257 | if (!pushKeyString(event->key())) {
258 | lua_pushstring(L, "ASDF");
259 | //std::cout << "UNHANDLED KEYUP" << std::endl;
260 | }
261 | int result = lua_pcall(L, 2, 0, 0);
262 | if (result != 0) {
263 | lua_error(L);
264 | }
265 | }
266 |
267 | void POBWindow::LAssert(lua_State* L, int cond, const char* fmt, ...) {
268 | if ( !cond ) {
269 | va_list va;
270 | va_start(va, fmt);
271 | lua_pushvfstring(L, fmt, va);
272 | va_end(va);
273 | lua_error(L);
274 | }
275 | }
276 |
277 | int POBWindow::IsUserData(lua_State* L, int index, const char* metaName)
278 | {
279 | if (lua_type(L, index) != LUA_TUSERDATA || lua_getmetatable(L, index) == 0) {
280 | return 0;
281 | }
282 | lua_getfield(L, LUA_REGISTRYINDEX, metaName);
283 | int ret = lua_rawequal(L, -2, -1);
284 | lua_pop(L, 2);
285 | return ret;
286 | }
287 |
288 | void POBWindow::SetDrawLayer(int layer) {
289 | SetDrawLayer(layer, 0);
290 | }
291 |
292 | void POBWindow::SetDrawLayer(int layer, int subLayer) {
293 | if (layer == curLayer && subLayer == curSubLayer) {
294 | return;
295 | }
296 |
297 | curLayer = layer;
298 | curSubLayer = subLayer;
299 | }
300 |
301 |
302 | void POBWindow::AppendCmd(std::unique_ptr cmd) {
303 | layers[{curLayer, curSubLayer}].emplace_back(std::move(cmd));
304 | }
305 |
306 | void POBWindow::DrawColor(const float col[4]) {
307 | if (col) {
308 | drawColor[0] = col[0];
309 | drawColor[1] = col[1];
310 | drawColor[2] = col[2];
311 | drawColor[3] = col[3];
312 | } else {
313 | drawColor[0] = 1.0f;
314 | drawColor[1] = 1.0f;
315 | drawColor[2] = 1.0f;
316 | drawColor[3] = 1.0f;
317 | }
318 | AppendCmd(std::make_unique(drawColor));
319 | }
320 |
321 | void POBWindow::DrawColor(uint32_t col) {
322 | drawColor[0] = ((col >> 16) & 0xFF) / 255.0f;
323 | drawColor[1] = ((col >> 8) & 0xFF) / 255.0f;
324 | drawColor[2] = (col & 0xFF) / 255.0f;
325 | drawColor[3] = (col >> 24) / 255.0f;
326 | }
327 |
328 |
329 | // Color escape table
330 | static const float colorEscape[10][4] = {
331 | {0.0f, 0.0f, 0.0f, 1.0f},
332 | {1.0f, 0.0f, 0.0f, 1.0f},
333 | {0.0f, 1.0f, 0.0f, 1.0f},
334 | {0.0f, 0.0f, 1.0f, 1.0f},
335 | {1.0f, 1.0f, 0.0f, 1.0f},
336 | {1.0f, 0.0f, 1.0f, 1.0f},
337 | {0.0f, 1.0f, 1.0f, 1.0f},
338 | {1.0f, 1.0f, 1.0f, 1.0f},
339 | {0.7f, 0.7f, 0.7f, 1.0f},
340 | {0.4f, 0.4f, 0.4f, 1.0f}
341 | };
342 |
343 | int IsColorEscape(const char* str)
344 | {
345 | if (str[0] != '^') {
346 | return 0;
347 | }
348 | if (isdigit(str[1])) {
349 | return 2;
350 | } else if (str[1] == 'x' || str[1] == 'X') {
351 | for (int c = 0; c < 6; c++) {
352 | if ( !isxdigit(str[c + 2]) ) {
353 | return 0;
354 | }
355 | }
356 | return 8;
357 | }
358 | return 0;
359 | }
360 |
361 | void ReadColorEscape(const char* str, float* out)
362 | {
363 | int len = IsColorEscape(str);
364 | switch (len) {
365 | case 2:
366 | out[0] = colorEscape[str[1] - '0'][0];
367 | out[1] = colorEscape[str[1] - '0'][1];
368 | out[2] = colorEscape[str[1] - '0'][2];
369 | break;
370 | case 8:
371 | {
372 | int xr, xg, xb;
373 | sscanf(str + 2, "%2x%2x%2x", &xr, &xg, &xb);
374 | out[0] = xr / 255.0f;
375 | out[1] = xg / 255.0f;
376 | out[2] = xb / 255.0f;
377 | }
378 | break;
379 | }
380 | }
381 |
382 | // =========
383 | // Callbacks
384 | // =========
385 |
386 | static int l_SetCallback(lua_State* L)
387 | {
388 | int n = lua_gettop(L);
389 | pobwindow->LAssert(L, n >= 1, "Usage: SetCallback(name[, func])");
390 | pobwindow->LAssert(L, lua_isstring(L, 1), "SetCallback() argument 1: expected string, got %t", 1);
391 | lua_pushvalue(L, 1);
392 | if (n >= 2) {
393 | pobwindow->LAssert(L, lua_isfunction(L, 2) || lua_isnil(L, 2), "SetCallback() argument 2: expected function or nil, got %t", 2);
394 | lua_pushvalue(L, 2);
395 | } else {
396 | lua_pushnil(L);
397 | }
398 | lua_settable(L, lua_upvalueindex(1));
399 | return 0;
400 | }
401 |
402 | static int l_GetCallback(lua_State* L)
403 | {
404 | int n = lua_gettop(L);
405 | pobwindow->LAssert(L, n >= 1, "Usage: GetCallback(name)");
406 | pobwindow->LAssert(L, lua_isstring(L, 1), "GetCallback() argument 1: expected string, got %t", 1);
407 | lua_pushvalue(L, 1);
408 | lua_gettable(L, lua_upvalueindex(1));
409 | return 1;
410 | }
411 |
412 | static int l_SetMainObject(lua_State* L)
413 | {
414 | int n = lua_gettop(L);
415 | lua_pushstring(L, "MainObject");
416 | if (n >= 1) {
417 | pobwindow->LAssert(L, lua_istable(L, 1) || lua_isnil(L, 1), "SetMainObject() argument 1: expected table or nil, got %t", 1);
418 | lua_pushvalue(L, 1);
419 | } else {
420 | lua_pushnil(L);
421 | }
422 | lua_settable(L, lua_upvalueindex(1));
423 | return 0;
424 | }
425 |
426 | // =============
427 | // Image Handles
428 | // =============
429 |
430 | struct imgHandle_s {
431 | std::shared_ptr *hnd;
432 | QImage* img;
433 | };
434 |
435 | static int l_NewImageHandle(lua_State* L)
436 | {
437 | auto imgHandle = (imgHandle_s*)lua_newuserdata(L, sizeof(imgHandle_s));
438 | imgHandle->hnd = nullptr;
439 | imgHandle->img = nullptr;
440 | lua_pushvalue(L, lua_upvalueindex(1));
441 | lua_setmetatable(L, -2);
442 | return 1;
443 | }
444 |
445 | static imgHandle_s* GetImgHandle(lua_State* L, const char* method, bool loaded)
446 | {
447 | pobwindow->LAssert(L, pobwindow->IsUserData(L, 1, "uiimghandlemeta"), "imgHandle:%s() must be used on an image handle", method);
448 | auto imgHandle = (imgHandle_s*)lua_touserdata(L, 1);
449 | lua_remove(L, 1);
450 | if (loaded) {
451 | //pobwindow->LAssert(L, imgHandle->hnd != NULL, "imgHandle:%s(): image handle has no image loaded", method);
452 | }
453 | return imgHandle;
454 | }
455 |
456 | static int l_imgHandleGC(lua_State* L)
457 | {
458 | imgHandle_s* imgHandle = GetImgHandle(L, "__gc", false);
459 | delete imgHandle->hnd;
460 | delete imgHandle->img;
461 | return 0;
462 | }
463 |
464 | static int l_imgHandleLoad(lua_State* L)
465 | {
466 | imgHandle_s* imgHandle = GetImgHandle(L, "Load", false);
467 | int n = lua_gettop(L);
468 | pobwindow->LAssert(L, n >= 1, "Usage: imgHandle:Load(fileName[, flag1[, flag2...]])");
469 | pobwindow->LAssert(L, lua_isstring(L, 1), "imgHandle:Load() argument 1: expected string, got %t", 1);
470 | QString fileName = lua_tostring(L, 1);
471 | QString fullFileName;
472 | if (fileName.contains(':') || pobwindow->scriptWorkDir.isEmpty()) {
473 | fullFileName = fileName;
474 | } else {
475 | fullFileName = pobwindow->scriptWorkDir + QDir::separator() + fileName;
476 | }
477 |
478 | delete imgHandle->hnd;
479 | imgHandle->hnd = new std::shared_ptr();
480 | delete imgHandle->img;
481 | int flags = TF_NOMIPMAP;
482 | for (int f = 2; f <= n; f++) {
483 | if ( !lua_isstring(L, f) ) {
484 | continue;
485 | }
486 | const char* flag = lua_tostring(L, f);
487 | if ( !strcmp(flag, "ASYNC") ) {
488 | flags|= TF_ASYNC;
489 | } else if ( !strcmp(flag, "CLAMP") ) {
490 | flags|= TF_CLAMP;
491 | } else if ( !strcmp(flag, "MIPMAP") ) {
492 | flags&= ~TF_NOMIPMAP;
493 | } else {
494 | pobwindow->LAssert(L, 0, "imgHandle:Load(): unrecognised flag '%s'", flag);
495 | }
496 | }
497 | imgHandle->img = new QImage();
498 | imgHandle->img->load(fullFileName);
499 | imgHandle->img->setText("fname", fullFileName);
500 | //imgHandle->hnd = new QOpenGLTexture(img);
501 | //pobwindow->renderer->RegisterShader(fullFileName, flags);
502 | return 0;
503 | }
504 |
505 | static int l_imgHandleUnload(lua_State* L)
506 | {
507 | imgHandle_s* imgHandle = GetImgHandle(L, "Unload", false);
508 | delete imgHandle->hnd;
509 | imgHandle->hnd = nullptr;
510 | delete imgHandle->img;
511 | imgHandle->img = nullptr;
512 | return 0;
513 | }
514 |
515 | static int l_imgHandleIsValid(lua_State* L)
516 | {
517 | imgHandle_s* imgHandle = GetImgHandle(L, "IsValid", false);
518 | lua_pushboolean(L, imgHandle->hnd != nullptr);
519 | return 1;
520 | }
521 |
522 | static int l_imgHandleIsLoading(lua_State* L)
523 | {
524 | imgHandle_s* imgHandle = GetImgHandle(L, "IsLoading", true);
525 | // int width, height;
526 | // pobwindow->renderer->GetShaderImageSize(imgHandle->hnd, width, height);
527 | lua_pushboolean(L, false);
528 | return 1;
529 | }
530 |
531 | static int l_imgHandleSetLoadingPriority(lua_State* L)
532 | {
533 | imgHandle_s* imgHandle = GetImgHandle(L, "SetLoadingPriority", true);
534 | int n = lua_gettop(L);
535 | pobwindow->LAssert(L, n >= 1, "Usage: imgHandle:SetLoadingPriority(pri)");
536 | pobwindow->LAssert(L, lua_isnumber(L, 1), "imgHandle:SetLoadingPriority() argument 1: expected number, got %t", 1);
537 | //pobwindow->renderer->SetShaderLoadingPriority(imgHandle->hnd, (int)lua_tointeger(L, 1));
538 | return 0;
539 | }
540 |
541 | static int l_imgHandleImageSize(lua_State* L)
542 | {
543 | imgHandle_s* imgHandle = GetImgHandle(L, "ImageSize", true);
544 | QSize size(imgHandle->img->size());
545 | lua_pushinteger(L, size.width());
546 | lua_pushinteger(L, size.height());
547 | return 2;
548 | }
549 |
550 | // =========
551 | // Rendering
552 | // =========
553 |
554 | static int l_RenderInit(lua_State* L)
555 | {
556 | return 0;
557 | }
558 |
559 | static int l_GetScreenSize(lua_State* L)
560 | {
561 | lua_pushinteger(L, pobwindow->width);
562 | lua_pushinteger(L, pobwindow->height);
563 | return 2;
564 | }
565 |
566 | static int l_SetClearColor(lua_State* L)
567 | {
568 | int n = lua_gettop(L);
569 | pobwindow->LAssert(L, n >= 3, "Usage: SetClearColor(red, green, blue[, alpha])");
570 | float color[4];
571 | for (int i = 1; i <= 3; i++) {
572 | pobwindow->LAssert(L, lua_isnumber(L, i), "SetClearColor() argument %d: expected number, got %t", i, i);
573 | color[i-1] = (float)lua_tonumber(L, i);
574 | }
575 | if (n >= 4 && !lua_isnil(L, 4)) {
576 | pobwindow->LAssert(L, lua_isnumber(L, 4), "SetClearColor() argument 4: expected number or nil, got %t", 4);
577 | color[3] = (float)lua_tonumber(L, 4);
578 | } else {
579 | color[3] = 1.0;
580 | }
581 | glClearColor(color[0], color[1], color[2], color[3]);
582 | return 0;
583 | }
584 |
585 | static int l_SetDrawLayer(lua_State* L)
586 | {
587 | int n = lua_gettop(L);
588 | pobwindow->LAssert(L, n >= 1, "Usage: SetDrawLayer({layer|nil}[, subLayer])");
589 | pobwindow->LAssert(L, lua_isnumber(L, 1) || lua_isnil(L, 1), "SetDrawLayer() argument 1: expected number or nil, got %t", 1);
590 | if (n >= 2) {
591 | pobwindow->LAssert(L, lua_isnumber(L, 2), "SetDrawLayer() argument 2: expected number, got %t", 2);
592 | }
593 | if (lua_isnil(L, 1)) {
594 | pobwindow->LAssert(L, n >= 2, "SetDrawLayer(): must provide subLayer if layer is nil");
595 | pobwindow->SetDrawSubLayer(lua_tointeger(L, 2));
596 | } else if (n >= 2) {
597 | pobwindow->SetDrawLayer(lua_tointeger(L, 1), lua_tointeger(L, 2));
598 | } else {
599 | pobwindow->SetDrawLayer(lua_tointeger(L, 1));
600 | }
601 | return 0;
602 | }
603 |
604 | void ViewportCmd::execute() {
605 | glViewport(x, pobwindow->height - y - h, w, h);
606 | glMatrixMode(GL_PROJECTION);
607 | glLoadIdentity();
608 | glOrtho(0, (float)w, (float)h, 0, -9999, 9999);
609 | glMatrixMode(GL_MODELVIEW);
610 | glLoadIdentity();
611 | }
612 |
613 | static int l_SetViewport(lua_State* L)
614 | {
615 | int n = lua_gettop(L);
616 | if (n) {
617 | pobwindow->LAssert(L, n >= 4, "Usage: SetViewport([x, y, width, height])");
618 | for (int i = 1; i <= 4; i++) {
619 | pobwindow->LAssert(L, lua_isnumber(L, i), "SetViewport() argument %d: expected number, got %t", i, i);
620 | }
621 | pobwindow->AppendCmd(std::make_unique((int)lua_tointeger(L, 1), (int)lua_tointeger(L, 2), (int)lua_tointeger(L, 3), (int)lua_tointeger(L, 4)));
622 | } else {
623 | pobwindow->AppendCmd(std::make_unique(0, 0, pobwindow->width, pobwindow->height));
624 | }
625 | return 0;
626 | }
627 |
628 | static int l_SetDrawColor(lua_State* L)
629 | {
630 | pobwindow->LAssert(L, pobwindow->isDrawing, "SetDrawColor() called outside of OnFrame");
631 | int n = lua_gettop(L);
632 | pobwindow->LAssert(L, n >= 1, "Usage: SetDrawColor(red, green, blue[, alpha]) or SetDrawColor(escapeStr)");
633 | float color[4];
634 | if (lua_type(L, 1) == LUA_TSTRING) {
635 | pobwindow->LAssert(L, IsColorEscape(lua_tostring(L, 1)), "SetDrawColor() argument 1: invalid color escape sequence");
636 | ReadColorEscape(lua_tostring(L, 1), color);
637 | color[3] = 1.0;
638 | } else {
639 | pobwindow->LAssert(L, n >= 3, "Usage: SetDrawColor(red, green, blue[, alpha]) or SetDrawColor(escapeStr)");
640 | for (int i = 1; i <= 3; i++) {
641 | pobwindow->LAssert(L, lua_isnumber(L, i), "SetDrawColor() argument %d: expected number, got %t", i, i);
642 | color[i-1] = (float)lua_tonumber(L, i);
643 | }
644 | if (n >= 4 && !lua_isnil(L, 4)) {
645 | pobwindow->LAssert(L, lua_isnumber(L, 4), "SetDrawColor() argument 4: expected number or nil, got %t", 4);
646 | color[3] = (float)lua_tonumber(L, 4);
647 | } else {
648 | color[3] = 1.0;
649 | }
650 | }
651 | pobwindow->DrawColor(color);
652 | return 0;
653 | }
654 |
655 | static int l_DrawImage(lua_State* L)
656 | {
657 | pobwindow->LAssert(L, pobwindow->isDrawing, "DrawImage() called outside of OnFrame");
658 | int n = lua_gettop(L);
659 | pobwindow->LAssert(L, n >= 5, "Usage: DrawImage({imgHandle|nil}, left, top, width, height[, tcLeft, tcTop, tcRight, tcBottom])");
660 | pobwindow->LAssert(L, lua_isnil(L, 1) || pobwindow->IsUserData(L, 1, "uiimghandlemeta"), "DrawImage() argument 1: expected image handle or nil, got %t", 1);
661 | std::shared_ptr hnd;
662 | if ( !lua_isnil(L, 1) ) {
663 | auto imgHandle = (imgHandle_s*)lua_touserdata(L, 1);
664 | if (imgHandle->hnd->get() == nullptr) {
665 | imgHandle->hnd->reset(new QOpenGLTexture(*(imgHandle->img)));
666 | if (!(*imgHandle->hnd)->isCreated()) {
667 | //std::cout << "BROKEN TEXTURE " << imgHandle->img->text("fname").toStdString() << std::endl;
668 | *imgHandle->hnd = pobwindow->white;
669 | }
670 | }
671 | pobwindow->LAssert(L, imgHandle->hnd != nullptr, "DrawImage(): image handle has no image loaded");
672 | hnd = *imgHandle->hnd;
673 | }
674 | float arg[8];
675 | if (n > 5) {
676 | pobwindow->LAssert(L, n >= 9, "DrawImage(): incomplete set of texture coordinates provided");
677 | for (int i = 2; i <= 9; i++) {
678 | pobwindow->LAssert(L, lua_isnumber(L, i), "DrawImage() argument %d: expected number, got %t", i, i);
679 | arg[i-2] = (float)lua_tonumber(L, i);
680 | }
681 | pobwindow->AppendCmd(std::make_unique(hnd, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7]));
682 | } else {
683 | for (int i = 2; i <= 5; i++) {
684 | pobwindow->LAssert(L, lua_isnumber(L, i), "DrawImage() argument %d: expected number, got %t", i, i);
685 | arg[i-2] = (float)lua_tonumber(L, i);
686 | }
687 | pobwindow->AppendCmd(std::make_unique(hnd, arg[0], arg[1], arg[2], arg[3]));
688 | }
689 | return 0;
690 | }
691 |
692 | void DrawImageQuadCmd::execute() {
693 | if (tex != nullptr && tex->isCreated()) {
694 | tex->bind();
695 | } else {
696 | pobwindow->white->bind();
697 | }
698 | glBegin(GL_TRIANGLE_FAN);
699 | for (int v = 0; v < 4; v++) {
700 | glTexCoord2d(s[v], t[v]);
701 | glVertex2d(x[v], y[v]);
702 | }
703 | glEnd();
704 | }
705 |
706 | static int l_DrawImageQuad(lua_State* L)
707 | {
708 | pobwindow->LAssert(L, pobwindow->isDrawing, "DrawImageQuad() called outside of OnFrame");
709 | int n = lua_gettop(L);
710 | pobwindow->LAssert(L, n >= 9, "Usage: DrawImageQuad({imgHandle|nil}, x1, y1, x2, y2, x3, y3, x4, y4[, s1, t1, s2, t2, s3, t3, s4, t4])");
711 | pobwindow->LAssert(L, lua_isnil(L, 1) || pobwindow->IsUserData(L, 1, "uiimghandlemeta"), "DrawImageQuad() argument 1: expected image handle or nil, got %t", 1);
712 | std::shared_ptr hnd;
713 | if ( !lua_isnil(L, 1) ) {
714 | auto imgHandle = (imgHandle_s*)lua_touserdata(L, 1);
715 | if ((*imgHandle->hnd).get() == nullptr) {
716 | (*imgHandle->hnd).reset(new QOpenGLTexture(*(imgHandle->img)));
717 | if (!(*imgHandle->hnd)->isCreated()) {
718 | // std::cout << "BROKEN TEXTURE" << imgHandle->img->text("fname").toStdString() << std::endl;
719 | *imgHandle->hnd = pobwindow->white;
720 | }
721 | }
722 | pobwindow->LAssert(L, imgHandle->hnd != nullptr, "DrawImageQuad(): image handle has no image loaded");
723 | hnd = *imgHandle->hnd;
724 | }
725 | float arg[16];
726 | if (n > 9) {
727 | pobwindow->LAssert(L, n >= 17, "DrawImageQuad(): incomplete set of texture coordinates provided");
728 | for (int i = 2; i <= 17; i++) {
729 | pobwindow->LAssert(L, lua_isnumber(L, i), "DrawImageQuad() argument %d: expected number, got %t", i, i);
730 | arg[i-2] = (float)lua_tonumber(L, i);
731 | }
732 | pobwindow->AppendCmd(std::make_unique(hnd, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15]));
733 | } else {
734 | for (int i = 2; i <= 9; i++) {
735 | pobwindow->LAssert(L, lua_isnumber(L, i), "DrawImageQuad() argument %d: expected number, got %t", i, i);
736 | arg[i-2] = (float)lua_tonumber(L, i);
737 | }
738 | pobwindow->AppendCmd(std::make_unique(hnd, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7]));
739 | }
740 | return 0;
741 | }
742 |
743 | DrawStringCmd::DrawStringCmd(float X, float Y, int Align, int Size, int Font, const char *Text) : text(Text) {
744 | dscount++;
745 | if (text.size() >= 2 && text[0] == '^') {
746 | switch(text[1].toLatin1()) {
747 | case '0':
748 | setCol(0.0f, 0.0f, 0.0f);
749 | break;
750 | case '1':
751 | setCol(1.0f, 0.0f, 0.0f);
752 | break;
753 | case '2':
754 | setCol(0.0f, 1.0f, 0.0f);
755 | break;
756 | case '3':
757 | setCol(0.0f, 0.0f, 1.0f);
758 | break;
759 | case '4':
760 | setCol(1.0f, 1.0f, 0.0f);
761 | break;
762 | case '5':
763 | setCol(1.0f, 0.0f, 1.0f);
764 | break;
765 | case '6':
766 | setCol(0.0f, 1.0f, 1.0f);
767 | break;
768 | case '7':
769 | setCol(1.0f, 1.0f, 1.0f);
770 | break;
771 | case '8':
772 | setCol(0.7f, 0.7f, 0.7f);
773 | break;
774 | case '9':
775 | setCol(0.4f, 0.4f, 0.4f);
776 | break;
777 | case 'x':
778 | int xr, xg, xb;
779 | sscanf(text.toStdString().c_str() + 2, "%2x%2x%2x", &xr, &xg, &xb);
780 | setCol(xr / 255.0f, xg / 255.0f, xb / 255.0f);
781 | break;
782 | default:
783 | break;
784 | }
785 | } else {
786 | col[3] = 0;
787 | }
788 | int count = 0;
789 | for (auto i = colourCodes.globalMatch(text);i.hasNext();i.next()) {
790 | count += 1;
791 | }
792 | if (count > 1) {
793 | //std::cout << text.toStdString().c_str() << " " << count << std::endl;
794 | }
795 | text.remove(colourCodes);
796 |
797 | QString cacheKey = (QString::number(Font) + "_" + QString::number(Size) + "_" + text);
798 | if (pobwindow->stringCache.contains(cacheKey)) {
799 | tex = *pobwindow->stringCache[cacheKey];
800 | } else {
801 | QString fontName;
802 | switch (Font) {
803 | case 1:
804 | fontName = "Liberation Sans";
805 | break;
806 | case 2:
807 | fontName = "Liberation Sans Bold";
808 | break;
809 | case 0:
810 | default:
811 | fontName = "Bitstream Vera Sans Mono";
812 | break;
813 | }
814 | QFont font(fontName);
815 | font.setPixelSize(Size + pobwindow->fontFudge);
816 | QFontMetrics fm(font);
817 | QSize size = fm.size(0, text);
818 |
819 | QImage brush(size, QImage::Format_ARGB32);
820 | brush.fill(QColor(255, 255, 255, 0));
821 | tex = nullptr;
822 | if (brush.width() && brush.height()) {
823 | QPainter p(&brush);
824 | p.setPen(QColor(255, 255, 255, 255));
825 | p.setFont(font);
826 | p.setCompositionMode(QPainter::CompositionMode_Plus);
827 | p.drawText(0, 0, size.width(), size.height(), 0, text);
828 | p.end();
829 | tex.reset(new QOpenGLTexture(brush));
830 | }
831 | pobwindow->stringCache.insert(cacheKey, new std::shared_ptr(tex));
832 | }
833 | int width = 0;
834 | int height = 0;
835 | if (tex.get() != nullptr) {
836 | width = tex->width();
837 | height = tex->height();
838 | }
839 |
840 | switch (Align) {
841 | case F_CENTRE:
842 | X = floor((pobwindow->width - width) / 2.0f + X);
843 | break;
844 | case F_RIGHT:
845 | X = floor(pobwindow->width - width - X);
846 | break;
847 | case F_CENTRE_X:
848 | X = floor(X - width / 2.0f);
849 | break;
850 | case F_RIGHT_X:
851 | X = floor(X - width) + 5;
852 | break;
853 | }
854 | x[0] = X;
855 | y[0] = Y;
856 | x[1] = X + width;
857 | y[1] = Y;
858 | x[2] = X + width;
859 | y[2] = Y + height;
860 | x[3] = X;
861 | y[3] = Y + height;
862 |
863 | s[0] = 0;
864 | t[0] = 0;
865 | s[1] = 1;
866 | t[1] = 0;
867 | s[2] = 1;
868 | t[2] = 1;
869 | s[3] = 0;
870 | t[3] = 1;
871 | }
872 |
873 | static int l_DrawString(lua_State* L)
874 | {
875 | pobwindow->LAssert(L, pobwindow->isDrawing, "DrawString() called outside of OnFrame");
876 | int n = lua_gettop(L);
877 | pobwindow->LAssert(L, n >= 6, "Usage: DrawString(left, top, align, height, font, text)");
878 | pobwindow->LAssert(L, lua_isnumber(L, 1), "DrawString() argument 1: expected number, got %t", 1);
879 | pobwindow->LAssert(L, lua_isnumber(L, 2), "DrawString() argument 2: expected number, got %t", 2);
880 | pobwindow->LAssert(L, lua_isstring(L, 3) || lua_isnil(L, 3), "DrawString() argument 3: expected string or nil, got %t", 3);
881 | pobwindow->LAssert(L, lua_isnumber(L, 4), "DrawString() argument 4: expected number, got %t", 4);
882 | pobwindow->LAssert(L, lua_isstring(L, 5), "DrawString() argument 5: expected string, got %t", 5);
883 | pobwindow->LAssert(L, lua_isstring(L, 6), "DrawString() argument 6: expected string, got %t", 6);
884 | static const char* alignMap[6] = { "LEFT", "CENTER", "RIGHT", "CENTER_X", "RIGHT_X", nullptr };
885 | static const char* fontMap[4] = { "FIXED", "VAR", "VAR BOLD", nullptr };
886 | pobwindow->AppendCmd(std::make_unique(
887 | (float)lua_tonumber(L, 1), (float)lua_tonumber(L, 2), luaL_checkoption(L, 3, "LEFT", alignMap),
888 | (int)lua_tointeger(L, 4), luaL_checkoption(L, 5, "FIXED", fontMap), lua_tostring(L, 6)
889 | ));
890 | return 0;
891 | }
892 |
893 | static int l_DrawStringWidth(lua_State* L)
894 | {
895 | int n = lua_gettop(L);
896 | pobwindow->LAssert(L, n >= 3, "Usage: DrawStringWidth(height, font, text)");
897 | pobwindow->LAssert(L, lua_isnumber(L, 1), "DrawStringWidth() argument 1: expected number, got %t", 1);
898 | pobwindow->LAssert(L, lua_isstring(L, 2), "DrawStringWidth() argument 2: expected string, got %t", 2);
899 | pobwindow->LAssert(L, lua_isstring(L, 3), "DrawStringWidth() argument 3: expected string, got %t", 3);
900 | int fontsize = lua_tointeger(L, 1);
901 | QString fontName = lua_tostring(L, 2);
902 | QString fontKey = "0";
903 | if (fontName == "VAR") {
904 | fontName = "Liberation Sans";
905 | fontKey = "1";
906 | } else if (fontName == "VAR BOLD") {
907 | fontName = "Liberation Sans Bold";
908 | fontKey = "2";
909 | } else {
910 | fontName = "Bitstream Vera Sans Mono";
911 | }
912 | QString text(lua_tostring(L, 3));
913 |
914 | text.remove(colourCodes);
915 |
916 | QString cacheKey = (fontKey + "_" + QString::number(fontsize) + "_" + text);
917 | if (pobwindow->stringCache.contains(cacheKey) && pobwindow->stringCache[cacheKey]->get()) {
918 | lua_pushinteger(L, (*pobwindow->stringCache[cacheKey])->width());
919 | return 1;
920 | }
921 |
922 | QFont font(fontName);
923 | font.setPixelSize(fontsize + pobwindow->fontFudge);
924 | QFontMetrics fm(font);
925 | lua_pushinteger(L, fm.size(0, text).width());
926 | return 1;
927 | }
928 |
929 | static int l_DrawStringCursorIndex(lua_State* L)
930 | {
931 | int n = lua_gettop(L);
932 | pobwindow->LAssert(L, n >= 5, "Usage: DrawStringCursorIndex(height, font, text, cursorX, cursorY)");
933 | pobwindow->LAssert(L, lua_isnumber(L, 1), "DrawStringCursorIndex() argument 1: expected number, got %t", 1);
934 | pobwindow->LAssert(L, lua_isstring(L, 2), "DrawStringCursorIndex() argument 2: expected string, got %t", 2);
935 | pobwindow->LAssert(L, lua_isstring(L, 3), "DrawStringCursorIndex() argument 3: expected string, got %t", 3);
936 | pobwindow->LAssert(L, lua_isnumber(L, 4), "DrawStringCursorIndex() argument 4: expected number, got %t", 4);
937 | pobwindow->LAssert(L, lua_isnumber(L, 5), "DrawStringCursorIndex() argument 5: expected number, got %t", 5);
938 |
939 | int fontsize = lua_tointeger(L, 1);
940 | QString fontName = lua_tostring(L, 2);
941 | if (fontName == "VAR") {
942 | fontName = "Liberation Sans";
943 | } else if (fontName == "VAR BOLD") {
944 | fontName = "Liberation Sans Bold";
945 | } else {
946 | fontName = "Bitstream Vera Sans Mono";
947 | }
948 | QString text(lua_tostring(L, 3));
949 |
950 | text.remove(colourCodes);
951 |
952 | QStringList texts = text.split("\n");
953 | QFont font(fontName);
954 | font.setPixelSize(fontsize + pobwindow->fontFudge);
955 | QFontMetrics fm(font);
956 | int curX = lua_tointeger(L, 4);
957 | int curY = lua_tointeger(L, 5);
958 | int yidx = std::max(0, std::min(texts.size() - 1, curY / fm.lineSpacing()));
959 | text = texts[yidx];
960 | int i = 0;
961 | for (;i <= text.size();i++) {
962 | if (fm.size(0, text.left(i)).width() > curX) {
963 | break;
964 | }
965 | }
966 | for (int y = 0;y < yidx;y++) {
967 | i += texts[y].size() + 1;
968 | }
969 | lua_pushinteger(L, i);
970 | return 1;
971 | }
972 |
973 | static int l_StripEscapes(lua_State* L)
974 | {
975 | int n = lua_gettop(L);
976 | pobwindow->LAssert(L, n >= 1, "Usage: StripEscapes(string)");
977 | pobwindow->LAssert(L, lua_isstring(L, 1), "StripEscapes() argument 1: expected string, got %t", 1);
978 | const char* str = lua_tostring(L, 1);
979 | char* strip = new char[strlen(str) + 1];
980 | char* p = strip;
981 | while (*str) {
982 | int esclen = IsColorEscape(str);
983 | if (esclen) {
984 | str+= esclen;
985 | } else {
986 | *(p++) = *(str++);
987 | }
988 | }
989 | *p = 0;
990 | lua_pushstring(L, strip);
991 | delete[] strip;
992 | return 1;
993 | }
994 |
995 | static int l_GetAsyncCount(lua_State* L)
996 | {
997 | // lua_pushinteger(L, pobwindow->GetTexAsyncCount());
998 | lua_pushinteger(L, 0);
999 | return 1;
1000 | }
1001 |
1002 | // ==============
1003 | // Search Handles
1004 | // ==============
1005 |
1006 | struct searchHandle_s {
1007 | QFileInfoList *fil;
1008 | };
1009 |
1010 | static int l_NewFileSearch(lua_State* L)
1011 | {
1012 | int n = lua_gettop(L);
1013 | pobwindow->LAssert(L, n >= 1, "Usage: NewFileSearch(spec[, findDirectories])");
1014 | pobwindow->LAssert(L, lua_isstring(L, 1), "NewFileSearch() argument 1: expected string, got %t", 1);
1015 | QString search_string(lua_tostring(L, 1));
1016 | QStringList split = search_string.split("/");
1017 | QString wildcard = split.takeLast();
1018 | QDir dir(split.join("/"));
1019 | QStringList filters;
1020 | filters << wildcard;
1021 | bool dirOnly = lua_toboolean(L, 2) != 0;
1022 | QFileInfoList fil = dir.entryInfoList(filters, QDir::NoDotAndDotDot | (dirOnly ? QDir::Dirs : QDir::Files));
1023 | if (fil.isEmpty()) {
1024 | return 0;
1025 | }
1026 |
1027 | auto handle = (searchHandle_s*)lua_newuserdata(L, sizeof(searchHandle_s));
1028 | handle->fil = new QFileInfoList(fil);
1029 | lua_pushvalue(L, lua_upvalueindex(1));
1030 | lua_setmetatable(L, -2);
1031 | return 1;
1032 | }
1033 |
1034 | static QFileInfoList* GetSearchHandle(lua_State* L, const char* method, bool valid)
1035 | {
1036 | pobwindow->LAssert(L, pobwindow->IsUserData(L, 1, "uisearchhandlemeta"), "searchHandle:%s() must be used on a search handle", method);
1037 | auto searchHandle = (searchHandle_s*)lua_touserdata(L, 1);
1038 | lua_remove(L, 1);
1039 | if (valid) {
1040 | pobwindow->LAssert(L, !searchHandle->fil->isEmpty(), "searchHandle:%s(): search handle is no longer valid (ran out of files to find)", method);
1041 | }
1042 | return searchHandle->fil;
1043 | }
1044 |
1045 | static int l_searchHandleGC(lua_State* L)
1046 | {
1047 | QFileInfoList* searchHandle = GetSearchHandle(L, "__gc", false);
1048 | delete searchHandle;
1049 | return 0;
1050 | }
1051 |
1052 | static int l_searchHandleNextFile(lua_State* L)
1053 | {
1054 | QFileInfoList* searchHandle = GetSearchHandle(L, "NextFile", true);
1055 | searchHandle->removeFirst();
1056 | if ( searchHandle->isEmpty() ) {
1057 | return 0;
1058 | }
1059 | lua_pushboolean(L, 1);
1060 | return 1;
1061 | }
1062 |
1063 | static int l_searchHandleGetFileName(lua_State* L)
1064 | {
1065 | QFileInfoList* searchHandle = GetSearchHandle(L, "GetFileName", true);
1066 | lua_pushstring(L, searchHandle->first().fileName().toStdString().c_str());
1067 | return 1;
1068 | }
1069 |
1070 | static int l_searchHandleGetFileSize(lua_State* L)
1071 | {
1072 | QFileInfoList* searchHandle = GetSearchHandle(L, "GetFileSize", true);
1073 | lua_pushinteger(L, searchHandle->first().size());
1074 | return 1;
1075 | }
1076 |
1077 | static int l_searchHandleGetFileModifiedTime(lua_State* L)
1078 | {
1079 | QFileInfoList* searchHandle = GetSearchHandle(L, "GetFileModifiedTime", true);
1080 | QDateTime modified = searchHandle->first().lastModified();
1081 | lua_pushnumber(L, modified.toMSecsSinceEpoch());
1082 | lua_pushstring(L, modified.date().toString().toStdString().c_str());
1083 | lua_pushstring(L, modified.time().toString().toStdString().c_str());
1084 | return 3;
1085 | }
1086 |
1087 | // =================
1088 | // General Functions
1089 | // =================
1090 |
1091 | static int l_SetWindowTitle(lua_State* L)
1092 | {
1093 | int n = lua_gettop(L);
1094 | pobwindow->LAssert(L, n >= 1, "Usage: SetWindowTitle(title)");
1095 | pobwindow->LAssert(L, lua_isstring(L, 1), "SetWindowTitle() argument 1: expected string, got %t", 1);
1096 | pobwindow->setTitle(lua_tostring(L, 1));
1097 | return 0;
1098 | }
1099 |
1100 | static int l_GetCursorPos(lua_State* L)
1101 | {
1102 | QPoint pos = QCursor::pos();
1103 | pos = pobwindow->mapFromGlobal(pos);
1104 | lua_pushinteger(L, pos.x());
1105 | lua_pushinteger(L, pos.y());
1106 | return 2;
1107 | }
1108 |
1109 | static int l_SetCursorPos(lua_State* L)
1110 | {
1111 | int n = lua_gettop(L);
1112 | pobwindow->LAssert(L, n >= 2, "Usage: SetCursorPos(x, y)");
1113 | pobwindow->LAssert(L, lua_isnumber(L, 1), "SetCursorPos() argument 1: expected number, got %t", 1);
1114 | pobwindow->LAssert(L, lua_isnumber(L, 2), "SetCursorPos() argument 2: expected number, got %t", 2);
1115 | //pobwindow->sys->video->SetRelativeCursor((int)lua_tointeger(L, 1), (int)lua_tointeger(L, 2));
1116 | return 0;
1117 | }
1118 |
1119 | static int l_ShowCursor(lua_State* L)
1120 | {
1121 | int n = lua_gettop(L);
1122 | pobwindow->LAssert(L, n >= 1, "Usage: ShowCursor(doShow)");
1123 | //pobwindow->sys->ShowCursor(lua_toboolean(L, 1));
1124 | return 0;
1125 | }
1126 |
1127 | static int l_IsKeyDown(lua_State* L)
1128 | {
1129 | int n = lua_gettop(L);
1130 | pobwindow->LAssert(L, n >= 1, "Usage: IsKeyDown(keyName)");
1131 | pobwindow->LAssert(L, lua_isstring(L, 1), "IsKeyDown() argument 1: expected string, got %t", 1);
1132 | size_t len;
1133 | const char* kname = lua_tolstring(L, 1, &len);
1134 | pobwindow->LAssert(L, len >= 1, "IsKeyDown() argument 1: string is empty", 1);
1135 | QString k(kname);
1136 | bool result = false;
1137 | if (k == "LEFTBUTTON") {
1138 | if (QGuiApplication::mouseButtons() & Qt::LeftButton) {
1139 | result = true;
1140 | }
1141 | } else {
1142 | int keys = QGuiApplication::keyboardModifiers();
1143 | if (k == "CTRL") {
1144 | result = keys & Qt::ControlModifier;
1145 | } else if (k == "SHIFT") {
1146 | result = keys & Qt::ShiftModifier;
1147 | } else if (k == "ALT") {
1148 | result = keys & Qt::AltModifier;
1149 | } else {
1150 | std::cout << "UNKNOWN ISKEYDOWN: " << k.toStdString() << std::endl;
1151 | }
1152 | }
1153 | lua_pushboolean(L, result);
1154 | //int key = pobwindow->KeyForName(kname);
1155 | //pobwindow->LAssert(L, key, "IsKeyDown(): unrecognised key name");
1156 | //lua_pushboolean(L, pobwindow->sys->IsKeyDown(key));
1157 | return 1;
1158 | }
1159 |
1160 | static int l_Copy(lua_State* L)
1161 | {
1162 | int n = lua_gettop(L);
1163 | pobwindow->LAssert(L, n >= 1, "Usage: Copy(string)");
1164 | pobwindow->LAssert(L, lua_isstring(L, 1), "Copy() argument 1: expected string, got %t", 1);
1165 | QGuiApplication::clipboard()->setText(lua_tostring(L, 1));
1166 | return 0;
1167 | }
1168 |
1169 | static int l_Paste(lua_State* L)
1170 | {
1171 | QString data = QGuiApplication::clipboard()->text();
1172 | if (data.size()) {
1173 | lua_pushstring(L, data.toStdString().c_str());
1174 | return 1;
1175 | } else {
1176 | return 0;
1177 | }
1178 | }
1179 |
1180 | static int l_Deflate(lua_State* L)
1181 | {
1182 | int n = lua_gettop(L);
1183 | pobwindow->LAssert(L, n >= 1, "Usage: Deflate(string)");
1184 | pobwindow->LAssert(L, lua_isstring(L, 1), "Deflate() argument 1: expected string, got %t", 1);
1185 | z_stream_s z;
1186 | z.zalloc = NULL;
1187 | z.zfree = NULL;
1188 | deflateInit(&z, 9);
1189 | size_t inLen;
1190 | Byte* in = (Byte*)lua_tolstring(L, 1, &inLen);
1191 | int outSz = deflateBound(&z, inLen);
1192 | Byte* out = new Byte[outSz];
1193 | z.next_in = in;
1194 | z.avail_in = inLen;
1195 | z.next_out = out;
1196 | z.avail_out = outSz;
1197 | int err = deflate(&z, Z_FINISH);
1198 | deflateEnd(&z);
1199 | if (err == Z_STREAM_END) {
1200 | lua_pushlstring(L, (const char*)out, z.total_out);
1201 | delete[] out;
1202 | return 1;
1203 | } else {
1204 | lua_pushnil(L);
1205 | lua_pushstring(L, zError(err));
1206 | delete[] out;
1207 | return 2;
1208 | }
1209 | }
1210 |
1211 | static int l_Inflate(lua_State* L)
1212 | {
1213 | int n = lua_gettop(L);
1214 | pobwindow->LAssert(L, n >= 1, "Usage: Inflate(string)");
1215 | pobwindow->LAssert(L, lua_isstring(L, 1), "Inflate() argument 1: expected string, got %t", 1);
1216 | size_t inLen;
1217 | Byte* in = (Byte*)lua_tolstring(L, 1, &inLen);
1218 | int outSz = inLen * 4;
1219 | Byte* out = new Byte[outSz];
1220 | z_stream_s z;
1221 | z.next_in = in;
1222 | z.avail_in = inLen;
1223 | z.zalloc = NULL;
1224 | z.zfree = NULL;
1225 | z.next_out = out;
1226 | z.avail_out = outSz;
1227 | inflateInit(&z);
1228 | int err;
1229 | while ((err = inflate(&z, Z_NO_FLUSH)) == Z_OK) {
1230 | if (z.avail_out == 0) {
1231 | // Output buffer filled, embiggen it
1232 | int newSz = outSz << 1;
1233 | Byte *newOut = (Byte *)realloc(out, newSz);
1234 | if (newOut) {
1235 | out = newOut;
1236 | } else {
1237 | // PANIC
1238 | delete[] out;
1239 | return 0;
1240 | }
1241 | z.next_out = out + outSz;
1242 | z.avail_out = outSz;
1243 | outSz = newSz;
1244 | }
1245 | }
1246 | inflateEnd(&z);
1247 | if (err == Z_STREAM_END) {
1248 | lua_pushlstring(L, (const char*)out, z.total_out);
1249 | delete[] out;
1250 | return 1;
1251 | } else {
1252 | lua_pushnil(L);
1253 | lua_pushstring(L, zError(err));
1254 | delete[] out;
1255 | return 2;
1256 | }
1257 | }
1258 |
1259 | static int l_GetTime(lua_State* L)
1260 | {
1261 | qint64 ms = QDateTime::currentDateTime().toMSecsSinceEpoch() - pobwindow->baseTime;
1262 | lua_pushinteger(L, ms);
1263 | return 1;
1264 | }
1265 |
1266 | static int l_GetScriptPath(lua_State* L)
1267 | {
1268 | lua_pushstring(L, pobwindow->scriptPath.toStdString().c_str());
1269 | return 1;
1270 | }
1271 |
1272 | static int l_GetRuntimePath(lua_State* L)
1273 | {
1274 | lua_pushstring(L, pobwindow->basePath.toStdString().c_str());
1275 | return 1;
1276 | }
1277 |
1278 | static int l_GetUserPath(lua_State* L)
1279 | {
1280 | lua_pushstring(L, pobwindow->userPath.toStdString().c_str());
1281 | return 1;
1282 | }
1283 |
1284 | static int l_MakeDir(lua_State* L)
1285 | {
1286 | int n = lua_gettop(L);
1287 | pobwindow->LAssert(L, n >= 1, "Usage: MakeDir(path)");
1288 | pobwindow->LAssert(L, lua_isstring(L, 1), "MakeDir() argument 1: expected string, got %t", 1);
1289 | lua_pushboolean(L, QDir().mkpath(lua_tostring(L, 1)));
1290 | return 1;
1291 | }
1292 |
1293 | static int l_RemoveDir(lua_State* L)
1294 | {
1295 | int n = lua_gettop(L);
1296 | pobwindow->LAssert(L, n >= 1, "Usage: l_RemoveDir(path)");
1297 | pobwindow->LAssert(L, lua_isstring(L, 1), "l_RemoveDir() argument 1: expected string, got %t", 1);
1298 | QDir d;
1299 | if (!d.rmdir(lua_tostring(L, 1))) {
1300 | lua_pushnil(L);
1301 | return 1;
1302 | } else {
1303 | lua_pushboolean(L, true);
1304 | return 1;
1305 | }
1306 | }
1307 |
1308 | static int l_SetWorkDir(lua_State* L)
1309 | {
1310 | int n = lua_gettop(L);
1311 | pobwindow->LAssert(L, n >= 1, "Usage: SetWorkDir(path)");
1312 | pobwindow->LAssert(L, lua_isstring(L, 1), "SetWorkDir() argument 1: expected string, got %t", 1);
1313 | if (QDir::setCurrent(lua_tostring(L, 1))) {
1314 | pobwindow->scriptWorkDir = lua_tostring(L, 1);
1315 | }
1316 | return 0;
1317 | }
1318 |
1319 | static int l_GetWorkDir(lua_State* L)
1320 | {
1321 | lua_pushstring(L, QDir::currentPath().toStdString().c_str());
1322 | return 1;
1323 | }
1324 |
1325 | static int l_LaunchSubScript(lua_State* L)
1326 | {
1327 | int n = lua_gettop(L);
1328 | pobwindow->LAssert(L, n >= 3, "Usage: LaunchSubScript(scriptText, funcList, subList[, ...])");
1329 | for (int i = 1; i <= 3; i++) {
1330 | pobwindow->LAssert(L, lua_isstring(L, i), "LaunchSubScript() argument %d: expected string, got %t", i, i);
1331 | }
1332 | for (int i = 4; i <= n; i++) {
1333 | pobwindow->LAssert(L, lua_isnil(L, i) || lua_isboolean(L, i) || lua_isnumber(L, i) || lua_isstring(L, i),
1334 | "LaunchSubScript() argument %d: only nil, boolean, number and string types can be passed to sub script", i);
1335 | }
1336 | int slot = pobwindow->subScriptList.size();
1337 | pobwindow->subScriptList.append(std::make_shared(L));
1338 | // Signal us when the subscript completes so we can trigger a repaint.
1339 | pobwindow->connect( pobwindow->subScriptList[slot].get(), &SubScript::finished, pobwindow, &POBWindow::subScriptFinished );
1340 | pobwindow->subScriptList[slot]->start();
1341 | lua_pushinteger(L, slot);
1342 | return 1;
1343 | }
1344 |
1345 | static int l_AbortSubScript(lua_State* L)
1346 | {
1347 | std::cout << "SUBSCRIPT ABORT STUB" << std::endl;
1348 | return 0;
1349 | /*
1350 | int n = lua_gettop(L);
1351 | pobwindow->LAssert(L, n >= 1, "Usage: AbortSubScript(ssID)");
1352 | pobwindow->LAssert(L, lua_islightuserdata(L, 1), "AbortSubScript() argument 1: expected subscript ID, got %t", 1);
1353 | notdword slot = (notdword)lua_touserdata(L, 1);
1354 | pobwindow->LAssert(L, slot < pobwindow->subScriptSize && pobwindow->subScriptList[slot], "AbortSubScript() argument 1: invalid subscript ID");
1355 | pobwindow->LAssert(L, pobwindow->subScriptList[slot]->IsRunning(), "AbortSubScript(): subscript isn't running");
1356 | ui_ISubScript::FreeHandle(pobwindow->subScriptList[slot]);
1357 | pobwindow->subScriptList[slot] = NULL;
1358 | return 0;
1359 | */
1360 | }
1361 |
1362 | static int l_IsSubScriptRunning(lua_State* L)
1363 | {
1364 | std::cout << "SUBSCRIPT RUNNING STUB" << std::endl;
1365 | return 0;
1366 | /*
1367 | int n = lua_gettop(L);
1368 | pobwindow->LAssert(L, n >= 1, "Usage: IsSubScriptRunning(ssID)");
1369 | pobwindow->LAssert(L, lua_islightuserdata(L, 1), "IsSubScriptRunning() argument 1: expected subscript ID, got %t", 1);
1370 | notdword slot = (notdword)lua_touserdata(L, 1);
1371 | pobwindow->LAssert(L, slot < pobwindow->subScriptSize && pobwindow->subScriptList[slot], "IsSubScriptRunning() argument 1: invalid subscript ID");
1372 | lua_pushboolean(L, pobwindow->subScriptList[slot]->IsRunning());
1373 | return 1;
1374 | */
1375 | }
1376 |
1377 | static int l_LoadModule(lua_State* L)
1378 | {
1379 | int n = lua_gettop(L);
1380 | pobwindow->LAssert(L, n >= 1, "Usage: LoadModule(name[, ...])");
1381 | pobwindow->LAssert(L, lua_isstring(L, 1), "LoadModule() argument 1: expected string, got %t", 1);
1382 | QString fileName(lua_tostring(L, 1));
1383 | if (!fileName.endsWith(".lua")) {
1384 | fileName = fileName + ".lua";
1385 | }
1386 | QDir::setCurrent(pobwindow->scriptPath);
1387 | int err = luaL_loadfile(L, fileName.toStdString().c_str());
1388 | QDir::setCurrent(pobwindow->scriptWorkDir);
1389 | pobwindow->LAssert(L, err == 0, "LoadModule() error loading '%s':\n%s", fileName.toStdString().c_str(), lua_tostring(L, -1));
1390 | lua_replace(L, 1); // Replace module name with module main chunk
1391 | lua_call(L, n - 1, LUA_MULTRET);
1392 | return lua_gettop(L);
1393 | }
1394 |
1395 | static int l_PLoadModule(lua_State* L)
1396 | {
1397 | int n = lua_gettop(L);
1398 | pobwindow->LAssert(L, n >= 1, "Usage: PLoadModule(name[, ...])");
1399 | pobwindow->LAssert(L, lua_isstring(L, 1), "PLoadModule() argument 1: expected string, got %t", 1);
1400 | QString fileName(lua_tostring(L, 1));
1401 | if (!fileName.endsWith(".lua")) {
1402 | fileName = fileName + ".lua";
1403 | }
1404 | QDir::setCurrent(pobwindow->scriptPath);
1405 | int err = luaL_loadfile(L, fileName.toStdString().c_str());
1406 | QDir::setCurrent(pobwindow->scriptWorkDir);
1407 | if (err) {
1408 | return 1;
1409 | }
1410 | lua_replace(L, 1); // Replace module name with module main chunk
1411 | //lua_getfield(L, LUA_REGISTRYINDEX, "traceback");
1412 | //lua_insert(L, 1); // Insert traceback function at start of stack
1413 | err = lua_pcall(L, n - 1, LUA_MULTRET, 0);
1414 | if (err) {
1415 | return 1;
1416 | }
1417 | lua_pushnil(L);
1418 | lua_insert(L, 1);
1419 | // lua_replace(L, 1); // Replace traceback function with nil
1420 | return lua_gettop(L);
1421 | }
1422 |
1423 | static int l_PCall(lua_State* L)
1424 | {
1425 | int n = lua_gettop(L);
1426 | pobwindow->LAssert(L, n >= 1, "Usage: PCall(func[, ...])");
1427 | pobwindow->LAssert(L, lua_isfunction(L, 1), "PCall() argument 1: expected function, got %t", 1);
1428 | lua_getfield(L, LUA_REGISTRYINDEX, "traceback");
1429 | lua_insert(L, 1); // Insert traceback function at start of stack
1430 | int err = lua_pcall(L, n - 1, LUA_MULTRET, 1);
1431 | if (err) {
1432 | lua_error(L);
1433 | return 1;
1434 | }
1435 | lua_pushnil(L);
1436 | lua_replace(L, 1); // Replace traceback function with nil
1437 | return lua_gettop(L);
1438 | }
1439 |
1440 | static int l_ConPrintf(lua_State* L)
1441 | {
1442 | int n = lua_gettop(L);
1443 | pobwindow->LAssert(L, n >= 1, "Usage: ConPrintf(fmt[, ...])");
1444 | pobwindow->LAssert(L, lua_isstring(L, 1), "ConPrintf() argument 1: expected string, got %t", 1);
1445 | lua_pushvalue(L, lua_upvalueindex(1)); // string.format
1446 | lua_insert(L, 1);
1447 | lua_call(L, n, 1);
1448 | pobwindow->LAssert(L, lua_isstring(L, 1), "ConPrintf() error: string.format returned non-string");
1449 | //std::cout << lua_tostring(L, 1) << std::endl;
1450 | //pobwindow->sys->con->Printf("%s\n", lua_tostring(L, 1));
1451 | return 0;
1452 | }
1453 |
1454 | static void printTableItter(lua_State* L, int index, int level, bool recurse)
1455 | {
1456 | lua_checkstack(L, 5);
1457 | lua_pushnil(L);
1458 | while (lua_next(L, index)) {
1459 | for (int t = 0; t < level; t++) std::cout << " ";
1460 | // Print key
1461 | if (lua_type(L, -2) == LUA_TSTRING) {
1462 | std::cout << "[\"" << lua_tostring(L, -2) << "\"] = ";
1463 | } else {
1464 | lua_pushvalue(L, 2); // Push tostring function
1465 | lua_pushvalue(L, -3); // Push key
1466 | lua_call(L, 1, 1); // Call tostring
1467 | std::cout << lua_tostring(L, -1) << " = ";
1468 | lua_pop(L, 1); // Pop result of tostring
1469 | }
1470 | // Print value
1471 | if (lua_type(L, -1) == LUA_TTABLE) {
1472 | bool expand = recurse;
1473 | if (expand) {
1474 | lua_pushvalue(L, -1); // Push value
1475 | lua_gettable(L, 3); // Index printed tables list
1476 | expand = lua_toboolean(L, -1) == 0;
1477 | lua_pop(L, 1); // Pop result of indexing
1478 | }
1479 | if (expand) {
1480 | lua_pushvalue(L, -1); // Push value
1481 | lua_pushboolean(L, 1);
1482 | lua_settable(L, 3); // Add to printed tables list
1483 | std::cout << "table: " << lua_topointer(L, -1) << " {"
1484 | << std::endl;
1485 | printTableItter(L, lua_gettop(L), level + 1, true);
1486 | for (int t = 0; t < level; t++) std::cout << " ";
1487 | std::cout << "}" << std::endl;
1488 | } else {
1489 | std::cout << "table: " << lua_topointer(L, -1) << " { ... }\n";
1490 | }
1491 | } else if (lua_type(L, -1) == LUA_TSTRING) {
1492 | std::cout << "\"" << lua_tostring(L, -1) << "\"" << std::endl;
1493 | } else {
1494 | lua_pushvalue(L, 2); // Push tostring function
1495 | lua_pushvalue(L, -2); // Push value
1496 | lua_call(L, 1, 1); // Call tostring
1497 | std::cout << lua_tostring(L, -1) << std::endl;
1498 | lua_pop(L, 1); // Pop result of tostring
1499 | }
1500 | lua_pop(L, 1); // Pop value
1501 | }
1502 | }
1503 |
1504 | static int l_ConPrintTable(lua_State* L)
1505 | {
1506 | return 0;
1507 | int n = lua_gettop(L);
1508 | pobwindow->LAssert(L, n >= 1, "Usage: ConPrintTable(tbl[, noRecurse])");
1509 | pobwindow->LAssert(L, lua_istable(L, 1), "ConPrintTable() argument 1: expected table, got %t", 1);
1510 | bool recurse = lua_toboolean(L, 2) == 0;
1511 | lua_settop(L, 1);
1512 | lua_getglobal(L, "tostring");
1513 | lua_newtable(L); // Printed tables list
1514 | lua_pushvalue(L, 1); // Push root table
1515 | lua_pushboolean(L, 1);
1516 | lua_settable(L, 3); // Add root table to printed tables list
1517 | printTableItter(L, 1, 0, recurse);
1518 | return 0;
1519 | }
1520 |
1521 | static int l_ConExecute(lua_State* L)
1522 | {
1523 | int n = lua_gettop(L);
1524 | pobwindow->LAssert(L, n >= 1, "Usage: ConExecute(cmd)");
1525 | pobwindow->LAssert(L, lua_isstring(L, 1), "ConExecute() argument 1: expected string, got %t", 1);
1526 | //pobwindow->sys->con->Execute(lua_tostring(L,1)); // FIXME
1527 | return 0;
1528 | }
1529 |
1530 | static int l_ConClear(lua_State* L)
1531 | {
1532 | // pobwindow->sys->con->Clear();
1533 | return 0;
1534 | }
1535 |
1536 | static int l_print(lua_State* L)
1537 | {
1538 | int n = lua_gettop(L);
1539 | lua_getglobal(L, "tostring");
1540 | for (int i = 1; i <= n; i++) {
1541 | lua_pushvalue(L, -1); // Push tostring function
1542 | lua_pushvalue(L, i);
1543 | lua_call(L, 1, 1); // Call tostring
1544 | const char* s = lua_tostring(L, -1);
1545 | pobwindow->LAssert(L, s != NULL, "print() error: tostring returned non-string");
1546 | if (i > 1) std::cout << " ";
1547 | std::cout << s;
1548 | lua_pop(L, 1); // Pop result of tostring
1549 | }
1550 | std::cout << std::endl;
1551 | return 0;
1552 | }
1553 |
1554 | static int l_SpawnProcess(lua_State* L)
1555 | {
1556 | int n = lua_gettop(L);
1557 | pobwindow->LAssert(L, n >= 1, "Usage: SpawnProcess(cmdName[, args])");
1558 | pobwindow->LAssert(L, lua_isstring(L, 1), "SpawnProcess() argument 1: expected string, got %t", 1);
1559 | // FIXME
1560 | // pobwindow->sys->SpawnProcess(lua_tostring(L, 1), lua_tostring(L, 2));
1561 | return 0;
1562 | }
1563 |
1564 | static int l_OpenURL(lua_State* L)
1565 | {
1566 | int n = lua_gettop(L);
1567 | pobwindow->LAssert(L, n >= 1, "Usage: OpenURL(url)");
1568 | pobwindow->LAssert(L, lua_isstring(L, 1), "OpenURL() argument 1: expected string, got %t", 1);
1569 | // FIXME
1570 | //pobwindow->sys->OpenURL(lua_tostring(L, 1));
1571 | return 0;
1572 | }
1573 |
1574 | static int l_SetProfiling(lua_State* L)
1575 | {
1576 | int n = lua_gettop(L);
1577 | pobwindow->LAssert(L, n >= 1, "Usage: SetProfiling(isEnabled)");
1578 | // FIXME
1579 | //pobwindow->debug->SetProfiling(lua_toboolean(L, 1) == 1);
1580 | return 0;
1581 | }
1582 |
1583 | static int l_Restart(lua_State* L)
1584 | {
1585 | // FIXME
1586 | //pobwindow->restartFlag = true;
1587 | return 0;
1588 | }
1589 |
1590 | static int l_Exit(lua_State* L)
1591 | {
1592 | int n = lua_gettop(L);
1593 | const char* msg = nullptr;
1594 | if (n >= 1 && !lua_isnil(L, 1)) {
1595 | pobwindow->LAssert(L, lua_isstring(L, 1), "Exit() argument 1: expected string or nil, got %t", 1);
1596 | msg = lua_tostring(L, 1);
1597 | }
1598 | // FIXME
1599 | //pobwindow->sys->Exit(msg);
1600 | //pobwindow->didExit = true;
1601 | // lua_pushstring(L, "dummy");
1602 | // lua_error(L);
1603 | return 0;
1604 | }
1605 |
1606 | #define ADDFUNC(n) lua_pushcclosure(L, l_##n, 0);lua_setglobal(L, #n);
1607 | #define ADDFUNCCL(n, u) lua_pushcclosure(L, l_##n, u);lua_setglobal(L, #n);
1608 |
1609 | int main(int argc, char **argv)
1610 | {
1611 | #ifdef __APPLE__
1612 | #define GL_SILENCE_DEPRECATION
1613 | QGuiApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
1614 | qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0");
1615 | #endif //__APPLE__
1616 |
1617 | QGuiApplication app{argc, argv};
1618 |
1619 | QStringList args = app.arguments();
1620 |
1621 | pobwindow = new POBWindow;
1622 |
1623 | if (args.size() > 1) {
1624 | bool ok;
1625 | int ff = args[1].toInt(&ok);
1626 | if (ok) {
1627 | pobwindow->fontFudge = ff;
1628 | args.removeAt(1); // Remove our hacky font factor from the arglist passed on to the script
1629 | }
1630 | }
1631 |
1632 | L = luaL_newstate();
1633 | luaL_openlibs(L);
1634 | luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE|LUAJIT_MODE_OFF);
1635 |
1636 | // Callbacks
1637 | lua_newtable(L); // Callbacks table
1638 | lua_pushvalue(L, -1); // Push callbacks table
1639 | ADDFUNCCL(SetCallback, 1);
1640 | lua_pushvalue(L, -1); // Push callbacks table
1641 | ADDFUNCCL(GetCallback, 1);
1642 | lua_pushvalue(L, -1); // Push callbacks table
1643 | ADDFUNCCL(SetMainObject, 1);
1644 | lua_setfield(L, LUA_REGISTRYINDEX, "uicallbacks");
1645 |
1646 | // Image handles
1647 | lua_newtable(L); // Image handle metatable
1648 | lua_pushvalue(L, -1); // Push image handle metatable
1649 | ADDFUNCCL(NewImageHandle, 1);
1650 | lua_pushvalue(L, -1); // Push image handle metatable
1651 | lua_setfield(L, -2, "__index");
1652 | lua_pushcfunction(L, l_imgHandleGC);
1653 | lua_setfield(L, -2, "__gc");
1654 | lua_pushcfunction(L, l_imgHandleLoad);
1655 | lua_setfield(L, -2, "Load");
1656 | lua_pushcfunction(L, l_imgHandleUnload);
1657 | lua_setfield(L, -2, "Unload");
1658 | lua_pushcfunction(L, l_imgHandleIsValid);
1659 | lua_setfield(L, -2, "IsValid");
1660 | lua_pushcfunction(L, l_imgHandleIsLoading);
1661 | lua_setfield(L, -2, "IsLoading");
1662 | lua_pushcfunction(L, l_imgHandleSetLoadingPriority);
1663 | lua_setfield(L, -2, "SetLoadingPriority");
1664 | lua_pushcfunction(L, l_imgHandleImageSize);
1665 | lua_setfield(L, -2, "ImageSize");
1666 | lua_setfield(L, LUA_REGISTRYINDEX, "uiimghandlemeta");
1667 |
1668 | // Rendering
1669 | ADDFUNC(RenderInit);
1670 | ADDFUNC(GetScreenSize);
1671 | ADDFUNC(SetClearColor);
1672 | ADDFUNC(SetDrawLayer);
1673 | ADDFUNC(SetViewport);
1674 | ADDFUNC(SetDrawColor);
1675 | ADDFUNC(DrawImage);
1676 | ADDFUNC(DrawImageQuad);
1677 | ADDFUNC(DrawString);
1678 | ADDFUNC(DrawStringWidth);
1679 | ADDFUNC(DrawStringCursorIndex);
1680 | ADDFUNC(StripEscapes);
1681 | ADDFUNC(GetAsyncCount);
1682 |
1683 | // Search handles
1684 | lua_newtable(L); // Search handle metatable
1685 | lua_pushvalue(L, -1); // Push search handle metatable
1686 | ADDFUNCCL(NewFileSearch, 1);
1687 | lua_pushvalue(L, -1); // Push search handle metatable
1688 | lua_setfield(L, -2, "__index");
1689 | lua_pushcfunction(L, l_searchHandleGC);
1690 | lua_setfield(L, -2, "__gc");
1691 | lua_pushcfunction(L, l_searchHandleNextFile);
1692 | lua_setfield(L, -2, "NextFile");
1693 | lua_pushcfunction(L, l_searchHandleGetFileName);
1694 | lua_setfield(L, -2, "GetFileName");
1695 | lua_pushcfunction(L, l_searchHandleGetFileSize);
1696 | lua_setfield(L, -2, "GetFileSize");
1697 | lua_pushcfunction(L, l_searchHandleGetFileModifiedTime);
1698 | lua_setfield(L, -2, "GetFileModifiedTime");
1699 | lua_setfield(L, LUA_REGISTRYINDEX, "uisearchhandlemeta");
1700 |
1701 | // General function
1702 | ADDFUNC(SetWindowTitle);
1703 | ADDFUNC(GetCursorPos);
1704 | ADDFUNC(SetCursorPos);
1705 | ADDFUNC(ShowCursor);
1706 | ADDFUNC(IsKeyDown);
1707 | ADDFUNC(Copy);
1708 | ADDFUNC(Paste);
1709 | ADDFUNC(Deflate);
1710 | ADDFUNC(Inflate);
1711 | ADDFUNC(GetTime);
1712 | ADDFUNC(GetScriptPath);
1713 | ADDFUNC(GetRuntimePath);
1714 | ADDFUNC(GetUserPath);
1715 | ADDFUNC(MakeDir);
1716 | ADDFUNC(RemoveDir);
1717 | ADDFUNC(SetWorkDir);
1718 | ADDFUNC(GetWorkDir);
1719 | ADDFUNC(LaunchSubScript);
1720 | ADDFUNC(AbortSubScript);
1721 | ADDFUNC(IsSubScriptRunning);
1722 | ADDFUNC(LoadModule);
1723 | ADDFUNC(PLoadModule);
1724 | ADDFUNC(PCall);
1725 | lua_getglobal(L, "string");
1726 | lua_getfield(L, -1, "format");
1727 | ADDFUNCCL(ConPrintf, 1);
1728 | lua_pop(L, 1); // Pop 'string' table
1729 | ADDFUNC(ConPrintTable);
1730 | ADDFUNC(ConExecute);
1731 | ADDFUNC(ConClear);
1732 | ADDFUNC(print);
1733 | ADDFUNC(SpawnProcess);
1734 | ADDFUNC(OpenURL);
1735 | ADDFUNC(SetProfiling);
1736 | ADDFUNC(Restart);
1737 | ADDFUNC(Exit);
1738 | lua_getglobal(L, "os");
1739 | lua_pushcfunction(L, l_Exit);
1740 | lua_setfield(L, -2, "exit");
1741 | lua_pop(L, 1); // Pop 'os' table
1742 | lua_createtable(L, args.size() - 1, 1);
1743 | for (int i = 0; i < args.size(); i++) {
1744 | lua_pushstring(L, args[i].toStdString().c_str());
1745 | lua_rawseti(L, -2, i);
1746 | }
1747 | lua_setglobal(L, "arg");
1748 |
1749 | // Override the package.path so dkjson.lua and other libraries are
1750 | // can be added via `require`
1751 | std::string basePath = pobwindow->basePath.toStdString();
1752 | std::string extraPathCommand = "package.path = package.path .. \";"
1753 | + basePath
1754 | + "/runtime/lua/?.lua\"";
1755 | luaL_dostring(L, extraPathCommand.c_str());
1756 |
1757 | int result = luaL_dofile(L, "Launch.lua");
1758 | if (result != 0) {
1759 | lua_error(L);
1760 | }
1761 |
1762 | pushCallback("OnInit");
1763 | result = lua_pcall(L, 1, 0, 0);
1764 | if (result != 0) {
1765 | lua_error(L);
1766 | }
1767 | pobwindow->resize(800, 600);
1768 | pobwindow->show();
1769 |
1770 | // Add the bundled fonts
1771 | QFontDatabase::addApplicationFont(QDir::currentPath() + "/VeraMono.ttf");
1772 | QFontDatabase::addApplicationFont(QDir::currentPath() + "/LiberationSans-Regular.ttf");
1773 | QFontDatabase::addApplicationFont(QDir::currentPath() + "/LiberationSans-Bold.ttf");
1774 | return app.exec();
1775 | }
1776 |
1777 |
--------------------------------------------------------------------------------
/main.h:
--------------------------------------------------------------------------------
1 | #ifndef MAIN_H
2 | #define MAIN_H
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | // Font alignment
11 | enum r_fontAlign_e {
12 | F_LEFT,
13 | F_CENTRE,
14 | F_RIGHT,
15 | F_CENTRE_X,
16 | F_RIGHT_X
17 | };
18 |
19 | // Fonts
20 | enum r_fonts_e {
21 | F_FIXED, // Monospaced: Bitsteam Vera Sans Mono
22 | F_VAR, // Normal: Liberation Sans
23 | F_VAR_BOLD, // Normal: Liberation Sans Bold
24 | F_NUMFONTS
25 | };
26 |
27 | // Texture flags
28 | enum r_texFlag_e {
29 | TF_CLAMP = 0x01, // Clamp texture
30 | TF_NOMIPMAP = 0x02, // No mipmaps
31 | TF_NEAREST = 0x04, // Use nearest-pixel magnification instead of linear
32 | TF_ASYNC = 0x08 // Asynchronous loading
33 | };
34 |
35 | class Cmd {
36 | public:
37 | virtual ~Cmd() = default;
38 | virtual void execute() = 0;
39 | };
40 |
41 | class ViewportCmd : public Cmd {
42 | public:
43 | ViewportCmd(int X, int Y, int W, int H) : x(X), y(Y), w(W), h(H) {
44 | }
45 |
46 | void execute();
47 | private:
48 | int x, y, w, h;
49 | };
50 |
51 | class ColorCmd : public Cmd {
52 | public:
53 | ColorCmd(float Col[4]) : col {Col[0], Col[1], Col[2], Col[3]} {}
54 | void execute() {
55 | glColor4fv(col);
56 | }
57 | private:
58 | float col[4];
59 | };
60 |
61 | class DrawImageQuadCmd : public Cmd {
62 | public:
63 | DrawImageQuadCmd() {}
64 | DrawImageQuadCmd(std::shared_ptr Tex, float X0, float Y0, float X1, float Y1, float X2, float Y2, float X3, float Y3, float S0 = 0, float T0 = 0, float S1 = 1, float T1 = 0, float S2 = 1, float T2 = 1, float S3 = 0, float T3 = 1) : x {X0, X1, X2, X3}, y {Y0, Y1, Y2, Y3}, s {S0, S1, S2, S3}, t {T0, T1, T2, T3}, tex(Tex) {
65 | }
66 |
67 | void execute();
68 | protected:
69 | std::shared_ptr tex;
70 | float x[4];
71 | float y[4];
72 | float s[4];
73 | float t[4];
74 | };
75 |
76 | class DrawImageCmd : public DrawImageQuadCmd {
77 | public:
78 | DrawImageCmd(std::shared_ptr tex, float x, float y, float w, float h, float s1 = 0, float t1 = 0, float s2 = 1.0f, float t2 = 1.0f) : DrawImageQuadCmd(tex, x, y, x + w, y, x + w, y + h, x, y + h, s1, t1, s2, t1, s2, t2, s1, t2) {
79 | }
80 | };
81 |
82 | class DrawStringCmd : public DrawImageQuadCmd {
83 | public:
84 | DrawStringCmd(float X, float Y, int Align, int Size, int Font, const char *Text);
85 | ~DrawStringCmd() {
86 | }
87 |
88 | void execute() {
89 | float curCol[4];
90 | if (col[3] > 0) {
91 | glGetFloatv(GL_CURRENT_COLOR, curCol);
92 | glColor4fv(col);
93 | }
94 | DrawImageQuadCmd::execute();
95 | if (col[3] > 0) {
96 | glColor4fv(curCol);
97 | }
98 | }
99 |
100 | void setCol(float c0, float c1, float c2) {
101 | col[0] = c0;
102 | col[1] = c1;
103 | col[2] = c2;
104 | col[3] = 1.0f;
105 | }
106 | private:
107 | float col[4];
108 | QString text;
109 | };
110 | #endif
111 |
--------------------------------------------------------------------------------
/meson.build:
--------------------------------------------------------------------------------
1 | project('POB Frontend', 'cpp', default_options : ['cpp_std=c++17'])
2 |
3 | qt5_dep = dependency('qt5', modules : ['Gui','Core','Widgets'])
4 | lua_dep = dependency('luajit')
5 | # NB on OSX you also need to invoke meson like so, because luajit:
6 | # LDFLAGS="-pagezero_size 10000 -image_base 100000000" meson pobfrontend build
7 | if build_machine.system() == 'darwin'
8 | gl_dep = dependency('appleframeworks', modules: ['OpenGL'])
9 | else
10 | gl_dep = dependency('gl')
11 | endif
12 | zlib_dep = dependency('zlib')
13 | curl_dep = dependency('libcurl')
14 |
15 | # Added flag based on https://stackoverflow.com/a/37729971/319066
16 | # and arguments based on https://mesonbuild.com/Adding-arguments.html
17 | compiler_arguments = ['-mmacosx-version-min=10.12', '-isysroot', '/Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk']
18 | add_project_arguments(compiler_arguments , language : 'c')
19 | add_project_arguments(compiler_arguments, language : 'cpp')
20 |
21 | linker_arguments = ['-mmacosx-version-min=10.12', '-isysroot', '/Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk']
22 | add_project_link_arguments(linker_arguments, language : 'c')
23 | add_project_link_arguments(linker_arguments, language : 'cpp')
24 |
25 | # Import the extension module that knows how
26 | # to invoke Qt tools.
27 | qt5 = import('qt5')
28 | prep = qt5.preprocess(moc_headers : ['subscript.hpp', 'pobwindow.hpp'])
29 |
30 | executable('PathOfBuilding',
31 | sources : ['main.cpp', prep],
32 | dependencies : [qt5_dep, gl_dep, zlib_dep, lua_dep, curl_dep],
33 | install : true)
34 |
35 |
36 | if build_machine.system() == 'darwin'
37 | install_data('pobLogo.icns', install_dir : 'Contents/Resources')
38 | install_data('Info.plist', install_dir : 'Contents')
39 | install_data('pobWrapper.sh', install_dir : 'Contents/MacOS')
40 | meson.add_install_script('mesonInstaller.sh')
41 | endif
42 |
--------------------------------------------------------------------------------
/mesonInstaller.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cp -rf "${MESON_SOURCE_ROOT}"/PathOfBuildingBuild/* "${MESON_INSTALL_PREFIX}"/Contents/MacOS/
4 | cp -f "${MESON_SOURCE_ROOT}"/fonts/*.ttf "${MESON_INSTALL_PREFIX}"/Contents/MacOS/
5 |
6 | mkdir -p "${MESON_INSTALL_PREFIX}/Contents/Frameworks"
7 |
8 | # Meson doesn't bundle dependencies of our shared library by default, so we have
9 | # to do it on our own.
10 | #
11 | # This fixes the error:
12 | # "Symbol not found: _curl_easy_option_by_id" since that didn't exist in older
13 | # cURL libraries.
14 | echo 'Bundling dylibs for lcurl.so'
15 | cd "${MESON_INSTALL_PREFIX}/Contents"
16 | dylibbundler --overwrite-dir --create-dir --bundle-deps --fix-file MacOS/lcurl.so
17 |
--------------------------------------------------------------------------------
/pobLogo.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hsource/pobfrontend/f0b601b07915b10878f9ec5eb5e9334265692476/pobLogo.icns
--------------------------------------------------------------------------------
/pobWrapper.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd "${0%/*}"
4 | ./PathOfBuilding
5 |
--------------------------------------------------------------------------------
/pobwindow.hpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "main.h"
10 | #include "subscript.hpp"
11 |
12 | extern "C" {
13 | #include "lua.h"
14 | #include "lualib.h"
15 | #include "lauxlib.h"
16 | #include "luajit.h"
17 | }
18 |
19 |
20 | class POBWindow : public QOpenGLWindow {
21 | Q_OBJECT
22 | public:
23 | // POBWindow(QWindow *parent = 0) : QOpenGLWindow(parent) {};
24 | POBWindow() : stringCache(5) {
25 | // QSurfaceFormat theformat(format());
26 | // format.setProfile(QSurfaceFormat::CompatibilityProfile);
27 | /* format.setDepthBufferSize(24);
28 | format.setStencilBufferSize(0);
29 | format.setGreenBufferSize(8);
30 | format.setRedBufferSize(8);
31 | format.setBlueBufferSize(8);*/
32 | // theformat.setAlphaBufferSize(8);
33 | // std::cout << theformat.hasAlpha() << std::endl;
34 | // setFormat(theformat);
35 | baseTime = QDateTime::currentDateTime().toMSecsSinceEpoch();
36 | scriptPath = QDir::currentPath();
37 | scriptWorkDir = QDir::currentPath();
38 | basePath = QDir::currentPath();
39 | userPath = QDir::homePath();
40 |
41 | fontFudge = 0;
42 |
43 | connect(&updateTimer, &QTimer::timeout, this, QOverload<>::of(&POBWindow::triggerUpdate));
44 | updateTimer.start(100);
45 | }
46 |
47 | // POBWindow() : QOpenGLWindow() {
48 | // };
49 | // ~POBWindow() {};
50 | //protected:
51 |
52 | void initializeGL();
53 | void resizeGL(int w, int h);
54 | void paintGL();
55 |
56 | void subScriptFinished();
57 | void mouseMoveEvent(QMouseEvent *event);
58 | void mousePressEvent(QMouseEvent *event);
59 | void mouseReleaseEvent(QMouseEvent *event);
60 | void mouseDoubleClickEvent(QMouseEvent *event);
61 | void wheelEvent(QWheelEvent *event);
62 | void keyPressEvent(QKeyEvent *event);
63 | void keyReleaseEvent(QKeyEvent *event);
64 |
65 | void LAssert(lua_State* L, int cond, const char* fmt, ...);
66 | int IsUserData(lua_State* L, int index, const char* metaName);
67 |
68 | void SetDrawLayer(int layer);
69 | void SetDrawLayer(int layer, int subLayer);
70 | void SetDrawSubLayer(int subLayer) {
71 | SetDrawLayer(curLayer, subLayer);
72 | }
73 | void AppendCmd(std::unique_ptr cmd);
74 | void DrawColor(const float col[4] = NULL);
75 | void DrawColor(uint32_t col);
76 | qint64 baseTime;
77 | QString scriptPath;
78 | QString scriptWorkDir;
79 | QString basePath;
80 | QString userPath;
81 | int curLayer;
82 | int curSubLayer;
83 | int fontFudge;
84 | int width;
85 | int height;
86 | bool isDrawing;
87 | QString fontName;
88 | float drawColor[4];
89 | std::map, std::vector>> layers;
90 | QList> subScriptList;
91 | std::shared_ptr white;
92 | QCache> stringCache;
93 | QTimer updateTimer;
94 | void triggerUpdate();
95 | };
96 |
--------------------------------------------------------------------------------
/subscript.hpp:
--------------------------------------------------------------------------------
1 | #ifndef SUBSCRIPT_HPP
2 | #define SUBSCRIPT_HPP
3 |
4 | #include
5 |
6 | #include
7 |
8 | extern "C" {
9 | #include "lua.h"
10 | #include "lualib.h"
11 | #include "lauxlib.h"
12 | #include "luajit.h"
13 | }
14 |
15 | static int dummy_ConPrintf(lua_State* L)
16 | {
17 | return 0;
18 | }
19 |
20 | class SubScript : public QThread {
21 | Q_OBJECT
22 | public:
23 | SubScript(lua_State *L_main) {
24 | L = luaL_newstate();
25 | // FIXME check for failure?
26 | lua_pushlightuserdata(L, this);
27 | lua_rawseti(L, LUA_REGISTRYINDEX, 0);
28 | luaL_openlibs(L);
29 | lua_pushcfunction(L, dummy_ConPrintf);
30 | lua_setglobal(L, "ConPrintf");
31 | int err = luaL_loadstring(L, lua_tostring(L_main, 1));
32 | if (err) {
33 | std::cout << "Error in subscript: " << err << std::endl;
34 | std::cout << lua_tostring(L, -1) << std::endl;
35 | }
36 | for (int stackpos = 4;stackpos <= lua_gettop(L_main);stackpos++) {
37 | switch (lua_type(L_main, stackpos)) {
38 | case LUA_TNIL:
39 | lua_pushnil(L);
40 | break;
41 | case LUA_TBOOLEAN:
42 | lua_pushboolean(L, lua_toboolean(L_main, stackpos));
43 | break;
44 | case LUA_TNUMBER:
45 | lua_pushnumber(L, lua_tonumber(L_main, stackpos));
46 | break;
47 | case LUA_TSTRING:
48 | lua_pushstring(L, lua_tostring(L_main, stackpos));
49 | break;
50 | }
51 | }
52 | lua_pushnumber(L, lua_gettop(L_main) - 3);
53 | }
54 |
55 | void run() override {
56 | int numarg = (int)lua_tointeger(L, -1);
57 | lua_pop(L, 1);
58 | if (lua_pcall(L, numarg, LUA_MULTRET, 0)) {
59 | std::cout << "Error in thread call: " << lua_tostring(L, -1) << std::endl;
60 | }
61 | };
62 |
63 | void onSubFinished(lua_State *L_main, int id) {
64 | lua_getfield(L_main, LUA_REGISTRYINDEX, "uicallbacks");
65 | lua_getfield(L_main, -1, "MainObject");
66 | lua_remove(L_main, -2);
67 | lua_getfield(L_main, -1, "OnSubFinished");
68 | lua_insert(L_main, -2);
69 | lua_pushinteger(L_main, id);
70 | int n = lua_gettop(L);
71 | for (int i = 1; i <= n; i++) {
72 | switch (lua_type(L, i)) {
73 | case LUA_TNIL:
74 | lua_pushnil(L_main);
75 | break;
76 | case LUA_TBOOLEAN:
77 | lua_pushboolean(L_main, lua_toboolean(L, i));
78 | break;
79 | case LUA_TNUMBER:
80 | lua_pushnumber(L_main, lua_tonumber(L, i));
81 | break;
82 | case LUA_TSTRING:
83 | lua_pushstring(L_main, lua_tostring(L, i));
84 | break;
85 | default:
86 | std::cout << "Subscript return " << (i - 1) << ": only nil, boolean, number and string can be returned from sub script" << std::endl;
87 | return;
88 | }
89 | }
90 | int result = lua_pcall(L_main, lua_gettop(L) + 2, 0, 0);
91 | if (result) {
92 | std::cout << "Error calling OnSubFinished: " << result << std::endl;
93 | std::cout << lua_tostring(L_main, -1) << std::endl;
94 | }
95 | }
96 | lua_State *L;
97 | };
98 |
99 | #endif
100 |
--------------------------------------------------------------------------------