Add Lisp integration to map editor

This commit is contained in:
KP 2024-08-01 07:16:20 -05:00
parent eca9313846
commit 6999c7d1e1
9 changed files with 3908 additions and 63 deletions

View file

@ -0,0 +1,36 @@
[06:58:04 AM] Info: Starting...
KP3D version 2
===============================
Copyright (C) kpworld.xyz 2018-2024
Contact me! @kp_cftsz
[06:58:04 AM] Info: Initializing SDL
[06:58:05 AM] Info: Initializing OpenGL
[06:58:05 AM] Info: OpenGL version: 4.6.0 NVIDIA 536.23
[06:58:05 AM] Info: Initializing GLEW
[06:58:05 AM] Info: Initializing SDL_mixer
[06:58:05 AM] Info: Reticulating splines...
[06:58:05 AM] Info: Ready!
[06:58:05 AM] Info: Loading material resource: block.png
[06:58:05 AM] Info: Found normal map texture: materials/block_n.png
[06:58:05 AM] Info: Loading material resource: brick2.jpg
[06:58:05 AM] Info: Found normal map texture: materials/brick2_n.jpg
[06:58:05 AM] Info: Loading material resource: bricks.jpg
[06:58:05 AM] Info: Found normal map texture: materials/bricks_n.jpg
[06:58:05 AM] Info: Loading material resource: FLAT5_7.png
[06:58:05 AM] Info: Found normal map texture: materials/FLAT5_7_n.png
[06:58:05 AM] Info: Loading material resource: floor0.png
[06:58:05 AM] Info: Found normal map texture: materials/floor0_n.png
[06:58:05 AM] Info: Loading material resource: floor1.png
[06:58:05 AM] Info: Found normal map texture: materials/floor1_n.png
[06:58:05 AM] Info: Loading material resource: GRASS2.png
[06:58:05 AM] Info: Found normal map texture: materials/GRASS2_n.png
[06:58:05 AM] Info: Loading material resource: hardwood.jpg
[06:58:05 AM] Info: Found normal map texture: materials/hardwood_n.jpg
[06:58:05 AM] Info: Map init
[06:58:05 AM] Info: Finalized mesh with 49 batches
[06:58:10 AM] Info: $ make-sector-from-points 0 4 ((30 30) (35 30) (35 35) (30 35))
[06:58:10 AM] Info: Finalized mesh with 54 batches
[06:58:10 AM] Info: $ 7.000000
[06:58:32 AM] Info: Finalized mesh with 60 batches

View file

@ -189,6 +189,7 @@
<ClCompile Include="ext\src\imgui\imgui_impl_sdl2.cpp" /> <ClCompile Include="ext\src\imgui\imgui_impl_sdl2.cpp" />
<ClCompile Include="ext\src\imgui\imgui_tables.cpp" /> <ClCompile Include="ext\src\imgui\imgui_tables.cpp" />
<ClCompile Include="ext\src\imgui\imgui_widgets.cpp" /> <ClCompile Include="ext\src\imgui\imgui_widgets.cpp" />
<ClCompile Include="ext\src\imgui\TextEditor.cpp" />
<ClCompile Include="ext\src\poly2tri\advancing_front.cc" /> <ClCompile Include="ext\src\poly2tri\advancing_front.cc" />
<ClCompile Include="ext\src\poly2tri\cdt.cc" /> <ClCompile Include="ext\src\poly2tri\cdt.cc" />
<ClCompile Include="ext\src\poly2tri\shapes.cc" /> <ClCompile Include="ext\src\poly2tri\shapes.cc" />

View file

@ -100,6 +100,7 @@
<ClCompile Include="src\KP3D_Material.cpp" /> <ClCompile Include="src\KP3D_Material.cpp" />
<ClCompile Include="src\KP3D_Resources.cpp" /> <ClCompile Include="src\KP3D_Resources.cpp" />
<ClCompile Include="ext\src\imgui\ImGuizmo.cpp" /> <ClCompile Include="ext\src\imgui\ImGuizmo.cpp" />
<ClCompile Include="ext\src\imgui\TextEditor.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include=".clang-format" /> <None Include=".clang-format" />

View file

@ -0,0 +1,390 @@
#pragma once
#include <string>
#include <vector>
#include <array>
#include <memory>
#include <unordered_set>
#include <unordered_map>
#include <map>
#include <regex>
#include "imgui.h"
class TextEditor
{
public:
enum class PaletteIndex
{
Default,
Keyword,
Number,
String,
CharLiteral,
Punctuation,
Preprocessor,
Identifier,
KnownIdentifier,
PreprocIdentifier,
Comment,
MultiLineComment,
Background,
Cursor,
Selection,
ErrorMarker,
Breakpoint,
LineNumber,
CurrentLineFill,
CurrentLineFillInactive,
CurrentLineEdge,
Max
};
enum class SelectionMode
{
Normal,
Word,
Line
};
struct Breakpoint
{
int mLine;
bool mEnabled;
std::string mCondition;
Breakpoint()
: mLine(-1)
, mEnabled(false)
{}
};
// Represents a character coordinate from the user's point of view,
// i. e. consider an uniform grid (assuming fixed-width font) on the
// screen as it is rendered, and each cell has its own coordinate, starting from 0.
// Tabs are counted as [1..mTabSize] count empty spaces, depending on
// how many space is necessary to reach the next tab stop.
// For example, coordinate (1, 5) represents the character 'B' in a line "\tABC", when mTabSize = 4,
// because it is rendered as " ABC" on the screen.
struct Coordinates
{
int mLine, mColumn;
Coordinates() : mLine(0), mColumn(0) {}
Coordinates(int aLine, int aColumn) : mLine(aLine), mColumn(aColumn)
{
assert(aLine >= 0);
assert(aColumn >= 0);
}
static Coordinates Invalid() { static Coordinates invalid(-1, -1); return invalid; }
bool operator ==(const Coordinates& o) const
{
return
mLine == o.mLine &&
mColumn == o.mColumn;
}
bool operator !=(const Coordinates& o) const
{
return
mLine != o.mLine ||
mColumn != o.mColumn;
}
bool operator <(const Coordinates& o) const
{
if (mLine != o.mLine)
return mLine < o.mLine;
return mColumn < o.mColumn;
}
bool operator >(const Coordinates& o) const
{
if (mLine != o.mLine)
return mLine > o.mLine;
return mColumn > o.mColumn;
}
bool operator <=(const Coordinates& o) const
{
if (mLine != o.mLine)
return mLine < o.mLine;
return mColumn <= o.mColumn;
}
bool operator >=(const Coordinates& o) const
{
if (mLine != o.mLine)
return mLine > o.mLine;
return mColumn >= o.mColumn;
}
};
struct Identifier
{
Coordinates mLocation;
std::string mDeclaration;
};
typedef std::string String;
typedef std::unordered_map<std::string, Identifier> Identifiers;
typedef std::unordered_set<std::string> Keywords;
typedef std::map<int, std::string> ErrorMarkers;
typedef std::unordered_set<int> Breakpoints;
typedef std::array<ImU32, (unsigned)PaletteIndex::Max> Palette;
typedef uint8_t Char;
struct Glyph
{
Char mChar;
PaletteIndex mColorIndex = PaletteIndex::Default;
bool mComment : 1;
bool mMultiLineComment : 1;
bool mPreprocessor : 1;
Glyph(Char aChar, PaletteIndex aColorIndex) : mChar(aChar), mColorIndex(aColorIndex),
mComment(false), mMultiLineComment(false), mPreprocessor(false) {}
};
typedef std::vector<Glyph> Line;
typedef std::vector<Line> Lines;
struct LanguageDefinition
{
typedef std::pair<std::string, PaletteIndex> TokenRegexString;
typedef std::vector<TokenRegexString> TokenRegexStrings;
typedef bool(*TokenizeCallback)(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end, PaletteIndex & paletteIndex);
std::string mName;
Keywords mKeywords;
Identifiers mIdentifiers;
Identifiers mPreprocIdentifiers;
std::string mCommentStart, mCommentEnd, mSingleLineComment;
char mPreprocChar;
bool mAutoIndentation;
TokenizeCallback mTokenize;
TokenRegexStrings mTokenRegexStrings;
bool mCaseSensitive;
LanguageDefinition()
: mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mCaseSensitive(true)
{
}
static const LanguageDefinition& CPlusPlus();
static const LanguageDefinition& HLSL();
static const LanguageDefinition& GLSL();
static const LanguageDefinition& C();
static const LanguageDefinition& Lisp();
static const LanguageDefinition& SQL();
static const LanguageDefinition& AngelScript();
static const LanguageDefinition& Lua();
};
TextEditor();
~TextEditor();
void SetLanguageDefinition(const LanguageDefinition& aLanguageDef);
const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; }
const Palette& GetPalette() const { return mPaletteBase; }
void SetPalette(const Palette& aValue);
void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; }
void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = aMarkers; }
void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false);
void SetText(const std::string& aText);
std::string GetText() const;
void SetTextLines(const std::vector<std::string>& aLines);
std::vector<std::string> GetTextLines() const;
std::string GetSelectedText() const;
std::string GetCurrentLineText()const;
int GetTotalLines() const { return (int)mLines.size(); }
bool IsOverwrite() const { return mOverwrite; }
void SetReadOnly(bool aValue);
bool IsReadOnly() const { return mReadOnly; }
bool IsTextChanged() const { return mTextChanged; }
bool IsCursorPositionChanged() const { return mCursorPositionChanged; }
bool IsColorizerEnabled() const { return mColorizerEnabled; }
void SetColorizerEnable(bool aValue);
Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); }
void SetCursorPosition(const Coordinates& aPosition);
inline void SetHandleMouseInputs (bool aValue){ mHandleMouseInputs = aValue;}
inline bool IsHandleMouseInputsEnabled() const { return mHandleKeyboardInputs; }
inline void SetHandleKeyboardInputs (bool aValue){ mHandleKeyboardInputs = aValue;}
inline bool IsHandleKeyboardInputsEnabled() const { return mHandleKeyboardInputs; }
inline void SetImGuiChildIgnored (bool aValue){ mIgnoreImGuiChild = aValue;}
inline bool IsImGuiChildIgnored() const { return mIgnoreImGuiChild; }
inline void SetShowWhitespaces(bool aValue) { mShowWhitespaces = aValue; }
inline bool IsShowingWhitespaces() const { return mShowWhitespaces; }
void SetTabSize(int aValue);
inline int GetTabSize() const { return mTabSize; }
void InsertText(const std::string& aValue);
void InsertText(const char* aValue);
void MoveUp(int aAmount = 1, bool aSelect = false);
void MoveDown(int aAmount = 1, bool aSelect = false);
void MoveLeft(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
void MoveRight(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
void MoveTop(bool aSelect = false);
void MoveBottom(bool aSelect = false);
void MoveHome(bool aSelect = false);
void MoveEnd(bool aSelect = false);
void SetSelectionStart(const Coordinates& aPosition);
void SetSelectionEnd(const Coordinates& aPosition);
void SetSelection(const Coordinates& aStart, const Coordinates& aEnd, SelectionMode aMode = SelectionMode::Normal);
void SelectWordUnderCursor();
void SelectAll();
bool HasSelection() const;
void Copy();
void Cut();
void Paste();
void Delete();
bool CanUndo() const;
bool CanRedo() const;
void Undo(int aSteps = 1);
void Redo(int aSteps = 1);
static const Palette& GetDarkPalette();
static const Palette& GetLightPalette();
static const Palette& GetRetroBluePalette();
private:
typedef std::vector<std::pair<std::regex, PaletteIndex>> RegexList;
struct EditorState
{
Coordinates mSelectionStart;
Coordinates mSelectionEnd;
Coordinates mCursorPosition;
};
class UndoRecord
{
public:
UndoRecord() {}
~UndoRecord() {}
UndoRecord(
const std::string& aAdded,
const TextEditor::Coordinates aAddedStart,
const TextEditor::Coordinates aAddedEnd,
const std::string& aRemoved,
const TextEditor::Coordinates aRemovedStart,
const TextEditor::Coordinates aRemovedEnd,
TextEditor::EditorState& aBefore,
TextEditor::EditorState& aAfter);
void Undo(TextEditor* aEditor);
void Redo(TextEditor* aEditor);
std::string mAdded;
Coordinates mAddedStart;
Coordinates mAddedEnd;
std::string mRemoved;
Coordinates mRemovedStart;
Coordinates mRemovedEnd;
EditorState mBefore;
EditorState mAfter;
};
typedef std::vector<UndoRecord> UndoBuffer;
void ProcessInputs();
void Colorize(int aFromLine = 0, int aCount = -1);
void ColorizeRange(int aFromLine = 0, int aToLine = 0);
void ColorizeInternal();
float TextDistanceToLineStart(const Coordinates& aFrom) const;
void EnsureCursorVisible();
int GetPageSize() const;
std::string GetText(const Coordinates& aStart, const Coordinates& aEnd) const;
Coordinates GetActualCursorCoordinates() const;
Coordinates SanitizeCoordinates(const Coordinates& aValue) const;
void Advance(Coordinates& aCoordinates) const;
void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd);
int InsertTextAt(Coordinates& aWhere, const char* aValue);
void AddUndo(UndoRecord& aValue);
Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const;
Coordinates FindWordStart(const Coordinates& aFrom) const;
Coordinates FindWordEnd(const Coordinates& aFrom) const;
Coordinates FindNextWord(const Coordinates& aFrom) const;
int GetCharacterIndex(const Coordinates& aCoordinates) const;
int GetCharacterColumn(int aLine, int aIndex) const;
int GetLineCharacterCount(int aLine) const;
int GetLineMaxColumn(int aLine) const;
bool IsOnWordBoundary(const Coordinates& aAt) const;
void RemoveLine(int aStart, int aEnd);
void RemoveLine(int aIndex);
Line& InsertLine(int aIndex);
void EnterCharacter(ImWchar aChar, bool aShift);
void Backspace();
void DeleteSelection();
std::string GetWordUnderCursor() const;
std::string GetWordAt(const Coordinates& aCoords) const;
ImU32 GetGlyphColor(const Glyph& aGlyph) const;
void HandleKeyboardInputs();
void HandleMouseInputs();
void Render();
float mLineSpacing;
Lines mLines;
EditorState mState;
UndoBuffer mUndoBuffer;
int mUndoIndex;
int mTabSize;
bool mOverwrite;
bool mReadOnly;
bool mWithinRender;
bool mScrollToCursor;
bool mScrollToTop;
bool mTextChanged;
bool mColorizerEnabled;
float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor.
int mLeftMargin;
bool mCursorPositionChanged;
int mColorRangeMin, mColorRangeMax;
SelectionMode mSelectionMode;
bool mHandleKeyboardInputs;
bool mHandleMouseInputs;
bool mIgnoreImGuiChild;
bool mShowWhitespaces;
Palette mPaletteBase;
Palette mPalette;
LanguageDefinition mLanguageDefinition;
RegexList mRegexList;
bool mCheckComments;
Breakpoints mBreakpoints;
ErrorMarkers mErrorMarkers;
ImVec2 mCharAdvance;
Coordinates mInteractiveStart, mInteractiveEnd;
std::string mLineBuffer;
uint64_t mStartTime;
float mLastClick;
};

File diff suppressed because it is too large Load diff

View file

@ -54,6 +54,107 @@ ksi::Cell FArithmetic()
return cell; return cell;
} }
ksi::Cell FSin()
{
using namespace ksi;
Cell cell;
cell.type = CELL_FUNCTION_CPP;
cell.data = [](std::list<Cell> args) -> Cell { return {CELL_NUMBER, sinf(FromCell<float>(args.front()))}; };
return cell;
}
ksi::Cell FCos()
{
using namespace ksi;
Cell cell;
cell.type = CELL_FUNCTION_CPP;
cell.data = [](std::list<Cell> args) -> Cell { return {CELL_NUMBER, cosf(FromCell<float>(args.front()))}; };
return cell;
}
ksi::Cell FSqrt()
{
using namespace ksi;
Cell cell;
cell.type = CELL_FUNCTION_CPP;
cell.data = [](std::list<Cell> args) -> Cell { return { CELL_NUMBER, sqrtf(FromCell<float>(args.front())) }; };
return cell;
}
ksi::Cell FAbs()
{
using namespace ksi;
Cell cell;
cell.type = CELL_FUNCTION_CPP;
cell.data = [](std::list<Cell> args) -> Cell { return { CELL_NUMBER, fabsf(FromCell<float>(args.front())) }; };
return cell;
}
ksi::Cell FLog()
{
using namespace ksi;
Cell cell;
cell.type = CELL_FUNCTION_CPP;
cell.data = [](std::list<Cell> args) -> Cell { return { CELL_NUMBER, logf(FromCell<float>(args.front())) }; };
return cell;
}
ksi::Cell FLog10()
{
using namespace ksi;
Cell cell;
cell.type = CELL_FUNCTION_CPP;
cell.data = [](std::list<Cell> args) -> Cell { return { CELL_NUMBER, log10f(FromCell<float>(args.front())) }; };
return cell;
}
ksi::Cell FFloor()
{
using namespace ksi;
Cell cell;
cell.type = CELL_FUNCTION_CPP;
cell.data = [](std::list<Cell> args) -> Cell { return { CELL_NUMBER, floorf(FromCell<float>(args.front())) }; };
return cell;
}
ksi::Cell FCeil()
{
using namespace ksi;
Cell cell;
cell.type = CELL_FUNCTION_CPP;
cell.data = [](std::list<Cell> args) -> Cell { return { CELL_NUMBER, ceilf(FromCell<float>(args.front())) }; };
return cell;
}
ksi::Cell FAtan2()
{
using namespace ksi;
Cell cell;
cell.type = CELL_FUNCTION_CPP;
cell.data = [](std::list<Cell> args) -> Cell {
return {CELL_NUMBER, atan2(FromCell<float>(args.front()), FromCell<float>(args.back()))};
};
return cell;
}
ksi::Cell FCar() ksi::Cell FCar()
{ {
using namespace ksi; using namespace ksi;
@ -414,11 +515,22 @@ Cell* Environment::Get(const std::string& sym_key)
void Environment::Init() void Environment::Init()
{ {
// Basic arithmetic // Math
Set("+", FArithmetic<'+'>()); Set("+", FArithmetic<'+'>());
Set("-", FArithmetic<'-'>()); Set("-", FArithmetic<'-'>());
Set("*", FArithmetic<'*'>()); Set("*", FArithmetic<'*'>());
Set("/", FArithmetic<'/'>()); Set("/", FArithmetic<'/'>());
Set("sin", FSin());
Set("cos", FCos());
Set("sqrt", FSqrt());
Set("abs", FAbs());
Set("log", FLog());
Set("log10", FLog10());
Set("floor", FFloor());
Set("ceil", FCeil());
Set("atan2", FAtan2());
Set("PI", {CELL_NUMBER, 3.14159265358979f});
Set("E", {CELL_NUMBER, 2.71828f});
// Cons/CAR/CDR // Cons/CAR/CDR
Set("car", FCar()); Set("car", FCar());

View file

@ -2,6 +2,7 @@
#include <imgui.h> #include <imgui.h>
#include <ImGuizmo.h> #include <ImGuizmo.h>
#include <TextEditor.h>
#include "KP3D_Renderer3D.h" #include "KP3D_Renderer3D.h"
#include "KP3D_StaticMesh.h" #include "KP3D_StaticMesh.h"
@ -33,6 +34,62 @@ inline float Distance(kp3d::Vec3 a, kp3d::Vec3 b)
return sqrtf((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y) + (b.z - a.z) * (b.z - a.z)); return sqrtf((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y) + (b.z - a.z) * (b.z - a.z));
} }
ksi::Cell FMakeSectorFromPoints()
{
using namespace ksi;
using namespace kp3d;
Cell cell;
cell.type = CELL_FUNCTION_CPP;
cell.data = [](std::list<Cell> args) -> Cell {
auto it = args.begin();
Cell c_floor_height = *it++;
Cell c_ceiling_height = *it++;
Cell c_pt_list = *it++;
std::vector<Vec3> pts;
std::list<Cell> pt_list = FromCell<std::list<Cell>>(c_pt_list);
for (const Cell& c: pt_list)
{
Cell c_x = Car(c);
Cell c_y = Car(Cdr(c));
pts.emplace_back(FromCell<float>(c_x), 0.0f, FromCell<float>(c_y));
}
// build da ting!!
std::shared_ptr<Sector> s = std::make_shared<Sector>();
s->ceiling.material = res::material_cache["block.png"].get();
s->floor.material = res::material_cache["block.png"].get();
s->floor.floor = true;
s->floor.base_height = 0.0f;
s->ceiling.base_height = 4.0f;
s->id = sandbox->map.sectors.size() + 1;
s->parent_id = 0;
s->inverted = false;
for (int i = 0; i < pts.size(); i++)
{
Wall wall;
wall.start = {pts[i].x, -pts[i].z};
wall.end = {pts[(i + 1) % pts.size()].x, -pts[(i + 1) % pts.size()].z};
wall.uid = i;
wall.flags = Wall::NO_FLAGS;
wall.user_flags = Wall::NO_UFLAGS;
for (int j = 0; j < 3; j++)
wall.materials[j] = res::material_cache["block.png"].get();
s->walls.push_back(wall);
}
sandbox->map.sectors.push_back(s);
sandbox->editor.RebuildMap();
return {CELL_NUMBER, s->id};
};
return cell;
}
} }
Editor::Editor() Editor::Editor()
@ -42,8 +99,15 @@ Editor::Editor()
// m_block.Load("block.png", true); // m_block.Load("block.png", true);
m_mode = MODE_NORMAL; m_mode = MODE_NORMAL;
auto lang = TextEditor::LanguageDefinition::Lisp();
build_text_editor.SetLanguageDefinition(lang);
build_text_editor.SetText("()");
kp3d::EventBus::Subscribe(this, &Editor::OnScrollWheel); kp3d::EventBus::Subscribe(this, &Editor::OnScrollWheel);
kp3d::EventBus::Subscribe(this, &Editor::OnKeyPress); kp3d::EventBus::Subscribe(this, &Editor::OnKeyPress);
// Put in our fancy Lisp integration stuff
kp3d::console::environment.Set("make-sector-from-points", FMakeSectorFromPoints());
} }
Editor::~Editor() Editor::~Editor()
@ -56,14 +120,14 @@ void Editor::Init()
void Editor::Update() void Editor::Update()
{ {
if (anything_hovered)
return;
#define KEY_SHORTCUT(key, action) if (sandbox->IsKeyDown(kp3d::KEY_##key)) { action; sandbox->KeyReset(kp3d::KEY_##key); } #define KEY_SHORTCUT(key, action) if (sandbox->IsKeyDown(kp3d::KEY_##key)) { action; sandbox->KeyReset(kp3d::KEY_##key); }
KEY_SHORTCUT(SPACE, m_mode = MODE_NORMAL); KEY_SHORTCUT(SPACE, m_mode = MODE_NORMAL);
KEY_SHORTCUT(V, m_mode = MODE_BUILD); KEY_SHORTCUT(V, m_mode = MODE_BUILD);
if (anything_hovered)
return;
switch (m_mode) switch (m_mode)
{ {
case MODE_BUILD: UpdateModeBuild(); break; case MODE_BUILD: UpdateModeBuild(); break;
@ -115,11 +179,11 @@ void Editor::RebuildMap()
void Editor::UpdateModeBuild() void Editor::UpdateModeBuild()
{ {
if (sandbox->IsMouseButtonDown(kp3d::MOUSE_BUTTON_LEFT)) if (sandbox->IsMouseButtonDown(kp3d::MOUSE_BUTTON_LEFT) && !build_show_options)
{ {
points.push_back(m_stem_pos); points.push_back(m_stem_pos);
if (points.size() >= 3 && kp3d::PosCmp(points.back(), points.front(), 1.0f / 128.0f))// points.back() == points.front()) if (points.size() >= 3 && kp3d::PosCmp(points.back(), points.front(), 1.0f / 128.0f)) // points.back() == points.front())
{ {
std::shared_ptr<kp3d::Sector> s = std::make_shared<kp3d::Sector>(); std::shared_ptr<kp3d::Sector> s = std::make_shared<kp3d::Sector>();
s->ceiling.material = kp3d::res::material_cache["block.png"].get(); s->ceiling.material = kp3d::res::material_cache["block.png"].get();
@ -150,26 +214,30 @@ void Editor::UpdateModeBuild()
sandbox->MouseButtonReset(kp3d::MOUSE_BUTTON_LEFT); sandbox->MouseButtonReset(kp3d::MOUSE_BUTTON_LEFT);
} }
static kp3d::Vec3 start_pos;
static bool has_start_pos = false;
if (sandbox->IsMouseButtonDown(kp3d::MOUSE_BUTTON_RIGHT)) if (sandbox->IsMouseButtonDown(kp3d::MOUSE_BUTTON_RIGHT))
{ {
if (!has_start_pos) if (!build_has_start_pos)
{ {
start_pos = m_stem_pos; build_start_pos = m_stem_pos;
has_start_pos = true; build_has_start_pos = true;
} }
points.clear(); points.clear();
points.emplace_back(m_stem_pos.x, start_pos.y, m_stem_pos.z); points.emplace_back(m_stem_pos.x, build_start_pos.y, m_stem_pos.z);
points.emplace_back(start_pos.x, start_pos.y, m_stem_pos.z); points.emplace_back(build_start_pos.x, build_start_pos.y, m_stem_pos.z);
points.emplace_back(start_pos.x, start_pos.y, start_pos.z); points.emplace_back(build_start_pos.x, build_start_pos.y, build_start_pos.z);
points.emplace_back(m_stem_pos.x, start_pos.y, start_pos.z); points.emplace_back(m_stem_pos.x, build_start_pos.y, build_start_pos.z);
points.emplace_back(m_stem_pos.x, start_pos.y, m_stem_pos.z); points.emplace_back(m_stem_pos.x, build_start_pos.y, m_stem_pos.z);
std::reverse(points.begin(), points.end()); std::reverse(points.begin(), points.end());
} }
else else
{ {
if (has_start_pos) if (sandbox->IsKeyDown(kp3d::KEY_LCTRL))
{
build_show_options = true;
}
else
{
if (build_has_start_pos && !build_show_options)
{ {
std::shared_ptr<kp3d::Sector> s = std::make_shared<kp3d::Sector>(); std::shared_ptr<kp3d::Sector> s = std::make_shared<kp3d::Sector>();
s->ceiling.material = kp3d::res::material_cache["block.png"].get(); s->ceiling.material = kp3d::res::material_cache["block.png"].get();
@ -197,7 +265,8 @@ void Editor::UpdateModeBuild()
sandbox->map.sectors.push_back(s); sandbox->map.sectors.push_back(s);
RebuildMap(); RebuildMap();
points.clear(); points.clear();
has_start_pos = false; build_has_start_pos = false;
}
} }
} }
} }
@ -210,7 +279,7 @@ void Editor::RenderModeBuild()
for (int i = 0; i < points.size() - 1; i++) for (int i = 0; i < points.size() - 1; i++)
RenderLine(points[i], points[i + 1], 0xFF00FFFF); RenderLine(points[i], points[i + 1], 0xFF00FFFF);
} }
if (points.size() > 0) if (points.size() > 0 && !build_show_options)
RenderLine(points.back(), m_stem_pos, 0xFFFF00FF); RenderLine(points.back(), m_stem_pos, 0xFFFF00FF);
// Render the "stem" // Render the "stem"
@ -224,6 +293,24 @@ void Editor::RenderModeBuild()
pos.z = Align(pos.z, 1.0f); pos.z = Align(pos.z, 1.0f);
RenderStem(pos); RenderStem(pos);
m_stem_pos = pos; m_stem_pos = pos;
if (build_show_options)
{
ImGui::SetNextWindowSize({320, 240}, ImGuiCond_FirstUseEver);
if (ImGui::Begin("Build Options", &build_show_options))
{
ImGui::SeparatorText("Shortcuts");
if (ImGui::Button("build-box")) {} ImGui::SameLine();
if (ImGui::Button("build-stairs")) {} ImGui::SameLine();
if (ImGui::Button("build-slope")) {}
ImGui::SeparatorText("Custom Routine");
ImGui::Button("Evaluate");
build_text_editor.Render("Lisp:");
ImGui::End();
}
}
} }
void Editor::UpdateModeNormal() void Editor::UpdateModeNormal()
@ -370,7 +457,7 @@ void Editor::UpdateModeNormal()
Wall& wall = sp->walls[i]; Wall& wall = sp->walls[i];
Wall& neighbor = sp->walls[(i - 1) % sp->walls.size()]; Wall& neighbor = sp->walls[(i - 1) % sp->walls.size()];
if (&wall == info.wall) if (&wall == info.wall)
neighbor.end = wall.end; neighbor.end = wall.end; // TODO: Revisit this
} }
} }
@ -731,14 +818,20 @@ void Editor::RenderUIInfo()
case MODE_BUILD: mode_str = "Build"; break; case MODE_BUILD: mode_str = "Build"; break;
} }
ImGui::Text("Mode: %s\n", mode_str.c_str()); ImGui::Text("Mode: %s\n", mode_str.c_str());
if (m_mode == MODE_BUILD)
{
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Caret Position: (%.1f, %.1f, %.1f)", m_stem_pos.x, m_stem_pos.y, m_stem_pos.z); ImGui::Text("Caret Position: (%.1f, %.1f, %.1f)", m_stem_pos.x, m_stem_pos.y, m_stem_pos.z);
ImGui::Text("MOUSE1 - place individual points");
ImGui::Text("MOUSE2 - place box");
ImGui::Text("MOUSE2 + LCTRL - place box with options");
if (ImGui::BeginPopupContextWindow()) if (ImGui::BeginPopupContextWindow())
{ {
if (ImGui::MenuItem("Hide", NULL, show_info_overlay == false)) if (ImGui::MenuItem("Hide", NULL, show_info_overlay == false))
show_info_overlay = false; show_info_overlay = false;
ImGui::EndPopup(); ImGui::EndPopup();
} }
}
ImGui::End(); ImGui::End();
} }
} }

View file

@ -2,6 +2,8 @@
#include <map> #include <map>
#include <TextEditor.h>
#include "KP3D_Texture.h" #include "KP3D_Texture.h"
#include "KP3D_Math.h" #include "KP3D_Math.h"
#include "KP3D_IOEvents.h" #include "KP3D_IOEvents.h"
@ -56,6 +58,9 @@ public:
private: private:
void RenderLine(kp3d::Vec3 start, kp3d::Vec3 end, kp3d::uint color); void RenderLine(kp3d::Vec3 start, kp3d::Vec3 end, kp3d::uint color);
public:
bool anything_hovered = false;
private: private:
kp3d::Texture m_banner; kp3d::Texture m_banner;
kp3d::Texture m_stem; kp3d::Texture m_stem;
@ -68,7 +73,6 @@ private:
bool show_about_view = false; bool show_about_view = false;
bool should_show_material_modal = false; bool should_show_material_modal = false;
char m_tex_filter_buf[512]; char m_tex_filter_buf[512];
bool anything_hovered = false;
bool editing_gizmo = false; bool editing_gizmo = false;
std::vector<const kp3d::Material**> m_materials_to_update; std::vector<const kp3d::Material**> m_materials_to_update;
@ -79,4 +83,10 @@ private:
kp3d::Vec3 ray_pos; kp3d::Vec3 ray_pos;
bool uv_adjusting = false; bool uv_adjusting = false;
kp3d::Vec3 build_start_pos;
kp3d::Vec3 build_end_pos;
bool build_has_start_pos = false;
bool build_show_options = false;
TextEditor build_text_editor;
}; };

View file

@ -88,15 +88,6 @@ void Sandbox::Update()
//KeyReset(kp3d::KEY_B); //KeyReset(kp3d::KEY_B);
} }
if (IsKeyDown(kp3d::KEY_Y))
map.test_u += 0.1f;
if (IsKeyDown(kp3d::KEY_H))
map.test_u -= 0.1f;
if (IsKeyDown(kp3d::KEY_U))
map.test_l += 0.1f;
if (IsKeyDown(kp3d::KEY_J))
map.test_l -= 0.1f;
// Mouse-look // Mouse-look
if (IsKeyDown(kp3d::KEY_ESCAPE)) if (IsKeyDown(kp3d::KEY_ESCAPE))
{ {
@ -105,10 +96,13 @@ void Sandbox::Update()
} }
float qerf_speed = 1.0f; float qerf_speed = 1.0f;
float move_speed = 0.2f; float move_speed = 0.2f;
if (!editor.anything_hovered)
{
if (IsKeyDown(kp3d::KEY_W)) camera.Move(camera.forward, move_speed); if (IsKeyDown(kp3d::KEY_W)) camera.Move(camera.forward, move_speed);
if (IsKeyDown(kp3d::KEY_S)) camera.Move(camera.forward, -move_speed); if (IsKeyDown(kp3d::KEY_S)) camera.Move(camera.forward, -move_speed);
if (IsKeyDown(kp3d::KEY_A)) camera.Move(camera.right, move_speed); if (IsKeyDown(kp3d::KEY_A)) camera.Move(camera.right, move_speed);
if (IsKeyDown(kp3d::KEY_D)) camera.Move(camera.right, -move_speed); if (IsKeyDown(kp3d::KEY_D)) camera.Move(camera.right, -move_speed);
}
//if (IsKeyDown(kp3d::KEY_SPACE)) camera.position.y += move_speed; //if (IsKeyDown(kp3d::KEY_SPACE)) camera.position.y += move_speed;
//if (IsKeyDown(kp3d::KEY_LSHIFT)) camera.position.y -= move_speed; //if (IsKeyDown(kp3d::KEY_LSHIFT)) camera.position.y -= move_speed;
//if (IsKeyDown(kp3d::KEY_Q)) camera.Rotate(kp3d::Camera::AXIS_X, qerf_speed); //if (IsKeyDown(kp3d::KEY_Q)) camera.Rotate(kp3d::Camera::AXIS_X, qerf_speed);