Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 40 additions & 152 deletions Library/PAX_GRAPHICA/3DModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,205 +12,93 @@
#ifndef PAX_MAHOROBA_3D_MODEL_HPP
#define PAX_MAHOROBA_3D_MODEL_HPP

#include <memory>

#include <PAX_GRAPHICA/Interface/Graphics3DModelImpl.hpp>

#if defined(PAXS_USING_SIV3D)
#include <Siv3D.hpp>
#elif defined(PAXS_USING_DXLIB)
#include <DxLib.h>
#elif defined(PAXS_USING_SFML)
#include <SFML/Graphics.hpp>
#include <PAX_GRAPHICA/Siv3D/Siv3DGraphics3DModelImpl.hpp>
#else
#include <PAX_GRAPHICA/Null/NullGraphics3DModelImpl.hpp>
#endif

#include <PAX_SAPIENTICA/Core/Math/Math.hpp>
#include <PAX_SAPIENTICA/System/AppConfig.hpp>

namespace paxg {

/// @brief 3D モデル描画の設定
struct Graphics3DModelConfig {
/// @brief カメラ設定
struct Camera {
/// @brief 垂直視野角(度)
double verticalFOV = 40.0;
double posX = 0.0;
double posY = 3.0;
double posZ = -16.0;
} camera;

/// @brief 背景色設定
struct Background {
float r = 1.0f; // 赤成分
float g = 1.0f; // 緑成分
float b = 1.0f; // 青成分
float a = 0.0f; // 透明度
} background;

/// @brief ファイルパス設定
struct FilePaths {
std::string modelPath = "Data/3DModels/KofunOBJ/Model/Sekishitsu/KamoKitaKofun/KamoKitaKofun.obj";
} paths;

/// @brief モデルの回転速度(度/フレーム)
double rotationSpeed = 1.0;
};

/// @brief 3D モデル描画クラス
/// @brief 3D モデル描画クラス with Pimpl idiom for graphics library abstraction
/// @note Uses unique_ptr for implementation hiding and automatic resource management
class Graphics3DModel {
private:
Graphics3DModelConfig config_;
std::unique_ptr<Graphics3DModelImpl> impl_;

#ifdef PAXS_USING_SIV3D
// 回転角度
int rotation_ = 0;

s3d::ColorF backgroundColor_;

// 3D モデルデータ
s3d::Model model_;

// 描画するテクスチャの設定
mutable s3d::MSRenderTexture renderTexture_;

// カメラ
mutable s3d::DebugCamera3D camera_;
/// @brief Create implementation based on the active graphics library
/// @param cfg Configuration for 3D model
/// @return Unique pointer to the implementation
static std::unique_ptr<Graphics3DModelImpl> createImpl(const Graphics3DModelConfig& cfg) {
#if defined(PAXS_USING_SIV3D)
return std::make_unique<Siv3DGraphics3DModelImpl>(cfg);
#else
return std::make_unique<NullGraphics3DModelImpl>(cfg);
#endif
}

public:
/// @brief デフォルト設定でコンストラクタ
Graphics3DModel() : Graphics3DModel(Graphics3DModelConfig{}) {}

/// @brief カスタム設定でコンストラクタ
explicit Graphics3DModel(const Graphics3DModelConfig& cfg) : config_(cfg) {
#ifdef PAXS_USING_SIV3D
// カメラ設定
camera_ = s3d::DebugCamera3D{
s3d::Graphics3D::GetRenderTargetSize(),
paxs::Math<double>::degToRad(config_.camera.verticalFOV),
s3d::Vec3{ config_.camera.posX, config_.camera.posY, config_.camera.posZ }
};

renderTexture_ = s3d::MSRenderTexture{
s3d::Size{s3d::Scene::Width(), s3d::Scene::Height()},
s3d::TextureFormat::R8G8B8A8_Unorm_SRGB,
s3d::HasDepth::Yes
};

// 背景色を設定
backgroundColor_ = s3d::ColorF{
config_.background.r,
config_.background.g,
config_.background.b,
config_.background.a
}.removeSRGBCurve();

// 3D モデルデータをロード
const auto rootPath = s3d::Unicode::FromUTF8(paxs::AppConfig::getInstance().getRootPath());
model_ = s3d::Model{ rootPath + s3d::Unicode::FromUTF8(config_.paths.modelPath) };

// モデルに付随するテクスチャをアセット管理に登録
s3d::Model::RegisterDiffuseTextures(model_, s3d::TextureDesc::MippedSRGB);
#endif
}
explicit Graphics3DModel(const Graphics3DModelConfig& cfg)
: config_(cfg), impl_(createImpl(cfg)) {}

/// @brief 回転角度を更新
/// @brief Update rotation angle
void updateRotation() {
#ifdef PAXS_USING_SIV3D
// モデルの回転更新
++rotation_;
if (rotation_ >= 360) rotation_ = 0;
#endif
if (impl_) {
impl_->updateRotation();
}
}

/// @brief 3Dモデルを描画
/// @brief Render 3D model
void render() const {
#ifdef PAXS_USING_SIV3D
s3d::Graphics3D::SetCameraTransform(camera_); // カメラ情報を設定

// 3D シーンの描画
const s3d::ScopedRenderTarget3D target{ renderTexture_.clear(backgroundColor_) };

// 3Dモデルの描画
const s3d::ScopedRenderStates3D renderStates{
s3d::BlendState::OpaqueAlphaToCoverage,
s3d::RasterizerState::SolidCullNone
};
model_.draw(
s3d::Vec3{ 0, 0, 0 },
s3d::Quaternion::RotateY(paxs::Math<double>::degToRad(static_cast<double>(rotation_)))
);

// RenderTexture を 2D シーンに描画
s3d::Graphics3D::Flush(); // 現在までの 3D 描画を実行

// 画面サイズが変更されたら幅を変える
// 毎フレームチェックすると重いため、3フレームに1回チェック
static int resize_check_count = 0;
if (resize_check_count >= 3) {
resize_check_count = 0;
if (renderTexture_.width() != s3d::Scene::Width()
|| renderTexture_.height() != s3d::Scene::Height()) {
renderTexture_ = s3d::MSRenderTexture{
s3d::Size{s3d::Scene::Width(), s3d::Scene::Height()},
s3d::TextureFormat::R8G8B8A8_Unorm_SRGB,
s3d::HasDepth::Yes
};
}
if (impl_) {
impl_->render();
}
++resize_check_count;

renderTexture_.resolve(); // テクスチャを描画可能にする
renderTexture_.draw(0, 0); // 指定した大きさで描画
#endif
}

/// @brief 設定を取得
const Graphics3DModelConfig& getConfig() const { return config_; }

/// @brief 設定を更新
void setConfig(const Graphics3DModelConfig& cfg) { config_ = cfg; }
void setConfig(const Graphics3DModelConfig& cfg) {
config_ = cfg;
impl_ = createImpl(cfg);
}

/// @brief カメラ設定を更新
void setCameraConfig(const Graphics3DModelConfig::Camera& cam) {
config_.camera = cam;
#ifdef PAXS_USING_SIV3D
camera_ = s3d::DebugCamera3D{
s3d::Graphics3D::GetRenderTargetSize(),
paxs::Math<double>::degToRad(config_.camera.verticalFOV),
s3d::Vec3{ config_.camera.posX, config_.camera.posY, config_.camera.posZ }
};
#endif
if (impl_) {
impl_->setCameraConfig(cam);
}
}

/// @brief 背景色設定を更新
void setBackgroundConfig(const Graphics3DModelConfig::Background& bg) {
config_.background = bg;
#ifdef PAXS_USING_SIV3D
backgroundColor_ = s3d::ColorF{
config_.background.r,
config_.background.g,
config_.background.b,
config_.background.a
}.removeSRGBCurve();
#endif
if (impl_) {
impl_->setBackgroundConfig(bg);
}
}

/// @brief 現在の回転角度を取得(度)
int getRotation() const {
#ifdef PAXS_USING_SIV3D
return rotation_;
#else
return 0;
#endif
return impl_ ? impl_->getRotation() : 0;
}

/// @brief 回転角度を設定(度)
void setRotation(int angle) {
#ifdef PAXS_USING_SIV3D
rotation_ = angle % 360;
#else
(void)angle;
#endif
if (impl_) {
impl_->setRotation(angle);
}
}
};

Expand Down
126 changes: 84 additions & 42 deletions Library/PAX_GRAPHICA/Circle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,66 +12,108 @@
#ifndef PAX_GRAPHICA_CIRCLE_HPP
#define PAX_GRAPHICA_CIRCLE_HPP

#include <memory>

#include <PAX_GRAPHICA/Color.hpp>
#include <PAX_GRAPHICA/Interface/CircleImpl.hpp>
#include <PAX_SAPIENTICA/Core/Type/Vector2.hpp>

#if defined(PAXS_USING_SIV3D)
#include <Siv3D.hpp>
#include <PAX_GRAPHICA/Siv3D/Siv3DCircleImpl.hpp>
#elif defined(PAXS_USING_DXLIB)
#include <DxLib.h>
#include <PAX_GRAPHICA/DxLib/DxLibCircleImpl.hpp>
#elif defined(PAXS_USING_SFML)
#include <SFML/Graphics.hpp>
#include <PAX_GRAPHICA/SFML_Circle.hpp>
#include <PAX_GRAPHICA/SFML/SFMLCircleImpl.hpp>
#else
#include <PAX_GRAPHICA/Null/NullCircleImpl.hpp>
#endif

#include <PAX_GRAPHICA/Window.hpp>

#include <PAX_SAPIENTICA/Core/Type/Vector2.hpp>

namespace paxg {

struct Circle
{
/// @brief Circle class with Pimpl idiom for graphics library abstraction
/// @note Uses shared_ptr for value semantics and automatic resource management
struct Circle {
private:
std::shared_ptr<CircleImpl> impl;

/// @brief Create implementation based on the active graphics library
/// @param x X-coordinate of the circle center
/// @param y Y-coordinate of the circle center
/// @param r Radius of the circle
/// @return Shared pointer to the implementation
static std::shared_ptr<CircleImpl> createImpl(float x, float y, float r) {
#if defined(PAXS_USING_SIV3D)
s3d::Circle circle;
constexpr Circle(const paxs::Vector2<int>& pos, const float r) : circle(pos.x, pos.y, r) {}
constexpr Circle(const paxs::Vector2<float>& pos, const float r) : circle(pos.x, pos.y, r) {}
constexpr Circle(const paxs::Vector2<double>& pos, const float r) : circle(static_cast<float>(pos.x), static_cast<float>(pos.y), r) {}
constexpr operator s3d::Circle() const { return circle; }
return std::make_shared<Siv3DCircleImpl>(x, y, r);
#elif defined(PAXS_USING_DXLIB)
return std::make_shared<DxLibCircleImpl>(x, y, r);
#elif defined(PAXS_USING_SFML)
return std::make_shared<SFMLCircleImpl>(x, y, r);
#else
float x, y, r;
constexpr Circle(const paxs::Vector2<int>& pos, const float r) : x(static_cast<float>(pos.x)), y(static_cast<float>(pos.y)), r(r) {}
constexpr Circle(const paxs::Vector2<float>& pos, const float r) : x(pos.x), y(pos.y), r(r) {}
constexpr Circle(const paxs::Vector2<double>& pos, const float r) : x(static_cast<float>(pos.x)), y(static_cast<float>(pos.y)), r(r) {}
return std::make_shared<NullCircleImpl>(x, y, r);
#endif
}

public:
/// @brief Constructor with separate x, y coordinates and radius
/// @param x X-coordinate of the circle center
/// @param y Y-coordinate of the circle center
/// @param r Radius of the circle
Circle(float x, float y, float r)
: impl(createImpl(x, y, r)) {}

/// @brief Constructor with Vector2<int> position and radius
/// @param pos Position of the circle center
/// @param r Radius of the circle
Circle(const paxs::Vector2<int>& pos, const float r)
: impl(createImpl(static_cast<float>(pos.x), static_cast<float>(pos.y), r)) {}

/// @brief Constructor with Vector2<float> position and radius
/// @param pos Position of the circle center
/// @param r Radius of the circle
Circle(const paxs::Vector2<float>& pos, const float r)
: impl(createImpl(pos.x, pos.y, r)) {}

/// @brief Constructor with Vector2<double> position and radius
/// @param pos Position of the circle center
/// @param r Radius of the circle
Circle(const paxs::Vector2<double>& pos, const float r)
: impl(createImpl(static_cast<float>(pos.x), static_cast<float>(pos.y), r)) {}

/// @brief Draw the circle without color
void draw() const {
#if defined(PAXS_USING_SIV3D)
circle.draw();
if (impl) {
impl->draw();
}
}

#elif defined(PAXS_USING_SFML)
SFML_Circle::getInstance()->circle.setRadius(r);
SFML_Circle::getInstance()->circle.setPosition({ x, y });
paxg::Window::window().draw(SFML_Circle::getInstance()->circle);
#endif
/// @brief Draw the circle with specified color
/// @param color The color to draw the circle
void draw(const Color& color) const {
if (impl) {
impl->draw(color);
}
}

#if defined(PAXS_USING_SIV3D)
void draw(const paxg::Color& c_) const {
circle.draw(c_.color);
/// @brief Get the position of the circle center
/// @return Position as Vector2<float>
paxs::Vector2<float> getPosition() const {
return impl ? impl->getPosition() : paxs::Vector2<float>(0.0f, 0.0f);
}
#elif defined(PAXS_USING_DXLIB)
void draw(const paxg::Color& c_) const {
DxLib::DrawCircle(
static_cast<int>(x), static_cast<int>(y), static_cast<int>(r),
DxLib::GetColor(c_.r, c_.g, c_.b), TRUE);

/// @brief Get the radius of the circle
float getRadius() const {
return impl ? impl->getRadius() : 0.0f;
}
#elif defined(PAXS_USING_SFML)
void draw(const paxg::Color& c_) const {
SFML_Circle::getInstance()->circle.setRadius(r);
SFML_Circle::getInstance()->circle.setPosition({ x, y });

SFML_Circle::getInstance()->circle.setFillColor(c_.color);
paxg::Window::window().draw(SFML_Circle::getInstance()->circle);
#if defined(PAXS_USING_SIV3D)
/// @brief Conversion operator to s3d::Circle (Siv3D only)
operator s3d::Circle() const {
auto* siv3dImpl = dynamic_cast<Siv3DCircleImpl*>(impl.get());
if (siv3dImpl) {
return siv3dImpl->getNativeCircle();
}
return s3d::Circle(0, 0, 0);
}
#else
void draw(const paxg::Color&) const {}
#endif
};
}
Expand Down
Loading