Squashed 'deps/nostalgia/' changes from 5433fd9b..e3675759
e3675759 [olympic/studio] Fix NewMenu not to overwrite existing files or create a file without name 2bc2003c [nostalgia/core/studio] Add key shortcuts for switching Palette pages b31062e6 [nostalgia] Update liccor file e4285bd4 [nostalgia/studio] Tweak background color of TileSheet editor a76638cc [olympic/studio] Make Project::romFS return a reference git-subtree-dir: deps/nostalgia git-subtree-split: e367575974a65633d4ad1e1335b2f24d8d0c2649
This commit is contained in:
		@@ -2,4 +2,4 @@
 | 
			
		||||
source:
 | 
			
		||||
- src
 | 
			
		||||
copyright_notice: |-
 | 
			
		||||
  Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
 | 
			
		||||
  Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,25 @@ PaletteEditorImGui::PaletteEditorImGui(turbine::Context &ctx, ox::CRStringView p
 | 
			
		||||
	undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PaletteEditorImGui::keyStateChanged(turbine::Key key, bool down) {
 | 
			
		||||
	if (!down) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if (key >= turbine::Key::Num_1 && key <= turbine::Key::Num_9) {
 | 
			
		||||
		if (turbine::buttonDown(m_ctx, turbine::Key::Mod_Alt)) {
 | 
			
		||||
			m_page = ox::min<std::size_t>(
 | 
			
		||||
					  static_cast<uint32_t>(key - turbine::Key::Num_1), m_pal.pages.size() - 1);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (key == turbine::Key::Num_0) {
 | 
			
		||||
		if (turbine::buttonDown(m_ctx, turbine::Key::Mod_Alt)) {
 | 
			
		||||
			m_selectedColorRow =
 | 
			
		||||
					ox::min<std::size_t>(
 | 
			
		||||
					  static_cast<uint32_t>(key - turbine::Key::Num_1 + 9), m_pal.pages.size() - 1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PaletteEditorImGui::draw(turbine::Context&) noexcept {
 | 
			
		||||
	auto const paneSize = ImGui::GetContentRegionAvail();
 | 
			
		||||
	{
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,8 @@ class PaletteEditorImGui: public studio::Editor {
 | 
			
		||||
	public:
 | 
			
		||||
		PaletteEditorImGui(turbine::Context &ctx, ox::CRStringView path);
 | 
			
		||||
 | 
			
		||||
		void keyStateChanged(turbine::Key key, bool down) override;
 | 
			
		||||
 | 
			
		||||
		void draw(turbine::Context&) noexcept final;
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
 
 | 
			
		||||
@@ -112,8 +112,8 @@ void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
 | 
			
		||||
	}
 | 
			
		||||
	auto const popupOpen = m_subsheetEditor.isOpen() && m_exportMenu.isOpen();
 | 
			
		||||
	auto const pal = m_model.pal();
 | 
			
		||||
	if (pal && !popupOpen) {
 | 
			
		||||
		const auto colorCnt = pal->pages[m_palPage].size();
 | 
			
		||||
	if (!popupOpen) {
 | 
			
		||||
		const auto colorCnt = pal.pages[m_model.palettePage()].size();
 | 
			
		||||
		if (key == turbine::Key::Alpha_D) {
 | 
			
		||||
			m_tool = Tool::Draw;
 | 
			
		||||
			setCopyEnabled(false);
 | 
			
		||||
@@ -131,15 +131,28 @@ void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
 | 
			
		||||
			setCutEnabled(false);
 | 
			
		||||
			setPasteEnabled(false);
 | 
			
		||||
			m_model.clearSelection();
 | 
			
		||||
		} else if (key >= turbine::Key::Num_1 && key <= turbine::Key::Num_9 && key <= turbine::Key::Num_0 + colorCnt) {
 | 
			
		||||
		} else if (key >= turbine::Key::Num_1 && key <= turbine::Key::Num_9) {
 | 
			
		||||
			if (turbine::buttonDown(m_ctx, turbine::Key::Mod_Alt)) {
 | 
			
		||||
				auto const idx = ox::min<std::size_t>(
 | 
			
		||||
						static_cast<uint32_t>(key - turbine::Key::Num_1), m_model.pal().pages.size() - 1);
 | 
			
		||||
				m_model.setPalettePage(idx);
 | 
			
		||||
			} else if (key <= turbine::Key::Num_0 + colorCnt) {
 | 
			
		||||
				auto idx = ox::min<std::size_t>(static_cast<uint32_t>(key - turbine::Key::Num_1), colorCnt - 1);
 | 
			
		||||
				m_view.setPalIdx(idx);
 | 
			
		||||
		} else if (key == turbine::Key::Num_0 && colorCnt >= 10) {
 | 
			
		||||
			auto idx = ox::min<std::size_t>(static_cast<uint32_t>(key - turbine::Key::Num_1 + 9), colorCnt - 1);
 | 
			
		||||
			}
 | 
			
		||||
		} else if (key == turbine::Key::Num_0) {
 | 
			
		||||
			if (turbine::buttonDown(m_ctx, turbine::Key::Mod_Alt)) {
 | 
			
		||||
				auto const idx = ox::min<std::size_t>(
 | 
			
		||||
						static_cast<uint32_t>(key - turbine::Key::Num_1 + 9), m_model.pal().pages.size() - 1);
 | 
			
		||||
				m_model.setPalettePage(idx);
 | 
			
		||||
			} else if (colorCnt >= 10) {
 | 
			
		||||
				auto idx = ox::min<std::size_t>(
 | 
			
		||||
						static_cast<uint32_t>(key - turbine::Key::Num_1 + 9), colorCnt - 1);
 | 
			
		||||
				m_view.setPalIdx(idx);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TileSheetEditorImGui::draw(turbine::Context&) noexcept {
 | 
			
		||||
	const auto paneSize = ImGui::GetContentRegionAvail();
 | 
			
		||||
@@ -306,8 +319,8 @@ ox::Error TileSheetEditorImGui::exportSubhseetToPng(int scale) noexcept {
 | 
			
		||||
	auto const err = toPngFile(
 | 
			
		||||
			path,
 | 
			
		||||
			std::move(pixels),
 | 
			
		||||
			*pal,
 | 
			
		||||
			m_palPage,
 | 
			
		||||
			pal,
 | 
			
		||||
			m_model.palettePage(),
 | 
			
		||||
			static_cast<unsigned>(width * scale),
 | 
			
		||||
			static_cast<unsigned>(height * scale));
 | 
			
		||||
	if (err) {
 | 
			
		||||
@@ -402,19 +415,18 @@ void TileSheetEditorImGui::drawPaletteSelector() noexcept {
 | 
			
		||||
		}
 | 
			
		||||
		ImGui::EndCombo();
 | 
			
		||||
	}
 | 
			
		||||
	auto const pages = m_model.pal()->pages.size();
 | 
			
		||||
	auto const pages = m_model.pal().pages.size();
 | 
			
		||||
	if (pages > 1) {
 | 
			
		||||
		ImGui::Indent(20);
 | 
			
		||||
		ox::Array<char, 10> numStr;
 | 
			
		||||
		ox_itoa(m_palPage + 1, numStr.data());
 | 
			
		||||
		ox_itoa(m_model.palettePage() + 1, numStr.data());
 | 
			
		||||
		ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - comboWidthSub);
 | 
			
		||||
		if (ImGui::BeginCombo("Page", numStr.data(), 0)) {
 | 
			
		||||
			for (auto n = 0u; n < pages; ++n) {
 | 
			
		||||
				const auto selected = (m_palPage == n);
 | 
			
		||||
				const auto selected = (m_model.palettePage() == n);
 | 
			
		||||
				ox_itoa(n + 1, numStr.data());
 | 
			
		||||
				if (ImGui::Selectable(numStr.data(), selected) && m_palPage != n) {
 | 
			
		||||
					m_palPage = n;
 | 
			
		||||
					m_model.setPalettePage(m_palPage);
 | 
			
		||||
				if (ImGui::Selectable(numStr.data(), selected) && m_model.palettePage() != n) {
 | 
			
		||||
					m_model.setPalettePage(n);
 | 
			
		||||
				}
 | 
			
		||||
				if (selected) {
 | 
			
		||||
					ImGui::SetItemDefaultFocus();
 | 
			
		||||
@@ -430,8 +442,9 @@ void TileSheetEditorImGui::drawPaletteSelector() noexcept {
 | 
			
		||||
		ImGui::TableSetupColumn("", 0, 0.22f);
 | 
			
		||||
		ImGui::TableSetupColumn("Color16", 0, 3);
 | 
			
		||||
		ImGui::TableHeadersRow();
 | 
			
		||||
		if (auto pal = m_view.pal()) {
 | 
			
		||||
			for (auto i = 0u; auto c: pal->pages[m_palPage]) {
 | 
			
		||||
		{
 | 
			
		||||
			auto const&pal = m_model.pal();
 | 
			
		||||
			for (auto i = 0u; auto c: pal.pages[m_model.palettePage()]) {
 | 
			
		||||
				ImGui::PushID(static_cast<int>(i));
 | 
			
		||||
				// Column: color idx
 | 
			
		||||
				ImGui::TableNextColumn();
 | 
			
		||||
@@ -473,7 +486,7 @@ ox::Error TileSheetEditorImGui::setPaletteSelection() noexcept {
 | 
			
		||||
	return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::Error TileSheetEditorImGui::markUnsavedChanges(const studio::UndoCommand*) noexcept {
 | 
			
		||||
ox::Error TileSheetEditorImGui::markUnsavedChanges(studio::UndoCommand const*) noexcept {
 | 
			
		||||
	setUnsavedChanges(true);
 | 
			
		||||
	return {};
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,6 @@ class TileSheetEditorImGui: public studio::Editor {
 | 
			
		||||
		float m_palViewWidth = 300;
 | 
			
		||||
		ox::Vec2 m_prevMouseDownPos;
 | 
			
		||||
		Tool m_tool = Tool::Draw;
 | 
			
		||||
		size_t m_palPage = 0;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		TileSheetEditorImGui(turbine::Context &ctx, ox::CRStringView path);
 | 
			
		||||
@@ -111,7 +110,7 @@ class TileSheetEditorImGui: public studio::Editor {
 | 
			
		||||
 | 
			
		||||
	// slots
 | 
			
		||||
	private:
 | 
			
		||||
		ox::Error markUnsavedChanges(const studio::UndoCommand*) noexcept;
 | 
			
		||||
		ox::Error markUnsavedChanges(studio::UndoCommand const*) noexcept;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -228,6 +228,7 @@ ox::Error TileSheetEditorModel::markUpdatedCmdId(studio::UndoCommand const*cmd)
 | 
			
		||||
	const auto cmdId = cmd->commandId();
 | 
			
		||||
	if (static_cast<CommandId>(cmdId) == CommandId::PaletteChange) {
 | 
			
		||||
		oxReturnError(readObj<Palette>(keelCtx(m_ctx), m_img.defaultPalette).moveTo(m_pal));
 | 
			
		||||
		m_palettePage = ox::min<size_t>(m_pal->pages.size(), 0);
 | 
			
		||||
		paletteChanged.emit();
 | 
			
		||||
	}
 | 
			
		||||
	auto tsCmd = dynamic_cast<const TileSheetCommand*>(cmd);
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
 | 
			
		||||
		constexpr TileSheet &img() noexcept;
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		constexpr Palette const*pal() const noexcept;
 | 
			
		||||
		constexpr Palette const&pal() const noexcept;
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		ox::StringView palPath() const noexcept;
 | 
			
		||||
@@ -139,11 +139,11 @@ constexpr TileSheet &TileSheetEditorModel::img() noexcept {
 | 
			
		||||
	return m_img;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr Palette const*TileSheetEditorModel::pal() const noexcept {
 | 
			
		||||
constexpr Palette const&TileSheetEditorModel::pal() const noexcept {
 | 
			
		||||
	if (m_pal) {
 | 
			
		||||
		return m_pal.get();
 | 
			
		||||
		return *m_pal;
 | 
			
		||||
	}
 | 
			
		||||
	return &s_defaultPalette;
 | 
			
		||||
	return s_defaultPalette;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr studio::UndoStack *TileSheetEditorModel::undoStack() noexcept {
 | 
			
		||||
 
 | 
			
		||||
@@ -21,8 +21,7 @@ TileSheetEditorView::TileSheetEditorView(turbine::Context &ctx, ox::StringView p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TileSheetEditorView::draw() noexcept {
 | 
			
		||||
	constexpr Color32 bgColor = 0x717d7e;
 | 
			
		||||
	glClearColor(redf(bgColor), greenf(bgColor), bluef(bgColor), 1.f);
 | 
			
		||||
	glClearColor(0.37f, 0.37f, 0.37f, 1.f);
 | 
			
		||||
	glClear(GL_COLOR_BUFFER_BIT);
 | 
			
		||||
	m_pixelsDrawer.draw(updated(), m_scrollOffset);
 | 
			
		||||
	m_pixelGridDrawer.draw(updated(), m_scrollOffset);
 | 
			
		||||
 
 | 
			
		||||
@@ -80,9 +80,6 @@ class TileSheetEditorView: public ox::SignalHandler {
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		constexpr TileSheet &img() noexcept;
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		constexpr const Palette *pal() const noexcept;
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		constexpr auto &model() noexcept {
 | 
			
		||||
			return m_model;
 | 
			
		||||
@@ -126,8 +123,4 @@ constexpr TileSheet &TileSheetEditorView::img() noexcept {
 | 
			
		||||
	return m_model.img();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr const Palette *TileSheetEditorView::pal() const noexcept {
 | 
			
		||||
	return m_model.pal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,8 @@ void TileSheetPixels::setPixelSizeMod(float sm) noexcept {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::Error TileSheetPixels::buildShader() noexcept {
 | 
			
		||||
	const auto Vshad = ox::sfmt(VShad, gl::GlslVersion);
 | 
			
		||||
	const auto Fshad = ox::sfmt(FShad, gl::GlslVersion);
 | 
			
		||||
	auto const Vshad = ox::sfmt(VShad, gl::GlslVersion);
 | 
			
		||||
	auto const Fshad = ox::sfmt(FShad, gl::GlslVersion);
 | 
			
		||||
	return glutils::buildShaderProgram(Vshad, Fshad).moveTo(m_shader);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -28,7 +28,7 @@ void TileSheetPixels::draw(bool update, ox::Vec2 const&scroll) noexcept {
 | 
			
		||||
	if (update) {
 | 
			
		||||
		glutils::sendVbo(m_bufferSet);
 | 
			
		||||
	}
 | 
			
		||||
	const auto uniformScroll = glGetUniformLocation(m_shader, "vScroll");
 | 
			
		||||
	auto const uniformScroll = glGetUniformLocation(m_shader, "vScroll");
 | 
			
		||||
	glUniform2f(uniformScroll, scroll.x, scroll.y);
 | 
			
		||||
	glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_bufferSet.elements.size()), GL_UNSIGNED_INT, nullptr);
 | 
			
		||||
	glBindVertexArray(0);
 | 
			
		||||
@@ -41,10 +41,10 @@ void TileSheetPixels::initBufferSet(ox::Vec2 const&paneSize) noexcept {
 | 
			
		||||
	m_bufferSet.ebo = glutils::generateBuffer();
 | 
			
		||||
	update(paneSize);
 | 
			
		||||
	// vbo layout
 | 
			
		||||
	const auto posAttr = static_cast<GLuint>(glGetAttribLocation(m_shader, "vPosition"));
 | 
			
		||||
	auto const posAttr = static_cast<GLuint>(glGetAttribLocation(m_shader, "vPosition"));
 | 
			
		||||
	glEnableVertexAttribArray(posAttr);
 | 
			
		||||
	glVertexAttribPointer(posAttr, 2, GL_FLOAT, GL_FALSE, VertexVboRowLength * sizeof(float), nullptr);
 | 
			
		||||
	const auto colorAttr = static_cast<GLuint>(glGetAttribLocation(m_shader, "vColor"));
 | 
			
		||||
	auto const colorAttr = static_cast<GLuint>(glGetAttribLocation(m_shader, "vColor"));
 | 
			
		||||
	glEnableVertexAttribArray(colorAttr);
 | 
			
		||||
	glVertexAttribPointer(colorAttr, 3, GL_FLOAT, GL_FALSE, VertexVboRowLength * sizeof(float),
 | 
			
		||||
	                      std::bit_cast<void*>(uintptr_t{2 * sizeof(float)}));
 | 
			
		||||
@@ -58,9 +58,9 @@ void TileSheetPixels::update(ox::Vec2 const&paneSize) noexcept {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::Vec2 TileSheetPixels::pixelSize(ox::Vec2 const&paneSize) const noexcept {
 | 
			
		||||
	const auto [sw, sh] = paneSize;
 | 
			
		||||
	auto const [sw, sh] = paneSize;
 | 
			
		||||
	constexpr float ymod = 0.35f / 10.0f;
 | 
			
		||||
	const auto xmod = ymod * sh / sw;
 | 
			
		||||
	auto const xmod = ymod * sh / sw;
 | 
			
		||||
	return {xmod * m_pixelSizeMod, ymod * m_pixelSizeMod};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -71,21 +71,21 @@ void TileSheetPixels::setPixelBufferObject(
 | 
			
		||||
		Color16 color,
 | 
			
		||||
		float *vbo,
 | 
			
		||||
		GLuint *ebo) const noexcept {
 | 
			
		||||
	const auto [xmod, ymod] = pixelSize(paneSize);
 | 
			
		||||
	auto const [xmod, ymod] = pixelSize(paneSize);
 | 
			
		||||
	x *= xmod;
 | 
			
		||||
	y *= -ymod;
 | 
			
		||||
	x -= 1.0f;
 | 
			
		||||
	y += 1.0f - ymod;
 | 
			
		||||
	const auto r = redf(color), g = greenf(color), b = bluef(color);
 | 
			
		||||
	auto const r = redf(color), g = greenf(color), b = bluef(color);
 | 
			
		||||
	// don't worry, these memcpys gets optimized to something much more ideal
 | 
			
		||||
	const ox::Array<float, VertexVboLength> vertices = {
 | 
			
		||||
	ox::Array<float, VertexVboLength> const vertices = {
 | 
			
		||||
			       x,        y, r, g, b, // bottom left
 | 
			
		||||
			x + xmod,        y, r, g, b, // bottom right
 | 
			
		||||
			x + xmod, y + ymod, r, g, b, // top right
 | 
			
		||||
			       x, y + ymod, r, g, b, // top left
 | 
			
		||||
	};
 | 
			
		||||
	memcpy(vbo, vertices.data(), sizeof(vertices));
 | 
			
		||||
	const ox::Array<GLuint, VertexEboLength> elms = {
 | 
			
		||||
	ox::Array<GLuint, VertexEboLength> const elms = {
 | 
			
		||||
			vertexRow + 0, vertexRow + 1, vertexRow + 2,
 | 
			
		||||
			vertexRow + 2, vertexRow + 3, vertexRow + 0,
 | 
			
		||||
	};
 | 
			
		||||
@@ -94,21 +94,21 @@ void TileSheetPixels::setPixelBufferObject(
 | 
			
		||||
 | 
			
		||||
void TileSheetPixels::setBufferObjects(ox::Vec2 const&paneSize) noexcept {
 | 
			
		||||
	// set buffer lengths
 | 
			
		||||
	const auto subSheet = m_model.activeSubSheet();
 | 
			
		||||
	const auto pal = m_model.pal();
 | 
			
		||||
	const auto width = subSheet->columns * TileWidth;
 | 
			
		||||
	const auto height = subSheet->rows * TileHeight;
 | 
			
		||||
	const auto pixels = static_cast<unsigned>(width * height);
 | 
			
		||||
	auto const subSheet = m_model.activeSubSheet();
 | 
			
		||||
	auto const&pal = m_model.pal();
 | 
			
		||||
	auto const width = subSheet->columns * TileWidth;
 | 
			
		||||
	auto const height = subSheet->rows * TileHeight;
 | 
			
		||||
	auto const pixels = static_cast<size_t>(width) * static_cast<size_t>(height);
 | 
			
		||||
	m_bufferSet.vertices.resize(pixels * VertexVboLength);
 | 
			
		||||
	m_bufferSet.elements.resize(pixels * VertexEboLength);
 | 
			
		||||
	// set pixels
 | 
			
		||||
	walkPixels(*subSheet, m_model.img().bpp, [&](std::size_t i, uint8_t p) {
 | 
			
		||||
		auto color = core::color(*pal, m_model.palettePage(), p);
 | 
			
		||||
		const auto pt = idxToPt(static_cast<int>(i), subSheet->columns);
 | 
			
		||||
		const auto fx = static_cast<float>(pt.x);
 | 
			
		||||
		const auto fy = static_cast<float>(pt.y);
 | 
			
		||||
		const auto vbo = &m_bufferSet.vertices[i * VertexVboLength];
 | 
			
		||||
		const auto ebo = &m_bufferSet.elements[i * VertexEboLength];
 | 
			
		||||
		auto color = core::color(pal, m_model.palettePage(), p);
 | 
			
		||||
		auto const pt = idxToPt(static_cast<int>(i), subSheet->columns);
 | 
			
		||||
		auto const fx = static_cast<float>(pt.x);
 | 
			
		||||
		auto const fy = static_cast<float>(pt.y);
 | 
			
		||||
		auto const vbo = &m_bufferSet.vertices[i * VertexVboLength];
 | 
			
		||||
		auto const ebo = &m_bufferSet.elements[i * VertexEboLength];
 | 
			
		||||
		if (i * VertexVboLength + VertexVboLength > m_bufferSet.vertices.size()) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
@@ -116,9 +116,9 @@ void TileSheetPixels::setBufferObjects(ox::Vec2 const&paneSize) noexcept {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (m_model.pixelSelected(i)) {
 | 
			
		||||
			const auto r = red16(color) / 2;
 | 
			
		||||
			const auto g = (green16(color) + 20) / 2;
 | 
			
		||||
			const auto b = (blue16(color) + 31) / 2;
 | 
			
		||||
			auto const r = red16(color) / 2;
 | 
			
		||||
			auto const g = (green16(color) + 20) / 2;
 | 
			
		||||
			auto const b = (blue16(color) + 31) / 2;
 | 
			
		||||
			color = color16(r, g, b);
 | 
			
		||||
		}
 | 
			
		||||
		setPixelBufferObject(paneSize, static_cast<unsigned>(i * VertexVboRows), fx, fy, color, vbo, ebo);
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ class TileSheetPixels {
 | 
			
		||||
		float m_pixelSizeMod = 1;
 | 
			
		||||
		glutils::GLProgram m_shader;
 | 
			
		||||
		glutils::BufferSet m_bufferSet;
 | 
			
		||||
		const class TileSheetEditorModel &m_model;
 | 
			
		||||
		class TileSheetEditorModel const&m_model;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		explicit TileSheetPixels(class TileSheetEditorModel &model) noexcept;
 | 
			
		||||
@@ -62,7 +62,14 @@ class TileSheetPixels {
 | 
			
		||||
		ox::Vec2 pixelSize(ox::Vec2 const&paneSize) const noexcept;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void setPixelBufferObject(ox::Vec2 const&paneS, unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) const noexcept;
 | 
			
		||||
		void setPixelBufferObject(
 | 
			
		||||
				ox::Vec2 const&paneS,
 | 
			
		||||
				unsigned vertexRow,
 | 
			
		||||
				float x,
 | 
			
		||||
				float y,
 | 
			
		||||
				Color16 color,
 | 
			
		||||
				float *vbo,
 | 
			
		||||
				GLuint *ebo) const noexcept;
 | 
			
		||||
 | 
			
		||||
		void setBufferObjects(ox::Vec2 const&paneS) noexcept;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -57,7 +57,7 @@ void NewMenu::addItemMaker(ox::UniquePtr<studio::ItemMaker> &&im) noexcept {
 | 
			
		||||
	std::sort(
 | 
			
		||||
			m_types.begin(), m_types.end(),
 | 
			
		||||
			[](ox::UPtr<ItemMaker> const&im1, ox::UPtr<ItemMaker> const&im2) {
 | 
			
		||||
				 return im1->name < im2->name;
 | 
			
		||||
				 return im1->typeName < im2->typeName;
 | 
			
		||||
			});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -65,7 +65,7 @@ void NewMenu::drawNewItemType(turbine::Context &ctx) noexcept {
 | 
			
		||||
	drawWindow(ctx, &m_open, [this] {
 | 
			
		||||
		auto items = ox_malloca(m_types.size() * sizeof(char const*), char const*, nullptr);
 | 
			
		||||
		for (auto i = 0u; auto const&im : m_types) {
 | 
			
		||||
			items.get()[i] = im->name.c_str();
 | 
			
		||||
			items.get()[i] = im->typeName.c_str();
 | 
			
		||||
			++i;
 | 
			
		||||
		}
 | 
			
		||||
		ImGui::ListBox("Item Type", &m_selectedType, items.get(), static_cast<int>(m_types.size()));
 | 
			
		||||
@@ -115,7 +115,16 @@ void NewMenu::drawLastPageButtons(turbine::Context &ctx) noexcept {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewMenu::finish(turbine::Context &ctx) noexcept {
 | 
			
		||||
	auto const [path, err] = m_types[static_cast<std::size_t>(m_selectedType)]->write(ctx, m_itemName);
 | 
			
		||||
	if (m_itemName.len() == 0) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	auto const sctx = turbine::applicationData<studio::StudioContext>(ctx);
 | 
			
		||||
	auto const&typeMaker = *m_types[static_cast<std::size_t>(m_selectedType)];
 | 
			
		||||
	if (sctx->project->exists(typeMaker.itemPath(m_itemName))) {
 | 
			
		||||
		oxLogError(OxError(1, "New file error: File already exists"));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	auto const [path, err] = typeMaker.write(ctx, m_itemName);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		oxLogError(err);
 | 
			
		||||
		return;
 | 
			
		||||
 
 | 
			
		||||
@@ -15,16 +15,21 @@ namespace studio {
 | 
			
		||||
 | 
			
		||||
class ItemMaker {
 | 
			
		||||
	public:
 | 
			
		||||
		ox::String const name;
 | 
			
		||||
		ox::String const typeName;
 | 
			
		||||
		ox::String const parentDir;
 | 
			
		||||
		ox::String const fileExt;
 | 
			
		||||
		constexpr explicit ItemMaker(ox::StringView pName, ox::StringView pParentDir, ox::CRStringView pFileExt) noexcept:
 | 
			
		||||
			name(pName),
 | 
			
		||||
			typeName(pName),
 | 
			
		||||
			parentDir(pParentDir),
 | 
			
		||||
			fileExt(pFileExt) {
 | 
			
		||||
		}
 | 
			
		||||
		virtual ~ItemMaker() noexcept = default;
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		inline virtual ox::String itemPath(ox::StringView pName) const noexcept {
 | 
			
		||||
			return ox::sfmt("/{}/{}.{}", parentDir, pName, fileExt);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Returns path of the file created.
 | 
			
		||||
		 * @param ctx
 | 
			
		||||
@@ -69,8 +74,8 @@ class ItemMakerT: public ItemMaker {
 | 
			
		||||
			 m_fmt(pFmt) {
 | 
			
		||||
		}
 | 
			
		||||
		ox::Result<ox::String> write(turbine::Context &ctx, ox::CRStringView pName) const noexcept override {
 | 
			
		||||
			auto const path = ox::sfmt("/{}/{}.{}", parentDir, pName, fileExt);
 | 
			
		||||
			auto sctx = turbine::applicationData<studio::StudioContext>(ctx);
 | 
			
		||||
			auto const path = itemPath(pName);
 | 
			
		||||
			auto const sctx = turbine::applicationData<studio::StudioContext>(ctx);
 | 
			
		||||
			keel::createUuidMapping(keelCtx(ctx), path, ox::UUID::generate().unwrap());
 | 
			
		||||
			oxReturnError(sctx->project->writeObj(path, m_item, m_fmt));
 | 
			
		||||
			return path;
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ class Project {
 | 
			
		||||
		ox::String const&projectPath() const noexcept;
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		ox::FileSystem *romFs() noexcept;
 | 
			
		||||
		ox::FileSystem &romFs() noexcept;
 | 
			
		||||
 | 
			
		||||
		ox::Error mkdir(ox::CRStringView path) const noexcept;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -51,8 +51,8 @@ ox::String const&Project::projectPath() const noexcept {
 | 
			
		||||
	return m_path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::FileSystem *Project::romFs() noexcept {
 | 
			
		||||
	return &m_fs;
 | 
			
		||||
ox::FileSystem &Project::romFs() noexcept {
 | 
			
		||||
	return m_fs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::Error Project::mkdir(ox::CRStringView path) const noexcept {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user