Compare commits
5 commits
10d69ce7ac
...
5f3bed1c58
Author | SHA1 | Date | |
---|---|---|---|
5f3bed1c58 | |||
6a58aa7fbd | |||
1f296e5fe4 | |||
46856a06e2 | |||
53b1788588 |
25 changed files with 315 additions and 74 deletions
|
@ -8,6 +8,8 @@ add_executable(autogen
|
|||
src/object/codegen.cpp
|
||||
src/data/analysis.cpp
|
||||
src/data/codegen.cpp
|
||||
src/enum/analysis.cpp
|
||||
src/enum/codegen.cpp
|
||||
)
|
||||
|
||||
set_target_properties(autogen PROPERTIES OUTPUT_NAME "autogen")
|
||||
|
|
89
autogen/src/enum/analysis.cpp
Normal file
89
autogen/src/enum/analysis.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
#include "analysis.h"
|
||||
#include "../util.h"
|
||||
#include <clang-c/CXFile.h>
|
||||
#include <clang-c/CXSourceLocation.h>
|
||||
#include <clang-c/Index.h>
|
||||
#include <cstdio>
|
||||
#include <optional>
|
||||
|
||||
using namespace enum_;
|
||||
|
||||
static int findEnumEntryValue(CXCursor cur, bool* success = nullptr) {
|
||||
int ret = -1;
|
||||
if (success != nullptr) *success = false;
|
||||
x_clang_visitChildren(cur, [&](CXCursor cur, CXCursor parent) {
|
||||
CXCursorKind kind = clang_getCursorKind(cur);
|
||||
|
||||
if (kind != CXCursor_IntegerLiteral) return CXChildVisit_Recurse;
|
||||
|
||||
// https://stackoverflow.com/a/63859988/16255372
|
||||
auto res = clang_Cursor_Evaluate(cur);
|
||||
ret = clang_EvalResult_getAsInt(res);
|
||||
clang_EvalResult_dispose(res);
|
||||
|
||||
if (success != nullptr) *success = true;
|
||||
return CXChildVisit_Break;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void processEnumEntry(CXCursor cur, EnumAnalysis* state, int* lastValue) {
|
||||
EnumEntry anly;
|
||||
|
||||
std::string name = x_clang_toString(clang_getCursorSpelling(cur));
|
||||
bool success;
|
||||
int value = findEnumEntryValue(cur, &success);
|
||||
|
||||
// Default to lastValue + 1
|
||||
if (!success) value = ++(*lastValue);
|
||||
*lastValue = value;
|
||||
|
||||
anly.name = name;
|
||||
anly.value = value;
|
||||
|
||||
state->entries.push_back(anly);
|
||||
}
|
||||
|
||||
static void processEnum(CXCursor cur, AnalysisState* state, std::string className, std::string srcRoot) {
|
||||
EnumAnalysis anly;
|
||||
|
||||
anly.name = className;
|
||||
|
||||
int lastValue = -1;
|
||||
|
||||
x_clang_visitChildren(cur, [&](CXCursor cur, CXCursor parent) {
|
||||
CXCursorKind kind = clang_getCursorKind(cur);
|
||||
|
||||
if (kind == CXCursor_EnumConstantDecl) {
|
||||
processEnumEntry(cur, &anly, &lastValue);
|
||||
}
|
||||
|
||||
return CXChildVisit_Continue;
|
||||
});
|
||||
|
||||
state->classes[className] = anly;
|
||||
}
|
||||
|
||||
bool enum_::analyzeClasses(CXCursor cursor, std::string srcRoot, AnalysisState* state) {
|
||||
// Search for classes
|
||||
x_clang_visitChildren(cursor, [&](CXCursor cur, CXCursor parent) {
|
||||
CXCursorKind kind = clang_getCursorKind(cur);
|
||||
if (kind == CXCursor_Namespace) return CXChildVisit_Recurse;
|
||||
if (kind != CXCursor_EnumDecl) return CXChildVisit_Continue;
|
||||
|
||||
CXSourceLocation loc = clang_getCursorLocation(cur);
|
||||
if (!clang_Location_isFromMainFile(loc)) return CXChildVisit_Continue; // This class is not from this header. Skip
|
||||
|
||||
std::string className = x_clang_toString(clang_getCursorDisplayName(cur));
|
||||
// Forward-decls can slip through the cracks, this prevents that, but also allows us to filter non-instance classes in the src/objects directory
|
||||
if (!findAnnotation(cur, "OB::def_enum")) return CXChildVisit_Continue; // Class is not "primary" declaration/is not instance, skip
|
||||
if (state->classes.count(className) > 0) return CXChildVisit_Continue; // Class has already been analyzed, skip...
|
||||
|
||||
processEnum(cur, state, className, srcRoot);
|
||||
|
||||
return CXChildVisit_Continue;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
26
autogen/src/enum/analysis.h
Normal file
26
autogen/src/enum/analysis.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace enum_ {
|
||||
|
||||
struct EnumEntry {
|
||||
std::string name;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct EnumAnalysis {
|
||||
std::string name;
|
||||
std::vector<EnumEntry> entries;
|
||||
};
|
||||
|
||||
struct AnalysisState {
|
||||
std::map<std::string, EnumAnalysis> classes;
|
||||
};
|
||||
|
||||
bool analyzeClasses(CXCursor cursor, std::string srcRoot, AnalysisState* state);
|
||||
|
||||
}
|
31
autogen/src/enum/codegen.cpp
Normal file
31
autogen/src/enum/codegen.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include "codegen.h"
|
||||
#include "analysis.h"
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace enum_;
|
||||
|
||||
void enum_::writeCodeForClass(std::ofstream& out, std::string headerPath, EnumAnalysis& state) {
|
||||
out << "#include \"datatypes/enum.h\"\n\n";
|
||||
|
||||
out << "static std::pair<int, std::string> __values_" << state.name << "[] = {\n";
|
||||
|
||||
for (auto entry : state.entries) {
|
||||
out << " { " << entry.value << ", \"" << entry.name << "\" },\n";
|
||||
}
|
||||
|
||||
out << "};\n\n";
|
||||
|
||||
out << "static _EnumData __data_" << state.name << " = {\n"
|
||||
<< " \"" << state.name << "\",\n"
|
||||
<< " __values_" << state.name << ",\n"
|
||||
<< " " << state.entries.size() << "\n"
|
||||
<< "};\n\n";
|
||||
|
||||
out << "namespace EnumType {\n"
|
||||
// extern is necessary here too to prevent "const" from marking Enum as implicitly static
|
||||
// https://stackoverflow.com/questions/2190919/mixing-extern-and-const#comment2509591_2190981
|
||||
<< " extern const Enum " << state.name << "(&__data_" << state.name << ");\n"
|
||||
<< "}\n\n";
|
||||
}
|
10
autogen/src/enum/codegen.h
Normal file
10
autogen/src/enum/codegen.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "analysis.h"
|
||||
#include <fstream>
|
||||
|
||||
namespace enum_ {
|
||||
|
||||
void writeCodeForClass(std::ofstream& out, std::string headerPath, EnumAnalysis& state);
|
||||
|
||||
}
|
|
@ -6,6 +6,8 @@
|
|||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include "enum/analysis.h"
|
||||
#include "enum/codegen.h"
|
||||
#include "object/analysis.h"
|
||||
#include "object/codegen.h"
|
||||
#include "data/analysis.h"
|
||||
|
@ -50,11 +52,13 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
|
|||
|
||||
object::AnalysisState objectAnlyState;
|
||||
data::AnalysisState dataAnlyState;
|
||||
enum_::AnalysisState enumAnlyState;
|
||||
|
||||
fs::path relpath = fs::relative(srcPath, srcRoot);
|
||||
printf("[AUTOGEN] Processing file %s...\n", relpath.c_str());
|
||||
object::analyzeClasses(cursor, srcRoot, &objectAnlyState);
|
||||
analyzeClasses(cursor, srcRoot, &dataAnlyState);
|
||||
data::analyzeClasses(cursor, srcRoot, &dataAnlyState);
|
||||
enum_::analyzeClasses(cursor, srcRoot, &enumAnlyState);
|
||||
|
||||
fs::create_directories(outPath.parent_path()); // Make sure generated dir exists before we try writing to it
|
||||
|
||||
|
@ -72,7 +76,11 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
|
|||
}
|
||||
|
||||
for (auto& [_, clazz] : dataAnlyState.classes) {
|
||||
writeCodeForClass(outStream, relpath, clazz);
|
||||
data::writeCodeForClass(outStream, relpath, clazz);
|
||||
}
|
||||
|
||||
for (auto& [_, clazz] : enumAnlyState.classes) {
|
||||
enum_::writeCodeForClass(outStream, relpath, clazz);
|
||||
}
|
||||
|
||||
outStream.close();
|
||||
|
|
|
@ -80,7 +80,13 @@ static void processField(CXCursor cur, ClassAnalysis* state) {
|
|||
anly.flags = anly.flags | PropertyFlags::PropertyFlag_Readonly;
|
||||
|
||||
CXType type = clang_getCursorType(cur);
|
||||
anly.backingFieldType = x_clang_toString(clang_getTypeSpelling(type)).c_str();
|
||||
anly.backingFieldType = x_clang_toString(clang_getTypeSpelling(type));
|
||||
CXCursor typeCur = clang_getTypeDeclaration(type);
|
||||
bool isEnum = findAnnotation(typeCur, "OB::def_enum").has_value();
|
||||
if (isEnum) {
|
||||
anly.backingFieldType = "EnumItem";
|
||||
anly.backingFieldEnum = x_clang_toString(clang_getTypeSpelling(type));
|
||||
}
|
||||
|
||||
state->properties.push_back(anly);
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ struct PropertyAnalysis {
|
|||
std::string fieldName;
|
||||
CFrameMember cframeMember = CFrameMember_None; // for cframe_position_prop etc.
|
||||
std::string backingFieldType;
|
||||
std::string backingFieldEnum;
|
||||
std::string onUpdateCallback;
|
||||
std::string category;
|
||||
PropertyFlags flags = (PropertyFlags)0;
|
||||
|
|
|
@ -89,6 +89,8 @@ static void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) {
|
|||
} else if (!subtype.empty()) {
|
||||
out << "\n std::weak_ptr<Instance> ref = value.get<InstanceRef>();"
|
||||
<< "\n this->" << prop.fieldName << " = ref.expired() ? std::weak_ptr<" << subtype << ">() : std::dynamic_pointer_cast<" << subtype << ">(ref.lock());";
|
||||
} else if (prop.backingFieldType == "EnumItem") {
|
||||
out << "\n this->" << prop.fieldName << " = (" << prop.backingFieldEnum << ")value.get<EnumItem>().Value();";
|
||||
} else {
|
||||
out << "\n this->" << prop.fieldName << " = " << castFromVariant("value", prop.backingFieldType) << ";";
|
||||
}
|
||||
|
@ -143,6 +145,8 @@ static void writePropertyGetHandler(std::ofstream& out, ClassAnalysis state) {
|
|||
out << "\n return Variant(" << prop.fieldName << ".Position());";
|
||||
} else if (prop.cframeMember == CFrameMember_Rotation) {
|
||||
out << "\n return Variant(" << prop.fieldName << ".ToEulerAnglesXYZ());";
|
||||
} else if (prop.backingFieldType == "EnumItem") {
|
||||
out << "\n return Variant(EnumType::" << prop.backingFieldEnum << ".FromValueInternal((int)" << prop.fieldName << "));";
|
||||
} else {
|
||||
out << "\n return Variant(" << castToVariant(prop.fieldName, prop.backingFieldType) << ");";
|
||||
}
|
||||
|
@ -193,7 +197,7 @@ static void writePropertyMetaHandler(std::ofstream& out, ClassAnalysis state) {
|
|||
std::string typeInfo = TYPEINFO_REFS[prop.backingFieldType];
|
||||
if (typeInfo.empty()) typeInfo = prop.backingFieldType + "::TYPE";
|
||||
if (!parseWeakPtr(prop.backingFieldType).empty()) typeInfo = "InstanceRef::TYPE";
|
||||
if (prop.backingFieldType == "SurfaceType") typeInfo = "INT_TYPE";
|
||||
if (prop.backingFieldType == "EnumItem") typeInfo = "EnumType::" + prop.backingFieldEnum;
|
||||
|
||||
std::string strFlags;
|
||||
if (prop.flags & PropertyFlag_Readonly)
|
||||
|
@ -256,8 +260,8 @@ void object::writeCodeForClass(std::ofstream& out, std::string headerPath, Class
|
|||
|
||||
out << "#define __AUTOGEN_EXTRA_INCLUDES__\n";
|
||||
out << "#include \"" << state.headerPath << "\"\n\n";
|
||||
out << "#include \"datatypes/variant.h\"\n\n";
|
||||
out << "#include \"datatypes/primitives.h\"\n\n";
|
||||
out << "#include \"datatypes/variant.h\"\n";
|
||||
out << "#include \"datatypes/primitives.h\"\n";
|
||||
out << "const InstanceType " << state.name << "::TYPE = {\n"
|
||||
<< " .super = &" << state.baseClass << "::TYPE,\n"
|
||||
<< " .className = \"" << state.name << "\",\n"
|
||||
|
|
|
@ -16,7 +16,7 @@ find_package(PkgConfig REQUIRED)
|
|||
pkg_check_modules(LUAJIT REQUIRED luajit)
|
||||
|
||||
# Run autogen
|
||||
file(GLOB_RECURSE AUTOGEN_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/src" "src/objects/*.h" "src/datatypes/*.h")
|
||||
file(GLOB_RECURSE AUTOGEN_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/src" "src/objects/*.h" "src/datatypes/*.h" "src/enum/*.h")
|
||||
|
||||
# https://cmake.org/cmake/help/book/mastering-cmake/chapter/Custom%20Commands.html
|
||||
foreach (SRC ${AUTOGEN_SOURCES})
|
||||
|
|
|
@ -38,11 +38,11 @@ struct InstanceType;
|
|||
struct TypeMeta {
|
||||
const TypeDesc* descriptor;
|
||||
union {
|
||||
Enum* enum_; // Applicable for EnumItem
|
||||
InstanceType* instType; // Applicable for InstanceRef
|
||||
const Enum* enum_; // Applicable for EnumItem
|
||||
const InstanceType* instType; // Applicable for InstanceRef
|
||||
};
|
||||
|
||||
inline TypeMeta(const TypeDesc* descriptor) : descriptor(descriptor) {}
|
||||
TypeMeta(Enum*);
|
||||
TypeMeta(InstanceType*);
|
||||
TypeMeta(const Enum*);
|
||||
TypeMeta(const InstanceType*);
|
||||
};
|
|
@ -4,7 +4,7 @@
|
|||
#include "error/data.h"
|
||||
#include <pugixml.hpp>
|
||||
|
||||
TypeMeta::TypeMeta(Enum* enum_) : enum_(enum_), descriptor(&EnumItem::TYPE) {}
|
||||
TypeMeta::TypeMeta(const Enum* enum_) : enum_(enum_), descriptor(&EnumItem::TYPE) {}
|
||||
|
||||
Enum::Enum(_EnumData* data) : data(data) {}
|
||||
|
||||
|
@ -34,6 +34,12 @@ std::optional<EnumItem> Enum::FromValue(int value) const {
|
|||
return {};
|
||||
}
|
||||
|
||||
EnumItem Enum::FromValueInternal(int value) const {
|
||||
auto result = this->FromValue(value);
|
||||
if (!result) return EnumItem(data, "", value);
|
||||
return result.value();
|
||||
}
|
||||
|
||||
EnumItem::EnumItem(_EnumData* parentData, std::string name, int value) : parentData(parentData), name(name), value(value) {}
|
||||
|
||||
//
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
#include "lua.h"
|
||||
|
||||
struct _EnumData {
|
||||
std::pair<int, std::string>* values;
|
||||
std::string name;
|
||||
std::pair<int, std::string>* values;
|
||||
int count;
|
||||
};
|
||||
|
||||
|
@ -27,6 +27,8 @@ public:
|
|||
std::vector<EnumItem> GetEnumItems() const;
|
||||
std::optional<EnumItem> FromName(std::string) const;
|
||||
std::optional<EnumItem> FromValue(int) const;
|
||||
|
||||
EnumItem FromValueInternal(int) const;
|
||||
|
||||
std::string ToString() const;
|
||||
void PushLuaValue(lua_State*) const;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "objects/base/member.h"
|
||||
#include <pugixml.hpp>
|
||||
|
||||
TypeMeta::TypeMeta(InstanceType* instType) : instType(instType), descriptor(&InstanceRef::TYPE) {}
|
||||
TypeMeta::TypeMeta(const InstanceType* instType) : instType(instType), descriptor(&InstanceRef::TYPE) {}
|
||||
|
||||
InstanceRef::InstanceRef() {};
|
||||
InstanceRef::InstanceRef(std::weak_ptr<Instance> instance) : ref(instance) {};
|
||||
|
|
13
core/src/enum/annotation.h
Normal file
13
core/src/enum/annotation.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
// Markers for the autogen engine to generate getters, setters, lua, etc.
|
||||
|
||||
// Base macros
|
||||
#ifdef __AUTOGEN__
|
||||
#define def_enum(...) clang::annotate("OB::def_enum", #__VA_ARGS__)
|
||||
#else
|
||||
#define def_enum(...)
|
||||
#endif
|
||||
|
||||
// Helper macros
|
||||
#define DEF_ENUM [[ def_enum() ]]
|
3
core/src/enum/meta.h
Normal file
3
core/src/enum/meta.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#include "surface.h"
|
33
core/src/enum/surface.h
Normal file
33
core/src/enum/surface.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include "datatypes/enum.h"
|
||||
#include "enum/annotation.h"
|
||||
|
||||
enum DEF_ENUM NormalId {
|
||||
Right = 0,
|
||||
Top = 1,
|
||||
Back = 2,
|
||||
Left = 3,
|
||||
Bottom = 4,
|
||||
Front = 5
|
||||
};
|
||||
|
||||
enum class DEF_ENUM SurfaceType {
|
||||
Smooth = 0,
|
||||
Glue = 1,
|
||||
Weld = 2,
|
||||
Studs = 3,
|
||||
Inlet = 4,
|
||||
Universal = 5,
|
||||
Hinge = 6,
|
||||
Motor = 7,
|
||||
};
|
||||
|
||||
namespace EnumType {
|
||||
extern const Enum NormalId;
|
||||
extern const Enum SurfaceType;
|
||||
};
|
||||
|
||||
class Vector3;
|
||||
NormalId faceFromNormal(Vector3);
|
||||
Vector3 normalFromFace(NormalId);
|
|
@ -13,7 +13,7 @@
|
|||
#include "objects/joint/jointinstance.h"
|
||||
#include "objects/joint/snap.h"
|
||||
#include "rendering/renderer.h"
|
||||
#include "rendering/surface.h"
|
||||
#include "enum/surface.h"
|
||||
#include <cstdio>
|
||||
#include <glm/common.hpp>
|
||||
#include <memory>
|
||||
|
@ -120,7 +120,7 @@ SurfaceType Part::surfaceFromFace(NormalId face) {
|
|||
case Front: return frontSurface;
|
||||
case Back: return backSurface;
|
||||
}
|
||||
return SurfaceSmooth; // Unreachable
|
||||
return SurfaceType::Smooth; // Unreachable
|
||||
}
|
||||
|
||||
float Part::GetSurfaceParamA(Vector3 face) {
|
||||
|
@ -199,14 +199,14 @@ bool Part::checkSurfacesTouching(CFrame surfaceFrame, Vector3 size, Vector3 myFa
|
|||
}
|
||||
|
||||
std::optional<std::shared_ptr<JointInstance>> makeJointFromSurfaces(SurfaceType a, SurfaceType b) {
|
||||
if (a == SurfaceWeld || b == SurfaceWeld || a == SurfaceGlue || b == SurfaceGlue) return Weld::New();
|
||||
if ((a == SurfaceStuds && (b == SurfaceInlets || b == SurfaceUniversal))
|
||||
|| (a == SurfaceInlets && (b == SurfaceStuds || b == SurfaceUniversal))
|
||||
|| (a == SurfaceUniversal && (b == SurfaceStuds || b == SurfaceInlets || b == SurfaceUniversal)))
|
||||
if (a == SurfaceType::Weld || b == SurfaceType::Weld || a == SurfaceType::Glue || b == SurfaceType::Glue) return Weld::New();
|
||||
if ((a == SurfaceType::Studs && (b == SurfaceType::Inlet || b == SurfaceType::Universal))
|
||||
|| (a == SurfaceType::Inlet && (b == SurfaceType::Studs || b == SurfaceType::Universal))
|
||||
|| (a == SurfaceType::Universal && (b == SurfaceType::Studs || b == SurfaceType::Inlet || b == SurfaceType::Universal)))
|
||||
return Snap::New();
|
||||
if (a == SurfaceHinge)
|
||||
if (a == SurfaceType::Hinge)
|
||||
return Rotate::New();
|
||||
if (a == SurfaceMotor)
|
||||
if (a == SurfaceType::Motor)
|
||||
return RotateV::New();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ void Part::MakeJoints() {
|
|||
SurfaceType otherSurface = surfaceFromFace(faceFromNormal(otherFace));
|
||||
|
||||
// If it is a hinge, only attach if actually touching the "hinge"
|
||||
if ((mySurface == SurfaceHinge || mySurface == SurfaceMotor) && !checkSurfacesTouching(surfaceFrame, Vector3(0.4, 0.4, 0.4), myFace, otherFace, otherPart)) continue;
|
||||
if ((mySurface == SurfaceType::Hinge || mySurface == SurfaceType::Motor) && !checkSurfacesTouching(surfaceFrame, Vector3(0.4, 0.4, 0.4), myFace, otherFace, otherPart)) continue;
|
||||
|
||||
// Create contacts
|
||||
// Contact always occurs at the center of Part0's surface (even if that point does not overlap both surfaces)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include "datatypes/signal.h"
|
||||
#include "datatypes/vector.h"
|
||||
#include "objects/base/instance.h"
|
||||
#include "rendering/surface.h"
|
||||
#include "enum/surface.h"
|
||||
#include <optional>
|
||||
#include <reactphysics3d/reactphysics3d.h>
|
||||
#include <vector>
|
||||
|
@ -70,12 +70,12 @@ public:
|
|||
DEF_PROP bool locked = false;
|
||||
|
||||
DEF_PROP_CATEGORY(SURFACE)
|
||||
DEF_PROP SurfaceType topSurface = SurfaceType::SurfaceStuds;
|
||||
DEF_PROP SurfaceType bottomSurface = SurfaceType::SurfaceInlets;
|
||||
DEF_PROP SurfaceType leftSurface = SurfaceType::SurfaceSmooth;
|
||||
DEF_PROP SurfaceType rightSurface = SurfaceType::SurfaceSmooth;
|
||||
DEF_PROP SurfaceType frontSurface = SurfaceType::SurfaceSmooth;
|
||||
DEF_PROP SurfaceType backSurface = SurfaceType::SurfaceSmooth;
|
||||
DEF_PROP SurfaceType topSurface = SurfaceType::Studs;
|
||||
DEF_PROP SurfaceType bottomSurface = SurfaceType::Inlet;
|
||||
DEF_PROP SurfaceType leftSurface = SurfaceType::Smooth;
|
||||
DEF_PROP SurfaceType rightSurface = SurfaceType::Smooth;
|
||||
DEF_PROP SurfaceType frontSurface = SurfaceType::Smooth;
|
||||
DEF_PROP SurfaceType backSurface = SurfaceType::Smooth;
|
||||
|
||||
DEF_PROP_CATEGORY(SURFACE_INPUT)
|
||||
DEF_PROP float topParamA = -0.5;
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include "../common.h"
|
||||
#include "../objects/part.h"
|
||||
#include "skybox.h"
|
||||
#include "surface.h"
|
||||
#include "enum/surface.h"
|
||||
#include "texture3d.h"
|
||||
|
||||
#include "renderer.h"
|
||||
|
@ -154,12 +154,12 @@ void renderParts() {
|
|||
shader->set("texScale", part->size);
|
||||
shader->set("transparency", part->transparency);
|
||||
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Right) + "]", part->rightSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Top) + "]", part->topSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Back) + "]", part->backSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Left) + "]", part->leftSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Bottom) + "]", part->bottomSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Front) + "]", part->frontSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Right) + "]", (int)part->rightSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Top) + "]", (int)part->topSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Back) + "]", (int)part->backSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Left) + "]", (int)part->leftSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Bottom) + "]", (int)part->bottomSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Front) + "]", (int)part->frontSurface);
|
||||
|
||||
CUBE_MESH->bind();
|
||||
glDrawArrays(GL_TRIANGLES, 0, CUBE_MESH->vertexCount);
|
||||
|
@ -184,12 +184,12 @@ void renderParts() {
|
|||
shader->set("texScale", part->size);
|
||||
shader->set("transparency", part->transparency);
|
||||
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Right) + "]", part->rightSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Top) + "]", part->topSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Back) + "]", part->backSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Left) + "]", part->leftSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Bottom) + "]", part->bottomSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Front) + "]", part->frontSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Right) + "]", (int)part->rightSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Top) + "]", (int)part->topSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Back) + "]", (int)part->backSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Left) + "]", (int)part->leftSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Bottom) + "]", (int)part->bottomSurface);
|
||||
shader->set("surfaces[" + std::to_string(NormalId::Front) + "]", (int)part->frontSurface);
|
||||
|
||||
CUBE_MESH->bind();
|
||||
glDrawArrays(GL_TRIANGLES, 0, CUBE_MESH->vertexCount);
|
||||
|
@ -233,7 +233,7 @@ void renderSurfaceExtras() {
|
|||
for (int i = 0; i < 6; i++) {
|
||||
NormalId face = (NormalId)i;
|
||||
SurfaceType type = part->GetSurfaceFromFace(face);
|
||||
if (type <= SurfaceType::SurfaceUniversal) continue;
|
||||
if (type <= SurfaceType::Universal) continue;
|
||||
|
||||
Vector3 surfaceCenter = part->cframe * (normalFromFace(face) * part->size / 2.f);
|
||||
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
enum NormalId {
|
||||
Right = 0,
|
||||
Top = 1,
|
||||
Back = 2,
|
||||
Left = 3,
|
||||
Bottom = 4,
|
||||
Front = 5
|
||||
};
|
||||
|
||||
enum SurfaceType {
|
||||
SurfaceSmooth = 0,
|
||||
SurfaceGlue = 1,
|
||||
SurfaceWeld = 2,
|
||||
SurfaceStuds = 3,
|
||||
SurfaceInlets = 4,
|
||||
SurfaceUniversal = 5,
|
||||
SurfaceHinge = 6,
|
||||
SurfaceMotor = 7,
|
||||
};
|
||||
|
||||
class Vector3;
|
||||
NormalId faceFromNormal(Vector3);
|
||||
Vector3 normalFromFace(NormalId);
|
|
@ -387,9 +387,9 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
|
|||
|
||||
// raycast part
|
||||
std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000);
|
||||
if (!rayHit || !partFromBody(rayHit->body)) return;
|
||||
if (!rayHit || !partFromBody(rayHit->body)) { setSelection({}); return; }
|
||||
std::shared_ptr<Part> part = partFromBody(rayHit->body);
|
||||
if (part->locked) return;
|
||||
if (part->locked) { setSelection({}); return; }
|
||||
initialFrame = part->cframe;
|
||||
initialHitPos = rayHit->worldPoint;
|
||||
initialHitNormal = rayHit->worldNormal;
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
#include "objects/base/member.h"
|
||||
|
||||
#include <QColorDialog>
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
#include <QSpinBox>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QPainter>
|
||||
#include <QTime>
|
||||
#include <functional>
|
||||
#include <qcombobox.h>
|
||||
#include <qnamespace.h>
|
||||
#include <qtreewidget.h>
|
||||
|
||||
|
@ -95,6 +97,18 @@ public:
|
|||
colorDialog->setCurrentColor(QColor::fromRgbF(color.R(), color.G(), color.B()));
|
||||
|
||||
return colorDialog;
|
||||
} else if (meta.type.descriptor == &EnumItem::TYPE) {
|
||||
QComboBox* comboBox = new QComboBox(parent);
|
||||
|
||||
EnumItem enumItem = currentValue.get<EnumItem>();
|
||||
std::vector<EnumItem> siblingItems = meta.type.enum_->GetEnumItems();
|
||||
for (int i = 0; i < siblingItems.size(); i++) {
|
||||
comboBox->addItem(QString::fromStdString(siblingItems[i].Name()));
|
||||
if (siblingItems[i].Value() == enumItem.Value())
|
||||
comboBox->setCurrentIndex(i);
|
||||
}
|
||||
|
||||
return comboBox;
|
||||
} else if (meta.type.descriptor->fromString) {
|
||||
QLineEdit* lineEdit = new QLineEdit(parent);
|
||||
lineEdit->setText(QString::fromStdString(currentValue.ToString()));
|
||||
|
@ -150,6 +164,15 @@ public:
|
|||
|
||||
Color3 color = currentValue.get<Color3>();
|
||||
colorDialog->setCurrentColor(QColor::fromRgbF(color.R(), color.G(), color.B()));
|
||||
} else if (meta.type.descriptor == &EnumItem::TYPE) {
|
||||
QComboBox* comboBox = dynamic_cast<QComboBox*>(editor);
|
||||
|
||||
EnumItem enumItem = currentValue.get<EnumItem>();
|
||||
std::vector<EnumItem> siblingItems = meta.type.enum_->GetEnumItems();
|
||||
for (int i = 0; i < siblingItems.size(); i++) {
|
||||
if (siblingItems[i].Value() == enumItem.Value())
|
||||
comboBox->setCurrentIndex(i);
|
||||
}
|
||||
} else if (meta.type.descriptor->fromString) {
|
||||
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
|
||||
|
||||
|
@ -211,6 +234,13 @@ public:
|
|||
inst->SetPropertyValue(propertyName, color3).expect();
|
||||
model->setData(index, QString::fromStdString(color3.ToString()), Qt::DisplayRole);
|
||||
model->setData(index, color, Qt::DecorationRole);
|
||||
} else if (meta.type.descriptor == &EnumItem::TYPE) {
|
||||
QComboBox* comboBox = dynamic_cast<QComboBox*>(editor);
|
||||
|
||||
std::vector<EnumItem> siblingItems = meta.type.enum_->GetEnumItems();
|
||||
EnumItem newItem = siblingItems[comboBox->currentIndex()];
|
||||
inst->SetPropertyValue(propertyName, newItem).expect("Failed to set enum value in properties pane");
|
||||
model->setData(index, QString::fromStdString(newItem.Name()), Qt::DisplayRole);
|
||||
} else if (meta.type.descriptor->fromString) {
|
||||
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
|
||||
|
||||
|
@ -319,7 +349,9 @@ void PropertiesView::setSelected(std::optional<std::shared_ptr<Instance>> instan
|
|||
// } else if (meta.type.descriptor == &CFrame::TYPE) {
|
||||
// Vector3 vector = currentValue.get<CFrame>().Position();
|
||||
// item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString()));
|
||||
} else {
|
||||
} else if (meta.type.descriptor == &EnumItem::TYPE) {
|
||||
item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.get<EnumItem>().Name()));
|
||||
} else {
|
||||
item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString()));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "objects/joint/snap.h"
|
||||
#include "objects/script.h"
|
||||
#include "objects/script/scriptcontext.h"
|
||||
#include "rendering/surface.h"
|
||||
#include "enum/surface.h"
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <qboxlayout.h>
|
||||
|
@ -131,7 +131,7 @@ void PlaceDocument::init() {
|
|||
// part1->frontSurface = SurfaceWeld;
|
||||
|
||||
// part0->backSurface = SurfaceHinge;
|
||||
part0->backSurface = SurfaceMotor;
|
||||
part0->backSurface = SurfaceType::Motor;
|
||||
// part1->frontSurface = SurfaceHinge;
|
||||
|
||||
std::shared_ptr<Script> script = Script::New();
|
||||
|
|
Loading…
Add table
Reference in a new issue