add box2D colliders simple impl, some little tweaks, fixed camera bug

This commit is contained in:
2025-12-13 22:42:03 +08:00
parent 4140a5b4be
commit c92c831d02
30 changed files with 964 additions and 310 deletions

Binary file not shown.

View File

@ -0,0 +1,155 @@
Scene: Scene Name
Environment:
AssetPath: assets/env/pink_sunrise_4k.hdr
Light:
Direction: [-0.787, -0.73299998, 1]
Radiance: [1, 1, 1]
Multiplier: 0.514999986
Entities:
- Entity: 12498244675852797835
TagComponent:
Tag: Box
TransformComponent:
Position: [-12.0348625, 6.59647179, 9.60061925e-07]
Rotation: [1, 0, 0, 0]
Scale: [3.00000024, 0.300000012, 1]
MeshComponent:
AssetPath: assets/meshes/Cube1m.fbx
RigidBody2DComponent:
BodyType: 0
Mass: 1
BoxCollider2DComponent:
Offset: [0, 0]
Size: [1.5, 0.150000006]
Density: 1
Friction: 1
- Entity: 5178862374589434728
TagComponent:
Tag: Camera
TransformComponent:
Position: [-21.7406311, 9.70659542, 15]
Rotation: [0.999910355, -0.0133911213, 0, 0]
Scale: [1, 1, 1]
ScriptComponent:
ModuleName: Example.BasicController
StoredFields:
- Name: Speed
Type: 1
Data: 12
CameraComponent:
Camera: some camera data...
Primary: true
- Entity: 1289165777996378215
TagComponent:
Tag: Cube
TransformComponent:
Position: [500, 0, 0]
Rotation: [1, 0, 0, 0]
Scale: [1200, 1, 5]
MeshComponent:
AssetPath: assets/meshes/Cube1m.fbx
RigidBody2DComponent:
BodyType: 0
Mass: 1
BoxCollider2DComponent:
Offset: [0, 0]
Size: [600, 0.5]
Density: 1
Friction: 2
- Entity: 14057422478420564497
TagComponent:
Tag: Player
TransformComponent:
Position: [-23.6932545, 1.59184527, -1.96369365e-06]
Rotation: [1, 0, 0, 0]
Scale: [1, 1, 1]
ScriptComponent:
ModuleName: Example.PlayerCube
StoredFields:
- Name: HorizontalForce
Type: 1
Data: 0.5
- Name: MaxSpeed
Type: 5
Data: [7, 10]
- Name: JumpForce
Type: 1
Data: 3
MeshComponent:
AssetPath: assets/meshes/Sphere1m.fbx
RigidBody2DComponent:
BodyType: 1
Mass: 29.2000008
CircleCollider2DComponent:
Offset: [0, 0]
Radius: 0.5
Density: 1
Friction: 1
- Entity: 1352995477042327524
TagComponent:
Tag: Box
TransformComponent:
Position: [-29.6808929, 29.7597198, 0]
Rotation: [0.707106769, 0, 0, 0.707106769]
Scale: [58.4179001, 4.47999144, 4.48000002]
MeshComponent:
AssetPath: assets/meshes/Cube1m.fbx
RigidBody2DComponent:
BodyType: 0
Mass: 3
BoxCollider2DComponent:
Offset: [0, 0]
Size: [29.7000008, 2.24000001]
Density: 1
Friction: 1
- Entity: 15223077898852293773
TagComponent:
Tag: Box
TransformComponent:
Position: [6.12674046, 45.5617676, 0]
Rotation: [0.977883637, 0, 0, -0.209149584]
Scale: [4.47999668, 4.47999668, 4.48000002]
MeshComponent:
AssetPath: assets/meshes/Cube1m.fbx
RigidBody2DComponent:
BodyType: 1
Mass: 1
BoxCollider2DComponent:
Offset: [0, 0]
Size: [2.24000001, 2.24000001]
Density: 1
Friction: 1
- Entity: 5421735812495444456
TagComponent:
Tag: Box
TransformComponent:
Position: [-20.766222, 2.29431438, 0]
Rotation: [1, 0, 0, 0]
Scale: [3.00000024, 0.300000012, 1]
MeshComponent:
AssetPath: assets/meshes/Cube1m.fbx
RigidBody2DComponent:
BodyType: 0
Mass: 1
BoxCollider2DComponent:
Offset: [0, 0]
Size: [1.5, 0.150000006]
Density: 1
Friction: 1
- Entity: 2842299641876190180
TagComponent:
Tag: Box
TransformComponent:
Position: [-16.6143265, 4.39151001, 6.43359499e-09]
Rotation: [1, 0, 0, 0]
Scale: [3.00000024, 0.300000012, 1]
MeshComponent:
AssetPath: assets/meshes/Cube1m.fbx
RigidBody2DComponent:
BodyType: 0
Mass: 1
BoxCollider2DComponent:
Offset: [0, 0]
Size: [1.5, 0.150000006]
Density: 1
Friction: 1

View File

@ -6,27 +6,20 @@ namespace Example
{
public float Speed;
private Entity m_PlayerEntity;
public void OnCreate()
{
m_PlayerEntity = FindEntityByTag("Player");
}
public void OnUpdate(float ts)
{
Mat4 transform = GetTransform();
Vec3 translation = transform.Translation;
float speed = Speed * ts;
if (Input.IsKeyPressed(KeyCode.Up))
translation.Y += speed;
else if (Input.IsKeyPressed(KeyCode.Down))
translation.Y -= speed;
if (Input.IsKeyPressed(KeyCode.Right))
translation.X += speed;
else if (Input.IsKeyPressed(KeyCode.Left))
translation.X -= speed;
translation.XY = m_PlayerEntity.GetTransform().Translation.XY;
translation.Y = Math.Max(translation.Y, 4.5f);
transform.Translation = translation;
SetTransform(transform);
}

View File

@ -11,11 +11,17 @@ namespace Example
class PlayerCube : Entity
{
public float HorizontalForce = 10.0f;
public float VerticalForce = 10.0f;
public float JumpForce = 10.0f;
private RigidBody2DComponent m_PhysicsBody;
private MaterialInstance m_MeshMaterial;
int m_CollisionCounter = 0;
public Vec2 MaxSpeed = new Vec2();
private bool Colliding => m_CollisionCounter > 0;
void OnCreate()
{
m_PhysicsBody = GetComponent<RigidBody2DComponent>();
@ -23,23 +29,46 @@ namespace Example
MeshComponent meshComponent = GetComponent<MeshComponent>();
m_MeshMaterial = meshComponent.Mesh.GetMaterial(0);
m_MeshMaterial.Set("u_Metalness", 0.0f);
AddCollision2DBeginCallback(OnPlayerCollisionBegin);
AddCollision2DEndCallback(OnPlayerCollisionEnd);
}
void OnPlayerCollisionBegin(float value)
{
m_CollisionCounter++;
}
void OnPlayerCollisionEnd(float value)
{
m_CollisionCounter--;
}
void OnUpdate(float ts)
{
float movementForce = HorizontalForce;
if (!Colliding)
{
movementForce *= 0.4f;
}
if (Input.IsKeyPressed(KeyCode.D))
m_PhysicsBody.ApplyLinearImpulse(new Vec2(HorizontalForce, 0), new Vec2(), true);
m_PhysicsBody.ApplyLinearImpulse(new Vec2(movementForce, 0), new Vec2(), true);
else if (Input.IsKeyPressed(KeyCode.A))
m_PhysicsBody.ApplyLinearImpulse(new Vec2(-HorizontalForce, 0), new Vec2(), true);
m_PhysicsBody.ApplyLinearImpulse(new Vec2(-movementForce, 0), new Vec2(), true);
if (Input.IsKeyPressed(KeyCode.Space))
m_PhysicsBody.ApplyLinearImpulse(new Vec2(0, VerticalForce), new Vec2(0, -10), true);
if (Colliding && Input.IsKeyPressed(KeyCode.Space))
m_PhysicsBody.ApplyLinearImpulse(new Vec2(0, JumpForce), new Vec2(0, 0), true);
Vec3 color = new Vec3(0.8f, 0.8f, 0.8f);
if (Input.IsKeyPressed(KeyCode.Q))
color = new Vec3(0.0f, 1.0f, 0.0f);
if (m_CollisionCounter > 0)
m_MeshMaterial.Set("u_AlbedoColor", new Vec3(1.0f, 0.0f, 0.0f));
else
m_MeshMaterial.Set("u_AlbedoColor", new Vec3(0.8f, 0.8f, 0.8f));
m_MeshMaterial.Set("u_AlbedoColor", color);
Vec2 linearVelocity = m_PhysicsBody.GetLinearVelocity();
linearVelocity.Clamp(new Vec2(-MaxSpeed.X, -1000), MaxSpeed);
m_PhysicsBody.SetLinearVelocity(linearVelocity);
if (Input.IsKeyPressed(KeyCode.R))
{

View File

@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Prism
@ -10,6 +11,16 @@ namespace Prism
{
}
private List<Action<float>> m_Collision2DBeginCallbacks = new List<Action<float>>();
private List<Action<float>> m_Collision2DEndCallbacks = new List<Action<float>>();
protected Entity() { ID = 0; }
internal Entity(ulong id)
{
ID = id;
}
public T CreateComponent<T>() where T : Component, new()
{
CreateComponent_Native(ID, typeof(T));
@ -34,6 +45,12 @@ namespace Prism
return null;
}
public Entity FindEntityByTag(string tag)
{
ulong entityID = FindEntityByTag_Native(tag);
return new Entity(entityID);
}
public Mat4 GetTransform()
{
Mat4 mat4Instance;
@ -46,6 +63,28 @@ namespace Prism
SetTransform_Native(ID, ref transform);
}
public void AddCollision2DBeginCallback(Action<float> callback)
{
m_Collision2DBeginCallbacks.Add(callback);
}
public void AddCollision2DEndCallback(Action<float> callback)
{
m_Collision2DEndCallbacks.Add(callback);
}
private void OnCollision2DBegin(float data)
{
foreach (var callback in m_Collision2DBeginCallbacks)
callback.Invoke(data);
}
private void OnCollision2DEnd(float data)
{
foreach (var callback in m_Collision2DEndCallbacks)
callback.Invoke(data);
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void CreateComponent_Native(ulong entityID, Type type);
[MethodImpl(MethodImplOptions.InternalCall)]
@ -54,6 +93,8 @@ namespace Prism
private static extern void GetTransform_Native(ulong entityID, out Mat4 matrix);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void SetTransform_Native(ulong entityID, ref Mat4 matrix);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern ulong FindEntityByTag_Native(string tag);
}
}

View File

@ -18,5 +18,27 @@ namespace Prism
X = x;
Y = y;
}
public Vec2(Vec3 vec) {
X = vec.X;
Y = vec.Y;
}
public void Clamp(Vec2 min, Vec2 max) {
if (X < min.X)
X = min.X;
if (X > max.X)
X = max.X;
if (Y < min.Y)
Y = min.Y;
if (Y > max.Y)
Y = max.Y;
}
public static Vec2 operator -(Vec2 vector)
{
return new Vec2(-vector.X, -vector.Y);
}
}
}

View File

@ -2,18 +2,24 @@ using System.Runtime.InteropServices;
namespace Prism
{
[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
public struct Vec3
{
[FieldOffset(0)] public float X;
[FieldOffset(4)] public float Y;
[FieldOffset(8)] public float Z;
public float X;
public float Y;
public float Z;
public Vec3(float scalar)
{
X = Y = Z = scalar;
}
public Vec3(Vec2 vec) {
X = vec.X;
Y = vec.Y;
Z = 0.0f;
}
public Vec3(float x, float y, float z)
{
X = x;
@ -21,6 +27,27 @@ namespace Prism
Z = z;
}
public Vec3(Vec4 vec) {
X = vec.X;
Y = vec.Y;
Z = vec.Z;
}
public Vec2 XY {
get { return new Vec2(X, Y); }
set { X = value.X; Y = value.Y; }
}
public Vec2 XZ
{
get { return new Vec2(X, Z); }
set { X = value.X; Z = value.Y; }
}
public Vec2 YZ
{
get { return new Vec2(Y, Z); }
set { Y = value.X; Z = value.Y; }
}
}
}

View File

@ -100,7 +100,27 @@ namespace Prism
ApplyLinearImpulse_Native(Entity.ID, ref impulse, ref offset, wake);
}
public Vec2 GetLinearVelocity()
{
GetLinearVelocity_Native(Entity.ID, out Vec2 velocity);
return velocity;
}
public void SetLinearVelocity(Vec2 velocity)
{
SetLinearVelocity_Native(Entity.ID, ref velocity);
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void ApplyLinearImpulse_Native(ulong entityID, ref Vec2 impulse, ref Vec2 offset, bool wake);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void GetLinearVelocity_Native(ulong entityID, out Vec2 velocity);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void SetLinearVelocity_Native(ulong entityID, ref Vec2 velocity);
}
public class BoxCollider2DComponent : Component
{
}
}

View File

@ -52,6 +52,12 @@ namespace Prism
memset(Data, 0, Size);
}
template<typename T>
T& Read(const uint32_t offset = 0)
{
return *static_cast<T*>(Data + offset);
}
void Write(const void* data, const uint32_t size, const uint32_t offset = 0) const
{
PM_CORE_ASSERT(offset + size <= Size, "Buffer overflow!");

View File

@ -48,14 +48,14 @@ namespace Prism
template<typename T2>
Ref(const Ref<T2>& other)
{
m_Instance = other.m_Instance;
m_Instance = (T*)other.m_Instance;
IncRef();
}
template<typename T2>
Ref(Ref&& other)
Ref(Ref<T2*>&& other)
{
m_Instance = other.m_Instance;
m_Instance = (T*)other.m_Instance;
other.m_Instance = nullptr;
}

View File

@ -73,7 +73,6 @@ namespace Prism
float m_Distance;
float m_Exposure = 0.8f;
float m_Pitch, m_Yaw;
};

View File

@ -111,6 +111,30 @@ namespace Prism
ImGui::CloseCurrentPopup();
}
}
if (!m_SelectionContext.HasComponent<RigidBody2DComponent>())
{
if (ImGui::Button("Rigidbody 2D"))
{
m_SelectionContext.AddComponent<RigidBody2DComponent>();
ImGui::CloseCurrentPopup();
}
}
if (!m_SelectionContext.HasComponent<BoxCollider2DComponent>())
{
if (ImGui::Button("Box Collider 2D"))
{
m_SelectionContext.AddComponent<BoxCollider2DComponent>();
ImGui::CloseCurrentPopup();
}
}
if (!m_SelectionContext.HasComponent<CircleCollider2DComponent>())
{
if (ImGui::Button("Circle Collider 2D"))
{
m_SelectionContext.AddComponent<CircleCollider2DComponent>();
ImGui::CloseCurrentPopup();
}
}
ImGui::EndPopup();
}
}
@ -323,6 +347,28 @@ namespace Prism
ImGui::NextColumn();
}
static bool Property(const char* label, bool& value)
{
bool modified = false;
ImGui::Text(label);
ImGui::NextColumn();
ImGui::PushItemWidth(-1);
s_IDBuffer[0] = '#';
s_IDBuffer[1] = '#';
memset(s_IDBuffer + 2, 0, 14);
// itoa(s_Counter++, s_IDBuffer + 2, 16);
snprintf(s_IDBuffer + 2, 14, "%x", s_Counter++);
if (ImGui::Checkbox(s_IDBuffer, &value))
modified = true;
ImGui::PopItemWidth();
ImGui::NextColumn();
return modified;
}
static bool Property(const char* label, int& value)
{
bool modified = false;
@ -444,6 +490,48 @@ namespace Prism
PopID();
}
template<typename T, typename UIFunction>
static void DrawComponent(const std::string& name, Entity entity, UIFunction uiFunction)
{
if (entity.HasComponent<T>())
{
bool removeComponent = false;
auto& component = entity.GetComponent<T>();
const bool open = ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(T).hash_code()), ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_AllowOverlap, name.c_str());
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0));
if (ImGui::Button("+"))
{
ImGui::OpenPopup("ComponentSettings");
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
if (ImGui::BeginPopup("ComponentSettings"))
{
if (ImGui::MenuItem("Remove component"))
removeComponent = true;
ImGui::EndPopup();
}
if (open)
{
uiFunction(component);
ImGui::NextColumn();
ImGui::Columns(1);
ImGui::TreePop();
}
ImGui::Separator();
if (removeComponent)
entity.RemoveComponent<T>();
}
}
void SceneHierarchyPanel::DrawComponents(Entity entity)
{
ImGui::AlignTextToFramePadding();
@ -532,12 +620,7 @@ namespace Prism
ImGui::Separator();
}
if (entity.HasComponent<MeshComponent>())
{
auto& mc = entity.GetComponent<MeshComponent>();
if (ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(MeshComponent).hash_code()), ImGuiTreeNodeFlags_DefaultOpen, "Mesh"))
{
DrawComponent<MeshComponent>("Mesh", entity, [](MeshComponent& meshComponent) {
ImGui::Columns(3);
ImGui::SetColumnWidth(0, 100);
ImGui::SetColumnWidth(1, 300);
@ -546,8 +629,8 @@ namespace Prism
ImGui::NextColumn();
ImGui::PushItemWidth(-1);
if (mc.Mesh)
ImGui::InputText("##meshFilePath", (char*)mc.Mesh->GetFilePath().c_str(), 256, ImGuiInputTextFlags_ReadOnly);
if (meshComponent.Mesh)
ImGui::InputText("##meshFilePath", (char*)meshComponent.Mesh->GetFilePath().c_str(), 256, ImGuiInputTextFlags_ReadOnly);
else
ImGui::InputText("##meshFilePath", (char*)"Null", 256, ImGuiInputTextFlags_ReadOnly);
@ -557,33 +640,24 @@ namespace Prism
{
const std::string file = Application::Get().OpenFile();
if (!file.empty())
mc.Mesh = Ref<Mesh>::Create(file);
meshComponent.Mesh = Ref<Mesh>::Create(file);
}
ImGui::NextColumn();
ImGui::Columns(1);
});
ImGui::TreePop();
}
ImGui::Separator();
}
if (entity.HasComponent<CameraComponent>())
{
auto& cc = entity.GetComponent<CameraComponent>();
if (ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(CameraComponent).hash_code()), ImGuiTreeNodeFlags_DefaultOpen, "Camera"))
{
DrawComponent<CameraComponent>("Camera", entity, [](CameraComponent& cameraComponent) {
// Projection Type
const char* projTypeStrings[] = { "Perspective", "Orthographic" };
const char* currentProj = projTypeStrings[(int)cc.Camera.GetProjectionType()];
const char* currentProj = projTypeStrings[(int)cameraComponent.Camera.GetProjectionType()];
if (ImGui::BeginCombo("Projection", currentProj))
{
for (int type = 0; type < 2; type++)
{
bool is_selected = (currentProj == projTypeStrings[type]);
const bool is_selected = (currentProj == projTypeStrings[type]);
if (ImGui::Selectable(projTypeStrings[type], is_selected))
{
currentProj = projTypeStrings[type];
cc.Camera.SetProjectionType((SceneCamera::ProjectionType)type);
cameraComponent.Camera.SetProjectionType((SceneCamera::ProjectionType)type);
}
if (is_selected)
ImGui::SetItemDefaultFocus();
@ -593,80 +667,64 @@ namespace Prism
BeginPropertyGrid();
// Perspective parameters
if (cc.Camera.GetProjectionType() == SceneCamera::ProjectionType::Perspective)
if (cameraComponent.Camera.GetProjectionType() == SceneCamera::ProjectionType::Perspective)
{
float verticalFOV = cc.Camera.GetPerspectiveVerticalFOV();
float verticalFOV = cameraComponent.Camera.GetPerspectiveVerticalFOV();
if (Property("Vertical FOV", verticalFOV))
cc.Camera.SetPerspectiveVerticalFOV(verticalFOV);
cameraComponent.Camera.SetPerspectiveVerticalFOV(verticalFOV);
float nearClip = cc.Camera.GetPerspectiveNearClip();
float nearClip = cameraComponent.Camera.GetPerspectiveNearClip();
if (Property("Near Clip", nearClip))
cc.Camera.SetPerspectiveNearClip(nearClip);
cameraComponent.Camera.SetPerspectiveNearClip(nearClip);
ImGui::SameLine();
float farClip = cc.Camera.GetPerspectiveFarClip();
float farClip = cameraComponent.Camera.GetPerspectiveFarClip();
if (Property("Far Clip", farClip))
cc.Camera.SetPerspectiveFarClip(farClip);
cameraComponent.Camera.SetPerspectiveFarClip(farClip);
}
// Orthographic parameters
else if (cc.Camera.GetProjectionType() == SceneCamera::ProjectionType::Orthographic)
else if (cameraComponent.Camera.GetProjectionType() == SceneCamera::ProjectionType::Orthographic)
{
float orthoSize = cc.Camera.GetOrthographicSize();
float orthoSize = cameraComponent.Camera.GetOrthographicSize();
if (Property("Size", orthoSize))
cc.Camera.SetOrthographicSize(orthoSize);
cameraComponent.Camera.SetOrthographicSize(orthoSize);
float nearClip = cc.Camera.GetOrthographicNearClip();
float nearClip = cameraComponent.Camera.GetOrthographicNearClip();
if (Property("Near Clip", nearClip))
cc.Camera.SetOrthographicNearClip(nearClip);
cameraComponent.Camera.SetOrthographicNearClip(nearClip);
ImGui::SameLine();
float farClip = cc.Camera.GetOrthographicFarClip();
float farClip = cameraComponent.Camera.GetOrthographicFarClip();
if (Property("Far Clip", farClip))
cc.Camera.SetOrthographicFarClip(farClip);
cameraComponent.Camera.SetOrthographicFarClip(farClip);
}
EndPropertyGrid();
});
ImGui::TreePop();
}
ImGui::Separator();
}
DrawComponent<SpriteRendererComponent>("Sprite Renderer", entity, [](SpriteRendererComponent& mc)
{
});
if (entity.HasComponent<SpriteRendererComponent>())
{
auto& src = entity.GetComponent<SpriteRendererComponent>();
if (ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(SpriteRendererComponent).hash_code()), ImGuiTreeNodeFlags_DefaultOpen, "Sprite Renderer"))
{
ImGui::TreePop();
}
ImGui::Separator();
}
if (entity.HasComponent<ScriptComponent>())
{
auto& sc = entity.GetComponent<ScriptComponent>();
if (ImGui::TreeNodeEx((void*)((uint32_t)entity | typeid(ScriptComponent).hash_code()), ImGuiTreeNodeFlags_DefaultOpen, "Script"))
{
DrawComponent<ScriptComponent>("Script", entity, [=](ScriptComponent& scriptComponent) mutable {
BeginPropertyGrid();
std::string oldName = sc.ModuleName;
if (Property("Module Name", sc.ModuleName, !ScriptEngine::ModuleExists(sc.ModuleName))) // TODO: no live edit
std::string oldName = scriptComponent.ModuleName;
if (Property("Module Name", scriptComponent.ModuleName, !ScriptEngine::ModuleExists(scriptComponent.ModuleName))) // TODO: no live edit
{
// Shutdown old script
if (ScriptEngine::ModuleExists(oldName))
ScriptEngine::ShutdownScriptEntity(entity, oldName);
if (ScriptEngine::ModuleExists(sc.ModuleName))
if (ScriptEngine::ModuleExists(scriptComponent.ModuleName))
ScriptEngine::InitScriptEntity(entity);
}
if (ScriptEngine::ModuleExists(sc.ModuleName))
// Public Fields
if (ScriptEngine::ModuleExists(scriptComponent.ModuleName))
{
EntityInstanceData& entityInstanceData = ScriptEngine::GetEntityInstanceData(entity.GetSceneUUID(), id);
auto& moduleFieldMap = entityInstanceData.ModuleFieldMap;
if (moduleFieldMap.find(sc.ModuleName) != moduleFieldMap.end())
if (moduleFieldMap.find(scriptComponent.ModuleName) != moduleFieldMap.end())
{
auto& publicFields = moduleFieldMap.at(sc.ModuleName);
auto& publicFields = moduleFieldMap.at(scriptComponent.ModuleName);
for (auto& [name, field] : publicFields)
{
bool isRuntime = m_Context->m_IsPlaying && field.IsRuntimeAvailable();
@ -738,19 +796,67 @@ namespace Prism
}
EndPropertyGrid();
#if TODO
if (ImGui::Button("Run Script"))
{
ScriptEngine::OnCreateEntity(entity);
}
#endif
});
ImGui::TreePop();
DrawComponent<RigidBody2DComponent>("Rigidbody 2D", entity, [](RigidBody2DComponent& rb2dComponent)
{
// Rigidbody2D Type
const char* rb2dTypeStrings[] = { "Static", "Dynamic", "Kinematic" };
const char* currentType = rb2dTypeStrings[(int)rb2dComponent.BodyType];
if (ImGui::BeginCombo("Type", currentType))
{
for (int type = 0; type < 3; type++)
{
bool is_selected = (currentType == rb2dTypeStrings[type]);
if (ImGui::Selectable(rb2dTypeStrings[type], is_selected))
{
currentType = rb2dTypeStrings[type];
rb2dComponent.BodyType = (RigidBody2DComponent::Type)type;
}
ImGui::Separator();
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
if (rb2dComponent.BodyType == RigidBody2DComponent::Type::Dynamic)
{
BeginPropertyGrid();
Property("Fixed Rotation", rb2dComponent.FixedRotation);
EndPropertyGrid();
}
});
DrawComponent<BoxCollider2DComponent>("Box Collider 2D", entity, [](BoxCollider2DComponent& bc2dComponent)
{
BeginPropertyGrid();
Property("Offset", bc2dComponent.Offset);
Property("Size", bc2dComponent.Size);
Property("Density", bc2dComponent.Density);
Property("Friction", bc2dComponent.Friction);
EndPropertyGrid();
});
DrawComponent<CircleCollider2DComponent>("Circle Collider 2D", entity, [](CircleCollider2DComponent& cc2dComponent)
{
BeginPropertyGrid();
Property("Offset", cc2dComponent.Offset);
Property("Radius", cc2dComponent.Radius);
Property("Density", cc2dComponent.Density);
Property("Friction", cc2dComponent.Friction);
EndPropertyGrid();
});
}

View File

@ -48,14 +48,10 @@ namespace Prism
OpenGLVertexBuffer::~OpenGLVertexBuffer()
{
#ifdef __MINGW32__
glDeleteBuffers(1, &m_RendererID);
#else
GLuint rendererID = m_RendererID;
Renderer::Submit([rendererID](){
glDeleteBuffers(1, &rendererID);
});
#endif
}
void OpenGLVertexBuffer::SetData(void* buffer, uint32_t size, uint32_t offset)
@ -105,13 +101,10 @@ namespace Prism
OpenGLIndexBuffer::~OpenGLIndexBuffer()
{
#ifdef __MINGW32__
glDeleteBuffers(1, &m_RendererID);
#else
Renderer::Submit([this](){
glDeleteBuffers(1, &m_RendererID);
const GLuint rendererID = m_RendererID;
Renderer::Submit([rendererID](){
glDeleteBuffers(1, &rendererID);
});
#endif
}
void OpenGLIndexBuffer::SetData(void* data, uint32_t size, uint32_t offset)

View File

@ -19,13 +19,10 @@ namespace Prism
OpenGLFrameBuffer::~OpenGLFrameBuffer()
{
#ifdef __MINGW32__
glDeleteFramebuffers(1, &m_RendererID);
#else
Renderer::Submit([=](){
glDeleteFramebuffers(1, &m_RendererID);
GLuint rendererID = m_RendererID;
Renderer::Submit([rendererID](){
glDeleteFramebuffers(1, &rendererID);
});
#endif
}
void OpenGLFrameBuffer::Bind() const
@ -71,13 +68,12 @@ namespace Prism
// TODO: Create Prism texture object based on format here
if (m_Specification.Format == FramebufferFormat::RGBA16F)
{
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA16F, m_Specification.Width, m_Specification.Height, GL_FALSE);
//glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA16F, m_Specification.Width, m_Specification.Height, GL_FALSE);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA16F, m_Specification.Width, m_Specification.Height, GL_TRUE);
}
else if (m_Specification.Format == FramebufferFormat::RGBA8)
{
// glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGBA8, m_Specification.Width, m_Specification.Height, GL_TRUE);
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA8, m_Specification.Width, m_Specification.Height, GL_FALSE);
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA8, m_Specification.Width, m_Specification.Height, GL_TRUE);
}
// glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -108,7 +104,7 @@ namespace Prism
glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE, 1, &m_DepthAttachment);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_DepthAttachment);
// glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, GL_TRUE);
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, GL_FALSE);
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, GL_TRUE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
// glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, m_DepthAttachment, 0);
}

View File

@ -118,14 +118,10 @@ namespace Prism
OpenGLTexture2D::~OpenGLTexture2D()
{
#ifdef __MINGW32__
glDeleteTextures(1, &m_RendererID);
#else
GLuint rendererID = m_RendererID;
Renderer::Submit([rendererID](){
glDeleteTextures(1, &rendererID);
});
#endif
}
void OpenGLTexture2D::Bind(uint32_t slot) const
@ -286,14 +282,10 @@ namespace Prism
OpenGLTextureCube::~OpenGLTextureCube()
{
#ifdef __MINGW32__
glDeleteTextures(1, &m_RendererID);
#else
GLuint rendererID = m_RendererID;
Renderer::Submit([rendererID]() {
glDeleteTextures(1, &rendererID);
});
#endif
}
void OpenGLTextureCube::Bind(uint32_t slot) const

View File

@ -40,14 +40,10 @@ namespace Prism
OpenGLVertexArray::~OpenGLVertexArray()
{
#ifdef __MINGW32__
glDeleteVertexArrays(1, &m_RendererID);
#else
GLuint rendererID = m_RendererID;
Renderer::Submit([rendererID](){
glDeleteVertexArrays(1, &rendererID);
});
#endif
}
void OpenGLVertexArray::Bind() const

View File

@ -38,6 +38,24 @@ namespace Prism
uint32_t GetFlags() const { return m_MaterialFlags; }
void SetFlag(MaterialFlag flag) { m_MaterialFlags |= (uint32_t)flag; }
template <typename T>
T& Get(const std::string& name)
{
auto decl = FindUniformDeclaration(name);
PM_CORE_ASSERT(decl, "Could not find uniform with name x");
auto& buffer = GetUniformBufferTarget(decl);
return buffer.Read<T>(decl->GetOffset());
}
template <typename T>
Ref<T> GetResource(const std::string& name)
{
const auto decl = FindResourceDeclaration(name);
const uint32_t slot = decl->GetRegister();
PM_CORE_ASSERT(slot < m_Textures.size(), "Texture slot is invalid!");
return m_Textures[slot];
}
template <typename T>
void Set(const std::string& name, const T& value);
@ -45,7 +63,11 @@ namespace Prism
void Set(const std::string& name, const Ref<Texture>& texture)
{
const auto decl = FindResourceDeclaration(name);
if (!decl) return;
if (!decl)
{
PM_CORE_WARN("Cannot find material property: ", name);
return;
}
uint32_t slot = decl->GetRegister();
if (m_Textures.size() <= slot)
m_Textures.resize((size_t)slot + 1);
@ -92,6 +114,41 @@ namespace Prism
static Ref<MaterialInstance> Create(const Ref<Material>& material);
template<typename T>
T& Get(const std::string& name)
{
const auto decl = m_Material->FindUniformDeclaration(name);
PM_CORE_ASSERT(decl, "Could not find uniform with name x");
auto& buffer = GetUniformBufferTarget(decl);
return buffer.Read<T>(decl->GetOffset());
}
template<typename T>
Ref<T> GetResource(const std::string& name)
{
const auto decl = m_Material->FindResourceDeclaration(name);
PM_CORE_ASSERT(decl, "Could not find uniform with name x");
uint32_t slot = decl->GetRegister();
PM_CORE_ASSERT(slot < m_Textures.size(), "Texture slot is invalid!");
return Ref<T>(m_Textures[slot]);
}
template<typename T>
Ref<T> TryGetResource(const std::string& name)
{
const auto decl = m_Material->FindResourceDeclaration(name);
if (!decl)
return nullptr;
const uint32_t slot = decl->GetRegister();
if (slot >= m_Textures.size())
return nullptr;
return Ref<T>(m_Textures[slot]);
}
template <typename T>
void Set(const std::string& name, const T& value)
{
@ -151,9 +208,8 @@ namespace Prism
void Material::Set(const std::string& name, const T& value)
{
auto decl = FindUniformDeclaration(name);
// HZ_CORE_ASSERT(decl, "Could not find uniform with name '{0}'", name);
PM_CORE_ASSERT(decl, "Could not find uniform with name 'x'");
auto& buffer = GetUniformBufferTarget(decl);
PM_CORE_ASSERT(decl, "Could not find uniform with name x");
const auto& buffer = GetUniformBufferTarget(decl);
buffer.Write(&value, decl->GetSize(), decl->GetOffset());
for (auto mi : m_MaterialInstances)

View File

@ -272,11 +272,12 @@ namespace Prism
PM_CORE_TRACE("COLOR = {0}, {1}, {2}", aiColor.r, aiColor.g, aiColor.b);
float shininess, metalness;
aiMaterial->Get(AI_MATKEY_SHININESS, shininess);
if (aiMaterial->Get(AI_MATKEY_SHININESS, shininess) != aiReturn_SUCCESS)
shininess = 80.0f; // Default value
aiMaterial->Get(AI_MATKEY_REFLECTIVITY, metalness);
if (aiMaterial->Get(AI_MATKEY_REFLECTIVITY, metalness) != aiReturn_SUCCESS)
metalness = 0.0f;
// float roughness = 1.0f - shininess * 0.01f;
// roughness *= roughness;
float roughness = 1.0f - glm::sqrt(shininess / 100.0f);
PM_MESH_LOG(" COLOR = {0}, {1}, {2}", aiColor.r, aiColor.g, aiColor.b);
PM_MESH_LOG(" ROUGHNESS = {0}", roughness);

View File

@ -120,7 +120,7 @@ namespace Prism
const std::vector<Ref<Texture2D>>& GetTextures() const { return m_Textures; }
const std::string& GetFilePath() const { return m_FilePath; }
const std::vector<Triangle> GetTriangleCache(uint32_t index) const { return m_TriangleCache.at(index); }
std::vector<Triangle> GetTriangleCache(const uint32_t index) const { return m_TriangleCache.at(index); }
private:
void BoneTransform(float time);
void ReadNodeHierarchy(float AnimationTime, const aiNode* pNode, const glm::mat4& ParentTransform);

View File

@ -76,7 +76,6 @@ namespace Prism
s_Data.CompositePass = RenderPass::Create(compRenderPassSpec);
s_Data.CompositeShader = Shader::Create("assets/shaders/SceneComposite.glsl");
// s_Data.CompositeShader = Shader::Create("assets/shaders/hdr.glsl");
s_Data.BRDFLUT = Texture2D::Create("assets/textures/BRDF_LUT.tga");

View File

@ -27,8 +27,7 @@ namespace Prism
std::string Tag;
TagComponent() = default;
TagComponent(const TagComponent& other)
: Tag(other.Tag) {}
TagComponent(const TagComponent& other) = default;
TagComponent(const std::string& tag)
: Tag(tag) {}
@ -42,8 +41,7 @@ namespace Prism
glm::mat4 Transform;
TransformComponent() = default;
TransformComponent(const TransformComponent& other)
: Transform(other.Transform) {}
TransformComponent(const TransformComponent& other) = default;
TransformComponent(const glm::mat4& transform)
: Transform(transform) {}
@ -57,8 +55,7 @@ namespace Prism
Ref<Prism::Mesh> Mesh;
MeshComponent() = default;
MeshComponent(const MeshComponent& other)
: Mesh(other.Mesh) {}
MeshComponent(const MeshComponent& other) = default;
MeshComponent(const Ref<Prism::Mesh>& mesh)
: Mesh(mesh) {}
@ -71,8 +68,7 @@ namespace Prism
std::string ModuleName;
ScriptComponent() = default;
ScriptComponent(const ScriptComponent& other)
: ModuleName(other.ModuleName) {}
ScriptComponent(const ScriptComponent& other) = default;
ScriptComponent(const std::string& moduleName)
: ModuleName(moduleName) {}
};
@ -84,8 +80,7 @@ namespace Prism
bool Primary = true;
CameraComponent() = default;
CameraComponent(const CameraComponent& other)
: Camera(other.Camera), Primary(other.Primary) {}
CameraComponent(const CameraComponent& other) = default;
operator SceneCamera& () { return Camera; }
operator const SceneCamera& () const { return Camera; }
@ -99,22 +94,20 @@ namespace Prism
float TilingFactor = 1.0f;
SpriteRendererComponent() = default;
SpriteRendererComponent(const SpriteRendererComponent& other)
: Color(other.Color), Texture(other.Texture), TilingFactor(other.TilingFactor) {}
SpriteRendererComponent(const SpriteRendererComponent& other) = default;
};
struct RigidBody2DComponent
{
enum class Type { Static, Dynamic, Kinematic };
Type BodyType;
float Mass = 1.0f;
bool FixedRotation = false;
// Storage for BodyID (box2d version 3.0^ use handle to resolve this)
b2BodyId RuntimeBodyID = b2_nullBodyId;
RigidBody2DComponent() = default;
RigidBody2DComponent(const RigidBody2DComponent& other)
: BodyType(other.BodyType), Mass(other.Mass) {}
RigidBody2DComponent(const RigidBody2DComponent& other) = default;
};
struct BoxCollider2DComponent
@ -122,12 +115,13 @@ namespace Prism
glm::vec2 Offset = { 0.0f,0.0f };
glm::vec2 Size = { 1.0f, 1.0f };
float Density = 1.0f;
float Friction = 1.0f;
// Storage for runtime
// void* RuntimeFixture = nullptr;
BoxCollider2DComponent() = default;
BoxCollider2DComponent(const BoxCollider2DComponent& other)
: Offset(other.Offset), Size(other.Size) {}
BoxCollider2DComponent(const BoxCollider2DComponent& other) = default;
};
struct CircleCollider2DComponent
@ -135,12 +129,13 @@ namespace Prism
glm::vec2 Offset = { 0.0f,0.0f };
float Radius = 1.0f;
float Density = 1.0f;
float Friction = 1.0f;
// Storage for runtime
// void* RuntimeFixture = nullptr;
CircleCollider2DComponent() = default;
CircleCollider2DComponent(const CircleCollider2DComponent& other)
: Offset(other.Offset), Radius(other.Radius) {}
CircleCollider2DComponent(const CircleCollider2DComponent& other) = default;
};
}

View File

@ -25,12 +25,14 @@ namespace Prism
template<typename T, typename... Args>
T& AddComponent(Args&&... args)
{
PM_CORE_ASSERT(!HasComponent<T>(), "Entity already has component!");
return m_Scene->m_Registry.emplace<T>(m_EntityHandle, std::forward<Args>(args)...);
}
template<typename T>
T& GetComponent()
{
PM_CORE_ASSERT(HasComponent<T>(), "Entity doesn't have component!");
return m_Scene->m_Registry.get<T>(m_EntityHandle);
}
@ -42,6 +44,7 @@ namespace Prism
template<typename T>
void RemoveComponent() const {
PM_CORE_ASSERT(HasComponent<T>(), "Entity doesn't have component!");
if (HasComponent<T>())
m_Scene->m_Registry.remove<T>(m_EntityHandle);
}
@ -64,7 +67,7 @@ namespace Prism
}
UUID GetUUID() { return GetComponent<IDComponent>().ID; }
UUID GetSceneUUID() { return m_Scene->GetUUID(); }
UUID GetSceneUUID() const { return m_Scene->GetUUID(); }
private:
explicit Entity(const std::string& name);

View File

@ -16,6 +16,11 @@
namespace Prism
{
// TODO: THIS SHOULD MOVE TO PHYSICS FILE!
std::unordered_map<UUID, Scene*> s_ActiveScenes;
static uint32_t s_SceneIDCounter = 0;
@ -29,7 +34,7 @@ namespace Prism
{
b2WorldId World;
Box2DWorldComponent() = default;
Box2DWorldComponent() = delete;
Box2DWorldComponent(const b2Vec2& gravity) {
b2WorldDef worldDef = b2DefaultWorldDef();
worldDef.gravity = gravity;
@ -37,9 +42,44 @@ namespace Prism
}
};
void ProcessContactEvents(const b2WorldId worldId) {
const b2ContactEvents contactEvents = b2World_GetContactEvents(worldId);
// Contact Begin Touch
for (int i = 0; i < contactEvents.beginCount; ++i) {
const b2ContactBeginTouchEvent& event = contactEvents.beginEvents[i];
auto& entityA = *static_cast<Entity *>(b2Body_GetUserData(b2Shape_GetBody(event.shapeIdA)));
auto& entityB = *static_cast<Entity *>(b2Body_GetUserData(b2Shape_GetBody(event.shapeIdB)));
if (entityA.HasComponent<ScriptComponent>() && ScriptEngine::ModuleExists(entityA.GetComponent<ScriptComponent>().ModuleName))
ScriptEngine::OnCollision2DBegin(entityA);
if (entityB.HasComponent<ScriptComponent>() && ScriptEngine::ModuleExists(entityB.GetComponent<ScriptComponent>().ModuleName))
ScriptEngine::OnCollision2DBegin(entityB);
}
// Contact Begin Touch
for (int i = 0; i < contactEvents.endCount; ++i) {
const b2ContactEndTouchEvent& event = contactEvents.endEvents[i];
auto& entityA = *static_cast<Entity *>(b2Body_GetUserData(b2Shape_GetBody(event.shapeIdA)));
auto& entityB = *static_cast<Entity *>(b2Body_GetUserData(b2Shape_GetBody(event.shapeIdB)));
if (entityA.HasComponent<ScriptComponent>() && ScriptEngine::ModuleExists(entityA.GetComponent<ScriptComponent>().ModuleName))
ScriptEngine::OnCollision2DEnd(entityA);
if (entityB.HasComponent<ScriptComponent>() && ScriptEngine::ModuleExists(entityB.GetComponent<ScriptComponent>().ModuleName))
ScriptEngine::OnCollision2DEnd(entityB);
}
}
void OnTransformConstruct(entt::registry& registry, entt::entity entity)
{
// HZ_CORE_TRACE("Transform Component constructed!");
// PM_CORE_TRACE("Transform Component constructed!");
}
void OnScriptComponentConstruct(entt::registry& registry, entt::entity entity)
@ -55,6 +95,15 @@ namespace Prism
ScriptEngine::InitScriptEntity(scene->m_EntityIDMap.at(entityID));
}
void OnScriptComponentDestroy(entt::registry& registry, entt::entity entity)
{
const auto sceneView = registry.view<SceneComponent>();
const UUID sceneID = registry.get<SceneComponent>(sceneView.front()).SceneID;
const auto entityID = registry.get<IDComponent>(entity).ID;
ScriptEngine::OnScriptComponentDestroyed(sceneID, entityID);
}
static std::tuple<glm::vec3, glm::quat, glm::vec3> GetTransformDecomposition(const glm::mat4& transform)
{
glm::vec3 scale, translation, skew;
@ -79,8 +128,9 @@ namespace Prism
m_SceneEntity = m_Registry.create();
m_Registry.emplace<SceneComponent>(m_SceneEntity, m_SceneID);
// TODO: Obviously not necessary in all cases
m_Registry.emplace<Box2DWorldComponent>(m_SceneEntity, b2Vec2{ 0.0f, -9.8f });
Box2DWorldComponent& b2World = m_Registry.emplace<Box2DWorldComponent>(m_SceneEntity, b2Vec2{ 0.0f, -9.8f });
s_ActiveScenes[m_SceneID] = this;
@ -89,6 +139,7 @@ namespace Prism
Scene::~Scene()
{
m_Registry.on_destroy<ScriptComponent>().disconnect();
m_Registry.clear();
s_ActiveScenes.erase(m_SceneID);
@ -117,16 +168,27 @@ namespace Prism
// Box2D physics
auto sceneView = m_Registry.view<Box2DWorldComponent>();
auto& box2DWorld = m_Registry.get<Box2DWorldComponent>(sceneView.front()).World;
const auto sceneView = m_Registry.view<Box2DWorldComponent>();
const auto& box2DWorld = m_Registry.get<Box2DWorldComponent>(sceneView.front()).World;
int32_t velocityIterations = 6;
int32_t positionIterations = 2;
constexpr int32_t positionIterations = 2;
// box2DWorld->Step(ts, velocityIterations, positionIterations);
b2World_Step(box2DWorld, ts, positionIterations);
{
auto view = m_Registry.view<RigidBody2DComponent>();
for (auto entity : view)
ProcessContactEvents(box2DWorld);
/*
const b2ContactEvents contactEvents = b2World_GetContactEvents(box2DWorld);
if (contactEvents.beginCount > 0)
PM_CORE_WARN("collision box counts in begin: {}", contactEvents.beginCount);
if (contactEvents.endCount > 0)
PM_CORE_WARN("collision box counts in end: {}", contactEvents.endCount);
*/
}
{
const auto view = m_Registry.view<RigidBody2DComponent>();
for (const auto entity : view)
{
Entity e = { entity, this };
auto& transform = e.Transform();
@ -163,10 +225,10 @@ namespace Prism
m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod);
auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>);
SceneRenderer::BeginScene(this, { camera, cameraViewMatrix });
SceneRenderer::BeginScene(this, { static_cast<Camera>(camera), cameraViewMatrix });
for (auto entity : group)
{
auto [transformComponent, meshComponent] = group.get<TransformComponent, MeshComponent>(entity);
const auto& [transformComponent, meshComponent] = group.get<TransformComponent, MeshComponent>(entity);
if (meshComponent.Mesh)
{
meshComponent.Mesh->OnUpdate(ts);
@ -208,7 +270,7 @@ namespace Prism
SceneRenderer::BeginScene(this, { static_cast<Camera>(editorCamera), editorCamera.GetViewMatrix() });
for (auto entity : group)
{
auto [transformComponent, meshComponent] = group.get<TransformComponent, MeshComponent>(entity);
const auto& [transformComponent, meshComponent] = group.get<TransformComponent, MeshComponent>(entity);
if (meshComponent.Mesh)
{
meshComponent.Mesh->OnUpdate(ts);
@ -218,7 +280,7 @@ namespace Prism
if (m_SelectedEntity == entity)
SceneRenderer::SubmitSelectedMesh(meshComponent, transformComponent);
else
SceneRenderer::SubmitMesh(meshComponent, transformComponent, nullptr);
SceneRenderer::SubmitMesh(meshComponent, transformComponent);
}
}
SceneRenderer::EndScene();
@ -266,9 +328,12 @@ namespace Prism
auto& world = m_Registry.get<Box2DWorldComponent>(sceneView.front()).World;
{
auto view = m_Registry.view<RigidBody2DComponent>();
m_PhysicsBodyEntityBuffer = new Entity[view.size()];
uint32_t physicsBodyEntityBufferIndex = 0;
for (auto entity : view)
{
Entity e = { entity, this };
UUID entityID = e.GetComponent<IDComponent>().ID;
auto& transform = e.Transform();
auto& rigidBody2D = m_Registry.get<RigidBody2DComponent>(entity);
@ -285,6 +350,13 @@ namespace Prism
float rotationZ = glm::eulerAngles(rotationQuat).z;
bodyDef.rotation = b2Rot{cos(rotationZ), sin(rotationZ)};
// box2D fixRotation renamed to motionlocks
bodyDef.motionLocks = b2MotionLocks{false, false, rigidBody2D.FixedRotation};
Entity* entityStorage = &m_PhysicsBodyEntityBuffer[physicsBodyEntityBufferIndex++];
*entityStorage = e;
bodyDef.userData = entityStorage;
rigidBody2D.RuntimeBodyID = b2CreateBody(world, &bodyDef);
}
}
@ -306,10 +378,10 @@ namespace Prism
b2BodyId bodyId = rigidBody2D.RuntimeBodyID;
b2Polygon boxShape = b2MakeOffsetBox(boxCollider2D.Size.x, boxCollider2D.Size.y, {boxCollider2D.Offset.x,boxCollider2D.Offset.y}, {1.0f, 0.0f});
b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.density = 1.0f;
shapeDef.material.friction = 1.0f;
shapeDef.density = boxCollider2D.Density;
shapeDef.material.friction = boxCollider2D.Friction;
shapeDef.enableContactEvents = true;
b2CreatePolygonShape(bodyId, &shapeDef, &boxShape);
}
@ -321,7 +393,6 @@ namespace Prism
for (auto entity : view)
{
Entity e = { entity, this };
auto& transform = e.Transform();
auto& circleCollider2D = m_Registry.get<CircleCollider2DComponent>(entity);
if (e.HasComponent<RigidBody2DComponent>())
@ -333,15 +404,15 @@ namespace Prism
b2Vec2 centor = {circleCollider2D.Offset.x, circleCollider2D.Offset.y};
b2Circle circleShape{
.center = centor,
.radius = circleCollider2D.Radius
};
b2Circle circleShape;
circleShape.center = centor;
circleShape.radius = circleCollider2D.Radius;
b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.density = 1.0f;
shapeDef.material.friction = 1.0f;
shapeDef.density = circleCollider2D.Density;
shapeDef.material.friction = circleCollider2D.Friction;
shapeDef.enableContactEvents = true;
b2CreateCircleShape(bodyId, &shapeDef, &circleShape);
}
@ -354,6 +425,7 @@ namespace Prism
void Scene::OnRuntimeStop()
{
delete[] m_PhysicsBodyEntityBuffer;
m_IsPlaying = false;
}
@ -464,6 +536,19 @@ namespace Prism
CopyComponentIfExists<CircleCollider2DComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
}
Entity Scene::FindEntityByTag(const std::string &tag) {
// TODO: If this becomes used often, consider indexing by tag
const auto view = m_Registry.view<TagComponent>();
for (const auto entity : view)
{
const auto& canditate = view.get<TagComponent>(entity).Tag;
if (canditate == tag)
return Entity(entity, this);
}
return Entity{};
}
void Scene::CopyTo(Ref<Scene>& target)
{
target->m_Light = m_Light;

View File

@ -28,7 +28,7 @@ namespace Prism
struct Light
{
glm::vec3 Direction{0.0f, 0.0f, 0.0f};
glm::vec3 Direction{-0.314f, -0.941f, -0.209f};
glm::vec3 Radiance{ 0.0f, 0.0f, 0.0f};
float Multiplier = 1.0f;
@ -80,6 +80,8 @@ namespace Prism
return m_Registry.view<T>();
}
Entity FindEntityByTag(const std::string& tag);
const EntityMap& GetEntityMap() const { return m_EntityIDMap; }
void CopyTo(Ref<Scene>& target);
@ -107,6 +109,7 @@ namespace Prism
EntityMap m_EntityIDMap;
entt::entity m_SelectedEntity;
Entity* m_PhysicsBodyEntityBuffer = nullptr;
Light m_Light;
float m_LightMultiplier = 0.3f;
@ -124,6 +127,7 @@ namespace Prism
friend class SceneSerializer;
friend class SceneHierarchyPanel;
friend void OnScriptComponentConstruct(entt::registry& registry, entt::entity entity);
friend void OnScriptComponentDestroy(entt::registry& registry, entt::entity entity);
};
}

View File

@ -296,7 +296,7 @@ namespace Prism
const auto& rigidbody2DComponent = entity.GetComponent<RigidBody2DComponent>();
out << YAML::Key << "BodyType" << YAML::Value << (int)rigidbody2DComponent.BodyType;
out << YAML::Key << "Mass" << YAML::Value << rigidbody2DComponent.Mass;
out << YAML::Key << "FixedRotation" << YAML::Value << rigidbody2DComponent.FixedRotation;
out << YAML::EndMap; // RigidBody2DComponent
}
@ -309,6 +309,8 @@ namespace Prism
const auto& boxCollider2DComponent = entity.GetComponent<BoxCollider2DComponent>();
out << YAML::Key << "Offset" << YAML::Value << boxCollider2DComponent.Offset;
out << YAML::Key << "Size" << YAML::Value << boxCollider2DComponent.Size;
out << YAML::Key << "Density" << YAML::Value << boxCollider2DComponent.Density;
out << YAML::Key << "Friction" << YAML::Value << boxCollider2DComponent.Friction;
out << YAML::EndMap; // BoxCollider2DComponent
}
@ -321,6 +323,8 @@ namespace Prism
const auto& circleCollider2DComponent = entity.GetComponent<CircleCollider2DComponent>();
out << YAML::Key << "Offset" << YAML::Value << circleCollider2DComponent.Offset;
out << YAML::Key << "Radius" << YAML::Value << circleCollider2DComponent.Radius;
out << YAML::Key << "Density" << YAML::Value << circleCollider2DComponent.Density;
out << YAML::Key << "Friction" << YAML::Value << circleCollider2DComponent.Friction;
out << YAML::EndMap; // CircleCollider2DComponent
}
@ -538,7 +542,7 @@ namespace Prism
{
auto& component = deserializedEntity.AddComponent<RigidBody2DComponent>();
component.BodyType = (RigidBody2DComponent::Type)rigidBody2DComponent["BodyType"].as<int>();
component.Mass = rigidBody2DComponent["Mass"].as<float>();
component.FixedRotation = rigidBody2DComponent["FixedRotation"] ? rigidBody2DComponent["FixedRotation"].as<bool>() : false;
}
if (auto boxCollider2DComponent = entity["BoxCollider2DComponent"])
@ -546,6 +550,8 @@ namespace Prism
auto& component = deserializedEntity.AddComponent<BoxCollider2DComponent>();
component.Offset = boxCollider2DComponent["Offset"].as<glm::vec2>();
component.Size = boxCollider2DComponent["Size"].as<glm::vec2>();
component.Density = boxCollider2DComponent["Density"] ? boxCollider2DComponent["Density"].as<float>() : 1.0f;
component.Friction = boxCollider2DComponent["Friction"] ? boxCollider2DComponent["Friction"].as<float>() : 1.0f;
}
if (auto circleCollider2DComponent = entity["CircleCollider2DComponent"])
@ -553,6 +559,8 @@ namespace Prism
auto& component = deserializedEntity.AddComponent<CircleCollider2DComponent>();
component.Offset = circleCollider2DComponent["Offset"].as<glm::vec2>();
component.Radius = circleCollider2DComponent["Radius"].as<float>();
component.Density = circleCollider2DComponent["Density"] ? circleCollider2DComponent["Density"].as<float>() : 1.0f;
component.Friction = circleCollider2DComponent["Friction"] ? circleCollider2DComponent["Friction"].as<float>() : 1.0f;
}
}
}

View File

@ -28,6 +28,12 @@ namespace Prism
static EntityInstanceMap s_EntityInstanceMap;
static MonoAssembly* s_AppAssembly = nullptr;
static MonoAssembly* s_CoreAssembly = nullptr;
MonoImage* s_AppAssemblyImage = nullptr;
MonoImage* s_CoreAssemblyImage = nullptr;
static MonoMethod* GetMethod(MonoImage* image, const std::string& methodDesc);
struct EntityScriptClass
@ -41,10 +47,18 @@ namespace Prism
MonoMethod* OnDestroyMethod = nullptr;
MonoMethod* OnUpdateMethod = nullptr;
// Physics
MonoMethod* OnCollision2DBeginMethod = nullptr;
MonoMethod* OnCollision2DEndMethod = nullptr;
void InitClassMethods(MonoImage* image)
{
OnCreateMethod = GetMethod(image, FullName + ":OnCreate()");
OnUpdateMethod = GetMethod(image, FullName + ":OnUpdate(single)");
// Physics (Entity class)
OnCollision2DBeginMethod = GetMethod(s_CoreAssemblyImage, "Prism.Entity:OnCollision2DBegin(single)");
OnCollision2DEndMethod = GetMethod(s_CoreAssemblyImage, "Prism.Entity:OnCollision2DEnd(single)");
}
};
@ -159,11 +173,11 @@ namespace Prism
{
MonoMethodDesc* desc = mono_method_desc_new(methodDesc.c_str(), 0);
if (!desc)
std::cout << "mono_method_desc_new failed" << std::endl;
PM_CORE_ERROR("mono_method_desc_new failed: {}", methodDesc);
MonoMethod* method = mono_method_desc_search_in_image(desc, image);
if (!method)
std::cout << "mono_method_desc_search_in_image failed" << std::endl;
PM_CORE_ERROR("mono_method_desc_search_in_image failed: {}", methodDesc);
return method;
}
@ -206,11 +220,6 @@ namespace Prism
}
}
static MonoAssembly* s_AppAssembly = nullptr;
static MonoAssembly* s_CoreAssembly = nullptr;
MonoImage* s_AppAssemblyImage = nullptr;
MonoImage* s_CoreAssemblyImage = nullptr;
static void LoadPrismRuntimeAssembly(const std::string& path)
{
if (s_AppAssembly)
@ -445,7 +454,41 @@ namespace Prism
}
}
void ScriptEngine::OnScriptComponentDestroyed(UUID sceneID, UUID entityID)
void ScriptEngine::OnCollision2DBegin(Entity entity)
{
OnCollision2DBegin(entity.m_Scene->GetUUID(), entity.GetComponent<IDComponent>().ID);
}
void ScriptEngine::OnCollision2DBegin(const UUID &sceneID, const UUID &entityID)
{
EntityInstance& entityInstance = GetEntityInstanceData(sceneID, entityID).Instance;
if (entityInstance.ScriptClass->OnCollision2DBeginMethod)
{
float value = 5.0f;
void* args[] = { &value };
CallMethod(entityInstance.GetInstance(), entityInstance.ScriptClass->OnCollision2DBeginMethod, args);
}
}
void ScriptEngine::OnCollision2DEnd(Entity entity)
{
OnCollision2DEnd(entity.m_Scene->GetUUID(), entity.GetComponent<IDComponent>().ID);
}
void ScriptEngine::OnCollision2DEnd(const UUID &sceneID, const UUID &entityID)
{
EntityInstance& entityInstance = GetEntityInstanceData(sceneID, entityID).Instance;
if (entityInstance.ScriptClass->OnCollision2DEndMethod)
{
float value = 5.0f;
void* args[] = { &value };
CallMethod(entityInstance.GetInstance(), entityInstance.ScriptClass->OnCollision2DEndMethod, args);
}
}
void ScriptEngine::OnScriptComponentDestroyed(const UUID &sceneID, const UUID &entityID)
{
PM_CORE_ASSERT(s_EntityInstanceMap.find(sceneID) != s_EntityInstanceMap.end());
auto& entityMap = s_EntityInstanceMap.at(sceneID);

View File

@ -118,7 +118,12 @@ namespace Prism
static void OnCreateEntity(UUID sceneID, UUID entityID);
static void OnUpdateEntity(UUID sceneID, UUID entityID, TimeStep ts);
static void OnScriptComponentDestroyed(UUID sceneID, UUID entityID);
static void OnCollision2DBegin(Entity entity);
static void OnCollision2DBegin(const UUID &sceneID, const UUID &entityID);
static void OnCollision2DEnd(Entity entity);
static void OnCollision2DEnd(const UUID &sceneID, const UUID &entityID);
static void OnScriptComponentDestroyed(const UUID &sceneID, const UUID &entityID);
static bool ModuleExists(const std::string& moduleName);
static void InitScriptEntity(Entity entity);

View File

@ -52,6 +52,7 @@ namespace Prism
mono_add_internal_call("Prism.Entity::SetTransform_Native",(const void*)Prism::Script::Prism_Entity_SetTransform);
mono_add_internal_call("Prism.Entity::CreateComponent_Native",(const void*)Prism::Script::Prism_Entity_CreateComponent);
mono_add_internal_call("Prism.Entity::HasComponent_Native",(const void*)Prism::Script::Prism_Entity_HasComponent);
mono_add_internal_call("Prism.Entity::FindEntityByTag_Native", (const void*)Prism::Script::Prism_Entity_FindEntityByTag);
mono_add_internal_call("Prism.MeshComponent::GetMesh_Native",(const void*)Prism::Script::Prism_MeshComponent_GetMesh);
mono_add_internal_call("Prism.MeshComponent::SetMesh_Native",(const void*)Prism::Script::Prism_MeshComponent_SetMesh);
@ -59,6 +60,8 @@ namespace Prism
mono_add_internal_call("Prism.Input::IsKeyPressed_Native", (const void*)Prism::Script::Prism_Input_IsKeyPressed);
mono_add_internal_call("Prism.RigidBody2DComponent::ApplyLinearImpulse_Native", (const void*)Prism::Script::Prism_RigidBody2DComponent_ApplyLinearImpulse);
mono_add_internal_call("Prism.RigidBody2DComponent::GetLinearVelocity_Native", (const void *)Prism::Script::Prism_RigidBody2DComponent_GetLinearVelocity);
mono_add_internal_call("Prism.RigidBody2DComponent::SetLinearVelocity_Native", (const void *)Prism::Script::Prism_RigidBody2DComponent_SetLinearVelocity);
mono_add_internal_call("Prism.Texture2D::Constructor_Native", (const void*)Prism::Script::Prism_Texture2D_Constructor);
mono_add_internal_call("Prism.Texture2D::Destructor_Native", (const void*)Prism::Script::Prism_Texture2D_Destructor);

View File

@ -108,6 +108,18 @@ namespace Prism { namespace Script {
return result;
}
uint64_t Prism_Entity_FindEntityByTag(MonoString* tag)
{
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
PM_CORE_ASSERT(scene, "No active scene!");
Entity entity = scene->FindEntityByTag(mono_string_to_utf8(tag));
if (entity)
return entity.GetComponent<IDComponent>().ID;
return 0;
}
void* Prism_MeshComponent_GetMesh(uint64_t entityID)
{
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
@ -148,6 +160,68 @@ namespace Prism { namespace Script {
b2Body_ApplyLinearImpulse(body, *(const b2Vec2*)impulse, b2Body_GetWorldCenterOfMass(body) + *(const b2Vec2*)offset, wake);
}
void Prism_RigidBody2DComponent_GetLinearVelocity(uint64_t entityID, glm::vec2 *outVelocity)
{
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
PM_CORE_ASSERT(scene, "No active scene!");
const auto& entityMap = scene->GetEntityMap();
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
Entity entity = entityMap.at(entityID);
PM_CORE_ASSERT(entity.HasComponent<RigidBody2DComponent>());
auto& component = entity.GetComponent<RigidBody2DComponent>();
b2Vec2 velocity = b2Body_GetLinearVelocity(component.RuntimeBodyID);
PM_CORE_ASSERT(outVelocity);
*outVelocity = { velocity.x, velocity.y };
}
void Prism_RigidBody2DComponent_SetLinearVelocity(uint64_t entityID, glm::vec2 *velocity)
{
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
PM_CORE_ASSERT(scene, "No active scene!");
const auto& entityMap = scene->GetEntityMap();
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
Entity entity = entityMap.at(entityID);
PM_CORE_ASSERT(entity.HasComponent<RigidBody2DComponent>());
auto& component = entity.GetComponent<RigidBody2DComponent>();
PM_CORE_ASSERT(velocity);
b2Body_SetLinearVelocity(component.RuntimeBodyID, {velocity->x, velocity->y});
}
void Hazel_RigidBody2DComponent_GetLinearVelocity(uint64_t entityID, glm::vec2* outVelocity)
{
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
PM_CORE_ASSERT(scene, "No active scene!");
const auto& entityMap = scene->GetEntityMap();
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
Entity entity = entityMap.at(entityID);
PM_CORE_ASSERT(entity.HasComponent<RigidBody2DComponent>());
auto& component = entity.GetComponent<RigidBody2DComponent>();
const auto& velocity = b2Body_GetLinearVelocity(component.RuntimeBodyID);
PM_CORE_ASSERT(outVelocity);
*outVelocity = { velocity.x, velocity.y };
}
void Hazel_RigidBody2DComponent_SetLinearVelocity(uint64_t entityID, glm::vec2* velocity)
{
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
PM_CORE_ASSERT(scene, "No active scene!");
const auto& entityMap = scene->GetEntityMap();
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
Entity entity = entityMap.at(entityID);
PM_CORE_ASSERT(entity.HasComponent<RigidBody2DComponent>());
const auto& component = entity.GetComponent<RigidBody2DComponent>();
PM_CORE_ASSERT(velocity);
b2Body_SetLinearVelocity(component.RuntimeBodyID, {velocity->x, velocity->y});
}
Ref<Mesh>* Prism_Mesh_Constructor(MonoString* filepath)
{
return new Ref<Mesh>(new Mesh(mono_string_to_utf8(filepath)));

View File

@ -28,12 +28,15 @@ namespace Prism { namespace Script {
void Prism_Entity_SetTransform(uint64_t entityID, glm::mat4* inTransform);
void Prism_Entity_CreateComponent(uint64_t entityID, void* type);
bool Prism_Entity_HasComponent(uint64_t entityID, void* type);
uint64_t Prism_Entity_FindEntityByTag(MonoString* tag);
void* Prism_MeshComponent_GetMesh(uint64_t entityID);
void Prism_MeshComponent_SetMesh(uint64_t entityID, Ref<Mesh>* inMesh);
// 2D Physic
void Prism_RigidBody2DComponent_ApplyLinearImpulse(uint64_t entityID, glm::vec2* impulse, glm::vec2* offset, bool wake);
void Prism_RigidBody2DComponent_GetLinearVelocity(uint64_t entityID, glm::vec2* outVelocity);
void Prism_RigidBody2DComponent_SetLinearVelocity(uint64_t entityID, glm::vec2* velocity);
// Renderer
// Texture2D