Clean project structure.
This commit is contained in:
parent
78a4fa99ff
commit
947bf937fd
496 changed files with 206 additions and 137 deletions
4
src/rendering/CMakeLists.txt
Normal file
4
src/rendering/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
add_subdirectory(fonts)
|
||||
add_subdirectory(graphics)
|
||||
add_subdirectory(mesh)
|
||||
add_subdirectory(visual_elements)
|
0
src/rendering/fonts/BasicFontEngine.cpp
Normal file
0
src/rendering/fonts/BasicFontEngine.cpp
Normal file
15
src/rendering/fonts/BasicFontEngine.h
Normal file
15
src/rendering/fonts/BasicFontEngine.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "IFontEngine.h"
|
||||
|
||||
#include "Image.h"
|
||||
#include "FontGlyph.h"
|
||||
|
||||
class BasicFontEngine : public IFontEngine
|
||||
{
|
||||
virtual void initialize(){};
|
||||
|
||||
virtual void loadFontFace(const std::filesystem::path& fontFile, float penSize = 16){};
|
||||
|
||||
virtual std::unique_ptr<FontGlyph> loadGlyph(unsigned charCode){return nullptr;};
|
||||
};
|
60
src/rendering/fonts/CMakeLists.txt
Normal file
60
src/rendering/fonts/CMakeLists.txt
Normal file
|
@ -0,0 +1,60 @@
|
|||
set(MODULE_NAME fonts)
|
||||
message(STATUS "Checking dependencies for module: " ${MODULE_NAME})
|
||||
|
||||
set(LIB_DEPENDS "")
|
||||
|
||||
list(APPEND LIB_INCLUDES
|
||||
FontReader.cpp
|
||||
TrueTypeFont.cpp
|
||||
FontsManager.cpp
|
||||
FontGlyph.cpp
|
||||
FontReader.h
|
||||
TrueTypeFont.h
|
||||
FontsManager.h
|
||||
FontGlyph.h
|
||||
IFont.h
|
||||
IFontEngine.h
|
||||
BasicFontEngine.h
|
||||
BasicFontEngine.cpp
|
||||
FontItem.h
|
||||
FontItem.cpp
|
||||
)
|
||||
|
||||
if(UNIX)
|
||||
find_package(Freetype QUIET)
|
||||
if(Freetype_FOUND)
|
||||
list(APPEND LIB_INCLUDES
|
||||
FreeTypeFontEngine.cpp
|
||||
)
|
||||
|
||||
list(APPEND LIB_DEPENDS
|
||||
Freetype::Freetype
|
||||
)
|
||||
list(APPEND DEFINES "HAS_FREETYPE")
|
||||
else()
|
||||
message(STATUS "Freetype not found - skipping support")
|
||||
endif()
|
||||
else()
|
||||
list(APPEND LIB_INCLUDES
|
||||
directx/DirectWriteFontEngine.h
|
||||
directx/DirectWriteHelpers.h
|
||||
directx/DirectWriteFontEngine.cpp
|
||||
directx/DirectWriteHelpers.cpp
|
||||
)
|
||||
list(APPEND LIB_DEPENDS
|
||||
Dwrite.lib D2d1.lib uuid.lib
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(${MODULE_NAME} SHARED ${LIB_INCLUDES})
|
||||
|
||||
target_include_directories(${MODULE_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/directx
|
||||
)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} PUBLIC core geometry image ${LIB_DEPENDS})
|
||||
|
||||
target_compile_definitions(${MODULE_NAME} PRIVATE ${DEFINES})
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/rendering)
|
||||
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
97
src/rendering/fonts/FontGlyph.cpp
Normal file
97
src/rendering/fonts/FontGlyph.cpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
#include "FontGlyph.h"
|
||||
|
||||
void GlyphRunOutlines::addSegment(const GlyphRunSegment& segment)
|
||||
{
|
||||
mFeatures[mFeatures.size() - 1].mSegments.push_back(segment);
|
||||
}
|
||||
|
||||
void GlyphRunOutlines::startFeature(const Point& point, bool isFilled)
|
||||
{
|
||||
GlyphRunFeature feature;
|
||||
feature.mFilled = isFilled;
|
||||
|
||||
GlyphRunSegment segment;
|
||||
segment.mType = GlyphRunSegment::Type::POINT;
|
||||
segment.mPoints.push_back(point);
|
||||
|
||||
feature.mSegments.push_back(segment);
|
||||
|
||||
mFeatures.push_back(feature);
|
||||
}
|
||||
|
||||
std::string GlyphRunOutlines::toPostScriptPath()
|
||||
{
|
||||
std::string path;
|
||||
for (const auto& feature : mFeatures)
|
||||
{
|
||||
if (feature.mSegments.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto start_point = feature.mSegments[0].mPoints[0];
|
||||
path += "M" + std::to_string(start_point.getX()) + " " + std::to_string(start_point.getY()) + " ";
|
||||
|
||||
for (std::size_t idx = 1; idx < feature.mSegments.size(); idx++)
|
||||
{
|
||||
if (feature.mSegments[idx].mType == GlyphRunSegment::Type::LINE)
|
||||
{
|
||||
for (const auto& point : feature.mSegments[idx].mPoints)
|
||||
{
|
||||
path += "L" + std::to_string(point.getX()) + " " + std::to_string(point.getY()) + " ";
|
||||
}
|
||||
}
|
||||
else if (feature.mSegments[idx].mType == GlyphRunSegment::Type::BEZIER)
|
||||
{
|
||||
path += "C";
|
||||
for (const auto& point : feature.mSegments[idx].mPoints)
|
||||
{
|
||||
path += std::to_string(point.getX()) + " " + std::to_string(point.getY()) + " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
path += "z ";
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
FontGlyph::FontGlyph(unsigned width, unsigned height, int bearingX, int bearingY, int advanceX, std::unique_ptr<Image> image)
|
||||
: mImage(std::move(image)),
|
||||
mWidth(width),
|
||||
mHeight(height),
|
||||
mBearingX(bearingX),
|
||||
mBearingY(bearingY),
|
||||
mAdvanceX(advanceX)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Image* FontGlyph::getImage() const
|
||||
{
|
||||
return mImage.get();
|
||||
}
|
||||
|
||||
unsigned FontGlyph::getWidth() const
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
unsigned FontGlyph::getHeight() const
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
int FontGlyph::getBearingX() const
|
||||
{
|
||||
return mBearingX;
|
||||
}
|
||||
|
||||
int FontGlyph::getBearingY() const
|
||||
{
|
||||
return mBearingY;
|
||||
}
|
||||
|
||||
int FontGlyph::getAdvanceX() const
|
||||
{
|
||||
return mAdvanceX;
|
||||
}
|
59
src/rendering/fonts/FontGlyph.h
Normal file
59
src/rendering/fonts/FontGlyph.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include "Point.h"
|
||||
#include "Image.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
struct GlyphRunSegment
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
POINT,
|
||||
LINE,
|
||||
BEZIER
|
||||
};
|
||||
std::vector<Point> mPoints;
|
||||
Type mType{ Type::LINE };
|
||||
};
|
||||
|
||||
struct GlyphRunFeature
|
||||
{
|
||||
bool mFilled{ true };
|
||||
std::vector<GlyphRunSegment> mSegments;
|
||||
};
|
||||
|
||||
class GlyphRunOutlines
|
||||
{
|
||||
public:
|
||||
void addSegment(const GlyphRunSegment& point);
|
||||
void startFeature(const Point& point, bool isFilled);
|
||||
|
||||
std::string toPostScriptPath();
|
||||
private:
|
||||
std::vector<GlyphRunFeature> mFeatures;
|
||||
};
|
||||
|
||||
class FontGlyph
|
||||
{
|
||||
public:
|
||||
FontGlyph(unsigned width, unsigned height, int bearingX, int bearingY, int advanceX, std::unique_ptr<Image> image);
|
||||
|
||||
Image* getImage() const;
|
||||
|
||||
unsigned getWidth() const;
|
||||
unsigned getHeight() const;
|
||||
int getBearingX() const;
|
||||
int getBearingY() const;
|
||||
int getAdvanceX() const;
|
||||
|
||||
private:
|
||||
unsigned mWidth{0};
|
||||
unsigned mHeight{0};
|
||||
int mBearingX{0};
|
||||
int mBearingY{0};
|
||||
int mAdvanceX{0};
|
||||
std::unique_ptr<Image> mImage;
|
||||
};
|
33
src/rendering/fonts/FontItem.cpp
Normal file
33
src/rendering/fonts/FontItem.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include "FontItem.h"
|
||||
|
||||
FontItem::FontItem(const std::string& faceName, float size)
|
||||
: mFaceName(faceName),
|
||||
mSize(size)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool FontItem::hasPath() const
|
||||
{
|
||||
return !mPath.empty();
|
||||
}
|
||||
|
||||
const Path& FontItem::getPath() const
|
||||
{
|
||||
return mPath;
|
||||
}
|
||||
|
||||
void FontItem::setPath(const Path& path)
|
||||
{
|
||||
mPath = path;
|
||||
}
|
||||
|
||||
const std::string& FontItem::getFaceName() const
|
||||
{
|
||||
return mFaceName;
|
||||
}
|
||||
|
||||
float FontItem::getSize() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
38
src/rendering/fonts/FontItem.h
Normal file
38
src/rendering/fonts/FontItem.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
using Path = std::filesystem::path;
|
||||
|
||||
class FontItem
|
||||
{
|
||||
public:
|
||||
FontItem(const std::string& faceName = "Arial", float size = 16);
|
||||
|
||||
const Path& getPath() const;
|
||||
|
||||
const std::string& getFaceName() const;
|
||||
|
||||
float getSize() const;
|
||||
|
||||
void setPath(const Path& path);
|
||||
|
||||
bool hasPath() const;
|
||||
|
||||
bool operator==(const FontItem& rhs) const
|
||||
{
|
||||
return (mSize == rhs.mSize)
|
||||
&& (mFaceName == rhs.mFaceName);
|
||||
}
|
||||
|
||||
bool operator!=(const FontItem& rhs) const
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
float mSize{24};
|
||||
std::string mFaceName;
|
||||
Path mPath;
|
||||
};
|
181
src/rendering/fonts/FontReader.cpp
Normal file
181
src/rendering/fonts/FontReader.cpp
Normal file
|
@ -0,0 +1,181 @@
|
|||
#include "FontReader.h"
|
||||
#include "TrueTypeFont.h"
|
||||
|
||||
#include "File.h"
|
||||
#include "BinaryStream.h"
|
||||
|
||||
//#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
FontReader::~FontReader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FontReader::setPath(const std::string& path)
|
||||
{
|
||||
mPath = path;
|
||||
}
|
||||
|
||||
bool FontReader::readOffsetSubtable()
|
||||
{
|
||||
mOffsetSubtable.scaler_type = *BinaryStream::getNextDWord(mFile->getInHandle());
|
||||
mCurrentOffset += 4;
|
||||
|
||||
mOffsetSubtable.num_tables = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
mCurrentOffset += 2;
|
||||
|
||||
mOffsetSubtable.search_range = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
mCurrentOffset += 2;
|
||||
|
||||
mOffsetSubtable.entry_selector = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
mCurrentOffset += 2;
|
||||
|
||||
mOffsetSubtable.range_shift = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
mCurrentOffset += 2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FontReader::logOffsetSubtable()
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "Offset Subtable\n";
|
||||
sstr << "scaler_type: " << mOffsetSubtable.scaler_type << "\n";
|
||||
|
||||
sstr << "num_tables: " << mOffsetSubtable.num_tables << "\n";
|
||||
|
||||
sstr << "search_range: " << mOffsetSubtable.search_range << "\n";
|
||||
|
||||
sstr << "entry_selector: " << mOffsetSubtable.entry_selector << "\n";
|
||||
|
||||
sstr << "range_shift: " << mOffsetSubtable.range_shift << "\n";
|
||||
sstr << "************\n";
|
||||
//std::cout << sstr.str() << std::endl;
|
||||
}
|
||||
|
||||
void FontReader::readTableDirectory()
|
||||
{
|
||||
mTables.clear();
|
||||
for (unsigned idx=0; idx<mOffsetSubtable.num_tables; idx++)
|
||||
{
|
||||
Table table;
|
||||
BinaryStream::getNextString(mFile->getInHandle(), table.name, 4);
|
||||
mCurrentOffset += 4;
|
||||
|
||||
table.checksum = *BinaryStream::getNextDWord(mFile->getInHandle());
|
||||
mCurrentOffset += 4;
|
||||
|
||||
table.offset = *BinaryStream::getNextDWord(mFile->getInHandle());
|
||||
mCurrentOffset += 4;
|
||||
|
||||
table.length = *BinaryStream::getNextDWord(mFile->getInHandle());
|
||||
mCurrentOffset += 4;
|
||||
|
||||
logTable(table);
|
||||
mTables.push_back(table);
|
||||
}
|
||||
}
|
||||
|
||||
void FontReader::logTable(const Table& table)
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "Table\n";
|
||||
sstr << "name: " << table.name << "\n";
|
||||
|
||||
sstr << "checksum: " << table.checksum << "\n";
|
||||
|
||||
sstr << "offset: " << table.offset << "\n";
|
||||
|
||||
sstr << "length: " << table.length << "\n";
|
||||
sstr << "************\n";
|
||||
//std::cout << sstr.str() << std::endl;
|
||||
}
|
||||
|
||||
void FontReader::readTable()
|
||||
{
|
||||
std::string working_table_name;
|
||||
for (const auto& table : mTables)
|
||||
{
|
||||
if (mCurrentOffset == table.offset)
|
||||
{
|
||||
working_table_name = table.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (working_table_name == "head")
|
||||
{
|
||||
readHeadTable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FontReader::readHeadTable()
|
||||
{
|
||||
//std::cout << "Reading head table" << std::endl;
|
||||
|
||||
TrueTypeFont::HeadTable table;
|
||||
|
||||
table.version = *BinaryStream::getNextDWord(mFile->getInHandle());
|
||||
table.fontRevision = *BinaryStream::getNextDWord(mFile->getInHandle());
|
||||
table.checksumAdjustment = *BinaryStream::getNextDWord(mFile->getInHandle());
|
||||
table.magicNumber = *BinaryStream::getNextDWord(mFile->getInHandle());
|
||||
mCurrentOffset += 16;
|
||||
|
||||
table.flags = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
table.unitsPerEm = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
mCurrentOffset += 4;
|
||||
|
||||
table.created = *BinaryStream::getNextQWord(mFile->getInHandle());
|
||||
table.modified = *BinaryStream::getNextQWord(mFile->getInHandle());
|
||||
mCurrentOffset += 16;
|
||||
|
||||
table.xMin = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
table.yMin = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
table.xMax = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
table.yMax = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
table.macStyle = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
table.lowestRecPPEM = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
table.fontDirectionHint = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
table.indexToLocFormat = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
table.glyphDataFormat = *BinaryStream::getNextWord(mFile->getInHandle());
|
||||
|
||||
mCurrentOffset += 18;
|
||||
|
||||
auto working_ttf_font = dynamic_cast<TrueTypeFont*>(mWorkingFont.get());
|
||||
working_ttf_font->setHeadTable(table);
|
||||
//std::cout << working_ttf_font->logHeadTable() << std::endl;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<IFont> FontReader::read()
|
||||
{
|
||||
mWorkingFont = std::make_unique<TrueTypeFont>();
|
||||
|
||||
mFile = std::make_unique<File>(mPath);
|
||||
mFile->open(File::AccessMode::Read);
|
||||
|
||||
readOffsetSubtable();
|
||||
//std::cout << "Current offset: " << mCurrentOffset << std::endl;
|
||||
|
||||
logOffsetSubtable();
|
||||
|
||||
readTableDirectory();
|
||||
//std::cout << "Current offset: " << mCurrentOffset << std::endl;
|
||||
|
||||
for (unsigned idx=0; idx<mOffsetSubtable.num_tables; idx++)
|
||||
{
|
||||
readTable();
|
||||
//std::cout << "Current offset: " << mCurrentOffset << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
mFile->close();
|
||||
|
||||
|
||||
|
||||
|
||||
return std::move(mWorkingFont);
|
||||
}
|
||||
|
54
src/rendering/fonts/FontReader.h
Normal file
54
src/rendering/fonts/FontReader.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "File.h"
|
||||
#include "IFont.h"
|
||||
|
||||
class File;
|
||||
|
||||
class FontReader
|
||||
{
|
||||
public:
|
||||
~FontReader();
|
||||
void setPath(const std::string& path);
|
||||
|
||||
std::unique_ptr<IFont> read();
|
||||
|
||||
private:
|
||||
|
||||
struct OffsetSubtable
|
||||
{
|
||||
uint32_t scaler_type{0};
|
||||
uint16_t num_tables{0};
|
||||
uint16_t search_range{0};
|
||||
uint16_t entry_selector{0};
|
||||
uint16_t range_shift{0};
|
||||
};
|
||||
|
||||
struct Table
|
||||
{
|
||||
std::string name;
|
||||
unsigned checksum{0};
|
||||
unsigned offset{0};
|
||||
unsigned length{0};
|
||||
};
|
||||
|
||||
bool readOffsetSubtable();
|
||||
void logOffsetSubtable();
|
||||
void logTable(const Table& table);
|
||||
|
||||
void readTableDirectory();
|
||||
|
||||
void readTable();
|
||||
void readHeadTable();
|
||||
|
||||
unsigned mCurrentOffset{0};
|
||||
OffsetSubtable mOffsetSubtable;
|
||||
std::vector<Table> mTables;
|
||||
|
||||
std::unique_ptr<IFont> mWorkingFont;
|
||||
std::unique_ptr<File> mFile;
|
||||
std::string mPath;
|
||||
};
|
57
src/rendering/fonts/FontsManager.cpp
Normal file
57
src/rendering/fonts/FontsManager.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include "FontsManager.h"
|
||||
|
||||
#ifdef HAS_FREETYPE
|
||||
#include "FreeTypeFontEngine.h"
|
||||
#else
|
||||
#include "BasicFontEngine.h"
|
||||
#endif
|
||||
|
||||
#include "FontGlyph.h"
|
||||
|
||||
FontsManager::FontsManager()
|
||||
{
|
||||
#ifdef HAS_FREETYPE
|
||||
mFontEngine = std::make_unique<FreeTypeFontEngine>();
|
||||
mUsesGlyphs = true;
|
||||
#else
|
||||
mFontEngine = std::make_unique<BasicFontEngine>();
|
||||
#endif
|
||||
mFontEngine->initialize();
|
||||
}
|
||||
|
||||
std::unique_ptr<FontsManager> FontsManager::Create()
|
||||
{
|
||||
return std::make_unique<FontsManager>();
|
||||
}
|
||||
|
||||
bool FontsManager::usesGlyphs() const
|
||||
{
|
||||
return mUsesGlyphs;
|
||||
}
|
||||
|
||||
IFontEngine* FontsManager::getFontEngine() const
|
||||
{
|
||||
return mFontEngine.get();
|
||||
}
|
||||
|
||||
FontGlyph* FontsManager::getGlyph(const std::string& fontFace, float size, uint32_t c)
|
||||
{
|
||||
auto path = std::filesystem::path("truetype/liberation/LiberationSans-Regular.ttf");
|
||||
|
||||
mFontEngine->loadFontFace(path, size);
|
||||
|
||||
auto iter = mGlyphs.find(c);
|
||||
if(iter != mGlyphs.end())
|
||||
{
|
||||
return iter->second.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto glyph = mFontEngine->loadGlyph(c);
|
||||
auto glyph_ptr = glyph.get();
|
||||
mGlyphs[c] = std::move(glyph);
|
||||
return glyph_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
28
src/rendering/fonts/FontsManager.h
Normal file
28
src/rendering/fonts/FontsManager.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "IFontEngine.h"
|
||||
#include "FontGlyph.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class FontsManager
|
||||
{
|
||||
public:
|
||||
FontsManager();
|
||||
static std::unique_ptr<FontsManager> Create();
|
||||
|
||||
IFontEngine* getFontEngine() const;
|
||||
|
||||
bool usesGlyphs() const;
|
||||
|
||||
FontGlyph* getGlyph(const std::string& fontFace, float size, uint32_t c);
|
||||
|
||||
private:
|
||||
bool mUsesGlyphs{ false };
|
||||
std::unique_ptr<IFontEngine> mFontEngine;
|
||||
std::unordered_map<uint32_t, std::unique_ptr<FontGlyph> > mGlyphs;
|
||||
};
|
||||
|
||||
using FontsManagerPtr = std::unique_ptr<FontsManager>;
|
103
src/rendering/fonts/FreeTypeFontEngine.cpp
Normal file
103
src/rendering/fonts/FreeTypeFontEngine.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include "FreeTypeFontEngine.h"
|
||||
|
||||
#include "Image.h"
|
||||
#include "Grid.h"
|
||||
#include "FileLogger.h"
|
||||
#include "FontGlyph.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void FreeTypeFontEngine::initialize()
|
||||
{
|
||||
if (mLibrary)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto error = FT_Init_FreeType(&mLibrary);
|
||||
if (error)
|
||||
{
|
||||
MLOG_ERROR("Error initializing FreeType. Code " << static_cast<int>(error));
|
||||
}
|
||||
}
|
||||
|
||||
void FreeTypeFontEngine::loadFontFace(const std::filesystem::path& fontFile, float penSize)
|
||||
{
|
||||
if (!mLibrary)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
if (mWorkingFontFace)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto full_path = mSystemFontLocation / fontFile;
|
||||
const auto error = FT_New_Face(mLibrary, full_path.c_str(), 0, &mWorkingFontFace );
|
||||
if ( error == FT_Err_Unknown_File_Format )
|
||||
{
|
||||
MLOG_ERROR("Found file but format not supported. Code " << static_cast<int>(error));
|
||||
}
|
||||
else if ( error )
|
||||
{
|
||||
MLOG_ERROR("Failed to find or open file. Code " << static_cast<int>(error));
|
||||
}
|
||||
FT_Set_Pixel_Sizes(mWorkingFontFace, penSize, 0);
|
||||
}
|
||||
|
||||
std::unique_ptr<FontGlyph> FreeTypeFontEngine::loadGlyph(uint32_t charCode)
|
||||
{
|
||||
auto glyph_index = FT_Get_Char_Index( mWorkingFontFace, charCode );
|
||||
if (glyph_index == 0)
|
||||
{
|
||||
MLOG_ERROR("Got the null glyph");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto error = FT_Load_Glyph(mWorkingFontFace, glyph_index, FT_LOAD_DEFAULT );
|
||||
if (error == FT_Err_Invalid_Argument)
|
||||
{
|
||||
MLOG_ERROR("Error loading glyph - bad arg. Code " << static_cast<int>(error));
|
||||
return nullptr;
|
||||
}
|
||||
else if(error)
|
||||
{
|
||||
MLOG_ERROR("Error loading glyph. Code " << static_cast<int>(error));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mWorkingFontFace->glyph->format != FT_GLYPH_FORMAT_BITMAP)
|
||||
{
|
||||
error = FT_Render_Glyph( mWorkingFontFace->glyph, FT_RENDER_MODE_NORMAL );
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
MLOG_ERROR("Error rendering glyph. Code " << static_cast<int>(error));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto rows = mWorkingFontFace->glyph->bitmap.rows;
|
||||
auto columns = mWorkingFontFace->glyph->bitmap.width;
|
||||
auto image = std::make_unique<Image>(columns, rows);
|
||||
|
||||
unsigned counter = 0;
|
||||
std::vector<unsigned char> data(rows*columns, 0);
|
||||
for (unsigned idx=0; idx<rows; idx++)
|
||||
{
|
||||
for (unsigned jdx=0; jdx<columns; jdx++)
|
||||
{
|
||||
data[counter] = mWorkingFontFace->glyph->bitmap.buffer[counter];
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
image->getGridT<unsigned char>()->setData(data);
|
||||
auto glyph = std::make_unique<FontGlyph>(mWorkingFontFace->glyph->bitmap.width,
|
||||
mWorkingFontFace->glyph->bitmap.rows,
|
||||
mWorkingFontFace->glyph->bitmap_left,
|
||||
mWorkingFontFace->glyph->bitmap_top,
|
||||
mWorkingFontFace->glyph->advance.x,
|
||||
std::move(image));
|
||||
|
||||
return glyph;
|
||||
}
|
28
src/rendering/fonts/FreeTypeFontEngine.h
Normal file
28
src/rendering/fonts/FreeTypeFontEngine.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "IFontEngine.h"
|
||||
|
||||
#include "Image.h"
|
||||
|
||||
class Image;
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
class FreeTypeFontEngine : public IFontEngine
|
||||
{
|
||||
public:
|
||||
FreeTypeFontEngine() = default;
|
||||
|
||||
void initialize() override;
|
||||
|
||||
void loadFontFace(const std::filesystem::path& fontFile, float penSize = 16) override;
|
||||
|
||||
std::unique_ptr<FontGlyph> loadGlyph(uint32_t charCode) override;
|
||||
|
||||
private:
|
||||
std::filesystem::path mSystemFontLocation{"/usr/share/fonts/"};
|
||||
|
||||
FT_Face mWorkingFontFace{nullptr};
|
||||
FT_Library mLibrary{nullptr};
|
||||
};
|
8
src/rendering/fonts/IFont.h
Normal file
8
src/rendering/fonts/IFont.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
class IFont
|
||||
{
|
||||
public:
|
||||
virtual ~IFont() = default;
|
||||
virtual void dumpInfo() = 0;
|
||||
};
|
19
src/rendering/fonts/IFontEngine.h
Normal file
19
src/rendering/fonts/IFontEngine.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
|
||||
class FontGlyph;
|
||||
|
||||
class IFontEngine
|
||||
{
|
||||
public:
|
||||
IFontEngine() = default;
|
||||
virtual ~IFontEngine() = default;
|
||||
|
||||
virtual void initialize(){};
|
||||
|
||||
virtual void loadFontFace(const std::filesystem::path& fontFile, float penSize = 16) = 0;
|
||||
|
||||
virtual std::unique_ptr<FontGlyph> loadGlyph(uint32_t charCode) = 0;
|
||||
};
|
31
src/rendering/fonts/TrueTypeFont.cpp
Normal file
31
src/rendering/fonts/TrueTypeFont.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include "TrueTypeFont.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
std::string TrueTypeFont::logHeadTable() const
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "Head Table\n";
|
||||
sstr << "version: " << mHeadTable.version << "\n";
|
||||
sstr << "fontRevision: " << mHeadTable.fontRevision << "\n";
|
||||
sstr << "checksumAdjustment: " << mHeadTable.checksumAdjustment << "\n";
|
||||
sstr << "magicNumber: " << mHeadTable.magicNumber << "\n";
|
||||
sstr << "flags: " << mHeadTable.flags << "\n";
|
||||
sstr << "unitsPerEm: " << mHeadTable.unitsPerEm << "\n";
|
||||
sstr << "created: " << mHeadTable.created << "\n";
|
||||
sstr << "modified: " << mHeadTable.modified << "\n";
|
||||
sstr << "xMin: " << mHeadTable.xMin << "\n";
|
||||
sstr << "yMin: " << mHeadTable.yMin << "\n";
|
||||
sstr << "xMax: " << mHeadTable.xMax << "\n";
|
||||
sstr << "yMax: " << mHeadTable.yMax << "\n";
|
||||
sstr << "macStyle: " << mHeadTable.macStyle << "\n";
|
||||
sstr << "lowestRecPPEM: " << mHeadTable.lowestRecPPEM << "\n";
|
||||
sstr << "fontDirectionHint: " << mHeadTable.fontDirectionHint << "\n";
|
||||
sstr << "indexToLocFormat: " << mHeadTable.indexToLocFormat << "\n";
|
||||
sstr << "glyphDataFormat: " << mHeadTable.glyphDataFormat << "\n";
|
||||
return sstr.str();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
52
src/rendering/fonts/TrueTypeFont.h
Normal file
52
src/rendering/fonts/TrueTypeFont.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
#include "IFont.h"
|
||||
|
||||
class TrueTypeFont : public IFont
|
||||
{
|
||||
public:
|
||||
|
||||
using Fixed = int32_t;
|
||||
using LongDateTime = int64_t;
|
||||
using FWord = int16_t;
|
||||
|
||||
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6head.html
|
||||
struct HeadTable
|
||||
{
|
||||
Fixed version{0};
|
||||
Fixed fontRevision{0};
|
||||
uint32_t checksumAdjustment{0};
|
||||
uint32_t magicNumber{0};
|
||||
uint16_t flags{0};
|
||||
uint16_t unitsPerEm{0};
|
||||
LongDateTime created{0};
|
||||
LongDateTime modified{0};
|
||||
FWord xMin{0};
|
||||
FWord yMin{0};
|
||||
FWord xMax{0};
|
||||
FWord yMax{0};
|
||||
uint16_t macStyle{0};
|
||||
uint16_t lowestRecPPEM{0};
|
||||
int16_t fontDirectionHint{0};
|
||||
int16_t indexToLocFormat{0};
|
||||
int16_t glyphDataFormat{0};
|
||||
};
|
||||
|
||||
std::string logHeadTable() const;
|
||||
|
||||
void setHeadTable(const HeadTable& table)
|
||||
{
|
||||
mHeadTable = table;
|
||||
}
|
||||
|
||||
void dumpInfo() override
|
||||
{
|
||||
//std::cout << "Got ttf" << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
HeadTable mHeadTable;
|
||||
};
|
54
src/rendering/fonts/directx/DirectWriteFontEngine.cpp
Normal file
54
src/rendering/fonts/directx/DirectWriteFontEngine.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include "DirectWriteFontEngine.h"
|
||||
|
||||
#include "FontGlyph.h"
|
||||
#include "UnicodeUtils.h"
|
||||
|
||||
#include "DirectWriteHelpers.h"
|
||||
|
||||
#include <dwrite.h>
|
||||
|
||||
void DirectWriteFontEngine::initialize()
|
||||
{
|
||||
mIsValid = SUCCEEDED(::DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory));
|
||||
|
||||
loadFontFaceFromName("Verdana", 16);
|
||||
}
|
||||
|
||||
void DirectWriteFontEngine::initializeOffScreenRenderer()
|
||||
{
|
||||
if (mOffScreenRenderer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto pInterface = OffScreenTextRenderer::Create();
|
||||
pInterface->QueryInterface(IID_IOffScreenTextRenderer, &mOffScreenRenderer);
|
||||
}
|
||||
|
||||
void DirectWriteFontEngine::loadFontFaceFromName(const std::string& fontName, float penSize)
|
||||
{
|
||||
mDWriteFactory->CreateTextFormat(UnicodeUtils::utf8ToUtf16WString(fontName).c_str(), nullptr, DWRITE_FONT_WEIGHT_NORMAL,
|
||||
DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, penSize, L"en-us", &mTextFormat);
|
||||
}
|
||||
|
||||
std::unique_ptr<FontGlyph> DirectWriteFontEngine::loadGlyph(uint32_t charCode)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<GlyphRunOutlines> DirectWriteFontEngine::getGlyphRunOutlines(const std::vector<uint32_t>& charCodes)
|
||||
{
|
||||
initializeOffScreenRenderer();
|
||||
|
||||
std::wstring text;
|
||||
for (auto code : charCodes)
|
||||
{
|
||||
text.push_back(code);
|
||||
}
|
||||
|
||||
auto hr = mDWriteFactory->CreateTextLayout(text.c_str(), static_cast<UINT32>(text.size()), mTextFormat.Get(), 50.0, 50.0, &mTextLayout);
|
||||
|
||||
mTextLayout->Draw(nullptr, mOffScreenRenderer.Get(), 0.0, 0.0);
|
||||
|
||||
return mOffScreenRenderer->getGlypyRunOutline();
|
||||
}
|
||||
|
38
src/rendering/fonts/directx/DirectWriteFontEngine.h
Normal file
38
src/rendering/fonts/directx/DirectWriteFontEngine.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include "IFontEngine.h"
|
||||
#include "FontGlyph.h"
|
||||
|
||||
#include <wrl.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class GlyphOutlineGeometrySink;
|
||||
class OffScreenTextRenderer;
|
||||
|
||||
struct IDWriteFactory;
|
||||
struct IDWriteTextFormat;
|
||||
struct IDWriteTextLayout;
|
||||
|
||||
class DirectWriteFontEngine : public IFontEngine
|
||||
{
|
||||
public:
|
||||
void initialize() override;
|
||||
|
||||
void loadFontFace(const std::filesystem::path& fontFile, float penSize = 16) override {};
|
||||
|
||||
void loadFontFaceFromName(const std::string& fontName, float penSize = 16);
|
||||
|
||||
std::unique_ptr<FontGlyph> loadGlyph(uint32_t charCode) override;
|
||||
|
||||
std::unique_ptr<GlyphRunOutlines> getGlyphRunOutlines(const std::vector<uint32_t>& charCodes);
|
||||
|
||||
private:
|
||||
void initializeOffScreenRenderer();
|
||||
|
||||
bool mIsValid{ false };
|
||||
Microsoft::WRL::ComPtr<IDWriteFactory> mDWriteFactory;
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> mTextFormat;
|
||||
Microsoft::WRL::ComPtr<IDWriteTextLayout> mTextLayout;
|
||||
Microsoft::WRL::ComPtr<OffScreenTextRenderer> mOffScreenRenderer;
|
||||
};
|
240
src/rendering/fonts/directx/DirectWriteHelpers.cpp
Normal file
240
src/rendering/fonts/directx/DirectWriteHelpers.cpp
Normal file
|
@ -0,0 +1,240 @@
|
|||
#include "DirectWriteHelpers.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include <wrl.h>
|
||||
|
||||
GlyphOutlineGeometrySink::GlyphOutlineGeometrySink()
|
||||
: mGlyphRunOutline(std::make_unique<GlyphRunOutlines>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
IUnknown* GlyphOutlineGeometrySink::Create()
|
||||
{
|
||||
return static_cast<IGlyphOutlineGeometrySink*>(new GlyphOutlineGeometrySink);
|
||||
}
|
||||
|
||||
HRESULT __stdcall GlyphOutlineGeometrySink::QueryInterface(const IID& iid, void** ppv)
|
||||
{
|
||||
if (IsEqualIID(iid, __uuidof(IUnknown)))
|
||||
{
|
||||
*ppv = static_cast<IGlyphOutlineGeometrySink*>(this);
|
||||
}
|
||||
else if (IsEqualIID(iid, IID_ID2D1SimplifiedGeometrySink))
|
||||
{
|
||||
*ppv = static_cast<IGlyphOutlineGeometrySink*>(this);
|
||||
}
|
||||
else if (IsEqualIID(iid, IID_IGlyphOutlineGeometrySink))
|
||||
{
|
||||
*ppv = static_cast<IGlyphOutlineGeometrySink*>(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppv = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ULONG __stdcall GlyphOutlineGeometrySink::AddRef()
|
||||
{
|
||||
return ::InterlockedIncrement(&mRefCount);
|
||||
}
|
||||
|
||||
ULONG __stdcall GlyphOutlineGeometrySink::Release()
|
||||
{
|
||||
return 0;
|
||||
if (::InterlockedDecrement(&mRefCount) == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRefCount;
|
||||
}
|
||||
|
||||
void __stdcall GlyphOutlineGeometrySink::SetFillMode(D2D1_FILL_MODE fillMode)
|
||||
{
|
||||
//MLOG_INFO("SetFillMode: " << bool(fillMode == D2D1_FILL_MODE_ALTERNATE));
|
||||
}
|
||||
|
||||
void __stdcall GlyphOutlineGeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT vertexFlags)
|
||||
{
|
||||
if (vertexFlags == D2D1_PATH_SEGMENT_NONE)
|
||||
{
|
||||
}
|
||||
else if (vertexFlags == D2D1_PATH_SEGMENT_FORCE_UNSTROKED)
|
||||
{
|
||||
}
|
||||
else if (vertexFlags == D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN)
|
||||
{
|
||||
}
|
||||
else if (vertexFlags == D2D1_PATH_SEGMENT_FORCE_DWORD)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void __stdcall GlyphOutlineGeometrySink::BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
|
||||
{
|
||||
mGlyphRunOutline->startFeature(Point(startPoint.x, startPoint.y), figureBegin == D2D1_FIGURE_BEGIN_FILLED);
|
||||
}
|
||||
|
||||
void __stdcall GlyphOutlineGeometrySink::AddLines(_In_reads_(pointsCount) CONST D2D1_POINT_2F* points, UINT32 pointsCount)
|
||||
{
|
||||
GlyphRunSegment segment;
|
||||
segment.mType = GlyphRunSegment::Type::LINE;
|
||||
for (UINT32 idx = 0; idx < pointsCount; idx++)
|
||||
{
|
||||
auto point = points[idx];
|
||||
segment.mPoints.push_back(Point(point.x, point.y));
|
||||
}
|
||||
mGlyphRunOutline->addSegment(segment);
|
||||
}
|
||||
|
||||
void __stdcall GlyphOutlineGeometrySink::AddBeziers(_In_reads_(beziersCount) CONST D2D1_BEZIER_SEGMENT* beziers, UINT32 beziersCount)
|
||||
{
|
||||
for (UINT32 idx = 0; idx < beziersCount; idx++)
|
||||
{
|
||||
GlyphRunSegment segment;
|
||||
segment.mType = GlyphRunSegment::Type::BEZIER;
|
||||
|
||||
auto bezier = beziers[idx];
|
||||
segment.mPoints.push_back(Point(bezier.point1.x, bezier.point1.y));
|
||||
segment.mPoints.push_back(Point(bezier.point2.x, bezier.point2.y));
|
||||
segment.mPoints.push_back(Point(bezier.point3.x, bezier.point3.y));
|
||||
|
||||
mGlyphRunOutline->addSegment(segment);
|
||||
}
|
||||
}
|
||||
|
||||
void __stdcall GlyphOutlineGeometrySink::EndFigure(D2D1_FIGURE_END figureEnd)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
HRESULT __stdcall GlyphOutlineGeometrySink::Close()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
std::unique_ptr<GlyphRunOutlines> GlyphOutlineGeometrySink::getGlypyRunOutline()
|
||||
{
|
||||
return std::move(mGlyphRunOutline);
|
||||
}
|
||||
|
||||
IUnknown* OffScreenTextRenderer::Create()
|
||||
{
|
||||
return static_cast<IOffScreenTextRenderer*>(new OffScreenTextRenderer);
|
||||
}
|
||||
|
||||
HRESULT __stdcall OffScreenTextRenderer::QueryInterface(const IID& iid, void** ppv)
|
||||
{
|
||||
if (IsEqualIID(iid, __uuidof(IUnknown)))
|
||||
{
|
||||
*ppv = static_cast<IOffScreenTextRenderer*>(this);
|
||||
}
|
||||
else if (IsEqualIID(iid, __uuidof(IDWritePixelSnapping)))
|
||||
{
|
||||
*ppv = static_cast<IOffScreenTextRenderer*>(this);
|
||||
}
|
||||
else if (IsEqualIID(iid, __uuidof(IDWriteTextRenderer)))
|
||||
{
|
||||
*ppv = static_cast<IOffScreenTextRenderer*>(this);
|
||||
}
|
||||
else if (IsEqualIID(iid, IID_IOffScreenTextRenderer))
|
||||
{
|
||||
*ppv = static_cast<IOffScreenTextRenderer*>(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppv = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ULONG __stdcall OffScreenTextRenderer::AddRef()
|
||||
{
|
||||
return ::InterlockedIncrement(&mRefCount);
|
||||
}
|
||||
|
||||
ULONG __stdcall OffScreenTextRenderer::Release()
|
||||
{
|
||||
return 0;
|
||||
if (::InterlockedDecrement(&mRefCount) == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRefCount;
|
||||
}
|
||||
|
||||
HRESULT __stdcall OffScreenTextRenderer::DrawGlyphRun(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode,
|
||||
_In_ DWRITE_GLYPH_RUN const* glyphRun, _In_ DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, _In_opt_ IUnknown* clientDrawingEffect)
|
||||
{
|
||||
auto pInterface = GlyphOutlineGeometrySink::Create();
|
||||
Microsoft::WRL::ComPtr<GlyphOutlineGeometrySink> sink;
|
||||
pInterface->QueryInterface(IID_IGlyphOutlineGeometrySink, &sink);
|
||||
|
||||
auto hr = glyphRun->fontFace->GetGlyphRunOutline(
|
||||
glyphRun->fontEmSize,
|
||||
glyphRun->glyphIndices,
|
||||
glyphRun->glyphAdvances,
|
||||
glyphRun->glyphOffsets,
|
||||
glyphRun->glyphCount,
|
||||
glyphRun->isSideways,
|
||||
glyphRun->bidiLevel % 2,
|
||||
sink.Get()
|
||||
);
|
||||
sink->Close();
|
||||
|
||||
mGlyphRunOutline = sink->getGlypyRunOutline();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall OffScreenTextRenderer::DrawUnderline(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, _In_ DWRITE_UNDERLINE const* underline,
|
||||
_In_opt_ IUnknown* clientDrawingEffect)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall OffScreenTextRenderer::DrawStrikethrough(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, _In_ DWRITE_STRIKETHROUGH const* strikethrough,
|
||||
_In_opt_ IUnknown* clientDrawingEffect)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall OffScreenTextRenderer::DrawInlineObject(_In_opt_ void* clientDrawingContext, FLOAT originX, FLOAT originY, _In_ IDWriteInlineObject* inlineObject,
|
||||
BOOL isSideways, BOOL isRightToLeft, _In_opt_ IUnknown* clientDrawingEffect)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall OffScreenTextRenderer::IsPixelSnappingDisabled(_In_opt_ void* clientDrawingContext, _Out_ BOOL* isDisabled)
|
||||
{
|
||||
*isDisabled = FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall OffScreenTextRenderer::GetCurrentTransform(_In_opt_ void* clientDrawingContext, _Out_ DWRITE_MATRIX* transform)
|
||||
{
|
||||
*transform = DWRITE_MATRIX(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __stdcall OffScreenTextRenderer::GetPixelsPerDip(_In_opt_ void* clientDrawingContext, _Out_ FLOAT* pixelsPerDip)
|
||||
{
|
||||
*pixelsPerDip = 1.0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
std::unique_ptr<GlyphRunOutlines> OffScreenTextRenderer::getGlypyRunOutline()
|
||||
{
|
||||
return std::move(mGlyphRunOutline);
|
||||
}
|
90
src/rendering/fonts/directx/DirectWriteHelpers.h
Normal file
90
src/rendering/fonts/directx/DirectWriteHelpers.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
#pragma once
|
||||
|
||||
#include "FontGlyph.h"
|
||||
|
||||
#include <d2d1_1.h>
|
||||
#include <dwrite.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
static const IID IID_IGlyphOutlineGeometrySink = { 0xaaf6ab8d, 0xd6cf, 0x4a3b, { 0xa6, 0x7a, 0x12, 0xf1, 0x42, 0xe0, 0x6b, 0xb9 } };
|
||||
class IGlyphOutlineGeometrySink : public IDWriteGeometrySink
|
||||
{
|
||||
public:
|
||||
virtual std::unique_ptr<GlyphRunOutlines> getGlypyRunOutline() = 0;
|
||||
};
|
||||
|
||||
class GlyphOutlineGeometrySink :public IGlyphOutlineGeometrySink
|
||||
{
|
||||
public:
|
||||
GlyphOutlineGeometrySink();
|
||||
|
||||
// IUnknown
|
||||
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
|
||||
virtual ULONG __stdcall AddRef();
|
||||
virtual ULONG __stdcall Release();
|
||||
|
||||
static IUnknown* Create();
|
||||
|
||||
// IDWriteGeometrySink aka ID2D1SimplifiedGeometrySink
|
||||
STDMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode);
|
||||
|
||||
STDMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags);
|
||||
|
||||
STDMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin);
|
||||
|
||||
STDMETHOD_(void, AddLines)(_In_reads_(pointsCount) CONST D2D1_POINT_2F* points, UINT32 pointsCount);
|
||||
|
||||
STDMETHOD_(void, AddBeziers)(_In_reads_(beziersCount) CONST D2D1_BEZIER_SEGMENT* beziers, UINT32 beziersCount);
|
||||
|
||||
STDMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd);
|
||||
|
||||
STDMETHOD(Close)();
|
||||
|
||||
// IGlyphOutlineGeometrySink
|
||||
std::unique_ptr<GlyphRunOutlines> getGlypyRunOutline() override;
|
||||
private:
|
||||
std::unique_ptr<GlyphRunOutlines> mGlyphRunOutline;
|
||||
long mRefCount{ 0 };
|
||||
};
|
||||
|
||||
|
||||
static const IID IID_IOffScreenTextRenderer = { 0xa43b0c49, 0x6080, 0x4731, { 0xa8, 0x72, 0x61, 0x50, 0x47, 0x3, 0x78, 0x10 } };
|
||||
class IOffScreenTextRenderer : public IDWriteTextRenderer
|
||||
{
|
||||
virtual std::unique_ptr<GlyphRunOutlines> getGlypyRunOutline() = 0;
|
||||
};
|
||||
|
||||
class OffScreenTextRenderer :public IOffScreenTextRenderer
|
||||
{
|
||||
public:
|
||||
// IUnknown
|
||||
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
|
||||
virtual ULONG __stdcall AddRef();
|
||||
virtual ULONG __stdcall Release();
|
||||
|
||||
static IUnknown* Create();
|
||||
|
||||
STDMETHOD(DrawGlyphRun)(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode,
|
||||
_In_ DWRITE_GLYPH_RUN const* glyphRun, _In_ DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, _In_opt_ IUnknown* clientDrawingEffect);
|
||||
|
||||
STDMETHOD(DrawUnderline)(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, _In_ DWRITE_UNDERLINE const* underline,
|
||||
_In_opt_ IUnknown* clientDrawingEffect);
|
||||
|
||||
STDMETHOD(DrawStrikethrough)(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, _In_ DWRITE_STRIKETHROUGH const* strikethrough,
|
||||
_In_opt_ IUnknown* clientDrawingEffect);
|
||||
|
||||
STDMETHOD(DrawInlineObject)(_In_opt_ void* clientDrawingContext, FLOAT originX, FLOAT originY, _In_ IDWriteInlineObject* inlineObject,
|
||||
BOOL isSideways, BOOL isRightToLeft, _In_opt_ IUnknown* clientDrawingEffect);
|
||||
|
||||
STDMETHOD(IsPixelSnappingDisabled)(_In_opt_ void* clientDrawingContext, _Out_ BOOL* isDisabled);
|
||||
|
||||
STDMETHOD(GetCurrentTransform)(_In_opt_ void* clientDrawingContext, _Out_ DWRITE_MATRIX* transform);
|
||||
|
||||
STDMETHOD(GetPixelsPerDip)(_In_opt_ void* clientDrawingContext, _Out_ FLOAT* pixelsPerDip);
|
||||
|
||||
std::unique_ptr<GlyphRunOutlines> getGlypyRunOutline() override;
|
||||
private:
|
||||
std::unique_ptr<GlyphRunOutlines> mGlyphRunOutline;
|
||||
long mRefCount{ 0 };
|
||||
};
|
20
src/rendering/graphics/AbstractPainter.h
Normal file
20
src/rendering/graphics/AbstractPainter.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
class DrawingContext;
|
||||
|
||||
class AbstractPainter
|
||||
{
|
||||
public:
|
||||
AbstractPainter(DrawingContext* context)
|
||||
: mDrawingContext(context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~AbstractPainter() = default;
|
||||
virtual void paint() = 0;
|
||||
virtual bool supportsGeometryPrimitives() const { return false; };
|
||||
|
||||
protected:
|
||||
DrawingContext* mDrawingContext{ nullptr };
|
||||
};
|
89
src/rendering/graphics/CMakeLists.txt
Normal file
89
src/rendering/graphics/CMakeLists.txt
Normal file
|
@ -0,0 +1,89 @@
|
|||
set(MODULE_NAME graphics)
|
||||
|
||||
message(STATUS "Checking dependencies for module: " ${MODULE_NAME})
|
||||
|
||||
set(platform_LIB_INCLUDES "")
|
||||
set(platform_INCLUDE_DIRS "")
|
||||
set(platform_HEADERS "")
|
||||
set(platform_LIBS "")
|
||||
|
||||
list(APPEND graphics_LIB_INCLUDES
|
||||
DrawingContext.cpp
|
||||
DrawingSurface.cpp
|
||||
RasterPainter.cpp
|
||||
PainterFactory.cpp
|
||||
${platform_LIB_INCLUDES}
|
||||
)
|
||||
|
||||
list(APPEND graphics_HEADERS
|
||||
${platform_HEADERS}
|
||||
RasterPainter.h
|
||||
DrawingContext.h
|
||||
PainterFactory.h
|
||||
AbstractPainter.h
|
||||
DrawingSurface.h
|
||||
)
|
||||
if(UNIX)
|
||||
set(OpenGL_GL_PREFERENCE "GLVND")
|
||||
find_package(OpenGL QUIET)
|
||||
if (OpenGL_FOUND)
|
||||
list(APPEND platform_LIBS OpenGL::GL OpenGL::GLU)
|
||||
list(APPEND graphics_LIB_INCLUDES
|
||||
opengl/OpenGlPainter.cpp
|
||||
opengl/OpenGlTextPainter.cpp
|
||||
opengl/OpenGlMeshPainter.cpp
|
||||
opengl/OpenGlFontTexture.cpp
|
||||
opengl/OpenGlShaderProgram.cpp
|
||||
)
|
||||
list(APPEND ${MODULE_NAME}
|
||||
opengl/OpenGlPainter.h
|
||||
opengl/OpenGlTextPainter.h
|
||||
opengl/OpenGlMeshPainter.h
|
||||
opengl/OpenGlFontTexture.h
|
||||
opengl/OpenGlShaderProgram.h)
|
||||
list(APPEND DEFINES "HAS_OPENGL")
|
||||
else()
|
||||
message(STATUS "OpenGL not found - skipping support")
|
||||
endif()
|
||||
else()
|
||||
list(APPEND graphics_LIB_INCLUDES
|
||||
directx/DirectXInterface.cpp
|
||||
directx/DirectX2dInterface.cpp
|
||||
directx/DirectXMesh.cpp
|
||||
directx/DirectXPainter.cpp
|
||||
directx/DirectX2dPainter.cpp
|
||||
directx/DirectXTextPainter.cpp
|
||||
directx/DirectXMeshPainter.cpp
|
||||
directx/DirectXShaderProgram.cpp
|
||||
)
|
||||
list(APPEND graphics_HEADERS
|
||||
directx/DirectXInterface.h
|
||||
directx/DirectX2dInterface.h
|
||||
directx/DirectXMesh.h
|
||||
directx/DirectXPainter.h
|
||||
directx/DirectX2dPainter.h
|
||||
directx/DirectXTextPainter.h
|
||||
directx/DirectXMeshPainter.h
|
||||
directx/DirectXShaderProgram.h
|
||||
)
|
||||
|
||||
find_package(DirectX-Headers REQUIRED)
|
||||
list(APPEND platform_LIBS D3D12.lib D3DCompiler.lib DXGI.lib Dwrite.lib D2d1.lib D3D11.lib Microsoft::DirectX-Headers)
|
||||
endif()
|
||||
|
||||
add_library(${MODULE_NAME} SHARED
|
||||
${graphics_LIB_INCLUDES}
|
||||
${graphics_HEADERS})
|
||||
|
||||
target_include_directories(${MODULE_NAME} PUBLIC
|
||||
${platform_INCLUDE_DIRS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/opengl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/directx
|
||||
)
|
||||
|
||||
target_compile_definitions(${MODULE_NAME} PRIVATE ${DEFINES})
|
||||
target_link_libraries(${MODULE_NAME} PUBLIC geometry mesh fonts image visual_elements ${platform_LIBS})
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/rendering)
|
||||
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
50
src/rendering/graphics/DrawingContext.cpp
Normal file
50
src/rendering/graphics/DrawingContext.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include "DrawingContext.h"
|
||||
|
||||
#include "AbstractPainter.h"
|
||||
#include "PainterFactory.h"
|
||||
|
||||
#include "Grid.h"
|
||||
#include "TriMesh.h"
|
||||
|
||||
#include "DrawingSurface.h"
|
||||
#include "Scene.h"
|
||||
|
||||
DrawingContext::DrawingContext(DrawingSurface* surface, FontsManager* fontsManager, DrawingMode requestedDrawingMode)
|
||||
: mSurface(surface),
|
||||
mDrawingMode(requestedDrawingMode),
|
||||
mFontsManager(fontsManager)
|
||||
{
|
||||
mPainter = PainterFactory::Create(this, mDrawingMode);
|
||||
|
||||
surface->getScene()->setSupportsGeometryPrimitives(mPainter->supportsGeometryPrimitives());
|
||||
surface->getScene()->setFontsManager(fontsManager);
|
||||
}
|
||||
|
||||
std::unique_ptr<DrawingContext> DrawingContext::Create(DrawingSurface* surface, FontsManager* fontsManager, DrawingMode requestedDrawingMode)
|
||||
{
|
||||
return std::make_unique<DrawingContext>(surface, fontsManager, requestedDrawingMode);
|
||||
}
|
||||
|
||||
DrawingSurface* DrawingContext::getSurface() const
|
||||
{
|
||||
return mSurface;
|
||||
}
|
||||
|
||||
FontsManager* DrawingContext::getFontsManager() const
|
||||
{
|
||||
return mFontsManager;
|
||||
}
|
||||
|
||||
void DrawingContext::paint()
|
||||
{
|
||||
if (mDrawingMode == DrawingMode::GRAPH)
|
||||
{
|
||||
mSurface->getScene()->update();
|
||||
}
|
||||
mPainter->paint();
|
||||
}
|
||||
|
||||
AbstractPainter* DrawingContext::getPainter() const
|
||||
{
|
||||
return mPainter.get();
|
||||
}
|
39
src/rendering/graphics/DrawingContext.h
Normal file
39
src/rendering/graphics/DrawingContext.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class AbstractPainter;
|
||||
class DrawingSurface;
|
||||
class FontsManager;
|
||||
|
||||
enum class DrawingMode
|
||||
{
|
||||
RASTER,
|
||||
GRAPH
|
||||
};
|
||||
|
||||
class DrawingContext
|
||||
{
|
||||
public:
|
||||
DrawingContext(DrawingSurface* surface, FontsManager* fontsManager = nullptr, DrawingMode requestedDrawingMode = DrawingMode::GRAPH);
|
||||
|
||||
static std::unique_ptr<DrawingContext> Create(DrawingSurface* surface, FontsManager* fontsManager, DrawingMode requestedDrawingMode);
|
||||
|
||||
DrawingSurface* getSurface() const;
|
||||
|
||||
FontsManager* getFontsManager() const;
|
||||
|
||||
void paint();
|
||||
|
||||
AbstractPainter* getPainter() const;
|
||||
|
||||
private:
|
||||
DrawingMode mDrawingMode;
|
||||
FontsManager* mFontsManager{nullptr};
|
||||
DrawingSurface* mSurface{nullptr};
|
||||
|
||||
std::unique_ptr<AbstractPainter> mPainter;
|
||||
};
|
||||
|
||||
using DrawingContextPtr = std::unique_ptr<DrawingContext>;
|
50
src/rendering/graphics/DrawingSurface.cpp
Normal file
50
src/rendering/graphics/DrawingSurface.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include "DrawingSurface.h"
|
||||
|
||||
#include "Image.h"
|
||||
#include "Scene.h"
|
||||
|
||||
#include "RootNode.h"
|
||||
|
||||
DrawingSurface::DrawingSurface()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<DrawingSurface> DrawingSurface::Create()
|
||||
{
|
||||
return std::make_unique<DrawingSurface>();
|
||||
}
|
||||
|
||||
void DrawingSurface::setSize(unsigned width, unsigned height, bool triggerResize)
|
||||
{
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
unsigned DrawingSurface::getWidth() const
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
unsigned DrawingSurface::getHeight() const
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
Scene* DrawingSurface::getScene()
|
||||
{
|
||||
if (!mScene)
|
||||
{
|
||||
mScene = std::make_unique<Scene>();
|
||||
}
|
||||
return mScene.get();
|
||||
}
|
||||
|
||||
Image* DrawingSurface::getImage()
|
||||
{
|
||||
if (!mBackingImage)
|
||||
{
|
||||
mBackingImage = std::make_unique<Image>(mWidth, mHeight);
|
||||
}
|
||||
return mBackingImage.get();
|
||||
}
|
31
src/rendering/graphics/DrawingSurface.h
Normal file
31
src/rendering/graphics/DrawingSurface.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
class Scene;
|
||||
class Image;
|
||||
|
||||
class DrawingSurface
|
||||
{
|
||||
public:
|
||||
DrawingSurface();
|
||||
virtual ~DrawingSurface() = default;
|
||||
|
||||
static std::unique_ptr<DrawingSurface> Create();
|
||||
|
||||
virtual void setSize(unsigned width, unsigned height, bool triggerResize = true);
|
||||
|
||||
unsigned getWidth() const;
|
||||
|
||||
unsigned getHeight() const;
|
||||
|
||||
Image* getImage();
|
||||
|
||||
Scene* getScene();
|
||||
|
||||
protected:
|
||||
unsigned mWidth = 0;
|
||||
unsigned mHeight = 0;
|
||||
std::unique_ptr<Scene> mScene;
|
||||
std::unique_ptr<Image> mBackingImage;
|
||||
};
|
50
src/rendering/graphics/PainterFactory.cpp
Normal file
50
src/rendering/graphics/PainterFactory.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include "PainterFactory.h"
|
||||
|
||||
#ifdef HAS_OPENGL
|
||||
#include "OpenGlPainter.h"
|
||||
#include "OpenGlMeshPainter.h"
|
||||
#include "OpenGlTextPainter.h"
|
||||
#include "OpenGlShaderProgram.h"
|
||||
#include "OpenGlFontTexture.h"
|
||||
#endif
|
||||
|
||||
#include "Grid.h"
|
||||
#include "RasterPainter.h"
|
||||
#include "DrawingContext.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "DirectXPainter.h"
|
||||
#include "DirectXMesh.h"
|
||||
#include "DirectXMeshPainter.h"
|
||||
#include "DirectXTextPainter.h"
|
||||
#endif
|
||||
|
||||
|
||||
std::unique_ptr<AbstractPainter> PainterFactory::Create(DrawingContext* context, DrawingMode drawMode)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (drawMode == DrawingMode::GRAPH)
|
||||
{
|
||||
return std::make_unique<DirectXPainter>(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_unique<RasterPainter>(context);
|
||||
}
|
||||
#else
|
||||
#ifdef HAS_OPENGL
|
||||
if (drawMode == DrawingMode::GRAPH)
|
||||
{
|
||||
return std::make_unique<OpenGlPainter>(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_unique<RasterPainter>(context);
|
||||
}
|
||||
#else
|
||||
return std::make_unique<RasterPainter>(context);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
14
src/rendering/graphics/PainterFactory.h
Normal file
14
src/rendering/graphics/PainterFactory.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractPainter.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
enum class DrawingMode;
|
||||
class DrawingContext;
|
||||
|
||||
class PainterFactory
|
||||
{
|
||||
public:
|
||||
static std::unique_ptr<AbstractPainter> Create(DrawingContext* context, DrawingMode drawMode);
|
||||
};
|
30
src/rendering/graphics/RasterPainter.cpp
Normal file
30
src/rendering/graphics/RasterPainter.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include "RasterPainter.h"
|
||||
|
||||
#include "DrawingSurface.h"
|
||||
#include "DrawingContext.h"
|
||||
#include "Grid.h"
|
||||
|
||||
RasterPainter::RasterPainter(DrawingContext* context)
|
||||
: AbstractPainter(context)
|
||||
{
|
||||
const auto width = context->getSurface()->getWidth();
|
||||
const auto height = context->getSurface()->getHeight();
|
||||
|
||||
mGrid = std::make_unique<Grid<unsigned char> >(Bounds{ 0.0, 0.0, 100.0, 100.0 }, width, height);
|
||||
}
|
||||
|
||||
void RasterPainter::paint()
|
||||
{
|
||||
const auto width = mDrawingContext->getSurface()->getWidth();
|
||||
const auto height = mDrawingContext->getSurface()->getHeight();
|
||||
mGrid->resetBounds(Bounds{ 0.0, 0.0, static_cast<double>(width), static_cast<double>(height) });
|
||||
|
||||
/*
|
||||
for (unsigned idx=0; idx< context->getNumItems(); idx++)
|
||||
{
|
||||
context->getDrawable(idx)->sample(mGrid.get());
|
||||
}
|
||||
|
||||
context->getSurface()->getImage()->setData(mGrid->getValues());
|
||||
*/
|
||||
}
|
21
src/rendering/graphics/RasterPainter.h
Normal file
21
src/rendering/graphics/RasterPainter.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractPainter.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class DrawingContext;
|
||||
|
||||
template<typename T>
|
||||
class Grid;
|
||||
|
||||
class RasterPainter : public AbstractPainter
|
||||
{
|
||||
public:
|
||||
RasterPainter(DrawingContext* context);
|
||||
|
||||
void paint() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Grid<unsigned char> > mGrid;
|
||||
};
|
76
src/rendering/graphics/directx/DirectX2dInterface.cpp
Normal file
76
src/rendering/graphics/directx/DirectX2dInterface.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
#include "DirectX2dInterface.h"
|
||||
|
||||
#include "DirectXInterface.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include <dxgi.h>
|
||||
#include <d2d1_3.h>
|
||||
#include <d2d1_1.h>
|
||||
#include <dwrite.h>
|
||||
|
||||
DirectX2dInterface::DirectX2dInterface(DirectXInterface* dxInterface)
|
||||
: mDxInterface(dxInterface)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool DirectX2dInterface::isValid() const
|
||||
{
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
ID2D1Factory3* DirectX2dInterface::getFactory() const
|
||||
{
|
||||
return mFactory.Get();
|
||||
}
|
||||
|
||||
IDWriteFactory* DirectX2dInterface::getDirectWriteFactory() const
|
||||
{
|
||||
return mDWriteFactory.Get();
|
||||
}
|
||||
|
||||
ID2D1DeviceContext2* DirectX2dInterface::getContext() const
|
||||
{
|
||||
return mDeviceContext.Get();
|
||||
}
|
||||
|
||||
ID2D1RenderTarget* DirectX2dInterface::getRenderTarget() const
|
||||
{
|
||||
if (mRenderTarget)
|
||||
{
|
||||
return mRenderTarget.Get();
|
||||
}
|
||||
else
|
||||
{
|
||||
return mDeviceContext.Get();
|
||||
}
|
||||
}
|
||||
|
||||
void DirectX2dInterface::initialize(IWICBitmap* bitmap, bool useSoftware)
|
||||
{
|
||||
D2D1_FACTORY_OPTIONS d2dFactoryOptions = {};
|
||||
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory3), &d2dFactoryOptions, &mFactory);
|
||||
|
||||
auto hr = mFactory->CreateWicBitmapRenderTarget(bitmap, D2D1::RenderTargetProperties(), &mRenderTarget);
|
||||
|
||||
initializeDirectWrite();
|
||||
}
|
||||
|
||||
bool DirectX2dInterface::initialize(IDXGIDevice* device)
|
||||
{
|
||||
D2D1_FACTORY_OPTIONS d2dFactoryOptions = {};
|
||||
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory3), &d2dFactoryOptions, &mFactory);
|
||||
|
||||
mFactory->CreateDevice(device, &mDevice);
|
||||
|
||||
D2D1_DEVICE_CONTEXT_OPTIONS deviceOptions = D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
|
||||
mDevice->CreateDeviceContext(deviceOptions, &mDeviceContext);
|
||||
|
||||
return initializeDirectWrite();
|
||||
}
|
||||
|
||||
bool DirectX2dInterface::initializeDirectWrite()
|
||||
{
|
||||
return SUCCEEDED(::DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory));
|
||||
}
|
44
src/rendering/graphics/directx/DirectX2dInterface.h
Normal file
44
src/rendering/graphics/directx/DirectX2dInterface.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include <wrl.h>
|
||||
#include <dwrite.h>
|
||||
#include <d2d1_3.h>
|
||||
|
||||
class DirectXInterface;
|
||||
|
||||
struct IDWriteFactory;
|
||||
struct ID2D1Factory3;
|
||||
struct ID2D1Device2;
|
||||
struct ID2D1DeviceContext2;
|
||||
struct ID2D1RenderTarget;
|
||||
struct IWICBitmap;
|
||||
struct IDXGIDevice;
|
||||
|
||||
class DirectX2dInterface
|
||||
{
|
||||
public:
|
||||
DirectX2dInterface(DirectXInterface* dxInterface);
|
||||
|
||||
ID2D1Factory3* getFactory() const;
|
||||
ID2D1DeviceContext2* getContext() const;
|
||||
IDWriteFactory* getDirectWriteFactory() const;
|
||||
ID2D1RenderTarget* getRenderTarget() const;
|
||||
|
||||
bool initialize(IDXGIDevice* device);
|
||||
void initialize(IWICBitmap* bitmap, bool useSoftware = true);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
private:
|
||||
bool initializeDirectWrite();
|
||||
|
||||
bool mIsValid{ false };
|
||||
|
||||
DirectXInterface* mDxInterface{ nullptr };
|
||||
|
||||
Microsoft::WRL::ComPtr<ID2D1Factory3> mFactory;
|
||||
Microsoft::WRL::ComPtr<ID2D1Device2> mDevice;
|
||||
Microsoft::WRL::ComPtr<ID2D1DeviceContext2> mDeviceContext;
|
||||
Microsoft::WRL::ComPtr<IDWriteFactory> mDWriteFactory;
|
||||
Microsoft::WRL::ComPtr<ID2D1RenderTarget> mRenderTarget;
|
||||
};
|
58
src/rendering/graphics/directx/DirectX2dPainter.cpp
Normal file
58
src/rendering/graphics/directx/DirectX2dPainter.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include "DirectX2dPainter.h"
|
||||
|
||||
#include "DirectX2dInterface.h"
|
||||
#include "AbstractGeometricItem.h"
|
||||
#include "Rectangle.h"
|
||||
#include "SceneModel.h"
|
||||
|
||||
void DirectX2dPainter::startDrawing()
|
||||
{
|
||||
mD2dInterface->getRenderTarget()->BeginDraw();
|
||||
}
|
||||
|
||||
void DirectX2dPainter::finishDrawing()
|
||||
{
|
||||
mD2dInterface->getRenderTarget()->EndDraw();
|
||||
}
|
||||
|
||||
D2D1::ColorF DirectX2dPainter::toD2dColor(const Color& color)
|
||||
{
|
||||
return D2D1::ColorF(static_cast<float>(color.getR() / 255.0), static_cast<float>(color.getG() / 255.0),
|
||||
static_cast<float>(color.getB() / 255.0), static_cast<float>(color.getAlpha()));
|
||||
}
|
||||
|
||||
void DirectX2dPainter::clearBackground(const Color& color)
|
||||
{
|
||||
mD2dInterface->getRenderTarget()->Clear(toD2dColor(color));
|
||||
}
|
||||
|
||||
void DirectX2dPainter::paint(SceneModel* model)
|
||||
{
|
||||
auto rt = mD2dInterface->getRenderTarget();
|
||||
|
||||
if (model->getGeometry()->getType() == AbstractGeometricItem::Type::RECTANGLE)
|
||||
{
|
||||
const auto loc = model->getTransform().getLocation();
|
||||
const auto scale_x = model->getTransform().getScaleX();
|
||||
const auto scale_y = model->getTransform().getScaleY();
|
||||
D2D1_RECT_F d2d_rect{ static_cast<float>(loc.getX()), static_cast<float>(loc.getY() + scale_y), static_cast<float>(loc.getX() + scale_x), static_cast<float>(loc.getY()) };
|
||||
|
||||
if (model->hasFillColor())
|
||||
{
|
||||
mSolidBrush->SetColor(toD2dColor(model->getFillColor()));
|
||||
rt->FillRectangle(d2d_rect, mSolidBrush.Get());
|
||||
}
|
||||
|
||||
if (model->hasOutlineColor())
|
||||
{
|
||||
mSolidBrush->SetColor(toD2dColor(model->getOutlineColor()));
|
||||
rt->DrawRectangle(d2d_rect, mSolidBrush.Get(), 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DirectX2dPainter::setD2dInterface(DirectX2dInterface* d2dIterface)
|
||||
{
|
||||
mD2dInterface = d2dIterface;
|
||||
auto hr = mD2dInterface->getRenderTarget()->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black, 1.0f), &mSolidBrush);
|
||||
}
|
36
src/rendering/graphics/directx/DirectX2dPainter.h
Normal file
36
src/rendering/graphics/directx/DirectX2dPainter.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include "Color.h"
|
||||
|
||||
#include <wrl.h>
|
||||
|
||||
class SceneModel;
|
||||
class DirectX2dInterface;
|
||||
|
||||
struct ID2D1SolidColorBrush;
|
||||
|
||||
namespace D2D1
|
||||
{
|
||||
class ColorF;
|
||||
}
|
||||
|
||||
class DirectX2dPainter
|
||||
{
|
||||
public:
|
||||
void startDrawing();
|
||||
|
||||
void clearBackground(const Color& color);
|
||||
|
||||
void finishDrawing();
|
||||
|
||||
void paint(SceneModel* model);
|
||||
|
||||
void setD2dInterface(DirectX2dInterface* d2dIterface);
|
||||
|
||||
private:
|
||||
static D2D1::ColorF toD2dColor(const Color& color);
|
||||
|
||||
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> mSolidBrush;
|
||||
|
||||
DirectX2dInterface* mD2dInterface{ nullptr };
|
||||
};
|
168
src/rendering/graphics/directx/DirectXInterface.cpp
Normal file
168
src/rendering/graphics/directx/DirectXInterface.cpp
Normal file
|
@ -0,0 +1,168 @@
|
|||
#include "DirectXInterface.h"
|
||||
|
||||
#include "DirectX2dInterface.h"
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include <dxgi.h>
|
||||
#include <dxgi1_6.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3d11on12.h>
|
||||
#include <d3d12.h>
|
||||
#include <d3d12sdklayers.h>
|
||||
|
||||
DirectXInterface::DirectXInterface()
|
||||
: mD2dInterface(std::make_unique<DirectX2dInterface>(this))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DirectXInterface::getHardwareAdapter(IDXGIAdapter1** ppAdapter)
|
||||
{
|
||||
*ppAdapter = nullptr;
|
||||
for (UINT adapterIndex = 0; ; ++adapterIndex)
|
||||
{
|
||||
IDXGIAdapter1* pAdapter = nullptr;
|
||||
if (mDxgiFactory->EnumAdapters1(adapterIndex, &pAdapter) == DXGI_ERROR_NOT_FOUND)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (SUCCEEDED(::D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr)))
|
||||
{
|
||||
*ppAdapter = pAdapter;
|
||||
return;
|
||||
}
|
||||
pAdapter->Release();
|
||||
}
|
||||
}
|
||||
|
||||
bool DirectXInterface::isValid() const
|
||||
{
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
ID3D12Device* DirectXInterface::getD3dDevice() const
|
||||
{
|
||||
return mD3dDevice.Get();
|
||||
}
|
||||
|
||||
ID3D11On12Device* DirectXInterface::get11On12Device() const
|
||||
{
|
||||
return mD3d11On12Device.Get();
|
||||
}
|
||||
|
||||
IDXGIFactory7* DirectXInterface::getDxgiFactory() const
|
||||
{
|
||||
return mDxgiFactory.Get();
|
||||
}
|
||||
|
||||
ID3D12CommandQueue* DirectXInterface::getCommandQueue() const
|
||||
{
|
||||
return mCommandQueue.Get();
|
||||
}
|
||||
|
||||
ID3D11DeviceContext* DirectXInterface::getD3d11DeviceContext() const
|
||||
{
|
||||
return mD3d11DeviceContext.Get();
|
||||
}
|
||||
|
||||
DirectX2dInterface* DirectXInterface::getD2dInterface() const
|
||||
{
|
||||
return mD2dInterface.get();
|
||||
}
|
||||
|
||||
void DirectXInterface::initialize()
|
||||
{
|
||||
MLOG_INFO("Initialize DirectX");
|
||||
createD3dFactory();
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIAdapter1> pAdapter;
|
||||
getHardwareAdapter(&pAdapter);
|
||||
createD3dDevice(pAdapter.Get());
|
||||
|
||||
createCommandQueue();
|
||||
|
||||
if (!initializeD11on12())
|
||||
{
|
||||
mIsValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
|
||||
mD3d11On12Device.As(&dxgiDevice);
|
||||
mIsValid = mD2dInterface->initialize(dxgiDevice.Get());
|
||||
}
|
||||
|
||||
bool DirectXInterface::createD3dFactory()
|
||||
{
|
||||
UINT dxgiFactoryFlags = 0;
|
||||
#if defined(DEBUG) || defined(_DEBUG)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<ID3D12Debug> debugController;
|
||||
if (SUCCEEDED(::D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
|
||||
{
|
||||
debugController->EnableDebugLayer();
|
||||
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (FAILED(::CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&mDxgiFactory))))
|
||||
{
|
||||
MLOG_ERROR("Failed to create DXGI Factory");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DirectXInterface::createD3dDevice(IDXGIAdapter1* pAdapter)
|
||||
{
|
||||
if (pAdapter)
|
||||
{
|
||||
if (FAILED(::D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&mD3dDevice))))
|
||||
{
|
||||
MLOG_ERROR("Failed to create D3D12 device, will try WARP.");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Microsoft::WRL::ComPtr<IDXGIAdapter> pWarpAdapter;
|
||||
mDxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&pWarpAdapter));
|
||||
if (FAILED(::D3D12CreateDevice(pWarpAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&mD3dDevice))))
|
||||
{
|
||||
MLOG_ERROR("Failed to create WARP device.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MLOG_ERROR("Failed to get DirectX adapter.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DirectXInterface::createCommandQueue()
|
||||
{
|
||||
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
|
||||
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||
if (FAILED(mD3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue))))
|
||||
{
|
||||
MLOG_ERROR("Failed to create command queue.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DirectXInterface::initializeD11on12()
|
||||
{
|
||||
Microsoft::WRL::ComPtr<ID3D11Device> d3d11Device;
|
||||
UINT d3d11DeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
||||
auto pCommandQueue = reinterpret_cast<IUnknown**>(mCommandQueue.GetAddressOf());
|
||||
if (FAILED(D3D11On12CreateDevice(mD3dDevice.Get(), d3d11DeviceFlags, nullptr, 0, pCommandQueue, 1, 0, &d3d11Device, &mD3d11DeviceContext, nullptr)))
|
||||
{
|
||||
MLOG_ERROR("Failed to create D3D11 on 12 Device");
|
||||
return false;
|
||||
}
|
||||
d3d11Device.As(&mD3d11On12Device);
|
||||
return true;
|
||||
}
|
55
src/rendering/graphics/directx/DirectXInterface.h
Normal file
55
src/rendering/graphics/directx/DirectXInterface.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
|
||||
#include <wrl.h>
|
||||
#include <d3d11on12.h>
|
||||
#include <dxgi1_6.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class DirectX2dInterface;
|
||||
|
||||
struct ID3D12Device;
|
||||
struct IDXGIFactory7;
|
||||
struct IDXGIAdapter1;
|
||||
struct ID3D12CommandQueue;
|
||||
|
||||
struct ID3D11DeviceContext;
|
||||
struct ID3D11On12Device;
|
||||
|
||||
class DirectXInterface
|
||||
{
|
||||
public:
|
||||
DirectXInterface();
|
||||
|
||||
IDXGIFactory7* getDxgiFactory() const;
|
||||
ID3D12Device* getD3dDevice() const;
|
||||
ID3D12CommandQueue* getCommandQueue() const;
|
||||
|
||||
ID3D11On12Device* get11On12Device() const;
|
||||
ID3D11DeviceContext* getD3d11DeviceContext() const;
|
||||
|
||||
DirectX2dInterface* getD2dInterface() const;
|
||||
|
||||
void initialize();
|
||||
bool isValid() const;
|
||||
|
||||
private:
|
||||
bool createD3dFactory();
|
||||
bool createD3dDevice(IDXGIAdapter1* ppAdapter);
|
||||
bool createCommandQueue();
|
||||
|
||||
void getHardwareAdapter(IDXGIAdapter1** ppAdapter);
|
||||
|
||||
bool initializeD11on12();
|
||||
|
||||
bool mIsValid{ false };
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIFactory7> mDxgiFactory;
|
||||
Microsoft::WRL::ComPtr<ID3D12Device> mD3dDevice;
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandQueue> mCommandQueue;
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11DeviceContext> mD3d11DeviceContext;
|
||||
Microsoft::WRL::ComPtr<ID3D11On12Device> mD3d11On12Device;
|
||||
|
||||
std::unique_ptr<DirectX2dInterface> mD2dInterface;
|
||||
};
|
141
src/rendering/graphics/directx/DirectXMesh.cpp
Normal file
141
src/rendering/graphics/directx/DirectXMesh.cpp
Normal file
|
@ -0,0 +1,141 @@
|
|||
#include "DirectXMesh.h"
|
||||
|
||||
#include "SceneModel.h"
|
||||
#include "DrawingContext.h"
|
||||
#include "DrawingSurface.h"
|
||||
|
||||
#include "TriMesh.h"
|
||||
#include "TriFace.h"
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include <directx/d3dx12.h>
|
||||
|
||||
DirectXMesh::DirectXMesh(SceneModel* model)
|
||||
: mModel(model)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DirectXMesh::update(DrawingContext* context, ID3D12Device* device)
|
||||
{
|
||||
mVertexBuffer.clear();
|
||||
mIndexBuffer.clear();
|
||||
|
||||
const auto width = float(context->getSurface()->getWidth());
|
||||
const auto height = float(context->getSurface()->getHeight());
|
||||
|
||||
auto model_color = mModel->getFillColor().getAsVectorDouble();
|
||||
std::vector<float> color = { float(model_color[0]), float(model_color[1]), float(model_color[2]), float(model_color[3]) };
|
||||
|
||||
auto transform = mModel->getTransform();
|
||||
|
||||
for (const auto& face : dynamic_cast<TriMesh*>(mModel->getMesh())->getFaces())
|
||||
{
|
||||
for (const auto& loc : face->getNodeLocations(AbstractFace::Orientation::CW))
|
||||
{
|
||||
auto x = loc.getX() * transform.getScaleX() + transform.getLocation().getX();
|
||||
auto y = loc.getY() * transform.getScaleY() + transform.getLocation().getY();
|
||||
x = 2 * x - 1;
|
||||
y = 2 * y - 1;
|
||||
|
||||
Vertex vert;
|
||||
vert.position = DirectX::XMFLOAT3(static_cast<float>(x), static_cast<float>(y), 0.0);
|
||||
vert.color = DirectX::XMFLOAT4(color[0], color[1], color[2], color[3]);
|
||||
MLOG_INFO("Adding vert: " << x << " | " << y);
|
||||
mVertexBuffer.push_back(vert);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
for (const auto& node : mModel->getMesh()->getNodes())
|
||||
{
|
||||
auto x = node->getPoint().getX() * transform.getScaleX() + transform.getLocation().getX();
|
||||
//x = 2 * x / width - 1.0;
|
||||
auto y = node->getPoint().getY() * transform.getScaleY() + transform.getLocation().getY();
|
||||
//y = 2 * y / height;
|
||||
Vertex vert;
|
||||
vert.position = DirectX::XMFLOAT3(x, y, 0.0);
|
||||
vert.color = DirectX::XMFLOAT4(color[0], color[1], color[2], color[3]);
|
||||
MLOG_INFO("Adding vert: " << x << " | " << y);
|
||||
mVertexBuffer.push_back(vert);
|
||||
}
|
||||
*/
|
||||
|
||||
//mIndexBuffer = dynamic_cast<TriMesh*>(mModel->getMesh())->getFaceNodeIds();
|
||||
mIndexBuffer = { 0, 1, 2 };
|
||||
for (auto id : mIndexBuffer)
|
||||
{
|
||||
MLOG_INFO("Adding id: " << id);
|
||||
}
|
||||
|
||||
createD3dVertexBuffer(device);
|
||||
createD3dIndexBuffer(device);
|
||||
|
||||
mVertexBuffer.clear();
|
||||
mIndexBuffer.clear();
|
||||
}
|
||||
|
||||
void DirectXMesh::createD3dVertexBuffer(ID3D12Device* device)
|
||||
{
|
||||
// Note: using upload heaps to transfer static data like vert buffers is not
|
||||
// recommended. Every time the GPU needs it, the upload heap will be marshalled
|
||||
// over. Please read up on Default Heap usage. An upload heap is used here for
|
||||
// code simplicity and because there are very few verts to actually transfer.
|
||||
CD3DX12_HEAP_PROPERTIES heapProps(D3D12_HEAP_TYPE_UPLOAD);
|
||||
const auto buffer_size = mVertexBuffer.size() * sizeof(Vertex);
|
||||
auto desc = CD3DX12_RESOURCE_DESC::Buffer(buffer_size);
|
||||
device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&mD3dVertexBuffer));
|
||||
|
||||
UINT8* pDataBegin;
|
||||
CD3DX12_RANGE readRange(0, 0);
|
||||
mD3dVertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pDataBegin));
|
||||
uploadVertexBuffer(pDataBegin);
|
||||
mD3dVertexBuffer->Unmap(0, nullptr);
|
||||
|
||||
mVertexBufferView.BufferLocation = mD3dVertexBuffer->GetGPUVirtualAddress();
|
||||
mVertexBufferView.StrideInBytes = sizeof(Vertex);
|
||||
mVertexBufferView.SizeInBytes = static_cast<UINT>(buffer_size);
|
||||
}
|
||||
|
||||
void DirectXMesh::uploadVertexBuffer(unsigned char* pBuffer) const
|
||||
{
|
||||
memcpy(pBuffer, mVertexBuffer.data(), mVertexBuffer.size() * sizeof(Vertex));
|
||||
}
|
||||
|
||||
void DirectXMesh::createD3dIndexBuffer(ID3D12Device* device)
|
||||
{
|
||||
CD3DX12_HEAP_PROPERTIES heapProps(D3D12_HEAP_TYPE_UPLOAD);
|
||||
const auto buffer_size = mIndexBuffer.size() * sizeof(unsigned);
|
||||
auto desc = CD3DX12_RESOURCE_DESC::Buffer(buffer_size);
|
||||
device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&mD3dIndexBuffer));
|
||||
|
||||
UINT8* pDataBegin;
|
||||
CD3DX12_RANGE readRange(0, 0);
|
||||
mD3dIndexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pDataBegin));
|
||||
uploadIndexBuffer(pDataBegin);
|
||||
mD3dIndexBuffer->Unmap(0, nullptr);
|
||||
|
||||
mIndexBufferView.BufferLocation = mD3dIndexBuffer->GetGPUVirtualAddress();
|
||||
mIndexBufferView.SizeInBytes = static_cast<UINT>(buffer_size);
|
||||
mIndexBufferView.Format = DXGI_FORMAT_R16_UINT;
|
||||
}
|
||||
|
||||
void DirectXMesh::uploadIndexBuffer(unsigned char* pBuffer) const
|
||||
{
|
||||
memcpy(pBuffer, mIndexBuffer.data(), mIndexBuffer.size() * sizeof(unsigned));
|
||||
}
|
||||
|
||||
const D3D12_VERTEX_BUFFER_VIEW& DirectXMesh::getVertBufferView() const
|
||||
{
|
||||
return mVertexBufferView;
|
||||
}
|
||||
|
||||
const D3D12_INDEX_BUFFER_VIEW& DirectXMesh::getIndexBufferView() const
|
||||
{
|
||||
return mIndexBufferView;
|
||||
}
|
||||
|
||||
SceneModel* DirectXMesh::getModel() const
|
||||
{
|
||||
return mModel;
|
||||
}
|
48
src/rendering/graphics/directx/DirectXMesh.h
Normal file
48
src/rendering/graphics/directx/DirectXMesh.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include <wrl.h>
|
||||
#include <directxmath.h>
|
||||
#include <d3d12.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class SceneModel;
|
||||
class DrawingContext;
|
||||
|
||||
class DirectXMesh
|
||||
{
|
||||
public:
|
||||
DirectXMesh(SceneModel* model);
|
||||
|
||||
const D3D12_VERTEX_BUFFER_VIEW& getVertBufferView() const;
|
||||
|
||||
const D3D12_INDEX_BUFFER_VIEW& getIndexBufferView() const;
|
||||
|
||||
SceneModel* getModel() const;
|
||||
|
||||
void update(DrawingContext* context, ID3D12Device* device);
|
||||
|
||||
private:
|
||||
struct Vertex
|
||||
{
|
||||
DirectX::XMFLOAT3 position;
|
||||
DirectX::XMFLOAT4 color;
|
||||
};
|
||||
|
||||
void createD3dVertexBuffer(ID3D12Device* device);
|
||||
void uploadVertexBuffer(unsigned char* pBuffer) const;
|
||||
|
||||
void createD3dIndexBuffer(ID3D12Device* device);
|
||||
void uploadIndexBuffer(unsigned char* pBuffer) const;
|
||||
|
||||
SceneModel* mModel{ nullptr };
|
||||
|
||||
std::vector<Vertex> mVertexBuffer;
|
||||
Microsoft::WRL::ComPtr<ID3D12Resource> mD3dVertexBuffer;
|
||||
D3D12_VERTEX_BUFFER_VIEW mVertexBufferView{};
|
||||
|
||||
std::vector<unsigned> mIndexBuffer;
|
||||
Microsoft::WRL::ComPtr<ID3D12Resource> mD3dIndexBuffer;
|
||||
D3D12_INDEX_BUFFER_VIEW mIndexBufferView{};
|
||||
};
|
131
src/rendering/graphics/directx/DirectXMeshPainter.cpp
Normal file
131
src/rendering/graphics/directx/DirectXMeshPainter.cpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
#include "DirectXMeshPainter.h"
|
||||
|
||||
#include "DrawingContext.h"
|
||||
#include "DrawingSurface.h"
|
||||
#include "Scene.h"
|
||||
#include "SceneModel.h"
|
||||
|
||||
#include "TriMesh.h"
|
||||
#include "LineMesh.h"
|
||||
|
||||
#include "DirectXShaderProgram.h"
|
||||
#include "DirectXMesh.h"
|
||||
#include "DirectXInterface.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
|
||||
#include <directx/d3dx12.h>
|
||||
|
||||
DirectXMeshPainter::DirectXMeshPainter()
|
||||
{
|
||||
auto shader_path = std::filesystem::path(__FILE__).parent_path() / "shaders.hlsl";
|
||||
mShaderProgram = std::make_unique<DirectXShaderProgram>(shader_path, shader_path);
|
||||
}
|
||||
|
||||
void DirectXMeshPainter::setDxInterface(DirectXInterface* dxInterface)
|
||||
{
|
||||
mDxInterface = dxInterface;
|
||||
}
|
||||
|
||||
void DirectXMeshPainter::initializeShader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DirectXMeshPainter::initializeD3d()
|
||||
{
|
||||
createRootSignature();
|
||||
createPipelineStateObject();
|
||||
}
|
||||
|
||||
void DirectXMeshPainter::createRootSignature()
|
||||
{
|
||||
CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc;
|
||||
rootSignatureDesc.Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> signature;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> error;
|
||||
D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error);
|
||||
mDxInterface->getD3dDevice()->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&mRootSignature));
|
||||
}
|
||||
|
||||
void DirectXMeshPainter::createPipelineStateObject()
|
||||
{
|
||||
auto vert_shader = mShaderProgram->getVertexShader();
|
||||
auto pixel_shader = mShaderProgram->getPixelShader();
|
||||
|
||||
D3D12_INPUT_ELEMENT_DESC inputElementDescs[] =
|
||||
{
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
||||
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
|
||||
};
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
|
||||
psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
|
||||
psoDesc.pRootSignature = mRootSignature.Get();
|
||||
psoDesc.VS = CD3DX12_SHADER_BYTECODE(vert_shader);
|
||||
psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixel_shader);
|
||||
psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
|
||||
psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
|
||||
psoDesc.DepthStencilState.DepthEnable = FALSE;
|
||||
psoDesc.DepthStencilState.StencilEnable = FALSE;
|
||||
psoDesc.SampleMask = UINT_MAX;
|
||||
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
psoDesc.NumRenderTargets = 1;
|
||||
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
psoDesc.SampleDesc.Count = 1;
|
||||
mDxInterface->getD3dDevice()->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&mPipelineState));
|
||||
}
|
||||
|
||||
ID3D12PipelineState* DirectXMeshPainter::getPipelineState() const
|
||||
{
|
||||
return mPipelineState.Get();
|
||||
}
|
||||
|
||||
ID3D12RootSignature* DirectXMeshPainter::getRootSignature() const
|
||||
{
|
||||
return mRootSignature.Get();
|
||||
}
|
||||
|
||||
void DirectXMeshPainter::updateCommandList(ID3D12GraphicsCommandList* commandList)
|
||||
{
|
||||
commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
for (const auto& mesh : mDxMeshes)
|
||||
{
|
||||
commandList->IASetIndexBuffer(&mesh->getIndexBufferView());
|
||||
commandList->IASetVertexBuffers(0, 1, &mesh->getVertBufferView());
|
||||
commandList->DrawInstanced(mesh->getVertBufferView().SizeInBytes/ mesh->getVertBufferView().StrideInBytes, 1, 0, 0);
|
||||
//commandList->DrawIndexedInstanced(3, 1, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DirectXMeshPainter::updateBuffers(DrawingContext* context)
|
||||
{
|
||||
mDxMeshes.clear();
|
||||
auto scene = context->getSurface()->getScene();
|
||||
for (const auto item : scene->getItems())
|
||||
{
|
||||
if (!item->isVisible())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->getType() == SceneItem::Type::MODEL)
|
||||
{
|
||||
auto model = dynamic_cast<SceneModel*>(item);
|
||||
if (model->getGeometry())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto dx_mesh = std::make_unique<DirectXMesh>(model);
|
||||
dx_mesh->update(context, mDxInterface->getD3dDevice());
|
||||
mDxMeshes.push_back(std::move(dx_mesh));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
41
src/rendering/graphics/directx/DirectXMeshPainter.h
Normal file
41
src/rendering/graphics/directx/DirectXMeshPainter.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <wrl.h>
|
||||
#include <d3d12.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class DrawingContext;
|
||||
class DirectXShaderProgram;
|
||||
class DirectXMesh;
|
||||
class DirectXInterface;
|
||||
|
||||
class DirectXMeshPainter
|
||||
{
|
||||
public:
|
||||
DirectXMeshPainter();
|
||||
|
||||
ID3D12PipelineState* getPipelineState() const;
|
||||
ID3D12RootSignature* getRootSignature() const;
|
||||
|
||||
void initializeD3d();
|
||||
|
||||
void setDxInterface(DirectXInterface* dxInterface);
|
||||
|
||||
void updateBuffers(DrawingContext* context);
|
||||
void updateCommandList(ID3D12GraphicsCommandList* commandList);
|
||||
private:
|
||||
void initializeShader();
|
||||
void createRootSignature();
|
||||
void createPipelineStateObject();
|
||||
|
||||
DirectXInterface* mDxInterface{ nullptr };
|
||||
|
||||
std::vector<std::unique_ptr<DirectXMesh> > mDxMeshes;
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D12RootSignature> mRootSignature;
|
||||
Microsoft::WRL::ComPtr<ID3D12PipelineState> mPipelineState;
|
||||
|
||||
std::unique_ptr<DirectXShaderProgram> mShaderProgram;
|
||||
};
|
144
src/rendering/graphics/directx/DirectXPainter.cpp
Normal file
144
src/rendering/graphics/directx/DirectXPainter.cpp
Normal file
|
@ -0,0 +1,144 @@
|
|||
#include "DirectXPainter.h"
|
||||
|
||||
#include "DrawingContext.h"
|
||||
#include "DrawingSurface.h"
|
||||
#include "Scene.h"
|
||||
#include "SceneItem.h"
|
||||
#include "SceneModel.h"
|
||||
#include "SceneText.h"
|
||||
|
||||
#include "TriMesh.h"
|
||||
|
||||
#include "FontsManager.h"
|
||||
#include "FontGlyph.h"
|
||||
#include "TextData.h"
|
||||
|
||||
#include "DirectXShaderProgram.h"
|
||||
#include "DirectXMeshPainter.h"
|
||||
#include "DirectXTextPainter.h"
|
||||
#include "DirectX2dPainter.h"
|
||||
#include "DirectXMesh.h"
|
||||
#include "DirectXInterface.h"
|
||||
#include "DirectX2dInterface.h"
|
||||
|
||||
#include <wincodec.h>
|
||||
#include "Win32WicImage.h"
|
||||
|
||||
#include "File.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
DirectXPainter::DirectXPainter(DrawingContext* context)
|
||||
: AbstractPainter(context),
|
||||
mMeshPainter(std::make_unique<DirectXMeshPainter>()),
|
||||
mTextPainter(std::make_unique<DirectXTextPainter>()),
|
||||
m2dPainter(std::make_unique<DirectX2dPainter>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DirectXMeshPainter* DirectXPainter::getMeshPainter() const
|
||||
{
|
||||
return mMeshPainter.get();
|
||||
}
|
||||
|
||||
void DirectXPainter::setDxInterface(DirectXInterface* dxInterface)
|
||||
{
|
||||
mRawDxInterface = dxInterface;
|
||||
resetPainters();
|
||||
}
|
||||
|
||||
DirectXInterface* DirectXPainter::getDxInterface() const
|
||||
{
|
||||
if (mDxInterface)
|
||||
{
|
||||
return mDxInterface.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
return mRawDxInterface;
|
||||
}
|
||||
}
|
||||
|
||||
void DirectXPainter::initializeMesh()
|
||||
{
|
||||
mMeshPainter->initializeD3d();
|
||||
}
|
||||
|
||||
void DirectXPainter::updateMesh()
|
||||
{
|
||||
mMeshPainter->updateBuffers(mDrawingContext);
|
||||
}
|
||||
|
||||
void DirectXPainter::initializeDxInterface()
|
||||
{
|
||||
mDxInterface = std::make_unique<DirectXInterface>();
|
||||
|
||||
auto backing_image = mDrawingContext->getSurface()->getImage();
|
||||
auto wic_bitmap = dynamic_cast<Win32WicImage*>(backing_image->getPlatformImage())->getBitmap();
|
||||
|
||||
mDxInterface->getD2dInterface()->initialize(wic_bitmap);
|
||||
|
||||
resetPainters();
|
||||
}
|
||||
|
||||
void DirectXPainter::resetPainters()
|
||||
{
|
||||
m2dPainter->setD2dInterface(getDxInterface()->getD2dInterface());
|
||||
mTextPainter->setD2dInterface(getDxInterface()->getD2dInterface());
|
||||
mMeshPainter->setDxInterface(getDxInterface());
|
||||
}
|
||||
|
||||
void DirectXPainter::paint()
|
||||
{
|
||||
if (!getDxInterface())
|
||||
{
|
||||
initializeDxInterface();
|
||||
}
|
||||
|
||||
auto scene = mDrawingContext->getSurface()->getScene();
|
||||
|
||||
m2dPainter->startDrawing();
|
||||
m2dPainter->clearBackground(scene->getBackgroundColor());
|
||||
|
||||
for (const auto item : scene->getItems())
|
||||
{
|
||||
if (!item->isVisible())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->getType() == SceneItem::Type::MODEL)
|
||||
{
|
||||
auto model = dynamic_cast<SceneModel*>(item);
|
||||
if (model->getGeometry())
|
||||
{
|
||||
m2dPainter->paint(model);
|
||||
}
|
||||
}
|
||||
else if (item->getType() == SceneItem::Type::TEXT)
|
||||
{
|
||||
auto text = dynamic_cast<SceneText*>(item);
|
||||
mTextPainter->paint(text, mDrawingContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m2dPainter->finishDrawing();
|
||||
}
|
||||
|
||||
void DirectXPainter::paintBackground(const D3D12_CPU_DESCRIPTOR_HANDLE& rtvHandle, ID3D12GraphicsCommandList* commandList)
|
||||
{
|
||||
const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
|
||||
commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
|
||||
}
|
||||
|
||||
void DirectXPainter::paintMesh(ID3D12GraphicsCommandList* commandList)
|
||||
{
|
||||
mMeshPainter->updateCommandList(commandList);
|
||||
}
|
||||
|
||||
bool DirectXPainter::supportsGeometryPrimitives() const
|
||||
{
|
||||
return true;
|
||||
}
|
48
src/rendering/graphics/directx/DirectXPainter.h
Normal file
48
src/rendering/graphics/directx/DirectXPainter.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractPainter.h"
|
||||
|
||||
#include <dwrite.h>
|
||||
#include <d2d1_3.h>
|
||||
#include <d2d1_1.h>
|
||||
#include <d3d12.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class DrawingContext;
|
||||
class DirectXMeshPainter;
|
||||
class DirectXTextPainter;
|
||||
class DirectX2dPainter;
|
||||
class DirectXInterface;
|
||||
|
||||
class DirectXPainter : public AbstractPainter
|
||||
{
|
||||
public:
|
||||
DirectXPainter(DrawingContext* context);
|
||||
|
||||
DirectXMeshPainter* getMeshPainter() const;
|
||||
void initializeMesh();
|
||||
|
||||
void paint() override;
|
||||
void paintBackground(const D3D12_CPU_DESCRIPTOR_HANDLE& rtvHandle, ID3D12GraphicsCommandList* commandList);
|
||||
void paintMesh(ID3D12GraphicsCommandList* commandList);
|
||||
|
||||
void setDxInterface(DirectXInterface* dxInterface);
|
||||
|
||||
bool supportsGeometryPrimitives() const override;
|
||||
|
||||
void updateMesh();
|
||||
|
||||
private:
|
||||
DirectXInterface* getDxInterface() const;
|
||||
|
||||
void initializeDxInterface();
|
||||
void resetPainters();
|
||||
|
||||
std::unique_ptr<DirectXMeshPainter> mMeshPainter;
|
||||
std::unique_ptr<DirectXTextPainter> mTextPainter;
|
||||
std::unique_ptr<DirectX2dPainter> m2dPainter;
|
||||
|
||||
DirectXInterface* mRawDxInterface{ nullptr };
|
||||
std::unique_ptr<DirectXInterface> mDxInterface;
|
||||
};
|
31
src/rendering/graphics/directx/DirectXShaderProgram.cpp
Normal file
31
src/rendering/graphics/directx/DirectXShaderProgram.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include "DirectXShaderProgram.h"
|
||||
|
||||
#include "File.h"
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include <d3d12.h>
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
DirectXShaderProgram::DirectXShaderProgram(const Path& vertShaderPath, const Path& fragShaderPath)
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
// Enable better shader debugging with the graphics debugging tools.
|
||||
// UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
|
||||
UINT compileFlags = 0;
|
||||
#else
|
||||
UINT compileFlags = 0;
|
||||
#endif
|
||||
|
||||
D3DCompileFromFile(vertShaderPath.c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &mVertexShader, nullptr);
|
||||
D3DCompileFromFile(fragShaderPath.c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &mPixelShader, nullptr);
|
||||
}
|
||||
|
||||
ID3DBlob* DirectXShaderProgram::getVertexShader() const
|
||||
{
|
||||
return mVertexShader.Get();
|
||||
}
|
||||
|
||||
ID3DBlob* DirectXShaderProgram::getPixelShader() const
|
||||
{
|
||||
return mPixelShader.Get();
|
||||
}
|
20
src/rendering/graphics/directx/DirectXShaderProgram.h
Normal file
20
src/rendering/graphics/directx/DirectXShaderProgram.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <wrl.h>
|
||||
#include <D3Dcommon.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
using Path = std::filesystem::path;
|
||||
|
||||
class DirectXShaderProgram
|
||||
{
|
||||
public:
|
||||
DirectXShaderProgram(const Path& vertShaderPath, const Path& pixelShaderPath);
|
||||
|
||||
ID3DBlob* getVertexShader() const;
|
||||
ID3DBlob* getPixelShader() const;
|
||||
private:
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> mVertexShader;
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> mPixelShader;
|
||||
};
|
62
src/rendering/graphics/directx/DirectXTextPainter.cpp
Normal file
62
src/rendering/graphics/directx/DirectXTextPainter.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include "DirectXTextPainter.h"
|
||||
|
||||
#include "DrawingContext.h"
|
||||
#include "DrawingSurface.h"
|
||||
|
||||
#include "FontsManager.h"
|
||||
#include "FontGlyph.h"
|
||||
|
||||
#include "TextData.h"
|
||||
#include "SceneText.h"
|
||||
#include "DirectX2dInterface.h"
|
||||
|
||||
#include "UnicodeUtils.h"
|
||||
#include "File.h"
|
||||
|
||||
#include "Win32BaseIncludes.h"
|
||||
|
||||
#include <d2d1_3.h>
|
||||
#include <d2d1_1.h>
|
||||
#include <dwrite.h>
|
||||
|
||||
DirectXTextPainter::DirectXTextPainter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DirectXTextPainter::setD2dInterface(DirectX2dInterface* d2dIterface)
|
||||
{
|
||||
mD2dInterface = d2dIterface;
|
||||
mD2dInterface->getRenderTarget()->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &mTextBrush);
|
||||
}
|
||||
|
||||
void DirectXTextPainter::updateTextFormat(const FontItem& font)
|
||||
{
|
||||
mD2dInterface->getDirectWriteFactory()->CreateTextFormat(
|
||||
UnicodeUtils::utf8ToUtf16WString(font.getFaceName()).c_str(),
|
||||
nullptr,
|
||||
DWRITE_FONT_WEIGHT_NORMAL,
|
||||
DWRITE_FONT_STYLE_NORMAL,
|
||||
DWRITE_FONT_STRETCH_NORMAL,
|
||||
static_cast<float>(font.getSize()),
|
||||
L"en-us",
|
||||
&mTextFormat
|
||||
);
|
||||
//mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
|
||||
//mTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
|
||||
}
|
||||
|
||||
void DirectXTextPainter::paint(SceneText* text, DrawingContext* context)
|
||||
{
|
||||
const auto location = text->getTransform().getLocation();
|
||||
D2D1_RECT_F textRect = D2D1::RectF(static_cast<float>(location.getX()), static_cast<float>(location.getY()), static_cast<float>(location.getX() + 200), static_cast<float>(location.getY() + 100));
|
||||
|
||||
updateTextFormat(text->getTextData().mFont);
|
||||
|
||||
auto content = UnicodeUtils::utf8ToUtf16WString(text->getTextData().mContent);
|
||||
|
||||
mD2dInterface->getRenderTarget()->DrawText(content.c_str(), static_cast<UINT32>(content.size()), mTextFormat.Get(), &textRect, mTextBrush.Get());
|
||||
}
|
||||
|
||||
|
||||
|
40
src/rendering/graphics/directx/DirectXTextPainter.h
Normal file
40
src/rendering/graphics/directx/DirectXTextPainter.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include "FontItem.h"
|
||||
|
||||
#include <wrl.h>
|
||||
#include <dwrite.h>
|
||||
#include <d2d1_3.h>
|
||||
#include <d2d1_1.h>
|
||||
#include <d3d12.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
class DrawingContext;
|
||||
class DirectXShaderProgram;
|
||||
class DirectX2dInterface;
|
||||
|
||||
class TextData;
|
||||
class SceneText;
|
||||
|
||||
struct ID2D1DeviceContext2;
|
||||
struct ID2D1SolidColorBrush;
|
||||
struct IDWriteFactory;
|
||||
|
||||
class DirectXTextPainter
|
||||
{
|
||||
public:
|
||||
DirectXTextPainter();
|
||||
|
||||
void paint(SceneText* text, DrawingContext* context);
|
||||
|
||||
void setD2dInterface(DirectX2dInterface* d2dIterface);
|
||||
|
||||
private:
|
||||
void updateTextFormat(const FontItem& font);
|
||||
|
||||
DirectX2dInterface* mD2dInterface{ nullptr };
|
||||
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> mTextBrush;
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> mTextFormat;
|
||||
};
|
20
src/rendering/graphics/directx/shaders.hlsl
Normal file
20
src/rendering/graphics/directx/shaders.hlsl
Normal file
|
@ -0,0 +1,20 @@
|
|||
struct PSInput
|
||||
{
|
||||
float4 position : SV_POSITION;
|
||||
float4 color : COLOR;
|
||||
};
|
||||
|
||||
PSInput VSMain(float4 position : POSITION, float4 color : COLOR)
|
||||
{
|
||||
PSInput result;
|
||||
|
||||
result.position = position;
|
||||
result.color = color;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 PSMain(PSInput input) : SV_TARGET
|
||||
{
|
||||
return input.color;
|
||||
}
|
42
src/rendering/graphics/opengl/OpenGlFontTexture.cpp
Normal file
42
src/rendering/graphics/opengl/OpenGlFontTexture.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "OpenGlFontTexture.h"
|
||||
|
||||
#include "FontGlyph.h"
|
||||
#include "Grid.h"
|
||||
#include "Image.h"
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
|
||||
OpenGlFontTexture::OpenGlFontTexture(FontGlyph* glyph)
|
||||
: mGlyph(glyph)
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
glGenTextures(1, &mHandle);
|
||||
glBindTexture(GL_TEXTURE_2D, mHandle);
|
||||
|
||||
auto buffer = glyph->getImage()->getGridT<unsigned char>()->getInternalData()->getDataPtr();
|
||||
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RED,
|
||||
mGlyph->getWidth(),
|
||||
mGlyph->getHeight(),
|
||||
0,
|
||||
GL_RED,
|
||||
GL_UNSIGNED_BYTE,
|
||||
buffer
|
||||
);
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
FontGlyph* OpenGlFontTexture::getGlyph() const
|
||||
{
|
||||
return mGlyph;
|
||||
}
|
20
src/rendering/graphics/opengl/OpenGlFontTexture.h
Normal file
20
src/rendering/graphics/opengl/OpenGlFontTexture.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
class FontGlyph;
|
||||
|
||||
class OpenGlFontTexture
|
||||
{
|
||||
public:
|
||||
OpenGlFontTexture(FontGlyph* glyph);
|
||||
|
||||
unsigned int getHandle() const
|
||||
{
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
FontGlyph* getGlyph() const;
|
||||
|
||||
private:
|
||||
unsigned int mHandle{0};
|
||||
FontGlyph* mGlyph{nullptr};
|
||||
};
|
137
src/rendering/graphics/opengl/OpenGlMeshPainter.cpp
Normal file
137
src/rendering/graphics/opengl/OpenGlMeshPainter.cpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
#include "OpenGlMeshPainter.h"
|
||||
|
||||
#include "DrawingContext.h"
|
||||
#include "DrawingSurface.h"
|
||||
#include "SceneModel.h"
|
||||
|
||||
#include "TriMesh.h"
|
||||
#include "LineMesh.h"
|
||||
|
||||
#include "OpenGlShaderProgram.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glx.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
OpenGlMeshPainter::OpenGlMeshPainter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void OpenGlMeshPainter::initializeShader()
|
||||
{
|
||||
auto vert_shader_path = std::filesystem::path(__FILE__).parent_path() / "shaders/default.vert";
|
||||
auto frag_shader_path = std::filesystem::path(__FILE__).parent_path() / "shaders/default.frag";
|
||||
mShaderProgram = std::make_unique<OpenGlShaderProgram>(vert_shader_path, frag_shader_path);
|
||||
}
|
||||
|
||||
void OpenGlMeshPainter::initializeBuffers()
|
||||
{
|
||||
glGenBuffers(1, &mVertexBuffer);
|
||||
|
||||
glGenBuffers(1, &mElementBuffer);
|
||||
|
||||
glGenVertexArrays(1, &mVertexArray);
|
||||
}
|
||||
|
||||
void OpenGlMeshPainter::paint(const std::vector<float>& verts, const std::vector<std::size_t>& elements, const std::vector<float>& color, bool lines)
|
||||
{
|
||||
glBindVertexArray(mVertexArray);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(float), verts.data(), GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mElementBuffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elements.size() * sizeof(unsigned), elements.data(), GL_STATIC_DRAW);
|
||||
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
//glm::mat4 projection = glm::ortho(0.0f, width, 0.0f, height);
|
||||
//glUniformMatrix4fv(glGetUniformLocation(mShaderProgram->getHandle(), "projection"), 1, GL_FALSE, glm::value_ptr(projection));
|
||||
|
||||
glUseProgram(mShaderProgram->getHandle());
|
||||
glBindVertexArray(mVertexArray);
|
||||
|
||||
int vertexColorLocation = glGetUniformLocation(mShaderProgram->getHandle(), "ourColor");
|
||||
glUniform4f(vertexColorLocation, float(color[0]), float(color[1]), float(color[2]), float(color[3]));
|
||||
|
||||
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
|
||||
if (lines)
|
||||
{
|
||||
glDrawElements(GL_LINES, elements.size(), GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDrawElements( GL_TRIANGLES, elements.size(), GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void OpenGlMeshPainter::paint(SceneModel* model, DrawingContext* context)
|
||||
{
|
||||
if (!mShaderProgram)
|
||||
{
|
||||
initializeShader();
|
||||
}
|
||||
|
||||
if (mVertexArray == 0)
|
||||
{
|
||||
initializeBuffers();
|
||||
}
|
||||
|
||||
auto surface = context->getSurface();
|
||||
const auto width = float(surface->getWidth());
|
||||
const auto height = float(surface->getHeight());
|
||||
|
||||
auto transform = model->getTransform();
|
||||
auto vertices = model->getMesh()->getVerticesFlat<float>();
|
||||
for (std::size_t idx = 0; idx<vertices.size(); idx++)
|
||||
{
|
||||
if (idx % 3 == 0)
|
||||
{
|
||||
auto x = vertices[idx]*transform.getScaleX() + transform.getLocation().getX();
|
||||
vertices[idx] = 2*x/width - 1.0;
|
||||
}
|
||||
else if(idx%3 == 1)
|
||||
{
|
||||
auto y = vertices[idx]*transform.getScaleY() + transform.getLocation().getY();
|
||||
vertices[idx] = 1.0 - 2*y/height;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::size_t> indices;
|
||||
const bool line_mesh = model->getMesh()->getType() == AbstractMesh::MeshType::LINE;
|
||||
if (line_mesh)
|
||||
{
|
||||
indices = dynamic_cast<LineMesh*>(model->getMesh())->getEdgeNodeIds();
|
||||
}
|
||||
else
|
||||
{
|
||||
indices = dynamic_cast<TriMesh*>(model->getMesh())->getFaceNodeIds();
|
||||
}
|
||||
|
||||
auto model_color = model->getFillColor().getAsVectorDouble();
|
||||
std::vector<float> color = {float(model_color[0]), float(model_color[1]), float(model_color[2]), float(model_color[3])};
|
||||
|
||||
paint(vertices, indices, color, line_mesh);
|
||||
|
||||
if (model->getShowOutline())
|
||||
{
|
||||
auto edge_indices = dynamic_cast<TriMesh*>(model->getMesh())->getEdgeNodeIds();
|
||||
paint(vertices, edge_indices, {0, 0, 0, 1}, true);
|
||||
}
|
||||
}
|
27
src/rendering/graphics/opengl/OpenGlMeshPainter.h
Normal file
27
src/rendering/graphics/opengl/OpenGlMeshPainter.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class DrawingContext;
|
||||
class OpenGlShaderProgram;
|
||||
class SceneModel;
|
||||
|
||||
class OpenGlMeshPainter
|
||||
{
|
||||
public:
|
||||
OpenGlMeshPainter();
|
||||
|
||||
void paint(SceneModel* model, DrawingContext* context);
|
||||
|
||||
private:
|
||||
void initializeShader();
|
||||
void initializeBuffers();
|
||||
|
||||
void paint(const std::vector<float>& verts, const std::vector<std::size_t>& elements, const std::vector<float>& color, bool lines = false);
|
||||
|
||||
unsigned mVertexBuffer{0};
|
||||
unsigned mElementBuffer{0};
|
||||
unsigned mVertexArray{0};
|
||||
std::unique_ptr<OpenGlShaderProgram> mShaderProgram;
|
||||
};
|
68
src/rendering/graphics/opengl/OpenGlPainter.cpp
Normal file
68
src/rendering/graphics/opengl/OpenGlPainter.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include "OpenGlPainter.h"
|
||||
|
||||
#include "DrawingContext.h"
|
||||
#include "DrawingSurface.h"
|
||||
#include "Scene.h"
|
||||
#include "SceneItem.h"
|
||||
#include "SceneModel.h"
|
||||
#include "SceneText.h"
|
||||
|
||||
#include "TriMesh.h"
|
||||
|
||||
#include "FontsManager.h"
|
||||
#include "FontGlyph.h"
|
||||
#include "TextData.h"
|
||||
|
||||
#include "OpenGlShaderProgram.h"
|
||||
#include "OpenGlMeshPainter.h"
|
||||
#include "OpenGlTextPainter.h"
|
||||
#include "OpenGlFontTexture.h"
|
||||
|
||||
#include "File.h"
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glx.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
OpenGlPainter::OpenGlPainter(DrawingContext* context)
|
||||
: AbstractPainter(context),
|
||||
mMeshPainter(std::make_unique<OpenGlMeshPainter>()),
|
||||
mTextPainter(std::make_unique<OpenGlTextPainter>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void OpenGlPainter::paint()
|
||||
{
|
||||
auto surface = mDrawingContext->getSurface();
|
||||
const auto width = double(surface->getWidth());
|
||||
const auto height = double(surface->getHeight());
|
||||
|
||||
glViewport(0, 0, width, height);
|
||||
glOrtho(0, width, 0, height, -1.0, 1.0);
|
||||
|
||||
glClearColor(0.5, 0.5, 1.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
auto scene = mDrawingContext->getSurface()->getScene();
|
||||
for (const auto item : scene->getItems())
|
||||
{
|
||||
if (item->getType() == SceneItem::Type::MODEL)
|
||||
{
|
||||
mMeshPainter->paint(dynamic_cast<SceneModel*>(item), mDrawingContext);
|
||||
}
|
||||
else if (item->getType() == SceneItem::Type::TEXT)
|
||||
{
|
||||
mTextPainter->paint(dynamic_cast<SceneText*>(item), mDrawingContext);
|
||||
}
|
||||
}
|
||||
|
||||
glFlush();
|
||||
}
|
25
src/rendering/graphics/opengl/OpenGlPainter.h
Normal file
25
src/rendering/graphics/opengl/OpenGlPainter.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractPainter.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
class DrawingContext;
|
||||
class OpenGlMeshPainter;
|
||||
class OpenGlTextPainter;
|
||||
|
||||
class TriMesh;
|
||||
|
||||
class OpenGlPainter : public AbstractPainter
|
||||
{
|
||||
public:
|
||||
OpenGlPainter(DrawingContext* context);
|
||||
void paint() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<OpenGlMeshPainter> mMeshPainter;
|
||||
std::unique_ptr<OpenGlTextPainter> mTextPainter;
|
||||
};
|
||||
|
||||
|
68
src/rendering/graphics/opengl/OpenGlShaderProgram.cpp
Normal file
68
src/rendering/graphics/opengl/OpenGlShaderProgram.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include "OpenGlShaderProgram.h"
|
||||
|
||||
#include "File.h"
|
||||
#include "FileLogger.h"
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
|
||||
OpenGlShaderProgram::OpenGlShaderProgram(const Path& vertShaderPath, const Path& fragShaderPath)
|
||||
{
|
||||
const auto vert_shader_source = File(vertShaderPath).read();
|
||||
const auto frag_shader_source = File(fragShaderPath).read();
|
||||
|
||||
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
|
||||
const char* vert_source = vert_shader_source.c_str();
|
||||
glShaderSource(vertexShader, 1, &vert_source, nullptr);
|
||||
glCompileShader(vertexShader);
|
||||
|
||||
int success;
|
||||
char infoLog[512];
|
||||
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
|
||||
if(!success)
|
||||
{
|
||||
glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
|
||||
MLOG_ERROR("ERROR::SHADER::VERTEX::COMPILATION_FAILED: " << infoLog);
|
||||
if (auto errCode = glGetError(); errCode != GL_NO_ERROR)
|
||||
{
|
||||
auto errString = gluErrorString(errCode);
|
||||
MLOG_ERROR("Got gl error " << errString);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int fragmentShader;
|
||||
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
const char* frag_source = frag_shader_source.c_str();
|
||||
glShaderSource(fragmentShader, 1, &frag_source, nullptr);
|
||||
glCompileShader(fragmentShader);
|
||||
|
||||
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
|
||||
if(!success)
|
||||
{
|
||||
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
|
||||
MLOG_ERROR("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED: " << infoLog);
|
||||
}
|
||||
|
||||
mHandle = glCreateProgram();
|
||||
|
||||
glAttachShader(mHandle, vertexShader);
|
||||
glAttachShader(mHandle, fragmentShader);
|
||||
glLinkProgram(mHandle);
|
||||
|
||||
glGetProgramiv(mHandle, GL_LINK_STATUS, &success);
|
||||
if(!success)
|
||||
{
|
||||
glGetProgramInfoLog(mHandle, 512, NULL, infoLog);
|
||||
MLOG_ERROR("Shader linking FAILED: " << infoLog);
|
||||
}
|
||||
|
||||
glDeleteShader(vertexShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
}
|
||||
|
||||
unsigned int OpenGlShaderProgram::getHandle() const
|
||||
{
|
||||
return mHandle;
|
||||
}
|
15
src/rendering/graphics/opengl/OpenGlShaderProgram.h
Normal file
15
src/rendering/graphics/opengl/OpenGlShaderProgram.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
using Path = std::filesystem::path;
|
||||
|
||||
class OpenGlShaderProgram
|
||||
{
|
||||
public:
|
||||
OpenGlShaderProgram(const Path& vertShaderPath, const Path& fragShaderPath);
|
||||
|
||||
unsigned int getHandle() const;
|
||||
private:
|
||||
unsigned int mHandle{0};
|
||||
};
|
147
src/rendering/graphics/opengl/OpenGlTextPainter.cpp
Normal file
147
src/rendering/graphics/opengl/OpenGlTextPainter.cpp
Normal file
|
@ -0,0 +1,147 @@
|
|||
#include "OpenGlTextPainter.h"
|
||||
|
||||
#include "DrawingContext.h"
|
||||
#include "DrawingSurface.h"
|
||||
|
||||
#include "FontsManager.h"
|
||||
#include "FontGlyph.h"
|
||||
|
||||
#include "OpenGlFontTexture.h"
|
||||
#include "OpenGlShaderProgram.h"
|
||||
#include "TextData.h"
|
||||
|
||||
#include "SceneText.h"
|
||||
|
||||
#include "File.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glx.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
OpenGlTextPainter::OpenGlTextPainter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void OpenGlTextPainter::initializeShader()
|
||||
{
|
||||
auto vert_shader_path = std::filesystem::path(__FILE__).parent_path() / "shaders/text.vert";
|
||||
auto frag_shader_path = std::filesystem::path(__FILE__).parent_path() / "shaders/text.frag";
|
||||
|
||||
mShaderProgram = std::make_unique<OpenGlShaderProgram>(vert_shader_path, frag_shader_path);
|
||||
}
|
||||
|
||||
void OpenGlTextPainter::initializeTextures(const TextData& textData, DrawingContext* context)
|
||||
{
|
||||
for (auto line : textData.mLines)
|
||||
{
|
||||
for (auto c : line)
|
||||
{
|
||||
if (auto iter = mFontTextures.find(c); iter == mFontTextures.end())
|
||||
{
|
||||
auto glyph = context->getFontsManager()->getGlyph(textData.mFont.getFaceName(), textData.mFont.getSize(), c);
|
||||
auto new_texture = std::make_unique<OpenGlFontTexture>(glyph);
|
||||
mFontTextures[c] = std::move(new_texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGlTextPainter::initializeBuffers()
|
||||
{
|
||||
glGenVertexArrays(1, &mVertexArray);
|
||||
glGenBuffers(1, &mVertexBuffer);
|
||||
|
||||
glBindVertexArray(mVertexArray);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, nullptr, GL_DYNAMIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void OpenGlTextPainter::paint(SceneText* text, DrawingContext* context)
|
||||
{
|
||||
if (!mShaderProgram)
|
||||
{
|
||||
initializeShader();
|
||||
}
|
||||
|
||||
if (mVertexArray == 0)
|
||||
{
|
||||
initializeBuffers();
|
||||
}
|
||||
|
||||
auto text_data = text->getTextData();
|
||||
|
||||
initializeTextures(text_data, context);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glUseProgram(mShaderProgram->getHandle());
|
||||
|
||||
glUniform3f(glGetUniformLocation(mShaderProgram->getHandle(), "textColor"), 0.0, 0.0, 0.0);
|
||||
|
||||
const auto width = float(context->getSurface()->getWidth());
|
||||
const auto height = float(context->getSurface()->getHeight());
|
||||
glm::mat4 projection = glm::ortho(0.0f, width, 0.0f, height);
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(mShaderProgram->getHandle(), "projection"), 1, GL_FALSE, glm::value_ptr(projection));
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindVertexArray(mVertexArray);
|
||||
|
||||
auto transform = text->getTransform();
|
||||
|
||||
float line_delta = 20;
|
||||
float line_offset = 0;
|
||||
for (auto line : text_data.mLines)
|
||||
{
|
||||
float x = transform.getLocation().getX();
|
||||
const float y = height - line_offset - transform.getLocation().getY();
|
||||
for (auto c : line)
|
||||
{
|
||||
auto texture = mFontTextures[c].get();
|
||||
|
||||
float xpos = x + texture->getGlyph()->getBearingX();
|
||||
float ypos = y - (int(texture->getGlyph()->getHeight()) - texture->getGlyph()->getBearingY());
|
||||
|
||||
float w = texture->getGlyph()->getWidth();
|
||||
float h = texture->getGlyph()->getHeight();
|
||||
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 }
|
||||
};
|
||||
glBindTexture(GL_TEXTURE_2D, texture->getHandle());
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
|
||||
auto offset = (texture->getGlyph()->getAdvanceX() >> 6); // bitshift by 6 to get value in pixels (2^6 = 64)
|
||||
x += offset;
|
||||
}
|
||||
line_offset += line_delta;
|
||||
}
|
||||
glBindVertexArray(0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
30
src/rendering/graphics/opengl/OpenGlTextPainter.h
Normal file
30
src/rendering/graphics/opengl/OpenGlTextPainter.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
class DrawingContext;
|
||||
class OpenGlFontTexture;
|
||||
class OpenGlShaderProgram;
|
||||
|
||||
class TextData;
|
||||
class SceneText;
|
||||
|
||||
class OpenGlTextPainter
|
||||
{
|
||||
public:
|
||||
OpenGlTextPainter();
|
||||
|
||||
void paint(SceneText* text, DrawingContext* context);
|
||||
|
||||
private:
|
||||
void initializeShader();
|
||||
void initializeTextures(const TextData& textData, DrawingContext* context);
|
||||
|
||||
void initializeBuffers();
|
||||
|
||||
unsigned mVertexBuffer{0};
|
||||
unsigned mVertexArray{0};
|
||||
std::unique_ptr<OpenGlShaderProgram> mShaderProgram;
|
||||
std::unordered_map<char, std::unique_ptr<OpenGlFontTexture> > mFontTextures;
|
||||
};
|
11
src/rendering/graphics/opengl/shaders/default.frag
Normal file
11
src/rendering/graphics/opengl/shaders/default.frag
Normal file
|
@ -0,0 +1,11 @@
|
|||
#version 330 core
|
||||
out vec4 FragColor;
|
||||
|
||||
in vec4 vertexColor; // the input variable from the vertex shader (same name and same type)
|
||||
|
||||
uniform vec4 ourColor; // we set this variable in the OpenGL code.
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = ourColor;
|
||||
}
|
7
src/rendering/graphics/opengl/shaders/default.vert
Normal file
7
src/rendering/graphics/opengl/shaders/default.vert
Normal file
|
@ -0,0 +1,7 @@
|
|||
#version 330 core
|
||||
layout (location = 0) in vec3 aPos;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(aPos, 1.0);
|
||||
}
|
12
src/rendering/graphics/opengl/shaders/text.frag
Normal file
12
src/rendering/graphics/opengl/shaders/text.frag
Normal file
|
@ -0,0 +1,12 @@
|
|||
#version 330 core
|
||||
in vec2 TexCoords;
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2D text;
|
||||
uniform vec3 textColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
|
||||
color = vec4(textColor, 1.0) * sampled;
|
||||
}
|
11
src/rendering/graphics/opengl/shaders/text.vert
Normal file
11
src/rendering/graphics/opengl/shaders/text.vert
Normal file
|
@ -0,0 +1,11 @@
|
|||
#version 330 core
|
||||
layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>
|
||||
out vec2 TexCoords;
|
||||
|
||||
uniform mat4 projection;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
|
||||
TexCoords = vertex.zw;
|
||||
}
|
34
src/rendering/mesh/AbstractFace.cpp
Normal file
34
src/rendering/mesh/AbstractFace.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
#include "AbstractFace.h"
|
||||
|
||||
#include "Edge.h"
|
||||
|
||||
AbstractFace::AbstractFace(std::size_t id)
|
||||
: mId(id)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AbstractFace::~AbstractFace()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AbstractFace::addVectorAttribute(const std::string& tag, const std::vector<double>& values)
|
||||
{
|
||||
mVectorAttributes[tag] = values;
|
||||
}
|
||||
|
||||
std::vector<double> AbstractFace::getVectorAttribute(const std::string& tag) const
|
||||
{
|
||||
auto iter = mVectorAttributes.find(tag);
|
||||
if (iter != mVectorAttributes.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void AbstractFace::setIndex(std::size_t idx)
|
||||
{
|
||||
mId = idx;
|
||||
}
|
47
src/rendering/mesh/AbstractFace.h
Normal file
47
src/rendering/mesh/AbstractFace.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include "Point.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
class Edge;
|
||||
|
||||
class AbstractFace
|
||||
{
|
||||
public:
|
||||
|
||||
enum class Orientation
|
||||
{
|
||||
CW,
|
||||
CCW
|
||||
};
|
||||
|
||||
AbstractFace(std::size_t id=0);
|
||||
|
||||
virtual ~AbstractFace();
|
||||
|
||||
virtual std::vector<std::size_t> getNodeIds() const = 0;
|
||||
|
||||
void addVectorAttribute(const std::string& tag, const std::vector<double>& values);
|
||||
|
||||
std::vector<double> getVectorAttribute(const std::string& tag) const;
|
||||
|
||||
virtual std::size_t getNumNodes() const = 0;
|
||||
|
||||
virtual void associateWidthEdges() = 0;
|
||||
|
||||
virtual std::vector<std::size_t> getEdgeIds() const = 0;
|
||||
|
||||
virtual std::vector<Point> getNodeLocations(Orientation orientation = Orientation::CCW) const = 0;
|
||||
|
||||
virtual void replaceEdge(Edge* original, Edge* replacement) = 0;
|
||||
|
||||
void setIndex(std::size_t idx);
|
||||
|
||||
protected:
|
||||
std::size_t mId{0};
|
||||
std::unordered_map<std::string, std::vector<double> > mVectorAttributes;
|
||||
};
|
75
src/rendering/mesh/AbstractMesh.cpp
Normal file
75
src/rendering/mesh/AbstractMesh.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include "AbstractMesh.h"
|
||||
|
||||
void AbstractMesh::addConstantNodeVectorAttribute(const std::string& tag, const std::vector<double>& values)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::vector<double> > AbstractMesh::getNodeVectorAttributes(const std::string& tag)
|
||||
{
|
||||
std::vector<std::vector<double> > attribs(mNodes.size());
|
||||
return attribs;
|
||||
}
|
||||
|
||||
void AbstractMesh::addVectorAttribute(const std::string& tag, const std::vector<double>& values)
|
||||
{
|
||||
mVectorAttributes[tag] = values;
|
||||
}
|
||||
|
||||
bool AbstractMesh::hasVectorAttribute(const std::string& tag) const
|
||||
{
|
||||
return mVectorAttributes.find(tag) != mVectorAttributes.end();
|
||||
}
|
||||
|
||||
unsigned AbstractMesh::getNumNodes() const
|
||||
{
|
||||
return unsigned(mNodes.size());
|
||||
}
|
||||
|
||||
const VecNodes& AbstractMesh::getNodes() const
|
||||
{
|
||||
return mNodes;
|
||||
}
|
||||
|
||||
std::vector<double> AbstractMesh::getVectorAttribute(const std::string& tag) const
|
||||
{
|
||||
auto iter = mVectorAttributes.find(tag);
|
||||
if (iter != mVectorAttributes.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void AbstractMesh::scale(double scaleX, double scaleY)
|
||||
{
|
||||
Transform transform({ 0.0, 0.0 }, scaleX, scaleY);
|
||||
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
node->apply(transform);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractMesh::transform(const Transform& transform)
|
||||
{
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
node->apply(transform);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractMesh::translate(double offsetX, double offsetY, double offsetZ)
|
||||
{
|
||||
const Point loc {-offsetX, -offsetY, -offsetZ};
|
||||
Transform transform(loc);
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
node->apply(transform);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractMesh::translate(const Point& offset)
|
||||
{
|
||||
translate(offset.getX(), offset.getY(), offset.getZ());
|
||||
}
|
68
src/rendering/mesh/AbstractMesh.h
Normal file
68
src/rendering/mesh/AbstractMesh.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
#pragma once
|
||||
|
||||
#include "Point.h"
|
||||
#include "Node.h"
|
||||
#include "Transform.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using NodePtr = std::unique_ptr<Node>;
|
||||
using VecNodes = std::vector<NodePtr>;
|
||||
|
||||
class AbstractMesh
|
||||
{
|
||||
public:
|
||||
enum class MeshType
|
||||
{
|
||||
LINE,
|
||||
TRI,
|
||||
QUAD
|
||||
};
|
||||
|
||||
virtual ~AbstractMesh() = default;
|
||||
|
||||
void addVectorAttribute(const std::string& tag, const std::vector<double>& values);
|
||||
|
||||
void addConstantNodeVectorAttribute(const std::string& tag, const std::vector<double>& values);
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> getVerticesFlat(T scaleX = 1.0, T scaleY = 1.0, T scaleZ = 1.0) const
|
||||
{
|
||||
std::vector<T> ret(3*mNodes.size());
|
||||
for(std::size_t idx = 0; idx<mNodes.size(); idx++)
|
||||
{
|
||||
auto node = mNodes[idx].get();
|
||||
ret[3*idx] = node->getPoint().getX()/scaleX;
|
||||
ret[3*idx + 1] = node->getPoint().getY()/scaleY;
|
||||
ret[3*idx + 2] = node->getPoint().getZ()/scaleZ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<AbstractMesh> copy() const = 0;
|
||||
|
||||
std::vector<std::vector<double> > getNodeVectorAttributes(const std::string& tag);
|
||||
|
||||
std::vector<double> getVectorAttribute(const std::string& tag) const;
|
||||
|
||||
virtual MeshType getType() const = 0;
|
||||
|
||||
bool hasVectorAttribute(const std::string& tag) const;
|
||||
|
||||
void scale(double scaleX, double scaleY);
|
||||
|
||||
void translate(const Point& offset);
|
||||
|
||||
void translate(double offsetX, double offsetY, double offsetZ = 0.0);
|
||||
|
||||
void transform(const Transform& transform);
|
||||
|
||||
unsigned getNumNodes() const;
|
||||
|
||||
const VecNodes& getNodes() const;
|
||||
|
||||
protected:
|
||||
std::unordered_map<std::string, std::vector<double> > mVectorAttributes;
|
||||
VecNodes mNodes;
|
||||
};
|
38
src/rendering/mesh/CMakeLists.txt
Normal file
38
src/rendering/mesh/CMakeLists.txt
Normal file
|
@ -0,0 +1,38 @@
|
|||
list(APPEND mesh_LIB_INCLUDES
|
||||
AbstractMesh.cpp
|
||||
AbstractMesh.h
|
||||
Edge.cpp
|
||||
Edge.h
|
||||
AbstractFace.cpp
|
||||
AbstractFace.h
|
||||
QuadFace.cpp
|
||||
QuadFace.h
|
||||
TriFace.cpp
|
||||
TriFace.h
|
||||
Node.cpp
|
||||
Node.h
|
||||
QuadMesh.cpp
|
||||
QuadMesh.h
|
||||
TriMesh.cpp
|
||||
TriMesh.h
|
||||
FaceMesh.cpp
|
||||
FaceMesh.h
|
||||
LineMesh.cpp
|
||||
LineMesh.h
|
||||
MeshPrimitives.cpp
|
||||
MeshPrimitives.h
|
||||
MeshBuilder.cpp
|
||||
MeshBuilder.h
|
||||
MeshObjWriter.h
|
||||
MeshObjWriter.cpp
|
||||
)
|
||||
|
||||
|
||||
# add the library
|
||||
add_library(mesh SHARED ${mesh_LIB_INCLUDES})
|
||||
target_link_libraries(mesh core geometry)
|
||||
|
||||
target_include_directories(mesh PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/")
|
||||
|
||||
set_target_properties( mesh PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||
set_property(TARGET mesh PROPERTY FOLDER src/rendering)
|
122
src/rendering/mesh/Edge.cpp
Normal file
122
src/rendering/mesh/Edge.cpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
#include "Edge.h"
|
||||
|
||||
#include "Node.h"
|
||||
|
||||
Edge::Edge(Node* node0, Node* node1, std::size_t id)
|
||||
: mNode0(node0),
|
||||
mNode1(node1),
|
||||
mId(id)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<Edge> Edge::Create(Node* node0, Node* node1, std::size_t id)
|
||||
{
|
||||
return std::make_unique<Edge>(node0, node1, id);
|
||||
}
|
||||
|
||||
Edge::~Edge()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::size_t Edge::getNode0Id() const
|
||||
{
|
||||
return mNode0->getIndex();
|
||||
}
|
||||
|
||||
std::size_t Edge::getNode1Id() const
|
||||
{
|
||||
return mNode1->getIndex();
|
||||
}
|
||||
|
||||
bool Edge::isOverlapping(Edge* edge) const
|
||||
{
|
||||
auto overlaps = edge->getNode0()->isCoincident(mNode0) && edge->getNode1()->isCoincident(mNode1);
|
||||
if (overlaps)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return edge->getNode1()->isCoincident(mNode0) && edge->getNode0()->isCoincident(mNode1);
|
||||
}
|
||||
}
|
||||
|
||||
bool Edge::hasSameNodes(Edge* edge) const
|
||||
{
|
||||
return edge->getNode0() == edge->getNode1() || edge->getNode1() == edge->getNode0();
|
||||
}
|
||||
|
||||
void Edge::replaceNodes(Node* node0, Node* node1)
|
||||
{
|
||||
mNode0 = node0;
|
||||
mNode1 = node1;
|
||||
}
|
||||
|
||||
Node* Edge::getNode0() const
|
||||
{
|
||||
return mNode0;
|
||||
}
|
||||
|
||||
Node* Edge::getNode1() const
|
||||
{
|
||||
return mNode1;
|
||||
}
|
||||
|
||||
Node* Edge::getOtherNode(Node* node) const
|
||||
{
|
||||
if (node == mNode0)
|
||||
{
|
||||
return mNode1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return mNode0;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t Edge::getId() const
|
||||
{
|
||||
return mId;
|
||||
}
|
||||
|
||||
void Edge::setState(State state)
|
||||
{
|
||||
mState = state;
|
||||
}
|
||||
|
||||
Edge::State Edge::getState() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Edge::clearConnectivity()
|
||||
{
|
||||
mAssociatedFaceIds.clear();
|
||||
}
|
||||
|
||||
std::size_t Edge::getNumConnectedFaces() const
|
||||
{
|
||||
return mAssociatedFaceIds.size();
|
||||
}
|
||||
|
||||
void Edge::associateFace(std::size_t faceId)
|
||||
{
|
||||
mAssociatedFaceIds.push_back(faceId);
|
||||
}
|
||||
|
||||
std::size_t Edge::getConnectedFaceId(std::size_t idx) const
|
||||
{
|
||||
return mAssociatedFaceIds[idx];
|
||||
}
|
||||
|
||||
void Edge::associateWithNodes()
|
||||
{
|
||||
mNode0->associateEdge(mId);
|
||||
mNode1->associateEdge(mId);
|
||||
}
|
||||
|
||||
void Edge::setIndex(std::size_t idx)
|
||||
{
|
||||
mId = idx;
|
||||
}
|
65
src/rendering/mesh/Edge.h
Normal file
65
src/rendering/mesh/Edge.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class Node;
|
||||
|
||||
class Edge
|
||||
{
|
||||
public:
|
||||
enum class State
|
||||
{
|
||||
HEALTHY,
|
||||
DIRTY
|
||||
};
|
||||
|
||||
Edge(Node* node0, Node* node1, std::size_t id = 0);
|
||||
|
||||
~Edge();
|
||||
|
||||
static std::unique_ptr<Edge> Create(Node* node0, Node* node1, std::size_t id = 0);
|
||||
|
||||
void associateFace(std::size_t faceId);
|
||||
|
||||
void associateWithNodes();
|
||||
|
||||
void clearConnectivity();
|
||||
|
||||
std::size_t getConnectedFaceId(std::size_t idx) const;
|
||||
|
||||
State getState() const;
|
||||
|
||||
std::size_t getId() const;
|
||||
|
||||
std::size_t getNode0Id() const;
|
||||
|
||||
std::size_t getNode1Id() const;
|
||||
|
||||
Node* getNode0() const;
|
||||
|
||||
Node* getNode1() const;
|
||||
|
||||
std::size_t getNumConnectedFaces() const;
|
||||
|
||||
Node* getOtherNode(Node* node) const;
|
||||
|
||||
bool isOverlapping(Edge* edge) const;
|
||||
|
||||
bool hasSameNodes(Edge* edge) const;
|
||||
|
||||
void replaceNodes(Node* node0, Node* node1);
|
||||
|
||||
void setState(State state);
|
||||
|
||||
void setIndex(std::size_t idx);
|
||||
|
||||
private:
|
||||
std::size_t mId{0};
|
||||
Node* mNode0{nullptr};
|
||||
Node* mNode1{nullptr};
|
||||
|
||||
std::vector<std::size_t> mAssociatedFaceIds;
|
||||
|
||||
State mState{State::HEALTHY};
|
||||
};
|
201
src/rendering/mesh/FaceMesh.cpp
Normal file
201
src/rendering/mesh/FaceMesh.cpp
Normal file
|
@ -0,0 +1,201 @@
|
|||
#include "FaceMesh.h"
|
||||
|
||||
#include "Node.h"
|
||||
#include "Edge.h"
|
||||
#include "AbstractFace.h"
|
||||
|
||||
FaceMesh::~FaceMesh()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FaceMesh::populate(VecNodes& nodes, VecEdges& edges, VecFaces& faces)
|
||||
{
|
||||
mNodes = std::move(nodes);
|
||||
mEdges = std::move(edges);
|
||||
mFaces = std::move(faces);
|
||||
|
||||
resetIds();
|
||||
resetConnectivity();
|
||||
}
|
||||
|
||||
const VecFaces& FaceMesh::getFaces() const
|
||||
{
|
||||
return mFaces;
|
||||
}
|
||||
|
||||
std::vector<std::size_t> FaceMesh::getFaceNodeIds() const
|
||||
{
|
||||
if (mFaces.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto nodes_per_face = mFaces[0]->getNumNodes();
|
||||
std::vector<std::size_t> ids(nodes_per_face*mFaces.size());
|
||||
|
||||
for(std::size_t idx=0; idx<mFaces.size(); idx++)
|
||||
{
|
||||
const auto nodeIds = mFaces[idx]->getNodeIds();
|
||||
for(std::size_t jdx=0; jdx<nodes_per_face; jdx++)
|
||||
{
|
||||
ids[nodes_per_face*idx + jdx] = nodeIds[jdx];
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double> > FaceMesh::getFaceVectorAttributes(const std::string& tag)
|
||||
{
|
||||
std::vector<std::vector<double> > attribs(mFaces.size());
|
||||
for(std::size_t idx=0; idx<mFaces.size(); idx++)
|
||||
{
|
||||
attribs[idx] = {mFaces[idx]->getVectorAttribute(tag)};
|
||||
}
|
||||
return attribs;
|
||||
}
|
||||
|
||||
void FaceMesh::addConstantFaceVectorAttribute(const std::string& tag, const std::vector<double>& values)
|
||||
{
|
||||
for (const auto& face : mFaces)
|
||||
{
|
||||
face->addVectorAttribute(tag, values);
|
||||
}
|
||||
}
|
||||
|
||||
void FaceMesh::resetIds()
|
||||
{
|
||||
std::size_t count = 0;
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
node->setIndex(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
for (auto& edge : mEdges)
|
||||
{
|
||||
edge->setIndex(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
for (auto& face : mFaces)
|
||||
{
|
||||
face->setIndex(count);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
void FaceMesh::resetConnectivity()
|
||||
{
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
node->clearConnectivity();
|
||||
}
|
||||
|
||||
for (auto& edge : mEdges)
|
||||
{
|
||||
edge->associateWithNodes();
|
||||
edge->clearConnectivity();
|
||||
}
|
||||
|
||||
for (auto& face : mFaces)
|
||||
{
|
||||
face->associateWidthEdges();
|
||||
}
|
||||
}
|
||||
|
||||
void FaceMesh::replaceIfOverlapping(FaceMesh* mesh, Node* target_node) const
|
||||
{
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
if (node->getNumConnectedEdges() == 3 && node->isCoincident(target_node))
|
||||
{
|
||||
target_node->setState(Node::State::DIRTY);
|
||||
for (std::size_t idx=0; idx<3; idx++)
|
||||
{
|
||||
auto edge = mesh->mEdges[idx].get();
|
||||
edge->replaceNodes(target_node, node.get());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FaceMesh::replaceIfOverlapping(FaceMesh* mesh, Edge* target_edge) const
|
||||
{
|
||||
for (auto& edge : mEdges)
|
||||
{
|
||||
if (edge->getNumConnectedFaces() == 2 && target_edge->hasSameNodes(edge.get()))
|
||||
{
|
||||
target_edge->setState(Edge::State::DIRTY);
|
||||
for (std::size_t idx=0; idx<2; idx++)
|
||||
{
|
||||
auto face = mesh->mFaces[idx].get();
|
||||
face->replaceEdge(target_edge, edge.get());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::size_t> FaceMesh::getEdgeNodeIds() const
|
||||
{
|
||||
std::vector<std::size_t> ids(2*mEdges.size());
|
||||
for(std::size_t idx=0; idx<mEdges.size(); idx++)
|
||||
{
|
||||
ids[2*idx] = mEdges[idx]->getNode0Id();
|
||||
ids[2*idx + 1] = mEdges[idx]->getNode1Id();
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
void FaceMesh::merge(std::unique_ptr<FaceMesh> mesh)
|
||||
{
|
||||
if (mesh->getType() != getType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& node : mesh->mNodes)
|
||||
{
|
||||
if (node->getNumConnectedEdges() == 3)
|
||||
{
|
||||
replaceIfOverlapping(mesh.get(), node.get());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& node : mesh->mNodes)
|
||||
{
|
||||
if (node->getState() == Node::State::HEALTHY)
|
||||
{
|
||||
mNodes.push_back(std::move(node));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& edge : mesh->mEdges)
|
||||
{
|
||||
if (edge->getNumConnectedFaces() == 2)
|
||||
{
|
||||
replaceIfOverlapping(mesh.get(), edge.get());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& edge : mesh->mEdges)
|
||||
{
|
||||
if (edge->getState() == Edge::State::HEALTHY)
|
||||
{
|
||||
mEdges.push_back(std::move(edge));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& face : mesh->mFaces)
|
||||
{
|
||||
mFaces.push_back(std::move(face));
|
||||
}
|
||||
|
||||
mesh.reset();
|
||||
resetIds();
|
||||
resetConnectivity();
|
||||
}
|
51
src/rendering/mesh/FaceMesh.h
Normal file
51
src/rendering/mesh/FaceMesh.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractMesh.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class Edge;
|
||||
class AbstractFace;
|
||||
|
||||
using EdgePtr = std::unique_ptr<Edge>;
|
||||
using AbstractFacePtr = std::unique_ptr<AbstractFace>;
|
||||
|
||||
using VecEdges = std::vector<EdgePtr>;
|
||||
using VecFaces = std::vector<AbstractFacePtr>;
|
||||
|
||||
class FaceMesh : public AbstractMesh
|
||||
{
|
||||
public:
|
||||
FaceMesh() = default;
|
||||
|
||||
~FaceMesh();
|
||||
|
||||
virtual std::unique_ptr<AbstractMesh> copy() const = 0;
|
||||
|
||||
void populate(VecNodes& nodes, VecEdges& edges, VecFaces& faces);
|
||||
|
||||
std::vector<std::size_t> getFaceNodeIds() const;
|
||||
|
||||
std::vector<std::size_t> getEdgeNodeIds() const;
|
||||
|
||||
void addConstantFaceVectorAttribute(const std::string& tag, const std::vector<double>& values);
|
||||
|
||||
std::vector<std::vector<double> > getFaceVectorAttributes(const std::string& tag);
|
||||
|
||||
void merge(std::unique_ptr<FaceMesh> mesh);
|
||||
|
||||
const VecFaces& getFaces() const;
|
||||
|
||||
protected:
|
||||
void resetConnectivity();
|
||||
|
||||
void resetIds();
|
||||
|
||||
void replaceIfOverlapping(FaceMesh* mesh, Node* node) const;
|
||||
|
||||
void replaceIfOverlapping(FaceMesh* mesh, Edge* edge) const;
|
||||
|
||||
VecEdges mEdges;
|
||||
VecFaces mFaces;
|
||||
};
|
35
src/rendering/mesh/LineMesh.cpp
Normal file
35
src/rendering/mesh/LineMesh.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "LineMesh.h"
|
||||
|
||||
#include "Edge.h"
|
||||
|
||||
LineMesh::~LineMesh()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LineMesh::populate(VecNodes& nodes, VecEdges& edges)
|
||||
{
|
||||
mNodes = std::move(nodes);
|
||||
mEdges = std::move(edges);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractMesh> LineMesh::copy() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LineMesh::MeshType LineMesh::getType() const
|
||||
{
|
||||
return LineMesh::MeshType::LINE;
|
||||
}
|
||||
|
||||
std::vector<std::size_t> LineMesh::getEdgeNodeIds() const
|
||||
{
|
||||
std::vector<std::size_t> ids(2*mEdges.size());
|
||||
for(std::size_t idx=0; idx<mEdges.size(); idx++)
|
||||
{
|
||||
ids[2*idx] = mEdges[idx]->getNode0Id();
|
||||
ids[2*idx + 1] = mEdges[idx]->getNode1Id();
|
||||
}
|
||||
return ids;
|
||||
}
|
29
src/rendering/mesh/LineMesh.h
Normal file
29
src/rendering/mesh/LineMesh.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractMesh.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class Edge;
|
||||
using EdgePtr = std::unique_ptr<Edge>;
|
||||
using VecEdges = std::vector<EdgePtr>;
|
||||
|
||||
class LineMesh : public AbstractMesh
|
||||
{
|
||||
public:
|
||||
LineMesh() = default;
|
||||
|
||||
~LineMesh();
|
||||
|
||||
void populate(VecNodes& nodes, VecEdges& edges);
|
||||
|
||||
std::vector<std::size_t> getEdgeNodeIds() const;
|
||||
|
||||
MeshType getType() const override;
|
||||
|
||||
std::unique_ptr<AbstractMesh> copy() const override;
|
||||
|
||||
private:
|
||||
VecEdges mEdges;
|
||||
};
|
55
src/rendering/mesh/MeshBuilder.cpp
Normal file
55
src/rendering/mesh/MeshBuilder.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
#include "MeshBuilder.h"
|
||||
|
||||
#include "Node.h"
|
||||
#include "Edge.h"
|
||||
#include "TriFace.h"
|
||||
|
||||
std::unique_ptr<TriMesh> MeshBuilder::buildTriMesh(const VecPoints& locations, const EdgeIds& edgeIds, const FaceIds& faceIds)
|
||||
{
|
||||
auto mesh = std::make_unique<TriMesh>();
|
||||
|
||||
VecNodes nodes(locations.size());
|
||||
for (std::size_t idx=0; idx<locations.size(); idx++)
|
||||
{
|
||||
nodes[idx] = Node::Create(locations[idx], idx);
|
||||
}
|
||||
|
||||
VecEdges edges(edgeIds.size());
|
||||
for (std::size_t idx=0; idx<edgeIds.size(); idx++)
|
||||
{
|
||||
edges[idx] = Edge::Create(nodes[edgeIds[idx].first].get(), nodes[edgeIds[idx].second].get(), idx);
|
||||
}
|
||||
|
||||
VecFaces faces(faceIds.size());
|
||||
for (std::size_t idx=0; idx<faceIds.size(); idx++)
|
||||
{
|
||||
faces[idx] = TriFace::Create(
|
||||
edges[faceIds[idx][0]].get(),
|
||||
edges[faceIds[idx][1]].get(),
|
||||
edges[faceIds[idx][2]].get(),
|
||||
idx);
|
||||
}
|
||||
|
||||
mesh->populate(nodes, edges, faces);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
std::unique_ptr<LineMesh> MeshBuilder::buildLineMesh(const VecPoints& locations, const EdgeIds& edgeIds)
|
||||
{
|
||||
auto mesh = std::make_unique<LineMesh>();
|
||||
|
||||
VecNodes nodes(locations.size());
|
||||
for (std::size_t idx=0; idx<locations.size(); idx++)
|
||||
{
|
||||
nodes[idx] = Node::Create(locations[idx], idx);
|
||||
}
|
||||
|
||||
VecEdges edges(edgeIds.size());
|
||||
for (std::size_t idx=0; idx<edgeIds.size(); idx++)
|
||||
{
|
||||
edges[idx] = Edge::Create(nodes[edgeIds[idx].first].get(), nodes[edgeIds[idx].second].get(), idx);
|
||||
}
|
||||
|
||||
mesh->populate(nodes, edges);
|
||||
return mesh;
|
||||
}
|
19
src/rendering/mesh/MeshBuilder.h
Normal file
19
src/rendering/mesh/MeshBuilder.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "TriMesh.h"
|
||||
#include "LineMesh.h"
|
||||
#include "Point.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
using EdgeIds = std::vector<std::pair<std::size_t, std::size_t> >;
|
||||
using FaceIds = std::vector<std::vector<std::size_t> >;
|
||||
using VecPoints = std::vector<Point>;
|
||||
|
||||
class MeshBuilder
|
||||
{
|
||||
public:
|
||||
static std::unique_ptr<TriMesh> buildTriMesh(const VecPoints& locations, const EdgeIds& edgeIds, const FaceIds& faceIds);
|
||||
|
||||
static std::unique_ptr<LineMesh> buildLineMesh(const VecPoints& locations, const EdgeIds& edgeIds);
|
||||
};
|
32
src/rendering/mesh/MeshObjWriter.cpp
Normal file
32
src/rendering/mesh/MeshObjWriter.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include "MeshObjWriter.h"
|
||||
|
||||
#include "File.h"
|
||||
#include "TriMesh.h"
|
||||
#include "AbstractFace.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
std::string MeshObjWriter::serialize(TriMesh* mesh)
|
||||
{
|
||||
std::stringstream output;
|
||||
for (const auto& node : mesh->getNodes())
|
||||
{
|
||||
const auto x = node->getPoint().getX();
|
||||
const auto y = node->getPoint().getY();
|
||||
const auto z = node->getPoint().getZ();
|
||||
output << "v "<< x << " " << y << " " << z << "\n";
|
||||
}
|
||||
|
||||
for (const auto& face : mesh->getFaces())
|
||||
{
|
||||
auto ids = face->getNodeIds();
|
||||
output << "f " << 1 + ids[0] << " " << 1 + ids[1] << " " << 1 + ids[2] << "\n";
|
||||
}
|
||||
return output.str();
|
||||
}
|
||||
|
||||
void MeshObjWriter::write(const Path& path, TriMesh* mesh)
|
||||
{
|
||||
File file(path);
|
||||
file.writeText(serialize(mesh));
|
||||
}
|
14
src/rendering/mesh/MeshObjWriter.h
Normal file
14
src/rendering/mesh/MeshObjWriter.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
using Path = std::filesystem::path;
|
||||
class TriMesh;
|
||||
|
||||
class MeshObjWriter
|
||||
{
|
||||
public:
|
||||
static std::string serialize(TriMesh* mesh);
|
||||
static void write(const Path& path, TriMesh* mesh);
|
||||
};
|
305
src/rendering/mesh/MeshPrimitives.cpp
Normal file
305
src/rendering/mesh/MeshPrimitives.cpp
Normal file
|
@ -0,0 +1,305 @@
|
|||
#include "MeshPrimitives.h"
|
||||
|
||||
#include "MeshBuilder.h"
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
std::unique_ptr<TriMesh> MeshPrimitives::buildRectangleAsTriMesh()
|
||||
{
|
||||
VecPoints locations = {
|
||||
{0, 0},
|
||||
{1, 0},
|
||||
{1, 1},
|
||||
{0, 1}
|
||||
};
|
||||
|
||||
EdgeIds edge_ids = {
|
||||
{0, 1},
|
||||
{1, 2},
|
||||
{2, 0},
|
||||
{2, 3},
|
||||
{3, 0}
|
||||
};
|
||||
|
||||
FaceIds face_ids = {
|
||||
{0, 1, 2},
|
||||
{2, 3, 4}
|
||||
};
|
||||
|
||||
return MeshBuilder::buildTriMesh(locations, edge_ids, face_ids);
|
||||
}
|
||||
|
||||
std::unique_ptr<TriMesh> MeshPrimitives::buildCircleAsTriMesh(std::size_t numSegments)
|
||||
{
|
||||
VecPoints locations(numSegments + 1);
|
||||
locations[0] = {0, 0};
|
||||
|
||||
const double delta_theta = (2.0*M_PI)/double(numSegments);
|
||||
double theta = 0.0;
|
||||
for(std::size_t idx=1; idx<=numSegments; idx++)
|
||||
{
|
||||
const double x = sin(theta);
|
||||
const double y = cos(theta);
|
||||
locations[idx] = {x, y};
|
||||
theta += delta_theta;
|
||||
std::cout << "Adding node at: " << x << " | " << y << std::endl;
|
||||
}
|
||||
|
||||
EdgeIds edge_ids(2*numSegments);
|
||||
for(std::size_t idx=0; idx<numSegments; idx++)
|
||||
{
|
||||
edge_ids[idx] = {0, idx+1};
|
||||
|
||||
auto wrap_node = idx + 2;
|
||||
if (wrap_node > numSegments)
|
||||
{
|
||||
wrap_node = 1;
|
||||
}
|
||||
edge_ids[idx + numSegments] = {idx + 1, wrap_node};
|
||||
}
|
||||
|
||||
FaceIds face_ids(numSegments);
|
||||
for(std::size_t idx=0; idx<numSegments; idx++)
|
||||
{
|
||||
auto top_edge_inner = idx + 1;
|
||||
if (top_edge_inner == numSegments)
|
||||
{
|
||||
top_edge_inner = 0;
|
||||
}
|
||||
|
||||
const auto outer_edge = idx + numSegments;
|
||||
face_ids[idx] = {idx, outer_edge, top_edge_inner};
|
||||
}
|
||||
return MeshBuilder::buildTriMesh(locations, edge_ids, face_ids);
|
||||
}
|
||||
|
||||
std::unique_ptr<LineMesh> MeshPrimitives::buildCircleAsLineMesh(std::size_t numSegments)
|
||||
{
|
||||
VecPoints locations(numSegments);
|
||||
const double delta_theta = (2.0*M_PI)/double(numSegments);
|
||||
double theta = 0.0;
|
||||
for(unsigned idx=0; idx<numSegments; idx++)
|
||||
{
|
||||
const double x = sin(theta);
|
||||
const double y = cos(theta);
|
||||
locations[idx] = {x, y};
|
||||
}
|
||||
|
||||
EdgeIds edge_ids(2*numSegments);
|
||||
for(unsigned idx=0; idx<numSegments; idx++)
|
||||
{
|
||||
auto top_node = idx + 1;
|
||||
if (top_node == numSegments)
|
||||
{
|
||||
top_node = 0;
|
||||
}
|
||||
edge_ids[idx] = {idx, top_node};
|
||||
}
|
||||
return MeshBuilder::buildLineMesh(locations, edge_ids);
|
||||
}
|
||||
|
||||
std::unique_ptr<TriMesh> MeshPrimitives::buildRoundedRectangleAsTriMesh(double radius, double aspect_ratio, std::size_t num_segments)
|
||||
{
|
||||
std::size_t num_fans = 4;
|
||||
std::size_t num_nodes_per_fan = num_segments + 2;
|
||||
VecPoints locations(num_fans * num_nodes_per_fan);
|
||||
|
||||
double rect_start_x = radius;
|
||||
double rect_end_x = 1.0 - radius;
|
||||
double rect_end_y = 1.0 - radius;
|
||||
|
||||
double delta_theta = (M_PI/4.0) / double (num_segments);
|
||||
double running_theta = 0;
|
||||
|
||||
locations[0] = {rect_end_x, radius};
|
||||
std::size_t offset = 1;
|
||||
for (std::size_t idx=0; idx<=num_segments; idx++)
|
||||
{
|
||||
locations[offset + idx] = {rect_end_x + radius*sin(running_theta), radius*(1.0 - cos(running_theta))};
|
||||
running_theta += delta_theta;
|
||||
}
|
||||
offset += num_segments;
|
||||
|
||||
locations[offset] = {rect_end_x, rect_end_y};
|
||||
offset++;
|
||||
running_theta = 0;
|
||||
for (std::size_t idx=0; idx<=num_segments;idx++)
|
||||
{
|
||||
locations[offset + idx] = {rect_end_x + radius*cos(running_theta), rect_end_y + radius*sin(running_theta)};
|
||||
running_theta += delta_theta;
|
||||
}
|
||||
offset += num_segments;
|
||||
|
||||
locations[offset] = {rect_start_x, rect_end_y};
|
||||
offset ++;
|
||||
running_theta = 0;
|
||||
for (std::size_t idx=0; idx<=num_segments;idx++)
|
||||
{
|
||||
locations[offset + idx] = {rect_start_x - radius*sin(running_theta), rect_end_y + radius*cos(running_theta)};
|
||||
running_theta += delta_theta;
|
||||
}
|
||||
offset += num_segments;
|
||||
|
||||
locations[offset] = {rect_start_x, radius};
|
||||
offset++;
|
||||
running_theta = 0;
|
||||
for (std::size_t idx=0; idx<=num_segments;idx++)
|
||||
{
|
||||
locations[offset + idx] = {rect_start_x - radius*cos(running_theta), radius *(1 - sin(running_theta))};
|
||||
running_theta += delta_theta;
|
||||
}
|
||||
|
||||
std::size_t num_edges_per_fan = 2*num_segments + 1;
|
||||
std::size_t num_inner_rect_edges = 3*num_fans;
|
||||
EdgeIds edge_ids(num_edges_per_fan*num_fans + num_inner_rect_edges + 1);
|
||||
|
||||
// Fan edges
|
||||
for (std::size_t jdx=0; jdx< num_fans; jdx++)
|
||||
{
|
||||
std::size_t node_offset = jdx*num_nodes_per_fan;
|
||||
std::size_t edge_offset = jdx*num_edges_per_fan;
|
||||
|
||||
// Inner edges
|
||||
for(std::size_t idx=0; idx<=num_segments; idx++)
|
||||
{
|
||||
edge_ids[edge_offset + idx] = {node_offset, node_offset + idx + 1};
|
||||
}
|
||||
|
||||
// Outer edges
|
||||
for(std::size_t idx=0; idx<num_segments; idx++)
|
||||
{
|
||||
edge_ids[edge_offset + num_segments + 1 + idx] = {node_offset + idx + 1, node_offset + idx + 2};
|
||||
}
|
||||
}
|
||||
|
||||
// Inner rect edges
|
||||
std::size_t edge_offset = num_edges_per_fan*num_fans;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<LineMesh> MeshPrimitives::buildRectangleAsLineMesh()
|
||||
{
|
||||
VecPoints locations = {
|
||||
{0, 0},
|
||||
{1, 0},
|
||||
{1, 1},
|
||||
{0, 1}
|
||||
};
|
||||
|
||||
EdgeIds edge_ids = {
|
||||
{0, 1},
|
||||
{1, 2},
|
||||
{2, 3},
|
||||
{3, 0}
|
||||
};
|
||||
|
||||
return MeshBuilder::buildLineMesh(locations, edge_ids);
|
||||
}
|
||||
|
||||
std::unique_ptr<TriMesh> MeshPrimitives::buildExplodedGridAsTriMesh(std::size_t numX, std::size_t numY)
|
||||
{
|
||||
double delta_x = 1.0/double(numX);
|
||||
double delta_y = 1.0/double(numY);
|
||||
|
||||
VecPoints locations (4 * numX * numY);
|
||||
double offset_x = delta_x/2.0;
|
||||
double offset_y = delta_y/2.0;
|
||||
for (std::size_t idx=0; idx<numY; idx++)
|
||||
{
|
||||
for(std::size_t jdx=0; jdx<numX; jdx++)
|
||||
{
|
||||
auto locX0 = offset_x - delta_x/2.0;
|
||||
auto locX1 = offset_x + delta_x/2.0;
|
||||
auto locY0 = offset_y - delta_y/2.0;
|
||||
auto locY1 = offset_y + delta_y/2.0;
|
||||
|
||||
auto id_offset = 4* (jdx + numX*idx);
|
||||
locations[id_offset] = Point(locX0, locY0);
|
||||
locations[id_offset + 1] = Point(locX1, locY0);
|
||||
locations[id_offset + 2] = Point(locX1, locY1);
|
||||
locations[id_offset + 3] = Point(locX0, locY1);
|
||||
|
||||
offset_x += delta_x;
|
||||
}
|
||||
offset_x = delta_x/2.0;
|
||||
offset_y += delta_y;
|
||||
}
|
||||
|
||||
EdgeIds edge_ids(5 * numX * numY);
|
||||
for (std::size_t idx=0; idx<numY; idx++)
|
||||
{
|
||||
for(std::size_t jdx=0; jdx<numX; jdx++)
|
||||
{
|
||||
std::size_t node_offset = 4 * (jdx + numX * idx);
|
||||
auto id_offset = 5* (jdx + numX*idx);
|
||||
edge_ids[id_offset] = {node_offset, node_offset + 1};
|
||||
edge_ids[id_offset + 1] = {node_offset + 1, node_offset + 2};
|
||||
edge_ids[id_offset + 2] = {node_offset + 2, node_offset + 3};
|
||||
edge_ids[id_offset + 3] = {node_offset + 3, node_offset};
|
||||
edge_ids[id_offset + 4] = {node_offset + 2, node_offset};
|
||||
}
|
||||
}
|
||||
|
||||
FaceIds face_ids(2 *numX * numY);
|
||||
for (std::size_t idx=0; idx<numY; idx++)
|
||||
{
|
||||
for(std::size_t jdx=0; jdx<numX; jdx++)
|
||||
{
|
||||
std::size_t edge_offset = 5 * (jdx + numX * idx);
|
||||
std::size_t face_offset = 2 * (jdx + numX * idx);
|
||||
face_ids[face_offset] = {edge_offset, edge_offset + 1, edge_offset + 4};
|
||||
face_ids[face_offset + 1] = {edge_offset + 4, edge_offset + 2, edge_offset + 3};
|
||||
}
|
||||
}
|
||||
|
||||
return MeshBuilder::buildTriMesh(locations, edge_ids, face_ids);
|
||||
}
|
||||
|
||||
std::unique_ptr<LineMesh> MeshPrimitives::buildExplodedGridAsLineMesh(std::size_t numX, std::size_t numY)
|
||||
{
|
||||
double delta_x = 1.0/double(numX);
|
||||
double delta_y = 1.0/double(numY);
|
||||
|
||||
VecPoints locations (4 * numX * numY);
|
||||
double offset_x = delta_x/2.0;
|
||||
double offset_y = delta_y/2.0;
|
||||
for (std::size_t idx=0; idx<numY; idx++)
|
||||
{
|
||||
for(std::size_t jdx=0; jdx<numX; jdx++)
|
||||
{
|
||||
auto locX0 = offset_x - delta_x/2.0;
|
||||
auto locX1 = offset_x + delta_x/2.0;
|
||||
auto locY0 = offset_y - delta_y/2.0;
|
||||
auto locY1 = offset_y + delta_y/2.0;
|
||||
|
||||
auto id_offset = 4* (jdx + numX*idx);
|
||||
locations[id_offset] = Point(locX0, locY0);
|
||||
locations[id_offset + 1] = Point(locX1, locY0);
|
||||
locations[id_offset + 2] = Point(locX1, locY1);
|
||||
locations[id_offset + 3] = Point(locX0, locY1);
|
||||
|
||||
offset_x += delta_x;
|
||||
}
|
||||
offset_x = delta_x/2.0;
|
||||
offset_y += delta_y;
|
||||
}
|
||||
|
||||
EdgeIds edge_ids(4 * numX * numY);
|
||||
for (std::size_t idx=0; idx<numY; idx++)
|
||||
{
|
||||
for(std::size_t jdx=0; jdx<numX; jdx++)
|
||||
{
|
||||
std::size_t node_offset = 4 * (jdx + numX * idx);
|
||||
auto id_offset = 4* (jdx + numX*idx);
|
||||
edge_ids[id_offset] = {node_offset, node_offset + 1};
|
||||
edge_ids[id_offset + 1] = {node_offset + 1, node_offset + 2};
|
||||
edge_ids[id_offset + 2] = {node_offset + 2, node_offset + 3};
|
||||
edge_ids[id_offset + 3] = {node_offset + 3, node_offset};
|
||||
}
|
||||
}
|
||||
|
||||
return MeshBuilder::buildLineMesh(locations, edge_ids);
|
||||
}
|
22
src/rendering/mesh/MeshPrimitives.h
Normal file
22
src/rendering/mesh/MeshPrimitives.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "TriMesh.h"
|
||||
#include "LineMesh.h"
|
||||
|
||||
class MeshPrimitives
|
||||
{
|
||||
public:
|
||||
static std::unique_ptr<TriMesh> buildCircleAsTriMesh(std::size_t numSegments = 24);
|
||||
|
||||
static std::unique_ptr<LineMesh> buildCircleAsLineMesh(std::size_t numSegments = 24);
|
||||
|
||||
static std::unique_ptr<TriMesh> buildRectangleAsTriMesh();
|
||||
|
||||
static std::unique_ptr<LineMesh> buildRectangleAsLineMesh();
|
||||
|
||||
static std::unique_ptr<TriMesh> buildExplodedGridAsTriMesh(std::size_t numX, std::size_t numY);
|
||||
|
||||
static std::unique_ptr<LineMesh> buildExplodedGridAsLineMesh(std::size_t numX, std::size_t numY);
|
||||
|
||||
static std::unique_ptr<TriMesh> buildRoundedRectangleAsTriMesh(double radius, double aspect_ratio = 1.0, std::size_t num_segments = 4);
|
||||
};
|
111
src/rendering/mesh/Node.cpp
Normal file
111
src/rendering/mesh/Node.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
#include "Node.h"
|
||||
|
||||
std::unique_ptr<Node> Node::Create(const Point& p, std::size_t index)
|
||||
{
|
||||
return std::make_unique<Node>(p, index);
|
||||
}
|
||||
|
||||
Node::~Node()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Node::Node(const Point& p, std::size_t index)
|
||||
: mPoint(p),
|
||||
mIndex(index)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::size_t Node::getIndex() const
|
||||
{
|
||||
return mIndex;
|
||||
}
|
||||
|
||||
void Node::updateIndex(std::size_t index)
|
||||
{
|
||||
mIndex = index;
|
||||
}
|
||||
|
||||
void Node::addVectorAttribute(const std::string& tag, const std::vector<double>& values)
|
||||
{
|
||||
mVectorAttributes[tag] = values;
|
||||
}
|
||||
|
||||
std::vector<double> Node::getVectorAttribute(const std::string& tag) const
|
||||
{
|
||||
auto iter = mVectorAttributes.find(tag);
|
||||
if (iter != mVectorAttributes.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
const Point& Node::getPoint() const
|
||||
{
|
||||
return mPoint;
|
||||
}
|
||||
|
||||
void Node::apply(const Transform& transform)
|
||||
{
|
||||
mPoint.apply(transform);
|
||||
}
|
||||
|
||||
bool Node::isCoincident(Node* node) const
|
||||
{
|
||||
return node->getPoint() == mPoint;
|
||||
}
|
||||
|
||||
void Node::setState(State state)
|
||||
{
|
||||
mState = state;
|
||||
}
|
||||
|
||||
Node::State Node::getState() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Node::clearConnectivity()
|
||||
{
|
||||
mAssociatedEdgeIds.clear();
|
||||
mAssociatedFaceIds.clear();
|
||||
}
|
||||
|
||||
std::size_t Node::getNumConnectedEdges() const
|
||||
{
|
||||
return mAssociatedEdgeIds.size();
|
||||
}
|
||||
|
||||
std::size_t Node::getNumConnectedFaces() const
|
||||
{
|
||||
return mAssociatedFaceIds.size();
|
||||
}
|
||||
|
||||
void Node::associateEdge(std::size_t edgeId)
|
||||
{
|
||||
mAssociatedEdgeIds.push_back(edgeId);
|
||||
}
|
||||
|
||||
void Node::associateFace(std::size_t faceId)
|
||||
{
|
||||
mAssociatedFaceIds.push_back(faceId);
|
||||
}
|
||||
|
||||
std::size_t Node::getConnectedEdgeId(std::size_t idx) const
|
||||
{
|
||||
return mAssociatedEdgeIds[idx];
|
||||
}
|
||||
|
||||
std::size_t Node::getConnectedFaceId(std::size_t idx) const
|
||||
{
|
||||
return mAssociatedFaceIds[idx];
|
||||
}
|
||||
|
||||
void Node::setIndex(std::size_t idx)
|
||||
{
|
||||
mIndex = idx;
|
||||
}
|
||||
|
||||
|
69
src/rendering/mesh/Node.h
Normal file
69
src/rendering/mesh/Node.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include "Point.h"
|
||||
#include "Transform.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
|
||||
enum class State
|
||||
{
|
||||
HEALTHY,
|
||||
DIRTY
|
||||
};
|
||||
|
||||
Node(const Point& p, std::size_t index = 0);
|
||||
|
||||
static std::unique_ptr<Node> Create(const Point& p, std::size_t index = 0);
|
||||
|
||||
~Node();
|
||||
|
||||
void apply(const Transform& transform);
|
||||
|
||||
void associateEdge(std::size_t edgeId);
|
||||
|
||||
void associateFace(std::size_t faceId);
|
||||
|
||||
void addVectorAttribute(const std::string& tag, const std::vector<double>& values);
|
||||
|
||||
void clearConnectivity();
|
||||
|
||||
std::size_t getIndex() const;
|
||||
|
||||
std::size_t getNumConnectedEdges() const;
|
||||
|
||||
std::size_t getNumConnectedFaces() const;
|
||||
|
||||
std::size_t getConnectedEdgeId(std::size_t idx) const;
|
||||
|
||||
std::size_t getConnectedFaceId(std::size_t idx) const;
|
||||
|
||||
State getState() const;
|
||||
|
||||
const Point& getPoint() const;
|
||||
|
||||
std::vector<double> getVectorAttribute(const std::string& tag) const;
|
||||
|
||||
bool isCoincident(Node* node) const;
|
||||
|
||||
void setState(State state);
|
||||
|
||||
void setIndex(std::size_t idx);
|
||||
|
||||
void updateIndex(std::size_t index);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::vector<double> > mVectorAttributes;
|
||||
std::size_t mIndex{0};
|
||||
Point mPoint;
|
||||
|
||||
std::vector<std::size_t> mAssociatedEdgeIds;
|
||||
std::vector<std::size_t> mAssociatedFaceIds;
|
||||
|
||||
State mState{State::HEALTHY};
|
||||
};
|
0
src/rendering/mesh/QuadFace.cpp
Normal file
0
src/rendering/mesh/QuadFace.cpp
Normal file
8
src/rendering/mesh/QuadFace.h
Normal file
8
src/rendering/mesh/QuadFace.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
class Edge;
|
||||
|
||||
class QuadFace
|
||||
{
|
||||
|
||||
};
|
0
src/rendering/mesh/QuadMesh.cpp
Normal file
0
src/rendering/mesh/QuadMesh.cpp
Normal file
0
src/rendering/mesh/QuadMesh.h
Normal file
0
src/rendering/mesh/QuadMesh.h
Normal file
108
src/rendering/mesh/TriFace.cpp
Normal file
108
src/rendering/mesh/TriFace.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include "TriFace.h"
|
||||
|
||||
#include "Edge.h"
|
||||
#include "Node.h"
|
||||
|
||||
TriFace::TriFace(Edge* edge0, Edge* edge1, Edge* edge2, std::size_t id)
|
||||
: AbstractFace(id),
|
||||
mEdge0(edge0),
|
||||
mEdge1(edge1),
|
||||
mEdge2(edge2)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<TriFace> TriFace::Create(Edge* edge0, Edge* edge1, Edge* edge2, std::size_t id)
|
||||
{
|
||||
return std::make_unique<TriFace>(edge0, edge1, edge2, id);
|
||||
}
|
||||
|
||||
TriFace::~TriFace()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::size_t> TriFace::getNodeIds() const
|
||||
{
|
||||
return {mEdge0->getNode0Id(), mEdge0->getNode1Id(), mEdge1->getNode1Id()};
|
||||
}
|
||||
|
||||
std::size_t TriFace::getNumNodes() const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
void TriFace::replaceEdge(Edge* original, Edge* replacement)
|
||||
{
|
||||
if (original == mEdge0)
|
||||
{
|
||||
mEdge0 = replacement;
|
||||
}
|
||||
else if (original == mEdge1)
|
||||
{
|
||||
mEdge1 = replacement;
|
||||
}
|
||||
else if (original == mEdge2)
|
||||
{
|
||||
mEdge2 = replacement;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t TriFace::getEdge0Id () const
|
||||
{
|
||||
return mEdge0->getId();
|
||||
}
|
||||
|
||||
std::size_t TriFace::getEdge1Id () const
|
||||
{
|
||||
return mEdge1->getId();
|
||||
}
|
||||
|
||||
std::size_t TriFace::getEdge2Id () const
|
||||
{
|
||||
return mEdge2->getId();
|
||||
}
|
||||
|
||||
std::vector<std::size_t> TriFace::getEdgeIds() const
|
||||
{
|
||||
return {mEdge0->getId(), mEdge1->getId(), mEdge2->getId()};
|
||||
}
|
||||
|
||||
void TriFace::associateWidthEdges()
|
||||
{
|
||||
mEdge0->associateFace(mId);
|
||||
mEdge1->associateFace(mId);
|
||||
mEdge2->associateFace(mId);
|
||||
}
|
||||
|
||||
std::vector<Point> TriFace::getNodeLocations(Orientation orientation) const
|
||||
{
|
||||
if (orientation != getOrientation())
|
||||
{
|
||||
return { mEdge0->getNode0()->getPoint(), mEdge0->getNode1()->getPoint(), mEdge1->getNode1()->getPoint() };
|
||||
}
|
||||
else
|
||||
{
|
||||
return { mEdge0->getNode0()->getPoint(), mEdge1->getNode1()->getPoint(), mEdge0->getNode1()->getPoint() };
|
||||
}
|
||||
}
|
||||
|
||||
Vector TriFace::getNormal() const
|
||||
{
|
||||
auto v0 = mEdge0->getNode0()->getPoint().getDelta(mEdge0->getNode1()->getPoint());
|
||||
auto v1 = mEdge0->getNode0()->getPoint().getDelta(mEdge1->getNode1()->getPoint());
|
||||
return v0.crossProduct(v1).getNormalized();
|
||||
}
|
||||
|
||||
AbstractFace::Orientation TriFace::getOrientation() const
|
||||
{
|
||||
Vector z_norm(0, 0, 1);
|
||||
if (z_norm.dotProduct(getNormal()) < 0.0)
|
||||
{
|
||||
return Orientation::CW;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Orientation::CCW;
|
||||
}
|
||||
}
|
40
src/rendering/mesh/TriFace.h
Normal file
40
src/rendering/mesh/TriFace.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractFace.h"
|
||||
#include "Vector.h"
|
||||
|
||||
class Edge;
|
||||
|
||||
class TriFace : public AbstractFace
|
||||
{
|
||||
public:
|
||||
TriFace(Edge* edge0, Edge* edge1, Edge* edge2, std::size_t id=0);
|
||||
|
||||
~TriFace();
|
||||
|
||||
static std::unique_ptr<TriFace> Create(Edge* edge0, Edge* edge1, Edge* edge2, std::size_t id=0);
|
||||
|
||||
void associateWidthEdges() override;
|
||||
|
||||
std::vector<std::size_t> getNodeIds() const override;
|
||||
|
||||
std::size_t getNumNodes() const override;
|
||||
|
||||
void replaceEdge(Edge* original, Edge* replacement);
|
||||
|
||||
std::size_t getEdge0Id () const;
|
||||
std::size_t getEdge1Id () const;
|
||||
std::size_t getEdge2Id () const;
|
||||
std::vector<std::size_t> getEdgeIds() const override;
|
||||
|
||||
std::vector<Point> getNodeLocations(Orientation orientation = Orientation::CCW) const override;
|
||||
|
||||
Vector getNormal() const;
|
||||
|
||||
AbstractFace::Orientation getOrientation() const;
|
||||
|
||||
private:
|
||||
Edge* mEdge0{nullptr};
|
||||
Edge* mEdge1{nullptr};
|
||||
Edge* mEdge2{nullptr};
|
||||
};
|
46
src/rendering/mesh/TriMesh.cpp
Normal file
46
src/rendering/mesh/TriMesh.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include "TriMesh.h"
|
||||
|
||||
#include "Edge.h"
|
||||
#include "TriFace.h"
|
||||
|
||||
TriMesh::~TriMesh()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AbstractMesh::MeshType TriMesh::getType() const
|
||||
{
|
||||
return AbstractMesh::MeshType::TRI;
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractMesh> TriMesh::copy() const
|
||||
{
|
||||
VecNodes nodes(mNodes.size());
|
||||
unsigned count = 0;
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
nodes[count] = std::make_unique<Node>(node->getPoint());
|
||||
count++;
|
||||
}
|
||||
|
||||
VecEdges edges(mEdges.size());
|
||||
count = 0;
|
||||
for (auto& edge : mEdges)
|
||||
{
|
||||
edges[count] = std::make_unique<Edge>(nodes[edge->getNode0Id()].get(), nodes[edge->getNode0Id()].get());
|
||||
count++;
|
||||
}
|
||||
|
||||
VecFaces faces(mFaces.size());
|
||||
count = 0;
|
||||
for (auto& face : mFaces)
|
||||
{
|
||||
auto ids = face->getEdgeIds();
|
||||
faces[count] = std::make_unique<TriFace>(edges[ids[0]].get(), edges[ids[1]].get(), edges[ids[2]].get());
|
||||
count++;
|
||||
}
|
||||
|
||||
auto mesh = std::make_unique<TriMesh>();
|
||||
mesh->populate(nodes, edges, faces);
|
||||
return mesh;
|
||||
}
|
15
src/rendering/mesh/TriMesh.h
Normal file
15
src/rendering/mesh/TriMesh.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "FaceMesh.h"
|
||||
|
||||
class TriMesh : public FaceMesh
|
||||
{
|
||||
public:
|
||||
TriMesh() = default;
|
||||
|
||||
~TriMesh();
|
||||
|
||||
std::unique_ptr<AbstractMesh> copy() const override;
|
||||
|
||||
MeshType getType() const;
|
||||
};
|
46
src/rendering/visual_elements/CMakeLists.txt
Normal file
46
src/rendering/visual_elements/CMakeLists.txt
Normal file
|
@ -0,0 +1,46 @@
|
|||
set(MODULE_NAME visual_elements)
|
||||
|
||||
list(APPEND visual_elements_LIB_INCLUDES
|
||||
basic_shapes/RectangleNode.h
|
||||
basic_shapes/RectangleNode.cpp
|
||||
basic_shapes/CircleNode.h
|
||||
basic_shapes/CircleNode.cpp
|
||||
basic_shapes/LineNode.h
|
||||
basic_shapes/LineNode.cpp
|
||||
scene/Scene.h
|
||||
scene/Scene.cpp
|
||||
scene/SceneInfo.h
|
||||
scene/SceneModel.h
|
||||
scene/SceneModel.cpp
|
||||
scene/SceneItem.h
|
||||
scene/SceneItem.cpp
|
||||
scene/SceneText.h
|
||||
scene/SceneText.cpp
|
||||
nodes/MaterialNode.h
|
||||
nodes/MaterialNode.cpp
|
||||
nodes/MeshNode.h
|
||||
nodes/MeshNode.cpp
|
||||
nodes/TextNode.h
|
||||
nodes/TextNode.cpp
|
||||
nodes/GridNode.h
|
||||
nodes/GridNode.cpp
|
||||
nodes/GeometryNode.h
|
||||
nodes/GeometryNode.cpp
|
||||
nodes/AbstractVisualNode.h
|
||||
nodes/AbstractVisualNode.cpp
|
||||
Texture.cpp
|
||||
)
|
||||
|
||||
add_library(${MODULE_NAME} SHARED ${visual_elements_LIB_INCLUDES})
|
||||
|
||||
target_include_directories(${MODULE_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/basic_shapes
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/scene
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/nodes
|
||||
)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} PUBLIC core geometry fonts mesh image)
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/rendering)
|
||||
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
29
src/rendering/visual_elements/TextData.h
Normal file
29
src/rendering/visual_elements/TextData.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "Color.h"
|
||||
#include "FontItem.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class TextData
|
||||
{
|
||||
public:
|
||||
bool operator==(const TextData& rhs) const
|
||||
{
|
||||
return (mContent == rhs.mContent)
|
||||
&& (mLines == rhs.mLines)
|
||||
&& (mFont == rhs.mFont);
|
||||
}
|
||||
|
||||
bool operator!=(const TextData& rhs) const
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
TextData() = default;
|
||||
std::string mContent;
|
||||
std::vector<std::string> mLines;
|
||||
FontItem mFont;
|
||||
};
|
0
src/rendering/visual_elements/Texture.cpp
Normal file
0
src/rendering/visual_elements/Texture.cpp
Normal file
7
src/rendering/visual_elements/Texture.h
Normal file
7
src/rendering/visual_elements/Texture.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
class Texture
|
||||
{
|
||||
public:
|
||||
Texture() = default;
|
||||
};
|
64
src/rendering/visual_elements/basic_shapes/CircleNode.cpp
Normal file
64
src/rendering/visual_elements/basic_shapes/CircleNode.cpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
#include "CircleNode.h"
|
||||
|
||||
#include "SceneModel.h"
|
||||
#include "AbstractMesh.h"
|
||||
#include "MeshPrimitives.h"
|
||||
#include "SceneInfo.h"
|
||||
#include "Circle.h"
|
||||
|
||||
CircleNode::CircleNode(const Point& location, double radius)
|
||||
: GeometryNode(location),
|
||||
mRadius(radius)
|
||||
{
|
||||
mMinorRadius = mRadius;
|
||||
}
|
||||
|
||||
CircleNode::Type CircleNode::getType()
|
||||
{
|
||||
return Type::Circle;
|
||||
}
|
||||
|
||||
double CircleNode::getRadius() const
|
||||
{
|
||||
return mRadius;
|
||||
}
|
||||
|
||||
void CircleNode::setRadius(double radius)
|
||||
{
|
||||
if (mRadius != radius)
|
||||
{
|
||||
mRadius = radius;
|
||||
mTransformIsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CircleNode::setMinorRadius(double radius)
|
||||
{
|
||||
if (mMinorRadius != radius)
|
||||
{
|
||||
mMinorRadius = radius;
|
||||
mTransformIsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CircleNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
|
||||
{
|
||||
if (sceneInfo->mSupportsGeometryPrimitives)
|
||||
{
|
||||
double unit_circle_radius = 0.5;
|
||||
auto circle = std::make_unique<Circle>(Point{ 0, 0 }, unit_circle_radius);
|
||||
circle->setMinorRadius(unit_circle_radius*mMinorRadius/mRadius);
|
||||
mBackgroundItem = std::make_unique<SceneModel>(std::move(circle));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto mesh = MeshPrimitives::buildCircleAsTriMesh();
|
||||
mBackgroundItem = std::make_unique<SceneModel>(std::move(mesh));
|
||||
}
|
||||
mBackgroundItem->setName(mName + "_Model");
|
||||
}
|
||||
|
||||
void CircleNode::updateTransform()
|
||||
{
|
||||
mBackgroundItem->updateTransform({ mLocation, 2 * mRadius, 2 * mRadius });
|
||||
}
|
21
src/rendering/visual_elements/basic_shapes/CircleNode.h
Normal file
21
src/rendering/visual_elements/basic_shapes/CircleNode.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "GeometryNode.h"
|
||||
|
||||
class CircleNode : public GeometryNode
|
||||
{
|
||||
public:
|
||||
CircleNode(const Point& location, double radius);
|
||||
|
||||
Type getType() override;
|
||||
double getRadius() const;
|
||||
|
||||
void setMinorRadius(double radius);
|
||||
void setRadius(double radius);
|
||||
private:
|
||||
void createOrUpdateGeometry(SceneInfo* sceneInfo) override;
|
||||
void updateTransform() override;
|
||||
|
||||
double mRadius{1.0};
|
||||
double mMinorRadius{ 1.0 };
|
||||
};
|
28
src/rendering/visual_elements/basic_shapes/LineNode.cpp
Normal file
28
src/rendering/visual_elements/basic_shapes/LineNode.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include "LineNode.h"
|
||||
|
||||
LineNode::LineNode(const Point& location, const std::vector<Point>& points)
|
||||
: GeometryNode(location),
|
||||
mPoints(points)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LineNode::Type LineNode::getType()
|
||||
{
|
||||
return Type::Line;
|
||||
}
|
||||
|
||||
void LineNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
|
||||
{
|
||||
if (sceneInfo->mSupportsGeometryPrimitives)
|
||||
{
|
||||
auto line = std::make_unique<Line>(Point{ 0, 0 }, mPoints);
|
||||
mBackgroundItem = std::make_unique<SceneModel>(std::move(line));
|
||||
}
|
||||
mBackgroundItem->setName(mName + "_Model");
|
||||
}
|
||||
|
||||
void LineNode::updateTransform()
|
||||
{
|
||||
mBackgroundItem->updateTransform({ mLocation });
|
||||
}
|
23
src/rendering/visual_elements/basic_shapes/LineNode.h
Normal file
23
src/rendering/visual_elements/basic_shapes/LineNode.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "GeometryNode.h"
|
||||
#include "SceneInfo.h"
|
||||
|
||||
#include "Line.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class LineNode : public GeometryNode
|
||||
{
|
||||
public:
|
||||
LineNode(const Point& location, const std::vector<Point>& points);
|
||||
|
||||
Type getType();
|
||||
|
||||
private:
|
||||
void createOrUpdateGeometry(SceneInfo* sceneInfo) override;
|
||||
|
||||
void updateTransform() override;
|
||||
|
||||
std::vector<Point> mPoints;
|
||||
};
|
73
src/rendering/visual_elements/basic_shapes/RectangleNode.cpp
Normal file
73
src/rendering/visual_elements/basic_shapes/RectangleNode.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
#include "RectangleNode.h"
|
||||
|
||||
#include "Rectangle.h"
|
||||
|
||||
#include "MeshPrimitives.h"
|
||||
#include "SceneInfo.h"
|
||||
|
||||
RectangleNode::RectangleNode(const Point& loc, double width, double height)
|
||||
: GeometryNode(loc),
|
||||
mWidth(width),
|
||||
mHeight(height)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<RectangleNode> RectangleNode::Create(const Point& loc, double width, double height)
|
||||
{
|
||||
return std::make_unique<RectangleNode>(loc, width, height);
|
||||
}
|
||||
|
||||
GeometryNode::Type RectangleNode::getType()
|
||||
{
|
||||
return GeometryNode::Type::Rectangle;
|
||||
}
|
||||
|
||||
double RectangleNode::getWidth() const
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
double RectangleNode::getHeight() const
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
void RectangleNode::setWidth(double width)
|
||||
{
|
||||
if (mWidth != width)
|
||||
{
|
||||
mTransformIsDirty = true;
|
||||
mWidth = width;
|
||||
}
|
||||
}
|
||||
|
||||
void RectangleNode::setHeight(double height)
|
||||
{
|
||||
if (mHeight != height)
|
||||
{
|
||||
mTransformIsDirty = true;
|
||||
mHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
void RectangleNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
|
||||
{
|
||||
if (sceneInfo->mSupportsGeometryPrimitives)
|
||||
{
|
||||
auto rect = std::make_unique<ntk::Rectangle>(Point{ 0, 0 }, 1, 1);
|
||||
mBackgroundItem = std::make_unique<SceneModel>(std::move(rect));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto mesh = MeshPrimitives::buildRectangleAsTriMesh();
|
||||
mBackgroundItem = std::make_unique<SceneModel>(std::move(mesh));
|
||||
|
||||
}
|
||||
mBackgroundItem->setName(mName + "_Model");
|
||||
}
|
||||
|
||||
void RectangleNode::updateTransform()
|
||||
{
|
||||
mBackgroundItem->updateTransform({ mLocation, mWidth, mHeight });
|
||||
}
|
30
src/rendering/visual_elements/basic_shapes/RectangleNode.h
Normal file
30
src/rendering/visual_elements/basic_shapes/RectangleNode.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "GeometryNode.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class RectangleNode : public GeometryNode
|
||||
{
|
||||
public:
|
||||
RectangleNode(const Point& loc, double width, double height);
|
||||
static std::unique_ptr<RectangleNode> Create(const Point& loc, double width, double height);
|
||||
|
||||
GeometryNode::Type getType() override;
|
||||
|
||||
double getWidth() const;
|
||||
double getHeight() const;
|
||||
|
||||
void setWidth(double width);
|
||||
void setHeight(double height);
|
||||
private:
|
||||
void createOrUpdateGeometry(SceneInfo* sceneInfo) override;
|
||||
void updateTransform() override;
|
||||
|
||||
double mWidth{1};
|
||||
double mHeight{1};
|
||||
};
|
||||
|
||||
using RectangleNodePtr = std::unique_ptr<RectangleNode>;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue