Skip to content

File Shape.h

File List > Amplitude > Math > Shape.h

Go to the documentation of this file

// Copyright (c) 2021-present Sparky Studios. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#ifndef _AM_MATH_SHAPE_H
#define _AM_MATH_SHAPE_H

#include <SparkyStudios/Audio/Amplitude/Core/Common.h>
#include <SparkyStudios/Audio/Amplitude/Core/Entity.h>
#include <SparkyStudios/Audio/Amplitude/Core/Listener.h>

#include <array>
#include <memory>
#include <span>

namespace SparkyStudios::Audio::Amplitude
{
    class ShapeDefinition;
    class BoxShapeDefinition;
    class CapsuleShapeDefinition;
    class ConeShapeDefinition;
    class SphereShapeDefinition;

    class AM_API_PUBLIC Shape
    {
    public:
        static std::shared_ptr<Shape> Create(const ShapeDefinition* definition);

        Shape();

        virtual ~Shape() = default;

        [[nodiscard]] virtual AmReal32 GetShortestDistanceToEdge(const Entity& entity) const;

        [[nodiscard]] virtual AmReal32 GetShortestDistanceToEdge(const Listener& listener) const;

        [[nodiscard]] virtual AmReal32 GetShortestDistanceToEdge(const AmVector3& location) const = 0;

        [[nodiscard]] virtual bool Contains(const Entity& entity) const;

        [[nodiscard]] virtual bool Contains(const Listener& listener) const;

        [[nodiscard]] virtual bool Contains(const AmVector3& location) const = 0;

        void SetLocation(const AmVector3& location);

        void SetOrientation(const Orientation& orientation);

        [[nodiscard]] const Orientation& GetOrientation() const;

        [[nodiscard]] const AmMatrix4& GetLookAt() const;

        [[nodiscard]] const AmVector3& GetLocation() const;

        [[nodiscard]] AmVector3 GetDirection() const;

        [[nodiscard]] AmVector3 GetUp() const;

    protected:
        virtual void Update() = 0;

        AM_INLINE void UpdateIfNeeded() const
        {
            if (m_needUpdate)
            {
                auto* self = const_cast<Shape*>(this);
                self->Update();
                self->m_needUpdate = false;
            }
        }

        AmVector3 m_location;

        Orientation m_orientation;

        AmMatrix4 m_lookAtMatrix;

        bool m_needUpdate;
    };

    class AM_API_PUBLIC Zone
    {
    public:
        explicit Zone(std::shared_ptr<Shape> inner, std::shared_ptr<Shape> outer);

        virtual ~Zone();

        [[nodiscard]] virtual AM_INLINE AmReal32 GetFactor(const Entity& entity) const
        {
            return GetFactor(entity.GetLocation());
        }

        [[nodiscard]] virtual AM_INLINE AmReal32 GetFactor(const Listener& listener) const
        {
            return GetFactor(listener.GetLocation());
        }

        [[nodiscard]] virtual AmReal32 GetFactor(const AmVector3& position) const = 0;

        void SetLocation(const AmVector3& location);

        [[nodiscard]] const AmVector3& GetLocation() const;

        void SetOrientation(const Orientation& orientation);

        [[nodiscard]] const Orientation& GetOrientation() const;

        [[nodiscard]] AmVector3 GetDirection() const;

        [[nodiscard]] AmVector3 GetUp() const;

    protected:
        std::shared_ptr<Shape> m_innerShape;

        std::shared_ptr<Shape> m_outerShape;
    };

    class AM_API_PUBLIC BoxShape final : public Shape
    {
        friend class BoxZone;

    public:
        static std::shared_ptr<BoxShape> Create(const BoxShapeDefinition* definition);

        explicit BoxShape(AmReal32 halfWidth, AmReal32 halfHeight, AmReal32 halfDepth);

        explicit BoxShape(const AmVector3& position, const AmVector3& dimensions);

        [[nodiscard]] AmReal32 GetHalfWidth() const;

        [[nodiscard]] AmReal32 GetHalfHeight() const;

        [[nodiscard]] AmReal32 GetHalfDepth() const;

        [[nodiscard]] AmReal32 GetWidth() const;

        [[nodiscard]] AmReal32 GetHeight() const;

        [[nodiscard]] AmReal32 GetDepth() const;

        void SetHalfWidth(AmReal32 halfWidth);

        void SetHalfHeight(AmReal32 halfHeight);

        void SetHalfDepth(AmReal32 halfDepth);

        [[nodiscard]] AmReal32 GetShortestDistanceToEdge(const AmVector3& location) const override;

        [[nodiscard]] bool Contains(const AmVector3& location) const override;

        [[nodiscard]] AmVector3 GetClosestPoint(const AmVector3& location) const;

        [[nodiscard]] std::span<const AmVector3> GetCorners() const;

        bool operator==(const BoxShape& other) const;

        bool operator!=(const BoxShape& other) const;

    private:
        void Update() override;

        AmReal32 _halfWidth;
        AmReal32 _halfHeight;
        AmReal32 _halfDepth;

        AmVector3 _u;
        AmVector3 _v;
        AmVector3 _w;

        AmVector3 _p1, _p2, _p3, _p4;
        AmReal32 _uP1, _vP1, _wP1, _uP2, _vP3, _wP4;

        std::array<AmVector3, 8> _corners;
    };

    class AM_API_PUBLIC CapsuleShape final : public Shape
    {
        friend class CapsuleZone;

    public:
        static std::shared_ptr<CapsuleShape> Create(const CapsuleShapeDefinition* definition);

        explicit CapsuleShape(AmReal32 radius, AmReal32 halfHeight);

        [[nodiscard]] AmReal32 GetRadius() const;

        [[nodiscard]] AmReal32 GetHalfHeight() const;

        [[nodiscard]] AmReal32 GetDiameter() const;

        [[nodiscard]] AmReal32 GetHeight() const;

        void SetRadius(AmReal32 radius);

        void SetHalfHeight(AmReal32 halfHeight);

        [[nodiscard]] AmReal32 GetShortestDistanceToEdge(const AmVector3& location) const override;

        [[nodiscard]] bool Contains(const AmVector3& location) const override;

        bool operator==(const CapsuleShape& other) const;

        bool operator!=(const CapsuleShape& other) const;

    private:
        void Update() override;

        AmReal32 _radius;
        AmReal32 _halfHeight;

        AmVector3 _a, _b;
    };

    class AM_API_PUBLIC ConeShape final : public Shape
    {
        friend class ConeZone;

    public:
        static std::shared_ptr<ConeShape> Create(const ConeShapeDefinition* definition);

        explicit ConeShape(AmReal32 radius, AmReal32 height);

        [[nodiscard]] AmReal32 GetRadius() const;

        [[nodiscard]] AmReal32 GetDiameter() const;

        [[nodiscard]] AmReal32 GetHeight() const;

        void SetRadius(AmReal32 radius);

        void SetHeight(AmReal32 height);

        [[nodiscard]] AmReal32 GetShortestDistanceToEdge(const AmVector3& location) const override;

        [[nodiscard]] bool Contains(const AmVector3& location) const override;

        bool operator==(const ConeShape& other) const;

        bool operator!=(const ConeShape& other) const;

    private:
        void Update() override;

        AmReal32 _radius;
        AmReal32 _height;
    };

    class AM_API_PUBLIC SphereShape final : public Shape
    {
        friend class SphereZone;

    public:
        static std::shared_ptr<SphereShape> Create(const SphereShapeDefinition* definition);

        explicit SphereShape(AmReal32 radius);

        [[nodiscard]] AmReal32 GetRadius() const;

        [[nodiscard]] AmReal32 GetDiameter() const;

        void SetRadius(AmReal32 radius);

        [[nodiscard]] AmReal32 GetShortestDistanceToEdge(const AmVector3& location) const override;

        [[nodiscard]] bool Contains(const AmVector3& location) const override;

        bool operator==(const SphereShape& other) const;

        bool operator!=(const SphereShape& other) const;

    private:
        void Update() override;

        AmReal32 _radius;
    };

    class AM_API_PUBLIC BoxZone : public Zone
    {
    public:
        BoxZone(std::shared_ptr<BoxShape> inner, std::shared_ptr<BoxShape> outer);

        [[nodiscard]] AmReal32 GetFactor(const AmVector3& position) const override;
    };

    class AM_API_PUBLIC CapsuleZone : public Zone
    {
    public:
        CapsuleZone(std::shared_ptr<CapsuleShape> inner, std::shared_ptr<CapsuleShape> outer);

        [[nodiscard]] AmReal32 GetFactor(const AmVector3& position) const override;
    };

    class AM_API_PUBLIC ConeZone : public Zone
    {
    public:
        ConeZone(std::shared_ptr<ConeShape> inner, std::shared_ptr<ConeShape> outer);

        [[nodiscard]] AmReal32 GetFactor(const AmVector3& position) const override;
    };

    class AM_API_PUBLIC SphereZone : public Zone
    {
    public:
        SphereZone(std::shared_ptr<SphereShape> inner, std::shared_ptr<SphereShape> outer);

        [[nodiscard]] AmReal32 GetFactor(const AmVector3& position) const override;
    };
} // namespace SparkyStudios::Audio::Amplitude

#endif // _AM_MATH_SHAPE_H