Compare commits
15 commits
8f68ae45ce
...
c5c8b0f56d
Author | SHA1 | Date | |
---|---|---|---|
c5c8b0f56d | |||
88829b1660 | |||
e15db6f82f | |||
b4e3c1a425 | |||
9438d9d0b2 | |||
e5c67be41a | |||
c7e5a21be0 | |||
08738ed0cc | |||
2a2130f42f | |||
c794d7b8ca | |||
ef961265a5 | |||
e44f70bbac | |||
1c896b521d | |||
3116bceb66 | |||
8aba15baa2 |
16
assets/font/AUTHORS
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
AUTHORS
|
||||||
|
|
||||||
|
Current Contributors (sorted alphabetically):
|
||||||
|
|
||||||
|
- Vishal Vijayraghavan <vishalvvr at fedoraproject dot org>
|
||||||
|
Project Owner/ Maintainer (Current)
|
||||||
|
Red Hat, Inc.
|
||||||
|
|
||||||
|
Previous Contributors
|
||||||
|
- Pravin Satpute <psatpute at redhat dot com>
|
||||||
|
Project Owner/ Maintainer
|
||||||
|
Red Hat, Inc.
|
||||||
|
|
||||||
|
- Steve Matteson
|
||||||
|
Original Designer
|
||||||
|
Ascender, Inc.
|
102
assets/font/LICENSE
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
Digitized data copyright (c) 2010 Google Corporation
|
||||||
|
with Reserved Font Arimo, Tinos and Cousine.
|
||||||
|
Copyright (c) 2012 Red Hat, Inc.
|
||||||
|
with Reserved Font Name Liberation.
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License,
|
||||||
|
Version 1.1.
|
||||||
|
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
|
||||||
|
PREAMBLE The goals of the Open Font License (OFL) are to stimulate
|
||||||
|
worldwide development of collaborative font projects, to support the font
|
||||||
|
creation efforts of academic and linguistic communities, and to provide
|
||||||
|
a free and open framework in which fonts may be shared and improved in
|
||||||
|
partnership with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves.
|
||||||
|
The fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply to
|
||||||
|
any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such.
|
||||||
|
This may include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components
|
||||||
|
as distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting ? in part or in whole ?
|
||||||
|
any of the components of the Original Version, by changing formats or
|
||||||
|
by porting the Font Software to a new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical writer
|
||||||
|
or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,in
|
||||||
|
Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the
|
||||||
|
corresponding Copyright Holder. This restriction only applies to the
|
||||||
|
primary font name as presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole, must
|
||||||
|
be distributed entirely under this license, and must not be distributed
|
||||||
|
under any other license. The requirement for fonts to remain under
|
||||||
|
this license does not apply to any document created using the Font
|
||||||
|
Software.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are not met.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
|
||||||
|
DEALINGS IN THE FONT SOFTWARE.
|
||||||
|
|
BIN
assets/font/LiberationMono-Bold.ttf
Normal file
BIN
assets/font/LiberationMono-BoldItalic.ttf
Normal file
BIN
assets/font/LiberationMono-Italic.ttf
Normal file
BIN
assets/font/LiberationMono-Regular.ttf
Normal file
BIN
assets/font/LiberationSans-Bold.ttf
Normal file
BIN
assets/font/LiberationSans-BoldItalic.ttf
Normal file
BIN
assets/font/LiberationSans-Italic.ttf
Normal file
BIN
assets/font/LiberationSans-Regular.ttf
Normal file
BIN
assets/font/LiberationSerif-Bold.ttf
Normal file
BIN
assets/font/LiberationSerif-BoldItalic.ttf
Normal file
BIN
assets/font/LiberationSerif-Italic.ttf
Normal file
BIN
assets/font/LiberationSerif-Regular.ttf
Normal file
1
assets/icons/editor/actions/48/NOTE.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Icons transform-move, transform-scale, and transform-rotate were modified from silk icons by maelstrom
|
BIN
assets/icons/editor/actions/48/edit-redo.png
Normal file
After Width: | Height: | Size: 625 B |
BIN
assets/icons/editor/actions/48/edit-undo.png
Normal file
After Width: | Height: | Size: 631 B |
BIN
assets/icons/editor/actions/48/object-group.png
Normal file
After Width: | Height: | Size: 553 B |
BIN
assets/icons/editor/actions/48/object-ungroup.png
Normal file
After Width: | Height: | Size: 666 B |
BIN
assets/icons/editor/actions/48/transform-move.png
Normal file
After Width: | Height: | Size: 355 B |
BIN
assets/icons/editor/actions/48/transform-rotate.png
Normal file
After Width: | Height: | Size: 443 B |
BIN
assets/icons/editor/actions/48/transform-scale.png
Normal file
After Width: | Height: | Size: 512 B |
22
assets/shaders/debug/debugfont.fs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec3 vPos;
|
||||||
|
in vec2 vTexCoord;
|
||||||
|
|
||||||
|
uniform sampler2D fontTex;
|
||||||
|
uniform int charIndex;
|
||||||
|
|
||||||
|
// Main
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
int x = (charIndex-32) % 16;
|
||||||
|
int y = (charIndex-32) / 16;
|
||||||
|
|
||||||
|
float fx = float(x) / 16;
|
||||||
|
float fy = float(y) / 8;
|
||||||
|
|
||||||
|
vec4 color = texture(fontTex, vec2(fx, fy) + vTexCoord * vec2(1.f/32, 1.f/16));
|
||||||
|
FragColor = vec3(color) == vec3(0, 0, 0) ? vec4(0, 0, 0, 0) : color;
|
||||||
|
// FragColor = color;
|
||||||
|
}
|
12
assets/shaders/debug/debugfont.vs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#version 330 core
|
||||||
|
in vec3 aPos;
|
||||||
|
in vec2 aTexCoord;
|
||||||
|
|
||||||
|
out vec3 vPos;
|
||||||
|
out vec2 vTexCoord;
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = vec4(aPos, 1.0);
|
||||||
|
vPos = aPos;
|
||||||
|
vTexCoord = aTexCoord;
|
||||||
|
}
|
|
@ -1,22 +1,14 @@
|
||||||
|
// https://learnopengl.com/In-Practice/Text-Rendering
|
||||||
|
|
||||||
#version 330 core
|
#version 330 core
|
||||||
|
in vec2 TexCoords;
|
||||||
|
out vec4 color;
|
||||||
|
|
||||||
out vec4 FragColor;
|
uniform sampler2D text;
|
||||||
in vec3 vPos;
|
uniform vec3 textColor;
|
||||||
in vec2 vTexCoord;
|
|
||||||
|
|
||||||
uniform sampler2D fontTex;
|
void main()
|
||||||
uniform int charIndex;
|
{
|
||||||
|
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
|
||||||
// Main
|
color = vec4(textColor, 1.0) * sampled;
|
||||||
|
}
|
||||||
void main() {
|
|
||||||
int x = (charIndex-32) % 16;
|
|
||||||
int y = (charIndex-32) / 16;
|
|
||||||
|
|
||||||
float fx = float(x) / 16;
|
|
||||||
float fy = float(y) / 8;
|
|
||||||
|
|
||||||
vec4 color = texture(fontTex, vec2(fx, fy) + vTexCoord * vec2(1.f/32, 1.f/16));
|
|
||||||
FragColor = vec3(color) == vec3(0, 0, 0) ? vec4(0, 0, 0, 0) : color;
|
|
||||||
// FragColor = color;
|
|
||||||
}
|
|
|
@ -1,12 +1,13 @@
|
||||||
#version 330 core
|
// https://learnopengl.com/In-Practice/Text-Rendering
|
||||||
in vec3 aPos;
|
|
||||||
in vec2 aTexCoord;
|
#version 330 core
|
||||||
|
layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>
|
||||||
|
out vec2 TexCoords;
|
||||||
|
|
||||||
|
uniform mat4 projection;
|
||||||
|
|
||||||
out vec3 vPos;
|
|
||||||
out vec2 vTexCoord;
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = vec4(aPos, 1.0);
|
gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
|
||||||
vPos = aPos;
|
TexCoords = vertex.zw;
|
||||||
vTexCoord = aTexCoord;
|
}
|
||||||
}
|
|
|
@ -34,7 +34,7 @@ int main() {
|
||||||
glewInit();
|
glewInit();
|
||||||
|
|
||||||
gDataModel->Init();
|
gDataModel->Init();
|
||||||
renderInit(window, 1200, 900);
|
renderInit(1200, 900);
|
||||||
|
|
||||||
// Baseplate
|
// Baseplate
|
||||||
gWorkspace()->AddChild(Part::New({
|
gWorkspace()->AddChild(Part::New({
|
||||||
|
@ -66,7 +66,7 @@ int main() {
|
||||||
|
|
||||||
processInput(window);
|
processInput(window);
|
||||||
gWorkspace()->PhysicsStep(deltaTime);
|
gWorkspace()->PhysicsStep(deltaTime);
|
||||||
render(window);
|
render();
|
||||||
|
|
||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
|
|
@ -7,6 +7,7 @@ find_package(OpenGL)
|
||||||
find_package(glm CONFIG REQUIRED)
|
find_package(glm CONFIG REQUIRED)
|
||||||
find_package(ReactPhysics3D REQUIRED)
|
find_package(ReactPhysics3D REQUIRED)
|
||||||
find_package(pugixml 1.15 REQUIRED)
|
find_package(pugixml 1.15 REQUIRED)
|
||||||
|
find_package(Freetype)
|
||||||
|
|
||||||
find_package(Stb REQUIRED)
|
find_package(Stb REQUIRED)
|
||||||
include_directories(${Stb_INCLUDE_DIR})
|
include_directories(${Stb_INCLUDE_DIR})
|
||||||
|
@ -44,7 +45,7 @@ list(APPEND SOURCES ${AUTOGEN_OUTS})
|
||||||
add_library(openblocks STATIC ${SOURCES})
|
add_library(openblocks STATIC ${SOURCES})
|
||||||
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
|
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
|
||||||
target_link_directories(openblocks PUBLIC ${LUAJIT_LIBRARY_DIRS})
|
target_link_directories(openblocks PUBLIC ${LUAJIT_LIBRARY_DIRS})
|
||||||
target_link_libraries(openblocks ${GLEW_LIBRARIES} ${LUAJIT_LIBRARIES} OpenGL::GL ReactPhysics3D::ReactPhysics3D pugixml::pugixml)
|
target_link_libraries(openblocks ${GLEW_LIBRARIES} ${LUAJIT_LIBRARIES} OpenGL::GL ReactPhysics3D::ReactPhysics3D pugixml::pugixml Freetype::Freetype)
|
||||||
target_include_directories(openblocks PUBLIC "src" "../include" ${LUAJIT_INCLUDE_DIRS})
|
target_include_directories(openblocks PUBLIC "src" "../include" ${LUAJIT_INCLUDE_DIRS})
|
||||||
add_dependencies(openblocks autogen_build autogen)
|
add_dependencies(openblocks autogen_build autogen)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "datatypes/annotation.h"
|
#include "datatypes/annotation.h"
|
||||||
#include "error/data.h"
|
#include "error/data.h"
|
||||||
#include "lua.h" // IWYU pragma: keep
|
#include "luaapis.h" // IWYU pragma: keep
|
||||||
|
|
||||||
struct _EnumData {
|
struct _EnumData {
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include "error/data.h"
|
#include "error/data.h"
|
||||||
#include "variant.h"
|
#include "variant.h"
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
#include "lua.h" // IWYU pragma: keep
|
#include "luaapis.h" // IWYU pragma: keep
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
// null
|
// null
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "lua.h" // IWYU pragma: keep
|
#include "luaapis.h" // IWYU pragma: keep
|
||||||
#include "objects/base/member.h"
|
#include "objects/base/member.h"
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
#include "datatypes/base.h"
|
#include "datatypes/base.h"
|
||||||
#include "variant.h"
|
#include "variant.h"
|
||||||
#include "lua.h" // IWYU pragma: keep
|
#include "luaapis.h" // IWYU pragma: keep
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
extern const char* WRAPPER_SRC; // TODO: Move this to a shared header
|
||||||
|
int script_errhandler(lua_State*); // extern
|
||||||
|
|
||||||
SignalSource::SignalSource() : std::shared_ptr<Signal>(std::make_shared<Signal>()) {}
|
SignalSource::SignalSource() : std::shared_ptr<Signal>(std::make_shared<Signal>()) {}
|
||||||
SignalSource::~SignalSource() = default;
|
SignalSource::~SignalSource() = default;
|
||||||
|
|
||||||
|
@ -25,6 +28,8 @@ LuaSignalConnection::LuaSignalConnection(lua_State* L, std::weak_ptr<Signal> par
|
||||||
// Save function and current thread so they don't get GC'd
|
// Save function and current thread so they don't get GC'd
|
||||||
function = luaL_ref(L, LUA_REGISTRYINDEX);
|
function = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
lua_pushthread(L);
|
lua_pushthread(L);
|
||||||
|
// For posterity, since I accidentally removed this once, the parent thread must not be
|
||||||
|
// deleted because it may (likely) contain upvalues that the handler references
|
||||||
thread = luaL_ref(L, LUA_REGISTRYINDEX);
|
thread = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,18 +61,21 @@ static void stackdump(lua_State* L) {
|
||||||
void LuaSignalConnection::Call(std::vector<Variant> args) {
|
void LuaSignalConnection::Call(std::vector<Variant> args) {
|
||||||
lua_State* thread = lua_newthread(state);
|
lua_State* thread = lua_newthread(state);
|
||||||
|
|
||||||
// Push function
|
// Push wrapepr as thread function
|
||||||
|
luaL_loadbuffer(thread, WRAPPER_SRC, strlen(WRAPPER_SRC), "=PCALL_WRAPPER");
|
||||||
|
|
||||||
|
// Push function as upvalue for wrapper
|
||||||
lua_rawgeti(thread, LUA_REGISTRYINDEX, function);
|
lua_rawgeti(thread, LUA_REGISTRYINDEX, function);
|
||||||
|
|
||||||
|
// Also push our error handler and generate wrapped function
|
||||||
|
lua_pushcfunction(thread, script_errhandler);
|
||||||
|
lua_call(thread, 2, 1);
|
||||||
|
|
||||||
for (Variant arg : args) {
|
for (Variant arg : args) {
|
||||||
arg.PushLuaValue(thread);
|
arg.PushLuaValue(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
int status = lua_resume(thread, args.size());
|
lua_resume(thread, args.size());
|
||||||
if (status > LUA_YIELD) {
|
|
||||||
Logger::error(lua_tostring(thread, -1));
|
|
||||||
lua_pop(thread, 1); // Pop return value
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_pop(state, 1); // Pop thread
|
lua_pop(state, 1); // Pop thread
|
||||||
}
|
}
|
||||||
|
@ -152,11 +160,7 @@ void Signal::Fire(std::vector<Variant> args) {
|
||||||
arg.PushLuaValue(thread);
|
arg.PushLuaValue(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
int status = lua_resume(thread, args.size());
|
lua_resume(thread, args.size());
|
||||||
if (status > LUA_YIELD) {
|
|
||||||
Logger::error(lua_tostring(thread, -1));
|
|
||||||
lua_pop(thread, 1); // Pop return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove thread from registry
|
// Remove thread from registry
|
||||||
luaL_unref(thread, LUA_REGISTRYINDEX, threadId);
|
luaL_unref(thread, LUA_REGISTRYINDEX, threadId);
|
||||||
|
|
77
core/src/lua/instancelib.cpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#include "objects/base/instance.h"
|
||||||
|
#include "datatypes/ref.h"
|
||||||
|
#include "luaapis.h" // IWYU pragma: keep
|
||||||
|
#include "objects/meta.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
static int lib_Instance_index(lua_State*);
|
||||||
|
static int lib_Instance_tostring(lua_State*);
|
||||||
|
static const struct luaL_Reg lib_Instance_metatable [] = {
|
||||||
|
{"__index", lib_Instance_index},
|
||||||
|
{"__tostring", lib_Instance_tostring},
|
||||||
|
{NULL, NULL} /* end of array */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __lua_impl__Instance__new(lua_State* L) {
|
||||||
|
int n = lua_gettop(L);
|
||||||
|
|
||||||
|
// First argument (className)
|
||||||
|
std::string className = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
|
// [Optional] Second argument (parent)
|
||||||
|
std::shared_ptr<Instance> parent;
|
||||||
|
if (n > 1) {
|
||||||
|
parent = **(std::shared_ptr<Instance>**)luaL_checkudata(L, 2, "__mt_instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up class name
|
||||||
|
if (INSTANCE_MAP.count(className) == 0)
|
||||||
|
return luaL_error(L, "Attempt to create instance of unknown type '%s'", className.c_str());
|
||||||
|
|
||||||
|
const InstanceType* type = INSTANCE_MAP[className];
|
||||||
|
|
||||||
|
if (type->flags & (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE) || type->constructor == nullptr)
|
||||||
|
return luaL_error(L, "Attempt to create Instance of type '%s', which is not creatable", className.c_str());
|
||||||
|
|
||||||
|
std::shared_ptr<Instance> object = type->constructor();
|
||||||
|
|
||||||
|
if (parent != nullptr)
|
||||||
|
object->SetParent(parent);
|
||||||
|
|
||||||
|
InstanceRef(object).PushLuaValue(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Instance::PushLuaLibrary(lua_State* L) {
|
||||||
|
lua_getglobal(L, "_G");
|
||||||
|
lua_pushstring(L, "Instance");
|
||||||
|
|
||||||
|
lua_newuserdata(L, 0);
|
||||||
|
|
||||||
|
// Create the library's metatable
|
||||||
|
luaL_newmetatable(L, "__mt_lib_Instance");
|
||||||
|
luaL_register(L, NULL, lib_Instance_metatable);
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
|
||||||
|
lua_rawset(L, -3);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int lib_Instance_tostring(lua_State* L) {
|
||||||
|
lua_pushstring(L, "Instance");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lib_Instance_index(lua_State* L) {
|
||||||
|
std::string key(lua_tostring(L, 2));
|
||||||
|
lua_pop(L, 2);
|
||||||
|
|
||||||
|
if (key == "new") {
|
||||||
|
lua_pushcfunction(L, __lua_impl__Instance__new);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return luaL_error(L, "%s is not a valid member of %s\n", key.c_str(), "Instance");
|
||||||
|
}
|
||||||
|
|
|
@ -95,6 +95,7 @@ public:
|
||||||
|
|
||||||
// Instance is abstract, so it should not implement GetClass directly
|
// Instance is abstract, so it should not implement GetClass directly
|
||||||
virtual const InstanceType* GetClass() = 0;
|
virtual const InstanceType* GetClass() = 0;
|
||||||
|
static void PushLuaLibrary(lua_State*); // Defined in lua/instancelib.cpp
|
||||||
bool SetParent(std::optional<std::shared_ptr<Instance>> newParent);
|
bool SetParent(std::optional<std::shared_ptr<Instance>> newParent);
|
||||||
std::optional<std::shared_ptr<Instance>> GetParent();
|
std::optional<std::shared_ptr<Instance>> GetParent();
|
||||||
bool IsParentLocked();
|
bool IsParentLocked();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "script.h"
|
#include "script.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "lauxlib.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "objects/base/member.h"
|
#include "objects/base/member.h"
|
||||||
|
@ -7,12 +8,16 @@
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
#include "objects/datamodel.h"
|
#include "objects/datamodel.h"
|
||||||
#include "datatypes/ref.h"
|
#include "datatypes/ref.h"
|
||||||
#include "lua.h" // IWYU pragma: keep
|
#include "luaapis.h" // IWYU pragma: keep
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
int script_wait(lua_State*);
|
int script_wait(lua_State*);
|
||||||
int script_delay(lua_State*);
|
int script_delay(lua_State*);
|
||||||
|
int script_errhandler(lua_State*);
|
||||||
|
|
||||||
|
// TODO: Move this to a shared header
|
||||||
|
const char* WRAPPER_SRC = "local func, errhandler = ... return function(...) local args = {...} xpcall(function() func(unpack(args)) end, errhandler) end";
|
||||||
|
|
||||||
Script::Script(): Instance(&TYPE) {
|
Script::Script(): Instance(&TYPE) {
|
||||||
source = "print(\"Hello, world!\")";
|
source = "print(\"Hello, world!\")";
|
||||||
|
@ -25,6 +30,7 @@ void Script::Run() {
|
||||||
std::shared_ptr<ScriptContext> scriptContext = dataModel().value()->GetService<ScriptContext>();
|
std::shared_ptr<ScriptContext> scriptContext = dataModel().value()->GetService<ScriptContext>();
|
||||||
|
|
||||||
lua_State* L = scriptContext->state;
|
lua_State* L = scriptContext->state;
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
|
||||||
// Create thread
|
// Create thread
|
||||||
this->thread = lua_newthread(L);
|
this->thread = lua_newthread(L);
|
||||||
|
@ -52,43 +58,28 @@ void Script::Run() {
|
||||||
|
|
||||||
lua_pop(Lt, 1); // _G
|
lua_pop(Lt, 1); // _G
|
||||||
|
|
||||||
// Load source and push onto thread stack as function ptr
|
// Push wrapper as thread function
|
||||||
// luaL_loadstring(Lt, source.c_str());
|
luaL_loadbuffer(Lt, WRAPPER_SRC, strlen(WRAPPER_SRC), "=PCALL_WRAPPER");
|
||||||
luaL_loadbuffer(Lt, source.c_str(), source.size(), scriptContext->RegisterScriptSource(shared<Script>()).c_str());
|
|
||||||
|
|
||||||
int status = lua_resume(Lt, 0);
|
|
||||||
if (status > LUA_YIELD) {
|
|
||||||
lua_Debug dbg;
|
|
||||||
lua_getstack(Lt, 1, &dbg);
|
|
||||||
lua_getinfo(Lt, "S", &dbg);
|
|
||||||
|
|
||||||
std::weak_ptr<Script> source = scriptContext->GetScriptFromSource(dbg.source);
|
// Load source code and push onto thread as upvalue for wrapper
|
||||||
|
int status = luaL_loadbuffer(Lt, source.c_str(), source.size(), this->GetFullName().c_str());
|
||||||
|
if (status != LUA_OK) {
|
||||||
|
// Failed to parse/load chunk
|
||||||
|
Logger::error(lua_tostring(Lt, -1));
|
||||||
|
|
||||||
std::string errorMessage = lua_tostring(Lt, -1);
|
lua_settop(L, top);
|
||||||
if (!source.expired())
|
return;
|
||||||
errorMessage = source.lock()->GetFullName() + errorMessage.substr(errorMessage.find(':'));
|
|
||||||
|
|
||||||
Logger::error(errorMessage);
|
|
||||||
lua_pop(Lt, 1); // Pop return value
|
|
||||||
|
|
||||||
Logger::traceStart();
|
|
||||||
|
|
||||||
int stack = 1;
|
|
||||||
while (lua_getstack(Lt, stack++, &dbg)) {
|
|
||||||
lua_getinfo(Lt, "nlSu", &dbg);
|
|
||||||
|
|
||||||
std::weak_ptr<Script> source = scriptContext->GetScriptFromSource(dbg.source);
|
|
||||||
if (source.expired()) {
|
|
||||||
Logger::trace(dbg.source, dbg.currentline);
|
|
||||||
} else {
|
|
||||||
Logger::trace(source.lock()->GetFullName(), dbg.currentline, &source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::traceEnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Push our error handler and then generate the wrapped function
|
||||||
|
lua_pushcfunction(Lt, script_errhandler);
|
||||||
|
lua_call(Lt, 2, 1);
|
||||||
|
|
||||||
|
// Resume the thread
|
||||||
|
lua_resume(Lt, 0);
|
||||||
|
|
||||||
lua_pop(L, 1); // Pop the thread
|
lua_pop(L, 1); // Pop the thread
|
||||||
|
lua_settop(L, top);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Script::Stop() {
|
void Script::Stop() {
|
||||||
|
@ -121,5 +112,29 @@ int script_delay(lua_State* L) {
|
||||||
// Schedule next run
|
// Schedule next run
|
||||||
scriptContext->PushThreadSleep(Lt, secs);
|
scriptContext->PushThreadSleep(Lt, secs);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int script_errhandler(lua_State* L) {
|
||||||
|
std::string errorMessage = lua_tostring(L, -1);
|
||||||
|
Logger::error(errorMessage);
|
||||||
|
|
||||||
|
// Traceback
|
||||||
|
|
||||||
|
Logger::traceStart();
|
||||||
|
|
||||||
|
lua_Debug dbg;
|
||||||
|
int stack = 1;
|
||||||
|
while (lua_getstack(L, stack++, &dbg)) {
|
||||||
|
lua_getinfo(L, "nlSu", &dbg);
|
||||||
|
// Ignore C frames and internal wrappers
|
||||||
|
if (strcmp(dbg.what, "C") == 0 || strcmp(dbg.source, "=PCALL_WRAPPER") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Logger::trace(dbg.source, dbg.currentline);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::traceEnd();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "lua.h" // IWYU pragma: keep
|
#include "luaapis.h" // IWYU pragma: keep
|
||||||
|
|
||||||
static int g_print(lua_State*);
|
static int g_print(lua_State*);
|
||||||
static int g_require(lua_State*);
|
static int g_require(lua_State*);
|
||||||
|
@ -46,6 +46,7 @@ void ScriptContext::InitService() {
|
||||||
Vector3::PushLuaLibrary(state);
|
Vector3::PushLuaLibrary(state);
|
||||||
CFrame::PushLuaLibrary(state);
|
CFrame::PushLuaLibrary(state);
|
||||||
Color3::PushLuaLibrary(state);
|
Color3::PushLuaLibrary(state);
|
||||||
|
Instance::PushLuaLibrary(state);
|
||||||
|
|
||||||
// TODO: custom os library
|
// TODO: custom os library
|
||||||
|
|
||||||
|
@ -105,11 +106,7 @@ void ScriptContext::RunSleepingThreads() {
|
||||||
// Time args
|
// Time args
|
||||||
lua_pushnumber(sleep.thread, float(tu_clock_micros() - sleep.timeYieldedWhen) / 1'000'000);
|
lua_pushnumber(sleep.thread, float(tu_clock_micros() - sleep.timeYieldedWhen) / 1'000'000);
|
||||||
lua_pushnumber(sleep.thread, float(tu_clock_micros()) / 1'000'000);
|
lua_pushnumber(sleep.thread, float(tu_clock_micros()) / 1'000'000);
|
||||||
int status = lua_resume(sleep.thread, 2);
|
lua_resume(sleep.thread, 2);
|
||||||
if (status > LUA_YIELD) {
|
|
||||||
Logger::error(lua_tostring(sleep.thread, -1));
|
|
||||||
lua_pop(sleep.thread, 1); // Pop return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove thread
|
// Remove thread
|
||||||
deleted = true;
|
deleted = true;
|
||||||
|
@ -134,23 +131,6 @@ void ScriptContext::RunSleepingThreads() {
|
||||||
schedTime = tu_clock_micros() - startTime;
|
schedTime = tu_clock_micros() - startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ScriptContext::RegisterScriptSource(std::shared_ptr<Script> script) {
|
|
||||||
// If it has already been registered, reference it here
|
|
||||||
for (auto& [id, script2] : scriptSources) {
|
|
||||||
if (!script2.expired() && script2.lock() == script)
|
|
||||||
return "=f" + std::to_string(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
int id = lastScriptSourceId++;
|
|
||||||
scriptSources[id] = script;
|
|
||||||
return "=f" + std::to_string(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::weak_ptr<Script> ScriptContext::GetScriptFromSource(std::string source) {
|
|
||||||
int id = std::stoi(source.c_str() + 2);
|
|
||||||
return scriptSources[id];
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://www.lua.org/source/5.1/lbaselib.c.html
|
// https://www.lua.org/source/5.1/lbaselib.c.html
|
||||||
static int g_print(lua_State* L) {
|
static int g_print(lua_State* L) {
|
||||||
std::string buf;
|
std::string buf;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#include "objects/annotation.h"
|
#include "objects/annotation.h"
|
||||||
#include "objects/base/service.h"
|
#include "objects/base/service.h"
|
||||||
#include "lua.h" // IWYU pragma: keep
|
#include "luaapis.h" // IWYU pragma: keep
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ class DEF_INST_SERVICE ScriptContext : public Service {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
std::vector<SleepingThread> sleepingThreads;
|
std::vector<SleepingThread> sleepingThreads;
|
||||||
std::map<int, std::weak_ptr<Script>> scriptSources;
|
|
||||||
int lastScriptSourceId = 0;
|
int lastScriptSourceId = 0;
|
||||||
protected:
|
protected:
|
||||||
void InitService() override;
|
void InitService() override;
|
||||||
|
@ -32,8 +31,6 @@ public:
|
||||||
lua_State* state;
|
lua_State* state;
|
||||||
void PushThreadSleep(lua_State* thread, float delay);
|
void PushThreadSleep(lua_State* thread, float delay);
|
||||||
void RunSleepingThreads();
|
void RunSleepingThreads();
|
||||||
std::string RegisterScriptSource(std::shared_ptr<Script>);
|
|
||||||
std::weak_ptr<Script> GetScriptFromSource(std::string source);
|
|
||||||
|
|
||||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<ScriptContext>(); };
|
static inline std::shared_ptr<Instance> Create() { return std::make_shared<ScriptContext>(); };
|
||||||
};
|
};
|
|
@ -7,19 +7,19 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
extern int viewportWidth, viewportHeight;
|
extern int viewportWidth, viewportHeight;
|
||||||
extern Texture* fontTexture;
|
extern Texture* debugFontTexture;
|
||||||
extern Shader* fontShader;
|
extern Shader* debugFontShader;
|
||||||
extern Shader* identityShader;
|
extern Shader* identityShader;
|
||||||
|
|
||||||
void drawChar(char c, int x, int y, float scale=1.f) {
|
void drawChar(char c, int x, int y, float scale=1.f) {
|
||||||
fontShader->use();
|
debugFontShader->use();
|
||||||
fontTexture->activate(1);
|
debugFontTexture->activate(1);
|
||||||
fontShader->set("fontTex", 1);
|
debugFontShader->set("fontTex", 1);
|
||||||
|
|
||||||
fontShader->set("charIndex", (int)c);
|
debugFontShader->set("charIndex", (int)c);
|
||||||
|
|
||||||
// https://stackoverflow.com/a/10631263
|
// https://stackoverflow.com/a/10631263
|
||||||
int tex = fontShader->getAttribute("aTexCoord");
|
int tex = debugFontShader->getAttribute("aTexCoord");
|
||||||
|
|
||||||
y = viewportHeight - y - 16*scale;
|
y = viewportHeight - y - 16*scale;
|
||||||
float x0 = float(x)/viewportWidth, y0 = float(y)/viewportHeight, x1 = ((float)x + 8*scale)/viewportWidth, y1 = ((float)y + 16*scale)/viewportHeight;
|
float x0 = float(x)/viewportWidth, y0 = float(y)/viewportHeight, x1 = ((float)x + 8*scale)/viewportWidth, y1 = ((float)y + 16*scale)/viewportHeight;
|
||||||
|
|
162
core/src/rendering/font.cpp
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
#include "font.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "panic.h"
|
||||||
|
#include "rendering/shader.h"
|
||||||
|
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <glm/ext/matrix_clip_space.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
// https://learnopengl.com/In-Practice/Text-Rendering
|
||||||
|
|
||||||
|
FT_Library freetype;
|
||||||
|
Shader* fontShader;
|
||||||
|
|
||||||
|
extern int viewportWidth, viewportHeight;
|
||||||
|
|
||||||
|
unsigned int textVAO, textVBO;
|
||||||
|
|
||||||
|
void fontInit() {
|
||||||
|
if (FT_Error err = FT_Init_FreeType(&freetype)) {
|
||||||
|
Logger::fatalErrorf("Failed to initialize Freetype: [%d]", err);
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
fontShader = new Shader("assets/shaders/font.vs", "assets/shaders/font.fs");
|
||||||
|
|
||||||
|
// Set up buffer
|
||||||
|
glGenVertexArrays(1, &textVAO);
|
||||||
|
glBindVertexArray(textVAO);
|
||||||
|
|
||||||
|
glGenBuffers(1, &textVBO);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, textVBO);
|
||||||
|
|
||||||
|
// Dynamic, because we update the vertices often V~~~~~~~~~~~~~~
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fontFinish() {
|
||||||
|
if (FT_Error err = FT_Done_FreeType(freetype)) {
|
||||||
|
Logger::fatalErrorf("Failed to free Freetype: [%d]", err);
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Font> loadFont(std::string fontName) {
|
||||||
|
std::string fontPath = "assets/font/" + fontName;
|
||||||
|
|
||||||
|
FT_Face face;
|
||||||
|
if (FT_Error err = FT_New_Face(freetype, fontPath.c_str(), 0, &face)) {
|
||||||
|
Logger::fatalErrorf("Failed to create font '%s': [%d]", fontName.c_str(), err);
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Font> font = std::make_shared<Font>();
|
||||||
|
|
||||||
|
FT_Set_Pixel_Sizes(face, 0, 48);
|
||||||
|
|
||||||
|
// Load each glyph
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
for (unsigned char c = 0; c < 128; c++) {
|
||||||
|
// load character glyph
|
||||||
|
if (FT_Error err = FT_Load_Char(face, c, FT_LOAD_RENDER)) {
|
||||||
|
Logger::errorf("Failed to load glyph %d in font '%s': [%d]", c, fontName.c_str(), err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate texture
|
||||||
|
unsigned int texture;
|
||||||
|
glGenTextures(1, &texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_RED,
|
||||||
|
face->glyph->bitmap.width,
|
||||||
|
face->glyph->bitmap.rows,
|
||||||
|
0,
|
||||||
|
GL_RED,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
face->glyph->bitmap.buffer
|
||||||
|
);
|
||||||
|
// set texture options
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
// now store character for later use
|
||||||
|
Character character;
|
||||||
|
character.ID = texture;
|
||||||
|
character.size = glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows);
|
||||||
|
character.bearing = glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top);
|
||||||
|
character.advance = (unsigned int)face->glyph->advance.x;
|
||||||
|
font->characters[c] = character;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Done_Face(face);
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawText(std::shared_ptr<Font> font, std::string text, float x, float y, float scale, glm::vec3 color) {
|
||||||
|
// activate corresponding render state
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
fontShader->use();
|
||||||
|
fontShader->set("textColor", color);
|
||||||
|
fontShader->set("text", 0);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
glm::mat4 projection = glm::ortho(0.0f, (float)viewportWidth, 0.0f, (float)viewportHeight);
|
||||||
|
fontShader->set("projection", projection);
|
||||||
|
|
||||||
|
// This is not in the learnopengl guide but it is VERY important
|
||||||
|
// I'm surprised I missed it but honestly... not so much. I'm an idiot
|
||||||
|
glBindVertexArray(textVAO);
|
||||||
|
|
||||||
|
// iterate through all characters
|
||||||
|
for (size_t i = 0; i < text.size(); i++) {
|
||||||
|
unsigned char c = text[i];
|
||||||
|
Character ch = font->characters[c];
|
||||||
|
|
||||||
|
float xpos = x + ch.bearing.x * scale;
|
||||||
|
float ypos = y - (ch.size.y - ch.bearing.y) * scale;
|
||||||
|
|
||||||
|
float w = ch.size.x * scale;
|
||||||
|
float h = ch.size.y * scale;
|
||||||
|
// render glyph texture over quad
|
||||||
|
glBindTexture(GL_TEXTURE_2D, ch.ID);
|
||||||
|
|
||||||
|
float vertices[6][4] = {
|
||||||
|
{ xpos, ypos + h, 0.0f, 0.0f },
|
||||||
|
{ xpos, ypos, 0.0f, 1.0f },
|
||||||
|
{ xpos + w, ypos, 1.0f, 1.0f },
|
||||||
|
|
||||||
|
{ xpos, ypos + h, 0.0f, 0.0f },
|
||||||
|
{ xpos + w, ypos, 1.0f, 1.0f },
|
||||||
|
{ xpos + w, ypos + h, 1.0f, 0.0f }
|
||||||
|
};
|
||||||
|
// render glyph texture over quad
|
||||||
|
glBindTexture(GL_TEXTURE_2D, ch.ID);
|
||||||
|
// update content of VBO memory
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, textVBO);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
// render quad
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
// now advance cursors for next glyph (note that advance is number of 1/64 pixels)
|
||||||
|
x += (ch.advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64)
|
||||||
|
}
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
23
core/src/rendering/font.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
// https://learnopengl.com/In-Practice/Text-Rendering
|
||||||
|
|
||||||
|
struct Character {
|
||||||
|
unsigned int ID; // ID handle of the glyph texture
|
||||||
|
glm::ivec2 size; // Size of glyph
|
||||||
|
glm::ivec2 bearing; // Offset from baseline to left/top of glyph
|
||||||
|
unsigned int advance; // Offset to advance to next glyph
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Font {
|
||||||
|
Character characters[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
void fontInit();
|
||||||
|
void fontFinish();
|
||||||
|
std::shared_ptr<Font> loadFont(std::string fontName);
|
||||||
|
void drawText(std::shared_ptr<Font> font, std::string text, float x, float y, float scale=1.f, glm::vec3 color = glm::vec3(1,1,1));
|
|
@ -1,5 +1,4 @@
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -23,6 +22,7 @@
|
||||||
#include "math_helper.h"
|
#include "math_helper.h"
|
||||||
#include "objects/service/selection.h"
|
#include "objects/service/selection.h"
|
||||||
#include "partassembly.h"
|
#include "partassembly.h"
|
||||||
|
#include "rendering/font.h"
|
||||||
#include "rendering/mesh2d.h"
|
#include "rendering/mesh2d.h"
|
||||||
#include "rendering/texture.h"
|
#include "rendering/texture.h"
|
||||||
#include "rendering/torus.h"
|
#include "rendering/torus.h"
|
||||||
|
@ -46,14 +46,16 @@ Shader* identityShader = NULL;
|
||||||
Shader* ghostShader = NULL;
|
Shader* ghostShader = NULL;
|
||||||
Shader* wireframeShader = NULL;
|
Shader* wireframeShader = NULL;
|
||||||
Shader* outlineShader = NULL;
|
Shader* outlineShader = NULL;
|
||||||
Shader* fontShader = NULL;
|
Shader* debugFontShader = NULL;
|
||||||
Shader* generic2dShader = NULL;
|
Shader* generic2dShader = NULL;
|
||||||
extern Camera camera;
|
extern Camera camera;
|
||||||
Skybox* skyboxTexture = NULL;
|
Skybox* skyboxTexture = NULL;
|
||||||
Texture3D* studsTexture = NULL;
|
Texture3D* studsTexture = NULL;
|
||||||
Texture* fontTexture = NULL;
|
Texture* debugFontTexture = NULL;
|
||||||
Mesh2D* rect2DMesh = NULL;
|
Mesh2D* rect2DMesh = NULL;
|
||||||
|
|
||||||
|
std::shared_ptr<Font> sansSerif;
|
||||||
|
|
||||||
bool debugRendererEnabled = false;
|
bool debugRendererEnabled = false;
|
||||||
bool wireframeRendering = false;
|
bool wireframeRendering = false;
|
||||||
|
|
||||||
|
@ -62,7 +64,7 @@ int viewportWidth, viewportHeight;
|
||||||
void renderDebugInfo();
|
void renderDebugInfo();
|
||||||
void drawRect(int x, int y, int width, int height, glm::vec3 color);
|
void drawRect(int x, int y, int width, int height, glm::vec3 color);
|
||||||
|
|
||||||
void renderInit(GLFWwindow* window, int width, int height) {
|
void renderInit(int width, int height) {
|
||||||
viewportWidth = width, viewportHeight = height;
|
viewportWidth = width, viewportHeight = height;
|
||||||
glViewport(0, 0, width, height);
|
glViewport(0, 0, width, height);
|
||||||
|
|
||||||
|
@ -74,7 +76,7 @@ void renderInit(GLFWwindow* window, int width, int height) {
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
fontTexture = new Texture("assets/textures/debugfnt.bmp", GL_RGB);
|
debugFontTexture = new Texture("assets/textures/debugfnt.bmp", GL_RGB);
|
||||||
|
|
||||||
skyboxTexture = new Skybox({
|
skyboxTexture = new Skybox({
|
||||||
"assets/textures/skybox/null_plainsky512_lf.jpg",
|
"assets/textures/skybox/null_plainsky512_lf.jpg",
|
||||||
|
@ -95,7 +97,7 @@ void renderInit(GLFWwindow* window, int width, int height) {
|
||||||
ghostShader = new Shader("assets/shaders/ghost.vs", "assets/shaders/ghost.fs");
|
ghostShader = new Shader("assets/shaders/ghost.vs", "assets/shaders/ghost.fs");
|
||||||
wireframeShader = new Shader("assets/shaders/wireframe.vs", "assets/shaders/wireframe.fs");
|
wireframeShader = new Shader("assets/shaders/wireframe.vs", "assets/shaders/wireframe.fs");
|
||||||
outlineShader = new Shader("assets/shaders/outline.vs", "assets/shaders/outline.fs");
|
outlineShader = new Shader("assets/shaders/outline.vs", "assets/shaders/outline.fs");
|
||||||
fontShader = new Shader("assets/shaders/font.vs", "assets/shaders/font.fs");
|
debugFontShader = new Shader("assets/shaders/debug/debugfont.vs", "assets/shaders/debug/debugfont.fs");
|
||||||
generic2dShader = new Shader("assets/shaders/generic2d.vs", "assets/shaders/generic2d.fs");
|
generic2dShader = new Shader("assets/shaders/generic2d.vs", "assets/shaders/generic2d.fs");
|
||||||
|
|
||||||
// Create mesh for 2d rectangle
|
// Create mesh for 2d rectangle
|
||||||
|
@ -110,6 +112,10 @@ void renderInit(GLFWwindow* window, int width, int height) {
|
||||||
};
|
};
|
||||||
|
|
||||||
rect2DMesh = new Mesh2D(6, rectVerts);
|
rect2DMesh = new Mesh2D(6, rectVerts);
|
||||||
|
|
||||||
|
// Initialize fonts
|
||||||
|
fontInit();
|
||||||
|
sansSerif = loadFont("LiberationSans-Regular.ttf");
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderParts() {
|
void renderParts() {
|
||||||
|
@ -356,7 +362,6 @@ void renderHandles() {
|
||||||
glm::vec4 screenPos = projection * view * glm::vec4((glm::vec3)cframe.Position(), 1.0f);
|
glm::vec4 screenPos = projection * view * glm::vec4((glm::vec3)cframe.Position(), 1.0f);
|
||||||
screenPos /= screenPos.w;
|
screenPos /= screenPos.w;
|
||||||
screenPos += 1; screenPos /= 2; screenPos.y = 1 - screenPos.y; screenPos *= glm::vec4(glm::vec2(viewportWidth, viewportHeight), 1, 1);
|
screenPos += 1; screenPos /= 2; screenPos.y = 1 - screenPos.y; screenPos *= glm::vec4(glm::vec2(viewportWidth, viewportHeight), 1, 1);
|
||||||
printVec((glm::vec3)screenPos);
|
|
||||||
|
|
||||||
drawRect(screenPos.x - 3, screenPos.y - 3, 6, 6, glm::vec3(0, 1, 1));
|
drawRect(screenPos.x - 3, screenPos.y - 3, 6, 6, glm::vec3(0, 1, 1));
|
||||||
}
|
}
|
||||||
|
@ -572,6 +577,7 @@ void renderRotationArcs() {
|
||||||
handleShader->set("viewPos", camera.cameraPos);
|
handleShader->set("viewPos", camera.cameraPos);
|
||||||
|
|
||||||
PartAssembly assembly = PartAssembly::FromSelection(gDataModel->GetService<Selection>());
|
PartAssembly assembly = PartAssembly::FromSelection(gDataModel->GetService<Selection>());
|
||||||
|
if (assembly.size() == Vector3::ZERO) return; // No parts are selected
|
||||||
|
|
||||||
for (HandleFace face : HandleFace::Faces) {
|
for (HandleFace face : HandleFace::Faces) {
|
||||||
if (glm::any(glm::lessThan(face.normal, glm::vec3(0)))) continue;
|
if (glm::any(glm::lessThan(face.normal, glm::vec3(0)))) continue;
|
||||||
|
@ -644,7 +650,7 @@ void addDebugRenderCFrame(CFrame frame, Color3 color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tu_time_t renderTime;
|
tu_time_t renderTime;
|
||||||
void render(GLFWwindow* window) {
|
void render() {
|
||||||
tu_time_t startTime = tu_clock_micros();
|
tu_time_t startTime = tu_clock_micros();
|
||||||
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
@ -664,6 +670,7 @@ void render(GLFWwindow* window) {
|
||||||
renderDebugInfo();
|
renderDebugInfo();
|
||||||
// TODO: Make this a debug flag
|
// TODO: Make this a debug flag
|
||||||
// renderAABB();
|
// renderAABB();
|
||||||
|
|
||||||
renderTime = tu_clock_micros() - startTime;
|
renderTime = tu_clock_micros() - startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
|
|
||||||
extern bool wireframeRendering;
|
extern bool wireframeRendering;
|
||||||
|
|
||||||
class CFrame;
|
class CFrame;
|
||||||
class Color3;
|
class Color3;
|
||||||
|
|
||||||
void renderInit(GLFWwindow* window, int width, int height);
|
void renderInit(int width, int height);
|
||||||
void render(GLFWwindow* window);
|
void render();
|
||||||
void setViewport(int width, int height);
|
void setViewport(int width, int height);
|
||||||
void addDebugRenderCFrame(CFrame);
|
void addDebugRenderCFrame(CFrame);
|
||||||
void addDebugRenderCFrame(CFrame, Color3);
|
void addDebugRenderCFrame(CFrame, Color3);
|
||||||
|
|
|
@ -7,7 +7,42 @@
|
||||||
|
|
||||||
struct vec { float x; float y; float z; };
|
struct vec { float x; float y; float z; };
|
||||||
|
|
||||||
void genTorusPoint(float outerRadius, float innerRadius, float tubeSides, float ringSides, int tube, int ring) {
|
unsigned int torusVAO, torusVBO;
|
||||||
|
int lastSize = 0;
|
||||||
|
void initTorus(int tubeSides, int ringSides) {
|
||||||
|
// Free existing buffer
|
||||||
|
if (torusVAO != 0)
|
||||||
|
glDeleteVertexArrays(1, &torusVAO);
|
||||||
|
if (torusVBO != 0)
|
||||||
|
glDeleteBuffers(1, &torusVBO);
|
||||||
|
|
||||||
|
lastSize = tubeSides * ringSides;
|
||||||
|
|
||||||
|
// Set up buffer
|
||||||
|
glGenVertexArrays(1, &torusVAO);
|
||||||
|
glBindVertexArray(torusVAO);
|
||||||
|
|
||||||
|
glGenBuffers(1, &torusVBO);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, torusVBO);
|
||||||
|
|
||||||
|
// Dynamic, because we update the vertices often V~~~~~~~~~~~~~~
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8 * 6 * tubeSides * ringSides, NULL, GL_DYNAMIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(0 * sizeof(float)));
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
|
||||||
|
glEnableVertexAttribArray(2);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void genTorusPoint(float* vertex, float outerRadius, float innerRadius, float tubeSides, float ringSides, int tube, int ring) {
|
||||||
float angle = float(tube) / tubeSides * 2 * PI;
|
float angle = float(tube) / tubeSides * 2 * PI;
|
||||||
float xL = innerRadius * cos(angle);
|
float xL = innerRadius * cos(angle);
|
||||||
float yL = innerRadius * sin(angle);
|
float yL = innerRadius * sin(angle);
|
||||||
|
@ -17,31 +52,41 @@ void genTorusPoint(float outerRadius, float innerRadius, float tubeSides, float
|
||||||
float y = (outerRadius + xL) * sin(outerAngle);
|
float y = (outerRadius + xL) * sin(outerAngle);
|
||||||
float z = yL;
|
float z = yL;
|
||||||
|
|
||||||
// return vec { x, y, z };
|
vertex[0] = x; vertex[1] = y; vertex[2] = z;
|
||||||
glVertex3f(x, y, z);
|
// TODO: Add normals and tex coords
|
||||||
}
|
}
|
||||||
|
|
||||||
// made by yours truly
|
// made by yours truly
|
||||||
void genTorus(float outerRadius, float innerRadius, int tubeSides, int ringSides) {
|
void genTorus(float outerRadius, float innerRadius, int tubeSides, int ringSides) {
|
||||||
glBegin(GL_TRIANGLES);
|
// Automatically generate VBO ad-hoc
|
||||||
|
if (lastSize != tubeSides * ringSides)
|
||||||
|
initTorus(tubeSides, ringSides);
|
||||||
|
|
||||||
|
float* vertices = new float[(tubeSides * ringSides * 6) * 8];
|
||||||
|
|
||||||
|
int vi = 0;
|
||||||
for (int i = 0; i < tubeSides; i++) {
|
for (int i = 0; i < tubeSides; i++) {
|
||||||
float tube = float(i) / tubeSides;
|
|
||||||
for (int j = 0; j < ringSides; j++) {
|
for (int j = 0; j < ringSides; j++) {
|
||||||
float ring = float(j) / ringSides;
|
|
||||||
|
|
||||||
int in = (i+1) % tubeSides;
|
int in = (i+1) % tubeSides;
|
||||||
int jn = (j+1) % tubeSides;
|
int jn = (j+1) % tubeSides;
|
||||||
|
|
||||||
genTorusPoint(outerRadius, innerRadius, tubeSides, ringSides, i, j);
|
genTorusPoint(&vertices[8*vi++], outerRadius, innerRadius, tubeSides, ringSides, i, j);
|
||||||
genTorusPoint(outerRadius, innerRadius, tubeSides, ringSides, in, j);
|
genTorusPoint(&vertices[8*vi++], outerRadius, innerRadius, tubeSides, ringSides, in, j);
|
||||||
genTorusPoint(outerRadius, innerRadius, tubeSides, ringSides, in, jn);
|
genTorusPoint(&vertices[8*vi++], outerRadius, innerRadius, tubeSides, ringSides, in, jn);
|
||||||
|
|
||||||
genTorusPoint(outerRadius, innerRadius, tubeSides, ringSides, in, jn);
|
genTorusPoint(&vertices[8*vi++], outerRadius, innerRadius, tubeSides, ringSides, in, jn);
|
||||||
genTorusPoint(outerRadius, innerRadius, tubeSides, ringSides, i, jn);
|
genTorusPoint(&vertices[8*vi++], outerRadius, innerRadius, tubeSides, ringSides, i, jn);
|
||||||
genTorusPoint(outerRadius, innerRadius, tubeSides, ringSides, i, j);
|
genTorusPoint(&vertices[8*vi++], outerRadius, innerRadius, tubeSides, ringSides, i, j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glEnd();
|
// Bind new data
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, torusVBO);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * 8 * 6 * tubeSides * ringSides, vertices);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
glBindVertexArray(torusVAO);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, tubeSides * ringSides * 6);
|
||||||
}
|
}
|
3
deps.txt
|
@ -8,4 +8,5 @@ qt6
|
||||||
reactphysics3d
|
reactphysics3d
|
||||||
pugixml
|
pugixml
|
||||||
luajit
|
luajit
|
||||||
qscintilla
|
qscintilla
|
||||||
|
freetype2
|
|
@ -98,14 +98,6 @@ add_custom_command(
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
#include("${QT_DEPLOY_SUPPORT}")
|
#include("${QT_DEPLOY_SUPPORT}")
|
||||||
|
|
||||||
# TODO: Add other translations
|
|
||||||
add_custom_command(
|
|
||||||
TARGET editor POST_BUILD
|
|
||||||
COMMAND ${WINDEPLOYQT_EXECUTABLE} $<TARGET_FILE:editor> --translations en --no-compiler-runtime --no-opengl-sw --no-system-d3d-compiler --plugindir $<TARGET_FILE_DIR:editor>/qtplugins
|
|
||||||
)
|
|
||||||
# No sense adding opengl-sw given that hardware acceleration is necessary, anyway
|
|
||||||
# Also don't want to clutter with plugins, add only needed ones
|
|
||||||
|
|
||||||
# Copy over QScintilla DLLs
|
# Copy over QScintilla DLLs
|
||||||
# TODO: Use a better approach?
|
# TODO: Use a better approach?
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
|
@ -113,6 +105,15 @@ if (WIN32)
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${QSCINTILLA_DLLS} $<TARGET_FILE_DIR:editor>
|
COMMAND ${CMAKE_COMMAND} -E copy ${QSCINTILLA_DLLS} $<TARGET_FILE_DIR:editor>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Add other translations
|
||||||
|
add_custom_command(
|
||||||
|
TARGET editor POST_BUILD
|
||||||
|
COMMAND ${WINDEPLOYQT_EXECUTABLE} $<TARGET_FILE:editor> ${QSCINTILLA_DLLS} --dir $<TARGET_FILE_DIR:editor> --translations en --no-compiler-runtime --no-opengl-sw --no-system-d3d-compiler --plugindir $<TARGET_FILE_DIR:editor>/qtplugins
|
||||||
|
)
|
||||||
|
# No sense adding opengl-sw given that hardware acceleration is necessary, anyway
|
||||||
|
# Also don't want to clutter with plugins, add only needed ones
|
||||||
|
|
||||||
|
|
||||||
# Copy qt.conf to override default plugins location
|
# Copy qt.conf to override default plugins location
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET editor POST_BUILD
|
TARGET editor POST_BUILD
|
||||||
|
|
|
@ -1 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
inline bool isDarkMode() {
|
||||||
|
// https://stackoverflow.com/a/78854851/16255372
|
||||||
|
#if defined(_WIN32)
|
||||||
|
// Never read dark theme on Windows as the app currently renders with white color palette regardless
|
||||||
|
return false;
|
||||||
|
#elif QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
||||||
|
const auto scheme = QGuiApplication::styleHints()->colorScheme();
|
||||||
|
return scheme == Qt::ColorScheme::Dark;
|
||||||
|
#else
|
||||||
|
const QPalette defaultPalette;
|
||||||
|
const auto text = defaultPalette.color(QPalette::WindowText);
|
||||||
|
const auto window = defaultPalette.color(QPalette::Window);
|
||||||
|
return text.lightness() > window.lightness();
|
||||||
|
#endif // QT_VERSION
|
||||||
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ MainGLWidget::MainGLWidget(QWidget* parent): QOpenGLWidget(parent), contextMenu(
|
||||||
|
|
||||||
void MainGLWidget::initializeGL() {
|
void MainGLWidget::initializeGL() {
|
||||||
glewInit();
|
glewInit();
|
||||||
renderInit(NULL, width(), height());
|
renderInit(width(), height());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void playSound(QString path) {
|
inline void playSound(QString path) {
|
||||||
|
@ -63,7 +63,7 @@ extern std::weak_ptr<Part> draggingObject;
|
||||||
extern std::optional<HandleFace> draggingHandle;
|
extern std::optional<HandleFace> draggingHandle;
|
||||||
extern Shader* shader;
|
extern Shader* shader;
|
||||||
void MainGLWidget::paintGL() {
|
void MainGLWidget::paintGL() {
|
||||||
::render(NULL);
|
::render();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isMouseRightDragging = false;
|
bool isMouseRightDragging = false;
|
||||||
|
|
|
@ -74,10 +74,16 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
ui->actionRedo->setShortcuts({QKeySequence("Ctrl+Shift+Z"), QKeySequence("Ctrl+Y")});
|
ui->actionRedo->setShortcuts({QKeySequence("Ctrl+Shift+Z"), QKeySequence("Ctrl+Y")});
|
||||||
|
|
||||||
QIcon::setThemeSearchPaths(QIcon::themeSearchPaths() + QStringList { "./assets/icons" });
|
QIcon::setThemeSearchPaths(QIcon::themeSearchPaths() + QStringList { "./assets/icons" });
|
||||||
|
|
||||||
|
// Force theme under windows
|
||||||
|
#ifdef _WIN32
|
||||||
|
QIcon::setThemeName("editor");
|
||||||
|
#else
|
||||||
if (isDarkMode())
|
if (isDarkMode())
|
||||||
QIcon::setFallbackThemeName("editor-dark");
|
QIcon::setFallbackThemeName("editor-dark");
|
||||||
else
|
else
|
||||||
QIcon::setThemeName("editor");
|
QIcon::setFallbackThemeName("editor");
|
||||||
|
#endif
|
||||||
|
|
||||||
// qApp->setStyle(QStyleFactory::create("fusion"));
|
// qApp->setStyle(QStyleFactory::create("fusion"));
|
||||||
defaultMessageHandler = qInstallMessageHandler(logQtMessage);
|
defaultMessageHandler = qInstallMessageHandler(logQtMessage);
|
||||||
|
|
|
@ -306,8 +306,7 @@
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset theme="edit-select">
|
<iconset theme="edit-select"/>
|
||||||
<normaloff>assets/icons/editor/drag.png</normaloff>assets/icons/editor/drag.png</iconset>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Select Objects</string>
|
<string>Select Objects</string>
|
||||||
|
|
|
@ -14,27 +14,15 @@
|
||||||
#include <qglobal.h>
|
#include <qglobal.h>
|
||||||
#include <qlayout.h>
|
#include <qlayout.h>
|
||||||
#include <qtextformat.h>
|
#include <qtextformat.h>
|
||||||
#include "mainwindow.h"
|
|
||||||
#include "objects/script.h"
|
|
||||||
#include "datatypes/variant.h"
|
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
#include <QStyleHints>
|
#include <QStyleHints>
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "editorcommon.h"
|
||||||
|
#include "objects/script.h"
|
||||||
|
#include "datatypes/variant.h"
|
||||||
|
|
||||||
QsciAPIs* makeApis(QsciLexer*);
|
QsciAPIs* makeApis(QsciLexer*);
|
||||||
|
|
||||||
inline bool isDarkMode() {
|
|
||||||
// https://stackoverflow.com/a/78854851/16255372
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
|
||||||
const auto scheme = QGuiApplication::styleHints()->colorScheme();
|
|
||||||
return scheme == Qt::ColorScheme::Dark;
|
|
||||||
#else
|
|
||||||
const QPalette defaultPalette;
|
|
||||||
const auto text = defaultPalette.color(QPalette::WindowText);
|
|
||||||
const auto window = defaultPalette.color(QPalette::Window);
|
|
||||||
return text.lightness() > window.lightness();
|
|
||||||
#endif // QT_VERSION
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<int, const QColor> DARK_MODE_COLOR_SCHEME = {{
|
std::map<int, const QColor> DARK_MODE_COLOR_SCHEME = {{
|
||||||
{QsciLexerLua::Comment, QColor("#808080")},
|
{QsciLexerLua::Comment, QColor("#808080")},
|
||||||
{QsciLexerLua::LineComment, QColor("#808080")},
|
{QsciLexerLua::LineComment, QColor("#808080")},
|
||||||
|
@ -71,7 +59,7 @@ class ObLuaLexer : public QsciLexerLua {
|
||||||
//"foreach foreachi getn "
|
//"foreach foreachi getn "
|
||||||
|
|
||||||
// Openblocks extensions
|
// Openblocks extensions
|
||||||
"shared require game workspace "
|
"shared require game workspace Instance Instance.new "
|
||||||
|
|
||||||
"_G _VERSION getfenv getmetatable ipairs loadstring "
|
"_G _VERSION getfenv getmetatable ipairs loadstring "
|
||||||
"next pairs pcall rawequal rawget rawset select "
|
"next pairs pcall rawequal rawget rawset select "
|
||||||
|
@ -151,7 +139,8 @@ ScriptDocument::ScriptDocument(std::shared_ptr<Script> script, QWidget* parent):
|
||||||
scintilla->setCaretForegroundColor(palette().text().color());
|
scintilla->setCaretForegroundColor(palette().text().color());
|
||||||
scintilla->setFont(font);
|
scintilla->setFont(font);
|
||||||
scintilla->setTabWidth(4);
|
scintilla->setTabWidth(4);
|
||||||
|
scintilla->setEolMode(QsciScintilla::EolUnix); // LF endings
|
||||||
|
|
||||||
scintilla->setText(QString::fromStdString(script->source));
|
scintilla->setText(QString::fromStdString(script->source));
|
||||||
|
|
||||||
ObLuaLexer* lexer = new ObLuaLexer;
|
ObLuaLexer* lexer = new ObLuaLexer;
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
"stb",
|
"stb",
|
||||||
"reactphysics3d",
|
"reactphysics3d",
|
||||||
"pkgconf",
|
"pkgconf",
|
||||||
"luajit"
|
"luajit",
|
||||||
|
"freetype"
|
||||||
],
|
],
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
|
|