├── debian ├── copyright ├── compat ├── kovel.manpages ├── kovel-cli.install ├── dirs ├── kovel.install ├── changelog ├── rules ├── kovel.sharedmimeinfo ├── postinst ├── control └── Kovel.1 ├── exporter └── .gitkeep ├── resources ├── kovel.rc ├── kovel.ico ├── kovel.png ├── favicon.ico ├── kovel.desktop ├── application-x-kovel-voxel.xml ├── kovel.hvif ├── kovel.rdef ├── kovel.svg └── kovel.xpm ├── test ├── Cube.kvl ├── test_json.sh └── test_dae.sh ├── samples ├── 3x3.kvl ├── Algo.kvl ├── Casa.kvl ├── Cube.kvl ├── Europa.kvl ├── KOVEL.kvl ├── KOVEL2.kvl ├── Sample.kvl ├── Single.kvl ├── Spain.kvl ├── Test.kvl ├── CubeCopy.kvl └── Cuadrancia.kvl ├── docs ├── Kovel-1.png ├── KovelIcon.png ├── KovelHaiku.png ├── KovelRotate.png ├── BlenderKovel.png ├── AppOrganization.md └── FileFormat.md ├── .gitmodules ├── .gitignore ├── docker-compose.yml ├── .clang-tidy ├── ui ├── wx │ ├── window.hpp │ ├── metadata.hpp │ ├── app.cpp │ ├── preview.hpp │ ├── metadata.cpp │ ├── preview.cpp │ └── window.cpp ├── haiku │ ├── window.hpp │ ├── metadata.hpp │ ├── preview.hpp │ ├── app.cpp │ ├── preview.cpp │ ├── metadata.cpp │ └── window.cpp └── gl │ ├── gl1.hpp │ └── gl1.cpp ├── Dockerfile ├── upload_ppa.sh ├── core ├── version.hpp ├── core.hpp └── core.cpp ├── format-tidy.sh ├── appveyor.yml ├── .travis.yml ├── CMakeLists.txt ├── .clang-format ├── cli └── cli.cpp ├── README.md └── LICENSE /debian/copyright: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /exporter/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /resources/kovel.rc: -------------------------------------------------------------------------------- 1 | id ICON "kovel.ico" -------------------------------------------------------------------------------- /debian/kovel.manpages: -------------------------------------------------------------------------------- 1 | debian/Kovel.1 2 | -------------------------------------------------------------------------------- /debian/kovel-cli.install: -------------------------------------------------------------------------------- 1 | build/kovelcli usr/bin 2 | -------------------------------------------------------------------------------- /debian/dirs: -------------------------------------------------------------------------------- 1 | usr/bin 2 | usr/share/applications 3 | usr/share/pixmaps 4 | -------------------------------------------------------------------------------- /test/Cube.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/test/Cube.kvl -------------------------------------------------------------------------------- /samples/3x3.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/3x3.kvl -------------------------------------------------------------------------------- /docs/Kovel-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/docs/Kovel-1.png -------------------------------------------------------------------------------- /docs/KovelIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/docs/KovelIcon.png -------------------------------------------------------------------------------- /samples/Algo.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/Algo.kvl -------------------------------------------------------------------------------- /samples/Casa.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/Casa.kvl -------------------------------------------------------------------------------- /samples/Cube.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/Cube.kvl -------------------------------------------------------------------------------- /samples/Europa.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/Europa.kvl -------------------------------------------------------------------------------- /samples/KOVEL.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/KOVEL.kvl -------------------------------------------------------------------------------- /samples/KOVEL2.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/KOVEL2.kvl -------------------------------------------------------------------------------- /samples/Sample.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/Sample.kvl -------------------------------------------------------------------------------- /samples/Single.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/Single.kvl -------------------------------------------------------------------------------- /samples/Spain.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/Spain.kvl -------------------------------------------------------------------------------- /samples/Test.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/Test.kvl -------------------------------------------------------------------------------- /docs/KovelHaiku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/docs/KovelHaiku.png -------------------------------------------------------------------------------- /docs/KovelRotate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/docs/KovelRotate.png -------------------------------------------------------------------------------- /resources/kovel.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/resources/kovel.ico -------------------------------------------------------------------------------- /resources/kovel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/resources/kovel.png -------------------------------------------------------------------------------- /samples/CubeCopy.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/CubeCopy.kvl -------------------------------------------------------------------------------- /docs/BlenderKovel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/docs/BlenderKovel.png -------------------------------------------------------------------------------- /resources/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/resources/favicon.ico -------------------------------------------------------------------------------- /samples/Cuadrancia.kvl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarroyoc/kovel/master/samples/Cuadrancia.kvl -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libbson"] 2 | path = libbson 3 | url = git://github.com/mongodb/libbson 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeCache.txt 2 | CMakeFiles 3 | Makefile 4 | cmake_install.cmake 5 | install_manifest.txt 6 | build 7 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.6" 2 | 3 | services: 4 | builder: 5 | build: . 6 | volumes: 7 | - ./:/opt/kovel -------------------------------------------------------------------------------- /test/test_json.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ../build/kovelcli -i Cube.kvl -x json -o Cube.json 3 | cat Cube.json | python -m json.tool 4 | -------------------------------------------------------------------------------- /debian/kovel.install: -------------------------------------------------------------------------------- 1 | build/Kovel usr/bin 2 | resources/kovel.desktop usr/share/applications 3 | resources/kovel.svg usr/share/pixmaps 4 | -------------------------------------------------------------------------------- /test/test_dae.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # xmllint comes in 'libxml2-utils' 4 | ../build/kovelcli -i Cube.kvl -x dae -o Cube.dae 5 | xmllint Cube.dae 6 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | kovel (1.0.0.5) xenial; urgency=low 2 | 3 | * First Release 4 | 5 | -- Adrian Arroyo Calle Sat, 14 Nov 2015 12:00:00 +1200 6 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | --- 2 | Checks: 'readability-braces-around-statements,misc-macro-parentheses' 3 | HeaderFilterRegex: '' 4 | AnalyzeTemporaryDtors: false 5 | User: adrian 6 | ... 7 | 8 | -------------------------------------------------------------------------------- /ui/wx/window.hpp: -------------------------------------------------------------------------------- 1 | #ifndef WINDOW_HPP 2 | #define WINDOW_HPP 3 | 4 | class MainWindow : public wxFrame { 5 | public: 6 | MainWindow(); 7 | void LoadFile(wxString path); 8 | }; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /resources/kovel.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Version=1.0 4 | Name=Kovel 5 | Comment=Voxel editor 6 | Exec=Kovel %f 7 | Icon=kovel 8 | Terminal=false 9 | Categories=Graphics;3DGraphics; 10 | MimeType=application/x-kovel-voxel 11 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | %: 3 | dh $@ 4 | 5 | override_dh_auto_configure: 6 | mkdir -p build 7 | cd build && cmake .. -DWX_UI=ON 8 | override_dh_auto_build: 9 | cd build && make 10 | override_dh_auto_install: 11 | echo "Install" 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster 2 | 3 | RUN apt-get update && apt-get install -y \ 4 | gcc g++ make cmake libwxgtk3.0-dev libwxbase3.0-dev \ 5 | wx3.0-headers wx-common libxml2-utils python \ 6 | && rm -rf /var/lib/apt/lists/* 7 | 8 | WORKDIR /opt/kovel 9 | 10 | CMD ["bash", "build_wx.sh"] -------------------------------------------------------------------------------- /upload_ppa.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Build Debian Package 4 | #dpkg-buildpackage -rfakeroot -kadrian.arroyocalle@gmail.com 5 | # Build Source package 6 | # Check CHANGELOG file 7 | debuild -S -sa -kadrian.arroyocalle@gmail.com 8 | dput ppa:adrian-arroyocalle/kovel ../kovel*source.changes # dput kovel-ppa 9 | -------------------------------------------------------------------------------- /docs/AppOrganization.md: -------------------------------------------------------------------------------- 1 | # Kovel App Organization 2 | 3 | 4 | * KovelUI - Two backends (Haiku and wxWidgets) 5 | * KovelGL - Realtime OpenGL representation of files being edited 6 | * KovelCore - Work with KVL files, materials, etc 7 | * KovelExport - BSON to ready to use COLLADA files 8 | * KovelExportCLI - Run KovelExport from command line, to build an asset pipeline 9 | -------------------------------------------------------------------------------- /ui/haiku/window.hpp: -------------------------------------------------------------------------------- 1 | #ifndef WINDOW_HPP 2 | #define WINDOW_HPP 3 | 4 | #include 5 | #include 6 | 7 | class KovelWindow : public BWindow { 8 | public: 9 | KovelWindow(); 10 | void LoadFile(BString path); 11 | bool QuitRequested(); 12 | void MessageReceived(BMessage* msg); 13 | BMenuBar* CreateMenuBar(); 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /debian/kovel.sharedmimeinfo: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Kovel file 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /resources/application-x-kovel-voxel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Kovel file 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ ! -f /etc/apt/sources.list.d/kovel.list ] 4 | then 5 | echo "deb http://ppa.launchpad.net/adrian-arroyocalle/kovel/ubuntu xenial main" > /etc/apt/sources.list.d/kovel.list 6 | apt-get update >> /dev/null 2> /tmp/kovel_apt_add_key.txt 7 | key=$(cat /tmp/kovel_apt_add_key.txt | cut -d":" -f6 | cut -d" " -f3) 8 | apt-key adv --keyserver keyserver.ubuntu.com --recv-keys $key 9 | fi 10 | -------------------------------------------------------------------------------- /ui/gl/gl1.hpp: -------------------------------------------------------------------------------- 1 | #ifndef GL1_HPP 2 | #define GL1_HPP 3 | 4 | #include "../../core/core.hpp" 5 | 6 | class GlPreviewer { 7 | public: 8 | GlPreviewer(); 9 | void Render(int width, int height, Geometry* geo, Material3D mat, float zoom, 10 | float rotation); 11 | void DrawCube(unsigned short x, unsigned short y, unsigned short z, 12 | Material mat); 13 | float zoom = 0; 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /ui/wx/metadata.hpp: -------------------------------------------------------------------------------- 1 | #ifndef METADATA_HPP 2 | #define METADATA_HPP 3 | 4 | #include "wx/wx.h" 5 | 6 | // This dialog can be used to create a new file or to edit the current file 7 | // metadata 8 | 9 | class MetadataDialog : public wxDialog { 10 | public: 11 | MetadataDialog(wxWindow* parent, bool newFile); 12 | ~MetadataDialog(); 13 | std::string name; 14 | std::string author; 15 | unsigned short gridSize = 5; 16 | // DATE and VERSION are generated by CORE 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /ui/haiku/metadata.hpp: -------------------------------------------------------------------------------- 1 | #ifndef METADATA_HPP 2 | #define METADATA_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class MetadataDialog : public BWindow { 9 | public: 10 | MetadataDialog(bool newFile); 11 | void MessageReceived(BMessage* msg); 12 | std::string name; 13 | std::string author; 14 | BTextControl* authorForm; 15 | BTextControl* nameForm; 16 | BSlider* gridForm; 17 | unsigned short gridSize = 5; 18 | bool n; 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /ui/wx/app.cpp: -------------------------------------------------------------------------------- 1 | #include "../../core/core.hpp" 2 | #include "wx/wx.h" 3 | 4 | #include "window.hpp" 5 | 6 | #ifdef WIN32 7 | #pragma comment(linker, "/SUBSYSTEM:WINDOWS") 8 | #endif 9 | 10 | class KovelApp : public wxApp { 11 | bool OnInit() { 12 | wxInitAllImageHandlers(); 13 | MainWindow* win = new MainWindow(); 14 | win->Show(); 15 | win->Update(); 16 | 17 | if (this->argc == 2) { 18 | win->LoadFile(this->argv[1]); 19 | } 20 | return true; 21 | } 22 | }; 23 | 24 | IMPLEMENT_APP(KovelApp) 25 | -------------------------------------------------------------------------------- /ui/haiku/preview.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PREVIEW_HPP 2 | #define PREVIEW_HPP 3 | 4 | #include "../gl/gl1.hpp" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class PreviewPanel : public BView { 11 | public: 12 | PreviewPanel(); 13 | float zoom = 0.0f; 14 | float rotation = 0.0f; 15 | void Render(); 16 | void Pulse(); 17 | 18 | private: 19 | GlPreviewer* gl; 20 | BStringView* zoomLevel; 21 | BStringView* rotationLevel; 22 | BGLView* canvas; 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /ui/wx/preview.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PREVIEW_HPP 2 | #define PREVIEW_HPP 3 | 4 | #include "../gl/gl1.hpp" 5 | 6 | #include "wx/wx.h" 7 | #include "wx/glcanvas.h" 8 | 9 | class PreviewPanel : public wxPanel { 10 | public: 11 | PreviewPanel(wxWindow* parent); 12 | void OnPaint(wxPaintEvent& event); 13 | void OnIdle(wxIdleEvent& event); 14 | float zoom = 0.0f; 15 | float rotation = 0.0f; 16 | 17 | private: 18 | wxGLCanvas* canvas; 19 | wxGLContext* ctx; 20 | GlPreviewer* gl; 21 | wxStaticText* zoomLevel; 22 | wxStaticText* rotationLevel; 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /core/version.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VERSION_HPP 2 | #define VERSION_HPP 3 | 4 | #define KOVEL_VERSION "0.1.0" 5 | #define KOVEL_COPYRIGHT "2015 Adrián Arroyo Calle" 6 | #define KOVEL_URL "http://github.com/AdrianArroyoCalle/kovel" 7 | #define AUTHOR_URL \ 8 | "http://adrianarroyocalle.github.io/" \ 9 | "?utm_source=Kovel&utm_medium=wxWidgetsApp&utm_campaign=Visit%20author%" \ 10 | "20page" 11 | #define DESCRIPTION \ 12 | "Kovel is a free voxel editor for Linux, Windows and Haiku. It can export " \ 13 | "to COLLADA" 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /format-tidy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #clang-format -style=file -i 4 | 5 | echo "clang-tidy" 6 | find ui \( -name \*.c -or -name \*.cpp -or -name \*.cc \) |xargs -i -n1 -P4 clang-tidy -fix -fix-errors {} -- 7 | find core \( -name \*.c -or -name \*.cpp -or -name \*.cc \) |xargs -i -n1 -P4 clang-tidy -fix -fix-errors {} -- 8 | find cli \( -name \*.c -or -name \*.cpp -or -name \*.cc \) |xargs -i -n1 -P4 clang-tidy -fix -fix-errors {} -- 9 | echo "clang-format" 10 | find ui \( -name \*.c -or -name \*.cpp -or -name \*.hpp -or -name \*.h \) |xargs -n12 -P4 clang-format -i -style=file 11 | find core \( -name \*.c -or -name \*.cpp -or -name \*.hpp -or -name \*.h \) |xargs -n12 -P4 clang-format -i -style=file 12 | find cli \( -name \*.c -or -name \*.cpp -or -name \*.hpp -or -name \*.h \) |xargs -n12 -P4 clang-format -i -style=file 13 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: kovel 2 | Section: graphics 3 | Priority: optional 4 | Maintainer: Adrián Arroyo Calle 5 | Build-Depends: debhelper (>= 9), cmake (>= 3.2), g++, libwxgtk3.0-dev, libwxbase3.0-dev, wx3.0-headers, wx-common, libxml2-utils, python 6 | Standards-Version: 3.9.6 7 | Homepage: http://adrianarroyocalle.github.io 8 | Vcs-Git: git://github.com/AdrianArroyoCalle/kovel 9 | 10 | Package: kovel 11 | Architecture: any 12 | Depends: ${misc:Depends}, ${shlibs:Depends} 13 | Description: A 3D voxel editor 14 | Kovel is a voxel editor. It allows you to build 3D models in a easy way. 15 | It reads KVL files and it can export to COLLADA DAE. 16 | 17 | Package: kovel-cli 18 | Architecture: any 19 | Depends: ${misc:Depends}, ${shlibs:Depends} 20 | Description: A 3D voxel editor (command line interface) 21 | Command line interface for Kovel. It allows you to build scripts and do 22 | Kovel operations from the command line. 23 | -------------------------------------------------------------------------------- /docs/FileFormat.md: -------------------------------------------------------------------------------- 1 | # Kovel Voxel Format 2 | 3 | Kovel is binary JSON (BSON) 4 | 5 | Mime-Type: application/x-kovel-voxel 6 | Extension: .kvl 7 | 8 | ```json 9 | { 10 | "metadata" : { 11 | "name" : "", 12 | "creator" : "", 13 | "date" : "", 14 | "version" : "" 15 | }, 16 | "materials" : { 17 | "MATERIAL_ID" : { 18 | "red" : "", 19 | "green" : "", 20 | "blue" : "", 21 | "opacity" : "", 22 | "texture" : "Base64 encoded texture" 23 | } 24 | }, 25 | "voxels" : [ //X 26 | [ // Y 27 | [{ 28 | /* Current */ 29 | "material" : "MATERIAL_ID", 30 | /* In a future */ 31 | "material" : { 32 | "top" : "MATERIAL_ID", 33 | "bottom": "MATERIAL_ID", 34 | "front" : "MATERIAL_ID", 35 | "back" : "MATERIAL_ID", 36 | "left" : "MATERIAL_ID", 37 | "right" : "MATERIAL_ID" 38 | }, 39 | /* optional */ 40 | "custom_mesh" : CustomMeshObject or INTEGER /* To be implemented */ 41 | }] //Z 42 | ] 43 | ] 44 | 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | os: Windows Server 2012 R2 3 | configuration: Release 4 | platform: x64 5 | clone_folder: C:\kovel 6 | install: 7 | - ps: >- 8 | git submodule init 9 | 10 | git submodule update 11 | 12 | mkdir wx 13 | 14 | cd wx 15 | 16 | Start-FileDownload ftp://ftp.wxwidgets.org/pub/3.0.0/binaries/wxMSW-3.0.0_vc120_x64_Dev.7z 17 | 18 | Start-FileDownload ftp://ftp.wxwidgets.org/pub/3.0.0/wxWidgets-3.0.0_headers.7z 19 | 20 | 7z x *.7z 21 | 22 | cd .. 23 | before_build: 24 | - cmd: >- 25 | cd C:\kovel 26 | 27 | cmake . -G "Visual Studio 12 2013 Win64" -DWX_UI=ON -DwxWidgets_ROOT_DIR="C:\kovel\wx" -DwxWidgets_LIB_DIR="C:\kovel\wx\lib\vc120_x64_dll" && exit 0 28 | 29 | cmake . -G "Visual Studio 12 2013 Win64" -DWX_UI=ON -DwxWidgets_ROOT_DIR="C:\kovel\wx" -DwxWidgets_LIB_DIR="C:\kovel\wx\lib\vc120_x64_dll" 30 | build: 31 | project: Kovel.vcxproj 32 | verbosity: normal 33 | test: off 34 | artifacts: 35 | - path: '**\*.exe' 36 | type: zip 37 | name: Nightly 38 | -------------------------------------------------------------------------------- /ui/haiku/app.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file app.cpp 3 | * @brief Entry point for Haiku native app 4 | */ 5 | 6 | #include "../../core/core.hpp" 7 | #include "../../core/version.hpp" 8 | #include "window.hpp" 9 | 10 | #include 11 | 12 | class KovelApp : public BApplication { 13 | public: 14 | KovelWindow* window; 15 | KovelApp() : BApplication("application/x-kovel-voxel") { 16 | window = new KovelWindow(); 17 | window->Show(); 18 | } 19 | void AboutRequested() { 20 | BString aboutText = ""; 21 | aboutText << "Kovel " << KOVEL_VERSION << "\n"; 22 | aboutText << "\n"; 23 | aboutText << "(C) " << KOVEL_COPYRIGHT << "\n"; 24 | aboutText << "Homepage: " << KOVEL_URL << "\n"; 25 | aboutText << "Licensed under the GNU GPL v2 license\n"; 26 | 27 | BAlert* about = new BAlert("About", aboutText, "Thanks"); 28 | about->Go(); 29 | } 30 | void LoadFile(char* filename) { 31 | window->LoadFile(filename); 32 | } 33 | }; 34 | 35 | int main(int argc, char** argv) { 36 | KovelApp app; 37 | if (argc == 2) { 38 | app.LoadFile(argv[1]); 39 | } 40 | app.Run(); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /resources/kovel.hvif: -------------------------------------------------------------------------------- 1 | 2 | resource() #'VICN' array { 3 | $"6E636966040300668005000300222B0380E5FF130A06BAA8B43CB922B51DB922" 4 | $"CA35BAA8CB16BC2ECA35BC2EB51D0A06BAA8B43CB922B51DB922CA35BAA8CB16" 5 | $"BC2ECA35BC2EB51D0805BAA8CB16BAA8B5FEB922B51DBAA8B5FEBC2EB51D0A04" 6 | $"BAA8B982BC2EBA63BC2EBDE7BAA8BD060A04BAA8B982C3CAB43CC550B51DBC2E" 7 | $"BA630A04BAA8B982C3CAB43CC550B51DBC2EBA630A04C550B51DC550B6DFBC2E" 8 | $"BC25BC2EBA630A04C550B51DC550B6DFBC2EBC25BC2EBA630A08BC2EBDE7BDB4" 9 | $"BD06BDB4BB44BF39BA63C6D6BEC8C550BFA9C550C16BBDB4BD060A08BC2EBDE7" 10 | $"BDB4BD06BDB4BB44BF39BA63C6D6BEC8C550BFA9C550C16BBDB4BD060802C550" 11 | $"BFA9BDB4BB440A04C3CABEC8C3CAC40EC550C4EFC550BFA90A04C3CABEC8C3CA" 12 | $"C40EC550C4EFC550BFA90A04C550C4EFC6D6C40EC6D6BEC8C550BFA90A04C550" 13 | $"C4EFC6D6C40EC6D6BEC8C550BFA90A04C3CAC40EC3CAC954C550CA35C550C4EF" 14 | $"0A04C3CAC40EC3CAC954C550CA35C550C4EF0A04C550CA35C6D6C954C6D6C40E" 15 | $"C550C4EF0A04C550CA35C6D6C954C6D6C40EC550C4EF130A000100000A010101" 16 | $"1001178000040A0101021001178000040A0101031001178000040A020104000A" 17 | $"0101051001178000040A000106000A0101071001178000040A030108000A0101" 18 | $"091001178000040A01010A1001178000040A03010B000A01010C100117800004" 19 | $"0A00010D000A01010E1001178000040A03010F000A0101101001178000040A00" 20 | $"0111000A010112100117800004" 21 | }; 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | env: 3 | - DOCKER_IMAGE="ubuntu:xenial" PKG="DEB" 4 | - DOCKER_IMAGE="ubuntu:bionic" PKG="DEB" 5 | - DOCKER_IMAGE="debian:buster" PKG="DEB" 6 | - DOCKER_IMAGE="fedora:31" PKG="DNF" 7 | - DOCKER_IMAGE="fedora:latest" PKG="DNF" 8 | - DOCKER_IMAGE="opensuse:tumbleweed" PKG="ZYPPER" 9 | services: 10 | - docker 11 | install: 12 | - docker pull $DOCKER_IMAGE 13 | script: 14 | - if [ "${PKG}" = "DEB" ]; then 15 | docker run -v $PWD:/cmake -t $DOCKER_IMAGE /bin/bash -c "cd /cmake && apt-get update && apt-get install -y cmake g++ libwxgtk3.0-dev libwxbase3.0-dev wx3.0-headers wx-common libxml2-utils python && ./build_wx.sh" 16 | ; 17 | fi 18 | - if [ "${PKG}" = "DNF" ]; then 19 | docker run -v $PWD:/cmake -t $DOCKER_IMAGE /bin/bash -c "cd /cmake && dnf -y install cmake gcc-c++ wxGTK3-devel wxGTK3-gl gcc make python libxml2-devel && ./build_wx.sh" 20 | ; 21 | fi 22 | - if [ "${PKG}" = "ZYPPER" ]; then 23 | docker run -v $PWD:/cmake -t $DOCKER_IMAGE /bin/bash -c "cd /cmake && zypper --non-interactive refresh && zypper --non-interactive install cmake gcc-c++ wxWidgets-2_9 && ./build_wx.sh" 24 | ; 25 | fi 26 | 27 | matrix: 28 | allow_failures: 29 | - env: DOCKER_IMAGE="ubuntu:xenial" PKG="DEB" 30 | - env: DOCKER_IMAGE="debian:buster" PKG="DEB" 31 | - env: DOCKER_IMAGE="fedora:31" PKG="DNF" 32 | - env: DOCKER_IMAGE="fedora:latest" PKG="DNF" 33 | - env: DOCKER_IMAGE="opensuse:tumbleweed" PKG="ZYPPER" 34 | -------------------------------------------------------------------------------- /resources/kovel.rdef: -------------------------------------------------------------------------------- 1 | resource app_signature "application/x-kovel-voxel"; 2 | 3 | resource app_flags B_SINGLE_LAUNCH; 4 | 5 | resource app_version { 6 | major = 1, 7 | middle = 0, 8 | minor = 0, 9 | 10 | variety = B_APPV_FINAL, 11 | internal = 1, 12 | 13 | short_info = "Kovel - Voxel editor", 14 | long_info = "Kovel is an easy-to-use opensource 3D voxel editor" 15 | }; 16 | 17 | 18 | resource vector_icon{ 19 | $"6E636966040300668005000300222B0380E5FF130A06BAA8B43CB922B51DB922" 20 | $"CA35BAA8CB16BC2ECA35BC2EB51D0A06BAA8B43CB922B51DB922CA35BAA8CB16" 21 | $"BC2ECA35BC2EB51D0805BAA8CB16BAA8B5FEB922B51DBAA8B5FEBC2EB51D0A04" 22 | $"BAA8B982BC2EBA63BC2EBDE7BAA8BD060A04BAA8B982C3CAB43CC550B51DBC2E" 23 | $"BA630A04BAA8B982C3CAB43CC550B51DBC2EBA630A04C550B51DC550B6DFBC2E" 24 | $"BC25BC2EBA630A04C550B51DC550B6DFBC2EBC25BC2EBA630A08BC2EBDE7BDB4" 25 | $"BD06BDB4BB44BF39BA63C6D6BEC8C550BFA9C550C16BBDB4BD060A08BC2EBDE7" 26 | $"BDB4BD06BDB4BB44BF39BA63C6D6BEC8C550BFA9C550C16BBDB4BD060802C550" 27 | $"BFA9BDB4BB440A04C3CABEC8C3CAC40EC550C4EFC550BFA90A04C3CABEC8C3CA" 28 | $"C40EC550C4EFC550BFA90A04C550C4EFC6D6C40EC6D6BEC8C550BFA90A04C550" 29 | $"C4EFC6D6C40EC6D6BEC8C550BFA90A04C3CAC40EC3CAC954C550CA35C550C4EF" 30 | $"0A04C3CAC40EC3CAC954C550CA35C550C4EF0A04C550CA35C6D6C954C6D6C40E" 31 | $"C550C4EF0A04C550CA35C6D6C954C6D6C40EC550C4EF130A000100000A010101" 32 | $"1001178000040A0101021001178000040A0101031001178000040A020104000A" 33 | $"0101051001178000040A000106000A0101071001178000040A030108000A0101" 34 | $"091001178000040A01010A1001178000040A03010B000A01010C100117800004" 35 | $"0A00010D000A01010E1001178000040A03010F000A0101101001178000040A00" 36 | $"0111000A010112100117800004" 37 | }; 38 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | PROJECT(Kovel) 2 | CMAKE_MINIMUM_REQUIRED(VERSION 3.1 FATAL_ERROR) 3 | 4 | SET(CMAKE_CXX_STANDARD 11) 5 | 6 | OPTION(HAIKU_UI "Use Haiku native API" OFF) 7 | OPTION(WX_UI "Use wxWidgets API" OFF) 8 | 9 | FILE(GLOB CORE_SRC "core/*.cpp") 10 | 11 | IF(HAIKU_UI) 12 | FILE(GLOB UI_SRC "ui/haiku/*.cpp") 13 | ENDIF() 14 | 15 | IF(WX_UI) 16 | FILE(GLOB UI_SRC "ui/wx/*.cpp") 17 | ENDIF() 18 | 19 | FILE(GLOB GL_SRC "ui/gl/*.cpp") 20 | FILE(GLOB EXPORT_SRC "exporter/*.cpp") 21 | FILE(GLOB CLI_SRC "cli/*.cpp") 22 | 23 | SET(KOVEL_SRC ${CORE_SRC} ${UI_SRC} ${GL_SRC} ${EXPORT_SRC}) 24 | IF(WIN32) 25 | LIST(APPEND KOVEL_SRC "resources/kovel.rc") 26 | ENDIF() 27 | 28 | ADD_SUBDIRECTORY(libbson) 29 | 30 | INCLUDE_DIRECTORIES("libbson/src/bson") 31 | INCLUDE_DIRECTORIES("${PROJECT_BINARY_DIR}/libbson/src/bson") 32 | 33 | ADD_EXECUTABLE(Kovel ${KOVEL_SRC}) 34 | ADD_EXECUTABLE(kovelcli ${CLI_SRC} ${CORE_SRC}) 35 | 36 | TARGET_LINK_LIBRARIES(Kovel bson_static) 37 | TARGET_LINK_LIBRARIES(kovelcli bson_static) 38 | 39 | FIND_PACKAGE(OpenGL REQUIRED) 40 | INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIRS}) 41 | 42 | IF(HAIKU_UI) 43 | TARGET_LINK_LIBRARIES(Kovel be root tracker ${OPENGL_LIBRARIES}) 44 | ADD_CUSTOM_COMMAND(TARGET Kovel COMMAND rc -o kovel.rsrc ${CMAKE_CURRENT_SOURCE_DIR}/resources/kovel.rdef COMMENT "Compiling resources") 45 | ADD_CUSTOM_COMMAND(TARGET Kovel COMMAND xres -o Kovel kovel.rsrc COMMENT "Adding resources to executable") 46 | ADD_CUSTOM_COMMAND(TARGET Kovel COMMAND mimeset --all Kovel COMMENT "Adjusting MIME types") 47 | # Apply icon and Haiku metadata 48 | ENDIF() 49 | 50 | IF(WX_UI) 51 | FIND_PACKAGE(wxWidgets COMPONENTS core base gl adv) 52 | INCLUDE_DIRECTORIES(${wxWidgets_INCLUDE_DIR}) 53 | INCLUDE( "${wxWidgets_USE_FILE}" ) 54 | TARGET_LINK_LIBRARIES(Kovel ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES}) 55 | ENDIF() 56 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: true 6 | AlignEscapedNewlinesLeft: false 7 | AlignOperands: true 8 | AlignTrailingComments: true 9 | AllowAllParametersOfDeclarationOnNextLine: true 10 | AllowShortBlocksOnASingleLine: false 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortIfStatementsOnASingleLine: false 13 | AllowShortLoopsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: None 15 | AlwaysBreakAfterDefinitionReturnType: false 16 | AlwaysBreakTemplateDeclarations: false 17 | AlwaysBreakBeforeMultilineStrings: false 18 | BreakBeforeBinaryOperators: None 19 | BreakBeforeTernaryOperators: true 20 | BreakConstructorInitializersBeforeComma: false 21 | BinPackParameters: true 22 | BinPackArguments: true 23 | ColumnLimit: 80 24 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 25 | ConstructorInitializerIndentWidth: 4 26 | DerivePointerAlignment: false 27 | ExperimentalAutoDetectBinPacking: false 28 | IndentCaseLabels: false 29 | IndentWrappedFunctionNames: false 30 | IndentFunctionDeclarationAfterType: false 31 | MaxEmptyLinesToKeep: 1 32 | KeepEmptyLinesAtTheStartOfBlocks: true 33 | NamespaceIndentation: None 34 | ObjCBlockIndentWidth: 2 35 | ObjCSpaceAfterProperty: false 36 | ObjCSpaceBeforeProtocolList: true 37 | PenaltyBreakBeforeFirstCallParameter: 19 38 | PenaltyBreakComment: 300 39 | PenaltyBreakString: 1000 40 | PenaltyBreakFirstLessLess: 120 41 | PenaltyExcessCharacter: 1000000 42 | PenaltyReturnTypeOnItsOwnLine: 60 43 | PointerAlignment: Left 44 | SpacesBeforeTrailingComments: 1 45 | Cpp11BracedListStyle: true 46 | Standard: Cpp11 47 | IndentWidth: 2 48 | TabWidth: 4 49 | UseTab: ForIndentation 50 | BreakBeforeBraces: Attach 51 | SpacesInParentheses: false 52 | SpacesInSquareBrackets: false 53 | SpacesInAngles: false 54 | SpaceInEmptyParentheses: false 55 | SpacesInCStyleCastParentheses: false 56 | SpaceAfterCStyleCast: false 57 | SpacesInContainerLiterals: true 58 | SpaceBeforeAssignmentOperators: true 59 | ContinuationIndentWidth: 4 60 | CommentPragmas: '^ IWYU pragma:' 61 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 62 | SpaceBeforeParens: ControlStatements 63 | DisableFormat: false 64 | ... 65 | 66 | -------------------------------------------------------------------------------- /ui/wx/metadata.cpp: -------------------------------------------------------------------------------- 1 | #include "../../core/core.hpp" 2 | 3 | #include "metadata.hpp" 4 | #include 5 | 6 | MetadataDialog::MetadataDialog(wxWindow* parent, bool newFile) 7 | : wxDialog(parent, wxID_ANY, "Metadata") { 8 | Core* core = Core::Instance(); 9 | wxFont font; 10 | font.SetPointSize(14); 11 | // DO UI 12 | wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); 13 | 14 | wxBoxSizer* name = new wxBoxSizer(wxHORIZONTAL); 15 | wxStaticText* nameLabel = new wxStaticText(this, wxID_ANY, "Name:"); 16 | nameLabel->SetFont(font); 17 | name->Add(nameLabel); 18 | this->name = core->name; 19 | wxTextCtrl* nameForm = new wxTextCtrl( 20 | this, wxID_ANY, (newFile) ? "" : wxString::FromUTF8(this->name.c_str())); 21 | nameForm->SetMinSize(wxSize(200, 10)); 22 | nameForm->Bind(wxEVT_TEXT, [this, nameForm](wxCommandEvent&) -> void { 23 | this->name = std::string(nameForm->GetValue().ToUTF8()); 24 | }, -1); 25 | name->Add(nameForm, 0, wxEXPAND | wxALL); 26 | 27 | wxBoxSizer* author = new wxBoxSizer(wxHORIZONTAL); 28 | wxStaticText* authorLabel = new wxStaticText(this, wxID_ANY, "Author:"); 29 | authorLabel->SetFont(font); 30 | author->Add(authorLabel); 31 | this->author = core->author; 32 | wxTextCtrl* authorForm = 33 | new wxTextCtrl(this, wxID_ANY, 34 | (newFile) ? "" : wxString::FromUTF8(this->author.c_str())); 35 | authorForm->SetMinSize(wxSize(200, 10)); 36 | authorForm->Bind(wxEVT_TEXT, [this, authorForm](wxCommandEvent&) -> void { 37 | this->author = std::string(authorForm->GetValue().ToUTF8()); 38 | }, -1); 39 | author->Add(authorForm, 0, wxEXPAND | wxALL); 40 | 41 | wxBoxSizer* grid = new wxBoxSizer(wxHORIZONTAL); 42 | wxStaticText* gridLabel = new wxStaticText(this, wxID_ANY, "Grid size: "); 43 | gridLabel->SetFont(font); 44 | grid->Add(gridLabel); 45 | wxSpinCtrl* gridForm = new wxSpinCtrl(this); 46 | gridForm->SetValue(core->grid); 47 | gridForm->Bind(wxEVT_SPINCTRL, [this, gridForm](wxCommandEvent&) -> void { 48 | this->gridSize = (unsigned short)gridForm->GetValue(); 49 | }, -1); 50 | if (!newFile) 51 | gridForm->Enable(false); 52 | grid->Add(gridForm, 0, wxEXPAND | wxALL); 53 | 54 | wxSizer* buttons = this->CreateButtonSizer(wxOK | wxCANCEL); 55 | 56 | sizer->Add(name, 0, wxEXPAND | wxALL); 57 | sizer->Add(author, 0, wxEXPAND | wxALL); 58 | sizer->Add(grid, 0, wxEXPAND | wxALL); 59 | sizer->Add(buttons, 0, wxEXPAND | wxALL); 60 | 61 | SetSizer(sizer); 62 | } 63 | 64 | MetadataDialog::~MetadataDialog() { 65 | } 66 | -------------------------------------------------------------------------------- /ui/haiku/preview.cpp: -------------------------------------------------------------------------------- 1 | #include "preview.hpp" 2 | 3 | #include 4 | #include 5 | 6 | #include "../gl/gl1.hpp" 7 | 8 | class PreviewWindow : public BWindow { 9 | public: 10 | BGLView* canvas; 11 | GlPreviewer* gl; 12 | PreviewWindow() 13 | : BWindow(BRect(400, 400, 800, 800), "Kovel - OpenGL preview", 14 | B_TITLED_WINDOW, 0) { 15 | gl = new GlPreviewer(); 16 | canvas = new BGLView(Bounds(), "GL", B_FOLLOW_ALL_SIDES, 0, 17 | BGL_RGB | BGL_ALPHA | BGL_DOUBLE); 18 | AddChild(canvas); 19 | } 20 | void Render(float zoom, float rotation) { 21 | Core* core = Core::Instance(); 22 | BRect frame = Bounds(); 23 | canvas->LockGL(); 24 | gl->Render(frame.Size().Width(), frame.Size().Height(), core->geo, 25 | core->mat, zoom, rotation); 26 | GLenum error; 27 | while ((error = glGetError()) != GL_NO_ERROR) { 28 | printf("OpenGL ERROR %s\n", error); 29 | } 30 | canvas->SwapBuffers(); 31 | canvas->UnlockGL(); 32 | } 33 | }; 34 | 35 | PreviewWindow* prev; 36 | 37 | PreviewPanel::PreviewPanel() : BView(NULL, B_WILL_DRAW | B_PULSE_NEEDED) { 38 | SetViewColor(220, 220, 220); 39 | BGroupLayout* box = new BGroupLayout(B_HORIZONTAL); 40 | BGroupLayout* control = new BGroupLayout(B_VERTICAL); 41 | BGroupLayout* zoomButton = new BGroupLayout(B_HORIZONTAL); 42 | BGroupLayout* rotationButton = new BGroupLayout(B_HORIZONTAL); 43 | 44 | SetLayout(box); 45 | 46 | zoomLevel = new BStringView(NULL, ""); 47 | rotationLevel = new BStringView(NULL, ""); 48 | BColorControl* color = 49 | new BColorControl(BPoint(0, 0), B_CELLS_32x8, 5.0, NULL, new BMessage(6)); 50 | BButton* zoomMore = new BButton("Zoom in", new BMessage(11)); 51 | BButton* zoomLess = new BButton("Zoom out", new BMessage(12)); 52 | BButton* rotationLeft = new BButton("Rotate left", new BMessage(9)); 53 | BButton* rotationRight = new BButton("Rotate right", new BMessage(10)); 54 | 55 | box->AddItem(control, 1); 56 | 57 | control->AddView(zoomLevel); 58 | control->AddView(rotationLevel); 59 | control->AddView(color); 60 | control->AddItem(zoomButton); 61 | control->AddItem(rotationButton); 62 | zoomButton->AddView(zoomMore); 63 | zoomButton->AddView(zoomLess); 64 | rotationButton->AddView(rotationLeft); 65 | rotationButton->AddView(rotationRight); 66 | 67 | /* Pulse for refreshing */ 68 | 69 | prev = new PreviewWindow(); 70 | prev->Show(); 71 | } 72 | 73 | void PreviewPanel::Render() { 74 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 75 | Pulse(); 76 | } 77 | 78 | void PreviewPanel::Pulse() { 79 | prev->Render(zoom, rotation); 80 | } 81 | -------------------------------------------------------------------------------- /debian/Kovel.1: -------------------------------------------------------------------------------- 1 | .\" generated with Ronn/v0.7.3 2 | .\" http://github.com/rtomayko/ronn/tree/0.7.3 3 | . 4 | .TH "README" "" "November 2015" "" "" 5 | . 6 | .P 7 | Welcome! Kovel is a 3D voxel editor for Linux and Windows\. Create fantastic models without knowledge\. Just fill the grid with your colors! Save your models in Kovel file (*\.kvl) or in COLLADA DAE \fIhttps://www\.khronos\.org/collada/\fR (only export)\. See changes in your models in realtime, rotate and scale\. Kovel also has infinite undo history (in a same file)\. Kovel has a command line tool (kovelcli) to automate your work pipeline\. Convert all your Kovel files into Collada DAE in a few commands\. 8 | . 9 | .SH "Building" 10 | Kovel requires: 11 | . 12 | .IP "\(bu" 4 13 | wxWidgets 3\.0 or higher 14 | . 15 | .IP "\(bu" 4 16 | CMake 3\.2 or higher 17 | . 18 | .IP "\(bu" 4 19 | OpenGL (current renderer uses OpenGL 1\.0 legacy API, so everything works) 20 | . 21 | .IP "\(bu" 4 22 | C++11 compiler (lambda support) 23 | . 24 | .IP "\(bu" 4 25 | libbson \- in tree 26 | . 27 | .IP "" 0 28 | . 29 | .IP "" 4 30 | . 31 | .nf 32 | 33 | git clone https://github\.com/AdrianArroyoCalle/kovel 34 | cd kovel 35 | git submodule init 36 | git submodule update 37 | . 38 | .fi 39 | . 40 | .IP "" 0 41 | . 42 | .IP "" 4 43 | . 44 | .nf 45 | 46 | sudo apt install cmake g++ libwxgtk3\.0\-dev libwxbase3\.0\-dev wx3\.0\-headers wx\-common 47 | . 48 | .fi 49 | . 50 | .IP "" 0 51 | . 52 | .P 53 | If you want to run the little test suite, you also need: 54 | . 55 | .IP "" 4 56 | . 57 | .nf 58 | 59 | sudo apt install libxml2\-utils python 60 | . 61 | .fi 62 | . 63 | .IP "" 0 64 | . 65 | .P 66 | Configure and compile 67 | . 68 | .IP "" 4 69 | . 70 | .nf 71 | 72 | mkdir build 73 | cd build 74 | cmake \.\. \-DWX_UI=ON 75 | make 76 | . 77 | .fi 78 | . 79 | .IP "" 0 80 | . 81 | .P 82 | Native package: 83 | . 84 | .IP "" 4 85 | . 86 | .nf 87 | 88 | dpkg\-buildpackage \-rfakeroot \-kYOUR_GPG_KEY 89 | . 90 | .fi 91 | . 92 | .IP "" 0 93 | . 94 | .P 95 | Tests: 96 | . 97 | .IP "" 4 98 | . 99 | .nf 100 | 101 | cd test 102 | \./test_dae\.sh 103 | \./test_json\.sh 104 | . 105 | .fi 106 | . 107 | .IP "" 0 108 | . 109 | .SH "Getting it" 110 | Launchpad PPA: 111 | . 112 | .IP "" 4 113 | . 114 | .nf 115 | 116 | sudo add\-apt\-repository \-y ppa:adrian\-arroyocalle/kovel 117 | sudo apt update 118 | sudo apt install kovel kovel\-cli 119 | . 120 | .fi 121 | . 122 | .IP "" 0 123 | . 124 | .SH "Screenshoots" 125 | 126 | . 127 | .SH "Donate" 128 | PayPal: http://paypal\.me/aarroyoc BitCoin: 1A2j8CwiFEhQ4Uycsjhr3gQPbJxFk1LRmM 129 | . 130 | .SH "Command line usage" 131 | . 132 | .P 133 | Example (export as COLLADA DAE) \fBkovelcli \-i File\.kvl \-x dae \-o File\.dae\fR 134 | -------------------------------------------------------------------------------- /cli/cli.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cli.cpp 3 | * @brief Entry point for Command Line kovel interface 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "../core/core.hpp" 10 | #include "../core/version.hpp" 11 | 12 | char* getCmdOption(char** begin, char** end, const std::string& option) { 13 | char** itr = std::find(begin, end, option); 14 | if (itr != end && ++itr != end) { 15 | return *itr; 16 | } 17 | return 0; 18 | } 19 | 20 | bool cmdOptionExists(char** begin, char** end, const std::string& option) { 21 | return std::find(begin, end, option) != end; 22 | } 23 | 24 | void ShowHelp() { 25 | /* Show help */ 26 | std::cout << std::endl; 27 | std::cout << "HELP" << std::endl; 28 | std::cout << "-h\tShow help" << std::endl; 29 | std::cout << "-i\tInput file" << std::endl; 30 | std::cout << "-x\tExport as [dae,json]" << std::endl; 31 | std::cout << "-o\tOut file" << std::endl; 32 | std::cout << std::endl; 33 | std::cout << "Example (export as COLLADA DAE)" << std::endl; 34 | std::cout << "kovelcli -i File.kvl -x dae -o File.dae" << std::endl; 35 | } 36 | 37 | int main(int argc, char** argv) { 38 | 39 | std::cout << "==============================" << std::endl; 40 | std::cout << "KOVEL " << KOVEL_VERSION << std::endl; 41 | std::cout << "(C) " << KOVEL_COPYRIGHT << std::endl; 42 | std::cout << "Help: " << KOVEL_URL << std::endl; 43 | std::cout << "==============================" << std::endl; 44 | 45 | /* Parse command line options, show help, version and run exporter */ 46 | 47 | if (cmdOptionExists(argv, argv + argc, "-h")) { 48 | ShowHelp(); 49 | return 0; 50 | } 51 | 52 | char* input = getCmdOption(argv, argv + argc, "-i"); 53 | char* exportAs = getCmdOption(argv, argv + argc, "-x"); 54 | char* output = getCmdOption(argv, argv + argc, "-o"); 55 | 56 | if (input && exportAs && output) { 57 | Core* core = Core::Instance(); 58 | std::cout << "Processing file: " << input << std::endl; 59 | core->LoadFile(input); 60 | 61 | #ifdef WIN32 62 | char* folder = std::getenv("TMP"); 63 | #else 64 | char* folder = std::getenv("TMPDIR"); 65 | if (folder == 0) { 66 | folder = (char*)"/tmp"; 67 | } 68 | #endif 69 | std::stringstream path; 70 | path << folder; 71 | path << "/KovelExport.tmp.kvl"; 72 | core->SaveFile(path.str()); 73 | if (!core->ValidateFile()) { 74 | std::cerr << "Kovel file is not valid!" << std::endl; 75 | return 2; 76 | } 77 | if (strcmp(exportAs, "dae") == 0) { 78 | core->ExportAsDAE(output); 79 | } else if (strcmp(exportAs, "json") == 0) { 80 | core->ExportAsJSON(output); 81 | } else { 82 | std::cerr << "You must specify export as 'dae' or 'json'!" << std::endl; 83 | return 3; 84 | } 85 | } else { 86 | ShowHelp(); 87 | return 1; 88 | } 89 | 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /ui/haiku/metadata.cpp: -------------------------------------------------------------------------------- 1 | #include "../../core/core.hpp" 2 | 3 | #include 4 | #include 5 | 6 | #include "metadata.hpp" 7 | 8 | const uint32 OK = 300, CANCEL = 301; 9 | 10 | MetadataDialog::MetadataDialog(bool newFile) 11 | : BWindow(BRect(100, 100, 500, 300), "Metadata", B_MODAL_WINDOW, 0) { 12 | n = newFile; 13 | BView* all = new BView(Bounds(), NULL, B_FOLLOW_ALL_SIDES, B_WILL_DRAW); 14 | AddChild(all); 15 | Core* core = Core::Instance(); 16 | BFont font; 17 | font.SetSize(14.0); 18 | 19 | all->SetViewColor(220, 220, 220); 20 | 21 | BGroupLayout* sizer = new BGroupLayout(B_VERTICAL); 22 | BGroupLayout* name = new BGroupLayout(B_HORIZONTAL); 23 | BGroupLayout* author = new BGroupLayout(B_HORIZONTAL); 24 | 25 | all->SetLayout(sizer); 26 | 27 | BStringView* nameLabel = new BStringView(NULL, "Name: "); 28 | nameLabel->SetFont(&font); 29 | 30 | this->name = core->name; 31 | nameForm = new BTextControl(NULL, "", "", NULL); 32 | nameForm->SetText((newFile) ? "" : this->name.c_str()); 33 | nameForm->SetExplicitMinSize(BSize(200, 10)); 34 | 35 | BStringView* authorLabel = new BStringView(NULL, "Author: "); 36 | authorLabel->SetFont(&font); 37 | 38 | this->author = core->author; 39 | authorForm = new BTextControl(NULL, "", "", NULL); 40 | authorForm->SetText((newFile) ? "" : this->author.c_str()); 41 | authorForm->SetExplicitMinSize(BSize(200, 10)); 42 | 43 | gridForm = new BSlider(BRect(0, 0, 50, 100), NULL, "Grid size", NULL, 1, 10); 44 | gridForm->SetValue(core->grid); 45 | if (!newFile) 46 | gridForm->SetEnabled(false); 47 | 48 | BButton* ok = new BButton("OK", new BMessage(OK)); 49 | 50 | sizer->AddItem(name); 51 | sizer->AddItem(author); 52 | sizer->AddView(gridForm); 53 | sizer->AddView(ok); 54 | sizer->AddView(new BButton("Cancel", new BMessage(CANCEL))); 55 | 56 | name->AddView(nameLabel); 57 | name->AddView(nameForm); 58 | author->AddView(authorLabel); 59 | author->AddView(authorForm); 60 | 61 | SetDefaultButton(ok); 62 | 63 | /*sizer->AddItem(grid); - Falta BSlider o similar */ 64 | /* sizer->AddView(buttons); - Faltan botones de OK y CANCEL */ 65 | } 66 | 67 | void MetadataDialog::MessageReceived(BMessage* msg) { 68 | switch (msg->what) { 69 | case OK: { 70 | int32 count = be_app->CountWindows(); 71 | for (int32 i = 0; i < count; i++) { 72 | BMessage* mesg = new BMessage(666); 73 | mesg->AddString("NAME", nameForm->Text()); 74 | mesg->AddString("AUTHOR", authorForm->Text()); 75 | mesg->AddInt32("GRID_SIZE", gridForm->Value()); 76 | mesg->AddBool("NEW_FILE", this->n); 77 | be_app->WindowAt(i)->PostMessage(mesg); 78 | } 79 | 80 | Quit(); 81 | break; 82 | } 83 | case CANCEL: { 84 | Quit(); 85 | break; 86 | } 87 | default: 88 | return BWindow::MessageReceived(msg); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /core/core.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_HPP 2 | #define CORE_HPP 3 | 4 | #ifdef WIN32 5 | #include 6 | #endif 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // Usar STDVector para los materiales en vez de eso 14 | 15 | class Geometry { 16 | public: 17 | Geometry(unsigned short grid) { 18 | this->g = grid; 19 | geo.resize(g); 20 | for (short u = 0; u < g; u++) { 21 | geo.at(u).resize(g); 22 | for (short v = 0; v < g; v++) { 23 | geo.at(u)[v].resize(g); 24 | } 25 | } 26 | } 27 | void SetGrid(unsigned short value, unsigned short x, unsigned short y, 28 | unsigned short z) { 29 | geo[x][y][z] = value; 30 | } 31 | unsigned short GetGrid(unsigned short x, unsigned short y, unsigned short z) { 32 | return geo[x][y][z]; 33 | } 34 | ~Geometry() { 35 | } 36 | unsigned short g; 37 | 38 | private: 39 | std::vector>> geo; 40 | }; 41 | 42 | class Material { 43 | public: 44 | Material() { 45 | this->name = "NullColour"; 46 | this->r = 1.0f; 47 | this->g = 1.0f; 48 | this->b = 0.0f; 49 | } 50 | Material(std::string name) { 51 | this->name = name; 52 | this->r = 1.0f; 53 | this->g = 1.0f; 54 | this->b = 0.0f; 55 | }; 56 | Material(std::string name, float r, float g, float b) { 57 | this->r = r; 58 | this->g = g; 59 | this->b = b; 60 | this->name = name; 61 | }; 62 | // Accept textures in future 63 | std::string name; 64 | 65 | public: 66 | double r, g, b; 67 | }; 68 | 69 | typedef std::vector>> Material3D; 70 | 71 | struct Undo { 72 | unsigned short value; 73 | unsigned short x; 74 | unsigned short y; 75 | unsigned short z; 76 | Material material; 77 | }; 78 | 79 | class Core { 80 | public: 81 | static Core* Instance(); 82 | 83 | protected: 84 | Core(); 85 | ~Core(); 86 | Core(Core const&) = delete; // Don't Implement. 87 | void operator=(Core const&) = delete; // Don't implement 88 | public: 89 | void NewFile(unsigned short gridSize); 90 | void LoadFile(std::string filename); 91 | void SaveFile(std::string filename); 92 | void UpdateGrid(unsigned short value, unsigned short x, unsigned short y, 93 | unsigned short z); 94 | void UpdateMetadata(); 95 | void SetMaterial(Material mat); 96 | bool ValidateFile(); 97 | bool ExportAsJSON(std::string filename); 98 | bool ExportAsDAE(std::string filename); 99 | void Undo(); 100 | Geometry* geo; 101 | Material3D mat; 102 | std::string name; 103 | std::string author; 104 | unsigned short grid; 105 | std::vector undo; 106 | 107 | private: 108 | bson_t kovel; 109 | static Core* pinstance; 110 | float r, g, b; 111 | std::unordered_map material; 112 | Material currentMat; 113 | }; 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /ui/wx/preview.cpp: -------------------------------------------------------------------------------- 1 | #include "preview.hpp" 2 | 3 | #include "wx/wx.h" 4 | #include "wx/glcanvas.h" 5 | 6 | #include "../gl/gl1.hpp" 7 | 8 | PreviewPanel::PreviewPanel(wxWindow* parent) 9 | : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(100, 100)) { 10 | wxBoxSizer* box = new wxBoxSizer(wxHORIZONTAL); 11 | 12 | gl = new GlPreviewer(); 13 | 14 | int attribList[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 32, 0}; 15 | 16 | canvas = new wxGLCanvas(this, wxID_ANY, attribList, wxDefaultPosition, 17 | wxSize(100, 100)); 18 | ctx = new wxGLContext(canvas); 19 | 20 | wxBoxSizer* control = new wxBoxSizer(wxVERTICAL); 21 | zoomLevel = new wxStaticText(this, wxID_ANY, "Zoom level: 0"); 22 | control->Add(zoomLevel); 23 | 24 | rotationLevel = new wxStaticText(this, wxID_ANY, "Rotation level: 0"); 25 | control->Add(rotationLevel); 26 | 27 | wxBoxSizer* zoomButton = new wxBoxSizer(wxHORIZONTAL); 28 | wxButton* zoomMore = new wxButton(this, wxID_ANY, "Zoom in"); 29 | zoomMore->Bind(wxEVT_BUTTON, 30 | [this](wxCommandEvent&) -> void { this->zoom += 1.0f; }, -1); 31 | zoomButton->Add(zoomMore, 1, wxEXPAND | wxALL, 0); 32 | wxButton* zoomLess = new wxButton(this, wxID_ANY, "Zoom out"); 33 | zoomLess->Bind(wxEVT_BUTTON, 34 | [this](wxCommandEvent&) -> void { this->zoom -= 1.0f; }, -1); 35 | zoomButton->Add(zoomLess, 1, wxEXPAND | wxALL, 0); 36 | 37 | control->Add(zoomButton); 38 | 39 | wxBoxSizer* rotationButton = new wxBoxSizer(wxHORIZONTAL); 40 | wxButton* rotationLeft = new wxButton(this, wxID_ANY, "Rotate left"); 41 | rotationLeft->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) -> void { 42 | this->rotation += 15; 43 | }, -1); 44 | rotationButton->Add(rotationLeft, 1, wxEXPAND | wxALL, 0); 45 | wxButton* rotationRight = new wxButton(this, wxID_ANY, "Rotate right"); 46 | rotationRight->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) -> void { 47 | this->rotation -= 15; 48 | }, -1); 49 | rotationButton->Add(rotationRight, 1, wxEXPAND | wxALL, 0); 50 | 51 | control->Add(rotationButton); 52 | 53 | box->Add(canvas, 2, wxALIGN_CENTER | wxSHAPED); 54 | box->Add(control, 1, wxEXPAND | wxALL, 0); 55 | 56 | SetSizer(box); 57 | 58 | Bind(wxEVT_IDLE, &PreviewPanel::OnIdle, this, -1); 59 | } 60 | 61 | void PreviewPanel::OnIdle(wxIdleEvent& event) { 62 | if (!canvas->IsShownOnScreen()) 63 | return; 64 | Core* core = Core::Instance(); 65 | wxSize size = canvas->GetSize(); 66 | wxClientDC(this); 67 | canvas->SetCurrent(*ctx); 68 | gl->Render(size.GetWidth(), size.GetHeight(), core->geo, core->mat, zoom, 69 | rotation); 70 | canvas->SwapBuffers(); 71 | 72 | zoomLevel->SetLabel(wxString::Format("Zoom level: %g", zoom)); 73 | rotationLevel->SetLabel(wxString::Format("Rotation level: %g", rotation)); 74 | } 75 | 76 | void PreviewPanel::OnPaint(wxPaintEvent& event) { 77 | if (!canvas->IsShownOnScreen()) 78 | return; 79 | Core* core = Core::Instance(); 80 | wxSize size = canvas->GetSize(); 81 | wxPaintDC(this); 82 | canvas->SetCurrent(*ctx); 83 | gl->Render(size.GetWidth(), size.GetHeight(), core->geo, core->mat, zoom, 84 | rotation); 85 | canvas->SwapBuffers(); 86 | } 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kovel 2 | 3 | [![Join the chat at https://gitter.im/AdrianArroyoCalle/kovel](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AdrianArroyoCalle/kovel?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | 5 | ![Kovel](resources/kovel.png) 6 | 7 | ![Travis CI](https://travis-ci.org/AdrianArroyoCalle/kovel.svg) 8 | 9 | Welcome! Kovel is a 3D voxel editor for Linux and Windows. Create fantastic models without knowledge. Just fill the grid with your colors! Save your models in Kovel file (*.kvl) or in [COLLADA DAE](https://www.khronos.org/collada/) (only export). 10 | See changes in your models in realtime, rotate and scale. Kovel also has infinite undo history (in a same file). Kovel has a command line tool (kovelcli) to automate your work pipeline. Convert all your Kovel files into Collada DAE in a few commands. 11 | 12 | ## Building 13 | 14 | Kovel requires: 15 | 16 | * wxWidgets 3.0 or higher 17 | * CMake 3.2 or higher 18 | * OpenGL (current renderer uses OpenGL 1.0 legacy API, so everything works) 19 | * C++11 compiler (lambda support) 20 | * libbson - in tree 21 | 22 | #### Get the source 23 | 24 | ``` 25 | git clone https://github.com/AdrianArroyoCalle/kovel 26 | cd kovel 27 | git submodule init 28 | git submodule update 29 | ``` 30 | 31 | #### Debian/Ubuntu 32 | 33 | ``` 34 | sudo apt install cmake g++ libwxgtk3.0-dev libwxbase3.0-dev wx3.0-headers wx-common 35 | ``` 36 | 37 | If you want to run the little test suite, you also need: 38 | 39 | ``` 40 | sudo apt install libxml2-utils python 41 | 42 | ``` 43 | 44 | Configure and compile 45 | 46 | ``` 47 | mkdir build 48 | cd build 49 | cmake .. -DWX_UI=ON 50 | make 51 | ``` 52 | 53 | Native package: 54 | 55 | ``` 56 | dpkg-buildpackage -rfakeroot -kYOUR_GPG_KEY 57 | ``` 58 | 59 | Tests: 60 | 61 | ``` 62 | cd test 63 | ./test_dae.sh 64 | ./test_json.sh 65 | ``` 66 | 67 | #### Windows 68 | 69 | ``` 70 | # AS ADMIN USER 71 | choco install 7zip.commandline 72 | ``` 73 | 74 | ``` 75 | mkdir wx 76 | cd wx 77 | wget -OutFile wxWidgets-3.0.2_headers.7z https://github.com/wxWidgets/wxWidgets/releases/download/v3.0.2/wxWidgets-3.0.2_headers.7z 78 | wget -OutFile wxMSW-3.0.2_vc120_x64_Dev.7z https://github.com/wxWidgets/wxWidgets/releases/download/v3.0.2/wxMSW-3.0.2_vc120_x64_Dev.7z 79 | # Change vc120 for your Visual Studio version and choose between x86 and x64. 80 | 7z x *.7z 81 | cmake . -G "Visual Studio 12 2013 Win64" -DWX_UI=ON -DwxWidgets_ROOT_DIR="C:\kovel\wx" -DwxWidgets_LIB_DIR="C:\kovel\wx\lib\vc120_x64_dll" && exit 0 82 | ``` 83 | 84 | Open the Visual Studio solution and build ALL_BUILD 85 | 86 | ## Getting it 87 | 88 | Launchpad PPA: 89 | 90 | ``` 91 | sudo add-apt-repository -y ppa:adrian-arroyocalle/kovel 92 | sudo apt update 93 | sudo apt install kovel kovel-cli 94 | ``` 95 | 96 | ## Screenshoots 97 | 98 | ![Kovel Basic](docs/Kovel-1.png) 99 | ![Kovel Blender](docs/BlenderKovel.png) 100 | ![Kovel rotate](docs/KovelRotate.png) 101 | ![Kovel Icon](docs/KovelIcon.png) 102 | 103 | ## Donate 104 | 105 | PayPal: http://paypal.me/aarroyoc 106 | BitCoin: 1A2j8CwiFEhQ4Uycsjhr3gQPbJxFk1LRmM 107 | 108 | ## Command line usage 109 | 110 | |Flag|Description| 111 | |--|-------------| 112 | |-h|Show help| 113 | |-i|Input file| 114 | |-x|Export as (dae,json)| 115 | |-o|Out file| 116 | 117 | Example (export as COLLADA DAE) 118 | ``` 119 | kovelcli -i File.kvl -x dae -o File.dae 120 | ``` 121 | 122 | 123 | 124 | ## Support on Beerpay 125 | Hey dude! Help me out for a couple of :beers:! 126 | 127 | [![Beerpay](https://beerpay.io/AdrianArroyoCalle/kovel/badge.svg?style=beer-square)](https://beerpay.io/AdrianArroyoCalle/kovel) [![Beerpay](https://beerpay.io/AdrianArroyoCalle/kovel/make-wish.svg?style=flat-square)](https://beerpay.io/AdrianArroyoCalle/kovel?focus=wish) -------------------------------------------------------------------------------- /ui/gl/gl1.cpp: -------------------------------------------------------------------------------- 1 | #include "gl1.hpp" 2 | 3 | #include 4 | 5 | GlPreviewer::GlPreviewer() { 6 | } 7 | 8 | void GlPreviewer::DrawCube(unsigned short x, unsigned short y, unsigned short z, 9 | Material mat) { 10 | glBegin(GL_TRIANGLES); 11 | 12 | glColor3f(mat.r, mat.g, mat.b); 13 | 14 | /* First face */ 15 | glVertex3f(0.0 + x, 0.0 + y, 0.0 + z); 16 | glVertex3f(0.0 + x, 1.0 + y, 0.0 + z); 17 | glVertex3f(0.0 + x, 1.0 + y, 1.0 + z); 18 | 19 | glVertex3f(0.0 + x, 0.0 + y, 0.0 + z); 20 | glVertex3f(0.0 + x, 1.0 + y, 1.0 + z); 21 | glVertex3f(0.0 + x, 0.0 + y, 1.0 + z); 22 | 23 | glColor3f(mat.r * 0.6, mat.g * 0.6, mat.b * 0.6); 24 | 25 | /* Third face */ 26 | glVertex3f(1.0 + x, 0.0 + y, 1.0 + z); 27 | glVertex3f(1.0 + x, 0.0 + y, 0.0 + z); 28 | glVertex3f(1.0 + x, 1.0 + y, 0.0 + z); 29 | 30 | glVertex3f(1.0 + x, 0.0 + y, 1.0 + z); 31 | glVertex3f(1.0 + x, 1.0 + y, 1.0 + z); 32 | glVertex3f(1.0 + x, 1.0 + y, 0.0 + z); 33 | 34 | glColor3f(mat.r, mat.g, mat.b); 35 | 36 | /* Forth face */ 37 | glVertex3f(0.0 + x, 0.0 + y, 0.0 + z); 38 | glVertex3f(0.0 + x, 1.0 + y, 0.0 + z); 39 | glVertex3f(1.0 + x, 1.0 + y, 0.0 + z); 40 | 41 | glVertex3f(0.0 + x, 0.0 + y, 0.0 + z); 42 | glVertex3f(1.0 + x, 0.0 + y, 0.0 + z); 43 | glVertex3f(1.0 + x, 1.0 + y, 0.0 + z); 44 | 45 | glColor3f(mat.r * 0.9, mat.g * 0.9, mat.b * 0.9); 46 | 47 | /* Fifth face - Top */ 48 | glVertex3f(0.0 + x, 1.0 + y, 0.0 + z); 49 | glVertex3f(0.0 + x, 1.0 + y, 1.0 + z); 50 | glVertex3f(1.0 + x, 1.0 + y, 1.0 + z); 51 | 52 | glVertex3f(0.0 + x, 1.0 + y, 0.0 + z); 53 | glVertex3f(1.0 + x, 1.0 + y, 0.0 + z); 54 | glVertex3f(1.0 + x, 1.0 + y, 1.0 + z); 55 | 56 | glColor3f(mat.r, mat.g, mat.b); 57 | 58 | /* Sixth face - Bottom*/ 59 | glVertex3f(0.0 + x, 0.0 + y, 0.0 + z); 60 | glVertex3f(0.0 + x, 0.0 + y, 1.0 + z); 61 | glVertex3f(1.0 + x, 0.0 + y, 1.0 + z); 62 | 63 | glVertex3f(0.0 + x, 0.0 + y, 0.0 + z); 64 | glVertex3f(1.0 + x, 0.0 + y, 0.0 + z); 65 | glVertex3f(1.0 + x, 0.0 + y, 1.0 + z); 66 | 67 | glColor3f(mat.r * 0.6, mat.g * 0.6, mat.b * 0.6); 68 | 69 | /* Second face */ 70 | glVertex3f(0.0 + x, 0.0 + y, 1.0 + z); 71 | glVertex3f(1.0 + x, 0.0 + y, 1.0 + z); 72 | glVertex3f(1.0 + x, 1.0 + y, 1.0 + z); 73 | 74 | glVertex3f(0.0 + x, 0.0 + y, 1.0 + z); 75 | glVertex3f(0.0 + x, 1.0 + y, 1.0 + z); 76 | glVertex3f(1.0 + x, 1.0 + y, 1.0 + z); 77 | glEnd(); 78 | } 79 | 80 | void GlPreviewer::Render(int width, int height, Geometry* geo, Material3D mat, 81 | float zoom, float rotation) { 82 | // USE OLD OPENGL 1 code 83 | #ifndef __HAIKU__ 84 | glClearColor(0.0, 0.0, 0.0, 1.0); 85 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 86 | #endif 87 | 88 | glEnable(GL_DEPTH_TEST); 89 | glDepthFunc(GL_LESS); 90 | 91 | glViewport(0, 0, width, height); 92 | 93 | // Isometric 94 | glMatrixMode(GL_PROJECTION); 95 | glLoadIdentity(); 96 | glOrtho(-10.0f + zoom, 10.0f - zoom, -10.0f + zoom, 10.0f - zoom, -10.0f, 97 | 10.0f); 98 | glMatrixMode(GL_MODELVIEW); 99 | glLoadIdentity(); 100 | glRotatef(35.264f, 1.0f, 0.0f, 0.0f); 101 | glRotatef(-45.0f, 0.0f, 1.0f, 0.0f); 102 | 103 | glRotatef(rotation, 0.0f, 1.0f, 0.0f); 104 | 105 | // Draw AXIS 106 | #ifdef __HAIKU__ 107 | glClearColor(0.0, 0.0, 0.0, 1.0); 108 | #endif 109 | // 110 | 111 | glColor3f(1.0, 0.0, 0.0); 112 | 113 | glBegin(GL_LINES); 114 | glVertex3f(0.0, 0.0, 0.0); 115 | glVertex3f(100.0, 0.0, 0.0); 116 | glEnd(); 117 | 118 | glColor3f(0.0, 1.0, 0.0); 119 | 120 | glBegin(GL_LINES); 121 | glVertex3f(0.0, 0.0, 0.0); 122 | glVertex3f(0.0, 100.0, 0.0); 123 | glEnd(); 124 | 125 | glColor3f(0.0, 0.0, 1.0); 126 | 127 | glBegin(GL_LINES); 128 | glVertex3f(0.0, 0.0, 0.0); 129 | glVertex3f(0.0, 0.0, 100.0); 130 | glEnd(); 131 | 132 | for (short i = 0; i < geo->g; i++) { 133 | for (short j = 0; j < geo->g; j++) { 134 | for (short k = 0; k < geo->g; k++) { 135 | if (geo->GetGrid(i, j, k) == 1) { 136 | DrawCube(i, j, k, mat[i][j][k]); 137 | } 138 | } 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /resources/kovel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 40 | 45 | 46 | 48 | 49 | 51 | image/svg+xml 52 | 54 | 55 | 56 | 57 | 58 | 63 | 68 | 73 | 78 | 83 | 88 | 93 | 98 | 103 | 108 | 113 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /resources/kovel.xpm: -------------------------------------------------------------------------------- 1 | /* XPM */ 2 | static char *kovel_xpm[] = { 3 | /* columns rows colors chars-per-pixel */ 4 | "32 32 154 2 ", 5 | " c #000000", 6 | ". c #010000", 7 | "X c #000100", 8 | "o c #010100", 9 | "O c #000001", 10 | "+ c #000101", 11 | "@ c #020000", 12 | "# c #030000", 13 | "$ c #000200", 14 | "% c #000002", 15 | "& c #040000", 16 | "* c #000400", 17 | "= c #000500", 18 | "- c #000600", 19 | "; c #000700", 20 | ": c #000004", 21 | "> c #000005", 22 | ", c #000006", 23 | "< c #000007", 24 | "1 c #0A0000", 25 | "2 c #0C0100", 26 | "3 c #0F0000", 27 | "4 c #000800", 28 | "5 c #000900", 29 | "6 c #000A00", 30 | "7 c #000B00", 31 | "8 c #000C00", 32 | "9 c #000D00", 33 | "0 c #010D00", 34 | "q c #000E00", 35 | "w c #000F00", 36 | "e c #050C00", 37 | "r c #090800", 38 | "t c #000009", 39 | "y c #00000A", 40 | "u c #00000E", 41 | "i c #00000F", 42 | "p c #140000", 43 | "a c #150000", 44 | "s c #160100", 45 | "d c #110400", 46 | "f c #170400", 47 | "g c #190100", 48 | "h c #1C0100", 49 | "j c #1F0100", 50 | "k c #1A0C00", 51 | "l c #160108", 52 | "z c #001100", 53 | "x c #011100", 54 | "c c #001200", 55 | "v c #001300", 56 | "b c #001400", 57 | "n c #011400", 58 | "m c #001500", 59 | "M c #001600", 60 | "N c #001601", 61 | "B c #011504", 62 | "V c #0E1002", 63 | "C c #0A1400", 64 | "Z c #001800", 65 | "A c #001A00", 66 | "S c #001C00", 67 | "D c #001E00", 68 | "F c #121200", 69 | "G c #181400", 70 | "H c #000010", 71 | "J c #000012", 72 | "K c #000013", 73 | "L c #000015", 74 | "P c #000016", 75 | "I c #000017", 76 | "U c #000018", 77 | "Y c #000019", 78 | "T c #00001A", 79 | "R c #00001B", 80 | "E c #00001C", 81 | "W c #01011C", 82 | "Q c #00001D", 83 | "! c #00001F", 84 | "~ c #210000", 85 | "^ c #002100", 86 | "/ c #002400", 87 | "( c #002500", 88 | ") c #002900", 89 | "_ c #002C00", 90 | "` c #002E00", 91 | "' c #002F00", 92 | "] c #003100", 93 | "[ c #003500", 94 | "{ c #003700", 95 | "} c #003800", 96 | "| c #003A00", 97 | " . c #003D00", 98 | ".. c #003E00", 99 | "X. c #003F00", 100 | "o. c #000020", 101 | "O. c #000021", 102 | "+. c #000022", 103 | "@. c #004000", 104 | "#. c #004100", 105 | "$. c #004200", 106 | "%. c #004600", 107 | "&. c #004700", 108 | "*. c #024700", 109 | "=. c #004800", 110 | "-. c #004900", 111 | ";. c #004A00", 112 | ":. c #004B00", 113 | ">. c #004C00", 114 | ",. c #004D00", 115 | "<. c #004E00", 116 | "1. c #004F00", 117 | "2. c #005000", 118 | "3. c #005100", 119 | "4. c #005200", 120 | "5. c #005300", 121 | "6. c #005400", 122 | "7. c #005500", 123 | "8. c #005600", 124 | "9. c #005700", 125 | "0. c #005800", 126 | "q. c #005900", 127 | "w. c #005A00", 128 | "e. c #005B00", 129 | "r. c #045B00", 130 | "t. c #005E00", 131 | "y. c #005F00", 132 | "u. c #006100", 133 | "i. c #006200", 134 | "p. c #006400", 135 | "a. c #006600", 136 | "s. c #006700", 137 | "d. c #006900", 138 | "f. c #006A00", 139 | "g. c #006B00", 140 | "h. c #006C00", 141 | "j. c #006E00", 142 | "k. c #006F00", 143 | "l. c #007100", 144 | "z. c #007200", 145 | "x. c #007400", 146 | "c. c #007500", 147 | "v. c #007600", 148 | "b. c #017600", 149 | "n. c #017700", 150 | "m. c #007800", 151 | "M. c #007C00", 152 | "N. c #007D00", 153 | "B. c #007E00", 154 | "V. c #008000", 155 | "C. c #008100", 156 | "Z. c #008200", 157 | "A. c #008300", 158 | "S. c #008400", 159 | /* pixels */ 160 | " Z c ", 161 | " N c ", 162 | " N w * ", 163 | " N c ", 164 | " Z c / 1.] / ", 165 | " N c a.V.B.z.5 ", 166 | " N c c V.V.V.d.5 ", 167 | " N c N a.x.B.y.5 ", 168 | " N c c 1.1.y.9.5 ", 169 | " N c N 2.-.-.-.w ", 170 | " * B r 1 & N 2.1.1.1.5 * ", 171 | " W l j ~ G 1.-.1.1.e c ) N 5 * ", 172 | " y o. n 1.-.-.1.k ~ ~ j f d -.V.x.z.N ", 173 | " W i N 2.1.1.1.5 & r 3 g r.d.z.a.F a 3 ", 174 | " < o. N 2.-.1.-.w q.j.9.-.1.-.2.C a g ", 175 | " W J N 2.1.1.-.w / x.x.m.2.2.2.-.* ", 176 | " o. N 2.-.-.2.9.| -.2.2.q.-.] @./ ", 177 | " I I c 2.1.-.u.B.V.d.-.1.2.| ", 178 | " o. N 1.1.-.9.q.y.y.@.X.1.N ", 179 | " J W c 2.-.1.-.-.*.1.X./ Z * ", 180 | " o.< N 2.1.-.1.1.2.2.x.x.z.2. ", 181 | " J W N 2.-.1.1.D Z *.j.d.x.1. * ", 182 | " o.y c 1.1.1.-.5 _ 2.-.2.*. ", 183 | " i W N 1.-.1.1.w ] q.2.1.q.a.2.*.w ", 184 | " o.i N 1.-.-.1.w N _ | @.d.m.B.x.N ", 185 | " y W * c 9.2.9.| * 1.9.q.9.c ", 186 | " < W i * D / [ N * -.1.-.1.c ", 187 | " < o. * X.-.2.[ ", 188 | " W J 5 c 5 ", 189 | " o. ", 190 | " W I ", 191 | " W " 192 | }; 193 | -------------------------------------------------------------------------------- /ui/haiku/window.cpp: -------------------------------------------------------------------------------- 1 | #include "../../core/core.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "window.hpp" 10 | #include "preview.hpp" 11 | #include "metadata.hpp" 12 | 13 | #include "../../core/version.hpp" 14 | 15 | BString FILE_PATH; 16 | 17 | uint32 BVIEW_FLAGS = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE; 18 | 19 | const uint32 NEW_FILE = 0, OPEN_FILE = 1, SAVE_FILE = 2, SAVE_FILEAS = 3, 20 | UNDO = 4, CLEARGRID = 5, SELECT_COLOR = 6, UP = 7, DOWN = 8, 21 | RLEFT = 9, RRIGHT = 10; 22 | const uint32 ZOOM_IN = 11, ZOOM_OUT = 12, META = 13, READ_FILE = 14, 23 | SAVE_FILE_DO = 15; 24 | const uint32 EXPORT_DAE = 16, EXPORT_DAE_DO = 17, EXPORT_JSON = 18, 25 | EXPORT_JSON_DO = 19; 26 | 27 | class ToolPanel : public BView { 28 | public: 29 | ToolPanel() : BView(NULL, B_WILL_DRAW) { 30 | SetViewColor(220, 220, 220); 31 | BGroupLayout* sizer = new BGroupLayout(B_VERTICAL); 32 | SetLayout(sizer); 33 | BFont font; 34 | font.SetSize(18.0); 35 | BTextView* header = new BTextView(NULL, B_WILL_DRAW | B_PULSE_NEEDED); 36 | header->SetFont(&font); 37 | sizer->AddView(header); 38 | 39 | SetExplicitMaxSize(BSize(100, 100)); 40 | 41 | /* Colour picker */ 42 | /* BColorControl */ 43 | } 44 | }; 45 | 46 | class GridPanel : public BView { 47 | public: 48 | unsigned short GRID_SIZE = 5; 49 | std::vector> GRID; 50 | short zCoord = 0; 51 | GridPanel() : BView(NULL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE) { 52 | SetViewColor(220, 220, 220); 53 | 54 | GRID.resize(GRID_SIZE); 55 | for (short u = 0; u < GRID_SIZE; u++) { 56 | GRID.at(u).resize(GRID_SIZE); 57 | for (short j = 0; j < GRID_SIZE; j++) { 58 | GRID[u][j] = false; 59 | } 60 | } 61 | SetExplicitMinSize(BSize(100, 100)); 62 | PaintNow(); 63 | } 64 | void PaintNow() { 65 | this->Draw(Bounds()); 66 | } 67 | void Draw(BRect rect) { 68 | SetDrawingMode(B_OP_COPY); 69 | BSize size = Bounds().Size(); 70 | int cellWidth = size.Width() / GRID_SIZE; 71 | int cellHeight = size.Height() / GRID_SIZE; 72 | for (int i = 0; i < GRID_SIZE; i++) { 73 | for (int j = 0; j < GRID_SIZE; j++) { 74 | this->SetHighColor(0, 0, 255); 75 | this->StrokeRect(BRect(i * cellWidth, j * cellHeight, 76 | i * cellWidth + cellWidth, 77 | j * cellHeight + cellHeight)); 78 | if (GRID[i][j]) 79 | this->SetHighColor(0, 220, 220); 80 | else 81 | this->SetHighColor(255, 255, 255); 82 | this->FillRect(BRect((i * cellWidth) + 4, (j * cellHeight) + 4, 83 | (i * cellWidth) + 4 + cellWidth - 8, 84 | (j * cellHeight) + 4 + cellHeight - 8)); 85 | } 86 | } 87 | } 88 | void MouseDown(BPoint point) { 89 | BSize size = this->Bounds().Size(); 90 | int cellWidth = size.Width() / GRID_SIZE; 91 | int cellHeight = size.Height() / GRID_SIZE; 92 | int xCoord = (point.x / cellWidth); 93 | int yCoord = (point.y / cellHeight); 94 | 95 | GRID[xCoord][yCoord] = !GRID[xCoord][yCoord]; 96 | 97 | Core* core = Core::Instance(); 98 | if (GRID[xCoord][yCoord]) { 99 | core->UpdateGrid(1, xCoord, zCoord, yCoord); 100 | } else { 101 | core->UpdateGrid(0, xCoord, zCoord, yCoord); 102 | } 103 | this->PaintNow(); 104 | } 105 | void ReloadWorkGrid(unsigned short g) { 106 | GRID_SIZE = g; 107 | Core* core = Core::Instance(); 108 | 109 | for (int i = 0; i < GRID_SIZE; i++) { 110 | GRID[i].clear(); 111 | } 112 | 113 | GRID.resize(GRID_SIZE); 114 | for (short i = 0; i < GRID_SIZE; i++) { 115 | GRID.at(i).resize(GRID_SIZE); 116 | for (int j = 0; j < GRID_SIZE; j++) { 117 | GRID[i][j] = core->geo->GetGrid(i, zCoord, j); 118 | } 119 | } 120 | this->PaintNow(); 121 | } 122 | void ClearGrid() { 123 | Core* core = Core::Instance(); 124 | for (int i = 0; i < GRID_SIZE; i++) { 125 | for (int j = 0; j < GRID_SIZE; j++) { 126 | core->UpdateGrid(0, i, zCoord, j); 127 | } 128 | } 129 | this->ReloadWorkGrid(GRID_SIZE); 130 | } 131 | void UpButton() { 132 | zCoord++; 133 | if (zCoord == GRID_SIZE) { 134 | zCoord--; 135 | } 136 | this->ReloadWorkGrid(GRID_SIZE); 137 | } 138 | void DownButton() { 139 | zCoord--; 140 | if (zCoord == -1) { 141 | zCoord++; 142 | } 143 | this->ReloadWorkGrid(GRID_SIZE); 144 | } 145 | }; 146 | 147 | GridPanel* workSide; 148 | 149 | class WorkPanel : public BView { 150 | 151 | public: 152 | WorkPanel() : BView(NULL, B_WILL_DRAW) { 153 | SetViewColor(220, 220, 220); 154 | 155 | BGroupLayout* sizer = new BGroupLayout(B_VERTICAL); 156 | BGroupLayout* workToolsSizer = new BGroupLayout(B_HORIZONTAL); 157 | SetLayout(sizer); 158 | 159 | workSide = new GridPanel(); 160 | BView* workTools = new BView(NULL, B_WILL_DRAW); 161 | workTools->SetViewColor(220, 220, 220); 162 | workTools->SetLayout(workToolsSizer); 163 | 164 | BButton* up = new BButton("Up", new BMessage(UP)); 165 | BButton* down = new BButton("Down", new BMessage(DOWN)); 166 | 167 | sizer->AddView(workSide, 3); 168 | sizer->AddView(workTools, 1); 169 | workToolsSizer->AddView(up, 1); 170 | workToolsSizer->AddView(down, 1); 171 | } 172 | void CleanGrid() { 173 | workSide->ClearGrid(); 174 | } 175 | void UpdateGrid(unsigned short g) { 176 | workSide->ReloadWorkGrid(g); 177 | } 178 | }; 179 | 180 | WorkPanel* workTwo; 181 | PreviewPanel* preview; 182 | ToolPanel* tool; 183 | 184 | /* All options */ 185 | /* mime type */ 186 | /* icono */ 187 | /* Graphical glitches */ 188 | 189 | KovelWindow::KovelWindow() 190 | : BWindow(BRect(30, 30, 330, 530), "(new file) -- Kovel - Voxel Editor", 191 | B_TITLED_WINDOW, 0) { 192 | Core* core = Core::Instance(); 193 | 194 | BGroupLayout* sizer = new BGroupLayout(B_HORIZONTAL); 195 | BGroupLayout* mainSizer = new BGroupLayout(B_VERTICAL); 196 | BGroupLayout* workSizer = new BGroupLayout(B_HORIZONTAL); 197 | 198 | BView* panel = new BView(Bounds(), NULL, B_FOLLOW_ALL_SIDES, 199 | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | 200 | B_FRAME_EVENTS | B_DRAW_ON_CHILDREN); 201 | panel->SetViewColor(220, 220, 220); 202 | panel->SetLayout(sizer); 203 | 204 | BView* main = new BView(NULL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | 205 | B_FRAME_EVENTS | B_DRAW_ON_CHILDREN); 206 | main->SetViewColor(220, 220, 220); 207 | main->SetLayout(mainSizer); 208 | tool = new ToolPanel(); 209 | 210 | BView* work = new BView(NULL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | 211 | B_FRAME_EVENTS | B_DRAW_ON_CHILDREN); 212 | work->SetLayout(workSizer); 213 | preview = new PreviewPanel(); 214 | 215 | workTwo = new WorkPanel(); 216 | 217 | workSizer->AddView(workTwo, 1); 218 | 219 | mainSizer->AddView(CreateMenuBar()); 220 | mainSizer->AddView(work, 1); 221 | mainSizer->AddView(preview, 1); 222 | 223 | sizer->AddView(main, 3); 224 | // sizer->AddView(tool,1); 225 | 226 | AddChild(panel); 227 | } 228 | 229 | BMenuBar* KovelWindow::CreateMenuBar() { 230 | /* MenuBar */ 231 | BMenuBar* menuBar = new BMenuBar("MenuBar"); 232 | BMenu* file = new BMenu("File"); 233 | BMenu* edit = new BMenu("Edit"); 234 | BMenu* help = new BMenu("Help"); 235 | 236 | menuBar->AddItem(file); 237 | menuBar->AddItem(edit); 238 | menuBar->AddItem(help); 239 | 240 | BMenuItem* newFile = new BMenuItem("New file", new BMessage(NEW_FILE)); 241 | newFile->SetShortcut('N', B_COMMAND_KEY); 242 | file->AddItem(newFile); 243 | 244 | BMenuItem* openFile = new BMenuItem("Open file...", new BMessage(OPEN_FILE)); 245 | openFile->SetShortcut('O', B_COMMAND_KEY); 246 | file->AddItem(openFile); 247 | 248 | BMenuItem* saveFile = new BMenuItem("Save file...", new BMessage(SAVE_FILE)); 249 | saveFile->SetShortcut('S', B_COMMAND_KEY); 250 | file->AddItem(saveFile); 251 | 252 | file->AddSeparatorItem(); 253 | 254 | BMenuItem* exportDAE = 255 | new BMenuItem("Export as DAE...", new BMessage(EXPORT_DAE)); 256 | file->AddItem(exportDAE); 257 | 258 | BMenuItem* exportJSON = 259 | new BMenuItem("Export as JSON...", new BMessage(EXPORT_JSON)); 260 | file->AddItem(exportJSON); 261 | 262 | file->AddSeparatorItem(); 263 | 264 | BMenuItem* quit = new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED)); 265 | quit->SetShortcut('Q', B_COMMAND_KEY); 266 | file->AddItem(quit); 267 | 268 | BMenuItem* undo = new BMenuItem("Undo", new BMessage(UNDO)); 269 | undo->SetShortcut('Z', B_COMMAND_KEY); 270 | edit->AddItem(undo); 271 | /*BMenuItem* meta=new BMenuItem("Edit metadata",new BMessage(META)); 272 | edit->AddItem(meta);*/ 273 | 274 | BMenuItem* clear = 275 | new BMenuItem("Clear current grid", new BMessage(CLEARGRID)); 276 | edit->AddItem(clear); 277 | /*BMenuItem* select=new BMenuItem("Select colour",new BMessage(SELECT_COLOR)); 278 | edit->AddItem(select);*/ 279 | 280 | BMenuItem* about = 281 | new BMenuItem("About Kovel", new BMessage(B_ABOUT_REQUESTED)); 282 | about->SetTarget(be_app); 283 | help->AddItem(about); 284 | 285 | return menuBar; 286 | } 287 | 288 | void KovelWindow::LoadFile(BString path) { 289 | Core* core = Core::Instance(); 290 | FILE_PATH = path; 291 | core->LoadFile(path.String()); 292 | workTwo->UpdateGrid(core->grid); 293 | this->SetTitle(path.Append(" -- Kovel - Voxel Editor").String()); 294 | } 295 | 296 | bool KovelWindow::QuitRequested() { 297 | be_app_messenger.SendMessage(B_QUIT_REQUESTED); 298 | return BWindow::QuitRequested(); 299 | } 300 | 301 | void KovelWindow::MessageReceived(BMessage* msg) { 302 | Core* core = Core::Instance(); 303 | switch (msg->what) { 304 | case NEW_FILE: { 305 | MetadataDialog* metadata = new MetadataDialog(true); 306 | metadata->Show(); 307 | break; 308 | } 309 | case 666: { 310 | if (msg->GetBool("NEW_FILE", false)) { 311 | core->NewFile(msg->GetInt32("GRID_SIZE", 5)); 312 | this->SetTitle("(new file) -- Kovel - Voxel Editor"); 313 | } 314 | core->name = msg->GetString("NAME", ""); 315 | core->author = msg->GetString("AUTHOR", ""); 316 | workTwo->UpdateGrid(core->grid); 317 | break; 318 | } 319 | case OPEN_FILE: { 320 | BFilePanel* filep = 321 | new BFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL, B_FILE_NODE, 322 | false, new BMessage(READ_FILE)); 323 | filep->Show(); 324 | break; 325 | } 326 | case SAVE_FILE: { 327 | BMessage* mesg = new BMessage(B_SAVE_REQUESTED); 328 | mesg->AddString("TYPE", "KVL"); 329 | BFilePanel* filep = new BFilePanel(B_SAVE_PANEL, new BMessenger(this), NULL, 330 | B_FILE_NODE, false, mesg); 331 | filep->Show(); 332 | break; 333 | } 334 | case EXPORT_DAE: { 335 | BMessage* mesg = new BMessage(B_SAVE_REQUESTED); 336 | mesg->AddString("TYPE", "DAE"); 337 | BFilePanel* filep = new BFilePanel(B_SAVE_PANEL, new BMessenger(this), NULL, 338 | B_FILE_NODE, false, mesg); 339 | filep->Show(); 340 | break; 341 | } 342 | case EXPORT_JSON: { 343 | BMessage* mesg = new BMessage(B_SAVE_REQUESTED); 344 | mesg->AddString("TYPE", "JSON"); 345 | BFilePanel* filep = new BFilePanel(B_SAVE_PANEL, new BMessenger(this), NULL, 346 | B_FILE_NODE, false, mesg); 347 | filep->Show(); 348 | break; 349 | } 350 | case B_SAVE_REQUESTED: { 351 | entry_ref ref; 352 | msg->FindRef("directory", 0, &ref); 353 | BEntry entry(&ref, true); 354 | BPath path; 355 | entry.GetPath(&path); 356 | BString name = msg->FindString("name"); 357 | BString filename = path.Path(); 358 | filename.Append("/"); 359 | filename.Append(name); 360 | BString type = msg->FindString("TYPE"); 361 | if (type == BString("KVL")) { 362 | if (!filename.EndsWith(".kvl")) { 363 | filename.Append(".kvl"); 364 | } 365 | FILE_PATH = filename; 366 | this->SetTitle(FILE_PATH.Append(" -- Kovel -Voxel Editor")); 367 | core->SaveFile(filename.String()); 368 | } 369 | if (type == BString("DAE")) { 370 | if (!filename.EndsWith(".dae")) { 371 | filename.Append(".dae"); 372 | } 373 | core->ExportAsDAE(filename.String()); 374 | } 375 | if (type == BString("JSON")) { 376 | if (!filename.EndsWith(".json")) { 377 | filename.Append(".json"); 378 | } 379 | core->ExportAsJSON(filename.String()); 380 | } 381 | break; 382 | } 383 | case READ_FILE: { 384 | if (msg->HasRef("refs")) { 385 | entry_ref ref; 386 | if (msg->FindRef("refs", 0, &ref) == B_OK) { 387 | BEntry entry(&ref, true); 388 | BPath path; 389 | entry.GetPath(&path); 390 | this->LoadFile(path.Path()); 391 | } 392 | } 393 | break; 394 | } 395 | case UNDO: { 396 | core->Undo(); 397 | workTwo->UpdateGrid(core->grid); 398 | preview->Render(); 399 | break; 400 | } 401 | case UP: { 402 | workSide->UpButton(); 403 | break; 404 | } 405 | case DOWN: { 406 | workSide->DownButton(); 407 | break; 408 | } 409 | case ZOOM_IN: { 410 | preview->zoom += 1.0f; 411 | preview->Render(); 412 | break; 413 | } 414 | case ZOOM_OUT: { 415 | preview->zoom -= 1.0f; 416 | preview->Render(); 417 | break; 418 | } 419 | case RLEFT: { 420 | preview->rotation += 15; 421 | preview->Render(); 422 | break; 423 | } 424 | case RRIGHT: { 425 | preview->rotation -= 15; 426 | preview->Render(); 427 | break; 428 | } 429 | case CLEARGRID: { 430 | workTwo->CleanGrid(); 431 | preview->Render(); 432 | break; 433 | } 434 | case SELECT_COLOR: { 435 | int32 color = msg->FindInt32("be:value"); 436 | color = color / (16 * 16); 437 | float r = ((color >> 16) & 0xFF) / 255.0; 438 | float g = ((color >> 8) & 0xFF) / 255.0; 439 | float b = ((color)&0xFF) / 255.0; 440 | char COLOR_NAME[1024]; 441 | sprintf(COLOR_NAME, "%x", color); 442 | Material mat(COLOR_NAME, r, g, b); 443 | core->SetMaterial(mat); 444 | break; 445 | } 446 | default: 447 | BWindow::MessageReceived(msg); 448 | } 449 | } 450 | 451 | /* Message Queue*/ 452 | -------------------------------------------------------------------------------- /core/core.cpp: -------------------------------------------------------------------------------- 1 | #include "core.hpp" 2 | #include "version.hpp" 3 | 4 | Core* Core::pinstance = 0; 5 | 6 | Core* Core::Instance() { 7 | if (pinstance == 0) { 8 | pinstance = new Core; 9 | } 10 | return pinstance; 11 | } 12 | 13 | Core::Core() { 14 | this->NewFile(5); 15 | } 16 | 17 | Core::~Core() { 18 | // delete geo; 19 | } 20 | 21 | void Core::NewFile(unsigned short g) { 22 | this->grid = g; 23 | // delete geo; 24 | geo = new Geometry(g); 25 | material.clear(); 26 | undo.clear(); 27 | mat.resize(g); 28 | for (short u = 0; u < g; u++) { 29 | mat.at(u).resize(g); 30 | for (short v = 0; v < g; v++) { 31 | mat.at(u)[v].resize(g); 32 | } 33 | } 34 | name = ""; 35 | author = ""; 36 | SetMaterial(currentMat); 37 | } 38 | 39 | void Core::LoadFile(std::string filename) { 40 | std::ifstream file(filename, std::ios::binary); 41 | file.seekg(0, std::ios::end); 42 | std::streamsize size = file.tellg(); 43 | file.seekg(0, std::ios::beg); 44 | 45 | std::vector buffer(size); 46 | if (file.read((char*)(buffer.data()), size)) { 47 | bson_t* doc; 48 | doc = bson_new_from_data(buffer.data(), size); 49 | 50 | short x = 0, y = 0, z = 0; 51 | 52 | bson_iter_t iter; 53 | bson_iter_t materials; 54 | bson_iter_t materialBSON; 55 | bson_iter_t childX; 56 | bson_iter_t childY; 57 | bson_iter_t childZ; 58 | bson_iter_t name; 59 | 60 | bson_iter_t metadata; 61 | bson_iter_t countGrid; 62 | 63 | unsigned short loadedGridSize = 0; 64 | bson_iter_init(&metadata, doc); 65 | bson_iter_find_descendant(&metadata, "voxels", &countGrid); 66 | bson_iter_recurse(&metadata, &countGrid); 67 | while (bson_iter_next(&countGrid)) { 68 | loadedGridSize++; 69 | } 70 | this->NewFile(loadedGridSize); 71 | 72 | // READ METADATA AND GRID SIZE 73 | 74 | bson_iter_init(&iter, doc); 75 | 76 | bson_iter_find_descendant(&iter, "metadata", &name); 77 | bson_iter_recurse(&iter, &name); 78 | while (bson_iter_next(&name)) { 79 | if (strcmp(bson_iter_key(&name), "name") == 0) { 80 | uint32_t length; 81 | this->name = bson_iter_utf8(&name, &length); 82 | } 83 | if (strcmp(bson_iter_key(&name), "creator") == 0) { 84 | uint32_t length; 85 | this->author = bson_iter_utf8(&name, &length); 86 | } 87 | } 88 | 89 | // Materials 90 | bson_iter_find_descendant(&iter, "materials", &materials); 91 | bson_iter_recurse(&iter, &materials); 92 | material.clear(); 93 | while (bson_iter_next(&materials)) { 94 | std::string matName = bson_iter_key(&materials); 95 | Material mat(matName); 96 | bson_iter_recurse(&materials, &materialBSON); 97 | while (bson_iter_next(&materialBSON)) { 98 | if (strcmp(bson_iter_key(&materialBSON), "red") == 0) { 99 | mat.r = bson_iter_double(&materialBSON); 100 | } 101 | if (strcmp(bson_iter_key(&materialBSON), "green") == 0) { 102 | mat.g = bson_iter_double(&materialBSON); 103 | } 104 | if (strcmp(bson_iter_key(&materialBSON), "blue") == 0) { 105 | mat.b = bson_iter_double(&materialBSON); 106 | } 107 | } 108 | material.insert({matName, mat}); 109 | } 110 | 111 | // Voxels 112 | bson_iter_find_descendant(&iter, "voxels", &childX); 113 | bson_iter_recurse(&iter, &childX); 114 | while (bson_iter_next(&childX)) { 115 | bson_iter_recurse(&childX, &childY); 116 | while (bson_iter_next(&childY)) { 117 | bson_iter_recurse(&childY, &childZ); 118 | while (bson_iter_next(&childZ)) { 119 | if (bson_iter_type(&childZ) == BSON_TYPE_NULL) { 120 | this->geo->SetGrid(0, x, y, z); 121 | } 122 | if (bson_iter_type(&childZ) == BSON_TYPE_DOCUMENT) { 123 | this->geo->SetGrid(1, x, y, z); 124 | bson_iter_t voxelObject; 125 | bson_iter_recurse(&childZ, &voxelObject); 126 | while (bson_iter_next(&voxelObject)) { 127 | if (strcmp(bson_iter_key(&voxelObject), "material") == 0) { 128 | uint32_t length; 129 | std::string matName = bson_iter_utf8(&voxelObject, &length); 130 | mat[x][y][z] = material[matName]; 131 | } 132 | } 133 | } 134 | z++; 135 | } 136 | z = 0; 137 | y++; 138 | } 139 | y = 0; 140 | x++; 141 | } 142 | } 143 | } 144 | 145 | void Core::SaveFile(std::string filename) { 146 | // Dump grid to File 147 | bson_init(&kovel); 148 | 149 | // METADATA 150 | bson_t metadata; 151 | bson_append_document_begin(&kovel, "metadata", -1, &metadata); 152 | BSON_APPEND_UTF8(&metadata, "name", this->name.c_str()); 153 | BSON_APPEND_UTF8(&metadata, "creator", this->author.c_str()); 154 | BSON_APPEND_UTF8(&metadata, "date", ""); 155 | BSON_APPEND_UTF8(&metadata, "version", KOVEL_VERSION); 156 | bson_append_document_end(&kovel, &metadata); 157 | 158 | // MATERIALS 159 | 160 | bson_t materials; 161 | bson_append_document_begin(&kovel, "materials", -1, &materials); 162 | 163 | for (auto kv : material) { 164 | bson_t materialBSON; 165 | Material mat = kv.second; 166 | bson_append_document_begin(&materials, mat.name.c_str(), -1, &materialBSON); 167 | BSON_APPEND_DOUBLE(&materialBSON, "red", mat.r); 168 | BSON_APPEND_DOUBLE(&materialBSON, "green", mat.g); 169 | BSON_APPEND_DOUBLE(&materialBSON, "blue", mat.b); 170 | bson_append_document_end(&materials, &materialBSON); 171 | } 172 | 173 | bson_append_document_end(&kovel, &materials); 174 | 175 | // VOXELS 176 | bson_t voxels; 177 | bson_append_array_begin(&kovel, "voxels", -1, &voxels); 178 | for (int i = 0; i < this->grid; i++) { 179 | bson_t voxelY; 180 | bson_append_array_begin(&voxels, "VoxelY", -1, &voxelY); 181 | for (int j = 0; j < this->grid; j++) { 182 | bson_t voxelZ; 183 | bson_append_array_begin(&voxelY, "VoxelZ", -1, &voxelZ); 184 | for (int k = 0; k < this->grid; k++) { 185 | bson_t voxelObject; 186 | if (this->geo->GetGrid(i, j, k) == 1) { 187 | bson_append_document_begin(&voxelZ, "VoxelObject", -1, &voxelObject); 188 | bson_append_utf8(&voxelObject, "material", -1, 189 | mat[i][j][k].name.c_str(), -1); 190 | bson_append_document_end(&voxelZ, &voxelObject); 191 | } else { 192 | bson_append_null(&voxelZ, "NULL", -1); 193 | } 194 | } 195 | bson_append_array_end(&voxelY, &voxelZ); 196 | } 197 | 198 | bson_append_array_end(&voxels, &voxelY); 199 | } 200 | bson_append_array_end(&kovel, &voxels); 201 | 202 | // Validate and Write 203 | if (this->ValidateFile()) { 204 | std::ofstream outfile; 205 | outfile.open(filename, std::ios::binary | std::ios::out); 206 | 207 | outfile.write((char*)bson_get_data(&kovel), kovel.len); 208 | 209 | outfile.close(); 210 | } else { 211 | std::cerr << "ERROR: Kovel file was badformed" << std::endl; 212 | } 213 | } 214 | 215 | bool Core::ValidateFile() { 216 | size_t offset; 217 | if (bson_validate(&kovel, BSON_VALIDATE_UTF8_ALLOW_NULL, &offset)) { 218 | return true; 219 | } else { 220 | return false; 221 | } 222 | } 223 | 224 | bool Core::ExportAsJSON(std::string filename) { 225 | if (this->ValidateFile()) { 226 | std::ofstream outfile; 227 | outfile.open(filename, std::ios::out); 228 | outfile << bson_as_json(&kovel, NULL); 229 | outfile.close(); 230 | return true; 231 | } else { 232 | return false; 233 | } 234 | } 235 | 236 | bool Core::ExportAsDAE(std::string filename) { 237 | std::ofstream ss; 238 | ss.open(filename, std::ios::out); 239 | ss << ""; 240 | ss << ""; 242 | ss << ""; 243 | ss << ""; 244 | ss << ""; 245 | ss << "Kovel User"; 246 | ss << ""; 247 | ss << ""; 248 | ss << "Kovel " << KOVEL_VERSION; 249 | ss << ""; 250 | ss << ""; 251 | ss << ""; 252 | ss << "Y_UP"; 253 | ss << ""; 254 | ss << ""; 255 | ss << ""; 256 | 257 | ss << ""; 258 | ss << ""; 259 | ss << ""; 260 | ss << ""; 261 | ss << "1 1 -1 1 " 262 | "-1 -1 -1 -0.9999998 -1 -0.9999997 1 -1 1 0.9999995 1 0.9999994 " 263 | "-1.000001 1 -1 -0.9999997 1 -1 1 1"; 264 | ss << ""; 265 | ss << ""; 267 | ss << ""; 268 | ss << ""; 269 | ss << ""; 270 | ss << ""; 271 | ss << ""; 272 | ss << ""; 273 | ss << ""; 274 | ss << "0 0 -1 0 0 1 " 275 | "1 -5.96046e-7 3.27825e-7 -4.76837e-7 -1 0 -1 2.38419e-7 -1.19209e-7 " 276 | "2.08616e-7 1 0 0 0 -1 0 0 1 1 0 -2.38419e-7 0 -1 -4.76837e-7 -1 " 277 | "2.38419e-7 -1.49012e-7 2.68221e-7 1 2.38419e-7"; 278 | ss << ""; 279 | ss << ""; 281 | ss << ""; 282 | ss << ""; 283 | ss << ""; 284 | ss << ""; 285 | ss << ""; 286 | ss << ""; 287 | ss << ""; 288 | ss << ""; 289 | ss << ""; 290 | ss << ""; 291 | ss << ""; 293 | ss << ""; 295 | ss << "3 3 3 3 3 3 3 3 3 3 3 3 "; 296 | ss << "

0 0 1 0 2 0 7 1 6 1 5 1 4 2 5 2 1 2 5 3 6 3 2 3 2 4 6 4 7 4 0 5 3 " 297 | "5 7 5 3 6 0 6 2 6 4 7 7 7 5 7 0 8 4 8 1 8 1 9 5 9 2 9 3 10 2 10 7 10 " 298 | "4 11 0 11 7 11

"; 299 | ss << "
"; 300 | ss << "
"; 301 | ss << "
"; 302 | ss << "
"; 303 | 304 | ss << ""; 305 | for (auto kv : material) { 306 | Material mat = kv.second; 307 | std::string str = mat.name; 308 | str.erase(std::remove(str.begin(), str.end(), ' '), str.end()); 309 | ss << ""; 310 | ss << ""; 311 | ss << ""; 312 | ss << ""; 313 | ss << ""; 314 | ss << "0 0 0 1"; 315 | ss << ""; 316 | ss << ""; 317 | ss << "0 0 0 1"; 318 | ss << ""; 319 | ss << ""; 320 | ss << "" << mat.r << " " << mat.g << " " << mat.b 321 | << " 1"; 322 | ss << ""; 323 | ss << ""; 324 | ss << "0.5 0.5 0.5 1"; 325 | ss << ""; 326 | ss << ""; 327 | ss << "50"; 328 | ss << ""; 329 | ss << ""; 330 | ss << "1"; 331 | ss << ""; 332 | ss << ""; 333 | ss << ""; 334 | ss << ""; 335 | ss << ""; 336 | } 337 | ss << ""; 338 | 339 | ss << ""; 340 | for (auto kv : material) { 341 | Material mat = kv.second; 342 | std::string str = mat.name; 343 | str.erase(std::remove(str.begin(), str.end(), ' '), str.end()); 344 | ss << ""; 345 | ss << ""; 346 | ss << ""; 347 | } 348 | ss << ""; 349 | 350 | ss << ""; 351 | ss << ""; 352 | for (int i = 0; i < this->grid; i++) { 353 | for (int j = 0; j < this->grid; j++) { 354 | for (int k = 0; k < this->grid; k++) { 355 | if (this->geo->GetGrid(i, j, k) == 1) { 356 | ss << ""; 357 | ss << ""; 358 | ss << "1 0 0 " << i * 2 << " 0 1 0 " << j * 2 << " 0 0 1 " << k * 2 359 | << " 0 0 0 1"; 360 | ss << ""; 361 | 362 | ss << ""; 363 | ss << ""; 364 | ss << ""; 365 | std::string str = mat[i][j][k].name; 366 | str.erase(std::remove(str.begin(), str.end(), ' '), str.end()); 367 | ss << ""; 369 | ss << ""; 370 | ss << ""; 371 | ss << ""; 372 | ss << ""; 373 | } 374 | } 375 | } 376 | } 377 | ss << ""; 378 | ss << ""; 379 | 380 | ss << ""; 381 | ss << ""; 382 | ss << ""; 383 | ss << "
"; 384 | 385 | ss.close(); 386 | 387 | return true; 388 | } 389 | 390 | void Core::UpdateMetadata() { 391 | } 392 | 393 | void Core::Undo() { 394 | if (undo.size() < 1) { 395 | return; 396 | } 397 | struct Undo u = undo.back(); 398 | undo.pop_back(); 399 | geo->SetGrid(u.value, u.x, u.y, u.z); 400 | mat[u.x][u.y][u.z] = u.material; 401 | } 402 | 403 | void Core::UpdateGrid(unsigned short value, unsigned short x, unsigned short y, 404 | unsigned short z) { 405 | // Save state to Undo 406 | 407 | struct Undo u; 408 | u.value = geo->GetGrid(x, y, z); 409 | u.x = x; 410 | u.y = y; 411 | u.z = z; 412 | u.material = mat[x][y][z]; 413 | undo.push_back(u); 414 | 415 | // Modify Geo 416 | geo->SetGrid(value, x, y, z); 417 | mat[x][y][z] = currentMat; 418 | } 419 | 420 | void Core::SetMaterial(Material mat) { 421 | // Check if already exists, otherwise, push it 422 | std::string matName = mat.name; 423 | if (material.find(matName) == material.end()) { 424 | // Doesn't exist 425 | material.insert({matName, mat}); 426 | } 427 | 428 | // Find and change to current material 429 | currentMat = material[matName]; 430 | } 431 | -------------------------------------------------------------------------------- /ui/wx/window.cpp: -------------------------------------------------------------------------------- 1 | #include "../../core/core.hpp" 2 | 3 | #include "wx/wx.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "window.hpp" 10 | #include "preview.hpp" 11 | #include "metadata.hpp" 12 | 13 | #include "../../core/version.hpp" 14 | 15 | wxColourPickerCtrl* picker; 16 | wxString FILE_PATH; 17 | 18 | class ToolPanelOld : public wxPanel { 19 | public: 20 | ToolPanelOld(wxWindow* parent) : wxPanel(parent, wxID_ANY) { 21 | 22 | // Maybe wxGrid here for buttons with pictures? 23 | wxGridSizer* grid = new wxGridSizer(16, 2, 5, 5); 24 | 25 | // GRID SIZER - TODO 26 | 27 | wxButton* newFile = new wxButton(this, wxID_ANY, "New file"); 28 | wxButton* openFile = new wxButton(this, -1, "Open file"); 29 | wxButton* saveFile = new wxButton(this, -1, "Save file"); 30 | wxButton* saveFileAs = new wxButton(this, -1, "Save file as..."); 31 | 32 | grid->Add(newFile, 0, wxEXPAND); 33 | grid->Add(openFile, 0, wxEXPAND); 34 | grid->Add(saveFile, 0, wxEXPAND); 35 | grid->Add(saveFileAs, 0, wxEXPAND); 36 | grid->Add(new wxStaticText(this, -1, ""), 0, wxEXPAND); 37 | grid->Add(new wxStaticText(this, -1, ""), 0, wxEXPAND); 38 | 39 | SetSizer(grid); 40 | SetMinSize(wxSize(100, 400)); 41 | } 42 | }; 43 | 44 | class ToolPanel : public wxPanel { 45 | public: 46 | ToolPanel(wxWindow* parent) : wxPanel(parent, wxID_ANY) { 47 | wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); 48 | wxStaticText* header = new wxStaticText(this, wxID_ANY, "Material"); 49 | wxFont font = header->GetFont(); 50 | font.SetPointSize(18); 51 | header->SetFont(font); 52 | sizer->Add(header, 0, wxEXPAND | wxALL); 53 | picker = new wxColourPickerCtrl(this, wxID_ANY, *wxYELLOW); 54 | sizer->Add(picker, 0, wxEXPAND | wxALL); 55 | picker->Bind( 56 | wxEVT_COLOURPICKER_CHANGED, [this](wxColourPickerEvent&) -> void { 57 | wxColour color = picker->GetColour(); 58 | Core* core = Core::Instance(); 59 | float r = ((float)color.Red()) / 255; 60 | float g = ((float)color.Green()) / 255; 61 | float b = ((float)color.Blue()) / 255; 62 | Material mat(color.GetAsString().ToStdString(), r, g, b); 63 | core->SetMaterial(mat); 64 | }, wxID_ANY); 65 | 66 | wxStaticLine* line = new wxStaticLine(this); 67 | sizer->Add(line, 0, wxEXPAND | wxALL); 68 | 69 | /* Texture selector will be here */ 70 | 71 | SetSizer(sizer); 72 | } 73 | }; 74 | 75 | class GridPanel : public wxPanel { 76 | public: 77 | unsigned short GRID_SIZE = 5; // 16 might be the maximum 78 | std::vector> GRID; 79 | short zCoord = 0; 80 | GridPanel(wxWindow* parent) : wxPanel(parent, wxID_ANY) { 81 | GRID.resize(GRID_SIZE); 82 | for (short u = 0; u < GRID_SIZE; u++) { 83 | GRID.at(u).resize(GRID_SIZE); 84 | for (int j = 0; j < GRID_SIZE; j++) { 85 | GRID[u][j] = false; 86 | } 87 | } 88 | SetSize(100, 100); 89 | PaintNow(); 90 | 91 | Bind(wxEVT_PAINT, &GridPanel::Paint, this, -1); 92 | Bind(wxEVT_LEFT_DOWN, &GridPanel::Click, this, -1); 93 | } 94 | ~GridPanel() { 95 | } 96 | void PaintNow() { 97 | wxClientDC dc(this); 98 | this->Render(dc); 99 | } 100 | void Render(wxDC& dc) { 101 | dc.SetPen(*wxTRANSPARENT_PEN); 102 | 103 | wxSize size = this->GetSize(); 104 | int cellWidth = size.GetWidth() / GRID_SIZE; 105 | int cellHeight = size.GetHeight() / GRID_SIZE; 106 | for (int i = 0; i < GRID_SIZE; i++) { 107 | for (int j = 0; j < GRID_SIZE; j++) { 108 | dc.SetBrush(*wxBLUE_BRUSH); 109 | dc.DrawRectangle(i * cellWidth, j * cellHeight, cellWidth, cellHeight); 110 | if (GRID[i][j]) 111 | dc.SetBrush(*wxCYAN_BRUSH); 112 | else 113 | dc.SetBrush(*wxWHITE_BRUSH); 114 | dc.DrawRectangle((i * cellWidth) + 2, (j * cellHeight) + 2, 115 | cellWidth - 4, cellHeight - 4); 116 | } 117 | } 118 | } 119 | void Click(wxMouseEvent& event) { 120 | wxClientDC dc(this); 121 | 122 | wxPoint point = event.GetLogicalPosition(dc); 123 | 124 | wxSize size = this->GetSize(); 125 | int cellWidth = size.GetWidth() / GRID_SIZE; 126 | int cellHeight = size.GetHeight() / GRID_SIZE; 127 | int xCoord = (point.x / cellWidth); 128 | int yCoord = (point.y / cellHeight); 129 | 130 | GRID[xCoord][yCoord] = !GRID[xCoord][yCoord]; 131 | 132 | Core* core = Core::Instance(); 133 | if (GRID[xCoord][yCoord]) { 134 | core->UpdateGrid(1, xCoord, zCoord, yCoord); 135 | } else { 136 | core->UpdateGrid(0, xCoord, zCoord, yCoord); 137 | } 138 | // Update preview 139 | 140 | this->PaintNow(); 141 | } 142 | void Paint(wxPaintEvent& event) { 143 | wxPaintDC dc(this); 144 | this->Render(dc); 145 | } 146 | void ReloadWorkGrid(unsigned short g) { 147 | GRID_SIZE = g; 148 | Core* core = Core::Instance(); 149 | 150 | for (int i = 0; i < GRID_SIZE; i++) { 151 | GRID[i].clear(); 152 | } 153 | 154 | GRID.resize(GRID_SIZE); 155 | for (short i = 0; i < GRID_SIZE; i++) { 156 | GRID.at(i).resize(GRID_SIZE); 157 | for (int j = 0; j < GRID_SIZE; j++) { 158 | GRID[i][j] = core->geo->GetGrid(i, zCoord, j); 159 | } 160 | } 161 | this->PaintNow(); 162 | } 163 | void ClearGrid() { 164 | Core* core = Core::Instance(); 165 | for (int i = 0; i < GRID_SIZE; i++) { 166 | for (int j = 0; j < GRID_SIZE; j++) { 167 | core->UpdateGrid(0, i, zCoord, j); 168 | } 169 | } 170 | this->ReloadWorkGrid(GRID_SIZE); 171 | } 172 | void UpButton(wxCommandEvent& event) { 173 | zCoord++; 174 | if (zCoord == GRID_SIZE) { 175 | zCoord--; 176 | } 177 | this->ReloadWorkGrid(GRID_SIZE); 178 | } 179 | void DownButton(wxCommandEvent& event) { 180 | zCoord--; 181 | if (zCoord == -1) { 182 | zCoord++; 183 | } 184 | this->ReloadWorkGrid(GRID_SIZE); 185 | } 186 | }; 187 | 188 | class WorkPanel : public wxPanel { 189 | public: 190 | GridPanel* workSide; 191 | WorkPanel(wxWindow* parent) : wxPanel(parent, wxID_ANY) { 192 | workSide = new GridPanel(this); 193 | wxPanel* workTools = new wxPanel(this, wxID_ANY); 194 | 195 | wxButton* up = new wxButton(workTools, wxID_ANY, "Up"); 196 | up->Bind(wxEVT_BUTTON, &GridPanel::UpButton, workSide, -1); 197 | wxButton* down = new wxButton(workTools, wxID_ANY, "Down"); 198 | down->Bind(wxEVT_BUTTON, &GridPanel::DownButton, workSide, -1); 199 | 200 | wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); 201 | sizer->Add(workSide, 3, wxALIGN_CENTER | wxSHAPED); 202 | sizer->Add(workTools, 1, wxEXPAND | wxALL); 203 | SetSizer(sizer); 204 | 205 | wxBoxSizer* workToolsSizer = new wxBoxSizer(wxHORIZONTAL); 206 | workToolsSizer->Add(up, 1, wxEXPAND | wxALL, 5); 207 | workToolsSizer->Add(down, 1, wxEXPAND | wxALL, 5); 208 | workTools->SetSizer(workToolsSizer); 209 | } 210 | void CleanGrid(wxCommandEvent& evt) { 211 | workSide->ClearGrid(); 212 | } 213 | void UpdateGrid(unsigned short g) { 214 | workSide->ReloadWorkGrid(g); 215 | } 216 | }; 217 | 218 | WorkPanel* workTwo; 219 | 220 | MainWindow::MainWindow() 221 | : wxFrame(NULL, -1, "(new file) -- Kovel - Voxel Editor", wxDefaultPosition, 222 | wxSize(800, 600), wxDEFAULT_FRAME_STYLE) { 223 | Core* core = Core::Instance(); 224 | 225 | wxPanel* panel = new wxPanel(this, wxID_ANY); 226 | 227 | wxPanel* main = new wxPanel(panel, wxID_ANY); 228 | ToolPanel* tool = new ToolPanel(panel); 229 | 230 | wxPanel* work = new wxPanel(main, wxID_ANY); 231 | PreviewPanel* preview = new PreviewPanel(main); 232 | 233 | WorkPanel* workOne = new WorkPanel(work); 234 | workTwo = new WorkPanel(work); 235 | WorkPanel* workThree = new WorkPanel(work); 236 | 237 | wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); 238 | sizer->Add(main, 3, wxEXPAND | wxALL); 239 | sizer->Add(tool, 1, wxEXPAND | wxALL); 240 | panel->SetSizer(sizer); 241 | 242 | wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); 243 | mainSizer->Add(work, 1, wxEXPAND | wxALL); 244 | mainSizer->Add(preview, 1, wxEXPAND | wxALL); 245 | main->SetSizer(mainSizer); 246 | 247 | wxBoxSizer* workSizer = new wxBoxSizer(wxHORIZONTAL); 248 | // workSizer->Add(workOne,1,wxEXPAND | wxALL,5); 249 | workSizer->Add(workTwo, 1, wxEXPAND | wxALL, 5); 250 | // workSizer->Add(workThree,1,wxEXPAND | wxALL,5); 251 | work->SetSizer(workSizer); 252 | 253 | // COMPLETE OPTIONS BAR - Done 254 | 255 | // Grid Size - Done 256 | 257 | // Read metadata - Done 258 | 259 | // Command Line Tool - Done 260 | 261 | // TEMP FOLDER - Done 262 | 263 | // Widget showing Y level 264 | 265 | // Zoom indicator - Done 266 | 267 | // Zoom button - Done 268 | 269 | // FIX BUGS (First Material) - Done 270 | 271 | // Export as JSON - Done 272 | 273 | // Export as DAE - Done 274 | 275 | // Open with MIME TYPE Double Click 276 | 277 | // - Mime Type - WINDOWS 278 | 279 | // - Command Line Interface - Done 280 | 281 | // Icon - WINDOWS 282 | 283 | // Capturas de pantalla - Done 284 | 285 | // Marketing 286 | 287 | // homepage - Done 288 | 289 | // homepage en español 290 | 291 | // DesdeLinux 292 | 293 | // Download links 294 | 295 | // Blog 296 | 297 | // Documentación man page - Done 298 | 299 | // Packaging (Debian, DESKTOP file, Windows MSI, Reg for MIME TYPE and 300 | // actions) 301 | 302 | // AND PUBLISH 1.0 303 | 304 | // In a future 305 | 306 | // Translation 307 | 308 | // (Three panels?) 309 | 310 | // Panel color 311 | 312 | // GLES 2.0 render 313 | 314 | // Haiku UI 315 | 316 | // Android UI 317 | 318 | // QML/Ubuntu UI 319 | 320 | // Textures 321 | 322 | // Custom mesh 323 | 324 | // MenuBar 325 | wxMenuBar* menuBar = new wxMenuBar; 326 | 327 | wxMenu* file = new wxMenu; 328 | wxMenuItem* newFile = new wxMenuItem(file, wxID_NEW, "&New file"); 329 | file->Append(newFile); 330 | Bind(wxEVT_MENU, [core, this](wxCommandEvent&) -> void { 331 | MetadataDialog* metadata = new MetadataDialog(this, true); 332 | if (metadata->ShowModal() == wxID_CANCEL) 333 | return; 334 | // wxMessageBox(wxString::FromUTF8(metadata->author.c_str())); 335 | core->NewFile(metadata->gridSize); 336 | core->name = metadata->name; 337 | core->author = metadata->author; 338 | workTwo->UpdateGrid(core->grid); 339 | this->SetLabel("(new file) -- Kovel - Voxel Editor"); 340 | }, wxID_NEW); 341 | 342 | file->Append(wxID_OPEN, "&Open file"); 343 | Bind(wxEVT_MENU, [this](wxCommandEvent&) -> void { 344 | wxFileDialog* fileDlg = new wxFileDialog(this, "Open Kovel file", "", "", 345 | "Kovel files (*.kvl)|*.kvl", 346 | wxFD_OPEN | wxFD_FILE_MUST_EXIST); 347 | if (fileDlg->ShowModal() == wxID_CANCEL) 348 | return; 349 | this->LoadFile(fileDlg->GetPath()); 350 | }, wxID_OPEN); 351 | 352 | wxMenuItem* saveFile = new wxMenuItem(file, wxID_SAVE, "&Save file"); 353 | file->Append(saveFile); 354 | Bind(wxEVT_MENU, [core, this](wxCommandEvent&) -> void { 355 | if (this->GetLabel().StartsWith("(new file)")) { 356 | wxFileDialog* fileDlg = new wxFileDialog( 357 | this, "Save Kovel file", "", "", "Kovel file (*.kvl)|*.kvl", 358 | wxFD_SAVE | wxFD_OVERWRITE_PROMPT); 359 | if (fileDlg->ShowModal() == wxID_CANCEL) 360 | return; 361 | FILE_PATH = fileDlg->GetPath(); 362 | if (!FILE_PATH.EndsWith(".kvl")) 363 | FILE_PATH.Append(".kvl"); 364 | core->SaveFile(FILE_PATH.ToStdString()); 365 | this->SetLabel(FILE_PATH + " -- Kovel - Voxel Editor"); 366 | } else { 367 | core->SaveFile(FILE_PATH.ToStdString()); 368 | } 369 | }, wxID_SAVE); 370 | 371 | file->Append(wxID_SAVEAS, "Save file as..."); 372 | Bind(wxEVT_MENU, [core, this](wxCommandEvent&) -> void { 373 | wxFileDialog* fileDlg = new wxFileDialog(this, "Save Kovel file", "", "", 374 | "Kovel file (*.kvl)|*.kvl", 375 | wxFD_SAVE | wxFD_OVERWRITE_PROMPT); 376 | if (fileDlg->ShowModal() == wxID_CANCEL) 377 | return; 378 | FILE_PATH = fileDlg->GetPath(); 379 | if (!FILE_PATH.EndsWith(".kvl")) 380 | FILE_PATH.Append(".kvl"); 381 | core->SaveFile(FILE_PATH.ToStdString()); 382 | this->SetLabel(FILE_PATH + " -- Kovel - Voxel Editor"); 383 | }, wxID_SAVEAS); 384 | 385 | file->AppendSeparator(); 386 | 387 | /* EXPORT */ 388 | 389 | file->Append(63, "Export as JSON..."); 390 | Bind(wxEVT_MENU, [core, this](wxCommandEvent&) -> void { 391 | wxFileDialog* fileDlg = new wxFileDialog(this, "Save JSON file", "", "", 392 | "JSON file (*.json)|*.json", 393 | wxFD_SAVE | wxFD_OVERWRITE_PROMPT); 394 | if (fileDlg->ShowModal() == wxID_CANCEL) 395 | return; 396 | wxString jsonPath = fileDlg->GetPath(); 397 | if (!jsonPath.EndsWith(".json")) 398 | jsonPath.Append(".json"); 399 | bool ret = core->ExportAsJSON(jsonPath.ToStdString()); 400 | if (!ret) 401 | wxMessageBox("Please, save your file first", "Error", 402 | wxOK | wxICON_ERROR); 403 | }, 63); 404 | 405 | file->Append(64, "Export as Collada DAE..."); 406 | Bind(wxEVT_MENU, [core, this](wxCommandEvent&) -> void { 407 | wxFileDialog* fileDlg = new wxFileDialog(this, "Save Collada DAE file", "", 408 | "", "Collada DAE (*.dae)|*.dae", 409 | wxFD_SAVE | wxFD_OVERWRITE_PROMPT); 410 | if (fileDlg->ShowModal() == wxID_CANCEL) 411 | return; 412 | wxString daePath = fileDlg->GetPath(); 413 | if (!daePath.EndsWith(".dae")) 414 | daePath.Append(".dae"); 415 | bool ret = core->ExportAsDAE(daePath.ToStdString()); 416 | if (!ret) 417 | wxMessageBox("Please, save your file first", "Error", 418 | wxOK | wxICON_ERROR); 419 | }, 64); 420 | 421 | file->AppendSeparator(); 422 | 423 | wxMenuItem* exit = new wxMenuItem(file, wxID_EXIT, "&Exit"); 424 | file->Append(exit); 425 | Bind(wxEVT_MENU, [this](wxCommandEvent&) -> void { this->Close(); }, 426 | wxID_EXIT); 427 | menuBar->Append(file, "&File"); 428 | 429 | wxMenu* edit = new wxMenu; 430 | edit->Append(wxID_UNDO, "&Undo\tCtrl-Z"); 431 | Bind(wxEVT_MENU, [core](wxCommandEvent&) -> void { 432 | core->Undo(); 433 | workTwo->UpdateGrid(core->grid); 434 | }, wxID_UNDO); 435 | 436 | edit->AppendSeparator(); 437 | edit->Append(65, "Edit &metadata"); 438 | Bind(wxEVT_MENU, [this, core](wxCommandEvent&) -> void { 439 | MetadataDialog* metadata = new MetadataDialog(this, false); 440 | if (metadata->ShowModal() == wxID_CANCEL) 441 | return; 442 | core->name = metadata->name; 443 | core->author = metadata->author; 444 | }, 65); 445 | wxMenuItem* clearWorkGrid = new wxMenuItem(edit, 66, "Clear work grid"); 446 | edit->Append(clearWorkGrid); 447 | Bind(wxEVT_MENU, &WorkPanel::CleanGrid, workTwo, 66); 448 | wxMenuItem* selectColor = new wxMenuItem(edit, 67, "Select colour"); 449 | edit->Append(selectColor); 450 | Bind(wxEVT_MENU, [this](wxCommandEvent&) -> void { 451 | // Color picker 452 | wxColourDialog* clrDlg = new wxColourDialog(this); 453 | if (clrDlg->ShowModal() == wxID_OK) { 454 | wxColourData& clrData = clrDlg->GetColourData(); // FILL THIS 455 | wxColour& color = clrData.GetColour(); 456 | picker->SetColour(color); 457 | Core* core = Core::Instance(); 458 | float r = ((float)color.Red()) / 255; 459 | float g = ((float)color.Green()) / 255; 460 | float b = ((float)color.Blue()) / 255; 461 | Material mat(color.GetAsString().ToStdString(), r, g, b); 462 | core->SetMaterial(mat); 463 | } 464 | }, 67); 465 | menuBar->Append(edit, "&Edit"); 466 | 467 | wxMenu* navigate = new wxMenu; 468 | navigate->Append(68, "Zoom &in"); 469 | Bind(wxEVT_MENU, 470 | [preview](wxCommandEvent&) -> void { preview->zoom += 1.0f; }, 68); 471 | navigate->Append(69, "Zoom &out"); 472 | Bind(wxEVT_MENU, 473 | [preview](wxCommandEvent&) -> void { preview->zoom -= 1.0f; }, 69); 474 | navigate->AppendSeparator(); 475 | navigate->Append(70, "Rotate left"); 476 | Bind(wxEVT_MENU, 477 | [preview](wxCommandEvent&) -> void { preview->rotation += 15; }, 70); 478 | navigate->Append(71, "Rotate right"); 479 | Bind(wxEVT_MENU, 480 | [preview](wxCommandEvent&) -> void { preview->rotation -= 15; }, 71); 481 | menuBar->Append(navigate, "&Navigate"); 482 | 483 | wxMenu* help = new wxMenu; 484 | help->Append(wxID_ANY, 485 | "Legacy OpenGL 1.0"); // Change to GL ES 2.0 in a future 486 | help->Append(100, "Visit author website"); 487 | Bind(wxEVT_MENU, [this](wxCommandEvent&) -> void { 488 | wxLaunchDefaultBrowser(AUTHOR_URL); 489 | }, 100); 490 | help->AppendSeparator(); 491 | help->Append(wxID_ABOUT, "&About..."); 492 | Bind(wxEVT_MENU, [this](wxCommandEvent&) -> void { 493 | wxAboutDialogInfo aboutInfo; 494 | aboutInfo.SetName("Kovel"); 495 | aboutInfo.SetVersion(KOVEL_VERSION); 496 | aboutInfo.SetDescription(DESCRIPTION); 497 | aboutInfo.SetCopyright(KOVEL_COPYRIGHT); 498 | aboutInfo.SetWebSite(KOVEL_URL); 499 | aboutInfo.AddDeveloper( 500 | wxString::FromUTF8(std::string("Adrián Arroyo Calle").c_str())); 501 | 502 | wxAboutBox(aboutInfo); 503 | }, wxID_ABOUT); 504 | menuBar->Append(help, "&Help"); 505 | SetMenuBar(menuBar); 506 | 507 | Centre(); 508 | } 509 | 510 | void MainWindow::LoadFile(wxString path) { 511 | Core* core = Core::Instance(); 512 | FILE_PATH = path; 513 | core->LoadFile(path.ToStdString()); 514 | workTwo->UpdateGrid(core->grid); 515 | this->SetLabel(path + " -- Kovel - Voxel Editor"); 516 | } 517 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | --------------------------------------------------------------------------------