Showing preview only (1,090K chars total). Download the full file or copy to clipboard to get everything.
Repository: Grisshink/scrap
Branch: main
Commit: e63a9395f400
Files: 67
Total size: 1.0 MB
Directory structure:
gitextract_3r4214vd/
├── .github/
│ ├── generate_notes.py
│ └── workflows/
│ ├── build.yml
│ └── release.yml
├── .gitignore
├── .gitmodules
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── data/
│ ├── nk57-cond.otf
│ ├── nk57-eb.otf
│ └── nk57.otf
├── default.nix
├── examples/
│ ├── 3d.scrp
│ ├── actual_3d.scrp
│ ├── ball.scrp
│ ├── circle.scrp
│ ├── clock.scrp
│ ├── colors.scrp
│ ├── fibonacci.scrp
│ ├── guess.scrp
│ ├── hello_world.scrp
│ ├── neon.scrp
│ └── trig.scrp
├── external/
│ ├── cfgpath.c
│ ├── cfgpath.h
│ ├── nanosvg.h
│ ├── nanosvgrast.h
│ ├── rprand.h
│ ├── tinyfiledialogs.c
│ └── tinyfiledialogs.h
├── scrap.desktop
├── scrap.rc
├── src/
│ ├── ast.c
│ ├── ast.h
│ ├── blocks.c
│ ├── compiler.c
│ ├── compiler.h
│ ├── config.h
│ ├── gc.c
│ ├── gc.h
│ ├── interpreter.c
│ ├── interpreter.h
│ ├── platform.c
│ ├── render.c
│ ├── save.c
│ ├── scrap-runtime.c
│ ├── scrap.c
│ ├── scrap.h
│ ├── scrap_gui.c
│ ├── scrap_gui.h
│ ├── std.c
│ ├── std.h
│ ├── term.c
│ ├── term.h
│ ├── thread.c
│ ├── thread.h
│ ├── ui.c
│ ├── util.c
│ ├── util.h
│ ├── vec.c
│ ├── vec.h
│ ├── vm.c
│ └── window.c
└── translations/
├── kk/
│ └── LC_MESSAGES/
│ └── scrap.po
├── ru/
│ └── LC_MESSAGES/
│ └── scrap.po
└── uk/
└── LC_MESSAGES/
└── scrap.po
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/generate_notes.py
================================================
import re
with open('CHANGELOG.md') as f:
changelog = f.read()
start = re.search('## ', changelog).start()
end = re.search('^# ', changelog[start:], flags=re.MULTILINE).start() + start
print("""
> [!WARNING]
> Scrap now pushes new experimental LLVM builds tagged with `-llvm`. Use these with caution!
""")
print(changelog[start:end].strip())
================================================
FILE: .github/workflows/build.yml
================================================
name: Build
on:
push:
branches:
- "main"
- "dev_**"
paths-ignore:
- "README.md"
- "LICENSE"
- "CHANGELOG.md"
pull_request:
branches:
- "main"
- "dev_**"
paths-ignore:
- "README.md"
- "LICENSE"
- "CHANGELOG.md"
jobs:
build-windows:
name: Windows build
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
- name: Install dependencies
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
install: mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-llvm make gettext
- name: Setup windres
run: ln -sf "${MSYSTEM_PREFIX}/bin/windres.exe" "${MSYSTEM_PREFIX}/bin/x86_64-w64-mingw32-windres"
- name: Build project (With compiler)
run: |
make clean
make USE_COMPILER=TRUE TARGET=WINDOWS
- name: Build project (With interpreter)
run: |
make clean
make TARGET=WINDOWS
build-linux:
name: Linux build
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y --no-install-recommends libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev gettext
- name: Install LLVM
run: |
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | gpg --dearmor -o llvm-snapshot.gpg
sudo mv llvm-snapshot.gpg /etc/apt/trusted.gpg.d/
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-19 main"
sudo apt-get update -y
sudo apt-get install -y --no-install-recommends llvm-19-dev
- name: Build project (With compiler)
run: |
make clean
make USE_COMPILER=TRUE LLVM_CONFIG=llvm-config-19
- name: Build project (With interpreter)
run: |
make clean
make
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
push:
tags:
- 'v*.*-*'
permissions:
contents: write
env:
SCRAP_VERSION: ${{ github.ref_name }}
jobs:
build-linux:
name: Build Linux release
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev gettext zlib1g-dev libzstd-dev libxml2-dev
- name: Install LLVM
run: |
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | gpg --dearmor -o llvm-snapshot.gpg
sudo mv llvm-snapshot.gpg /etc/apt/trusted.gpg.d/
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-19 main"
sudo apt-get update -y
sudo apt-get install -y --no-install-recommends llvm-19-dev
- name: Build Scrap compiler
run: |
make clean
make USE_COMPILER=TRUE LLVM_CONFIG=llvm-config-19 LLVM_LINK_STATIC=TRUE
mkdir -p build/scrap-${SCRAP_VERSION}-llvm-linux
cp -r data examples extras locale build/scrap-${SCRAP_VERSION}-llvm-linux/
cp LICENSE README.md CHANGELOG.md scrap libscrapstd.a build/scrap-${SCRAP_VERSION}-llvm-linux/
tar --directory=build -czf build/scrap-${SCRAP_VERSION}-llvm-linux.tar.gz scrap-${SCRAP_VERSION}-llvm-linux
mkdir -p dist
mv build/*.gz dist/
- name: Build Scrap interpreter
run: |
make clean
make
mkdir -p build/scrap-${SCRAP_VERSION}-linux
cp -r data examples extras locale build/scrap-${SCRAP_VERSION}-linux/
cp LICENSE README.md CHANGELOG.md scrap libscrapstd.a build/scrap-${SCRAP_VERSION}-linux/
tar --directory=build -czf build/scrap-${SCRAP_VERSION}-linux.tar.gz scrap-${SCRAP_VERSION}-linux
mv build/*.gz dist/
- name: Upload Linux artifacts
uses: actions/upload-artifact@v6
with:
name: scrap-${{ env.SCRAP_VERSION }}-linux
path: dist/*
retention-days: 10
build-appimage:
name: Build Appimage release
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev gettext zlib1g-dev libzstd-dev libxml2-dev
- name: Install LLVM
run: |
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | gpg --dearmor -o llvm-snapshot.gpg
sudo mv llvm-snapshot.gpg /etc/apt/trusted.gpg.d/
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-19 main"
sudo apt-get update -y
sudo apt-get install -y --no-install-recommends llvm-19-dev
- name: Install AppImageTool
run: |
wget -O appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x appimagetool
sudo mv appimagetool /usr/bin/appimagetool
- name: Build Scrap compiler
run: |
make clean
make USE_COMPILER=TRUE LLVM_CONFIG=llvm-config-19 LLVM_LINK_STATIC=TRUE
mkdir -p build/scrap.AppDir
cp scrap build/scrap.AppDir/AppRun
cp -r data locale build/scrap.AppDir/
cp scrap.desktop libscrapstd.a extras/scrap.png build/scrap.AppDir/
mkdir -p dist
appimagetool --appimage-extract-and-run build/scrap.AppDir build/Scrap-${SCRAP_VERSION}-llvm.AppImage
mv build/Scrap-${SCRAP_VERSION}-llvm.AppImage dist/
- name: Build Scrap interpreter
run: |
make clean
make
mkdir -p build/scrap.AppDir
cp scrap build/scrap.AppDir/AppRun
cp -r data locale build/scrap.AppDir/
cp scrap.desktop libscrapstd.a extras/scrap.png build/scrap.AppDir/
appimagetool --appimage-extract-and-run build/scrap.AppDir build/Scrap-${SCRAP_VERSION}.AppImage
mv build/Scrap-${SCRAP_VERSION}.AppImage dist/
- name: Upload AppImage artifacts
uses: actions/upload-artifact@v6
with:
name: scrap-${{ env.SCRAP_VERSION }}-appimage
path: dist/*
retention-days: 10
build-windows:
name: Build Windows release
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
- name: Install dependencies
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
install: mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-llvm make gettext
- name: Setup windres
run: ln -sf "${MSYSTEM_PREFIX}/bin/windres.exe" "${MSYSTEM_PREFIX}/bin/x86_64-w64-mingw32-windres"
- name: Build Scrap compiler
run: |
make clean
make USE_COMPILER=TRUE TARGET=WINDOWS
mkdir -p build/scrap-${SCRAP_VERSION}-llvm-windows64
cp -r locale data examples extras build/scrap-${SCRAP_VERSION}-llvm-windows64/
cp CHANGELOG.md LICENSE README.md libscrapstd-win.a scrap.exe build/scrap-${SCRAP_VERSION}-llvm-windows64/
powershell.exe -Command "Compress-Archive -Path build/scrap-${SCRAP_VERSION}-llvm-windows64 -DestinationPath build/scrap-${SCRAP_VERSION}-llvm-windows64.zip -Force"
mkdir -p dist
mv build/*.zip dist/
- name: Build Scrap interpreter
run: |
make clean
make TARGET=WINDOWS
mkdir -p build/scrap-${SCRAP_VERSION}-windows64
cp -r locale data examples extras build/scrap-${SCRAP_VERSION}-windows64/
cp CHANGELOG.md LICENSE README.md libscrapstd-win.a scrap.exe build/scrap-${SCRAP_VERSION}-windows64/
powershell.exe -Command "Compress-Archive -Path build/scrap-${SCRAP_VERSION}-windows64 -DestinationPath build/scrap-${SCRAP_VERSION}-windows64.zip -Force"
mv build/*.zip dist/
- name: Upload Windows artifacts
uses: actions/upload-artifact@v6
with:
name: scrap-${{ env.SCRAP_VERSION }}-windows64
path: dist/*
retention-days: 10
release:
needs: [build-linux, build-appimage, build-windows]
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Download build artifacts
uses: actions/download-artifact@v7
with:
path: dist
pattern: 'scrap-*'
merge-multiple: true
- name: Generate release notes
run: python "$GITHUB_WORKSPACE/.github/generate_notes.py" > release_notes.md
- name: Create a draft release
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
gh release create "$SCRAP_VERSION" --draft --title "$SCRAP_VERSION" --notes-file release_notes.md
gh release upload "$SCRAP_VERSION" "$GITHUB_WORKSPACE/dist/*.AppImage"
gh release upload "$SCRAP_VERSION" "$GITHUB_WORKSPACE/dist/*.tar.gz"
gh release upload "$SCRAP_VERSION" "$GITHUB_WORKSPACE/dist/*.zip"
================================================
FILE: .gitignore
================================================
tags
*.o
scrap
scrap.exe
profile.json
coredump
config.txt
scrap.res
private/
locale/
scrap.AppDir/
build/
a.out
libscrapstd.a
libscrapstd-win.a
================================================
FILE: .gitmodules
================================================
[submodule "raylib"]
path = raylib
url = https://github.com/raysan5/raylib.git
================================================
FILE: CHANGELOG.md
================================================
# v0.6.1-beta *(27-02-2026)*
## What's new?
- Re-added block folding feature. Now if the last argument size was more than 500 pixels then the next arguments will be drawn on the next line to save horizontal space
## Fixes
- Fixed buffer overflow when rendering glyphs that are not present in font (This also fixes text in Kazakh language being absolutely broken)
- Fixed crash when saving/loading blocks with color arguments
- Fixed memory leak when converting legacy color arguments
# v0.6-beta *(31-01-2026)*
## What's new?
- Scrap now shows confirmation window when trying to close scrap with unsaved changes
- Blocks inside block pallete are now split into subcategories
- Added new color type and integrated it with color related blocks
- Added new example (neon.scrp) featuring new color system
- Added ability to change colors of custom blocks
- Added browse button for path text inputs
- Added various icons to buttons and windows
- Added multiple block pickup system. You can now pickup and drop multiple block chains using `shift` button
- Added a settings option to toggle block previews
- UI size and Font settings can now be applied without reloading the app
## Fixes
- Fixed block definitions being able to be edited in block palette
- Fixed pow block not working with float values in compiler
- Dropdowns now close when dragging code area with middle mouse button. This prevents a bunch of crashes related to dropdowns
# v0.5.1-beta *(27-12-2025)*
## What's new?
- Updated Raylib version to latest commit (fc843dc557 as of time writing)
- Added visual feedback when settings are applied
- Text inputs in blocks are now rendered as slightly tinted to block color
## Fixes
- Fixed search menu spawning incomplete control blocks
- Fixed text inputs being editable in block palette
- Projects built with LLVM now switch to UTF-8 code page on windows. This fixes garbled output when printing characters outside ASCII range
# v0.5-beta *(20-12-2025)*
## What's new?
- Added new experimental LLVM compiler backend. It is available as a separate download option in the releases (tagged with `-llvm`)
- (LLVM only) Added option to build scrap project into executable. Windows users are expected to have gcc (Specifically `x86_64-w64-mingw32-gcc`) installed and added to PATH, Linux users only need a linker to build, such as `ld` (Configurable in build options)
- All variables declared under `When |> clicked` are now considered global and can be accessed anywhere in the code. The rest of the variables are considered local and only visible in the scope they are declared
- Added a lot of runtime/compile time errors, such as out of scope variable access, mismatched types and etc.
- Shortened list and variable blocks to make code a bit more concise
- Implemented text selection to all text inputs, as well as more useful shortcuts such as Shift selection (Shift-<arrows>), copy (Ctrl-C), paste (Ctrl-V), cut (Ctrl-X), delete all (Ctrl-U) and select all (Ctrl-A)
- Terminal contents are now cropped when the terminal is resized
- Added block previews when trying to attach blockchains together
- Save files are no longer limited to 32 KB
## Fixes
- Fixed numpad Enter key not working in certain scenarios
- Fixed race condition with thread running state after calling `pthread_create`. This should theoretically fix code not stopping its execution on Windows
- Fixed code area being able to scroll while window is open
- Fixed memory leak when copying blockdef with instantiated blocks
- Fixed block search menu being able to open when code is running
- Control blocks (like while, if) now render correctly in the block palette
- Fixed code area being able to be dragged outside the code panel when code is running
# v0.4.2-beta *(12-02-2025)*
## Fixes
- Fixed loaded custom blocks having undefined hints
- Fixed textboxed being interactable while vm is running
- Fixed code area floating away when editing panel while the block is selected
- Minor translation fixes
# v0.4.1-beta *(07-02-2025)*
## What's new?
- Added Ukrainian translation *(by @jackmophin)*
## Fixes
- Fixed localizations sometimes not working on Windows
- Fixed codebase scrolling with search menu at the same time
# v0.4-beta *(05-02-2025)*
## What's new?
- Added translations for 2 languages: Russian *(by @Grisshink)* and Kazakh *(by @unknownkeyNB)*
- The sidebar (Now named as block palette to remove ambiguity) is now split up into various categories to make finding blocks easier
- The terminal's background color has been changed to match with the color of other panels
- All of the text boxes were upgraded to allow inserting or deleting at any position
- Now if any block input is empty, it will show a small hint of what it needs
- Added codebase movement through keyboard keys, see `README.md` for more details
- Added block search menu. You can open it by pressing `S` in code area
## Fixes
- Fixed "crash" when vm overflows/underflows one its stacks
- Fixed crash when trying to divide by zero in code
- Fixed scrollbars sometimes appearing behind scroll container
- Fixed text in the settings going out of bounds when the text is too large
- Fixed codespace occasionally jumping far away when it is being dragged outside of the window
- Fixed code renderer not checking with proper culling bounds. This should slightly improve performance of the renderer
# v0.3.1-beta *(28-01-2025)*
## Fixes
- Fixed a crash when attaching a block on a chain which overlaps on top of another block which is an argument to another block in different chain
- Fixed scroll containers not updating their lower bounds when resized
# v0.3-beta *(26-01-2025)*
## What's new?
- The whole gui system was reworked to remove cluttered code and to allow more flexible UI. As a result some parts of the UI may have changed slightly
- Added `New project` button to quickly clear the workspace
- The code area has been split up into flexible, customizable panels. This gives a lot more choice for UI customization
- Now scrap only redraws the screen if its internal state is changed or an input is recieved
- Updated `actual_3d.scrp` example
- Now scrap config is saved in OS specific folder, instead of saving relative to the working directory
- Added terminal colors support
- Added `colors.scrp` example to demonstrate the use of colors
# v0.2-beta *(06-01-2025)*
## What's new?
- Added various string manipulation blocks
- Added shortcuts to run/stop project (they are bound to `F5` and `F6` buttons respectively)
- Added codebase movement through scroll wheel/touchpad
- Added another 3D example
## Fixes
- Fixed save corruption when saving unused custom blocks
- Fixed custom blocks breaking when deleting arguments
- Fixed some compilation issues with gcc-9
- Fixed AppImage paths issue again
- Fixed block highlighting with custom blocks
# v0.1.1-beta *(30-12-2024)*
## What's new?
- Added icon to the executable
- Added experimental MacOS release provided by @arducat
## Fixes
- Fixed AppImage paths issue
- Fixed some resizing issues on linux
# v0.1-beta *(29-12-2024)*
- First beta release!
================================================
FILE: LICENSE
================================================
zlib License
Copyright (C) 2024-2026 Grisshink
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
================================================
FILE: Makefile
================================================
SCRAP_VERSION ?= dev
MAKE ?= make
TARGET ?= LINUX
BUILD_MODE ?= RELEASE
USE_COMPILER ?= FALSE
BUILD_FOLDER := build/
PREFIX ?= /usr/local
ifeq ($(USE_COMPILER), TRUE)
SCRAP_VERSION := $(SCRAP_VERSION)-llvm
endif
CFLAGS := -Wall -Wextra -std=c11 -D_GNU_SOURCE -DSCRAP_VERSION=\"$(SCRAP_VERSION)\" -I./raylib/src
ifeq ($(TARGET), LINUX)
CC := gcc
LDFLAGS := -lm -lpthread -lX11 -ldl
else ifeq ($(TARGET), OSX)
# Thanks to @arducat for MacOS support
CC := clang
LDFLAGS := -framework CoreVideo -framework IOKit -framework Cocoa -framework GLUT -framework OpenGL -lm -lpthread -lintl
else
CC := x86_64-w64-mingw32-gcc
LDFLAGS := -static -lole32 -lcomdlg32 -lwinmm -lgdi32 -lintl -liconv -lshlwapi -Wl,--subsystem,windows
endif
ifeq ($(ARABIC_MODE), TRUE)
CFLAGS += -DARABIC_MODE
endif
ifeq ($(RAM_OVERLOAD), TRUE)
CFLAGS += -DRAM_OVERLOAD
endif
ifeq ($(CC), clang)
CFLAGS += -ferror-limit=5
else
CFLAGS += -fmax-errors=5
endif
ifeq ($(BUILD_MODE), RELEASE)
CFLAGS += -s -O3
else
CFLAGS += -g -O1 -DDEBUG
LDFLAGS += -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer
endif
STD_CFLAGS := $(CFLAGS) -fPIC
ifeq ($(BUILD_MODE), DEBUG)
CFLAGS += -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer
endif
STD_OBJFILES := $(addprefix $(BUILD_FOLDER),vec-stand.o gc-stand.o std-stand.o scrap-runtime.o)
OBJFILES := $(addprefix $(BUILD_FOLDER),filedialogs.o render.o save.o term.o blocks.o scrap.o vec.o util.o ui.o scrap_gui.o window.o cfgpath.o platform.o ast.o gc.o std.o thread.o vm.o)
BUNDLE_FILES := data examples extras locale LICENSE README.md CHANGELOG.md
SCRAP_HEADERS := src/scrap.h src/ast.h src/config.h src/scrap_gui.h
EXE_NAME := scrap
ifeq ($(TARGET), WINDOWS)
STD_NAME := libscrapstd-win.a
else
STD_NAME := libscrapstd.a
endif
ifeq ($(USE_COMPILER), FALSE)
OBJFILES += $(addprefix $(BUILD_FOLDER),interpreter.o)
SCRAP_HEADERS += src/interpreter.h
CFLAGS += -DUSE_INTERPRETER
else
LLVM_CONFIG ?= llvm-config
OBJFILES += $(addprefix $(BUILD_FOLDER),compiler.o)
SCRAP_HEADERS += src/compiler.h
LLVM_LDFLAGS := --ldflags --system-libs --libs core executionengine mcjit analysis native
ifeq ($(TARGET), WINDOWS)
LDFLAGS += `$(LLVM_CONFIG) $(LLVM_FLAGS) --link-static $(LLVM_LDFLAGS) | sed 's/\.dll//'`
else
ifeq ($(LLVM_LINK_STATIC), TRUE)
LDFLAGS += -Wl,-Bstatic `$(LLVM_CONFIG) $(LLVM_FLAGS) --link-static $(LLVM_LDFLAGS)` -Wl,-Bdynamic
else
LDFLAGS += `$(LLVM_CONFIG) $(LLVM_FLAGS) $(LLVM_LDFLAGS)`
endif
endif
CFLAGS += `$(LLVM_CONFIG) --cflags`
LDFLAGS += -lstdc++
endif
.PHONY: all clean target translations
all: target std translations
mkbuild:
mkdir -p $(BUILD_FOLDER)
clean:
$(MAKE) -C raylib/src clean
rm -f scrap.res $(EXE_NAME) $(EXE_NAME).exe libscrapstd.a libscrapstd-win.a
rm -rf locale $(BUILD_FOLDER)
translations:
@echo === Generating locales... ===
rm -rf locale
cp -r translations locale
msgfmt -o locale/ru/LC_MESSAGES/scrap.mo locale/ru/LC_MESSAGES/scrap.po
rm locale/ru/LC_MESSAGES/scrap.po
msgfmt -o locale/kk/LC_MESSAGES/scrap.mo locale/kk/LC_MESSAGES/scrap.po
rm locale/kk/LC_MESSAGES/scrap.po
msgfmt -o locale/uk/LC_MESSAGES/scrap.mo locale/uk/LC_MESSAGES/scrap.po
rm locale/uk/LC_MESSAGES/scrap.po
install: translations target std
mkdir -p $(PREFIX)/share/scrap
mkdir -p $(PREFIX)/share/doc/scrap
mkdir -p $(PREFIX)/bin
mkdir -p $(PREFIX)/lib
cp -r data $(PREFIX)/share/scrap
cp -r locale $(PREFIX)/share
cp -r examples $(PREFIX)/share/doc/scrap
cp $(EXE_NAME) $(PREFIX)/bin
cp $(STD_NAME) $(PREFIX)/lib
uninstall:
rm -rf $(PREFIX)/share/scrap
rm -rf $(PREFIX)/share/doc/scrap
rm -f $(PREFIX)/bin/$(EXE_NAME)
rm -f $(PREFIX)/lib/$(STD_NAME)
ifeq ($(TARGET), WINDOWS)
target: mkbuild $(EXE_NAME).exe
else
target: mkbuild $(EXE_NAME)
endif
$(EXE_NAME).exe: $(OBJFILES)
$(MAKE) -C raylib/src CC=$(CC) PLATFORM_OS=$(TARGET)
x86_64-w64-mingw32-windres scrap.rc -O coff -o scrap.res
$(CC) -o $@ $^ raylib/src/libraylib.a scrap.res $(LDFLAGS)
$(EXE_NAME): $(OBJFILES)
$(MAKE) -C raylib/src CC=$(CC) PLATFORM_OS=$(TARGET)
$(CC) -o $@ $^ raylib/src/libraylib.a $(LDFLAGS)
std: mkbuild $(STD_OBJFILES)
ar rcs $(STD_NAME) $(STD_OBJFILES)
$(BUILD_FOLDER)scrap.o: src/scrap.c $(SCRAP_HEADERS)
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)window.o: src/window.c $(SCRAP_HEADERS) external/tinyfiledialogs.h
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)scrap_gui.o: src/scrap_gui.c src/scrap_gui.h
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)render.o: src/render.c $(SCRAP_HEADERS)
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)save.o: src/save.c $(SCRAP_HEADERS) external/cfgpath.h
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)term.o: src/term.c src/term.h $(SCRAP_HEADERS)
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)blocks.o: src/blocks.c $(SCRAP_HEADERS)
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)vec.o: src/vec.c
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)util.o: src/util.c $(SCRAP_HEADERS)
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)ui.o: src/ui.c $(SCRAP_HEADERS)
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)platform.o: src/platform.c
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)ast.o: src/ast.c src/ast.h
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)interpreter.o: src/interpreter.c $(SCRAP_HEADERS)
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)compiler.o: src/compiler.c src/compiler.h src/gc.h src/ast.h $(SCRAP_HEADERS)
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)gc.o: src/gc.c src/gc.h src/vec.h src/std.h
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)std.o: src/std.c src/std.h src/gc.h src/term.h
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)thread.o: src/thread.c src/thread.h
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)vm.o: src/vm.c $(SCRAP_HEADERS)
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)gc-stand.o: src/gc.c src/gc.h src/vec.h src/std.h
$(CC) $(STD_CFLAGS) -DSTANDALONE_STD -c -o $@ $<
$(BUILD_FOLDER)std-stand.o: src/std.c src/std.h src/gc.h
$(CC) $(STD_CFLAGS) -DSTANDALONE_STD -c -o $@ $<
$(BUILD_FOLDER)scrap-runtime.o: src/scrap-runtime.c src/gc.h
$(CC) $(STD_CFLAGS) -DSTANDALONE_STD -c -o $@ $<
$(BUILD_FOLDER)vec-stand.o: src/vec.c
$(CC) $(STD_CFLAGS) -DSTANDALONE_STD -c -o $@ $<
$(BUILD_FOLDER)filedialogs.o: external/tinyfiledialogs.c
$(CC) $(CFLAGS) -c -o $@ $<
$(BUILD_FOLDER)cfgpath.o: external/cfgpath.c
$(CC) $(CFLAGS) -c -o $@ $<
================================================
FILE: README.md
================================================

# Scrap




Scrap is a new block based programming language with the aim towards advanced users.
It is written in pure C and mostly inspired by other block based languages such as [Scratch](https://scratch.mit.edu/) and
its forks such as [Turbowarp](https://turbowarp.org).
> [!WARNING]
> Scrap is currently in **Beta** stage. Some features may be missing or break, so use with caution!
## Notable advantages from scratch
- *(LLVM only)* Faster runtime. The speed is achieved using compilation through LLVM
- The addition of separate else if, else blocks (C-end blocks as i call them), which eliminates a lot of nested checks with if-else blocks (i.e. more flexible variant of if-else block in Snap!)
- Variables can have a lifetime, which avoids variable name conflicts and allows to make temporary variables
- Custom blocks can return values and can be used as an argument for other block
- Various string manipulation blocks and bitwise operator blocks
- Data type conversion functions
- More strict checks for [[] = []] and [[] != []] blocks. Now they are case sensitive and will check data type for equality
- Lists are now a data type instead of a different type of variable, this allows nesting lists inside a list
- The code runs in a separate thread. This solves some performance issues compared to Scratch
- Modularized interface. Most of the interface can be rearranged or moved to another tab
- *(LLVM only)* Standalone builds. Scrap projects can be built and run as native executables without significant runtime overhead
## Controls
- Click on blocks to pick up them, click again to drop them
- Hold `Ctrl` to take single block, `Alt` to duplicate blocks and `Shift` to pickup/drop multiple block chains
- Hold left mouse button to move around code space
- Holding middle mouse button will do the same, except it works everywhere
- Press `Tab` to jump to chain in code base (Useful if you got lost in code base)
- Press `F5` to run the project. Press `F6` to stop it.
- Press arrow keys while the block is highlighted to move the block cursor around
- Press `Enter` to enter the highlighted text box and `Esc` to leave that text box
- Press `S` to open block search menu
## Binary Installation
### Github releases
See [Releases](https://github.com/Grisshink/scrap/releases) page for all available download options for
Windows, Linux as well as their respective LLVM builds
### AUR
Scrap is now available for download from Arch User Repository (AUR) as [scrap-git](https://aur.archlinux.org/packages/scrap-git) package.
This package will download and build latest Scrap commit from git (LLVM PKGBUILDs are coming soon)
To install Scrap from AUR you can use your preferred AUR helper, for example with `yay`:
```bash
yay -S scrap-git
```
## Building
### Dependencies
Scrap requires these dependencies to run:
- [gettext](https://www.gnu.org/software/gettext/)
- [LLVM](https://llvm.org/) *(Only required if building with `USE_COMPILER=TRUE` flag)*
Currently Scrap can be built for *Windows*, *Linux*, *MacOS* and *FreeBSD*.
#### Download commands for Windows (MSYS2 UCRT64)
```bash
pacman -S mingw-w64-ucrt-x86_64-gcc make gettext
ln -sf "${MSYSTEM_PREFIX}/bin/windres.exe" "${MSYSTEM_PREFIX}/bin/x86_64-w64-mingw32-windres"
```
#### Download commands for Windows (LLVM) *(Experimental)*
If you are going to compile with `USE_COMPILER=TRUE` flag, then you need to install additional dependencies:
```bash
pacman -S mingw-w64-ucrt-x86_64-llvm
```
#### Download commands for Debian
```bash
sudo apt install libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev gettext
```
#### Download commands for Arch linux
Download command for arch-based distributions:
```bash
sudo pacman -S libx11 libxrandr libxi libxcursor libxinerama gettext
```
#### Download commands for OpenSUSE
Download command for openSUSE:
```bash
sudo zypper install libX11-devel libXrandr-devel libXi-devel libXcursor-devel libXinerama-devel gettext
```
### Build
Before building the repo needs to be cloned along with its submodules. To do this, run:
```bash
git clone --recursive https://github.com/Grisshink/scrap.git
cd scrap
```
#### Windows build
NOTE: This guide will assume that you have [MSYS2](https://www.msys2.org/) installed and running on your system.
After that, run the following commands:
```bash
make -B TARGET=WINDOWS
./scrap.exe
```
NOTE: When running `make clean` MSYS2 will occasionally drop you into command prompt.
To fix this, just type `exit` in the cmd and the cleanup process will proceed
#### Linux build
To build and run Scrap on linux you need to install `gcc` (10+) and `make`. After install, just run following commands:
```bash
make -j$(nproc)
./scrap
```
#### FreeBSD build
To build and run Scrap on FreeBSD you need to install `gcc` (10+) and `gmake`. After install, just run following commands:
```bash
gmake MAKE=gmake -j$(nproc)
./scrap
```
#### NixOS build
To build and run Scrap on NixOS, just run the following commands:
```bash
nix-shell
make -j$(nproc)
./scrap
```
#### MacOS build
> [!WARNING]
> MacOS build is not being tested right now, so it may not work properly or not at all, you have been warned!
To build and run Scrap on macOS, you need to install `gcc` (10+) and `make`.
First, install Homebrew:
```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
After that, you need to run the following commands:
```bash
brew install gettext
make -j$(nproc) TARGET=OSX
./scrap
```
Thanks to [@arducat](https://github.com/arducat) for MacOS support.
## Screenshots



## Wait, there is more?
In `examples/` folder you can find some example code writen in Scrap that uses most features from Scrap
In `extras/` folder you can find some various artwork made for Scrap.
The splash art was made by [@FlaffyTheBest](https://scratch.mit.edu/users/FlaffyTheBest/),
the logo was made by [@Grisshink](https://github.com/Grisshink) with some inspiration for logo from [@unixource](https://github.com/unixource),
the wallpaper was made by [@Grisshink](https://github.com/Grisshink)
## License
All scrap code is licensed under the terms of [zlib license](/LICENSE).
================================================
FILE: default.nix
================================================
with import <nixpkgs> {};
pkgs.mkShell {
stdenv = pkgs.clangStdenv;
packages = with pkgs; [
glfw
cmake
clang
wayland
libx11
];
nativeBuildInputs = [
pkgs.libGL
];
LD_LIBRARY_PATH = with pkgs; lib.makeLibraryPath [
libGL
libxrandr
libxinerama
libxcursor
libxi
];
LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
}
# thanks to https://github.com/deltaphc/raylib-rs/issues/187 !
# TODO: implement buildFHSEnv
================================================
FILE: external/cfgpath.c
================================================
#include "cfgpath.h"
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <direct.h>
#define mkdir _mkdir
#endif
#ifdef __unix__
#include <sys/param.h>
#endif
#if defined(CFGPATH_LINUX)
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#elif defined(CFGPATH_WINDOWS)
#include <shlobj.h>
#elif defined(CFGPATH_MAC)
#include <CoreServices/CoreServices.h>
#include <sys/stat.h>
#endif
void get_user_config_file(char *out, unsigned int maxlen, const char *appname)
{
#ifdef CFGPATH_LINUX
const char *out_orig = out;
char *home = getenv("XDG_CONFIG_HOME");
unsigned int config_len = 0;
if (!home) {
home = getenv("HOME");
if (!home) {
// Can't find home directory
out[0] = 0;
return;
}
config_len = strlen(".config/");
}
unsigned int home_len = strlen(home);
unsigned int appname_len = strlen(appname);
const int ext_len = strlen(".conf");
/* first +1 is "/", second is terminating null */
if (home_len + 1 + config_len + appname_len + ext_len + 1 > maxlen) {
out[0] = 0;
return;
}
memcpy(out, home, home_len);
out += home_len;
*out = '/';
out++;
if (config_len) {
memcpy(out, ".config/", config_len);
out += config_len;
/* Make the .config folder if it doesn't already exist */
*out = '\0';
mkdir(out_orig, 0755);
}
memcpy(out, appname, appname_len);
out += appname_len;
memcpy(out, ".conf", ext_len);
out += ext_len;
*out = '\0';
#elif defined(CFGPATH_WINDOWS)
if (maxlen < MAX_PATH) {
out[0] = 0;
return;
}
if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, out))) {
out[0] = 0;
return;
}
/* We don't try to create the AppData folder as it always exists already */
unsigned int appname_len = strlen(appname);
if (strlen(out) + 1 + appname_len + strlen(".ini") + 1 > maxlen) {
out[0] = 0;
return;
}
strcat(out, "\\");
strcat(out, appname);
strcat(out, ".ini");
#elif defined(CFGPATH_MAC)
FSRef ref;
FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
char home[MAX_PATH];
FSRefMakePath(&ref, (UInt8 *)&home, MAX_PATH);
/* first +1 is "/", second is terminating null */
const char *ext = ".conf";
if (strlen(home) + 1 + strlen(appname) + strlen(ext) + 1 > maxlen) {
out[0] = 0;
return;
}
strcpy(out, home);
strcat(out, PATH_SEPARATOR_STRING);
strcat(out, appname);
strcat(out, ext);
#endif
}
void get_user_config_folder(char *out, unsigned int maxlen, const char *appname)
{
#ifdef CFGPATH_LINUX
const char *out_orig = out;
char *home = getenv("XDG_CONFIG_HOME");
unsigned int config_len = 0;
if (!home) {
home = getenv("HOME");
if (!home) {
// Can't find home directory
out[0] = 0;
return;
}
config_len = strlen(".config/");
}
unsigned int home_len = strlen(home);
unsigned int appname_len = strlen(appname);
/* first +1 is "/", second is trailing "/", third is terminating null */
if (home_len + 1 + config_len + appname_len + 1 + 1 > maxlen) {
out[0] = 0;
return;
}
memcpy(out, home, home_len);
out += home_len;
*out = '/';
out++;
if (config_len) {
memcpy(out, ".config/", config_len);
out += config_len;
/* Make the .config folder if it doesn't already exist */
*out = '\0';
mkdir(out_orig, 0755);
}
memcpy(out, appname, appname_len);
out += appname_len;
/* Make the .config/appname folder if it doesn't already exist */
*out = '\0';
mkdir(out_orig, 0755);
*out = '/';
out++;
*out = '\0';
#elif defined(CFGPATH_WINDOWS)
if (maxlen < MAX_PATH) {
out[0] = 0;
return;
}
if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, out))) {
out[0] = 0;
return;
}
/* We don't try to create the AppData folder as it always exists already */
unsigned int appname_len = strlen(appname);
if (strlen(out) + 1 + appname_len + 1 + 1 > maxlen) {
out[0] = 0;
return;
}
strcat(out, "\\");
strcat(out, appname);
/* Make the AppData\appname folder if it doesn't already exist */
mkdir(out);
strcat(out, "\\");
#elif defined(CFGPATH_MAC)
FSRef ref;
FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &ref);
char home[MAX_PATH];
FSRefMakePath(&ref, (UInt8 *)&home, MAX_PATH);
/* first +1 is "/", second is trailing "/", third is terminating null */
if (strlen(home) + 1 + strlen(appname) + 1 + 1 > maxlen) {
out[0] = 0;
return;
}
strcpy(out, home);
strcat(out, PATH_SEPARATOR_STRING);
strcat(out, appname);
/* Make the .config/appname folder if it doesn't already exist */
mkdir(out, 0755);
strcat(out, PATH_SEPARATOR_STRING);
#endif
}
void get_user_data_folder(char *out, unsigned int maxlen, const char *appname)
{
#ifdef CFGPATH_LINUX
const char *out_orig = out;
char *home = getenv("XDG_DATA_HOME");
unsigned int config_len = 0;
if (!home) {
home = getenv("HOME");
if (!home) {
// Can't find home directory
out[0] = 0;
return;
}
config_len = strlen(".local/share/");
}
unsigned int home_len = strlen(home);
unsigned int appname_len = strlen(appname);
/* first +1 is "/", second is trailing "/", third is terminating null */
if (home_len + 1 + config_len + appname_len + 1 + 1 > maxlen) {
out[0] = 0;
return;
}
memcpy(out, home, home_len);
out += home_len;
*out = '/';
out++;
if (config_len) {
memcpy(out, ".local/share/", config_len);
out += config_len;
/* Make the .local/share folder if it doesn't already exist */
*out = '\0';
mkdir(out_orig, 0755);
}
memcpy(out, appname, appname_len);
out += appname_len;
/* Make the .local/share/appname folder if it doesn't already exist */
*out = '\0';
mkdir(out_orig, 0755);
*out = '/';
out++;
*out = '\0';
#elif defined(CFGPATH_WINDOWS) || defined(CFGPATH_MAC)
/* No distinction under Windows or OS X */
get_user_config_folder(out, maxlen, appname);
#endif
}
void get_user_cache_folder(char *out, unsigned int maxlen, const char *appname)
{
#ifdef CFGPATH_LINUX
const char *out_orig = out;
char *home = getenv("XDG_CACHE_HOME");
unsigned int config_len = 0;
if (!home) {
home = getenv("HOME");
if (!home) {
// Can't find home directory
out[0] = 0;
return;
}
config_len = strlen(".cache/");
}
unsigned int home_len = strlen(home);
unsigned int appname_len = strlen(appname);
/* first +1 is "/", second is trailing "/", third is terminating null */
if (home_len + 1 + config_len + appname_len + 1 + 1 > maxlen) {
out[0] = 0;
return;
}
memcpy(out, home, home_len);
out += home_len;
*out = '/';
out++;
if (config_len) {
memcpy(out, ".cache/", config_len);
out += config_len;
/* Make the .cache folder if it doesn't already exist */
*out = '\0';
mkdir(out_orig, 0755);
}
memcpy(out, appname, appname_len);
out += appname_len;
/* Make the .cache/appname folder if it doesn't already exist */
*out = '\0';
mkdir(out_orig, 0755);
*out = '/';
out++;
*out = '\0';
#elif defined(CFGPATH_WINDOWS)
if (maxlen < MAX_PATH) {
out[0] = 0;
return;
}
if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, out))) {
out[0] = 0;
return;
}
/* We don't try to create the AppData folder as it always exists already */
unsigned int appname_len = strlen(appname);
if (strlen(out) + 1 + appname_len + 1 + 1 > maxlen) {
out[0] = 0;
return;
}
strcat(out, "\\");
strcat(out, appname);
/* Make the AppData\appname folder if it doesn't already exist */
mkdir(out);
strcat(out, "\\");
#elif defined(CFGPATH_MAC)
/* No distinction under OS X */
get_user_config_folder(out, maxlen, appname);
#endif
}
================================================
FILE: external/cfgpath.h
================================================
/**
* @file cfgpath.h
* @brief Cross platform methods for obtaining paths to configuration files.
*
* Copyright (C) 2013 Adam Nielsen <malvineous@shikadi.net>
*
* This code is placed in the public domain. You are free to use it for any
* purpose. If you add new platform support, please contribute a patch!
*
* Example use:
*
* char cfgdir[256];
* get_user_config_file(cfgdir, sizeof(cfgdir), "myapp");
* if (cfgdir[0] == 0) {
* printf("Unable to find home directory.\n");
* return 1;
* }
* printf("Saving configuration file to %s\n", cfgdir);
*
* A number of constants are also defined:
*
* - MAX_PATH: Maximum length of a path, in characters. Used to allocate a
* char array large enough to hold the returned path.
*
* - PATH_SEPARATOR_CHAR: The separator between folders. This will be either a
* forward slash or a backslash depending on the platform. This is a
* character constant.
*
* - PATH_SEPARATOR_STRING: The same as PATH_SEPARATOR_CHAR but as a C string,
* to make it easier to append to other string constants.
*/
#ifndef CFGPATH_H_
#define CFGPATH_H_
#define MAX_PATH 512 /* arbitrary value */
#if defined(__linux__) || defined(BSD) || defined(__FreeBSD__)
#define CFGPATH_LINUX
#define PATH_SEPARATOR_CHAR '/'
#define PATH_SEPARATOR_STRING "/"
#elif defined(_WIN32)
#define CFGPATH_WINDOWS
#define PATH_SEPARATOR_CHAR '\\'
#define PATH_SEPARATOR_STRING "\\"
#elif defined(__APPLE__)
#define CFGPATH_MAC
#define PATH_SEPARATOR_CHAR '/'
#define PATH_SEPARATOR_STRING "/"
#else
#error cfgpath.h functions have not been implemented for your platform! Please send patches.
#endif
/** Get an absolute path to a single configuration file, specific to this user.
*
* This function is useful for programs that need only a single configuration
* file. The file is unique to the user account currently logged in.
*
* Output is typically:
*
* Windows: C:\Users\jcitizen\AppData\Roaming\appname.ini
* Linux: /home/jcitizen/.config/appname.conf
* Mac: /Users/jcitizen/Library/Application Support/appname.conf
*
* @param out
* Buffer to write the path. On return will contain the path, or an empty
* string on error.
*
* @param maxlen
* Length of out. Must be >= MAX_PATH.
*
* @param appname
* Short name of the application. Avoid using spaces or version numbers, and
* use lowercase if possible.
*
* @post The file may or may not exist.
* @post The folder holding the file is created if needed.
*/
void get_user_config_file(char *out, unsigned int maxlen, const char *appname);
/** Get an absolute path to a configuration folder, specific to this user.
*
* This function is useful for programs that need to store multiple
* configuration files. The output is a folder (which may not exist and will
* need to be created) suitable for storing a number of files.
*
* The returned path will always end in a platform-specific trailing slash, so
* that a filename can simply be appended to the path.
*
* Output is typically:
*
* Windows: C:\Users\jcitizen\AppData\Roaming\appname\
* Linux: /home/jcitizen/.config/appname/
* Mac: /Users/jcitizen/Library/Application Support/appname/
*
* @param out
* Buffer to write the path. On return will contain the path, or an empty
* string on error.
*
* @param maxlen
* Length of out. Must be >= MAX_PATH.
*
* @param appname
* Short name of the application. Avoid using spaces or version numbers, and
* use lowercase if possible.
*
* @post The folder is created if needed.
*/
void get_user_config_folder(char *out, unsigned int maxlen, const char *appname);
/** Get an absolute path to a data storage folder, specific to this user.
*
* This function is useful for programs that need to store larger amounts of
* data specific to each user. The output is a folder (which may not exist and
* will need to be created) suitable for storing a number of data files.
*
* This path should be used for persistent, important data files the user would
* want to keep. Do not use this path for temporary files, cache files, or
* other files that can be recreated if they are deleted. Use
* get_user_cache_folder() for those instead.
*
* The returned path will always end in a platform-specific trailing slash, so
* that a filename can simply be appended to the path.
*
* Output is typically:
*
* Windows: C:\Users\jcitizen\AppData\Roaming\appname-data\
* Linux: /home/jcitizen/.local/share/appname/
* Mac: /Users/jcitizen/Library/Application Support/appname-data/
*
* @param out
* Buffer to write the path. On return will contain the path, or an empty
* string on error.
*
* @param maxlen
* Length of out. Must be >= MAX_PATH.
*
* @param appname
* Short name of the application. Avoid using spaces or version numbers, and
* use lowercase if possible.
*
* @post The folder is created if needed.
*/
void get_user_data_folder(char *out, unsigned int maxlen, const char *appname);
/** Get an absolute path to a temporary storage folder, specific to this user.
*
* This function is useful for programs that temporarily need to store larger
* amounts of data specific to each user. The output is a folder (which may
* not exist and will need to be created) suitable for storing a number of
* temporary files. The files may be lost or deleted when the program
* terminates.
*
* This path should be used for temporary, unimportant data files that can
* safely be deleted after the program terminates. Do not use this path for
* any important files the user would want to keep. Use get_user_data_folder()
* for those instead.
*
* The returned path will always end in a platform-specific trailing slash, so
* that a filename can simply be appended to the path.
*
* Output is typically:
*
* Windows: C:\Users\jcitizen\AppData\Local\appname\
* Linux: /home/jcitizen/.cache/appname/
* Mac: /Users/jcitizen/Library/Application Support/appname/
*
* @param out
* Buffer to write the path. On return will contain the path, or an empty
* string on error.
*
* @param maxlen
* Length of out. Must be >= MAX_PATH.
*
* @param appname
* Short name of the application. Avoid using spaces or version numbers, and
* use lowercase if possible.
*
* @post The folder is created if needed.
*/
void get_user_cache_folder(char *out, unsigned int maxlen, const char *appname);
#endif /* CFGPATH_H_ */
================================================
FILE: external/nanosvg.h
================================================
/*
* Copyright (c) 2013-14 Mikko Mononen memon@inside.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* The SVG parser is based on Anti-Grain Geometry 2.4 SVG example
* Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/)
*
* Arc calculation code based on canvg (https://code.google.com/p/canvg/)
*
* Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
*
*/
#ifndef NANOSVG_H
#define NANOSVG_H
#ifndef NANOSVG_CPLUSPLUS
#ifdef __cplusplus
extern "C" {
#endif
#endif
// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
//
// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game.
//
// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request!
//
// The shapes in the SVG images are transformed by the viewBox and converted to specified units.
// That is, you should get the same looking data as your designed in your favorite app.
//
// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
//
// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
// DPI (dots-per-inch) controls how the unit conversion is done.
//
// If you don't know or care about the units stuff, "px" and 96 should get you going.
/* Example Usage:
// Load SVG
NSVGimage* image;
image = nsvgParseFromFile("test.svg", "px", 96);
printf("size: %f x %f\n", image->width, image->height);
// Use...
for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) {
for (NSVGpath *path = shape->paths; path != NULL; path = path->next) {
for (int i = 0; i < path->npts-1; i += 3) {
float* p = &path->pts[i*2];
drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
}
}
}
// Delete
nsvgDelete(image);
*/
enum NSVGpaintType {
NSVG_PAINT_UNDEF = -1,
NSVG_PAINT_NONE = 0,
NSVG_PAINT_COLOR = 1,
NSVG_PAINT_LINEAR_GRADIENT = 2,
NSVG_PAINT_RADIAL_GRADIENT = 3
};
enum NSVGspreadType {
NSVG_SPREAD_PAD = 0,
NSVG_SPREAD_REFLECT = 1,
NSVG_SPREAD_REPEAT = 2
};
enum NSVGlineJoin {
NSVG_JOIN_MITER = 0,
NSVG_JOIN_ROUND = 1,
NSVG_JOIN_BEVEL = 2
};
enum NSVGlineCap {
NSVG_CAP_BUTT = 0,
NSVG_CAP_ROUND = 1,
NSVG_CAP_SQUARE = 2
};
enum NSVGfillRule {
NSVG_FILLRULE_NONZERO = 0,
NSVG_FILLRULE_EVENODD = 1
};
enum NSVGflags {
NSVG_FLAGS_VISIBLE = 0x01
};
enum NSVGpaintOrder {
NSVG_PAINT_FILL = 0x00,
NSVG_PAINT_MARKERS = 0x01,
NSVG_PAINT_STROKE = 0x02,
};
typedef struct NSVGgradientStop {
unsigned int color;
float offset;
} NSVGgradientStop;
typedef struct NSVGgradient {
float xform[6];
char spread;
float fx, fy;
int nstops;
NSVGgradientStop stops[1];
} NSVGgradient;
typedef struct NSVGpaint {
signed char type;
union {
unsigned int color;
NSVGgradient* gradient;
};
} NSVGpaint;
typedef struct NSVGpath
{
float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...
int npts; // Total number of bezier points.
char closed; // Flag indicating if shapes should be treated as closed.
float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
struct NSVGpath* next; // Pointer to next path, or NULL if last element.
} NSVGpath;
typedef struct NSVGshape
{
char id[64]; // Optional 'id' attr of the shape or its group
NSVGpaint fill; // Fill paint
NSVGpaint stroke; // Stroke paint
float opacity; // Opacity of the shape.
float strokeWidth; // Stroke width (scaled).
float strokeDashOffset; // Stroke dash offset (scaled).
float strokeDashArray[8]; // Stroke dash array (scaled).
char strokeDashCount; // Number of dash values in dash array.
char strokeLineJoin; // Stroke join type.
char strokeLineCap; // Stroke cap type.
float miterLimit; // Miter limit
char fillRule; // Fill rule, see NSVGfillRule.
unsigned char paintOrder; // Encoded paint order (3×2-bit fields) see NSVGpaintOrder
unsigned char flags; // Logical or of NSVG_FLAGS_* flags
float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
char fillGradient[64]; // Optional 'id' of fill gradient
char strokeGradient[64]; // Optional 'id' of stroke gradient
float xform[6]; // Root transformation for fill/stroke gradient
NSVGpath* paths; // Linked list of paths in the image.
struct NSVGshape* next; // Pointer to next shape, or NULL if last element.
} NSVGshape;
typedef struct NSVGimage
{
float width; // Width of the image.
float height; // Height of the image.
NSVGshape* shapes; // Linked list of shapes in the image.
} NSVGimage;
// Parses SVG file from a file, returns SVG image as paths.
NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi);
// Parses SVG file from a null terminated string, returns SVG image as paths.
// Important note: changes the string.
NSVGimage* nsvgParse(char* input, const char* units, float dpi);
// Duplicates a path.
NSVGpath* nsvgDuplicatePath(NSVGpath* p);
// Deletes an image.
void nsvgDelete(NSVGimage* image);
#ifndef NANOSVG_CPLUSPLUS
#ifdef __cplusplus
}
#endif
#endif
#ifdef NANOSVG_IMPLEMENTATION
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define NSVG_PI (3.14159265358979323846264338327f)
#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs.
#define NSVG_ALIGN_MIN 0
#define NSVG_ALIGN_MID 1
#define NSVG_ALIGN_MAX 2
#define NSVG_ALIGN_NONE 0
#define NSVG_ALIGN_MEET 1
#define NSVG_ALIGN_SLICE 2
#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0)
#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16))
#ifdef _MSC_VER
#pragma warning (disable: 4996) // Switch off security warnings
#pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings
#ifdef __cplusplus
#define NSVG_INLINE inline
#else
#define NSVG_INLINE
#endif
#else
#define NSVG_INLINE inline
#endif
static int nsvg__isspace(char c)
{
return strchr(" \t\n\v\f\r", c) != 0;
}
static int nsvg__isdigit(char c)
{
return c >= '0' && c <= '9';
}
static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; }
static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; }
// Simple XML parser
#define NSVG_XML_TAG 1
#define NSVG_XML_CONTENT 2
#define NSVG_XML_MAX_ATTRIBS 256
static void nsvg__parseContent(char* s,
void (*contentCb)(void* ud, const char* s),
void* ud)
{
// Trim start white spaces
while (*s && nsvg__isspace(*s)) s++;
if (!*s) return;
if (contentCb)
(*contentCb)(ud, s);
}
static void nsvg__parseElement(char* s,
void (*startelCb)(void* ud, const char* el, const char** attr),
void (*endelCb)(void* ud, const char* el),
void* ud)
{
const char* attr[NSVG_XML_MAX_ATTRIBS];
int nattr = 0;
char* name;
int start = 0;
int end = 0;
char quote;
// Skip white space after the '<'
while (*s && nsvg__isspace(*s)) s++;
// Check if the tag is end tag
if (*s == '/') {
s++;
end = 1;
} else {
start = 1;
}
// Skip comments, data and preprocessor stuff.
if (!*s || *s == '?' || *s == '!')
return;
// Get tag name
name = s;
while (*s && !nsvg__isspace(*s)) s++;
if (*s) { *s++ = '\0'; }
// Get attribs
while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {
char* name = NULL;
char* value = NULL;
// Skip white space before the attrib name
while (*s && nsvg__isspace(*s)) s++;
if (!*s) break;
if (*s == '/') {
end = 1;
break;
}
name = s;
// Find end of the attrib name.
while (*s && !nsvg__isspace(*s) && *s != '=') s++;
if (*s) { *s++ = '\0'; }
// Skip until the beginning of the value.
while (*s && *s != '\"' && *s != '\'') s++;
if (!*s) break;
quote = *s;
s++;
// Store value and find the end of it.
value = s;
while (*s && *s != quote) s++;
if (*s) { *s++ = '\0'; }
// Store only well formed attributes
if (name && value) {
attr[nattr++] = name;
attr[nattr++] = value;
}
}
// List terminator
attr[nattr++] = 0;
attr[nattr++] = 0;
// Call callbacks.
if (start && startelCb)
(*startelCb)(ud, name, attr);
if (end && endelCb)
(*endelCb)(ud, name);
}
int nsvg__parseXML(char* input,
void (*startelCb)(void* ud, const char* el, const char** attr),
void (*endelCb)(void* ud, const char* el),
void (*contentCb)(void* ud, const char* s),
void* ud)
{
char* s = input;
char* mark = s;
int state = NSVG_XML_CONTENT;
while (*s) {
if (*s == '<' && state == NSVG_XML_CONTENT) {
// Start of a tag
*s++ = '\0';
nsvg__parseContent(mark, contentCb, ud);
mark = s;
state = NSVG_XML_TAG;
} else if (*s == '>' && state == NSVG_XML_TAG) {
// Start of a content or new tag.
*s++ = '\0';
nsvg__parseElement(mark, startelCb, endelCb, ud);
mark = s;
state = NSVG_XML_CONTENT;
} else {
s++;
}
}
return 1;
}
/* Simple SVG parser. */
#define NSVG_MAX_ATTR 128
enum NSVGgradientUnits {
NSVG_USER_SPACE = 0,
NSVG_OBJECT_SPACE = 1
};
#define NSVG_MAX_DASHES 8
enum NSVGunits {
NSVG_UNITS_USER,
NSVG_UNITS_PX,
NSVG_UNITS_PT,
NSVG_UNITS_PC,
NSVG_UNITS_MM,
NSVG_UNITS_CM,
NSVG_UNITS_IN,
NSVG_UNITS_PERCENT,
NSVG_UNITS_EM,
NSVG_UNITS_EX
};
typedef struct NSVGcoordinate {
float value;
int units;
} NSVGcoordinate;
typedef struct NSVGlinearData {
NSVGcoordinate x1, y1, x2, y2;
} NSVGlinearData;
typedef struct NSVGradialData {
NSVGcoordinate cx, cy, r, fx, fy;
} NSVGradialData;
typedef struct NSVGgradientData
{
char id[64];
char ref[64];
signed char type;
union {
NSVGlinearData linear;
NSVGradialData radial;
};
char spread;
char units;
float xform[6];
int nstops;
NSVGgradientStop* stops;
struct NSVGgradientData* next;
} NSVGgradientData;
typedef struct NSVGattrib
{
char id[64];
float xform[6];
unsigned int fillColor;
unsigned int strokeColor;
float opacity;
float fillOpacity;
float strokeOpacity;
char fillGradient[64];
char strokeGradient[64];
float strokeWidth;
float strokeDashOffset;
float strokeDashArray[NSVG_MAX_DASHES];
int strokeDashCount;
char strokeLineJoin;
char strokeLineCap;
float miterLimit;
char fillRule;
float fontSize;
unsigned int stopColor;
float stopOpacity;
float stopOffset;
char hasFill;
char hasStroke;
char visible;
unsigned char paintOrder;
} NSVGattrib;
typedef struct NSVGparser
{
NSVGattrib attr[NSVG_MAX_ATTR];
int attrHead;
float* pts;
int npts;
int cpts;
NSVGpath* plist;
NSVGimage* image;
NSVGgradientData* gradients;
NSVGshape* shapesTail;
float viewMinx, viewMiny, viewWidth, viewHeight;
int alignX, alignY, alignType;
float dpi;
char pathFlag;
char defsFlag;
} NSVGparser;
static void nsvg__xformIdentity(float* t)
{
t[0] = 1.0f; t[1] = 0.0f;
t[2] = 0.0f; t[3] = 1.0f;
t[4] = 0.0f; t[5] = 0.0f;
}
static void nsvg__xformSetTranslation(float* t, float tx, float ty)
{
t[0] = 1.0f; t[1] = 0.0f;
t[2] = 0.0f; t[3] = 1.0f;
t[4] = tx; t[5] = ty;
}
static void nsvg__xformSetScale(float* t, float sx, float sy)
{
t[0] = sx; t[1] = 0.0f;
t[2] = 0.0f; t[3] = sy;
t[4] = 0.0f; t[5] = 0.0f;
}
static void nsvg__xformSetSkewX(float* t, float a)
{
t[0] = 1.0f; t[1] = 0.0f;
t[2] = tanf(a); t[3] = 1.0f;
t[4] = 0.0f; t[5] = 0.0f;
}
static void nsvg__xformSetSkewY(float* t, float a)
{
t[0] = 1.0f; t[1] = tanf(a);
t[2] = 0.0f; t[3] = 1.0f;
t[4] = 0.0f; t[5] = 0.0f;
}
static void nsvg__xformSetRotation(float* t, float a)
{
float cs = cosf(a), sn = sinf(a);
t[0] = cs; t[1] = sn;
t[2] = -sn; t[3] = cs;
t[4] = 0.0f; t[5] = 0.0f;
}
static void nsvg__xformMultiply(float* t, float* s)
{
float t0 = t[0] * s[0] + t[1] * s[2];
float t2 = t[2] * s[0] + t[3] * s[2];
float t4 = t[4] * s[0] + t[5] * s[2] + s[4];
t[1] = t[0] * s[1] + t[1] * s[3];
t[3] = t[2] * s[1] + t[3] * s[3];
t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
t[0] = t0;
t[2] = t2;
t[4] = t4;
}
static void nsvg__xformInverse(float* inv, float* t)
{
double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1];
if (det > -1e-6 && det < 1e-6) {
nsvg__xformIdentity(t);
return;
}
invdet = 1.0 / det;
inv[0] = (float)(t[3] * invdet);
inv[2] = (float)(-t[2] * invdet);
inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet);
inv[1] = (float)(-t[1] * invdet);
inv[3] = (float)(t[0] * invdet);
inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet);
}
static void nsvg__xformPremultiply(float* t, float* s)
{
float s2[6];
memcpy(s2, s, sizeof(float)*6);
nsvg__xformMultiply(s2, t);
memcpy(t, s2, sizeof(float)*6);
}
static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t)
{
*dx = x*t[0] + y*t[2] + t[4];
*dy = x*t[1] + y*t[3] + t[5];
}
static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t)
{
*dx = x*t[0] + y*t[2];
*dy = x*t[1] + y*t[3];
}
#define NSVG_EPSILON (1e-12)
static int nsvg__ptInBounds(float* pt, float* bounds)
{
return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3];
}
static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3)
{
double it = 1.0-t;
return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3;
}
static void nsvg__curveBounds(float* bounds, float* curve)
{
int i, j, count;
double roots[2], a, b, c, b2ac, t, v;
float* v0 = &curve[0];
float* v1 = &curve[2];
float* v2 = &curve[4];
float* v3 = &curve[6];
// Start the bounding box by end points
bounds[0] = nsvg__minf(v0[0], v3[0]);
bounds[1] = nsvg__minf(v0[1], v3[1]);
bounds[2] = nsvg__maxf(v0[0], v3[0]);
bounds[3] = nsvg__maxf(v0[1], v3[1]);
// Bezier curve fits inside the convex hull of it's control points.
// If control points are inside the bounds, we're done.
if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds))
return;
// Add bezier curve inflection points in X and Y.
for (i = 0; i < 2; i++) {
a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i];
b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i];
c = 3.0 * v1[i] - 3.0 * v0[i];
count = 0;
if (fabs(a) < NSVG_EPSILON) {
if (fabs(b) > NSVG_EPSILON) {
t = -c / b;
if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
roots[count++] = t;
}
} else {
b2ac = b*b - 4.0*c*a;
if (b2ac > NSVG_EPSILON) {
t = (-b + sqrt(b2ac)) / (2.0 * a);
if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
roots[count++] = t;
t = (-b - sqrt(b2ac)) / (2.0 * a);
if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
roots[count++] = t;
}
}
for (j = 0; j < count; j++) {
v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]);
bounds[0+i] = nsvg__minf(bounds[0+i], (float)v);
bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v);
}
}
}
static unsigned char nsvg__encodePaintOrder(enum NSVGpaintOrder a, enum NSVGpaintOrder b, enum NSVGpaintOrder c) {
return (a & 0x03) | ((b & 0x03) << 2) | ((c & 0x03) << 4);
}
static NSVGparser* nsvg__createParser(void)
{
NSVGparser* p;
p = (NSVGparser*)malloc(sizeof(NSVGparser));
if (p == NULL) goto error;
memset(p, 0, sizeof(NSVGparser));
p->image = (NSVGimage*)malloc(sizeof(NSVGimage));
if (p->image == NULL) goto error;
memset(p->image, 0, sizeof(NSVGimage));
// Init style
nsvg__xformIdentity(p->attr[0].xform);
memset(p->attr[0].id, 0, sizeof p->attr[0].id);
p->attr[0].fillColor = NSVG_RGB(0,0,0);
p->attr[0].strokeColor = NSVG_RGB(0,0,0);
p->attr[0].opacity = 1;
p->attr[0].fillOpacity = 1;
p->attr[0].strokeOpacity = 1;
p->attr[0].stopOpacity = 1;
p->attr[0].strokeWidth = 1;
p->attr[0].strokeLineJoin = NSVG_JOIN_MITER;
p->attr[0].strokeLineCap = NSVG_CAP_BUTT;
p->attr[0].miterLimit = 4;
p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
p->attr[0].hasFill = 1;
p->attr[0].visible = 1;
p->attr[0].paintOrder = nsvg__encodePaintOrder(NSVG_PAINT_FILL, NSVG_PAINT_STROKE, NSVG_PAINT_MARKERS);
return p;
error:
if (p) {
if (p->image) free(p->image);
free(p);
}
return NULL;
}
static void nsvg__deletePaths(NSVGpath* path)
{
while (path) {
NSVGpath *next = path->next;
if (path->pts != NULL)
free(path->pts);
free(path);
path = next;
}
}
static void nsvg__deletePaint(NSVGpaint* paint)
{
if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT)
free(paint->gradient);
}
static void nsvg__deleteGradientData(NSVGgradientData* grad)
{
NSVGgradientData* next;
while (grad != NULL) {
next = grad->next;
free(grad->stops);
free(grad);
grad = next;
}
}
static void nsvg__deleteParser(NSVGparser* p)
{
if (p != NULL) {
nsvg__deletePaths(p->plist);
nsvg__deleteGradientData(p->gradients);
nsvgDelete(p->image);
free(p->pts);
free(p);
}
}
static void nsvg__resetPath(NSVGparser* p)
{
p->npts = 0;
}
static void nsvg__addPoint(NSVGparser* p, float x, float y)
{
if (p->npts+1 > p->cpts) {
p->cpts = p->cpts ? p->cpts*2 : 8;
p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float));
if (!p->pts) return;
}
p->pts[p->npts*2+0] = x;
p->pts[p->npts*2+1] = y;
p->npts++;
}
static void nsvg__moveTo(NSVGparser* p, float x, float y)
{
if (p->npts > 0) {
p->pts[(p->npts-1)*2+0] = x;
p->pts[(p->npts-1)*2+1] = y;
} else {
nsvg__addPoint(p, x, y);
}
}
static void nsvg__lineTo(NSVGparser* p, float x, float y)
{
float px,py, dx,dy;
if (p->npts > 0) {
px = p->pts[(p->npts-1)*2+0];
py = p->pts[(p->npts-1)*2+1];
dx = x - px;
dy = y - py;
nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f);
nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f);
nsvg__addPoint(p, x, y);
}
}
static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y)
{
if (p->npts > 0) {
nsvg__addPoint(p, cpx1, cpy1);
nsvg__addPoint(p, cpx2, cpy2);
nsvg__addPoint(p, x, y);
}
}
static NSVGattrib* nsvg__getAttr(NSVGparser* p)
{
return &p->attr[p->attrHead];
}
static void nsvg__pushAttr(NSVGparser* p)
{
if (p->attrHead < NSVG_MAX_ATTR-1) {
p->attrHead++;
memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib));
}
}
static void nsvg__popAttr(NSVGparser* p)
{
if (p->attrHead > 0)
p->attrHead--;
}
static float nsvg__actualOrigX(NSVGparser* p)
{
return p->viewMinx;
}
static float nsvg__actualOrigY(NSVGparser* p)
{
return p->viewMiny;
}
static float nsvg__actualWidth(NSVGparser* p)
{
return p->viewWidth;
}
static float nsvg__actualHeight(NSVGparser* p)
{
return p->viewHeight;
}
static float nsvg__actualLength(NSVGparser* p)
{
float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p);
return sqrtf(w*w + h*h) / sqrtf(2.0f);
}
static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length)
{
NSVGattrib* attr = nsvg__getAttr(p);
switch (c.units) {
case NSVG_UNITS_USER: return c.value;
case NSVG_UNITS_PX: return c.value;
case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi;
case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi;
case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi;
case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi;
case NSVG_UNITS_IN: return c.value * p->dpi;
case NSVG_UNITS_EM: return c.value * attr->fontSize;
case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica.
case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length;
default: return c.value;
}
return c.value;
}
static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id)
{
NSVGgradientData* grad = p->gradients;
if (id == NULL || *id == '\0')
return NULL;
while (grad != NULL) {
if (strcmp(grad->id, id) == 0)
return grad;
grad = grad->next;
}
return NULL;
}
static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, float *xform, signed char* paintType)
{
NSVGgradientData* data = NULL;
NSVGgradientData* ref = NULL;
NSVGgradientStop* stops = NULL;
NSVGgradient* grad;
float ox, oy, sw, sh, sl;
int nstops = 0;
int refIter;
data = nsvg__findGradientData(p, id);
if (data == NULL) return NULL;
// TODO: use ref to fill in all unset values too.
ref = data;
refIter = 0;
while (ref != NULL) {
NSVGgradientData* nextRef = NULL;
if (stops == NULL && ref->stops != NULL) {
stops = ref->stops;
nstops = ref->nstops;
break;
}
nextRef = nsvg__findGradientData(p, ref->ref);
if (nextRef == ref) break; // prevent infite loops on malformed data
ref = nextRef;
refIter++;
if (refIter > 32) break; // prevent infite loops on malformed data
}
if (stops == NULL) return NULL;
grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1));
if (grad == NULL) return NULL;
// The shape width and height.
if (data->units == NSVG_OBJECT_SPACE) {
ox = localBounds[0];
oy = localBounds[1];
sw = localBounds[2] - localBounds[0];
sh = localBounds[3] - localBounds[1];
} else {
ox = nsvg__actualOrigX(p);
oy = nsvg__actualOrigY(p);
sw = nsvg__actualWidth(p);
sh = nsvg__actualHeight(p);
}
sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f);
if (data->type == NSVG_PAINT_LINEAR_GRADIENT) {
float x1, y1, x2, y2, dx, dy;
x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw);
y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh);
x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw);
y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh);
// Calculate transform aligned to the line
dx = x2 - x1;
dy = y2 - y1;
grad->xform[0] = dy; grad->xform[1] = -dx;
grad->xform[2] = dx; grad->xform[3] = dy;
grad->xform[4] = x1; grad->xform[5] = y1;
} else {
float cx, cy, fx, fy, r;
cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw);
cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh);
fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw);
fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh);
r = nsvg__convertToPixels(p, data->radial.r, 0, sl);
// Calculate transform aligned to the circle
grad->xform[0] = r; grad->xform[1] = 0;
grad->xform[2] = 0; grad->xform[3] = r;
grad->xform[4] = cx; grad->xform[5] = cy;
grad->fx = fx / r;
grad->fy = fy / r;
}
nsvg__xformMultiply(grad->xform, data->xform);
nsvg__xformMultiply(grad->xform, xform);
grad->spread = data->spread;
memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop));
grad->nstops = nstops;
*paintType = data->type;
return grad;
}
static float nsvg__getAverageScale(float* t)
{
float sx = sqrtf(t[0]*t[0] + t[2]*t[2]);
float sy = sqrtf(t[1]*t[1] + t[3]*t[3]);
return (sx + sy) * 0.5f;
}
static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform)
{
NSVGpath* path;
float curve[4*2], curveBounds[4];
int i, first = 1;
for (path = shape->paths; path != NULL; path = path->next) {
nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform);
for (i = 0; i < path->npts-1; i += 3) {
nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform);
nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform);
nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform);
nsvg__curveBounds(curveBounds, curve);
if (first) {
bounds[0] = curveBounds[0];
bounds[1] = curveBounds[1];
bounds[2] = curveBounds[2];
bounds[3] = curveBounds[3];
first = 0;
} else {
bounds[0] = nsvg__minf(bounds[0], curveBounds[0]);
bounds[1] = nsvg__minf(bounds[1], curveBounds[1]);
bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]);
bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]);
}
curve[0] = curve[6];
curve[1] = curve[7];
}
}
}
static void nsvg__addShape(NSVGparser* p)
{
NSVGattrib* attr = nsvg__getAttr(p);
float scale = 1.0f;
NSVGshape* shape;
NSVGpath* path;
int i;
if (p->plist == NULL)
return;
shape = (NSVGshape*)malloc(sizeof(NSVGshape));
if (shape == NULL) goto error;
memset(shape, 0, sizeof(NSVGshape));
memcpy(shape->id, attr->id, sizeof shape->id);
memcpy(shape->fillGradient, attr->fillGradient, sizeof shape->fillGradient);
memcpy(shape->strokeGradient, attr->strokeGradient, sizeof shape->strokeGradient);
memcpy(shape->xform, attr->xform, sizeof shape->xform);
scale = nsvg__getAverageScale(attr->xform);
shape->strokeWidth = attr->strokeWidth * scale;
shape->strokeDashOffset = attr->strokeDashOffset * scale;
shape->strokeDashCount = (char)attr->strokeDashCount;
for (i = 0; i < attr->strokeDashCount; i++)
shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
shape->strokeLineJoin = attr->strokeLineJoin;
shape->strokeLineCap = attr->strokeLineCap;
shape->miterLimit = attr->miterLimit;
shape->fillRule = attr->fillRule;
shape->opacity = attr->opacity;
shape->paintOrder = attr->paintOrder;
shape->paths = p->plist;
p->plist = NULL;
// Calculate shape bounds
shape->bounds[0] = shape->paths->bounds[0];
shape->bounds[1] = shape->paths->bounds[1];
shape->bounds[2] = shape->paths->bounds[2];
shape->bounds[3] = shape->paths->bounds[3];
for (path = shape->paths->next; path != NULL; path = path->next) {
shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]);
shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]);
shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]);
shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]);
}
// Set fill
if (attr->hasFill == 0) {
shape->fill.type = NSVG_PAINT_NONE;
} else if (attr->hasFill == 1) {
shape->fill.type = NSVG_PAINT_COLOR;
shape->fill.color = attr->fillColor;
shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24;
} else if (attr->hasFill == 2) {
shape->fill.type = NSVG_PAINT_UNDEF;
}
// Set stroke
if (attr->hasStroke == 0) {
shape->stroke.type = NSVG_PAINT_NONE;
} else if (attr->hasStroke == 1) {
shape->stroke.type = NSVG_PAINT_COLOR;
shape->stroke.color = attr->strokeColor;
shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24;
} else if (attr->hasStroke == 2) {
shape->stroke.type = NSVG_PAINT_UNDEF;
}
// Set flags
shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
// Add to tail
if (p->image->shapes == NULL)
p->image->shapes = shape;
else
p->shapesTail->next = shape;
p->shapesTail = shape;
return;
error:
if (shape) free(shape);
}
static void nsvg__addPath(NSVGparser* p, char closed)
{
NSVGattrib* attr = nsvg__getAttr(p);
NSVGpath* path = NULL;
float bounds[4];
float* curve;
int i;
if (p->npts < 4)
return;
if (closed)
nsvg__lineTo(p, p->pts[0], p->pts[1]);
// Expect 1 + N*3 points (N = number of cubic bezier segments).
if ((p->npts % 3) != 1)
return;
path = (NSVGpath*)malloc(sizeof(NSVGpath));
if (path == NULL) goto error;
memset(path, 0, sizeof(NSVGpath));
path->pts = (float*)malloc(p->npts*2*sizeof(float));
if (path->pts == NULL) goto error;
path->closed = closed;
path->npts = p->npts;
// Transform path.
for (i = 0; i < p->npts; ++i)
nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform);
// Find bounds
for (i = 0; i < path->npts-1; i += 3) {
curve = &path->pts[i*2];
nsvg__curveBounds(bounds, curve);
if (i == 0) {
path->bounds[0] = bounds[0];
path->bounds[1] = bounds[1];
path->bounds[2] = bounds[2];
path->bounds[3] = bounds[3];
} else {
path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]);
path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]);
path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]);
path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]);
}
}
path->next = p->plist;
p->plist = path;
return;
error:
if (path != NULL) {
if (path->pts != NULL) free(path->pts);
free(path);
}
}
// We roll our own string to float because the std library one uses locale and messes things up.
static double nsvg__atof(const char* s)
{
char* cur = (char*)s;
char* end = NULL;
double res = 0.0, sign = 1.0;
long long intPart = 0, fracPart = 0;
char hasIntPart = 0, hasFracPart = 0;
// Parse optional sign
if (*cur == '+') {
cur++;
} else if (*cur == '-') {
sign = -1;
cur++;
}
// Parse integer part
if (nsvg__isdigit(*cur)) {
// Parse digit sequence
intPart = strtoll(cur, &end, 10);
if (cur != end) {
res = (double)intPart;
hasIntPart = 1;
cur = end;
}
}
// Parse fractional part.
if (*cur == '.') {
cur++; // Skip '.'
if (nsvg__isdigit(*cur)) {
// Parse digit sequence
fracPart = strtoll(cur, &end, 10);
if (cur != end) {
res += (double)fracPart / pow(10.0, (double)(end - cur));
hasFracPart = 1;
cur = end;
}
}
}
// A valid number should have integer or fractional part.
if (!hasIntPart && !hasFracPart)
return 0.0;
// Parse optional exponent
if (*cur == 'e' || *cur == 'E') {
long expPart = 0;
cur++; // skip 'E'
expPart = strtol(cur, &end, 10); // Parse digit sequence with sign
if (cur != end) {
res *= pow(10.0, (double)expPart);
}
}
return res * sign;
}
static const char* nsvg__parseNumber(const char* s, char* it, const int size)
{
const int last = size-1;
int i = 0;
// sign
if (*s == '-' || *s == '+') {
if (i < last) it[i++] = *s;
s++;
}
// integer part
while (*s && nsvg__isdigit(*s)) {
if (i < last) it[i++] = *s;
s++;
}
if (*s == '.') {
// decimal point
if (i < last) it[i++] = *s;
s++;
// fraction part
while (*s && nsvg__isdigit(*s)) {
if (i < last) it[i++] = *s;
s++;
}
}
// exponent
if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) {
if (i < last) it[i++] = *s;
s++;
if (*s == '-' || *s == '+') {
if (i < last) it[i++] = *s;
s++;
}
while (*s && nsvg__isdigit(*s)) {
if (i < last) it[i++] = *s;
s++;
}
}
it[i] = '\0';
return s;
}
static const char* nsvg__getNextPathItemWhenArcFlag(const char* s, char* it)
{
it[0] = '\0';
while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
if (!*s) return s;
if (*s == '0' || *s == '1') {
it[0] = *s++;
it[1] = '\0';
return s;
}
return s;
}
static const char* nsvg__getNextPathItem(const char* s, char* it)
{
it[0] = '\0';
// Skip white spaces and commas
while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
if (!*s) return s;
if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) {
s = nsvg__parseNumber(s, it, 64);
} else {
// Parse command
it[0] = *s++;
it[1] = '\0';
return s;
}
return s;
}
static unsigned int nsvg__parseColorHex(const char* str)
{
unsigned int r=0, g=0, b=0;
if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3 ) // 2 digit hex
return NSVG_RGB(r, g, b);
if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3 ) // 1 digit hex, e.g. #abc -> 0xccbbaa
return NSVG_RGB(r*17, g*17, b*17); // same effect as (r<<4|r), (g<<4|g), ..
return NSVG_RGB(128, 128, 128);
}
// Parse rgb color. The pointer 'str' must point at "rgb(" (4+ characters).
// This function returns gray (rgb(128, 128, 128) == '#808080') on parse errors
// for backwards compatibility. Note: other image viewers return black instead.
static unsigned int nsvg__parseColorRGB(const char* str)
{
int i;
unsigned int rgbi[3];
float rgbf[3];
// try decimal integers first
if (sscanf(str, "rgb(%u, %u, %u)", &rgbi[0], &rgbi[1], &rgbi[2]) != 3) {
// integers failed, try percent values (float, locale independent)
const char delimiter[3] = {',', ',', ')'};
str += 4; // skip "rgb("
for (i = 0; i < 3; i++) {
while (*str && (nsvg__isspace(*str))) str++; // skip leading spaces
if (*str == '+') str++; // skip '+' (don't allow '-')
if (!*str) break;
rgbf[i] = nsvg__atof(str);
// Note 1: it would be great if nsvg__atof() returned how many
// bytes it consumed but it doesn't. We need to skip the number,
// the '%' character, spaces, and the delimiter ',' or ')'.
// Note 2: The following code does not allow values like "33.%",
// i.e. a decimal point w/o fractional part, but this is consistent
// with other image viewers, e.g. firefox, chrome, eog, gimp.
while (*str && nsvg__isdigit(*str)) str++; // skip integer part
if (*str == '.') {
str++;
if (!nsvg__isdigit(*str)) break; // error: no digit after '.'
while (*str && nsvg__isdigit(*str)) str++; // skip fractional part
}
if (*str == '%') str++; else break;
while (*str && nsvg__isspace(*str)) str++;
if (*str == delimiter[i]) str++;
else break;
}
if (i == 3) {
rgbi[0] = roundf(rgbf[0] * 2.55f);
rgbi[1] = roundf(rgbf[1] * 2.55f);
rgbi[2] = roundf(rgbf[2] * 2.55f);
} else {
rgbi[0] = rgbi[1] = rgbi[2] = 128;
}
}
// clip values as the CSS spec requires
for (i = 0; i < 3; i++) {
if (rgbi[i] > 255) rgbi[i] = 255;
}
return NSVG_RGB(rgbi[0], rgbi[1], rgbi[2]);
}
typedef struct NSVGNamedColor {
const char* name;
unsigned int color;
} NSVGNamedColor;
NSVGNamedColor nsvg__colors[] = {
{ "red", NSVG_RGB(255, 0, 0) },
{ "green", NSVG_RGB( 0, 128, 0) },
{ "blue", NSVG_RGB( 0, 0, 255) },
{ "yellow", NSVG_RGB(255, 255, 0) },
{ "cyan", NSVG_RGB( 0, 255, 255) },
{ "magenta", NSVG_RGB(255, 0, 255) },
{ "black", NSVG_RGB( 0, 0, 0) },
{ "grey", NSVG_RGB(128, 128, 128) },
{ "gray", NSVG_RGB(128, 128, 128) },
{ "white", NSVG_RGB(255, 255, 255) },
#ifdef NANOSVG_ALL_COLOR_KEYWORDS
{ "aliceblue", NSVG_RGB(240, 248, 255) },
{ "antiquewhite", NSVG_RGB(250, 235, 215) },
{ "aqua", NSVG_RGB( 0, 255, 255) },
{ "aquamarine", NSVG_RGB(127, 255, 212) },
{ "azure", NSVG_RGB(240, 255, 255) },
{ "beige", NSVG_RGB(245, 245, 220) },
{ "bisque", NSVG_RGB(255, 228, 196) },
{ "blanchedalmond", NSVG_RGB(255, 235, 205) },
{ "blueviolet", NSVG_RGB(138, 43, 226) },
{ "brown", NSVG_RGB(165, 42, 42) },
{ "burlywood", NSVG_RGB(222, 184, 135) },
{ "cadetblue", NSVG_RGB( 95, 158, 160) },
{ "chartreuse", NSVG_RGB(127, 255, 0) },
{ "chocolate", NSVG_RGB(210, 105, 30) },
{ "coral", NSVG_RGB(255, 127, 80) },
{ "cornflowerblue", NSVG_RGB(100, 149, 237) },
{ "cornsilk", NSVG_RGB(255, 248, 220) },
{ "crimson", NSVG_RGB(220, 20, 60) },
{ "darkblue", NSVG_RGB( 0, 0, 139) },
{ "darkcyan", NSVG_RGB( 0, 139, 139) },
{ "darkgoldenrod", NSVG_RGB(184, 134, 11) },
{ "darkgray", NSVG_RGB(169, 169, 169) },
{ "darkgreen", NSVG_RGB( 0, 100, 0) },
{ "darkgrey", NSVG_RGB(169, 169, 169) },
{ "darkkhaki", NSVG_RGB(189, 183, 107) },
{ "darkmagenta", NSVG_RGB(139, 0, 139) },
{ "darkolivegreen", NSVG_RGB( 85, 107, 47) },
{ "darkorange", NSVG_RGB(255, 140, 0) },
{ "darkorchid", NSVG_RGB(153, 50, 204) },
{ "darkred", NSVG_RGB(139, 0, 0) },
{ "darksalmon", NSVG_RGB(233, 150, 122) },
{ "darkseagreen", NSVG_RGB(143, 188, 143) },
{ "darkslateblue", NSVG_RGB( 72, 61, 139) },
{ "darkslategray", NSVG_RGB( 47, 79, 79) },
{ "darkslategrey", NSVG_RGB( 47, 79, 79) },
{ "darkturquoise", NSVG_RGB( 0, 206, 209) },
{ "darkviolet", NSVG_RGB(148, 0, 211) },
{ "deeppink", NSVG_RGB(255, 20, 147) },
{ "deepskyblue", NSVG_RGB( 0, 191, 255) },
{ "dimgray", NSVG_RGB(105, 105, 105) },
{ "dimgrey", NSVG_RGB(105, 105, 105) },
{ "dodgerblue", NSVG_RGB( 30, 144, 255) },
{ "firebrick", NSVG_RGB(178, 34, 34) },
{ "floralwhite", NSVG_RGB(255, 250, 240) },
{ "forestgreen", NSVG_RGB( 34, 139, 34) },
{ "fuchsia", NSVG_RGB(255, 0, 255) },
{ "gainsboro", NSVG_RGB(220, 220, 220) },
{ "ghostwhite", NSVG_RGB(248, 248, 255) },
{ "gold", NSVG_RGB(255, 215, 0) },
{ "goldenrod", NSVG_RGB(218, 165, 32) },
{ "greenyellow", NSVG_RGB(173, 255, 47) },
{ "honeydew", NSVG_RGB(240, 255, 240) },
{ "hotpink", NSVG_RGB(255, 105, 180) },
{ "indianred", NSVG_RGB(205, 92, 92) },
{ "indigo", NSVG_RGB( 75, 0, 130) },
{ "ivory", NSVG_RGB(255, 255, 240) },
{ "khaki", NSVG_RGB(240, 230, 140) },
{ "lavender", NSVG_RGB(230, 230, 250) },
{ "lavenderblush", NSVG_RGB(255, 240, 245) },
{ "lawngreen", NSVG_RGB(124, 252, 0) },
{ "lemonchiffon", NSVG_RGB(255, 250, 205) },
{ "lightblue", NSVG_RGB(173, 216, 230) },
{ "lightcoral", NSVG_RGB(240, 128, 128) },
{ "lightcyan", NSVG_RGB(224, 255, 255) },
{ "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) },
{ "lightgray", NSVG_RGB(211, 211, 211) },
{ "lightgreen", NSVG_RGB(144, 238, 144) },
{ "lightgrey", NSVG_RGB(211, 211, 211) },
{ "lightpink", NSVG_RGB(255, 182, 193) },
{ "lightsalmon", NSVG_RGB(255, 160, 122) },
{ "lightseagreen", NSVG_RGB( 32, 178, 170) },
{ "lightskyblue", NSVG_RGB(135, 206, 250) },
{ "lightslategray", NSVG_RGB(119, 136, 153) },
{ "lightslategrey", NSVG_RGB(119, 136, 153) },
{ "lightsteelblue", NSVG_RGB(176, 196, 222) },
{ "lightyellow", NSVG_RGB(255, 255, 224) },
{ "lime", NSVG_RGB( 0, 255, 0) },
{ "limegreen", NSVG_RGB( 50, 205, 50) },
{ "linen", NSVG_RGB(250, 240, 230) },
{ "maroon", NSVG_RGB(128, 0, 0) },
{ "mediumaquamarine", NSVG_RGB(102, 205, 170) },
{ "mediumblue", NSVG_RGB( 0, 0, 205) },
{ "mediumorchid", NSVG_RGB(186, 85, 211) },
{ "mediumpurple", NSVG_RGB(147, 112, 219) },
{ "mediumseagreen", NSVG_RGB( 60, 179, 113) },
{ "mediumslateblue", NSVG_RGB(123, 104, 238) },
{ "mediumspringgreen", NSVG_RGB( 0, 250, 154) },
{ "mediumturquoise", NSVG_RGB( 72, 209, 204) },
{ "mediumvioletred", NSVG_RGB(199, 21, 133) },
{ "midnightblue", NSVG_RGB( 25, 25, 112) },
{ "mintcream", NSVG_RGB(245, 255, 250) },
{ "mistyrose", NSVG_RGB(255, 228, 225) },
{ "moccasin", NSVG_RGB(255, 228, 181) },
{ "navajowhite", NSVG_RGB(255, 222, 173) },
{ "navy", NSVG_RGB( 0, 0, 128) },
{ "oldlace", NSVG_RGB(253, 245, 230) },
{ "olive", NSVG_RGB(128, 128, 0) },
{ "olivedrab", NSVG_RGB(107, 142, 35) },
{ "orange", NSVG_RGB(255, 165, 0) },
{ "orangered", NSVG_RGB(255, 69, 0) },
{ "orchid", NSVG_RGB(218, 112, 214) },
{ "palegoldenrod", NSVG_RGB(238, 232, 170) },
{ "palegreen", NSVG_RGB(152, 251, 152) },
{ "paleturquoise", NSVG_RGB(175, 238, 238) },
{ "palevioletred", NSVG_RGB(219, 112, 147) },
{ "papayawhip", NSVG_RGB(255, 239, 213) },
{ "peachpuff", NSVG_RGB(255, 218, 185) },
{ "peru", NSVG_RGB(205, 133, 63) },
{ "pink", NSVG_RGB(255, 192, 203) },
{ "plum", NSVG_RGB(221, 160, 221) },
{ "powderblue", NSVG_RGB(176, 224, 230) },
{ "purple", NSVG_RGB(128, 0, 128) },
{ "rosybrown", NSVG_RGB(188, 143, 143) },
{ "royalblue", NSVG_RGB( 65, 105, 225) },
{ "saddlebrown", NSVG_RGB(139, 69, 19) },
{ "salmon", NSVG_RGB(250, 128, 114) },
{ "sandybrown", NSVG_RGB(244, 164, 96) },
{ "seagreen", NSVG_RGB( 46, 139, 87) },
{ "seashell", NSVG_RGB(255, 245, 238) },
{ "sienna", NSVG_RGB(160, 82, 45) },
{ "silver", NSVG_RGB(192, 192, 192) },
{ "skyblue", NSVG_RGB(135, 206, 235) },
{ "slateblue", NSVG_RGB(106, 90, 205) },
{ "slategray", NSVG_RGB(112, 128, 144) },
{ "slategrey", NSVG_RGB(112, 128, 144) },
{ "snow", NSVG_RGB(255, 250, 250) },
{ "springgreen", NSVG_RGB( 0, 255, 127) },
{ "steelblue", NSVG_RGB( 70, 130, 180) },
{ "tan", NSVG_RGB(210, 180, 140) },
{ "teal", NSVG_RGB( 0, 128, 128) },
{ "thistle", NSVG_RGB(216, 191, 216) },
{ "tomato", NSVG_RGB(255, 99, 71) },
{ "turquoise", NSVG_RGB( 64, 224, 208) },
{ "violet", NSVG_RGB(238, 130, 238) },
{ "wheat", NSVG_RGB(245, 222, 179) },
{ "whitesmoke", NSVG_RGB(245, 245, 245) },
{ "yellowgreen", NSVG_RGB(154, 205, 50) },
#endif
};
static unsigned int nsvg__parseColorName(const char* str)
{
int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor);
for (i = 0; i < ncolors; i++) {
if (strcmp(nsvg__colors[i].name, str) == 0) {
return nsvg__colors[i].color;
}
}
return NSVG_RGB(128, 128, 128);
}
static unsigned int nsvg__parseColor(const char* str)
{
size_t len = 0;
while(*str == ' ') ++str;
len = strlen(str);
if (len >= 1 && *str == '#')
return nsvg__parseColorHex(str);
else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(')
return nsvg__parseColorRGB(str);
return nsvg__parseColorName(str);
}
static float nsvg__parseOpacity(const char* str)
{
float val = nsvg__atof(str);
if (val < 0.0f) val = 0.0f;
if (val > 1.0f) val = 1.0f;
return val;
}
static float nsvg__parseMiterLimit(const char* str)
{
float val = nsvg__atof(str);
if (val < 0.0f) val = 0.0f;
return val;
}
static int nsvg__parseUnits(const char* units)
{
if (units[0] == 'p' && units[1] == 'x')
return NSVG_UNITS_PX;
else if (units[0] == 'p' && units[1] == 't')
return NSVG_UNITS_PT;
else if (units[0] == 'p' && units[1] == 'c')
return NSVG_UNITS_PC;
else if (units[0] == 'm' && units[1] == 'm')
return NSVG_UNITS_MM;
else if (units[0] == 'c' && units[1] == 'm')
return NSVG_UNITS_CM;
else if (units[0] == 'i' && units[1] == 'n')
return NSVG_UNITS_IN;
else if (units[0] == '%')
return NSVG_UNITS_PERCENT;
else if (units[0] == 'e' && units[1] == 'm')
return NSVG_UNITS_EM;
else if (units[0] == 'e' && units[1] == 'x')
return NSVG_UNITS_EX;
return NSVG_UNITS_USER;
}
static int nsvg__isCoordinate(const char* s)
{
// optional sign
if (*s == '-' || *s == '+')
s++;
// must have at least one digit, or start by a dot
return (nsvg__isdigit(*s) || *s == '.');
}
static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
{
NSVGcoordinate coord = {0, NSVG_UNITS_USER};
char buf[64];
coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64));
coord.value = nsvg__atof(buf);
return coord;
}
static NSVGcoordinate nsvg__coord(float v, int units)
{
NSVGcoordinate coord = {v, units};
return coord;
}
static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length)
{
NSVGcoordinate coord = nsvg__parseCoordinateRaw(str);
return nsvg__convertToPixels(p, coord, orig, length);
}
static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na)
{
const char* end;
const char* ptr;
char it[64];
*na = 0;
ptr = str;
while (*ptr && *ptr != '(') ++ptr;
if (*ptr == 0)
return 1;
end = ptr;
while (*end && *end != ')') ++end;
if (*end == 0)
return 1;
while (ptr < end) {
if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) {
if (*na >= maxNa) return 0;
ptr = nsvg__parseNumber(ptr, it, 64);
args[(*na)++] = (float)nsvg__atof(it);
} else {
++ptr;
}
}
return (int)(end - str);
}
static int nsvg__parseMatrix(float* xform, const char* str)
{
float t[6];
int na = 0;
int len = nsvg__parseTransformArgs(str, t, 6, &na);
if (na != 6) return len;
memcpy(xform, t, sizeof(float)*6);
return len;
}
static int nsvg__parseTranslate(float* xform, const char* str)
{
float args[2];
float t[6];
int na = 0;
int len = nsvg__parseTransformArgs(str, args, 2, &na);
if (na == 1) args[1] = 0.0;
nsvg__xformSetTranslation(t, args[0], args[1]);
memcpy(xform, t, sizeof(float)*6);
return len;
}
static int nsvg__parseScale(float* xform, const char* str)
{
float args[2];
int na = 0;
float t[6];
int len = nsvg__parseTransformArgs(str, args, 2, &na);
if (na == 1) args[1] = args[0];
nsvg__xformSetScale(t, args[0], args[1]);
memcpy(xform, t, sizeof(float)*6);
return len;
}
static int nsvg__parseSkewX(float* xform, const char* str)
{
float args[1];
int na = 0;
float t[6];
int len = nsvg__parseTransformArgs(str, args, 1, &na);
nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI);
memcpy(xform, t, sizeof(float)*6);
return len;
}
static int nsvg__parseSkewY(float* xform, const char* str)
{
float args[1];
int na = 0;
float t[6];
int len = nsvg__parseTransformArgs(str, args, 1, &na);
nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI);
memcpy(xform, t, sizeof(float)*6);
return len;
}
static int nsvg__parseRotate(float* xform, const char* str)
{
float args[3];
int na = 0;
float m[6];
float t[6];
int len = nsvg__parseTransformArgs(str, args, 3, &na);
if (na == 1)
args[1] = args[2] = 0.0f;
nsvg__xformIdentity(m);
if (na > 1) {
nsvg__xformSetTranslation(t, -args[1], -args[2]);
nsvg__xformMultiply(m, t);
}
nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI);
nsvg__xformMultiply(m, t);
if (na > 1) {
nsvg__xformSetTranslation(t, args[1], args[2]);
nsvg__xformMultiply(m, t);
}
memcpy(xform, m, sizeof(float)*6);
return len;
}
static void nsvg__parseTransform(float* xform, const char* str)
{
float t[6];
int len;
nsvg__xformIdentity(xform);
while (*str)
{
if (strncmp(str, "matrix", 6) == 0)
len = nsvg__parseMatrix(t, str);
else if (strncmp(str, "translate", 9) == 0)
len = nsvg__parseTranslate(t, str);
else if (strncmp(str, "scale", 5) == 0)
len = nsvg__parseScale(t, str);
else if (strncmp(str, "rotate", 6) == 0)
len = nsvg__parseRotate(t, str);
else if (strncmp(str, "skewX", 5) == 0)
len = nsvg__parseSkewX(t, str);
else if (strncmp(str, "skewY", 5) == 0)
len = nsvg__parseSkewY(t, str);
else{
++str;
continue;
}
if (len != 0) {
str += len;
} else {
++str;
continue;
}
nsvg__xformPremultiply(xform, t);
}
}
static void nsvg__parseUrl(char* id, const char* str)
{
int i = 0;
str += 4; // "url(";
if (*str && *str == '#')
str++;
while (i < 63 && *str && *str != ')') {
id[i] = *str++;
i++;
}
id[i] = '\0';
}
static char nsvg__parseLineCap(const char* str)
{
if (strcmp(str, "butt") == 0)
return NSVG_CAP_BUTT;
else if (strcmp(str, "round") == 0)
return NSVG_CAP_ROUND;
else if (strcmp(str, "square") == 0)
return NSVG_CAP_SQUARE;
// TODO: handle inherit.
return NSVG_CAP_BUTT;
}
static char nsvg__parseLineJoin(const char* str)
{
if (strcmp(str, "miter") == 0)
return NSVG_JOIN_MITER;
else if (strcmp(str, "round") == 0)
return NSVG_JOIN_ROUND;
else if (strcmp(str, "bevel") == 0)
return NSVG_JOIN_BEVEL;
// TODO: handle inherit.
return NSVG_JOIN_MITER;
}
static char nsvg__parseFillRule(const char* str)
{
if (strcmp(str, "nonzero") == 0)
return NSVG_FILLRULE_NONZERO;
else if (strcmp(str, "evenodd") == 0)
return NSVG_FILLRULE_EVENODD;
// TODO: handle inherit.
return NSVG_FILLRULE_NONZERO;
}
static unsigned char nsvg__parsePaintOrder(const char* str)
{
if (strcmp(str, "normal") == 0 || strcmp(str, "fill stroke markers") == 0)
return nsvg__encodePaintOrder(NSVG_PAINT_FILL, NSVG_PAINT_STROKE, NSVG_PAINT_MARKERS);
else if (strcmp(str, "fill markers stroke") == 0)
return nsvg__encodePaintOrder(NSVG_PAINT_FILL, NSVG_PAINT_MARKERS, NSVG_PAINT_STROKE);
else if (strcmp(str, "markers fill stroke") == 0)
return nsvg__encodePaintOrder(NSVG_PAINT_MARKERS, NSVG_PAINT_FILL, NSVG_PAINT_STROKE);
else if (strcmp(str, "markers stroke fill") == 0)
return nsvg__encodePaintOrder(NSVG_PAINT_MARKERS, NSVG_PAINT_STROKE, NSVG_PAINT_FILL);
else if (strcmp(str, "stroke fill markers") == 0)
return nsvg__encodePaintOrder(NSVG_PAINT_STROKE, NSVG_PAINT_FILL, NSVG_PAINT_MARKERS);
else if (strcmp(str, "stroke markers fill") == 0)
return nsvg__encodePaintOrder(NSVG_PAINT_STROKE, NSVG_PAINT_MARKERS, NSVG_PAINT_FILL);
// TODO: handle inherit.
return nsvg__encodePaintOrder(NSVG_PAINT_FILL, NSVG_PAINT_STROKE, NSVG_PAINT_MARKERS);
}
static const char* nsvg__getNextDashItem(const char* s, char* it)
{
int n = 0;
it[0] = '\0';
// Skip white spaces and commas
while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
// Advance until whitespace, comma or end.
while (*s && (!nsvg__isspace(*s) && *s != ',')) {
if (n < 63)
it[n++] = *s;
s++;
}
it[n++] = '\0';
return s;
}
static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray)
{
char item[64];
int count = 0, i;
float sum = 0.0f;
// Handle "none"
if (str[0] == 'n')
return 0;
// Parse dashes
while (*str) {
str = nsvg__getNextDashItem(str, item);
if (!*item) break;
if (count < NSVG_MAX_DASHES)
strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p)));
}
for (i = 0; i < count; i++)
sum += strokeDashArray[i];
if (sum <= 1e-6f)
count = 0;
return count;
}
static void nsvg__parseStyle(NSVGparser* p, const char* str);
static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
{
float xform[6];
NSVGattrib* attr = nsvg__getAttr(p);
if (!attr) return 0;
if (strcmp(name, "style") == 0) {
nsvg__parseStyle(p, value);
} else if (strcmp(name, "display") == 0) {
if (strcmp(value, "none") == 0)
attr->visible = 0;
// Don't reset ->visible on display:inline, one display:none hides the whole subtree
} else if (strcmp(name, "fill") == 0) {
if (strcmp(value, "none") == 0) {
attr->hasFill = 0;
} else if (strncmp(value, "url(", 4) == 0) {
attr->hasFill = 2;
nsvg__parseUrl(attr->fillGradient, value);
} else {
attr->hasFill = 1;
attr->fillColor = nsvg__parseColor(value);
}
} else if (strcmp(name, "opacity") == 0) {
attr->opacity = nsvg__parseOpacity(value);
} else if (strcmp(name, "fill-opacity") == 0) {
attr->fillOpacity = nsvg__parseOpacity(value);
} else if (strcmp(name, "stroke") == 0) {
if (strcmp(value, "none") == 0) {
attr->hasStroke = 0;
} else if (strncmp(value, "url(", 4) == 0) {
attr->hasStroke = 2;
nsvg__parseUrl(attr->strokeGradient, value);
} else {
attr->hasStroke = 1;
attr->strokeColor = nsvg__parseColor(value);
}
} else if (strcmp(name, "stroke-width") == 0) {
attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
} else if (strcmp(name, "stroke-dasharray") == 0) {
attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray);
} else if (strcmp(name, "stroke-dashoffset") == 0) {
attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
} else if (strcmp(name, "stroke-opacity") == 0) {
attr->strokeOpacity = nsvg__parseOpacity(value);
} else if (strcmp(name, "stroke-linecap") == 0) {
attr->strokeLineCap = nsvg__parseLineCap(value);
} else if (strcmp(name, "stroke-linejoin") == 0) {
attr->strokeLineJoin = nsvg__parseLineJoin(value);
} else if (strcmp(name, "stroke-miterlimit") == 0) {
attr->miterLimit = nsvg__parseMiterLimit(value);
} else if (strcmp(name, "fill-rule") == 0) {
attr->fillRule = nsvg__parseFillRule(value);
} else if (strcmp(name, "font-size") == 0) {
attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
} else if (strcmp(name, "transform") == 0) {
nsvg__parseTransform(xform, value);
nsvg__xformPremultiply(attr->xform, xform);
} else if (strcmp(name, "stop-color") == 0) {
attr->stopColor = nsvg__parseColor(value);
} else if (strcmp(name, "stop-opacity") == 0) {
attr->stopOpacity = nsvg__parseOpacity(value);
} else if (strcmp(name, "offset") == 0) {
attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f);
} else if (strcmp(name, "paint-order") == 0) {
attr->paintOrder = nsvg__parsePaintOrder(value);
} else if (strcmp(name, "id") == 0) {
strncpy(attr->id, value, 63);
attr->id[63] = '\0';
} else {
return 0;
}
return 1;
}
static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end)
{
const char* str;
const char* val;
char name[512];
char value[512];
int n;
str = start;
while (str < end && *str != ':') ++str;
val = str;
// Right Trim
while (str > start && (*str == ':' || nsvg__isspace(*str))) --str;
++str;
n = (int)(str - start);
if (n > 511) n = 511;
if (n) memcpy(name, start, n);
name[n] = 0;
while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val;
n = (int)(end - val);
if (n > 511) n = 511;
if (n) memcpy(value, val, n);
value[n] = 0;
return nsvg__parseAttr(p, name, value);
}
static void nsvg__parseStyle(NSVGparser* p, const char* str)
{
const char* start;
const char* end;
while (*str) {
// Left Trim
while(*str && nsvg__isspace(*str)) ++str;
start = str;
while(*str && *str != ';') ++str;
end = str;
// Right Trim
while (end > start && (*end == ';' || nsvg__isspace(*end))) --end;
++end;
nsvg__parseNameValue(p, start, end);
if (*str) ++str;
}
}
static void nsvg__parseAttribs(NSVGparser* p, const char** attr)
{
int i;
for (i = 0; attr[i]; i += 2)
{
if (strcmp(attr[i], "style") == 0)
nsvg__parseStyle(p, attr[i + 1]);
else
nsvg__parseAttr(p, attr[i], attr[i + 1]);
}
}
static int nsvg__getArgsPerElement(char cmd)
{
switch (cmd) {
case 'v':
case 'V':
case 'h':
case 'H':
return 1;
case 'm':
case 'M':
case 'l':
case 'L':
case 't':
case 'T':
return 2;
case 'q':
case 'Q':
case 's':
case 'S':
return 4;
case 'c':
case 'C':
return 6;
case 'a':
case 'A':
return 7;
case 'z':
case 'Z':
return 0;
}
return -1;
}
static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
{
if (rel) {
*cpx += args[0];
*cpy += args[1];
} else {
*cpx = args[0];
*cpy = args[1];
}
nsvg__moveTo(p, *cpx, *cpy);
}
static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
{
if (rel) {
*cpx += args[0];
*cpy += args[1];
} else {
*cpx = args[0];
*cpy = args[1];
}
nsvg__lineTo(p, *cpx, *cpy);
}
static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
{
if (rel)
*cpx += args[0];
else
*cpx = args[0];
nsvg__lineTo(p, *cpx, *cpy);
}
static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
{
if (rel)
*cpy += args[0];
else
*cpy = args[0];
nsvg__lineTo(p, *cpx, *cpy);
}
static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy,
float* cpx2, float* cpy2, float* args, int rel)
{
float x2, y2, cx1, cy1, cx2, cy2;
if (rel) {
cx1 = *cpx + args[0];
cy1 = *cpy + args[1];
cx2 = *cpx + args[2];
cy2 = *cpy + args[3];
x2 = *cpx + args[4];
y2 = *cpy + args[5];
} else {
cx1 = args[0];
cy1 = args[1];
cx2 = args[2];
cy2 = args[3];
x2 = args[4];
y2 = args[5];
}
nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
*cpx2 = cx2;
*cpy2 = cy2;
*cpx = x2;
*cpy = y2;
}
static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy,
float* cpx2, float* cpy2, float* args, int rel)
{
float x1, y1, x2, y2, cx1, cy1, cx2, cy2;
x1 = *cpx;
y1 = *cpy;
if (rel) {
cx2 = *cpx + args[0];
cy2 = *cpy + args[1];
x2 = *cpx + args[2];
y2 = *cpy + args[3];
} else {
cx2 = args[0];
cy2 = args[1];
x2 = args[2];
y2 = args[3];
}
cx1 = 2*x1 - *cpx2;
cy1 = 2*y1 - *cpy2;
nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
*cpx2 = cx2;
*cpy2 = cy2;
*cpx = x2;
*cpy = y2;
}
static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy,
float* cpx2, float* cpy2, float* args, int rel)
{
float x1, y1, x2, y2, cx, cy;
float cx1, cy1, cx2, cy2;
x1 = *cpx;
y1 = *cpy;
if (rel) {
cx = *cpx + args[0];
cy = *cpy + args[1];
x2 = *cpx + args[2];
y2 = *cpy + args[3];
} else {
cx = args[0];
cy = args[1];
x2 = args[2];
y2 = args[3];
}
// Convert to cubic bezier
cx1 = x1 + 2.0f/3.0f*(cx - x1);
cy1 = y1 + 2.0f/3.0f*(cy - y1);
cx2 = x2 + 2.0f/3.0f*(cx - x2);
cy2 = y2 + 2.0f/3.0f*(cy - y2);
nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
*cpx2 = cx;
*cpy2 = cy;
*cpx = x2;
*cpy = y2;
}
static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy,
float* cpx2, float* cpy2, float* args, int rel)
{
float x1, y1, x2, y2, cx, cy;
float cx1, cy1, cx2, cy2;
x1 = *cpx;
y1 = *cpy;
if (rel) {
x2 = *cpx + args[0];
y2 = *cpy + args[1];
} else {
x2 = args[0];
y2 = args[1];
}
cx = 2*x1 - *cpx2;
cy = 2*y1 - *cpy2;
// Convert to cubix bezier
cx1 = x1 + 2.0f/3.0f*(cx - x1);
cy1 = y1 + 2.0f/3.0f*(cy - y1);
cx2 = x2 + 2.0f/3.0f*(cx - x2);
cy2 = y2 + 2.0f/3.0f*(cy - y2);
nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
*cpx2 = cx;
*cpy2 = cy;
*cpx = x2;
*cpy = y2;
}
static float nsvg__sqr(float x) { return x*x; }
static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); }
static float nsvg__vecrat(float ux, float uy, float vx, float vy)
{
return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy));
}
static float nsvg__vecang(float ux, float uy, float vx, float vy)
{
float r = nsvg__vecrat(ux,uy, vx,vy);
if (r < -1.0f) r = -1.0f;
if (r > 1.0f) r = 1.0f;
return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r);
}
static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
{
// Ported from canvg (https://code.google.com/p/canvg/)
float rx, ry, rotx;
float x1, y1, x2, y2, cx, cy, dx, dy, d;
float x1p, y1p, cxp, cyp, s, sa, sb;
float ux, uy, vx, vy, a1, da;
float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6];
float sinrx, cosrx;
int fa, fs;
int i, ndivs;
float hda, kappa;
rx = fabsf(args[0]); // y radius
ry = fabsf(args[1]); // x radius
rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle
fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc
fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction
x1 = *cpx; // start point
y1 = *cpy;
if (rel) { // end point
x2 = *cpx + args[5];
y2 = *cpy + args[6];
} else {
x2 = args[5];
y2 = args[6];
}
dx = x1 - x2;
dy = y1 - y2;
d = sqrtf(dx*dx + dy*dy);
if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) {
// The arc degenerates to a line
nsvg__lineTo(p, x2, y2);
*cpx = x2;
*cpy = y2;
return;
}
sinrx = sinf(rotx);
cosrx = cosf(rotx);
// Convert to center point parameterization.
// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
// 1) Compute x1', y1'
x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f;
y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f;
d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry);
if (d > 1) {
d = sqrtf(d);
rx *= d;
ry *= d;
}
// 2) Compute cx', cy'
s = 0.0f;
sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p);
sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p);
if (sa < 0.0f) sa = 0.0f;
if (sb > 0.0f)
s = sqrtf(sa / sb);
if (fa == fs)
s = -s;
cxp = s * rx * y1p / ry;
cyp = s * -ry * x1p / rx;
// 3) Compute cx,cy from cx',cy'
cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp;
cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp;
// 4) Calculate theta1, and delta theta.
ux = (x1p - cxp) / rx;
uy = (y1p - cyp) / ry;
vx = (-x1p - cxp) / rx;
vy = (-y1p - cyp) / ry;
a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle
da = nsvg__vecang(ux,uy, vx,vy); // Delta angle
// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;
// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
if (fs == 0 && da > 0)
da -= 2 * NSVG_PI;
else if (fs == 1 && da < 0)
da += 2 * NSVG_PI;
// Approximate the arc using cubic spline segments.
t[0] = cosrx; t[1] = sinrx;
t[2] = -sinrx; t[3] = cosrx;
t[4] = cx; t[5] = cy;
// Split arc into max 90 degree segments.
// The loop assumes an iteration per end point (including start and end), this +1.
ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f);
hda = (da / (float)ndivs) / 2.0f;
// Fix for ticket #179: division by 0: avoid cotangens around 0 (infinite)
if ((hda < 1e-3f) && (hda > -1e-3f))
hda *= 0.5f;
else
hda = (1.0f - cosf(hda)) / sinf(hda);
kappa = fabsf(4.0f / 3.0f * hda);
if (da < 0.0f)
kappa = -kappa;
for (i = 0; i <= ndivs; i++) {
a = a1 + da * ((float)i/(float)ndivs);
dx = cosf(a);
dy = sinf(a);
nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position
nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent
if (i > 0)
nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y);
px = x;
py = y;
ptanx = tanx;
ptany = tany;
}
*cpx = x2;
*cpy = y2;
}
static void nsvg__parsePath(NSVGparser* p, const char** attr)
{
const char* s = NULL;
char cmd = '\0';
float args[10];
int nargs;
int rargs = 0;
char initPoint;
float cpx, cpy, cpx2, cpy2;
const char* tmp[4];
char closedFlag;
int i;
char item[64];
for (i = 0; attr[i]; i += 2) {
if (strcmp(attr[i], "d") == 0) {
s = attr[i + 1];
} else {
tmp[0] = attr[i];
tmp[1] = attr[i + 1];
tmp[2] = 0;
tmp[3] = 0;
nsvg__parseAttribs(p, tmp);
}
}
if (s) {
nsvg__resetPath(p);
cpx = 0; cpy = 0;
cpx2 = 0; cpy2 = 0;
initPoint = 0;
closedFlag = 0;
nargs = 0;
while (*s) {
item[0] = '\0';
if ((cmd == 'A' || cmd == 'a') && (nargs == 3 || nargs == 4))
s = nsvg__getNextPathItemWhenArcFlag(s, item);
if (!*item)
s = nsvg__getNextPathItem(s, item);
if (!*item) break;
if (cmd != '\0' && nsvg__isCoordinate(item)) {
if (nargs < 10)
args[nargs++] = (float)nsvg__atof(item);
if (nargs >= rargs) {
switch (cmd) {
case 'm':
case 'M':
nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0);
// Moveto can be followed by multiple coordinate pairs,
// which should be treated as linetos.
cmd = (cmd == 'm') ? 'l' : 'L';
rargs = nsvg__getArgsPerElement(cmd);
cpx2 = cpx; cpy2 = cpy;
initPoint = 1;
break;
case 'l':
case 'L':
nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0);
cpx2 = cpx; cpy2 = cpy;
break;
case 'H':
case 'h':
nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);
cpx2 = cpx; cpy2 = cpy;
break;
case 'V':
case 'v':
nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);
cpx2 = cpx; cpy2 = cpy;
break;
case 'C':
case 'c':
nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0);
break;
case 'S':
case 's':
nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0);
break;
case 'Q':
case 'q':
nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0);
break;
case 'T':
case 't':
nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0);
break;
case 'A':
case 'a':
nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0);
cpx2 = cpx; cpy2 = cpy;
break;
default:
if (nargs >= 2) {
cpx = args[nargs-2];
cpy = args[nargs-1];
cpx2 = cpx; cpy2 = cpy;
}
break;
}
nargs = 0;
}
} else {
cmd = item[0];
if (cmd == 'M' || cmd == 'm') {
// Commit path.
if (p->npts > 0)
nsvg__addPath(p, closedFlag);
// Start new subpath.
nsvg__resetPath(p);
closedFlag = 0;
nargs = 0;
} else if (initPoint == 0) {
// Do not allow other commands until initial point has been set (moveTo called once).
cmd = '\0';
}
if (cmd == 'Z' || cmd == 'z') {
closedFlag = 1;
// Commit path.
if (p->npts > 0) {
// Move current point to first point
cpx = p->pts[0];
cpy = p->pts[1];
cpx2 = cpx; cpy2 = cpy;
nsvg__addPath(p, closedFlag);
}
// Start new subpath.
nsvg__resetPath(p);
nsvg__moveTo(p, cpx, cpy);
closedFlag = 0;
nargs = 0;
}
rargs = nsvg__getArgsPerElement(cmd);
if (rargs == -1) {
// Command not recognized
cmd = '\0';
rargs = 0;
}
}
}
// Commit path.
if (p->npts)
nsvg__addPath(p, closedFlag);
}
nsvg__addShape(p);
}
static void nsvg__parseRect(NSVGparser* p, const char** attr)
{
float x = 0.0f;
float y = 0.0f;
float w = 0.0f;
float h = 0.0f;
float rx = -1.0f; // marks not set
float ry = -1.0f;
int i;
for (i = 0; attr[i]; i += 2) {
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p));
if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p));
if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
}
}
if (rx < 0.0f && ry > 0.0f) rx = ry;
if (ry < 0.0f && rx > 0.0f) ry = rx;
if (rx < 0.0f) rx = 0.0f;
if (ry < 0.0f) ry = 0.0f;
if (rx > w/2.0f) rx = w/2.0f;
if (ry > h/2.0f) ry = h/2.0f;
if (w != 0.0f && h != 0.0f) {
nsvg__resetPath(p);
if (rx < 0.00001f || ry < 0.0001f) {
nsvg__moveTo(p, x, y);
nsvg__lineTo(p, x+w, y);
nsvg__lineTo(p, x+w, y+h);
nsvg__lineTo(p, x, y+h);
} else {
// Rounded rectangle
nsvg__moveTo(p, x+rx, y);
nsvg__lineTo(p, x+w-rx, y);
nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry);
nsvg__lineTo(p, x+w, y+h-ry);
nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h);
nsvg__lineTo(p, x+rx, y+h);
nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry);
nsvg__lineTo(p, x, y+ry);
nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y);
}
nsvg__addPath(p, 1);
nsvg__addShape(p);
}
}
static void nsvg__parseCircle(NSVGparser* p, const char** attr)
{
float cx = 0.0f;
float cy = 0.0f;
float r = 0.0f;
int i;
for (i = 0; attr[i]; i += 2) {
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p)));
}
}
if (r > 0.0f) {
nsvg__resetPath(p);
nsvg__moveTo(p, cx+r, cy);
nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r);
nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy);
nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r);
nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy);
nsvg__addPath(p, 1);
nsvg__addShape(p);
}
}
static void nsvg__parseEllipse(NSVGparser* p, const char** attr)
{
float cx = 0.0f;
float cy = 0.0f;
float rx = 0.0f;
float ry = 0.0f;
int i;
for (i = 0; attr[i]; i += 2) {
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
}
}
if (rx > 0.0f && ry > 0.0f) {
nsvg__resetPath(p);
nsvg__moveTo(p, cx+rx, cy);
nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry);
nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy);
nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry);
nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy);
nsvg__addPath(p, 1);
nsvg__addShape(p);
}
}
static void nsvg__parseLine(NSVGparser* p, const char** attr)
{
float x1 = 0.0;
float y1 = 0.0;
float x2 = 0.0;
float y2 = 0.0;
int i;
for (i = 0; attr[i]; i += 2) {
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
}
}
nsvg__resetPath(p);
nsvg__moveTo(p, x1, y1);
nsvg__lineTo(p, x2, y2);
nsvg__addPath(p, 0);
nsvg__addShape(p);
}
static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)
{
int i;
const char* s;
float args[2];
int nargs, npts = 0;
char item[64];
nsvg__resetPath(p);
for (i = 0; attr[i]; i += 2) {
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "points") == 0) {
s = attr[i + 1];
nargs = 0;
while (*s) {
s = nsvg__getNextPathItem(s, item);
args[nargs++] = (float)nsvg__atof(item);
if (nargs >= 2) {
if (npts == 0)
nsvg__moveTo(p, args[0], args[1]);
else
nsvg__lineTo(p, args[0], args[1]);
nargs = 0;
npts++;
}
}
}
}
}
nsvg__addPath(p, (char)closeFlag);
nsvg__addShape(p);
}
static void nsvg__parseSVG(NSVGparser* p, const char** attr)
{
int i;
for (i = 0; attr[i]; i += 2) {
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "width") == 0) {
p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
} else if (strcmp(attr[i], "height") == 0) {
p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
} else if (strcmp(attr[i], "viewBox") == 0) {
const char *s = attr[i + 1];
char buf[64];
s = nsvg__parseNumber(s, buf, 64);
p->viewMinx = nsvg__atof(buf);
while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
if (!*s) return;
s = nsvg__parseNumber(s, buf, 64);
p->viewMiny = nsvg__atof(buf);
while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
if (!*s) return;
s = nsvg__parseNumber(s, buf, 64);
p->viewWidth = nsvg__atof(buf);
while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
if (!*s) return;
s = nsvg__parseNumber(s, buf, 64);
p->viewHeight = nsvg__atof(buf);
} else if (strcmp(attr[i], "preserveAspectRatio") == 0) {
if (strstr(attr[i + 1], "none") != 0) {
// No uniform scaling
p->alignType = NSVG_ALIGN_NONE;
} else {
// Parse X align
if (strstr(attr[i + 1], "xMin") != 0)
p->alignX = NSVG_ALIGN_MIN;
else if (strstr(attr[i + 1], "xMid") != 0)
p->alignX = NSVG_ALIGN_MID;
else if (strstr(attr[i + 1], "xMax") != 0)
p->alignX = NSVG_ALIGN_MAX;
// Parse X align
if (strstr(attr[i + 1], "yMin") != 0)
p->alignY = NSVG_ALIGN_MIN;
else if (strstr(attr[i + 1], "yMid") != 0)
p->alignY = NSVG_ALIGN_MID;
else if (strstr(attr[i + 1], "yMax") != 0)
p->alignY = NSVG_ALIGN_MAX;
// Parse meet/slice
p->alignType = NSVG_ALIGN_MEET;
if (strstr(attr[i + 1], "slice") != 0)
p->alignType = NSVG_ALIGN_SLICE;
}
}
}
}
}
static void nsvg__parseGradient(NSVGparser* p, const char** attr, signed char type)
{
int i;
NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData));
if (grad == NULL) return;
memset(grad, 0, sizeof(NSVGgradientData));
grad->units = NSVG_OBJECT_SPACE;
grad->type = type;
if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) {
grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT);
grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
} else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) {
grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
}
nsvg__xformIdentity(grad->xform);
for (i = 0; attr[i]; i += 2) {
if (strcmp(attr[i], "id") == 0) {
strncpy(grad->id, attr[i+1], 63);
grad->id[63] = '\0';
} else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "gradientUnits") == 0) {
if (strcmp(attr[i+1], "objectBoundingBox") == 0)
grad->units = NSVG_OBJECT_SPACE;
else
grad->units = NSVG_USER_SPACE;
} else if (strcmp(attr[i], "gradientTransform") == 0) {
nsvg__parseTransform(grad->xform, attr[i + 1]);
} else if (strcmp(attr[i], "cx") == 0) {
grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]);
} else if (strcmp(attr[i], "cy") == 0) {
grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]);
} else if (strcmp(attr[i], "r") == 0) {
grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]);
} else if (strcmp(attr[i], "fx") == 0) {
grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]);
} else if (strcmp(attr[i], "fy") == 0) {
grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]);
} else if (strcmp(attr[i], "x1") == 0) {
grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]);
} else if (strcmp(attr[i], "y1") == 0) {
grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]);
} else if (strcmp(attr[i], "x2") == 0) {
grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]);
} else if (strcmp(attr[i], "y2") == 0) {
grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]);
} else if (strcmp(attr[i], "spreadMethod") == 0) {
if (strcmp(attr[i+1], "pad") == 0)
grad->spread = NSVG_SPREAD_PAD;
else if (strcmp(attr[i+1], "reflect") == 0)
grad->spread = NSVG_SPREAD_REFLECT;
else if (strcmp(attr[i+1], "repeat") == 0)
grad->spread = NSVG_SPREAD_REPEAT;
} else if (strcmp(attr[i], "xlink:href") == 0) {
const char *href = attr[i+1];
strncpy(grad->ref, href+1, 62);
grad->ref[62] = '\0';
}
}
}
grad->next = p->gradients;
p->gradients = grad;
}
static void nsvg__parseGradientStop(NSVGparser* p, const char** attr)
{
NSVGattrib* curAttr = nsvg__getAttr(p);
NSVGgradientData* grad;
NSVGgradientStop* stop;
int i, idx;
curAttr->stopOffset = 0;
curAttr->stopColor = 0;
curAttr->stopOpacity = 1.0f;
for (i = 0; attr[i]; i += 2) {
nsvg__parseAttr(p, attr[i], attr[i + 1]);
}
// Add stop to the last gradient.
grad = p->gradients;
if (grad == NULL) return;
grad->nstops++;
grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops);
if (grad->stops == NULL) return;
// Insert
idx = grad->nstops-1;
for (i = 0; i < grad->nstops-1; i++) {
if (curAttr->stopOffset < grad->stops[i].offset) {
idx = i;
break;
}
}
if (idx != grad->nstops-1) {
for (i = grad->nstops-1; i > idx; i--)
grad->stops[i] = grad->stops[i-1];
}
stop = &grad->stops[idx];
stop->color = curAttr->stopColor;
stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24;
stop->offset = curAttr->stopOffset;
}
static void nsvg__startElement(void* ud, const char* el, const char** attr)
{
NSVGparser* p = (NSVGparser*)ud;
if (p->defsFlag) {
// Skip everything but gradients in defs
if (strcmp(el, "linearGradient") == 0) {
nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
} else if (strcmp(el, "radialGradient") == 0) {
nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
} else if (strcmp(el, "stop") == 0) {
nsvg__parseGradientStop(p, attr);
}
return;
}
if (strcmp(el, "g") == 0) {
nsvg__pushAttr(p);
nsvg__parseAttribs(p, attr);
} else if (strcmp(el, "path") == 0) {
if (p->pathFlag) // Do not allow nested paths.
return;
nsvg__pushAttr(p);
nsvg__parsePath(p, attr);
nsvg__popAttr(p);
} else if (strcmp(el, "rect") == 0) {
nsvg__pushAttr(p);
nsvg__parseRect(p, attr);
nsvg__popAttr(p);
} else if (strcmp(el, "circle") == 0) {
nsvg__pushAttr(p);
nsvg__parseCircle(p, attr);
nsvg__popAttr(p);
} else if (strcmp(el, "ellipse") == 0) {
nsvg__pushAttr(p);
nsvg__parseEllipse(p, attr);
nsvg__popAttr(p);
} else if (strcmp(el, "line") == 0) {
nsvg__pushAttr(p);
nsvg__parseLine(p, attr);
nsvg__popAttr(p);
} else if (strcmp(el, "polyline") == 0) {
nsvg__pushAttr(p);
nsvg__parsePoly(p, attr, 0);
nsvg__popAttr(p);
} else if (strcmp(el, "polygon") == 0) {
nsvg__pushAttr(p);
nsvg__parsePoly(p, attr, 1);
nsvg__popAttr(p);
} else if (strcmp(el, "linearGradient") == 0) {
nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
} else if (strcmp(el, "radialGradient") == 0) {
nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
} else if (strcmp(el, "stop") == 0) {
nsvg__parseGradientStop(p, attr);
} else if (strcmp(el, "defs") == 0) {
p->defsFlag = 1;
} else if (strcmp(el, "svg") == 0) {
nsvg__parseSVG(p, attr);
}
}
static void nsvg__endElement(void* ud, const char* el)
{
NSVGparser* p = (NSVGparser*)ud;
if (strcmp(el, "g") == 0) {
nsvg__popAttr(p);
} else if (strcmp(el, "path") == 0) {
p->pathFlag = 0;
} else if (strcmp(el, "defs") == 0) {
p->defsFlag = 0;
}
}
static void nsvg__content(void* ud, const char* s)
{
NSVG_NOTUSED(ud);
NSVG_NOTUSED(s);
// empty
}
static void nsvg__imageBounds(NSVGparser* p, float* bounds)
{
NSVGshape* shape;
shape = p->image->shapes;
if (shape == NULL) {
bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;
return;
}
bounds[0] = shape->bounds[0];
bounds[1] = shape->bounds[1];
bounds[2] = shape->bounds[2];
bounds[3] = shape->bounds[3];
for (shape = shape->next; shape != NULL; shape = shape->next) {
bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]);
bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]);
bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]);
bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]);
}
}
static float nsvg__viewAlign(float content, float container, int type)
{
if (type == NSVG_ALIGN_MIN)
return 0;
else if (type == NSVG_ALIGN_MAX)
return container - content;
// mid
return (container - content) * 0.5f;
}
static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy)
{
float t[6];
nsvg__xformSetTranslation(t, tx, ty);
nsvg__xformMultiply (grad->xform, t);
nsvg__xformSetScale(t, sx, sy);
nsvg__xformMultiply (grad->xform, t);
}
static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
{
NSVGshape* shape;
NSVGpath* path;
float tx, ty, sx, sy, us, bounds[4], t[6], avgs;
int i;
float* pt;
// Guess image size if not set completely.
nsvg__imageBounds(p, bounds);
if (p->viewWidth == 0) {
if (p->image->width > 0) {
p->viewWidth = p->image->width;
} else {
p->viewMinx = bounds[0];
p->viewWidth = bounds[2] - bounds[0];
}
}
if (p->viewHeight == 0) {
if (p->image->height > 0) {
p->viewHeight = p->image->height;
} else {
p->viewMiny = bounds[1];
p->viewHeight = bounds[3] - bounds[1];
}
}
if (p->image->width == 0)
p->image->width = p->viewWidth;
if (p->image->height == 0)
p->image->height = p->viewHeight;
tx = -p->viewMinx;
ty = -p->viewMiny;
sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0;
sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0;
// Unit scaling
us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f);
// Fix aspect ratio
if (p->alignType == NSVG_ALIGN_MEET) {
// fit whole image into viewbox
sx = sy = nsvg__minf(sx, sy);
tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;
ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;
} else if (p->alignType == NSVG_ALIGN_SLICE) {
// fill whole viewbox with image
sx = sy = nsvg__maxf(sx, sy);
tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;
ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;
}
// Transform
sx *= us;
sy *= us;
avgs = (sx+sy) / 2.0f;
for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
shape->bounds[0] = (shape->bounds[0] + tx) * sx;
shape->bounds[1] = (shape->bounds[1] + ty) * sy;
shape->bounds[2] = (shape->bounds[2] + tx) * sx;
shape->bounds[3] = (shape->bounds[3] + ty) * sy;
for (path = shape->paths; path != NULL; path = path->next) {
path->bounds[0] = (path->bounds[0] + tx) * sx;
path->bounds[1] = (path->bounds[1] + ty) * sy;
path->bounds[2] = (path->bounds[2] + tx) * sx;
path->bounds[3] = (path->bounds[3] + ty) * sy;
for (i =0; i < path->npts; i++) {
pt = &path->pts[i*2];
pt[0] = (pt[0] + tx) * sx;
pt[1] = (pt[1] + ty) * sy;
}
}
if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) {
nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy);
memcpy(t, shape->fill.gradient->xform, sizeof(float)*6);
nsvg__xformInverse(shape->fill.gradient->xform, t);
}
if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) {
nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy);
memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6);
nsvg__xformInverse(shape->stroke.gradient->xform, t);
}
shape->strokeWidth *= avgs;
shape->strokeDashOffset *= avgs;
for (i = 0; i < shape->strokeDashCount; i++)
shape->strokeDashArray[i] *= avgs;
}
}
static void nsvg__createGradients(NSVGparser* p)
{
NSVGshape* shape;
for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
if (shape->fill.type == NSVG_PAINT_UNDEF) {
if (shape->fillGradient[0] != '\0') {
float inv[6], localBounds[4];
nsvg__xformInverse(inv, shape->xform);
nsvg__getLocalBounds(localBounds, shape, inv);
shape->fill.gradient = nsvg__createGradient(p, shape->fillGradient, localBounds, shape->xform, &shape->fill.type);
}
if (shape->fill.type == NSVG_PAINT_UNDEF) {
shape->fill.type = NSVG_PAINT_NONE;
}
}
if (shape->stroke.type == NSVG_PAINT_UNDEF) {
if (shape->strokeGradient[0] != '\0') {
float inv[6], localBounds[4];
nsvg__xformInverse(inv, shape->xform);
nsvg__getLocalBounds(localBounds, shape, inv);
shape->stroke.gradient = nsvg__createGradient(p, shape->strokeGradient, localBounds, shape->xform, &shape->stroke.type);
}
if (shape->stroke.type == NSVG_PAINT_UNDEF) {
shape->stroke.type = NSVG_PAINT_NONE;
}
}
}
}
NSVGimage* nsvgParse(char* input, const char* units, float dpi)
{
NSVGparser* p;
NSVGimage* ret = 0;
p = nsvg__createParser();
if (p == NULL) {
return NULL;
}
p->dpi = dpi;
nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p);
// Create gradients after all definitions have been parsed
nsvg__createGradients(p);
// Scale to viewBox
nsvg__scaleToViewbox(p, units);
ret = p->image;
p->image = NULL;
nsvg__deleteParser(p);
return ret;
}
NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)
{
FILE* fp = NULL;
size_t size;
char* data = NULL;
NSVGimage* image = NULL;
fp = fopen(filename, "rb");
if (!fp) goto error;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
data = (char*)malloc(size+1);
if (data == NULL) goto error;
if (fread(data, 1, size, fp) != size) goto error;
data[size] = '\0'; // Must be null terminated.
fclose(fp);
image = nsvgParse(data, units, dpi);
free(data);
return image;
error:
if (fp) fclose(fp);
if (data) free(data);
if (image) nsvgDelete(image);
return NULL;
}
NSVGpath* nsvgDuplicatePath(NSVGpath* p)
{
NSVGpath* res = NULL;
if (p == NULL)
return NULL;
res = (NSVGpath*)malloc(sizeof(NSVGpath));
if (res == NULL) goto error;
memset(res, 0, sizeof(NSVGpath));
res->pts = (float*)malloc(p->npts*2*sizeof(float));
if (res->pts == NULL) goto error;
memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2);
res->npts = p->npts;
memcpy(res->bounds, p->bounds, sizeof(p->bounds));
res->closed = p->closed;
return res;
error:
if (res != NULL) {
free(res->pts);
free(res);
}
return NULL;
}
void nsvgDelete(NSVGimage* image)
{
NSVGshape *snext, *shape;
if (image == NULL) return;
shape = image->shapes;
while (shape != NULL) {
snext = shape->next;
nsvg__deletePaths(shape->paths);
nsvg__deletePaint(&shape->fill);
nsvg__deletePaint(&shape->stroke);
free(shape);
shape = snext;
}
free(image);
}
#endif // NANOSVG_IMPLEMENTATION
#endif // NANOSVG_H
================================================
FILE: external/nanosvgrast.h
================================================
/*
* Copyright (c) 2013-14 Mikko Mononen memon@inside.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* The polygon rasterization is heavily based on stb_truetype rasterizer
* by Sean Barrett - http://nothings.org/
*
*/
#ifndef NANOSVGRAST_H
#define NANOSVGRAST_H
#include "nanosvg.h"
#ifndef NANOSVGRAST_CPLUSPLUS
#ifdef __cplusplus
extern "C" {
#endif
#endif
typedef struct NSVGrasterizer NSVGrasterizer;
/* Example Usage:
// Load SVG
NSVGimage* image;
image = nsvgParseFromFile("test.svg", "px", 96);
// Create rasterizer (can be used to render multiple images).
struct NSVGrasterizer* rast = nsvgCreateRasterizer();
// Allocate memory for image
unsigned char* img = malloc(w*h*4);
// Rasterize
nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4);
*/
// Allocated rasterizer context.
NSVGrasterizer* nsvgCreateRasterizer(void);
// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha)
// r - pointer to rasterizer context
// image - pointer to image to rasterize
// tx,ty - image offset (applied after scaling)
// scale - image scale
// dst - pointer to destination image data, 4 bytes per pixel (RGBA)
// w - width of the image to render
// h - height of the image to render
// stride - number of bytes per scaleline in the destination buffer
void nsvgRasterize(NSVGrasterizer* r,
NSVGimage* image, float tx, float ty, float scale,
unsigned char* dst, int w, int h, int stride);
// Deletes rasterizer context.
void nsvgDeleteRasterizer(NSVGrasterizer*);
#ifndef NANOSVGRAST_CPLUSPLUS
#ifdef __cplusplus
}
#endif
#endif
#ifdef NANOSVGRAST_IMPLEMENTATION
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define NSVG__SUBSAMPLES 5
#define NSVG__FIXSHIFT 10
#define NSVG__FIX (1 << NSVG__FIXSHIFT)
#define NSVG__FIXMASK (NSVG__FIX-1)
#define NSVG__MEMPAGE_SIZE 1024
typedef struct NSVGedge {
float x0,y0, x1,y1;
int dir;
struct NSVGedge* next;
} NSVGedge;
typedef struct NSVGpoint {
float x, y;
float dx, dy;
float len;
float dmx, dmy;
unsigned char flags;
} NSVGpoint;
typedef struct NSVGactiveEdge {
int x,dx;
float ey;
int dir;
struct NSVGactiveEdge *next;
} NSVGactiveEdge;
typedef struct NSVGmemPage {
unsigned char mem[NSVG__MEMPAGE_SIZE];
int size;
struct NSVGmemPage* next;
} NSVGmemPage;
typedef struct NSVGcachedPaint {
signed char type;
char spread;
float xform[6];
unsigned int colors[256];
} NSVGcachedPaint;
struct NSVGrasterizer
{
float px, py;
float tessTol;
float distTol;
NSVGedge* edges;
int nedges;
int cedges;
NSVGpoint* points;
int npoints;
int cpoints;
NSVGpoint* points2;
int npoints2;
int cpoints2;
NSVGactiveEdge* freelist;
NSVGmemPage* pages;
NSVGmemPage* curpage;
unsigned char* scanline;
int cscanline;
unsigned char* bitmap;
int width, height, stride;
};
NSVGrasterizer* nsvgCreateRasterizer(void)
{
NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer));
if (r == NULL) goto error;
memset(r, 0, sizeof(NSVGrasterizer));
r->tessTol = 0.25f;
r->distTol = 0.01f;
return r;
error:
nsvgDeleteRasterizer(r);
return NULL;
}
void nsvgDeleteRasterizer(NSVGrasterizer* r)
{
NSVGmemPage* p;
if (r == NULL) return;
p = r->pages;
while (p != NULL) {
NSVGmemPage* next = p->next;
free(p);
p = next;
}
if (r->edges) free(r->edges);
if (r->points) free(r->points);
if (r->points2) free(r->points2);
if (r->scanline) free(r->scanline);
free(r);
}
static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur)
{
NSVGmemPage *newp;
// If using existing chain, return the next page in chain
if (cur != NULL && cur->next != NULL) {
return cur->next;
}
// Alloc new page
newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage));
if (newp == NULL) return NULL;
memset(newp, 0, sizeof(NSVGmemPage));
// Add to linked list
if (cur != NULL)
cur->next = newp;
else
r->pages = newp;
return newp;
}
static void nsvg__resetPool(NSVGrasterizer* r)
{
NSVGmemPage* p = r->pages;
while (p != NULL) {
p->size = 0;
p = p->next;
}
r->curpage = r->pages;
}
static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size)
{
unsigned char* buf;
if (size > NSVG__MEMPAGE_SIZE) return NULL;
if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
r->curpage = nsvg__nextPage(r, r->curpage);
}
buf = &r->curpage->mem[r->curpage->size];
r->curpage->size += size;
return buf;
}
static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol)
{
float dx = x2 - x1;
float dy = y2 - y1;
return dx*dx + dy*dy < tol*tol;
}
static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags)
{
NSVGpoint* pt;
if (r->npoints > 0) {
pt = &r->points[r->npoints-1];
if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
pt->flags = (unsigned char)(pt->flags | flags);
return;
}
}
if (r->npoints+1 > r->cpoints) {
r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
if (r->points == NULL) return;
}
pt = &r->points[r->npoints];
pt->x = x;
pt->y = y;
pt->flags = (unsigned char)flags;
r->npoints++;
}
static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt)
{
if (r->npoints+1 > r->cpoints) {
r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
if (r->points == NULL) return;
}
r->points[r->npoints] = pt;
r->npoints++;
}
static void nsvg__duplicatePoints(NSVGrasterizer* r)
{
if (r->npoints > r->cpoints2) {
r->cpoints2 = r->npoints;
r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2);
if (r->points2 == NULL) return;
}
memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints);
r->npoints2 = r->npoints;
}
static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1)
{
NSVGedge* e;
// Skip horizontal edges
if (y0 == y1)
return;
if (r->nedges+1 > r->cedges) {
r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;
r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges);
if (r->edges == NULL) return;
}
e = &r->edges[r->nedges];
r->nedges++;
if (y0 < y1) {
e->x0 = x0;
e->y0 = y0;
e->x1 = x1;
e->y1 = y1;
e->dir = 1;
} else {
e->x0 = x1;
e->y0 = y1;
e->x1 = x0;
e->y1 = y0;
e->dir = -1;
}
}
static float nsvg__normalize(float *x, float* y)
{
float d = sqrtf((*x)*(*x) + (*y)*(*y));
if (d > 1e-6f) {
float id = 1.0f / d;
*x *= id;
*y *= id;
}
return d;
}
static float nsvg__absf(float x) { return x < 0 ? -x : x; }
static float nsvg__roundf(float x) { return (x >= 0) ? floorf(x + 0.5) : ceilf(x - 0.5); }
static void nsvg__flattenCubicBez(NSVGrasterizer* r,
float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4,
int level, int type)
{
float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
float dx,dy,d2,d3;
if (level > 10) return;
x12 = (x1+x2)*0.5f;
y12 = (y1+y2)*0.5f;
x23 = (x2+x3)*0.5f;
y23 = (y2+y3)*0.5f;
x34 = (x3+x4)*0.5f;
y34 = (y3+y4)*0.5f;
x123 = (x12+x23)*0.5f;
y123 = (y12+y23)*0.5f;
dx = x4 - x1;
dy = y4 - y1;
d2 = nsvg__absf((x2 - x4) * dy - (y2 - y4) * dx);
d3 = nsvg__absf((x3 - x4) * dy - (y3 - y4) * dx);
if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {
nsvg__addPathPoint(r, x4, y4, type);
return;
}
x234 = (x23+x34)*0.5f;
y234 = (y23+y34)*0.5f;
x1234 = (x123+x234)*0.5f;
y1234 = (y123+y234)*0.5f;
nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
}
static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale)
{
int i, j;
NSVGpath* path;
for (path = shape->paths; path != NULL; path = path->next) {
r->npoints = 0;
// Flatten path
nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
for (i = 0; i < path->npts-1; i += 3) {
float* p = &path->pts[i*2];
nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0);
}
// Close path
nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
// Build edges
for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
}
}
enum NSVGpointFlags
{
NSVG_PT_CORNER = 0x01,
NSVG_PT_BEVEL = 0x02,
NSVG_PT_LEFT = 0x04
};
static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
{
float w = lineWidth * 0.5f;
float dx = p1->x - p0->x;
float dy = p1->y - p0->y;
float len = nsvg__normalize(&dx, &dy);
float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f;
float dlx = dy, dly = -dx;
float lx = px - dlx*w, ly = py - dly*w;
float rx = px + dlx*w, ry = py + dly*w;
left->x = lx; left->y = ly;
right->x = rx; right->y = ry;
}
static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
{
float w = lineWidth * 0.5f;
float px = p->x, py = p->y;
float dlx = dy, dly = -dx;
float lx = px - dlx*w, ly = py - dly*w;
float rx = px + dlx*w, ry = py + dly*w;
nsvg__addEdge(r, lx, ly, rx, ry);
if (connect) {
nsvg__addEdge(r, left->x, left->y, lx, ly);
nsvg__addEdge(r, rx, ry, right->x, right->y);
}
left->x = lx; left->y = ly;
right->x = rx; right->y = ry;
}
static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
{
float w = lineWidth * 0.5f;
float px = p->x - dx*w, py = p->y - dy*w;
float dlx = dy, dly = -dx;
float lx = px - dlx*w, ly = py - dly*w;
float rx = px + dlx*w, ry = py + dly*w;
nsvg__addEdge(r, lx, ly, rx, ry);
if (connect) {
nsvg__addEdge(r, left->x, left->y, lx, ly);
nsvg__addEdge(r, rx, ry, right->x, right->y);
}
left->x = lx; left->y = ly;
right->x = rx; right->y = ry;
}
#ifndef NSVG_PI
#define NSVG_PI (3.14159265358979323846264338327f)
#endif
static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect)
{
int i;
float w = lineWidth * 0.5f;
float px = p->x, py = p->y;
float dlx = dy, dly = -dx;
float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
for (i = 0; i < ncap; i++) {
float a = (float)i/(float)(ncap-1)*NSVG_PI;
float ax = cosf(a) * w, ay = sinf(a) * w;
float x = px - dlx*ax - dx*ay;
float y = py - dly*ax - dy*ay;
if (i > 0)
nsvg__addEdge(r, prevx, prevy, x, y);
prevx = x;
prevy = y;
if (i == 0) {
lx = x; ly = y;
} else if (i == ncap-1) {
rx = x; ry = y;
}
}
if (connect) {
nsvg__addEdge(r, left->x, left->y, lx, ly);
nsvg__addEdge(r, rx, ry, right->x, right->y);
}
left->x = lx; left->y = ly;
right->x = rx; right->y = ry;
}
static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
{
float w = lineWidth * 0.5f;
float dlx0 = p0->dy, dly0 = -p0->dx;
float dlx1 = p1->dy, dly1 = -p1->dx;
float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);
float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);
float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);
float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);
nsvg__addEdge(r, lx0, ly0, left->x, left->y);
nsvg__addEdge(r, lx1, ly1, lx0, ly0);
nsvg__addEdge(r, right->x, right->y, rx0, ry0);
nsvg__addEdge(r, rx0, ry0, rx1, ry1);
left->x = lx1; left->y = ly1;
right->x = rx1; right->y = ry1;
}
static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
{
float w = lineWidth * 0.5f;
float dlx0 = p0->dy, dly0 = -p0->dx;
float dlx1 = p1->dy, dly1 = -p1->dx;
float lx0, rx0, lx1, rx1;
float ly0, ry0, ly1, ry1;
if (p1->flags & NSVG_PT_LEFT) {
lx0 = lx1 = p1->x - p1->dmx * w;
ly0 = ly1 = p1->y - p1->dmy * w;
nsvg__addEdge(r, lx1, ly1, left->x, left->y);
rx0 = p1->x + (dlx0 * w);
ry0 = p1->y + (dly0 * w);
rx1 = p1->x + (dlx1 * w);
ry1 = p1->y + (dly1 * w);
nsvg__addEdge(r, right->x, right->y, rx0, ry0);
nsvg__addEdge(r, rx0, ry0, rx1, ry1);
} else {
lx0 = p1->x - (dlx0 * w);
ly0 = p1->y - (dly0 * w);
lx1 = p1->x - (dlx1 * w);
ly1 = p1->y - (dly1 * w);
nsvg__addEdge(r, lx0, ly0, left->x, left->y);
nsvg__addEdge(r, lx1, ly1, lx0, ly0);
rx0 = rx1 = p1->x + p1->dmx * w;
ry0 = ry1 = p1->y + p1->dmy * w;
nsvg__addEdge(r, right->x, right->y, rx1, ry1);
}
left->x = lx1; left->y = ly1;
right->x = rx1; right->y = ry1;
}
static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap)
{
int i, n;
float w = lineWidth * 0.5f;
float dlx0 = p0->dy, dly0 = -p0->dx;
float dlx1 = p1->dy, dly1 = -p1->dx;
float a0 = atan2f(dly0, dlx0);
float a1 = atan2f(dly1, dlx1);
float da = a1 - a0;
float lx, ly, rx, ry;
if (da < NSVG_PI) da += NSVG_PI*2;
if (da > NSVG_PI) da -= NSVG_PI*2;
n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap);
if (n < 2) n = 2;
if (n > ncap) n = ncap;
lx = left->x;
ly = left->y;
rx = right->x;
ry = right->y;
for (i = 0; i < n; i++) {
float u = (float)i/(float)(n-1);
float a = a0 + u*da;
float ax = cosf(a) * w, ay = sinf(a) * w;
float lx1 = p1->x - ax, ly1 = p1->y - ay;
float rx1 = p1->x + ax, ry1 = p1->y + ay;
nsvg__addEdge(r, lx1, ly1, lx, ly);
nsvg__addEdge(r, rx, ry, rx1, ry1);
lx = lx1; ly = ly1;
rx = rx1; ry = ry1;
}
left->x = lx; left->y = ly;
right->x = rx; right->y = ry;
}
static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth)
{
float w = lineWidth * 0.5f;
float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);
float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);
nsvg__addEdge(r, lx, ly, left->x, left->y);
nsvg__addEdge(r, right->x, right->y, rx, ry);
left->x = lx; left->y = ly;
right->x = rx; right->y = ry;
}
static int nsvg__curveDivs(float r, float arc, float tol)
{
float da = acosf(r / (r + tol)) * 2.0f;
int divs = (int)ceilf(arc / da);
if (divs < 2) divs = 2;
return divs;
}
static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth)
{
int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle.
NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0};
NSVGpoint* p0, *p1;
int j, s, e;
// Build stroke edges
if (closed) {
// Looping
p0 = &points[npoints-1];
p1 = &points[0];
s = 0;
e = npoints;
} else {
// Add cap
p0 = &points[0];
p1 = &points[1];
s = 1;
e = npoints-1;
}
if (closed) {
nsvg__initClosed(&left, &right, p0, p1, lineWidth);
firstLeft = left;
firstRight = right;
} else {
// Add cap
float dx = p1->x - p0->x;
float dy = p1->y - p0->y;
nsvg__normalize(&dx, &dy);
if (lineCap == NSVG_CAP_BUTT)
nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
else if (lineCap == NSVG_CAP_SQUARE)
nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
else if (lineCap == NSVG_CAP_ROUND)
nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);
}
for (j = s; j < e; ++j) {
if (p1->flags & NSVG_PT_CORNER) {
if (lineJoin == NSVG_JOIN_ROUND)
nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);
else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL))
nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);
else
nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);
} else {
nsvg__straightJoin(r, &left, &right, p1, lineWidth);
}
p0 = p1++;
}
if (closed) {
// Loop it
nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);
nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);
} else {
// Add cap
float dx = p1->x - p0->x;
float dy = p1->y - p0->y;
nsvg__normalize(&dx, &dy);
if (lineCap == NSVG_CAP_BUTT)
nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
else if (lineCap == NSVG_CAP_SQUARE)
nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
else if (lineCap == NSVG_CAP_ROUND)
nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);
}
}
static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin)
{
int i, j;
NSVGpoint* p0, *p1;
p0 = &r->points[r->npoints-1];
p1 = &r->points[0];
for (i = 0; i < r->npoints; i++) {
// Calculate segment direction and length
p0->dx = p1->x - p0->x;
p0->dy = p1->y - p0->y;
p0->len = nsvg__normalize(&p0->dx, &p0->dy);
// Advance
p0 = p1++;
}
// calculate joins
p0 = &r->points[r->npoints-1];
p1 = &r->points[0];
for (j = 0; j < r->npoints; j++) {
float dlx0, dly0, dlx1, dly1, dmr2, cross;
dlx0 = p0->dy;
dly0 = -p0->dx;
dlx1 = p1->dy;
dly1 = -p1->dx;
// Calculate extrusions
p1->dmx = (dlx0 + dlx1) * 0.5f;
p1->dmy = (dly0 + dly1) * 0.5f;
dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
if (dmr2 > 0.000001f) {
float s2 = 1.0f / dmr2;
if (s2 > 600.0f) {
s2 = 600.0f;
}
p1->dmx *= s2;
p1->dmy *= s2;
}
// Clear flags, but keep the corner.
p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;
// Keep track of left turns.
cross = p1->dx * p0->dy - p0->dx * p1->dy;
if (cross > 0.0f)
p1->flags |= NSVG_PT_LEFT;
// Check to see if the corner needs to be beveled.
if (p1->flags & NSVG_PT_CORNER) {
if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) {
p1->flags |= NSVG_PT_BEVEL;
}
}
p0 = p1++;
}
}
static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale)
{
int i, j, closed;
NSVGpath* path;
NSVGpoint* p0, *p1;
float miterLimit = shape->miterLimit;
int lineJoin = shape->strokeLineJoin;
int lineCap = shape->strokeLineCap;
float lineWidth = shape->strokeWidth * scale;
for (path = shape->paths; path != NULL; path = path->next) {
// Flatten path
r->npoints = 0;
nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER);
for (i = 0; i < path->npts-1; i += 3) {
float* p = &path->pts[i*2];
nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER);
}
if (r->npoints < 2)
continue;
closed = path->closed;
// If the first and last points are the same, remove the last, mark as closed path.
p0 = &r->points[r->npoints-1];
p1 = &r->points[0];
if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
r->npoints--;
p0 = &r->points[r->npoints-1];
closed = 1;
}
if (shape->strokeDashCount > 0) {
int idash = 0, dashState = 1;
float totalDist = 0, dashLen, allDashLen, dashOffset;
NSVGpoint cur;
if (closed)
nsvg__appendPathPoint(r, r->points[0]);
// Duplicate points -> points2.
nsvg__duplicatePoints(r);
r->npoints = 0;
cur = r->points2[0];
nsvg__appendPathPoint(r, cur);
// Figure out dash offset.
allDashLen = 0;
for (j = 0; j < shape->strokeDashCount; j++)
allDashLen += shape->strokeDashArray[j];
if (shape->strokeDashCount & 1)
allDashLen *= 2.0f;
// Find location inside pattern
dashOffset = fmodf(shape->strokeDashOffset, allDashLen);
if (dashOffset < 0.0f)
dashOffset += allDashLen;
while (dashOffset > shape->strokeDashArray[idash]) {
dashOffset -= shape->strokeDashArray[idash];
idash = (idash + 1) % shape->strokeDashCount;
}
dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale;
for (j = 1; j < r->npoints2; ) {
float dx = r->points2[j].x - cur.x;
float dy = r->points2[j].y - cur.y;
float dist = sqrtf(dx*dx + dy*dy);
if ((totalDist + dist) > dashLen) {
// Calculate intermediate point
float d = (dashLen - totalDist) / dist;
float x = cur.x + dx * d;
float y = cur.y + dy * d;
nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER);
// Stroke
if (r->npoints > 1 && dashState) {
nsvg__prepareStroke(r, miterLimit, lineJoin);
nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
}
// Advance dash pattern
dashState = !dashState;
idash = (idash+1) % shape->strokeDashCount;
dashLen = shape->strokeDashArray[idash] * scale;
// Restart
cur.x = x;
cur.y = y;
cur.flags = NSVG_PT_CORNER;
totalDist = 0.0f;
r->npoints = 0;
nsvg__appendPathPoint(r, cur);
} else {
totalDist += dist;
cur = r->points2[j];
nsvg__appendPathPoint(r, cur);
j++;
}
}
// Stroke any leftover path
if (r->npoints > 1 && dashState) {
nsvg__prepareStroke(r, miterLimit, lineJoin);
nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
}
} else {
nsvg__prepareStroke(r, miterLimit, lineJoin);
nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth);
}
}
}
static int nsvg__cmpEdge(const void *p, const void *q)
{
const NSVGedge* a = (const NSVGedge*)p;
const NSVGedge* b = (const NSVGedge*)q;
if (a->y0 < b->y0) return -1;
if (a->y0 > b->y0) return 1;
return 0;
}
static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint)
{
NSVGactiveEdge* z;
if (r->freelist != NULL) {
// Restore from freelist.
z = r->freelist;
r->freelist = z->next;
} else {
// Alloc new edge.
z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge));
if (z == NULL) return NULL;
}
float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
// STBTT_assert(e->y0 <= start_point);
// round dx down to avoid going too far
if (dxdy < 0)
z->dx = (int)(-nsvg__roundf(NSVG__FIX * -dxdy));
else
z->dx = (int)nsvg__roundf(NSVG__FIX * dxdy);
z->x = (int)nsvg__roundf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
// z->x -= off_x * FIX;
z->ey = e->y1;
z->next = 0;
z->dir = e->dir;
return z;
}
static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z)
{
z->next = r->freelist;
r->freelist = z;
}
static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax)
{
int i = x0 >> NSVG__FIXSHIFT;
int j = x1 >> NSVG__FIXSHIFT;
if (i < *xmin) *xmin = i;
if (j > *xmax) *xmax = j;
if (i < len && j >= 0) {
if (i == j) {
// x0,x1 are the same pixel, so compute combined coverage
scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));
} else {
if (i >= 0) // add antialiasing for x0
scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));
else
i = -1; // clip
if (j < len) // add antialiasing for x1
scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));
else
j = len; // clip
for (++i; i < j; ++i) // fill pixels between x0 and x1
scanline[i] = (unsigned char)(scanline[i] + maxWeight);
}
}
}
// note: this routine clips fills that extend off the edges... ideally this
// wouldn't happen, but it could happen if the truetype glyph bounding boxes
// are wrong, or if the user supplies a too-small bitmap
static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule)
{
// non-zero winding fill
int x0 = 0, w = 0;
if (fillRule == NSVG_FILLRULE_NONZERO) {
// Non-zero
while (e != NULL) {
if (w == 0) {
// if we're currently at zero, we need to record the edge start point
x0 = e->x; w += e->dir;
} else {
int x1 = e->x; w += e->dir;
// if we went to zero, we need to draw
if (w == 0)
nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
}
e = e->next;
}
} else if (fillRule == NSVG_FILLRULE_EVENODD) {
// Even-odd
while (e != NULL) {
if (w == 0) {
// if we're currently at zero, we need to record the edge start point
x0 = e->x; w = 1;
} else {
int x1 = e->x; w = 0;
nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
}
e = e->next;
}
}
}
static float nsvg__clampf(float a, float mn, float mx) {
if (isnan(a))
return mn;
return a < mn ? mn : (a > mx ? mx : a);
}
static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
return ((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16) | ((unsigned int)a << 24);
}
static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u)
{
int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
}
static unsigned int nsvg__applyOpacity(unsigned int c, float u)
{
int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
int r = (c) & 0xff;
int g = (c>>8) & 0xff;
int b = (c>>16) & 0xff;
int a = (((c>>24) & 0xff)*iu) >> 8;
return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
}
static inline int nsvg__div255(int x)
{
return ((x+1) * 257) >> 16;
}
static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y,
float tx, float ty, float scale, NSVGcachedPaint* cache)
{
if (cache->type == NSVG_PAINT_COLOR) {
int i, cr, cg, cb, ca;
cr = cache->colors[0] & 0xff;
cg = (cache->colors[0] >> 8) & 0xff;
cb = (cache->colors[0] >> 16) & 0xff;
ca = (cache->colors[0] >> 24) & 0xff;
for (i = 0; i < count; i++) {
int r,g,b;
int a = nsvg__div255((int)cover[0] * ca);
int ia = 255 - a;
// Premultiply
r = nsvg__div255(cr * a);
g = nsvg__div255(cg * a);
b = nsvg__div255(cb * a);
// Blend over
r += nsvg__div255(ia * (int)dst[0]);
g += nsvg__div255(ia * (int)dst[1]);
b += nsvg__div255(ia * (int)dst[2]);
a += nsvg__div255(ia * (int)dst[3]);
dst[0] = (unsigned char)r;
dst[1] = (unsigned char)g;
dst[2] = (unsigned char)b;
dst[3] = (unsigned char)a;
cover++;
dst += 4;
}
} else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) {
// TODO: spread modes.
// TODO: plenty of opportunities to optimize.
float fx, fy, dx, gy;
float* t = cache->xform;
int i, cr, cg, cb, ca;
unsigned int c;
fx = ((float)x - tx) / scale;
fy = ((float)y - ty) / scale;
dx = 1.0f / scale;
for (i = 0; i < count; i++) {
int r,g,b,a,ia;
gy = fx*t[1] + fy*t[3] + t[5];
c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)];
cr = (c) & 0xff;
cg = (c >> 8) & 0xff;
cb = (c >> 16) & 0xff;
ca = (c >> 24) & 0xff;
a = nsvg__div255((int)cover[0] * ca);
ia = 255 - a;
// Premultiply
r = nsvg__div255(cr * a);
g = nsvg__div255(cg * a);
b = nsvg__div255(cb * a);
// Blend over
r += nsvg__div255(ia * (int)dst[0]);
g += nsvg__div255(ia * (int)dst[1]);
b += nsvg__div255(ia * (int)dst[2]);
a += nsvg__div255(ia * (int)dst[3]);
dst[0] = (unsigned char)r;
dst[1] = (unsigned char)g;
dst[2] = (unsigned char)b;
dst[3] = (unsigned char)a;
cover++;
dst += 4;
fx += dx;
}
} else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) {
// TODO: spread modes.
// TODO: plenty of opportunities to optimize.
// TODO: focus (fx,fy)
float fx, fy, dx, gx, gy, gd;
float* t = cache->xform;
int i, cr, cg, cb, ca;
unsigned int c;
fx = ((float)x - tx) / scale;
fy = ((float)y - ty) / scale;
dx = 1.0f / scale;
for (i = 0; i < count; i++) {
int r,g,b,a,ia;
gx = fx*t[0] + fy*t[2] + t[4];
gy = fx*t[1] + fy*t[3] + t[5];
gd = sqrtf(gx*gx + gy*gy);
c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)];
cr = (c) & 0xff;
cg = (c >> 8) & 0xff;
cb = (c >> 16) & 0xff;
ca = (c >> 24) & 0xff;
a = nsvg__div255((int)cover[0] * ca);
ia = 255 - a;
// Premultiply
r = nsvg__div255(cr * a);
g = nsvg__div255(cg * a);
b = nsvg__div255(cb * a);
// Blend over
r += nsvg__div255(ia * (int)dst[0]);
g += nsvg__div255(ia * (int)dst[1]);
b += nsvg__div255(ia * (int)dst[2]);
a += nsvg__div255(ia * (int)dst[3]);
dst[0] = (unsigned char)r;
dst[1] = (unsigned char)g;
dst[2] = (unsigned char)b;
dst[3] = (unsigned char)a;
cover++;
dst += 4;
fx += dx;
}
}
}
static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule)
{
NSVGactiveEdge *active = NULL;
int y, s;
int e = 0;
int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline
int xmin, xmax;
for (y = 0; y < r->height; y++) {
memset(r->scanline, 0, r->width);
xmin = r->width;
xmax = 0;
for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
// find center of pixel for this scanline
float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f;
NSVGactiveEdge **step = &active;
// update all active edges;
// remove all active edges that terminate before the center of this scanline
while (*step) {
NSVGactiveEdge *z = *step;
if (z->ey <= scany) {
*step = z->next; // delete from list
// NSVG__assert(z->valid);
nsvg__freeActive(r, z);
} else {
z->x += z->dx; // advance to position for current scanline
step = &((*step)->next); // advance through list
}
}
// resort the list if needed
for (;;) {
int changed = 0;
step = &active;
while (*step && (*step)->next) {
if ((*step)->x > (*step)->next->x) {
NSVGactiveEdge* t = *step;
NSVGactiveEdge* q = t->next;
t->next = q->next;
q->next = t;
*step = q;
changed = 1;
}
step = &(*step)->next;
}
if (!changed) break;
}
// insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
while (e < r->nedges && r->edges[e].y0 <= scany) {
if (r->edges[e].y1 > scany) {
NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
if (z == NULL) break;
// find insertion point
if (active == NULL) {
active = z;
} else if (z->x < active->x) {
// insert at front
z->next = active;
active = z;
} else {
// find thing to insert AFTER
NSVGactiveEdge* p = active;
while (p->next && p->next->x < z->x)
p = p->next;
// at this point, p->next->x is NOT < z->x
z->next = p->next;
p->next = z;
}
}
e++;
}
// now process all active edges in non-zero fashion
if (active != NULL)
nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule);
}
// Blit
if (xmin < 0) xmin = 0;
if (xmax > r->width-1) xmax = r->width-1;
if (xmin <= xmax) {
nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache);
}
}
}
static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)
{
int x,y;
// Unpremultiply
for (y = 0; y < h; y++) {
unsigned char *row = &image[y*stride];
for (x = 0; x < w; x++) {
int r = row[0], g = row[1], b = row[2], a = row[3];
if (a != 0) {
row[0] = (unsigned char)(r*255/a);
row[1] = (unsigned char)(g*255/a);
row[2] = (unsigned char)(b*255/a);
}
row += 4;
}
}
// Defringe
for (y = 0; y < h; y++) {
unsigned char *row = &image[y*stride];
for (x = 0; x < w; x++) {
int r = 0, g = 0, b = 0, a = row[3], n = 0;
if (a == 0) {
if (x-1 > 0 && row[-1] != 0) {
r += row[-4];
g += row[-3];
b += row[-2];
n++;
}
if (x+1 < w && row[7] != 0) {
r += row[4];
g += row[5];
b += row[6];
n++;
}
if (y-1 > 0 && row[-stride+3] != 0) {
r += row[-stride];
g += row[-stride+1];
b += row[-stride+2];
n++;
}
if (y+1 < h && row[stride+3] != 0) {
r += row[stride];
g += row[stride+1];
b += row[stride+2];
n++;
}
if (n > 0) {
row[0] = (unsigned char)(r/n);
row[1] = (unsigned char)(g/n);
row[2] = (unsigned char)(b/n);
}
}
row += 4;
}
}
}
static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity)
{
int i, j;
NSVGgradient* grad;
cache->type = paint->type;
if (paint->type == NSVG_PAINT_COLOR) {
cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);
return;
}
grad = paint->gradient;
cache->spread = grad->spread;
memcpy(cache->xform, grad->xform, sizeof(float)*6);
if (grad->nstops == 0) {
for (i = 0; i < 256; i++)
cache->colors[i] = 0;
} else if (grad->nstops == 1) {
unsigned int color = nsvg__applyOpacity(grad->stops[0].color, opacity);
for (i = 0; i < 256; i++)
cache->colors[i] = color;
} else {
unsigned int ca, cb = 0;
float ua, ub, du, u;
int ia, ib, count;
ca = nsvg__applyOpacity(grad->stops[0].color, opacity);
ua = nsvg__clampf(grad->stops[0].offset, 0, 1);
ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1);
ia = (int)(ua * 255.0f);
ib = (int)(ub * 255.0f);
for (i = 0; i < ia; i++) {
cache->colors[i] = ca;
}
for (i = 0; i < grad->nstops-1; i++) {
ca = nsvg__applyOpacity(grad->stops[i].color, opacity);
cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity);
ua = nsvg__clampf(grad->stops[i].offset, 0, 1);
ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1);
ia = (int)(ua * 255.0f);
ib = (int)(ub * 255.0f);
count = ib - ia;
if (count <= 0) continue;
u = 0;
du = 1.0f / (float)count;
for (j = 0; j < count; j++) {
cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
u += du;
}
}
for (i = ib; i < 256; i++)
cache->colors[i] = cb;
}
}
/*
static void dumpEdges(NSVGrasterizer* r, const char* name)
{
float xmin = 0, xmax = 0, ymin = 0, ymax = 0;
NSVGedge *e = NULL;
int i;
if (r->nedges == 0) return;
FILE* fp = fopen(name, "w");
if (fp == NULL) return;
xmin = xmax = r->edges[0].x0;
ymin = ymax = r->edges[0].y0;
for (i = 0; i < r->nedges; i++) {
e = &r->edges[i];
xmin = nsvg__minf(xmin, e->x0);
xmin = nsvg__minf(xmin, e->x1);
xmax = nsvg__maxf(xmax, e->x0);
xmax = nsvg__maxf(xmax, e->x1);
ymin = nsvg__minf(ymin, e->y0);
ymin = nsvg__minf(ymin, e->y1);
ymax = nsvg__maxf(ymax, e->y0);
ymax = nsvg__maxf(ymax, e->y1);
}
fprintf(fp, "<svg viewBox=\"%f %f %f %f\" xmlns=\"http://www.w3.org/2000/svg\">", xmin, ymin, (xmax - xmin), (ymax - ymin));
for (i = 0; i < r->nedges; i++) {
e = &r->edges[i];
fprintf(fp ,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke:#000;\" />", e->x0,e->y0, e->x1,e->y1);
}
for (i = 0; i < r->npoints; i++) {
if (i+1 < r->npoints)
fprintf(fp ,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke:#f00;\" />", r->points[i].x, r->points[i].y, r->points[i+1].x, r->points[i+1].y);
fprintf(fp ,"<circle cx=\"%f\" cy=\"%f\" r=\"1\" style=\"fill:%s;\" />", r->points[i].x, r->points[i].y, r->points[i].flags == 0 ? "#f00" : "#0f0");
}
fprintf(fp, "</svg>");
fclose(fp);
}
*/
void nsvgRasterize(NSVGrasterizer* r,
NSVGimage* image, float tx, float ty, float scale,
unsigned char* dst, int w, int h, int stride)
{
NSVGshape *shape = NULL;
NSVGedge *e = NULL;
NSVGcachedPaint cache;
int i;
int j;
unsigned char paintOrder;
r->bitmap = dst;
r->width = w;
r->height = h;
r->stride = stride;
if (w > r->cscanline) {
r->cscanline = w;
r->scanline = (unsigned char*)realloc(r->scanline, w);
if (r->scanline == NULL) return;
}
for (i = 0; i < h; i++)
memset(&dst[i*stride], 0, w*4);
for (shape = image->shapes; shape != NULL; shape = shape->next) {
if (!(shape->flags & NSVG_FLAGS_VISIBLE))
continue;
for (j = 0; j < 3; j++) {
paintOrder = (shape->paintOrder >> (2 * j)) & 0x03;
if (paintOrder == NSVG_PAINT_FILL && shape->fill.type != NSVG_PAINT_NONE) {
nsvg__resetPool(r);
r->freelist = NULL;
r->nedges = 0;
nsvg__flattenShape(r, shape, scale);
// Scale and translate edges
for (i = 0; i < r->nedges; i++) {
e = &r->edges[i];
e->x0 = tx + e->x0;
e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
e->x1 = tx + e->x1;
e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
}
// Rasterize edges
if (r->nedges != 0)
qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
nsvg__initPaint(&cache, &shape->fill, shape->opacity);
nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule);
}
if (paintOrder == NSVG_PAINT_STROKE && shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {
nsvg__resetPool(r);
r->freelist = NULL;
r->nedges = 0;
nsvg__flattenShapeStroke(r, shape, scale);
// dumpEdges(r, "edge.svg");
// Scale and translate edges
for (i = 0; i < r->nedges; i++) {
e = &r->edges[i];
e->x0 = tx + e->x0;
e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
e->x1 = tx + e->x1;
e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
}
// Rasterize edges
if (r->nedges != 0)
qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
nsvg__initPaint(&cache, &shape->stroke, shape->opacity);
nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO);
}
}
}
nsvg__unpremultiplyAlpha(dst, w, h, stride);
r->bitmap = NULL;
r->width = 0;
r->height = 0;
r->stride = 0;
}
#endif // NANOSVGRAST_IMPLEMENTATION
#endif // NANOSVGRAST_H
================================================
FILE: external/rprand.h
================================================
/**********************************************************************************************
*
* rprand v1.0 - A simple and easy-to-use pseudo-random numbers generator (PRNG)
*
* FEATURES:
* - Pseudo-random values generation, 32 bits: [0..4294967295]
* - Sequence generation avoiding duplicate values
* - Using standard and proven prng algorithm (Xoshiro128**)
* - State initialized with a separate generator (SplitMix64)
*
* LIMITATIONS:
* - No negative numbers, up to the user to manage them
*
* POSSIBLE IMPROVEMENTS:
* - Support 64 bits generation
*
* ADDITIONAL NOTES:
* This library implements two pseudo-random number generation algorithms:
*
* - Xoshiro128** : https://prng.di.unimi.it/xoshiro128starstar.c
* - SplitMix64 : https://prng.di.unimi.it/splitmix64.c
*
* SplitMix64 is used to initialize the Xoshiro128** state, from a provided seed
*
* It's suggested to use SplitMix64 to initialize the state of the generators starting from
* a 64-bit seed, as research has shown that initialization must be performed with a generator
* radically different in nature from the one initialized to avoid correlation on similar seeds.
*
* CONFIGURATION:
* #define RPRAND_IMPLEMENTATION
* Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation.
*
* DEPENDENCIES: none
*
* VERSIONS HISTORY:
* 1.0 (01-Jun-2023) First version
*
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2023 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#ifndef RPRAND_H
#define RPRAND_H
#define RPRAND_VERSION "1.0"
// Function specifiers in case library is build/used as a shared library (Windows)
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
#if defined(_WIN32)
#if defined(BUILD_LIBTYPE_SHARED)
#define RPRAND __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
#elif defined(USE_LIBTYPE_SHARED)
#define RPRAND __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
#endif
#endif
// Function specifiers definition
#ifndef RPRANDAPI
#define RPRANDAPI // Functions defined as 'extern' by default (implicit specifiers)
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
// Allow custom memory allocators
#ifndef RPRAND_CALLOC
#define RPRAND_CALLOC(ptr,sz) calloc(ptr,sz)
#endif
#ifndef RPRAND_FREE
#define RPRAND_FREE(ptr) free(ptr)
#endif
// Simple log system to avoid RPNG_LOG() calls if required
// NOTE: Avoiding those calls, also avoids const strings memory usage
#define RPRAND_SHOW_LOG_INFO
#if defined(RPNG_SHOW_LOG_INFO)
#define RPRAND_LOG(...) printf(__VA_ARGS__)
#else
#define RPRAND_LOG(...)
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
//...
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
RPRANDAPI void rprand_set_seed(unsigned long long seed); // Set rprand_state for Xoshiro128**, seed is 64bit
RPRANDAPI int rprand_get_value(int min, int max); // Get random value within a range, min and max included
RPRANDAPI int *rprand_load_sequence(unsigned int count, int min, int max); // Load pseudo-random numbers sequence with no duplicates
RPRANDAPI void rprand_unload_sequence(int *sequence); // Unload pseudo-random numbers sequence
#ifdef __cplusplus
}
#endif
#endif // RPRAND_H
/***********************************************************************************
*
* RPRAND IMPLEMENTATION
*
************************************************************************************/
#if defined(RPRAND_IMPLEMENTATION)
#include <stdlib.h> // Required for: calloc(), free(), abs()
#include <stdint.h> // Required for data types: uint32_t, uint64_t
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// ...
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
static uint64_t rprand_seed = 0xAABBCCDD; // SplitMix64 default seed (aligned to rprand_state)
static uint32_t rprand_state[4] = { // Xoshiro128** state, initialized by SplitMix64
0x96ea83c1,
0x218b21e5,
0xaa91febd,
0x976414d4
};
//----------------------------------------------------------------------------------
// Module internal functions declaration
//----------------------------------------------------------------------------------
static uint32_t rprand_xoshiro(void); // Xoshiro128** generator (uses global rprand_state)
static uint64_t rprand_splitmix64(void); // SplitMix64 generator (uses seed to generate rprand_state)
//----------------------------------------------------------------------------------
// Module functions definition
//----------------------------------------------------------------------------------
// Set rprand_state for Xoshiro128**
// NOTE: We use a custom generation algorithm using SplitMix64
void rprand_set_seed(unsigned long long seed)
{
rprand_seed = (uint64_t)seed; // Set SplitMix64 seed for further use
// To generate the Xoshiro128** state, we use SplitMix64 generator first
// We generate 4 pseudo-random 64bit numbers that we combine using their LSB|MSB
rprand_state[0] = (uint32_t)(rprand_splitmix64() & 0xffffffff);
rprand_state[1] = (uint32_t)((rprand_splitmix64() & 0xffffffff00000000) >> 32);
rprand_state[2] = (uint32_t)(rprand_splitmix64() & 0xffffffff);
rprand_state[3] = (uint32_t)((rprand_splitmix64() & 0xffffffff00000000) >> 32);
}
// Get random value within a range, min and max included
int rprand_get_value(int min, int max)
{
int value = rprand_xoshiro()%(abs(max - min) + 1) + min;
return value;
}
// Load pseudo-random numbers sequence with no duplicates, min and max included
int *rprand_load_sequence(unsigned int count, int min, int max)
{
int *sequence = NULL;
if (count > (unsigned int)(abs(max - min) + 1))
{
RPRAND_LOG("WARNING: Sequence count required is greater than range provided\n");
//count = (max - min);
return sequence;
}
sequence = (int *)RPRAND_CALLOC(count, sizeof(int));
int value = 0;
bool value_is_dup = false;
for (unsigned int i = 0; i < count;)
{
value = ((unsigned int)rprand_xoshiro()%(abs(max - min) + 1)) + min;
for (unsigned int j = 0; j < i; j++)
{
if (sequence[j] == value)
{
value_is_dup = true;
break;
}
}
if (!value_is_dup)
{
sequence[i] = value;
i++;
}
value_is_dup = false;
}
return sequence;
}
// Unload pseudo-random numbers sequence
void rprand_unload_sequence(int *sequence)
{
RPRAND_FREE(sequence);
sequence = NULL;
}
//----------------------------------------------------------------------------------
// Module internal functions definition
//----------------------------------------------------------------------------------
static inline uint32_t rprand_rotate_left(const uint32_t x, int k)
{
return (x << k) | (x >> (32 - k));
}
// Xoshiro128** generator info:
//
// Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
//
// To the extent possible under law, the author has dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// See <http://creativecommons.org/publicdomain/zero/1.0/>.
//
// This is xoshiro128** 1.1, one of our 32-bit all-purpose, rock-solid
// generators. It has excellent speed, a state size (128 bits) that is
// large enough for mild parallelism, and it passes all tests we are aware
// of.
//
// Note that version 1.0 had mistakenly s[0] instead of s[1] as state
// word passed to the scrambler.
//
// For generating just single-precision (i.e., 32-bit) floating-point
// numbers, xoshiro128+ is even faster.
//
// The state must be seeded so that it is not everywhere zero.
//
uint32_t rprand_xoshiro(void)
{
const uint32_t result = rprand_rotate_left(rprand_state[1]*5, 7)*9;
const uint32_t t = rprand_state[1] << 9;
rprand_state[2] ^= rprand_state[0];
rprand_state[3] ^= rprand_state[1];
rprand_state[1] ^= rprand_state[2];
rprand_state[0] ^= rprand_state[3];
rprand_state[2] ^= t;
rprand_state[3] = rprand_rotate_left(rprand_state[3], 11);
return result;
}
// SplitMix64 generator info:
//
// Written in 2015 by Sebastiano Vigna (vigna@acm.org)
//
// To the extent possible under law, the author has dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// See <http://creativecommons.org/publicdomain/zero/1.0/>.
//
//
// This is a fixed-increment version of Java 8's SplittableRandom generator
// See http://dx.doi.org/10.1145/2714064.2660195 and
// http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
//
// It is a very fast generator passing BigCrush, and it can be useful if
// for some reason you absolutely want 64 bits of state.
uint64_t rprand_splitmix64()
{
uint64_t z = (rprand_seed += 0x9e3779b97f4a7c15);
z = (z ^ (z >> 30))*0xbf58476d1ce4e5b9;
z = (z ^ (z >> 27))*0x94d049bb133111eb;
return z ^ (z >> 31);
}
#endif // RPRAND_IMPLEMENTATION
================================================
FILE: external/tinyfiledialogs.c
================================================
/* SPDX-License-Identifier: Zlib
Copyright (c) 2014 - 2024 Guillaume Vareille http://ysengrin.com
________________________________________________________________
| |
| 100% compatible C C++ -> You can rename this .c file as .cpp |
|________________________________________________________________|
********* TINY FILE DIALOGS OFFICIAL WEBSITE IS ON SOURCEFORGE *********
_________
/ \ tinyfiledialogs.c v3.18.2 [Jun 8, 2024] zlib licence
|tiny file| Unique code file created [November 9, 2014]
| dialogs |
\____ ___/ http://tinyfiledialogs.sourceforge.net
\| git clone http://git.code.sf.net/p/tinyfiledialogs/code tinyfd
____________________________________________
| |
| email: tinyfiledialogs at ysengrin.com |
|____________________________________________|
_________________________________________________________________________________
| |
| the windows only wchar_t UTF-16 prototypes are at the bottom of the header file |
|_________________________________________________________________________________|
_________________________________________________________
| |
| on windows: - since v3.6 char is UTF-8 by default |
| - if you want MBCS set tinyfd_winUtf8 to 0 |
| - functions like fopen expect MBCS |
|_________________________________________________________|
If you like tinyfiledialogs, please upvote my stackoverflow answer
https://stackoverflow.com/a/47651444
- License -
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
__________________________________________
| ______________________________________ |
| | | |
| | DO NOT USE USER INPUT IN THE DIALOGS | |
| |______________________________________| |
|__________________________________________|
*/
#if defined(__GNUC__) || defined(__clang__)
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* used only to resolve symbolic links. Can be commented out */
#ifndef _POSIX_C_SOURCE
#ifdef __FreeBSD__
#define _POSIX_C_SOURCE 199506L /* 199506L is enough for freebsd for realpath() */
#elif defined(__illumos__) || defined(__solaris__)
#define _POSIX_C_SOURCE 200112L /* illumos/solaris needs 200112L for realpath() */
#else
#define _POSIX_C_SOURCE 2 /* to accept POSIX 2 in old ANSI C standards */
#endif
#endif
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#ifdef _WIN32
#ifdef __BORLANDC__
#define _getch getch
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#include <windows.h>
#include <commdlg.h>
#include <shlobj.h>
#include <conio.h>
#include <direct.h>
#define TINYFD_NOCCSUNICODE
#define TINYFD_SLASH "\\"
#else
#include <limits.h>
#include <unistd.h>
#include <dirent.h> /* on old systems try <sys/dir.h> instead */
#include <termios.h>
#include <sys/utsname.h>
#include <signal.h> /* on old systems try <sys/signal.h> instead */
#define TINYFD_SLASH "/"
#endif /* _WIN32 */
#include "tinyfiledialogs.h"
#define MAX_PATH_OR_CMD 1024 /* _MAX_PATH or MAX_PATH */
#ifndef MAX_MULTIPLE_FILES
#define MAX_MULTIPLE_FILES 1024
#endif
#define LOW_MULTIPLE_FILES 32
char tinyfd_version[8] = "3.18.2";
/******************************************************************************************************/
/**************************************** UTF-8 on Windows ********************************************/
/******************************************************************************************************/
#ifdef _WIN32
/* if you want to use UTF-8 ( instead of the UTF-16/wchar_t functions at the end of tinyfiledialogs.h )
Make sure your code is really prepared for UTF-8 (on windows, functions like fopen() expect MBCS and not UTF-8) */
int tinyfd_winUtf8 = 1; /* on windows char strings can be 1:UTF-8(default) or 0:MBCS */
/* for MBCS change this to 0, here or in your code */
#endif
/******************************************************************************************************/
/******************************************************************************************************/
/******************************************************************************************************/
int tinyfd_verbose = 0 ; /* on unix: prints the command line calls */
int tinyfd_silent = 1 ; /* 1 (default) or 0 : on unix, hide errors and warnings from called dialogs */
/* Curses dialogs are difficult to use, on windows they are only ascii and uses the unix backslah */
int tinyfd_allowCursesDialogs = 0 ; /* 0 (default) or 1 */
int tinyfd_forceConsole = 0 ; /* 0 (default) or 1 */
/* for unix & windows: 0 (graphic mode) or 1 (console mode).
0: try to use a graphic solution, if it fails then it uses console mode.
1: forces all dialogs into console mode even when the X server is present.
it can use the package dialog or dialog.exe.
on windows it only make sense for console applications */
int tinyfd_assumeGraphicDisplay = 0; /* 0 (default) or 1 */
/* some systems don't set the environment variable DISPLAY even when a graphic display is present.
set this to 1 to tell tinyfiledialogs to assume the existence of a graphic display */
char tinyfd_response[1024];
/* if you pass "tinyfd_query" as aTitle,
the functions will not display the dialogs
but return 0 for console mode, 1 for graphic mode.
tinyfd_response is then filled with the retain solution.
possible values for tinyfd_response are (all lowercase)
for graphic mode:
windows_wchar windows applescript kdialog zenity zenity3 yad matedialog
shellementary qarma python2-tkinter python3-tkinter python-dbus
perl-dbus gxmessage gmessage xmessage xdialog gdialog dunst
for console mode:
dialog whiptail basicinput no_solution */
static int gWarningDisplayed = 0 ;
static char gTitle[]="missing software! (we will try basic console input)";
#ifdef _WIN32
char tinyfd_needs[] = "\
___________\n\
/ \\ \n\
| tiny file |\n\
| dialogs |\n\
\\_____ ____/\n\
\\|\
\ntiny file dialogs on Windows needs:\
\n a graphic display\
\nor dialog.exe (curses console mode ** Disabled by default **)\
\nor a console for basic input";
#else
char tinyfd_needs[] = "\
___________\n\
/ \\ \n\
| tiny file |\n\
| dialogs |\n\
\\_____ ____/\n\
\\|\
\ntiny file dialogs on UNIX needs:\
\n applescript or kdialog or yad or Xdialog\
\nor zenity (or matedialog or shellementary or qarma)\
\nor python (2 or 3) + tkinter + python-dbus (optional)\
\nor dialog (opens console if needed) ** Disabled by default **\
\nor xterm + bash (opens console for basic input)\
\nor existing console for basic input.";
#endif
#ifdef _MSC_VER
#pragma warning(disable:4996) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */
#pragma warning(disable:4100) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */
#pragma warning(disable:4706) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */
#endif
static int getenvDISPLAY(void)
{
return tinyfd_assumeGraphicDisplay || getenv("DISPLAY");
}
static char * getCurDir(void)
{
static char lCurDir[MAX_PATH_OR_CMD];
return getcwd(lCurDir, sizeof(lCurDir));
}
static char * getPathWithoutFinalSlash(
char * aoDestination, /* make sure it is allocated, use _MAX_PATH */
char const * aSource) /* aoDestination and aSource can be the same */
{
char const * lTmp ;
if ( aSource )
{
lTmp = strrchr(aSource, '/');
if (!lTmp)
{
lTmp = strrchr(aSource, '\\');
}
if (lTmp)
{
strncpy(aoDestination, aSource, lTmp - aSource );
aoDestination[lTmp - aSource] = '\0';
}
else
{
* aoDestination = '\0';
}
}
else
{
* aoDestination = '\0';
}
return aoDestination;
}
static char * getLastName(
char * aoDestination, /* make sure it is allocated */
char const * aSource)
{
/* copy the last name after '/' or '\' */
char const * lTmp ;
if ( aSource )
{
lTmp = strrchr(aSource, '/');
if (!lTmp)
{
lTmp = strrchr(aSource, '\\');
}
if (lTmp)
{
strcpy(aoDestination, lTmp + 1);
}
else
{
strcpy(aoDestination, aSource);
}
}
else
{
* aoDestination = '\0';
}
return aoDestination;
}
static void ensureFinalSlash( char * aioString )
{
if ( aioString && strlen( aioString ) )
{
char * lastcar = aioString + strlen( aioString ) - 1 ;
if ( strncmp( lastcar , TINYFD_SLASH , 1 ) )
{
strcat( lastcar , TINYFD_SLASH ) ;
}
}
}
static void Hex2RGB( char const aHexRGB[8] , unsigned char aoResultRGB[3] )
{
char lColorChannel[8] ;
if ( aoResultRGB )
{
if ( aHexRGB )
{
strcpy(lColorChannel, aHexRGB ) ;
aoResultRGB[2] = (unsigned char)strtoul(lColorChannel+5,NULL,16);
lColorChannel[5] = '\0';
aoResultRGB[1] = (unsigned char)strtoul(lColorChannel+3,NULL,16);
lColorChannel[3] = '\0';
aoResultRGB[0] = (unsigned char)strtoul(lColorChannel+1,NULL,16);
/* printf("%d %d %d\n", aoResultRGB[0], aoResultRGB[1], aoResultRGB[2]); */
}
else
{
aoResultRGB[0]=0;
aoResultRGB[1]=0;
aoResultRGB[2]=0;
}
}
}
static void RGB2Hex( unsigned char const aRGB[3], char aoResultHexRGB[8] )
{
if ( aoResultHexRGB )
{
if ( aRGB )
{
#if (defined(__cplusplus ) && __cplusplus >= 201103L) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__clang__)
sprintf(aoResultHexRGB, "#%02hhx%02hhx%02hhx", aRGB[0], aRGB[1], aRGB[2]);
#else
sprintf(aoResultHexRGB, "#%02hx%02hx%02hx", aRGB[0], aRGB[1], aRGB[2]);
#endif
/*printf("aoResultHexRGB %s\n", aoResultHexRGB);*/
}
else
{
aoResultHexRGB[0]=0;
aoResultHexRGB[1]=0;
aoResultHexRGB[2]=0;
}
}
}
void tfd_replaceSubStr( char const * aSource, char const * aOldSubStr,
char const * aNewSubStr, char * aoDestination )
{
char const * pOccurence ;
char const * p ;
char const * lNewSubStr = "" ;
size_t lOldSubLen = strlen( aOldSubStr ) ;
if ( ! aSource )
{
* aoDestination = '\0' ;
return ;
}
if ( ! aOldSubStr )
{
strcpy( aoDestination , aSource ) ;
return ;
}
if ( aNewSubStr )
{
lNewSubStr = aNewSubStr ;
}
p = aSource ;
* aoDestination = '\0' ;
while ( ( pOccurence = strstr( p , aOldSubStr ) ) != NULL )
{
strncat( aoDestination , p , pOccurence - p ) ;
strcat( aoDestination , lNewSubStr ) ;
p = pOccurence + lOldSubLen ;
}
strcat( aoDestination , p ) ;
}
static int filenameValid( char const * aFileNameWithoutPath )
{
if ( ! aFileNameWithoutPath
|| ! strlen(aFileNameWithoutPath)
|| strpbrk(aFileNameWithoutPath , "\\/:*?\"<>|") )
{
return 0 ;
}
return 1 ;
}
#ifndef _WIN32
static int fileExists( char const * aFilePathAndName )
{
FILE * lIn ;
if ( ! aFilePathAndName || ! strlen(aFilePathAndName) )
{
return 0 ;
}
lIn = fopen( aFilePathAndName , "r" ) ;
if ( ! lIn )
{
return 0 ;
}
fclose( lIn ) ;
return 1 ;
}
#endif
static void wipefile(char const * aFilename)
{
int i;
struct stat st;
FILE * lIn;
if (stat(aFilename, &st) == 0)
{
if ((lIn = fopen(aFilename, "w")))
{
for (i = 0; i < st.st_size; i++)
{
fputc('A', lIn);
}
fclose(lIn);
}
}
}
int tfd_quoteDetected(char const * aString)
{
char const * p;
if (!aString) return 0;
p = aString;
if ( strchr(p, '\''))
{
return 1;
}
if ( strchr(p, '\"'))
{
return 1;
}
if ( strchr(p, '`'))
{
return 1;
}
p = aString;
while ((p = strchr(p, '$')))
{
p ++ ;
if ( ( * p == '(' ) || ( * p == '_' ) || isalpha( * p) ) return 1 ;
}
return 0;
}
char const * tinyfd_getGlobalChar(char const * aCharVariableName) /* to be called from C# (you don't need this in C or C++) */
{
if (!aCharVariableName || !strlen(aCharVariableName)) return NULL;
else if (!strcmp(aCharVariableName, "tinyfd_version")) return tinyfd_version;
else if (!strcmp(aCharVariableName, "tinyfd_needs")) return tinyfd_needs;
else if (!strcmp(aCharVariableName, "tinyfd_response")) return tinyfd_response;
else return NULL ;
}
int tinyfd_getGlobalInt(char const * aIntVariableName) /* to be called from C# (you don't need this in C or C++) */
{
if ( !aIntVariableName || !strlen(aIntVariableName) ) return -1 ;
else if ( !strcmp(aIntVariableName, "tinyfd_verbose") ) return tinyfd_verbose ;
else if ( !strcmp(aIntVariableName, "tinyfd_silent") ) return tinyfd_silent ;
else if ( !strcmp(aIntVariableName, "tinyfd_allowCursesDialogs") ) return tinyfd_allowCursesDialogs ;
else if ( !strcmp(aIntVariableName, "tinyfd_forceConsole") ) return tinyfd_forceConsole ;
else if ( !strcmp(aIntVariableName, "tinyfd_assumeGraphicDisplay") ) return tinyfd_assumeGraphicDisplay ;
#ifdef _WIN32
else if ( !strcmp(aIntVariableName, "tinyfd_winUtf8") ) return tinyfd_winUtf8 ;
#endif
else return -1;
}
int tinyfd_setGlobalInt(char const * aIntVariableName, int aValue) /* to be called from C# (you don't need this in C or C++) */
{
if (!aIntVariableName || !strlen(aIntVariableName)) return -1 ;
else if (!strcmp(aIntVariableName, "tinyfd_verbose")) { tinyfd_verbose = aValue; return tinyfd_verbose; }
else if (!strcmp(aIntVariableName, "tinyfd_silent")) { tinyfd_silent = aValue; return tinyfd_silent; }
else if (!strcmp(aIntVariableName, "tinyfd_allowCursesDialogs")) { tinyfd_allowCursesDialogs = aValue; return tinyfd_allowCursesDialogs; }
else if (!strcmp(aIntVariableName, "tinyfd_forceConsole")) { tinyfd_forceConsole = aValue; return tinyfd_forceConsole; }
else if (!strcmp(aIntVariableName, "tinyfd_assumeGraphicDisplay")) { tinyfd_assumeGraphicDisplay = aValue; return tinyfd_assumeGraphicDisplay; }
#ifdef _WIN32
else if (!strcmp(aIntVariableName, "tinyfd_winUtf8")) { tinyfd_winUtf8 = aValue; return tinyfd_winUtf8; }
#endif
else return -1;
}
#ifdef _WIN32
static int powershellPresent(void)
{ /*only on vista and above (or installed on xp)*/
static int lPowershellPresent = -1;
char lBuff[MAX_PATH_OR_CMD];
FILE* lIn;
char const* lString = "powershell.exe";
if (lPowershellPresent < 0)
{
if (!(lIn = _popen("where powershell.exe", "r")))
{
lPowershellPresent = 0;
return 0;
}
while (fgets(lBuff, sizeof(lBuff), lIn) != NULL)
{
}
_pclose(lIn);
if (lBuff[strlen(lBuff) - 1] == '\n')
{
lBuff[strlen(lBuff) - 1] = '\0';
}
if (strcmp(lBuff + strlen(lBuff) - strlen(lString), lString))
{
lPowershellPresent = 0;
}
else
{
lPowershellPresent = 1;
}
}
return lPowershellPresent;
}
static int windowsVersion(void)
{
#if !defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR)
typedef LONG NTSTATUS ;
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
HMODULE hMod;
RtlGetVersionPtr lFxPtr;
RTL_OSVERSIONINFOW lRovi = { 0 };
hMod = GetModuleHandleW(L"ntdll.dll");
if (hMod) {
lFxPtr = (RtlGetVersionPtr)GetProcAddress(hMod, "RtlGetVersion");
if (lFxPtr)
{
lRovi.dwOSVersionInfoSize = sizeof(lRovi);
gitextract_3r4214vd/
├── .github/
│ ├── generate_notes.py
│ └── workflows/
│ ├── build.yml
│ └── release.yml
├── .gitignore
├── .gitmodules
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── data/
│ ├── nk57-cond.otf
│ ├── nk57-eb.otf
│ └── nk57.otf
├── default.nix
├── examples/
│ ├── 3d.scrp
│ ├── actual_3d.scrp
│ ├── ball.scrp
│ ├── circle.scrp
│ ├── clock.scrp
│ ├── colors.scrp
│ ├── fibonacci.scrp
│ ├── guess.scrp
│ ├── hello_world.scrp
│ ├── neon.scrp
│ └── trig.scrp
├── external/
│ ├── cfgpath.c
│ ├── cfgpath.h
│ ├── nanosvg.h
│ ├── nanosvgrast.h
│ ├── rprand.h
│ ├── tinyfiledialogs.c
│ └── tinyfiledialogs.h
├── scrap.desktop
├── scrap.rc
├── src/
│ ├── ast.c
│ ├── ast.h
│ ├── blocks.c
│ ├── compiler.c
│ ├── compiler.h
│ ├── config.h
│ ├── gc.c
│ ├── gc.h
│ ├── interpreter.c
│ ├── interpreter.h
│ ├── platform.c
│ ├── render.c
│ ├── save.c
│ ├── scrap-runtime.c
│ ├── scrap.c
│ ├── scrap.h
│ ├── scrap_gui.c
│ ├── scrap_gui.h
│ ├── std.c
│ ├── std.h
│ ├── term.c
│ ├── term.h
│ ├── thread.c
│ ├── thread.h
│ ├── ui.c
│ ├── util.c
│ ├── util.h
│ ├── vec.c
│ ├── vec.h
│ ├── vm.c
│ └── window.c
└── translations/
├── kk/
│ └── LC_MESSAGES/
│ └── scrap.po
├── ru/
│ └── LC_MESSAGES/
│ └── scrap.po
└── uk/
└── LC_MESSAGES/
└── scrap.po
SYMBOL INDEX (1132 symbols across 35 files)
FILE: external/cfgpath.c
function get_user_config_file (line 23) | void get_user_config_file(char *out, unsigned int maxlen, const char *ap...
function get_user_config_folder (line 102) | void get_user_config_folder(char *out, unsigned int maxlen, const char *...
function get_user_data_folder (line 186) | void get_user_data_folder(char *out, unsigned int maxlen, const char *ap...
function get_user_cache_folder (line 236) | void get_user_cache_folder(char *out, unsigned int maxlen, const char *a...
FILE: external/nanosvg.h
type NSVGpaintType (line 74) | enum NSVGpaintType {
type NSVGspreadType (line 82) | enum NSVGspreadType {
type NSVGlineJoin (line 88) | enum NSVGlineJoin {
type NSVGlineCap (line 94) | enum NSVGlineCap {
type NSVGfillRule (line 100) | enum NSVGfillRule {
type NSVGflags (line 105) | enum NSVGflags {
type NSVGpaintOrder (line 109) | enum NSVGpaintOrder {
type NSVGgradientStop (line 115) | typedef struct NSVGgradientStop {
type NSVGgradient (line 120) | typedef struct NSVGgradient {
type NSVGpaint (line 128) | typedef struct NSVGpaint {
type NSVGpath (line 136) | typedef struct NSVGpath
type NSVGshape (line 145) | typedef struct NSVGshape
type NSVGimage (line 169) | typedef struct NSVGimage
function nsvg__isspace (line 228) | static int nsvg__isspace(char c)
function nsvg__isdigit (line 233) | static int nsvg__isdigit(char c)
function NSVG_INLINE (line 238) | static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a...
function NSVG_INLINE (line 239) | static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a...
function nsvg__parseContent (line 248) | static void nsvg__parseContent(char* s,
function nsvg__parseElement (line 260) | static void nsvg__parseElement(char* s,
function nsvg__parseXML (line 336) | int nsvg__parseXML(char* input,
type NSVGgradientUnits (line 371) | enum NSVGgradientUnits {
type NSVGunits (line 378) | enum NSVGunits {
type NSVGcoordinate (line 391) | typedef struct NSVGcoordinate {
type NSVGlinearData (line 396) | typedef struct NSVGlinearData {
type NSVGradialData (line 400) | typedef struct NSVGradialData {
type NSVGgradientData (line 404) | typedef struct NSVGgradientData
type NSVGattrib (line 421) | typedef struct NSVGattrib
type NSVGparser (line 450) | typedef struct NSVGparser
function nsvg__xformIdentity (line 468) | static void nsvg__xformIdentity(float* t)
function nsvg__xformSetTranslation (line 475) | static void nsvg__xformSetTranslation(float* t, float tx, float ty)
function nsvg__xformSetScale (line 482) | static void nsvg__xformSetScale(float* t, float sx, float sy)
function nsvg__xformSetSkewX (line 489) | static void nsvg__xformSetSkewX(float* t, float a)
function nsvg__xformSetSkewY (line 496) | static void nsvg__xformSetSkewY(float* t, float a)
function nsvg__xformSetRotation (line 503) | static void nsvg__xformSetRotation(float* t, float a)
function nsvg__xformMultiply (line 511) | static void nsvg__xformMultiply(float* t, float* s)
function nsvg__xformInverse (line 524) | static void nsvg__xformInverse(float* inv, float* t)
function nsvg__xformPremultiply (line 540) | static void nsvg__xformPremultiply(float* t, float* s)
function nsvg__xformPoint (line 548) | static void nsvg__xformPoint(float* dx, float* dy, float x, float y, flo...
function nsvg__xformVec (line 554) | static void nsvg__xformVec(float* dx, float* dy, float x, float y, float...
function nsvg__ptInBounds (line 562) | static int nsvg__ptInBounds(float* pt, float* bounds)
function nsvg__evalBezier (line 568) | static double nsvg__evalBezier(double t, double p0, double p1, double p2...
function nsvg__curveBounds (line 574) | static void nsvg__curveBounds(float* bounds, float* curve)
function nsvg__encodePaintOrder (line 625) | static unsigned char nsvg__encodePaintOrder(enum NSVGpaintOrder a, enum ...
function NSVGparser (line 629) | static NSVGparser* nsvg__createParser(void)
function nsvg__deletePaths (line 668) | static void nsvg__deletePaths(NSVGpath* path)
function nsvg__deletePaint (line 679) | static void nsvg__deletePaint(NSVGpaint* paint)
function nsvg__deleteGradientData (line 685) | static void nsvg__deleteGradientData(NSVGgradientData* grad)
function nsvg__deleteParser (line 696) | static void nsvg__deleteParser(NSVGparser* p)
function nsvg__resetPath (line 707) | static void nsvg__resetPath(NSVGparser* p)
function nsvg__addPoint (line 712) | static void nsvg__addPoint(NSVGparser* p, float x, float y)
function nsvg__moveTo (line 724) | static void nsvg__moveTo(NSVGparser* p, float x, float y)
function nsvg__lineTo (line 734) | static void nsvg__lineTo(NSVGparser* p, float x, float y)
function nsvg__cubicBezTo (line 748) | static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, floa...
function NSVGattrib (line 757) | static NSVGattrib* nsvg__getAttr(NSVGparser* p)
function nsvg__pushAttr (line 762) | static void nsvg__pushAttr(NSVGparser* p)
function nsvg__popAttr (line 770) | static void nsvg__popAttr(NSVGparser* p)
function nsvg__actualOrigX (line 776) | static float nsvg__actualOrigX(NSVGparser* p)
function nsvg__actualOrigY (line 781) | static float nsvg__actualOrigY(NSVGparser* p)
function nsvg__actualWidth (line 786) | static float nsvg__actualWidth(NSVGparser* p)
function nsvg__actualHeight (line 791) | static float nsvg__actualHeight(NSVGparser* p)
function nsvg__actualLength (line 796) | static float nsvg__actualLength(NSVGparser* p)
function nsvg__convertToPixels (line 802) | static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, floa...
function NSVGgradientData (line 821) | static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const cha...
function NSVGgradient (line 834) | static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id,...
function nsvg__getAverageScale (line 921) | static float nsvg__getAverageScale(float* t)
function nsvg__getLocalBounds (line 928) | static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float*...
function nsvg__addShape (line 958) | static void nsvg__addShape(NSVGparser* p)
function nsvg__addPath (line 1043) | static void nsvg__addPath(NSVGparser* p, char closed)
function nsvg__atof (line 1104) | static double nsvg__atof(const char* s)
function nsvg__parseColorHex (line 1237) | static unsigned int nsvg__parseColorHex(const char* str)
function nsvg__parseColorRGB (line 1251) | static unsigned int nsvg__parseColorRGB(const char* str)
type NSVGNamedColor (line 1301) | typedef struct NSVGNamedColor {
function nsvg__parseColorName (line 1460) | static unsigned int nsvg__parseColorName(const char* str)
function nsvg__parseColor (line 1473) | static unsigned int nsvg__parseColor(const char* str)
function nsvg__parseOpacity (line 1485) | static float nsvg__parseOpacity(const char* str)
function nsvg__parseMiterLimit (line 1493) | static float nsvg__parseMiterLimit(const char* str)
function nsvg__parseUnits (line 1500) | static int nsvg__parseUnits(const char* units)
function nsvg__isCoordinate (line 1523) | static int nsvg__isCoordinate(const char* s)
function NSVGcoordinate (line 1532) | static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
function NSVGcoordinate (line 1541) | static NSVGcoordinate nsvg__coord(float v, int units)
function nsvg__parseCoordinate (line 1547) | static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float...
function nsvg__parseTransformArgs (line 1553) | static int nsvg__parseTransformArgs(const char* str, float* args, int ma...
function nsvg__parseMatrix (line 1582) | static int nsvg__parseMatrix(float* xform, const char* str)
function nsvg__parseTranslate (line 1592) | static int nsvg__parseTranslate(float* xform, const char* str)
function nsvg__parseScale (line 1605) | static int nsvg__parseScale(float* xform, const char* str)
function nsvg__parseSkewX (line 1617) | static int nsvg__parseSkewX(float* xform, const char* str)
function nsvg__parseSkewY (line 1628) | static int nsvg__parseSkewY(float* xform, const char* str)
function nsvg__parseRotate (line 1639) | static int nsvg__parseRotate(float* xform, const char* str)
function nsvg__parseTransform (line 1668) | static void nsvg__parseTransform(float* xform, const char* str)
function nsvg__parseUrl (line 1702) | static void nsvg__parseUrl(char* id, const char* str)
function nsvg__parseLineCap (line 1715) | static char nsvg__parseLineCap(const char* str)
function nsvg__parseLineJoin (line 1727) | static char nsvg__parseLineJoin(const char* str)
function nsvg__parseFillRule (line 1739) | static char nsvg__parseFillRule(const char* str)
function nsvg__parsePaintOrder (line 1749) | static unsigned char nsvg__parsePaintOrder(const char* str)
function nsvg__parseStrokeDashArray (line 1783) | static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, fl...
function nsvg__parseAttr (line 1811) | static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* ...
function nsvg__parseNameValue (line 1886) | static int nsvg__parseNameValue(NSVGparser* p, const char* start, const ...
function nsvg__parseStyle (line 1918) | static void nsvg__parseStyle(NSVGparser* p, const char* str)
function nsvg__parseAttribs (line 1939) | static void nsvg__parseAttribs(NSVGparser* p, const char** attr)
function nsvg__getArgsPerElement (line 1951) | static int nsvg__getArgsPerElement(char cmd)
function nsvg__pathMoveTo (line 1984) | static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, floa...
function nsvg__pathLineTo (line 1996) | static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, floa...
function nsvg__pathHLineTo (line 2008) | static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, flo...
function nsvg__pathVLineTo (line 2017) | static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, flo...
function nsvg__pathCubicBezTo (line 2026) | static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy,
function nsvg__pathCubicBezShortTo (line 2055) | static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* ...
function nsvg__pathQuadBezTo (line 2085) | static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy,
function nsvg__pathQuadBezShortTo (line 2119) | static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy,
function nsvg__sqr (line 2152) | static float nsvg__sqr(float x) { return x*x; }
function nsvg__vmag (line 2153) | static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); }
function nsvg__vecrat (line 2155) | static float nsvg__vecrat(float ux, float uy, float vx, float vy)
function nsvg__vecang (line 2160) | static float nsvg__vecang(float ux, float uy, float vx, float vy)
function nsvg__pathArcTo (line 2168) | static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float...
function nsvg__parsePath (line 2289) | static void nsvg__parsePath(NSVGparser* p, const char** attr)
function nsvg__parseRect (line 2437) | static void nsvg__parseRect(NSVGparser* p, const char** attr)
function nsvg__parseCircle (line 2492) | static void nsvg__parseCircle(NSVGparser* p, const char** attr)
function nsvg__parseEllipse (line 2522) | static void nsvg__parseEllipse(NSVGparser* p, const char** attr)
function nsvg__parseLine (line 2555) | static void nsvg__parseLine(NSVGparser* p, const char** attr)
function nsvg__parsePoly (line 2582) | static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeF...
function nsvg__parseSVG (line 2618) | static void nsvg__parseSVG(NSVGparser* p, const char** attr)
function nsvg__parseGradient (line 2673) | static void nsvg__parseGradient(NSVGparser* p, const char** attr, signed...
function nsvg__parseGradientStop (line 2743) | static void nsvg__parseGradientStop(NSVGparser* p, const char** attr)
function nsvg__startElement (line 2785) | static void nsvg__startElement(void* ud, const char* el, const char** attr)
function nsvg__endElement (line 2847) | static void nsvg__endElement(void* ud, const char* el)
function nsvg__content (line 2860) | static void nsvg__content(void* ud, const char* s)
function nsvg__imageBounds (line 2867) | static void nsvg__imageBounds(NSVGparser* p, float* bounds)
function nsvg__viewAlign (line 2887) | static float nsvg__viewAlign(float content, float container, int type)
function nsvg__scaleGradient (line 2897) | static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, ...
function nsvg__scaleToViewbox (line 2907) | static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
function nsvg__createGradients (line 2998) | static void nsvg__createGradients(NSVGparser* p)
function NSVGimage (line 3028) | NSVGimage* nsvgParse(char* input, const char* units, float dpi)
function NSVGimage (line 3055) | NSVGimage* nsvgParseFromFile(const char* filename, const char* units, fl...
function NSVGpath (line 3084) | NSVGpath* nsvgDuplicatePath(NSVGpath* p)
function nsvgDelete (line 3114) | void nsvgDelete(NSVGimage* image)
FILE: external/nanosvgrast.h
type NSVGrasterizer (line 36) | typedef struct NSVGrasterizer NSVGrasterizer;
type NSVGedge (line 89) | typedef struct NSVGedge {
type NSVGpoint (line 95) | typedef struct NSVGpoint {
type NSVGactiveEdge (line 103) | typedef struct NSVGactiveEdge {
type NSVGmemPage (line 110) | typedef struct NSVGmemPage {
type NSVGcachedPaint (line 116) | typedef struct NSVGcachedPaint {
type NSVGrasterizer (line 123) | struct NSVGrasterizer
function NSVGrasterizer (line 153) | NSVGrasterizer* nsvgCreateRasterizer(void)
function nsvgDeleteRasterizer (line 169) | void nsvgDeleteRasterizer(NSVGrasterizer* r)
function NSVGmemPage (line 190) | static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur)
function nsvg__resetPool (line 213) | static void nsvg__resetPool(NSVGrasterizer* r)
function nsvg__ptEquals (line 235) | static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float ...
function nsvg__addPathPoint (line 242) | static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int ...
function nsvg__appendPathPoint (line 267) | static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt)
function nsvg__duplicatePoints (line 278) | static void nsvg__duplicatePoints(NSVGrasterizer* r)
function nsvg__addEdge (line 290) | static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x...
function nsvg__normalize (line 322) | static float nsvg__normalize(float *x, float* y)
function nsvg__absf (line 333) | static float nsvg__absf(float x) { return x < 0 ? -x : x; }
function nsvg__roundf (line 334) | static float nsvg__roundf(float x) { return (x >= 0) ? floorf(x + 0.5) :...
function nsvg__flattenCubicBez (line 336) | static void nsvg__flattenCubicBez(NSVGrasterizer* r,
function nsvg__flattenShape (line 374) | static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, floa...
type NSVGpointFlags (line 395) | enum NSVGpointFlags
function nsvg__initClosed (line 402) | static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoin...
function nsvg__buttCap (line 416) | static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint*...
function nsvg__squareCap (line 434) | static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoin...
function nsvg__roundCap (line 456) | static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint...
function nsvg__bevelJoin (line 492) | static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoin...
function nsvg__miterJoin (line 512) | static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoin...
function nsvg__roundJoin (line 548) | static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoin...
function nsvg__straightJoin (line 589) | static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGp...
function nsvg__curveDivs (line 602) | static int nsvg__curveDivs(float r, float arc, float tol)
function nsvg__expandStroke (line 610) | static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int...
function nsvg__prepareStroke (line 681) | static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int...
function nsvg__flattenShapeStroke (line 738) | static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape...
function nsvg__cmpEdge (line 849) | static int nsvg__cmpEdge(const void *p, const void *q)
function NSVGactiveEdge (line 860) | static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, f...
function nsvg__freeActive (line 890) | static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z)
function nsvg__fillScanline (line 896) | static void nsvg__fillScanline(unsigned char* scanline, int len, int x0,...
function nsvg__fillActiveEdges (line 926) | static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVG...
function nsvg__clampf (line 960) | static float nsvg__clampf(float a, float mn, float mx) {
function nsvg__RGBA (line 966) | static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigne...
function nsvg__lerpRGBA (line 971) | static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, flo...
function nsvg__applyOpacity (line 981) | static unsigned int nsvg__applyOpacity(unsigned int c, float u)
function nsvg__div255 (line 991) | static inline int nsvg__div255(int x)
function nsvg__scanlineSolid (line 996) | static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned ...
function nsvg__rasterizeSortedEdges (line 1124) | static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, floa...
function nsvg__unpremultiplyAlpha (line 1212) | static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h,...
function nsvg__initPaint (line 1272) | static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, fl...
function nsvgRasterize (line 1375) | void nsvgRasterize(NSVGrasterizer* r,
FILE: external/rprand.h
function rprand_set_seed (line 169) | void rprand_set_seed(unsigned long long seed)
function rprand_get_value (line 182) | int rprand_get_value(int min, int max)
function rprand_unload_sequence (line 232) | void rprand_unload_sequence(int *sequence)
function rprand_rotate_left (line 241) | static inline uint32_t rprand_rotate_left(const uint32_t x, int k)
function rprand_xoshiro (line 269) | uint32_t rprand_xoshiro(void)
function rprand_splitmix64 (line 303) | uint64_t rprand_splitmix64()
FILE: external/tinyfiledialogs.c
function getenvDISPLAY (line 195) | static int getenvDISPLAY(void)
function ensureFinalSlash (line 268) | static void ensureFinalSlash( char * aioString )
function Hex2RGB (line 281) | static void Hex2RGB( char const aHexRGB[8] , unsigned char aoResultRGB[3] )
function RGB2Hex (line 305) | static void RGB2Hex( unsigned char const aRGB[3], char aoResultHexRGB[8] )
function tfd_replaceSubStr (line 328) | void tfd_replaceSubStr( char const * aSource, char const * aOldSubStr,
function filenameValid (line 362) | static int filenameValid( char const * aFileNameWithoutPath )
function fileExists (line 375) | static int fileExists( char const * aFilePathAndName )
function wipefile (line 394) | static void wipefile(char const * aFilename)
function tfd_quoteDetected (line 414) | int tfd_quoteDetected(char const * aString)
function tinyfd_getGlobalInt (line 457) | int tinyfd_getGlobalInt(char const * aIntVariableName) /* to be called f...
function tinyfd_setGlobalInt (line 472) | int tinyfd_setGlobalInt(char const * aIntVariableName, int aValue) /* to...
function powershellPresent (line 488) | static int powershellPresent(void)
function windowsVersion (line 522) | static int windowsVersion(void)
function replaceChr (line 549) | static void replaceChr(char * aString, char aOldChr, char aNewChr)
function sizeUtf16From8 (line 571) | static int sizeUtf16From8(char const * aUtf8string)
function sizeUtf16FromMbcs (line 578) | static int sizeUtf16FromMbcs(char const * aMbcsString)
function sizeUtf8 (line 585) | static int sizeUtf8(wchar_t const * aUtf16string)
function sizeMbcs (line 592) | static int sizeMbcs(wchar_t const * aMbcsString)
function wchar_t (line 601) | wchar_t* tinyfd_mbcsTo16(char const* aMbcsString)
function wchar_t (line 619) | wchar_t * tinyfd_utf8to16(char const * aUtf8string)
function tinyfd_beep (line 695) | void tinyfd_beep(void)
function wipefileW (line 702) | static void wipefileW(wchar_t const * aFilename)
function wchar_t (line 726) | static wchar_t * getPathWithoutFinalSlashW(
function wchar_t (line 756) | static wchar_t * getLastNameW(
function Hex2RGBW (line 786) | static void Hex2RGBW(wchar_t const aHexRGB[8], unsigned char aoResultRGB...
function RGB2HexW (line 811) | static void RGB2HexW( unsigned char const aRGB[3], wchar_t aoResultHexRG...
function dirExists (line 841) | static int dirExists(char const * aDirPath)
function fileExists (line 888) | static int fileExists(char const * aFilePathAndName)
function replaceWchar (line 932) | static void replaceWchar(wchar_t * aString,
function quoteDetectedW (line 961) | static int quoteDetectedW(wchar_t const * aString)
function EnumThreadWndProc (line 1032) | static int __stdcall EnumThreadWndProc(HWND hwnd, LPARAM lParam)
function hiddenConsoleW (line 1049) | static void hiddenConsoleW(wchar_t const * aString, wchar_t const * aDia...
function tinyfd_messageBoxW (line 1079) | int tinyfd_messageBoxW(
function tinyfd_notifyPopupW (line 1238) | int tinyfd_notifyPopupW(
function wchar_t (line 1628) | wchar_t * tinyfd_saveFileDialogW(
function wchar_t (line 1730) | wchar_t * tinyfd_openFileDialogW(
function BOOL (line 1898) | BOOL CALLBACK BrowseCallbackProcW_enum(HWND hWndChild, LPARAM lParam)
function BrowseCallbackProcW (line 1913) | static int __stdcall BrowseCallbackProcW(HWND hwnd, UINT uMsg, LPARAM lp...
function wchar_t (line 1927) | wchar_t * tinyfd_selectFolderDialogW(
function wchar_t (line 1976) | wchar_t * tinyfd_colorChooserW(
function messageBoxWinGui (line 2041) | static int messageBoxWinGui(
function notifyWinGui (line 2089) | static int notifyWinGui(
function inputBoxWinGui (line 2127) | static int inputBoxWinGui(
function dialogPresent (line 2403) | static int dialogPresent(void)
function messageBoxWinConsole (line 2438) | static int messageBoxWinConsole(
function inputBoxWinConsole (line 2554) | static int inputBoxWinConsole(
function writeUtf8 (line 2833) | static void writeUtf8( char const * aUtf8String )
function tinyfd_messageBox (line 2845) | int tinyfd_messageBox(
function tinyfd_notifyPopup (line 2966) | int tinyfd_notifyPopup(
function tfd_isDarwin (line 3390) | int tfd_isDarwin(void)
function dirExists (line 3402) | static int dirExists( char const * aDirPath )
function detectPresence (line 3417) | static int detectPresence( char const * aExecutable )
function tryCommand (line 3497) | static int tryCommand( char const * aCommand )
function isTerminalRunning (line 3517) | static int isTerminalRunning(void)
function isDialogVersionBetter09b (line 3553) | int isDialogVersionBetter09b(void)
function whiptailPresentOnly (line 3590) | static int whiptailPresentOnly(void)
function whiptailPresent (line 3744) | static int whiptailPresent(void)
function graphicMode (line 3760) | static int graphicMode(void)
function ffplayPresent (line 3768) | static int ffplayPresent(void)
function pactlPresent (line 3779) | static int pactlPresent( void )
function speakertestPresent (line 3803) | static int speakertestPresent(void)
function playPresent (line 3814) | static int playPresent(void) /* play is part of sox */
function beepexePresent (line 3825) | static int beepexePresent(void)
function playsoundPresent (line 3847) | static int playsoundPresent(void) /* playsound is part of pipewire */
function paplayPresent (line 3862) | static int paplayPresent(void) /* playsound is part of pipewire */
function xmessagePresent (line 3877) | static int xmessagePresent(void)
function gxmessagePresent (line 3888) | static int gxmessagePresent(void)
function gmessagePresent (line 3899) | static int gmessagePresent(void)
function notifysendPresent (line 3910) | static int notifysendPresent(void)
function perlPresent (line 3921) | static int perlPresent(void)
function afplayPresent (line 3945) | static int afplayPresent(void)
function xdialogPresent (line 3969) | static int xdialogPresent(void)
function gdialogPresent (line 3980) | static int gdialogPresent(void)
function osascriptPresent (line 3991) | static int osascriptPresent(void)
function dunstifyPresent (line 4003) | static int dunstifyPresent(void)
function dunstPresent (line 4027) | static int dunstPresent(void)
function tfd_qarmaPresent (line 4052) | int tfd_qarmaPresent(void)
function tfd_matedialogPresent (line 4063) | int tfd_matedialogPresent(void)
function tfd_shellementaryPresent (line 4074) | int tfd_shellementaryPresent(void)
function tfd_xpropPresent (line 4085) | int tfd_xpropPresent(void)
function tfd_zenityPresent (line 4114) | int tfd_zenityPresent(void)
function tfd_yadPresent (line 4125) | int tfd_yadPresent(void)
function tfd_zenity3Present (line 4136) | int tfd_zenity3Present(void)
function tfd_kdialogPresent (line 4177) | int tfd_kdialogPresent(void)
function osx9orBetter (line 4230) | static int osx9orBetter(void)
function python3Present (line 4258) | static int python3Present(void)
function python2Present (line 4274) | static int python2Present(void)
function tkinter3Present (line 4290) | static int tkinter3Present(void)
function tkinter2Present (line 4311) | static int tkinter2Present(void)
function pythonDbusPresent (line 4332) | static int pythonDbusPresent(void)
function sigHandler (line 4365) | static void sigHandler(int signum)
function tinyfd_beep (line 4376) | void tinyfd_beep(void)
function tinyfd_messageBox (line 4446) | int tinyfd_messageBox(
function tinyfd_notifyPopup (line 5436) | int tinyfd_notifyPopup(
type termios (line 5676) | struct termios
type termios (line 5677) | struct termios
function tfd_messageBox (line 7912) | void tfd_messageBox(
function tfd_inputBox (line 7923) | void tfd_inputBox(
function tfd_saveFileDialog (line 7937) | void tfd_saveFileDialog(
function tfd_openFileDialog (line 7955) | void tfd_openFileDialog(
function tfd_selectFolderDialog (line 7975) | void tfd_selectFolderDialog(
function tfd_colorChooser (line 7986) | void tfd_colorChooser(
FILE: src/ast.c
function Block (line 56) | Block block_new(Blockdef* blockdef) {
function Block (line 129) | Block block_copy(Block* block, Block* parent) {
function block_free (line 172) | void block_free(Block* block) {
function block_update_all_links (line 199) | void block_update_all_links(Block* block) {
function block_update_parent_links (line 207) | void block_update_parent_links(Block* block) {
function BlockChain (line 214) | BlockChain blockchain_new(void) {
function BlockChain (line 225) | BlockChain blockchain_copy_single(BlockChain* chain, size_t pos) {
function BlockChain (line 256) | BlockChain blockchain_copy(BlockChain* chain, size_t pos) {
function blockchain_update_parent_links (line 296) | void blockchain_update_parent_links(BlockChain* chain) {
function blockchain_add_block (line 302) | void blockchain_add_block(BlockChain* chain, Block block) {
function blockchain_clear_blocks (line 307) | void blockchain_clear_blocks(BlockChain* chain) {
function blockchain_insert (line 314) | void blockchain_insert(BlockChain* dst, BlockChain* src, size_t pos) {
function blockchain_detach_single (line 325) | void blockchain_detach_single(BlockChain* dst, BlockChain* src, size_t p...
function blockchain_detach (line 356) | void blockchain_detach(BlockChain* dst, BlockChain* src, size_t pos) {
function blockchain_free (line 390) | void blockchain_free(BlockChain* chain) {
function argument_set_block (line 395) | void argument_set_block(Argument* block_arg, Block block) {
function argument_set_const_string (line 403) | void argument_set_const_string(Argument* block_arg, char* text) {
function argument_set_text (line 415) | void argument_set_text(Argument* block_arg, char* text) {
function argument_set_color (line 425) | void argument_set_color(Argument* block_arg, BlockdefColor color) {
function Blockdef (line 430) | Blockdef* blockdef_new(const char* id, BlockdefType type, BlockdefColor ...
function Blockdef (line 443) | Blockdef* blockdef_copy(Blockdef* blockdef) {
function blockdef_add_text (line 495) | void blockdef_add_text(Blockdef* blockdef, const char* text) {
function blockdef_add_argument (line 506) | void blockdef_add_argument(Blockdef* blockdef, char* defualt_data, const...
function blockdef_add_blockdef_editor (line 520) | void blockdef_add_blockdef_editor(Blockdef* blockdef) {
function blockdef_add_dropdown (line 526) | void blockdef_add_dropdown(Blockdef* blockdef, InputDropdownSource dropd...
function blockdef_add_color_input (line 537) | void blockdef_add_color_input(Blockdef* blockdef, BlockdefColor color) {
function blockdef_add_image (line 545) | void blockdef_add_image(Blockdef* blockdef, BlockdefImage image) {
function blockdef_set_id (line 553) | void blockdef_set_id(Blockdef* blockdef, const char* new_id) {
function blockdef_delete_input (line 558) | void blockdef_delete_input(Blockdef* blockdef, size_t input) {
function blockdef_free (line 575) | void blockdef_free(Blockdef* blockdef) {
FILE: src/ast.h
type BlockdefColor (line 27) | typedef struct BlockdefColor BlockdefColor;
type BlockdefImage (line 28) | typedef struct BlockdefImage BlockdefImage;
type ArgumentType (line 30) | typedef enum ArgumentType ArgumentType;
type ArgumentData (line 31) | typedef union ArgumentData ArgumentData;
type Argument (line 32) | typedef struct Argument Argument;
type Block (line 33) | typedef struct Block Block;
type InputArgumentConstraint (line 35) | typedef enum InputArgumentConstraint InputArgumentConstraint;
type InputDropdownSource (line 36) | typedef enum InputDropdownSource InputDropdownSource;
type InputArgument (line 37) | typedef struct InputArgument InputArgument;
type InputDropdown (line 38) | typedef struct InputDropdown InputDropdown;
type InputType (line 39) | typedef enum InputType InputType;
type InputData (line 40) | typedef union InputData InputData;
type Input (line 41) | typedef struct Input Input;
type BlockdefType (line 43) | typedef enum BlockdefType BlockdefType;
type Blockdef (line 44) | typedef struct Blockdef Blockdef;
type BlockChain (line 46) | typedef struct BlockChain BlockChain;
type DataType (line 50) | typedef enum {
type BlockdefColor (line 64) | struct BlockdefColor {
type BlockdefImage (line 68) | struct BlockdefImage {
type InputArgumentConstraint (line 73) | enum InputArgumentConstraint {
type InputArgument (line 78) | struct InputArgument {
type InputDropdownSource (line 85) | enum InputDropdownSource {
type InputDropdown (line 89) | struct InputDropdown {
type InputType (line 102) | enum InputType {
type Input (line 111) | struct Input {
type BlockdefType (line 116) | enum BlockdefType {
type Blockdef (line 124) | struct Blockdef {
type Block (line 133) | struct Block {
type ArgumentType (line 146) | enum ArgumentType {
type Argument (line 156) | struct Argument {
type BlockChain (line 162) | struct BlockChain {
FILE: src/blocks.c
type String (line 37) | typedef struct {
function block_do_nothing (line 67) | bool block_do_nothing(Exec* exec, Block* block, int argc, AnyValue* argv...
function block_noop (line 77) | bool block_noop(Exec* exec, Block* block, int argc, AnyValue* argv, AnyV...
function block_on_start (line 87) | bool block_on_start(Exec* exec, Block* block, int argc, AnyValue* argv, ...
function block_define_block (line 97) | bool block_define_block(Exec* exec, Block* block, int argc, AnyValue* ar...
function block_loop (line 107) | bool block_loop(Exec* exec, Block* block, int argc, AnyValue* argv, AnyV...
function block_if (line 123) | bool block_if(Exec* exec, Block* block, int argc, AnyValue* argv, AnyVal...
function block_else_if (line 146) | bool block_else_if(Exec* exec, Block* block, int argc, AnyValue* argv, A...
function block_else (line 170) | bool block_else(Exec* exec, Block* block, int argc, AnyValue* argv, AnyV...
function block_repeat (line 195) | bool block_repeat(Exec* exec, Block* block, int argc, AnyValue* argv, An...
function block_while (line 240) | bool block_while(Exec* exec, Block* block, int argc, AnyValue* argv, Any...
function block_sleep (line 269) | bool block_sleep(Exec* exec, Block* block, int argc, AnyValue* argv, Any...
function block_declare_var (line 293) | bool block_declare_var(Exec* exec, Block* block, int argc, AnyValue* arg...
function block_get_var (line 320) | bool block_get_var(Exec* exec, Block* block, int argc, AnyValue* argv, A...
function block_set_var (line 340) | bool block_set_var(Exec* exec, Block* block, int argc, AnyValue* argv, A...
function block_create_list (line 363) | bool block_create_list(Exec* exec, Block* block, int argc, AnyValue* arg...
function block_list_add (line 374) | bool block_list_add(Exec* exec, Block* block, int argc, AnyValue* argv, ...
function block_list_get (line 387) | bool block_list_get(Exec* exec, Block* block, int argc, AnyValue* argv, ...
function block_list_length (line 408) | bool block_list_length(Exec* exec, Block* block, int argc, AnyValue* arg...
function block_list_set (line 422) | bool block_list_set(Exec* exec, Block* block, int argc, AnyValue* argv, ...
function block_print (line 443) | bool block_print(Exec* exec, Block* block, int argc, AnyValue* argv, Any...
function block_println (line 486) | bool block_println(Exec* exec, Block* block, int argc, AnyValue* argv, A...
function block_cursor_x (line 493) | bool block_cursor_x(Exec* exec, Block* block, int argc, AnyValue* argv, ...
function block_cursor_y (line 508) | bool block_cursor_y(Exec* exec, Block* block, int argc, AnyValue* argv, ...
function block_cursor_max_x (line 524) | bool block_cursor_max_x(Exec* exec, Block* block, int argc, AnyValue* ar...
function block_cursor_max_y (line 539) | bool block_cursor_max_y(Exec* exec, Block* block, int argc, AnyValue* ar...
function block_set_cursor (line 554) | bool block_set_cursor(Exec* exec, Block* block, int argc, AnyValue* argv...
function block_set_fg_color (line 570) | bool block_set_fg_color(Exec* exec, Block* block, int argc, AnyValue* ar...
function block_set_bg_color (line 580) | bool block_set_bg_color(Exec* exec, Block* block, int argc, AnyValue* ar...
function block_reset_color (line 590) | bool block_reset_color(Exec* exec, Block* block, int argc, AnyValue* arg...
function block_term_clear (line 603) | bool block_term_clear(Exec* exec, Block* block, int argc, AnyValue* argv...
function block_term_set_clear (line 615) | bool block_term_set_clear(Exec* exec, Block* block, int argc, AnyValue* ...
function block_input (line 625) | bool block_input(Exec* exec, Block* block, int argc, AnyValue* argv, Any...
function block_get_char (line 634) | bool block_get_char(Exec* exec, Block* block, int argc, AnyValue* argv, ...
function block_random (line 644) | bool block_random(Exec* exec, Block* block, int argc, AnyValue* argv, An...
function block_join (line 662) | bool block_join(Exec* exec, Block* block, int argc, AnyValue* argv, AnyV...
function block_ord (line 671) | bool block_ord(Exec* exec, Block* block, int argc, AnyValue* argv, AnyVa...
function block_chr (line 684) | bool block_chr(Exec* exec, Block* block, int argc, AnyValue* argv, AnyVa...
function block_letter_in (line 692) | bool block_letter_in(Exec* exec, Block* block, int argc, AnyValue* argv,...
function block_substring (line 700) | bool block_substring(Exec* exec, Block* block, int argc, AnyValue* argv,...
function block_length (line 708) | bool block_length(Exec* exec, Block* block, int argc, AnyValue* argv, An...
function block_unix_time (line 716) | bool block_unix_time(Exec* exec, Block* block, int argc, AnyValue* argv,...
function block_convert_int (line 726) | bool block_convert_int(Exec* exec, Block* block, int argc, AnyValue* arg...
function block_convert_float (line 735) | bool block_convert_float(Exec* exec, Block* block, int argc, AnyValue* a...
function block_convert_str (line 744) | bool block_convert_str(Exec* exec, Block* block, int argc, AnyValue* arg...
function block_convert_bool (line 752) | bool block_convert_bool(Exec* exec, Block* block, int argc, AnyValue* ar...
function block_convert_color (line 761) | bool block_convert_color(Exec* exec, Block* block, int argc, AnyValue* a...
function block_typeof (line 770) | bool block_typeof(Exec* exec, Block* block, int argc, AnyValue* argv, An...
function block_plus (line 779) | bool block_plus(Exec* exec, Block* block, int argc, AnyValue* argv, AnyV...
function block_minus (line 792) | bool block_minus(Exec* exec, Block* block, int argc, AnyValue* argv, Any...
function block_mult (line 805) | bool block_mult(Exec* exec, Block* block, int argc, AnyValue* argv, AnyV...
function block_div (line 818) | bool block_div(Exec* exec, Block* block, int argc, AnyValue* argv, AnyVa...
function block_pow (line 837) | bool block_pow(Exec* exec, Block* block, int argc, AnyValue* argv, AnyVa...
function block_math (line 864) | bool block_math(Exec* exec, Block* block, int argc, AnyValue* argv, AnyV...
function block_pi (line 884) | bool block_pi(Exec* exec, Block* block, int argc, AnyValue* argv, AnyVal...
function block_bit_not (line 894) | bool block_bit_not(Exec* exec, Block* block, int argc, AnyValue* argv, A...
function block_bit_and (line 903) | bool block_bit_and(Exec* exec, Block* block, int argc, AnyValue* argv, A...
function block_bit_xor (line 912) | bool block_bit_xor(Exec* exec, Block* block, int argc, AnyValue* argv, A...
function block_bit_or (line 921) | bool block_bit_or(Exec* exec, Block* block, int argc, AnyValue* argv, An...
function block_rem (line 930) | bool block_rem(Exec* exec, Block* block, int argc, AnyValue* argv, AnyVa...
function block_less (line 943) | bool block_less(Exec* exec, Block* block, int argc, AnyValue* argv, AnyV...
function block_less_eq (line 957) | bool block_less_eq(Exec* exec, Block* block, int argc, AnyValue* argv, A...
function block_more (line 970) | bool block_more(Exec* exec, Block* block, int argc, AnyValue* argv, AnyV...
function block_more_eq (line 983) | bool block_more_eq(Exec* exec, Block* block, int argc, AnyValue* argv, A...
function block_not (line 996) | bool block_not(Exec* exec, Block* block, int argc, AnyValue* argv, AnyVa...
function block_and (line 1005) | bool block_and(Exec* exec, Block* block, int argc, AnyValue* argv, AnyVa...
function block_or (line 1014) | bool block_or(Exec* exec, Block* block, int argc, AnyValue* argv, AnyVal...
function block_true (line 1023) | bool block_true(Exec* exec, Block* block, int argc, AnyValue* argv, AnyV...
function block_false (line 1033) | bool block_false(Exec* exec, Block* block, int argc, AnyValue* argv, Any...
function block_eq (line 1043) | bool block_eq(Exec* exec, Block* block, int argc, AnyValue* argv, AnyVal...
function block_not_eq (line 1086) | bool block_not_eq(Exec* exec, Block* block, int argc, AnyValue* argv, An...
function block_exec_custom (line 1092) | bool block_exec_custom(Exec* exec, Block* block, int argc, AnyValue* arg...
function block_custom_arg (line 1110) | bool block_custom_arg(Exec* exec, Block* block, int argc, AnyValue* argv...
function block_return (line 1129) | bool block_return(Exec* exec, Block* block, int argc, AnyValue* argv, An...
function block_gc_collect (line 1139) | bool block_gc_collect(Exec* exec, Block* block, int argc, AnyValue* argv...
function LLVMValueRef (line 1157) | LLVMValueRef arg_to_value(Exec* exec, Block* block, FuncArg arg) {
function LLVMValueRef (line 1178) | LLVMValueRef arg_to_bool(Exec* exec, Block* block, FuncArg arg) {
function LLVMValueRef (line 1205) | LLVMValueRef arg_to_integer(Exec* exec, Block* block, FuncArg arg) {
function LLVMValueRef (line 1231) | LLVMValueRef arg_to_float(Exec* exec, Block* block, FuncArg arg) {
function LLVMValueRef (line 1258) | LLVMValueRef arg_to_any_string(Exec* exec, Block* block, FuncArg arg) {
function LLVMValueRef (line 1286) | LLVMValueRef arg_to_string_ref(Exec* exec, Block* block, FuncArg arg) {
function LLVMValueRef (line 1314) | LLVMValueRef arg_to_color(Exec* exec, Block* block, FuncArg arg) {
function LLVMValueRef (line 1341) | LLVMValueRef arg_to_list(Exec* exec, Block* block, FuncArg arg) {
function LLVMValueRef (line 1362) | LLVMValueRef arg_to_any(Exec* exec, Block* block, FuncArg arg) {
function FuncArg (line 1384) | FuncArg arg_cast(Exec* exec, Block* block, FuncArg arg, DataType cast_to...
function block_return (line 1412) | bool block_return(Exec* exec, Block* block, int argc, FuncArg* argv, Fun...
function block_custom_arg (line 1447) | bool block_custom_arg(Exec* exec, Block* block, int argc, FuncArg* argv,...
function block_exec_custom (line 1467) | bool block_exec_custom(Exec* exec, Block* block, int argc, FuncArg* argv...
function block_not_eq (line 1492) | bool block_not_eq(Exec* exec, Block* block, int argc, FuncArg* argv, Fun...
function block_eq (line 1556) | bool block_eq(Exec* exec, Block* block, int argc, FuncArg* argv, FuncArg...
function block_false (line 1616) | bool block_false(Exec* exec, Block* block, int argc, FuncArg* argv, Func...
function block_true (line 1626) | bool block_true(Exec* exec, Block* block, int argc, FuncArg* argv, FuncA...
function block_or (line 1636) | bool block_or(Exec* exec, Block* block, int argc, FuncArg* argv, FuncArg...
function block_and (line 1648) | bool block_and(Exec* exec, Block* block, int argc, FuncArg* argv, FuncAr...
function block_not (line 1660) | bool block_not(Exec* exec, Block* block, int argc, FuncArg* argv, FuncAr...
function block_more_eq (line 1670) | bool block_more_eq(Exec* exec, Block* block, int argc, FuncArg* argv, Fu...
function block_more (line 1688) | bool block_more(Exec* exec, Block* block, int argc, FuncArg* argv, FuncA...
function block_less_eq (line 1706) | bool block_less_eq(Exec* exec, Block* block, int argc, FuncArg* argv, Fu...
function block_less (line 1724) | bool block_less(Exec* exec, Block* block, int argc, FuncArg* argv, FuncA...
function block_bit_or (line 1742) | bool block_bit_or(Exec* exec, Block* block, int argc, FuncArg* argv, Fun...
function block_bit_xor (line 1754) | bool block_bit_xor(Exec* exec, Block* block, int argc, FuncArg* argv, Fu...
function block_bit_and (line 1766) | bool block_bit_and(Exec* exec, Block* block, int argc, FuncArg* argv, Fu...
function block_bit_not (line 1778) | bool block_bit_not(Exec* exec, Block* block, int argc, FuncArg* argv, Fu...
function block_pi (line 1790) | bool block_pi(Exec* exec, Block* block, int argc, FuncArg* argv, FuncArg...
function block_math (line 1800) | bool block_math(Exec* exec, Block* block, int argc, FuncArg* argv, FuncA...
function block_pow (line 1818) | bool block_pow(Exec* exec, Block* block, int argc, FuncArg* argv, FuncAr...
function block_rem (line 1839) | bool block_rem(Exec* exec, Block* block, int argc, FuncArg* argv, FuncAr...
function block_div (line 1892) | bool block_div(Exec* exec, Block* block, int argc, FuncArg* argv, FuncAr...
function block_mult (line 1945) | bool block_mult(Exec* exec, Block* block, int argc, FuncArg* argv, FuncA...
function block_minus (line 1963) | bool block_minus(Exec* exec, Block* block, int argc, FuncArg* argv, Func...
function block_plus (line 1981) | bool block_plus(Exec* exec, Block* block, int argc, FuncArg* argv, FuncA...
function block_typeof (line 2000) | bool block_typeof(Exec* exec, Block* block, int argc, FuncArg* argv, Fun...
function block_convert_color (line 2014) | bool block_convert_color(Exec* exec, Block* block, int argc, FuncArg* ar...
function block_convert_bool (line 2024) | bool block_convert_bool(Exec* exec, Block* block, int argc, FuncArg* arg...
function block_convert_str (line 2034) | bool block_convert_str(Exec* exec, Block* block, int argc, FuncArg* argv...
function block_convert_float (line 2044) | bool block_convert_float(Exec* exec, Block* block, int argc, FuncArg* ar...
function block_convert_int (line 2054) | bool block_convert_int(Exec* exec, Block* block, int argc, FuncArg* argv...
function block_unix_time (line 2064) | bool block_unix_time(Exec* exec, Block* block, int argc, FuncArg* argv, ...
function block_length (line 2073) | bool block_length(Exec* exec, Block* block, int argc, FuncArg* argv, Fun...
function block_substring (line 2084) | bool block_substring(Exec* exec, Block* block, int argc, FuncArg* argv, ...
function block_letter_in (line 2101) | bool block_letter_in(Exec* exec, Block* block, int argc, FuncArg* argv, ...
function block_chr (line 2115) | bool block_chr(Exec* exec, Block* block, int argc, FuncArg* argv, FuncAr...
function block_ord (line 2126) | bool block_ord(Exec* exec, Block* block, int argc, FuncArg* argv, FuncAr...
function block_join (line 2137) | bool block_join(Exec* exec, Block* block, int argc, FuncArg* argv, FuncA...
function block_random (line 2150) | bool block_random(Exec* exec, Block* block, int argc, FuncArg* argv, Fun...
function block_get_char (line 2166) | bool block_get_char(Exec* exec, Block* block, int argc, FuncArg* argv, F...
function block_input (line 2175) | bool block_input(Exec* exec, Block* block, int argc, FuncArg* argv, Func...
function block_term_set_clear (line 2184) | bool block_term_set_clear(Exec* exec, Block* block, int argc, FuncArg* a...
function block_term_clear (line 2197) | bool block_term_clear(Exec* exec, Block* block, int argc, FuncArg* argv,...
function block_reset_color (line 2207) | bool block_reset_color(Exec* exec, Block* block, int argc, FuncArg* argv...
function block_set_bg_color (line 2219) | bool block_set_bg_color(Exec* exec, Block* block, int argc, FuncArg* arg...
function block_set_fg_color (line 2232) | bool block_set_fg_color(Exec* exec, Block* block, int argc, FuncArg* arg...
function block_set_cursor (line 2245) | bool block_set_cursor(Exec* exec, Block* block, int argc, FuncArg* argv,...
function block_cursor_max_y (line 2259) | bool block_cursor_max_y(Exec* exec, Block* block, int argc, FuncArg* arg...
function block_cursor_max_x (line 2268) | bool block_cursor_max_x(Exec* exec, Block* block, int argc, FuncArg* arg...
function block_cursor_y (line 2277) | bool block_cursor_y(Exec* exec, Block* block, int argc, FuncArg* argv, F...
function block_cursor_x (line 2286) | bool block_cursor_x(Exec* exec, Block* block, int argc, FuncArg* argv, F...
function block_print (line 2295) | bool block_print(Exec* exec, Block* block, int argc, FuncArg* argv, Func...
function block_println (line 2340) | bool block_println(Exec* exec, Block* block, int argc, FuncArg* argv, Fu...
function block_list_length (line 2350) | bool block_list_length(Exec* exec, Block* block, int argc, FuncArg* argv...
function block_list_set (line 2361) | bool block_list_set(Exec* exec, Block* block, int argc, FuncArg* argv, F...
function block_list_get (line 2379) | bool block_list_get(Exec* exec, Block* block, int argc, FuncArg* argv, F...
function block_list_add (line 2393) | bool block_list_add(Exec* exec, Block* block, int argc, FuncArg* argv, F...
function block_create_list (line 2410) | bool block_create_list(Exec* exec, Block* block, int argc, FuncArg* argv...
function block_gc_collect (line 2419) | bool block_gc_collect(Exec* exec, Block* block, int argc, FuncArg* argv,...
function block_set_var (line 2429) | bool block_set_var(Exec* exec, Block* block, int argc, FuncArg* argv, Fu...
function block_get_var (line 2460) | bool block_get_var(Exec* exec, Block* block, int argc, FuncArg* argv, Fu...
function block_declare_var (line 2489) | bool block_declare_var(Exec* exec, Block* block, int argc, FuncArg* argv...
function block_sleep (line 2562) | bool block_sleep(Exec* exec, Block* block, int argc, FuncArg* argv, Func...
function block_while (line 2573) | bool block_while(Exec* exec, Block* block, int argc, FuncArg* argv, Func...
function block_repeat (line 2615) | bool block_repeat(Exec* exec, Block* block, int argc, FuncArg* argv, Fun...
function block_else (line 2681) | bool block_else(Exec* exec, Block* block, int argc, FuncArg* argv, FuncA...
function block_else_if (line 2719) | bool block_else_if(Exec* exec, Block* block, int argc, FuncArg* argv, Fu...
function block_if (line 2779) | bool block_if(Exec* exec, Block* block, int argc, FuncArg* argv, FuncArg...
function block_loop (line 2831) | bool block_loop(Exec* exec, Block* block, int argc, FuncArg* argv, FuncA...
function block_do_nothing (line 2868) | bool block_do_nothing(Exec* exec, Block* block, int argc, FuncArg* argv,...
function block_noop (line 2886) | bool block_noop(Exec* exec, Block* block, int argc, FuncArg* argv, FuncA...
function block_define_block (line 2896) | bool block_define_block(Exec* exec, Block* block, int argc, FuncArg* arg...
function block_on_start (line 2921) | bool block_on_start(Exec* exec, Block* block, int argc, FuncArg* argv, F...
function register_blocks (line 2936) | void register_blocks(Vm* vm) {
FILE: src/compiler.c
function Exec (line 52) | Exec exec_new(Thread* thread, CompilerMode mode) {
function exec_free (line 63) | void exec_free(Exec* exec) {
function exec_cleanup (line 67) | void exec_cleanup(void* e) {
function exec_run (line 92) | bool exec_run(void* e) {
function exec_handle_running_state (line 107) | static void exec_handle_running_state(Exec* exec) {
function exec_set_error (line 112) | void exec_set_error(Exec* exec, Block* block, const char* fmt, ...) {
function control_stack_push (line 121) | static bool control_stack_push(Exec* exec, Block* block) {
function Block (line 130) | static Block* control_stack_pop(Exec* exec) {
function global_variable_add (line 138) | void global_variable_add(Exec* exec, Variable variable) {
function variable_stack_push (line 142) | bool variable_stack_push(Exec* exec, Block* block, Variable variable) {
function Variable (line 151) | Variable* variable_get(Exec* exec, const char* var_name) {
function variable_stack_frame_push (line 161) | static bool variable_stack_frame_push(Exec* exec) {
function variable_stack_frame_pop (line 175) | static bool variable_stack_frame_pop(Exec* exec) {
function evaluate_block (line 188) | static bool evaluate_block(Exec* exec, Block* block, FuncArg* return_val...
function evaluate_chain (line 278) | static bool evaluate_chain(Exec* exec, BlockChain* chain) {
function DefineArgument (line 311) | DefineArgument* get_custom_argument(Exec* exec, Blockdef* blockdef, Defi...
function vector_add_str (line 323) | static void vector_add_str(char** vec, const char* str) {
function DefineFunction (line 327) | DefineFunction* define_function(Exec* exec, Blockdef* blockdef) {
function LLVMValueRef (line 388) | LLVMValueRef build_gc_root_begin(Exec* exec, Block* block) {
function LLVMValueRef (line 404) | LLVMValueRef build_gc_root_end(Exec* exec, Block* block) {
function LLVMValueRef (line 419) | static LLVMValueRef get_function(Exec* exec, const char* func_name) {
function LLVMValueRef (line 433) | static LLVMValueRef build_call_va(Exec* exec, const char* func_name, LLV...
function LLVMValueRef (line 457) | LLVMValueRef build_call_count(Exec* exec, const char* func_name, size_t ...
function LLVMValueRef (line 470) | LLVMValueRef build_call(Exec* exec, const char* func_name, ...) {
function add_function (line 485) | static void add_function(Exec* exec, const char* name, LLVMTypeRef retur...
function LLVMValueRef (line 493) | static LLVMValueRef register_globals(Exec* exec) {
function free_defined_functions (line 717) | static void free_defined_functions(Exec* exec) {
function compile_program (line 724) | static bool compile_program(Exec* exec) {
function vector_append (line 800) | static void vector_append(char** vec, const char* str) {
function file_exists (line 806) | static bool file_exists(char* path) {
function build_program (line 853) | static bool build_program(Exec* exec) {
function run_program (line 951) | static bool run_program(Exec* exec) {
FILE: src/compiler.h
type ControlState (line 53) | typedef enum {
type FuncArgData (line 59) | typedef union {
type FuncArg (line 65) | typedef struct {
type Variable (line 70) | typedef struct {
type VariableStackFrame (line 76) | typedef struct {
type CompileFunction (line 81) | typedef struct {
type DefineArgument (line 88) | typedef struct {
type DefineFunction (line 93) | typedef struct {
type CompilerState (line 99) | typedef enum {
type CompilerMode (line 106) | typedef enum {
type GcBlock (line 111) | typedef struct {
type Exec (line 116) | typedef struct {
FILE: src/gc.c
function Gc (line 70) | Gc gc_new(size_t memory_min, size_t memory_max) {
function gc_free (line 83) | void gc_free(Gc* gc) {
function gc_mark_any (line 100) | static void gc_mark_any(Gc* gc, AnyValue* any) {
function gc_mark_refs (line 115) | static void gc_mark_refs(Gc* gc, GcChunkData* chunk) {
function gc_collect (line 136) | void gc_collect(Gc* gc) {
function gc_root_begin (line 238) | void gc_root_begin(Gc* gc) {
function gc_root_end (line 249) | void gc_root_end(Gc* gc) {
function gc_add_root (line 256) | void gc_add_root(Gc* gc, void* stack_ptr) {
function gc_add_temp_root (line 260) | void gc_add_temp_root(Gc* gc, void* ptr) {
function gc_root_save (line 265) | void gc_root_save(Gc* gc) {
function gc_root_restore (line 274) | void gc_root_restore(Gc* gc) {
function gc_flush (line 294) | void gc_flush(Gc* gc) {
FILE: src/gc.h
type GcChunkData (line 32) | typedef struct {
type GcChunk (line 38) | typedef struct {
type GcRoot (line 43) | typedef struct {
type Gc (line 48) | typedef struct {
FILE: src/interpreter.c
function define_function (line 39) | void define_function(Exec* exec, Blockdef* blockdef, BlockChain* chain) {
function Exec (line 55) | Exec exec_new(Thread* thread) {
function exec_free (line 67) | void exec_free(Exec* exec) {
function exec_run (line 71) | bool exec_run(void* e) {
function exec_cleanup (line 114) | void exec_cleanup(void* e) {
function exec_set_error (line 125) | void exec_set_error(Exec* exec, Block* block, const char* fmt, ...) {
function evaluate_argument (line 134) | bool evaluate_argument(Exec* exec, Argument* arg, AnyValue* return_val) {
function exec_block (line 157) | bool exec_block(Exec* exec, Block* block, AnyValue* block_return, Contro...
function exec_run_chain (line 201) | bool exec_run_chain(Exec* exec, BlockChain* chain, int argc, AnyValue* a...
function exec_set_skip_block (line 290) | void exec_set_skip_block(Exec* exec) {
function Variable (line 294) | Variable* variable_stack_push_var(Exec* exec, const char* name, AnyValue...
function variable_stack_pop_layer (line 312) | void variable_stack_pop_layer(Exec* exec) {
function variable_stack_cleanup (line 322) | void variable_stack_cleanup(Exec* exec) {
function Variable (line 326) | Variable* variable_stack_get_variable(Exec* exec, const char* name) {
function chain_stack_push (line 340) | void chain_stack_push(Exec* exec, ChainStackData data) {
function chain_stack_pop (line 348) | void chain_stack_pop(Exec* exec) {
function arg_stack_push_arg (line 356) | void arg_stack_push_arg(Exec* exec, AnyValue arg) {
function arg_stack_undo_args (line 364) | void arg_stack_undo_args(Exec* exec, size_t count) {
FILE: src/interpreter.h
type Variable (line 34) | typedef struct Variable Variable;
type Exec (line 35) | typedef struct Exec Exec;
type ChainStackData (line 36) | typedef struct ChainStackData ChainStackData;
type ControlState (line 38) | typedef enum {
type Variable (line 46) | struct Variable {
type ChainStackData (line 61) | struct ChainStackData {
type DefineArgument (line 71) | typedef struct {
type DefineFunction (line 76) | typedef struct {
type Exec (line 82) | struct Exec {
FILE: src/platform.c
function scrap_set_env (line 36) | void scrap_set_env(const char* name, const char* value) {
function next_arg (line 50) | static size_t next_arg(char* cmd, size_t i, char** out_arg) {
function spawn_process (line 74) | bool spawn_process(char* command, char* error, size_t error_len) {
FILE: src/render.c
type BorderType (line 38) | typedef enum {
type RectType (line 47) | typedef enum {
type ImageType (line 53) | typedef enum {
function rl_vec_equal (line 63) | bool rl_vec_equal(Color lhs, Color rhs) {
function actionbar_show (line 67) | void actionbar_show(const char* text) {
function draw_dots (line 80) | static void draw_dots(void) {
function draw_term (line 103) | static void draw_term(int x, int y) {
function prerender_font_shadow (line 155) | void prerender_font_shadow(Font* font) {
function blockdef_on_hover (line 182) | static void blockdef_on_hover(GuiElement* el) {
function blockdef_input_on_hover (line 189) | static void blockdef_input_on_hover(GuiElement* el) {
function editor_del_button_on_hover (line 200) | static void editor_del_button_on_hover(GuiElement* el) {
function editor_button_on_hover (line 211) | static void editor_button_on_hover(GuiElement* el) {
function editor_color_on_hover (line 221) | static void editor_color_on_hover(GuiElement* el) {
function draw_editor_button (line 233) | static void draw_editor_button(Texture2D* texture, ButtonClickHandler ha...
function input_on_hover (line 243) | void input_on_hover(GuiElement* el) {
function input_selection_on_render (line 256) | void input_selection_on_render(GuiElement* el) {
function input_cursor_on_render (line 274) | void input_cursor_on_render(GuiElement* el) {
function draw_input_text (line 290) | void draw_input_text(Font* font, char** input, const char* hint, unsigne...
function argument_input_on_hover (line 325) | static void argument_input_on_hover(GuiElement* el) {
function draw_argument_input (line 334) | static void draw_argument_input(Argument* arg, char** input, const char*...
function draw_blockdef (line 365) | static void draw_blockdef(Blockdef* blockdef, bool editing) {
function block_on_hover (line 434) | static void block_on_hover(GuiElement* el) {
function argument_on_render (line 443) | static void argument_on_render(GuiElement* el) {
function block_on_render (line 447) | static void block_on_render(GuiElement* el) {
function block_argument_on_hover (line 452) | static void block_argument_on_hover(GuiElement* el) {
function argument_on_hover (line 459) | static void argument_on_hover(GuiElement* el) {
function draw_block (line 472) | static void draw_block(Block* block, bool highlight, bool can_hover, boo...
function tab_button_add_on_hover (line 764) | static void tab_button_add_on_hover(GuiElement* el) {
function tab_button_on_hover (line 775) | static void tab_button_on_hover(GuiElement* el) {
function button_on_hover (line 786) | static void button_on_hover(GuiElement* el) {
function panel_editor_button_on_hover (line 797) | static void panel_editor_button_on_hover(GuiElement* el) {
function draw_panel_editor_button (line 806) | static void draw_panel_editor_button(const char* text, int size, GuiColo...
function GuiElement (line 820) | static GuiElement* draw_button(const char* text, Texture2D* icon, int si...
function draw_top_bar (line 839) | static void draw_top_bar(void) {
function draw_tab_bar (line 861) | static void draw_tab_bar(void) {
function blockchain_on_hover (line 924) | static void blockchain_on_hover(GuiElement* el) {
function draw_block_preview (line 929) | static void draw_block_preview(void) {
function GuiElement (line 937) | static GuiElement* draw_blockchain(BlockChain* chain, bool ghost, bool s...
function category_on_hover (line 1064) | static void category_on_hover(GuiElement* el) {
function draw_category (line 1074) | static void draw_category(BlockCategory* category) {
function draw_block_categories (line 1105) | static void draw_block_categories(void) {
function draw_block_palette (line 1135) | static void draw_block_palette(void) {
function spectrum_on_hover (line 1178) | static void spectrum_on_hover(GuiElement* el) {
function spectrum_on_render (line 1183) | static void spectrum_on_render(GuiElement* el) {
function color_picker_on_hover (line 1191) | static void color_picker_on_hover(GuiElement* el) {
function color_picker_sv_on_hover (line 1196) | static void color_picker_sv_on_hover(GuiElement* el) {
function color_picker_sv_on_render (line 1201) | static void color_picker_sv_on_render(GuiElement* el) {
function draw_color_picker (line 1212) | static void draw_color_picker(void) {
function code_area_on_render (line 1293) | static void code_area_on_render(GuiElement* el) {
function draw_code_area (line 1297) | static void draw_code_area(void) {
function draw_split_preview (line 1384) | static void draw_split_preview(PanelTree* panel) {
function draw_term_panel (line 1435) | static void draw_term_panel(void) {
function panel_on_hover (line 1451) | static void panel_on_hover(GuiElement* el) {
function draw_panel (line 1478) | static void draw_panel(PanelTree* panel) {
function draw_code (line 1558) | static void draw_code(void) {
function list_dropdown_on_hover (line 1581) | static void list_dropdown_on_hover(GuiElement* el) {
function draw_list_dropdown (line 1593) | static void draw_list_dropdown(void) {
function dropdown_on_render (line 1627) | static void dropdown_on_render(GuiElement* el) {
function draw_dropdown (line 1637) | static void draw_dropdown(void) {
function search_on_hover (line 1667) | static void search_on_hover(GuiElement* el) {
function draw_search_list (line 1672) | static void draw_search_list(void) {
function panel_editor_on_hover (line 1718) | static void panel_editor_on_hover(GuiElement* el) {
function scrap_gui_process (line 1724) | void scrap_gui_process(void) {
function svg_load (line 1834) | bool svg_load(const char* file_name, size_t width, size_t height, Image*...
function render_border_control (line 1882) | static void render_border_control(GuiDrawCommand cmd) {
function render_border_control_body (line 1898) | static void render_border_control_body(GuiDrawCommand cmd) {
function render_border_control_end (line 1914) | static void render_border_control_end(GuiDrawCommand cmd) {
function render_border_end (line 1931) | static void render_border_end(GuiDrawCommand cmd) {
function render_border_notched (line 1949) | static void render_border_notched(GuiDrawCommand cmd) {
function render_rect_notched (line 1966) | static void render_rect_notched(GuiDrawCommand cmd) {
function draw_text_slice (line 1980) | static void draw_text_slice(Font font, const char *text, float pos_x, fl...
function scrap_gui_render (line 2004) | static void scrap_gui_render(void) {
function print_debug (line 2125) | static void print_debug(int* num, char* fmt, ...) {
function write_debug_buffer (line 2132) | static void write_debug_buffer(void) {
function scrap_gui_process_render (line 2164) | void scrap_gui_process_render(void) {
FILE: src/save.c
type SaveData (line 45) | typedef struct {
function Language (line 90) | Language code_to_language(const char* code) {
function reload_fonts (line 162) | void reload_fonts(void) {
function vector_set_string (line 193) | void vector_set_string(char** vec, char* str) {
function config_new (line 199) | void config_new(Config* config) {
function config_free (line 205) | void config_free(Config* config) {
function config_copy (line 211) | void config_copy(Config* dst, Config* src) {
function set_default_config (line 222) | void set_default_config(Config* config) {
function project_config_new (line 233) | void project_config_new(ProjectConfig* config) {
function project_config_free (line 238) | void project_config_free(ProjectConfig* config) {
function project_config_set_default (line 243) | void project_config_set_default(ProjectConfig* config) {
function apply_config (line 248) | void apply_config(Config* dst, Config* src) {
function save_panel_config (line 270) | void save_panel_config(char* file_str, int* cursor, PanelTree* panel) {
function PanelTree (line 315) | PanelTree* load_panel_config(char** config) {
function save_config (line 376) | void save_config(Config* config) {
function PanelTree (line 403) | PanelTree* find_panel_in_all_tabs(PanelType panel_type) {
function add_missing_panels (line 411) | void add_missing_panels(void) {
function load_config (line 423) | void load_config(Config* config) {
function save_read_varint (line 506) | bool save_read_varint(SaveData* save, unsigned int* out) {
function save_add_item (line 524) | void save_add_item(SaveData* save, const void* data, size_t data_size) {
function save_add_varint (line 534) | void save_add_varint(SaveData* save, unsigned int data) {
function save_add_array (line 544) | void save_add_array(SaveData* save, const void* array, int array_size, s...
function free_save (line 549) | void free_save(SaveData* save) {
function save_blockdef_input (line 555) | void save_blockdef_input(SaveData* save, Input* input) {
function save_blockdef (line 571) | void save_blockdef(SaveData* save, Blockdef* blockdef) {
function save_block_arguments (line 581) | void save_block_arguments(SaveData* save, Argument* arg) {
function save_block (line 611) | void save_block(SaveData* save, Block* block) {
function save_blockchain (line 623) | void save_blockchain(SaveData* save, BlockChain* chain) {
function rename_blockdef (line 632) | void rename_blockdef(Blockdef* blockdef, int id) {
function save_find_id (line 641) | int save_find_id(const char* id) {
function save_add_id (line 648) | void save_add_id(const char* id) {
function block_collect_ids (line 653) | void block_collect_ids(Block* block) {
function collect_all_code_ids (line 677) | void collect_all_code_ids(BlockChain* code) {
function save_code (line 686) | void save_code(const char* file_path, ProjectConfig* config, BlockChain*...
function Blockdef (line 729) | Blockdef* find_blockdef(Blockdef** blockdefs, const char* id) {
function load_blockdef_input (line 736) | bool load_blockdef_input(SaveData* save, Input* input) {
function Blockdef (line 778) | Blockdef* load_blockdef(SaveData* save) {
function load_block_argument (line 820) | bool load_block_argument(SaveData* save, Argument* arg) {
function load_block (line 874) | bool load_block(SaveData* save, Block* block) {
function load_blockchain (line 915) | bool load_blockchain(SaveData* save, BlockChain* chain) {
function BlockChain (line 952) | BlockChain* load_code(const char* file_path, ProjectConfig* out_config) {
FILE: src/scrap-runtime.c
function main (line 32) | int main(void) {
FILE: src/scrap.c
function Image (line 107) | Image setup(void) {
function cleanup (line 208) | void cleanup(void) {
function main (line 237) | int main(void) {
FILE: src/scrap.h
type Vm (line 33) | typedef struct Vm Vm;
type PanelTree (line 41) | typedef struct PanelTree PanelTree;
type BlockCategory (line 42) | typedef struct BlockCategory BlockCategory;
type Language (line 44) | typedef enum {
type Config (line 52) | typedef struct {
type ProjectConfig (line 63) | typedef struct {
type SplitSide (line 70) | typedef enum {
type SplitPreview (line 78) | typedef struct {
type PanelType (line 82) | typedef enum {
type PanelTree (line 91) | struct PanelTree {
type EditorHoverPart (line 100) | typedef enum {
type EditorHoverInfo (line 109) | typedef struct {
type DropdownType (line 133) | typedef enum {
type HSV (line 138) | typedef struct {
type ColorPickerPartType (line 142) | typedef enum {
type ListDropdown (line 148) | typedef struct {
type ColorPickerDropdown (line 156) | typedef struct {
type Dropdown (line 163) | typedef struct {
type DropdownData (line 176) | typedef struct {
type SliderHoverInfo (line 182) | typedef struct {
type InputHoverInfo (line 189) | typedef struct {
type BlockCategoryItemType (line 196) | typedef enum {
type BlockCategoryItem (line 201) | typedef struct {
type BlockCategory (line 212) | struct BlockCategory {
type PanelHoverInfo (line 221) | typedef struct {
type ButtonHoverInfo (line 235) | typedef struct {
type HoverInfo (line 240) | typedef struct {
type TextureList (line 266) | typedef struct {
type Fonts (line 292) | typedef struct {
type Assets (line 299) | typedef struct {
type Tab (line 306) | typedef struct {
type ActionBar (line 311) | typedef struct {
type BlockCode (line 316) | typedef struct {
type BlockPalette (line 321) | typedef struct {
type Editor (line 330) | typedef struct {
type UI (line 357) | typedef struct {
type Vm (line 379) | struct Vm {
FILE: src/scrap_gui.c
function inside_scissor (line 68) | static bool inside_scissor(GuiDrawBounds rect, GuiBounds scissor) {
function mouse_inside (line 73) | static bool mouse_inside(Gui* gui, GuiBounds rect) {
function Gui (line 78) | Gui gui_new(size_t arena_size) {
function gui_free (line 84) | void gui_free(Gui* gui) {
function gui_begin (line 88) | void gui_begin(Gui* gui) {
function gui_end (line 102) | void gui_end(Gui* gui) {
function gui_set_measure_text_func (line 108) | void gui_set_measure_text_func(Gui* gui, GuiMeasureTextSliceFunc measure...
function gui_set_measure_image_func (line 112) | void gui_set_measure_image_func(Gui* gui, GuiMeasureImageFunc measure_im...
function gui_update_mouse_pos (line 116) | void gui_update_mouse_pos(Gui* gui, short mouse_x, short mouse_y) {
function gui_update_mouse_scroll (line 121) | void gui_update_mouse_scroll(Gui* gui, int mouse_scroll) {
function gui_update_window_size (line 125) | void gui_update_window_size(Gui* gui, unsigned short win_w, unsigned sho...
function is_command_lesseq (line 130) | static bool is_command_lesseq(GuiDrawCommand* left, GuiDrawCommand* righ...
function merge (line 143) | static void merge(GuiDrawCommandList list, GuiDrawCommandList aux_list, ...
function split_and_merge_commands (line 156) | static void split_and_merge_commands(GuiDrawCommandList list, GuiDrawCom...
function sort_commands (line 165) | static void sort_commands(GuiDrawCommandList list, GuiDrawCommandList au...
function flush_command_batch (line 170) | static void flush_command_batch(Gui* gui) {
function new_draw_command (line 180) | static void new_draw_command(Gui* gui, GuiDrawBounds bounds, GuiDrawType...
function GuiBounds (line 195) | static GuiBounds scissor_rect(GuiBounds rect, GuiBounds scissor) {
function gui_get_anchor_pos (line 214) | static void gui_get_anchor_pos(GuiElement* el, float* anchor_x, float* a...
function gui_render (line 227) | static void gui_render(Gui* gui, GuiElement* el) {
function GuiElement (line 344) | static GuiElement* gui_element_new(Gui* gui) {
function GuiElement (line 355) | GuiElement* gui_element_begin(Gui* gui) {
function gui_element_offset (line 377) | static void gui_element_offset(GuiElement* el, int offset_x, int offset_...
function gui_element_realign (line 384) | static void gui_element_realign(GuiElement* el) {
function gui_element_resize (line 420) | static void gui_element_resize(Gui* gui, GuiElement* el, unsigned short ...
function gui_element_advance (line 493) | static void gui_element_advance(GuiElement* el, GuiMeasurement ms) {
function gui_element_end (line 507) | void gui_element_end(Gui* gui) {
function GuiElement (line 535) | GuiElement* gui_get_element(Gui* gui) {
function gui_on_hover (line 539) | void gui_on_hover(Gui* gui, GuiHandler handler) {
function gui_on_render (line 544) | void gui_on_render(Gui* gui, GuiHandler handler) {
function gui_set_anchor (line 549) | void gui_set_anchor(Gui* gui, GuiAlignmentType anchor_x, GuiAlignmentTyp...
function gui_set_parent_anchor (line 554) | void gui_set_parent_anchor(Gui* gui, GuiElement* anchor) {
function gui_set_shader (line 559) | void gui_set_shader(Gui* gui, void* shader) {
function gui_set_scroll_scaling (line 564) | void gui_set_scroll_scaling(Gui* gui, int scroll_scaling) {
function gui_set_scroll (line 569) | void gui_set_scroll(Gui* gui, int* scroll_value) {
function gui_set_scissor (line 574) | void gui_set_scissor(Gui* gui) {
function gui_scale_element (line 579) | void gui_scale_element(Gui* gui, float scaling) {
function gui_set_floating (line 599) | void gui_set_floating(Gui* gui) {
function gui_set_position (line 604) | void gui_set_position(Gui* gui, int x, int y) {
function gui_set_custom_data (line 610) | void gui_set_custom_data(Gui* gui, void* custom_data) {
function gui_set_fixed (line 615) | void gui_set_fixed(Gui* gui, unsigned short w, unsigned short h) {
function gui_set_fit (line 622) | void gui_set_fit(Gui* gui, GuiElementDirection direction) {
function gui_set_padding (line 631) | void gui_set_padding(Gui* gui, unsigned short pad_w, unsigned short pad_...
function gui_set_gap (line 641) | void gui_set_gap(Gui* gui, unsigned short gap) {
function gui_set_grow (line 646) | void gui_set_grow(Gui* gui, GuiElementDirection direction) {
function gui_set_percent_size (line 657) | void gui_set_percent_size(Gui* gui, float percentage, GuiElementDirectio...
function gui_set_draw_subtype (line 669) | void gui_set_draw_subtype(Gui* gui, unsigned char subtype) {
function gui_set_direction (line 674) | void gui_set_direction(Gui* gui, GuiElementDirection direction) {
function gui_set_rect (line 679) | void gui_set_rect(Gui* gui, GuiColor color) {
function gui_set_border (line 685) | void gui_set_border(Gui* gui, GuiColor color, unsigned int border_width) {
function gui_set_text_slice (line 692) | void gui_set_text_slice(Gui* gui, void* font, const char* text, unsigned...
function gui_set_text (line 705) | inline void gui_set_text(Gui* gui, void* font, const char* text, unsigne...
function gui_set_image (line 709) | void gui_set_image(Gui* gui, void* image, unsigned short size, GuiColor ...
function gui_set_align (line 719) | void gui_set_align(Gui* gui, GuiAlignmentType align_x, GuiAlignmentType ...
function gui_set_min_size (line 725) | void gui_set_min_size(Gui* gui, unsigned short min_w, unsigned short min...
function gui_text_slice (line 733) | inline void gui_text_slice(Gui* gui, void* font, const char* text, unsig...
function gui_text (line 740) | inline void gui_text(Gui* gui, void* font, const char* text, unsigned sh...
function gui_image (line 746) | inline void gui_image(Gui* gui, void* image, unsigned short size, GuiCol...
function gui_grow (line 752) | inline void gui_grow(Gui* gui, GuiElementDirection direction) {
function gui_spacer (line 758) | inline void gui_spacer(Gui* gui, unsigned short w, unsigned short h) {
function GuiMemArena (line 764) | GuiMemArena* gui_arena_new(size_t reserve_size, size_t commit_size) {
function gui_arena_free (line 782) | void gui_arena_free(GuiMemArena* arena) {
function gui_arena_pop (line 834) | void gui_arena_pop(GuiMemArena* arena, size_t size) {
function gui_arena_pop_to (line 839) | void gui_arena_pop_to(GuiMemArena* arena, size_t pos) {
function gui_arena_clear (line 844) | void gui_arena_clear(GuiMemArena* arena) {
function gui_plat_get_pagesize (line 852) | static unsigned long gui_plat_get_pagesize(void) {
function gui_plat_mem_commit (line 863) | static bool gui_plat_mem_commit(void* ptr, size_t size) {
function gui_plat_mem_release (line 868) | static bool gui_plat_mem_release(void* ptr, size_t size) {
function gui_plat_get_pagesize (line 877) | static unsigned long gui_plat_get_pagesize(void) {
function gui_plat_mem_commit (line 887) | static bool gui_plat_mem_commit(void* ptr, size_t size) {
function gui_plat_mem_release (line 891) | static bool gui_plat_mem_release(void* ptr, size_t size) {
FILE: src/scrap_gui.h
type Gui (line 29) | typedef struct Gui Gui;
type GuiElement (line 30) | typedef struct GuiElement GuiElement;
type GuiMeasurement (line 32) | typedef struct {
type GuiBounds (line 36) | typedef struct {
type GuiDrawBounds (line 41) | typedef struct {
type GuiColor (line 45) | typedef struct {
type GuiTextData (line 49) | typedef struct {
type GuiDrawType (line 55) | typedef enum {
type GuiDrawData (line 67) | typedef union {
type GuiDrawCommand (line 75) | typedef struct {
type GuiAlignmentType (line 84) | typedef enum {
type GuiElementSizing (line 92) | typedef enum {
type GuiElementDirection (line 99) | typedef enum {
type GuiElement (line 106) | struct GuiElement {
type GuiMeasurement (line 164) | typedef GuiMeasurement (*GuiMeasureTextSliceFunc)(void* font, const char...
type GuiMeasurement (line 165) | typedef GuiMeasurement (*GuiMeasureImageFunc)(void* image, unsigned shor...
type GuiMemArena (line 167) | typedef struct {
type GuiDrawCommandList (line 172) | typedef struct {
type GuiScissorStack (line 177) | typedef struct {
type Gui (line 182) | struct Gui {
FILE: src/std.c
function get_codepoint (line 48) | static int get_codepoint(const char *text, int *codepoint_size) {
function leading_ones (line 203) | static int leading_ones(unsigned char byte) {
function std_int_pow (line 212) | int std_int_pow(int base, int exp) {
function StdColor (line 224) | StdColor std_parse_color(const char* value) {
function List (line 231) | List* std_list_new(Gc* gc) {
function AnyValue (line 239) | static AnyValue std_get_any(DataType data_type, va_list va) {
function std_list_add (line 275) | void std_list_add(Gc* gc, List* list, DataType data_type, ...) {
function std_list_add_any (line 286) | void std_list_add_any(Gc* gc, List* list, AnyValue any) {
function std_list_set (line 302) | void std_list_set(List* list, int index, DataType data_type, ...) {
function AnyValue (line 315) | AnyValue* std_list_get(Gc* gc, List* list, int index) {
function std_list_length (line 325) | int std_list_length(List* list) {
function AnyValue (line 329) | AnyValue* std_any_from_value(Gc* gc, DataType data_type, ...) {
function StringHeader (line 346) | StringHeader* std_string_from_literal(Gc* gc, const char* literal, unsig...
function StringHeader (line 359) | StringHeader* std_string_letter_in(Gc* gc, int target, StringHeader* inp...
function StringHeader (line 376) | StringHeader* std_string_substring(Gc* gc, int begin, int end, StringHea...
function StringHeader (line 408) | StringHeader* std_string_join(Gc* gc, StringHeader* left, StringHeader* ...
function std_string_length (line 418) | int std_string_length(StringHeader* str) {
function std_string_is_eq (line 430) | bool std_string_is_eq(StringHeader* left, StringHeader* right) {
function StringHeader (line 438) | StringHeader* std_string_chr(Gc* gc, int value) {
function std_string_ord (line 444) | int std_string_ord(StringHeader* str) {
function StringHeader (line 451) | StringHeader* std_string_from_integer(Gc* gc, int value) {
function StringHeader (line 457) | StringHeader* std_string_from_bool(Gc* gc, bool value) {
function StringHeader (line 461) | StringHeader* std_string_from_float(Gc* gc, double value) {
function StringHeader (line 467) | StringHeader* std_string_from_color(Gc* gc, StdColor value) {
function StringHeader (line 478) | StringHeader* std_string_from_any(Gc* gc, AnyValue* value) {
function std_integer_from_any (line 505) | int std_integer_from_any(AnyValue* value) {
function std_float_from_any (line 525) | double std_float_from_any(AnyValue* value) {
function std_bool_from_any (line 545) | int std_bool_from_any(AnyValue* value) {
function StdColor (line 572) | StdColor std_color_from_any(AnyValue* value) {
function List (line 594) | List* std_list_from_any(Gc* gc, AnyValue* value) {
function std_any_is_eq (line 605) | bool std_any_is_eq(AnyValue* left, AnyValue* right) {
function std_sleep (line 629) | int std_sleep(int usecs) {
function std_set_random_seed (line 643) | void std_set_random_seed(int seed) {
function std_get_random (line 647) | int std_get_random(int min, int max) {
function std_term_print_any (line 655) | int std_term_print_any(AnyValue* any) {
function test_cancel (line 687) | void test_cancel(void) {}
function std_term_print_str (line 689) | int std_term_print_str(const char* str) {
function std_term_print_integer (line 695) | int std_term_print_integer(int value) {
function std_term_print_float (line 701) | int std_term_print_float(double value) {
function std_term_print_bool (line 707) | int std_term_print_bool(bool value) {
function std_term_print_color (line 713) | int std_term_print_color(StdColor value) {
function std_term_set_fg_color (line 719) | void std_term_set_fg_color(Color color) {
function std_term_set_bg_color (line 725) | void std_term_set_bg_color(Color color) {
function std_term_set_clear_color (line 732) | void std_term_set_clear_color(Color color) {
function std_term_cursor_max_y (line 736) | int std_term_cursor_max_y(void) {
function std_term_cursor_max_x (line 748) | int std_term_cursor_max_x(void) {
function std_term_cursor_x (line 760) | int std_term_cursor_x(void) {
function std_term_cursor_y (line 764) | int std_term_cursor_y(void) {
function std_term_clear (line 768) | void std_term_clear(void) {
function std_term_set_cursor (line 777) | void std_term_set_cursor(int x, int y) {
function StringHeader (line 784) | StringHeader* std_term_get_char(Gc* gc) {
function StringHeader (line 798) | StringHeader* std_term_get_input(Gc* gc) {
function std_term_print_list (line 822) | int std_term_print_list(List* list) {
function std_term_print_str (line 830) | int std_term_print_str(const char* str) {
function std_term_print_integer (line 834) | int std_term_print_integer(int value) {
function std_term_print_float (line 838) | int std_term_print_float(double value) {
function std_term_print_bool (line 842) | int std_term_print_bool(bool value) {
function std_term_print_color (line 846) | int std_term_print_color(StdColor value) {
function std_term_set_fg_color (line 850) | void std_term_set_fg_color(TermColor color) {
function std_term_set_bg_color (line 854) | void std_term_set_bg_color(TermColor color) {
function std_term_set_clear_color (line 858) | void std_term_set_clear_color(TermColor color) {
function std_term_clear (line 862) | void std_term_clear(void) {
function StringHeader (line 866) | StringHeader* std_term_get_char(Gc* gc) {
function std_term_set_cursor (line 878) | void std_term_set_cursor(int x, int y) {
function std_term_cursor_x (line 886) | int std_term_cursor_x(void) {
function std_term_cursor_y (line 894) | int std_term_cursor_y(void) {
function std_term_cursor_max_x (line 902) | int std_term_cursor_max_x(void) {
function std_term_cursor_max_y (line 909) | int std_term_cursor_max_y(void) {
function StringHeader (line 916) | StringHeader* std_term_get_input(Gc* gc) {
function std_term_print_list (line 936) | int std_term_print_list(List* list) {
FILE: src/std.h
type StringHeader (line 28) | typedef struct {
type StdColor (line 34) | typedef struct {
type AnyValue (line 38) | typedef struct AnyValue AnyValue;
type List (line 39) | typedef struct List List;
type AnyValueData (line 41) | typedef union {
type AnyValue (line 51) | struct AnyValue {
type List (line 56) | struct List {
type Color (line 118) | typedef struct {
FILE: src/term.c
function leading_ones (line 34) | int leading_ones(unsigned char byte) {
function term_init (line 43) | void term_init(MeasureTextSliceFunc measure_text, void* font, unsigned s...
function term_restart (line 56) | void term_restart(void) {
function term_free (line 67) | void term_free(void) {
function term_input_put_char (line 72) | void term_input_put_char(char ch) {
function term_input_get_char (line 80) | char term_input_get_char(void) {
function term_scroll_down (line 89) | void term_scroll_down(void) {
function term_set_fg_color (line 100) | void term_set_fg_color(TermColor color) {
function term_set_bg_color (line 106) | void term_set_bg_color(TermColor color) {
function term_set_clear_color (line 112) | void term_set_clear_color(TermColor color) {
function term_print_str (line 118) | int term_print_str(const char* str) {
function term_print_integer (line 167) | int term_print_integer(int value) {
function term_print_float (line 173) | int term_print_float(double value) {
function term_print_bool (line 179) | int term_print_bool(bool value) {
function term_print_color (line 183) | int term_print_color(TermColor value) {
function term_clear (line 189) | void term_clear(void) {
function term_resize (line 200) | void term_resize(float screen_w, float screen_h) {
FILE: src/term.h
type TermColor (line 31) | typedef struct {
type TerminalChar (line 35) | typedef struct {
type TermVec (line 41) | typedef struct {
type TermVec (line 45) | typedef TermVec (*MeasureTextSliceFunc)(void* font, const char* text, un...
type Terminal (line 47) | typedef struct {
FILE: src/thread.c
function Mutex (line 23) | Mutex mutex_new(void) {
function mutex_free (line 32) | void mutex_free(Mutex* mutex) {
function mutex_lock (line 36) | void mutex_lock(Mutex* mutex) {
function mutex_unlock (line 40) | void mutex_unlock(Mutex* mutex) {
function Thread (line 44) | Thread thread_new(ThreadEntry entry_func, ThreadCleanup cleanup_func) {
function thread_start (line 63) | bool thread_start(Thread* thread, void* data) {
function thread_is_running (line 76) | bool thread_is_running(Thread* thread) {
function thread_handle_stopping_state (line 80) | void thread_handle_stopping_state(Thread* thread) {
function thread_exit (line 87) | void thread_exit(Thread* thread, bool success) {
function thread_stop (line 96) | bool thread_stop(Thread* thread) {
function ThreadReturnCode (line 102) | ThreadReturnCode thread_join(Thread* thread) {
function ThreadReturnCode (line 119) | ThreadReturnCode thread_try_join(Thread* thread) {
FILE: src/thread.h
type ThreadState (line 27) | typedef enum {
type ThreadReturnCode (line 35) | typedef enum {
type Thread (line 46) | typedef struct {
type pthread_mutex_t (line 54) | typedef pthread_mutex_t Mutex;
FILE: src/ui.c
type FileMenuInds (line 34) | typedef enum {
function panel_split (line 47) | void panel_split(PanelTree* panel, SplitSide side, PanelType new_panel_t...
function PanelTree (line 98) | PanelTree* panel_new(PanelType type) {
function panel_delete (line 108) | void panel_delete(PanelTree* panel) {
function tab_delete (line 123) | void tab_delete(size_t tab) {
function delete_all_tabs (line 131) | void delete_all_tabs(void) {
function tab_new (line 136) | size_t tab_new(char* name, PanelTree* root_panel) {
function tab_insert (line 152) | void tab_insert(char* name, PanelTree* root_panel, size_t position) {
function init_panels (line 166) | void init_panels(void) {
function search_glyph (line 174) | int search_glyph(Font font, int codepoint) {
function GuiMeasurement (line 186) | static GuiMeasurement measure_slice(Font font, const char *text, unsigne...
function GuiMeasurement (line 213) | GuiMeasurement scrap_gui_measure_image(void* image, unsigned short size) {
function GuiMeasurement (line 218) | GuiMeasurement scrap_gui_measure_text(void* font, const char* text, unsi...
function TermVec (line 222) | TermVec term_measure_text(void* font, const char* text, unsigned int tex...
function sanitize_block (line 228) | static void sanitize_block(Block* block) {
function sanitize_links (line 240) | static void sanitize_links(void) {
function switch_tab_to_panel (line 257) | static void switch_tab_to_panel(PanelType panel) {
function set_mark (line 268) | static void set_mark(void) {
function copy_text (line 276) | static void copy_text(char* text, int start, int end) {
function delete_region (line 285) | static void delete_region(char** text) {
function edit_text (line 296) | static bool edit_text(char** text) {
function PanelTree (line 440) | PanelTree* find_panel(PanelTree* root, PanelType panel) {
function deselect_all (line 453) | static void deselect_all(void) {
function show_dropdown (line 459) | void show_dropdown(DropdownType type, void* ref_object, ButtonClickHandl...
function show_list_dropdown (line 466) | void show_list_dropdown(char** list, int list_len, void* ref_object, But...
function show_color_picker_dropdown (line 474) | void show_color_picker_dropdown(Color* edit_color, void* ref_object, But...
function handle_dropdown_close (line 489) | bool handle_dropdown_close(void) {
function save_project (line 511) | bool save_project(void) {
function load_project (line 526) | void load_project(void) {
function handle_file_menu_click (line 563) | bool handle_file_menu_click(void) {
function handle_block_dropdown_click (line 586) | bool handle_block_dropdown_click(void) {
function handle_color_picker_click (line 592) | bool handle_color_picker_click(void) {
function handle_file_button_click (line 597) | bool handle_file_button_click(void) {
function handle_settings_button_click (line 603) | bool handle_settings_button_click(void) {
function handle_about_button_click (line 608) | bool handle_about_button_click(void) {
function handle_run_button_click (line 613) | bool handle_run_button_click(void) {
function handle_build_button_click (line 622) | bool handle_build_button_click(void) {
function handle_stop_button_click (line 628) | bool handle_stop_button_click(void) {
function handle_category_click (line 633) | bool handle_category_click(void) {
function handle_jump_to_block_button_click (line 638) | bool handle_jump_to_block_button_click(void) {
function handle_error_window_close_button_click (line 644) | bool handle_error_window_close_button_click(void) {
function handle_tab_button (line 649) | bool handle_tab_button(void) {
function handle_add_tab_button (line 655) | bool handle_add_tab_button(void) {
function handle_panel_editor_save_button (line 686) | bool handle_panel_editor_save_button(void) {
function handle_panel_editor_cancel_button (line 692) | bool handle_panel_editor_cancel_button(void) {
function handle_editor_add_arg_button (line 697) | bool handle_editor_add_arg_button(void) {
function handle_editor_add_text_button (line 726) | bool handle_editor_add_text_button(void) {
function handle_editor_del_arg_button (line 751) | bool handle_editor_del_arg_button(void) {
function handle_editor_edit_button (line 773) | bool handle_editor_edit_button(void) {
function handle_editor_close_button (line 780) | bool handle_editor_close_button(void) {
function handle_editor_color_button (line 787) | bool handle_editor_color_button(void) {
function remove_blockdef (line 794) | static void remove_blockdef(BlockChain* chain) {
function handle_block_palette_click (line 809) | static bool handle_block_palette_click(bool mouse_empty) {
function handle_blockdef_editor_click (line 840) | static bool handle_blockdef_editor_click(void) {
function code_put_blocks (line 853) | static void code_put_blocks(bool single) {
function code_attach_to_argument (line 881) | static void code_attach_to_argument(void) {
function code_copy_argument (line 904) | static void code_copy_argument(void) {
function code_swap_argument (line 911) | static void code_swap_argument(void) {
function code_detach_argument (line 934) | static void code_detach_argument(void) {
function code_copy_blocks (line 957) | static void code_copy_blocks(bool single) {
function code_detach_blocks (line 971) | static void code_detach_blocks(bool single) {
function code_attach_block (line 998) | static void code_attach_block(void) {
function handle_code_editor_click (line 1016) | static bool handle_code_editor_click(bool mouse_empty) {
function handle_editor_panel_click (line 1088) | static bool handle_editor_panel_click(void) {
function get_input_ind (line 1129) | static void get_input_ind(void) {
function handle_mouse_click (line 1171) | static bool handle_mouse_click(void) {
function block_next_argument (line 1262) | static void block_next_argument() {
function block_prev_argument (line 1287) | static void block_prev_argument() {
function handle_code_panel_key_press (line 1325) | static bool handle_code_panel_key_press(void) {
function search_string (line 1413) | static bool search_string(const char* str, const char* substr) {
function search_blockdef (line 1435) | static bool search_blockdef(Blockdef* blockdef) {
function update_search (line 1444) | void update_search(void) {
function handle_key_press (line 1454) | static void handle_key_press(void) {
function handle_mouse_wheel (line 1531) | static void handle_mouse_wheel(void) {
function handle_mouse_drag (line 1551) | static void handle_mouse_drag(void) {
function scrap_gui_process_ui (line 1584) | void scrap_gui_process_ui(void) {
FILE: src/util.c
function Timer (line 28) | Timer start_timer(const char* name) {
function end_timer (line 35) | double end_timer(Timer timer) {
function scrap_log (line 48) | void scrap_log(int log_level, const char *text, ...) {
function scrap_log_va (line 55) | void scrap_log_va(int log_level, const char *text, va_list args) {
FILE: src/util.h
type Timer (line 49) | typedef struct {
FILE: src/vec.c
function vector_header (line 37) | vector_header* vector_get_header(vector vec) { return &((vector_header*)...
function vector (line 39) | vector vector_create(void)
function vector_free (line 48) | void vector_free(vector vec) { free(vector_get_header(vec)); }
function vec_size_t (line 50) | vec_size_t vector_size(vector vec) { return vector_get_header(vec)->size; }
function vec_size_t (line 52) | vec_size_t vector_capacity(vector vec) { return vector_get_header(vec)->...
function vector_header (line 54) | vector_header* vector_realloc(vector_header* h, vec_type_t type_size)
function vector_has_space (line 63) | bool vector_has_space(vector_header* h)
function _vector_erase (line 103) | void _vector_erase(vector vec, vec_type_t type_size, vec_size_t pos, vec...
function _vector_remove (line 113) | void _vector_remove(vector vec, vec_type_t type_size, vec_size_t pos)
function vector_pop (line 118) | void vector_pop(vector vec) { --vector_get_header(vec)->size; }
function vector_clear (line 120) | void vector_clear(vector vec) { vector_get_header(vec)->size = 0; }
function _vector_reserve (line 122) | void _vector_reserve(vector* vec_addr, vec_type_t type_size, vec_size_t ...
function vector (line 135) | vector _vector_copy(vector vec, vec_type_t type_size)
FILE: src/vec.h
type vec_size_t (line 50) | typedef size_t vec_size_t;
type vec_type_t (line 52) | typedef size_t vec_type_t;
type vector_header (line 54) | typedef struct
FILE: src/vm.c
function BlockChain (line 27) | static BlockChain* find_blockchain(Block* block) {
function Block (line 38) | Block block_new_ms(Blockdef* blockdef) {
function blockdef_register (line 47) | size_t blockdef_register(Vm* vm, Blockdef* blockdef) {
function blockdef_unregister (line 59) | void blockdef_unregister(Vm* vm, size_t block_id) {
function BlockCategory (line 64) | BlockCategory block_category_new(const char* name, Color color) {
function BlockCategory (line 74) | BlockCategory* block_category_register(BlockCategory category) {
function block_category_unregister (line 90) | void block_category_unregister(BlockCategory* category) {
function block_category_add_blockdef (line 111) | void block_category_add_blockdef(BlockCategory* category, Blockdef* bloc...
function block_category_add_label (line 122) | void block_category_add_label(BlockCategory* category, const char* label...
function unregister_categories (line 129) | void unregister_categories(void) {
function clear_compile_error (line 141) | void clear_compile_error(void) {
function Vm (line 148) | Vm vm_new(void) {
function vm_free (line 166) | void vm_free(Vm* vm) {
function vm_start (line 182) | bool vm_start(CompilerMode mode) {
function vm_stop (line 208) | bool vm_stop(void) {
function vm_handle_running_thread (line 216) | void vm_handle_running_thread(void) {
FILE: src/window.c
type WindowGui (line 32) | typedef struct {
function ease_out_expo (line 50) | float ease_out_expo(float x) {
function about_on_license_button_click (line 54) | static bool about_on_license_button_click(void) {
function window_on_close_button_click (line 59) | static bool window_on_close_button_click(void) {
function vector_append (line 64) | static void vector_append(char** vec, const char* str) {
function settings_on_browse_button_click (line 70) | static bool settings_on_browse_button_click(void) {
function settings_on_left_slider_button_click (line 86) | static bool settings_on_left_slider_button_click(void) {
function settings_on_right_slider_button_click (line 92) | static bool settings_on_right_slider_button_click(void) {
function settings_on_dropdown_button_click (line 98) | static bool settings_on_dropdown_button_click(void) {
function settings_on_dropdown_click (line 104) | static bool settings_on_dropdown_click(void) {
function settings_on_panel_editor_button_click (line 109) | static bool settings_on_panel_editor_button_click(void) {
function settings_on_reset_button_click (line 119) | static bool settings_on_reset_button_click(void) {
function settings_on_reset_panels_button_click (line 125) | static bool settings_on_reset_panels_button_click(void) {
function settings_on_apply_button_click (line 133) | static bool settings_on_apply_button_click(void) {
function settings_on_toggle_button_click (line 140) | static bool settings_on_toggle_button_click(void) {
function project_settings_on_build_button_click (line 146) | static bool project_settings_on_build_button_click(void) {
function save_confirmation_on_yes_button_click (line 156) | static bool save_confirmation_on_yes_button_click(void) {
function save_confirmation_on_no_button_click (line 165) | static bool save_confirmation_on_no_button_click(void) {
function save_confirmation_on_cancel_button_click (line 170) | static bool save_confirmation_on_cancel_button_click(void) {
function init_gui_window (line 175) | void init_gui_window(void) {
function gui_window_is_shown (line 179) | bool gui_window_is_shown(void) {
function WindowGuiRenderFunc (line 183) | WindowGuiRenderFunc gui_window_get_render_func(void) {
function gui_window_show (line 187) | void gui_window_show(WindowGuiRenderFunc func) {
function gui_window_hide (line 196) | void gui_window_hide(void) {
function gui_window_hide_immediate (line 201) | void gui_window_hide_immediate(void) {
function settings_button_on_hover (line 206) | static void settings_button_on_hover(GuiElement* el) {
function close_button_on_hover (line 212) | static void close_button_on_hover(GuiElement* el) {
function window_on_hover (line 221) | static void window_on_hover(GuiElement* el) {
function begin_window (line 226) | static void begin_window(const char* title, Texture2D* icon, int w, int ...
function end_window (line 269) | static void end_window(void) {
function warning_on_hover (line 296) | static void warning_on_hover(GuiElement* el) {
function begin_setting (line 302) | static void begin_setting(const char* name, bool warning) {
function slider_on_hover (line 334) | static void slider_on_hover(GuiElement* el) {
function slider_button_on_hover (line 345) | static void slider_button_on_hover(GuiElement* el) {
function draw_slider (line 353) | static void draw_slider(int min, int max, int* value) {
function end_setting (line 409) | static void end_setting(void) {
function text_input_on_hover (line 414) | static void text_input_on_hover(GuiElement* el) {
function dropdown_input_on_hover (line 419) | static void dropdown_input_on_hover(GuiElement* el) {
function draw_dropdown_input (line 426) | static void draw_dropdown_input(int* value, char** list, int list_len) {
function draw_text_input (line 466) | static void draw_text_input(char** input, const char* hint, int* scroll,...
function draw_button (line 508) | static void draw_button(const char* label, Texture2D* icon, ButtonClickH...
function toggle_on_hover (line 537) | static void toggle_on_hover(GuiElement* el) {
function draw_toggle (line 543) | static void draw_toggle(bool* value) {
function handle_window (line 563) | void handle_window(void) {
function draw_settings_window (line 595) | void draw_settings_window(void) {
function draw_project_settings_window (line 694) | void draw_project_settings_window(void) {
function draw_about_window (line 721) | void draw_about_window(void) {
function draw_save_confirmation_window (line 774) | void draw_save_confirmation_window(void) {
function draw_window (line 794) | void draw_window(void) {
Condensed preview — 67 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,160K chars).
[
{
"path": ".github/generate_notes.py",
"chars": 352,
"preview": "import re\n\nwith open('CHANGELOG.md') as f:\n changelog = f.read()\n\nstart = re.search('## ', changelog).start()\nend ="
},
{
"path": ".github/workflows/build.yml",
"chars": 2465,
"preview": "name: Build\n\non:\n push:\n branches:\n - \"main\"\n - \"dev_**\"\n paths-ignore:\n - \"README.md\"\n - \"LI"
},
{
"path": ".github/workflows/release.yml",
"chars": 7532,
"preview": "name: Release\n\non:\n push:\n tags:\n - 'v*.*-*'\n\npermissions:\n contents: write\n\nenv:\n SCRAP_VERSION: ${{ github."
},
{
"path": ".gitignore",
"chars": 144,
"preview": "tags\n*.o\nscrap\nscrap.exe\nprofile.json\ncoredump\nconfig.txt\nscrap.res\nprivate/\nlocale/\nscrap.AppDir/\nbuild/\na.out\nlibscrap"
},
{
"path": ".gitmodules",
"chars": 81,
"preview": "[submodule \"raylib\"]\n\tpath = raylib\n\turl = https://github.com/raysan5/raylib.git\n"
},
{
"path": "CHANGELOG.md",
"chars": 7094,
"preview": "# v0.6.1-beta *(27-02-2026)*\n\n## What's new?\n- Re-added block folding feature. Now if the last argument size was more th"
},
{
"path": "LICENSE",
"chars": 868,
"preview": "zlib License\n\nCopyright (C) 2024-2026 Grisshink\n\nThis software is provided 'as-is', without any express or implied\nwarra"
},
{
"path": "Makefile",
"chars": 6313,
"preview": "SCRAP_VERSION ?= dev\n\nMAKE ?= make\nTARGET ?= LINUX\nBUILD_MODE ?= RELEASE\nUSE_COMPILER ?= FALSE\nBUILD_FOLDER := build/\nPR"
},
{
"path": "README.md",
"chars": 6675,
"preview": "\n\n# Scrap\n\n || defined(__MINGW32__)\n #include <direct.h>\n #define mkdir _mkdir\n#en"
},
{
"path": "external/cfgpath.h",
"chars": 6509,
"preview": "/**\n * @file cfgpath.h\n * @brief Cross platform methods for obtaining paths to configuration files.\n *\n * Copyright (C)"
},
{
"path": "external/nanosvg.h",
"chars": 84904,
"preview": "/*\n * Copyright (c) 2013-14 Mikko Mononen memon@inside.org\n *\n * This software is provided 'as-is', without any express "
},
{
"path": "external/nanosvgrast.h",
"chars": 39398,
"preview": "/*\n * Copyright (c) 2013-14 Mikko Mononen memon@inside.org\n *\n * This software is provided 'as-is', without any express "
},
{
"path": "external/rprand.h",
"chars": 11693,
"preview": "/**********************************************************************************************\n*\n* rprand v1.0 - A si"
},
{
"path": "external/tinyfiledialogs.c",
"chars": 243635,
"preview": "/* SPDX-License-Identifier: Zlib\nCopyright (c) 2014 - 2024 Guillaume Vareille http://ysengrin.com\n\t ____________________"
},
{
"path": "external/tinyfiledialogs.h",
"chars": 16284,
"preview": "/* SPDX-License-Identifier: Zlib\nCopyright (c) 2014 - 2024 Guillaume Vareille http://ysengrin.com\n\t ____________________"
},
{
"path": "scrap.desktop",
"chars": 91,
"preview": "[Desktop Entry]\nName=Scrap\nExec=AppRun\nIcon=scrap\nType=Application\nCategories=Development;\n"
},
{
"path": "scrap.rc",
"chars": 34,
"preview": "scrap_icon ICON \"extras/icon.ico\"\n"
},
{
"path": "src/ast.c",
"chars": 19565,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/ast.h",
"chars": 5886,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/blocks.c",
"chars": 139790,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/compiler.c",
"chars": 44209,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/compiler.h",
"chars": 6246,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/config.h",
"chars": 2865,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/gc.c",
"chars": 9437,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/gc.h",
"chars": 2263,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/interpreter.c",
"chars": 13271,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/interpreter.h",
"chars": 5353,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/platform.c",
"chars": 7807,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/render.c",
"chars": 89882,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/save.c",
"chars": 34722,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/scrap-runtime.c",
"chars": 1308,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/scrap.c",
"chars": 10577,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/scrap.h",
"chars": 13535,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/scrap_gui.c",
"chars": 30588,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/scrap_gui.h",
"chars": 9362,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/std.c",
"chars": 27345,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/std.h",
"chars": 4483,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/term.c",
"chars": 7690,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/term.h",
"chars": 2557,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/thread.c",
"chars": 3924,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/thread.h",
"chars": 2320,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/ui.c",
"chars": 61862,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/util.c",
"chars": 2390,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/util.h",
"chars": 2035,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/vec.c",
"chars": 4324,
"preview": "/*\nBSD 3-Clause License\n\nCopyright (c) 2024, Mashpoe\nAll rights reserved.\n\nRedistribution and use in source and binary f"
},
{
"path": "src/vec.h",
"chars": 4264,
"preview": "/*\nBSD 3-Clause License\n\nCopyright (c) 2024, Mashpoe\nAll rights reserved.\n\nRedistribution and use in source and binary f"
},
{
"path": "src/vm.c",
"chars": 9063,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "src/window.c",
"chars": 29669,
"preview": "// Scrap is a project that allows anyone to build software using simple, block based interface.\n//\n// Copyright (C) 2024"
},
{
"path": "translations/kk/LC_MESSAGES/scrap.po",
"chars": 6049,
"preview": "msgid \"\"\nmsgstr \"\"\n\"Language: kz\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\n#: blocks.c\nmsgid \"Hello, scrap!\"\nmsgst"
},
{
"path": "translations/ru/LC_MESSAGES/scrap.po",
"chars": 12899,
"preview": "msgid \"\"\nmsgstr \"\"\n\"Language: ru\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\n#: blocks.c\nmsgid \"Hello, scrap!\"\nmsgst"
},
{
"path": "translations/uk/LC_MESSAGES/scrap.po",
"chars": 6507,
"preview": "msgid \"\"\nmsgstr \"\"\n\"Language: uk\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\n#: blocks.c\nmsgid \"Hello, scrap!\"\nmsgst"
}
]
// ... and 14 more files (download for full content)
About this extraction
This page contains the full source code of the Grisshink/scrap GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 67 files (1.0 MB), approximately 305.3k tokens, and a symbol index with 1132 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.