Skip to content

Commit 8be59f4

Browse files
committed
PBR is working. KTX2 with BasisU is working.
Shadows are working. Gamma and exposure are working as sliders in the UI. Need to cleanup and Physics and then we're feature complete.
1 parent b998a13 commit 8be59f4

24 files changed

+2667
-1040
lines changed

attachments/simple_engine/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ set(SOURCES
9797
renderer_compute.cpp
9898
renderer_utils.cpp
9999
renderer_resources.cpp
100+
renderer_shadows.cpp
100101
memory_pool.cpp
101102
resource_manager.cpp
102103
entity.cpp

attachments/simple_engine/engine.cpp

Lines changed: 181 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -40,40 +40,59 @@ bool Engine::Initialize(const std::string& appName, int width, int height, bool
4040

4141
// Set mouse callback
4242
platform->SetMouseCallback([this](float x, float y, uint32_t buttons) {
43-
// Handle camera rotation when left mouse button is pressed
44-
if (buttons & 1) { // Left mouse button (bit 0)
45-
if (!cameraControl.mouseLeftPressed) {
46-
cameraControl.mouseLeftPressed = true;
47-
cameraControl.firstMouse = true;
43+
// Check if ImGui wants to capture mouse input first
44+
bool imguiWantsMouse = imguiSystem && imguiSystem->WantCaptureMouse();
45+
46+
if (!imguiWantsMouse) {
47+
// Handle mouse click for poke functionality (right mouse button)
48+
if (buttons & 2) { // Right mouse button (bit 1)
49+
if (!cameraControl.mouseRightPressed) {
50+
cameraControl.mouseRightPressed = true;
51+
// Perform poke on mouse click
52+
HandleMousePoke(x, y);
53+
}
54+
} else {
55+
cameraControl.mouseRightPressed = false;
4856
}
4957

50-
if (cameraControl.firstMouse) {
58+
// Handle camera rotation when left mouse button is pressed
59+
if (buttons & 1) { // Left mouse button (bit 0)
60+
if (!cameraControl.mouseLeftPressed) {
61+
cameraControl.mouseLeftPressed = true;
62+
cameraControl.firstMouse = true;
63+
}
64+
65+
if (cameraControl.firstMouse) {
66+
cameraControl.lastMouseX = x;
67+
cameraControl.lastMouseY = y;
68+
cameraControl.firstMouse = false;
69+
}
70+
71+
float xOffset = x - cameraControl.lastMouseX;
72+
float yOffset = cameraControl.lastMouseY - y; // Reversed since y-coordinates go from bottom to top
5173
cameraControl.lastMouseX = x;
5274
cameraControl.lastMouseY = y;
53-
cameraControl.firstMouse = false;
54-
}
55-
56-
float xOffset = x - cameraControl.lastMouseX;
57-
float yOffset = cameraControl.lastMouseY - y; // Reversed since y-coordinates go from bottom to top
58-
cameraControl.lastMouseX = x;
59-
cameraControl.lastMouseY = y;
6075

61-
xOffset *= cameraControl.mouseSensitivity;
62-
yOffset *= cameraControl.mouseSensitivity;
76+
xOffset *= cameraControl.mouseSensitivity;
77+
yOffset *= cameraControl.mouseSensitivity;
6378

64-
cameraControl.yaw += xOffset;
65-
cameraControl.pitch += yOffset;
79+
cameraControl.yaw += xOffset;
80+
cameraControl.pitch += yOffset;
6681

67-
// Constrain pitch to avoid gimbal lock
68-
if (cameraControl.pitch > 89.0f) cameraControl.pitch = 89.0f;
69-
if (cameraControl.pitch < -89.0f) cameraControl.pitch = -89.0f;
70-
} else {
71-
cameraControl.mouseLeftPressed = false;
82+
// Constrain pitch to avoid gimbal lock
83+
if (cameraControl.pitch > 89.0f) cameraControl.pitch = 89.0f;
84+
if (cameraControl.pitch < -89.0f) cameraControl.pitch = -89.0f;
85+
} else {
86+
cameraControl.mouseLeftPressed = false;
87+
}
7288
}
7389

7490
if (imguiSystem) {
7591
imguiSystem->HandleMouse(x, y, buttons);
7692
}
93+
94+
// Always perform hover detection (even when ImGui is active)
95+
HandleMouseHover(x, y);
7796
});
7897

7998
// Set keyboard callback
@@ -104,6 +123,7 @@ bool Engine::Initialize(const std::string& appName, int width, int height, bool
104123
case GLFW_KEY_PAGE_DOWN:
105124
cameraControl.moveDown = pressed;
106125
break;
126+
default: break;
107127
}
108128

109129
if (imguiSystem) {
@@ -137,7 +157,7 @@ bool Engine::Initialize(const std::string& appName, int width, int height, bool
137157
return false;
138158
}
139159

140-
// Initialize physics system
160+
// Initialize a physics system
141161
physicsSystem->SetRenderer(renderer.get());
142162
if (!physicsSystem->Initialize()) {
143163
return false;
@@ -148,7 +168,7 @@ bool Engine::Initialize(const std::string& appName, int width, int height, bool
148168
return false;
149169
}
150170

151-
// Connect ImGui system to audio system for UI controls
171+
// Connect ImGui system to an audio system for UI controls
152172
imguiSystem->SetAudioSystem(audioSystem.get());
153173

154174
initialized = true;
@@ -207,19 +227,16 @@ void Engine::Cleanup() {
207227

208228
Entity* Engine::CreateEntity(const std::string& name) {
209229
// Check if an entity with this name already exists
210-
if (entityMap.find(name) != entityMap.end()) {
230+
if (entityMap.contains(name)) {
211231
return nullptr;
212232
}
213233

214234
// Create the entity
215235
auto entity = std::make_unique<Entity>(name);
216-
Entity* entityPtr = entity.get();
217-
218236
// Add to the map and vector
219-
entityMap[name] = entityPtr;
220237
entities.push_back(std::move(entity));
221238

222-
return entityPtr;
239+
return entities.back().get();
223240
}
224241

225242
Entity* Engine::GetEntity(const std::string& name) {
@@ -310,10 +327,7 @@ ImGuiSystem* Engine::GetImGuiSystem() const {
310327
}
311328

312329
void Engine::Update(float deltaTime) {
313-
// Check for completed background loading and create entities if ready
314-
CheckAndCreateLoadedEntities();
315-
316-
// Update physics system
330+
// Update a physics system
317331
physicsSystem->Update(deltaTime);
318332

319333
// Update audio system
@@ -380,7 +394,7 @@ float Engine::CalculateDeltaTime() {
380394
return delta / 1000.0f; // Convert to seconds
381395
}
382396

383-
void Engine::HandleResize(int width, int height) {
397+
void Engine::HandleResize(int width, int height) const {
384398
// Update the active camera's aspect ratio
385399
if (activeCamera) {
386400
activeCamera->SetAspectRatio(static_cast<float>(width) / static_cast<float>(height));
@@ -397,28 +411,28 @@ void Engine::HandleResize(int width, int height) {
397411
}
398412
}
399413

400-
void Engine::UpdateCameraControls(float deltaTime) {
414+
void Engine::UpdateCameraControls(float deltaTime) const {
401415
if (!activeCamera) return;
402416

403-
// Get camera transform component
404-
TransformComponent* cameraTransform = activeCamera->GetOwner()->GetComponent<TransformComponent>();
417+
// Get a camera transform component
418+
auto* cameraTransform = activeCamera->GetOwner()->GetComponent<TransformComponent>();
405419
if (!cameraTransform) return;
406420

407421
// Calculate movement speed
408422
float velocity = cameraControl.cameraSpeed * deltaTime;
409423

410424
// Calculate camera direction vectors based on yaw and pitch
411425
glm::vec3 front;
412-
front.x = cos(glm::radians(cameraControl.yaw)) * cos(glm::radians(cameraControl.pitch));
413-
front.y = sin(glm::radians(cameraControl.pitch));
414-
front.z = sin(glm::radians(cameraControl.yaw)) * cos(glm::radians(cameraControl.pitch));
426+
front.x = cosf(glm::radians(cameraControl.yaw)) * cosf(glm::radians(cameraControl.pitch));
427+
front.y = sinf(glm::radians(cameraControl.pitch));
428+
front.z = sinf(glm::radians(cameraControl.yaw)) * cosf(glm::radians(cameraControl.pitch));
415429
front = glm::normalize(front);
416430

417431
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f);
418432
glm::vec3 right = glm::normalize(glm::cross(front, up));
419433
up = glm::normalize(glm::cross(right, front));
420434

421-
// Get current camera position
435+
// Get the current camera position
422436
glm::vec3 position = cameraTransform->GetPosition();
423437

424438
// Apply movement based on input
@@ -444,25 +458,139 @@ void Engine::UpdateCameraControls(float deltaTime) {
444458
// Update camera position
445459
cameraTransform->SetPosition(position);
446460

447-
// Update camera target based on direction
461+
// Update camera target based on a direction
448462
glm::vec3 target = position + front;
449463
activeCamera->SetTarget(target);
450464
}
451465

452-
void Engine::CheckAndCreateLoadedEntities() {
453-
// Check if background loading is complete
454-
if (g_loadingState.loadingComplete && !g_loadingState.loadedMaterials.empty()) {
455-
// Create entities from loaded materials on the main thread
456-
CreateEntitiesFromLoadedMaterials(this);
466+
void Engine::HandleMousePoke(float mouseX, float mouseY) const {
467+
if (!activeCamera || !physicsSystem) {
468+
return;
469+
}
470+
471+
// Get window dimensions
472+
int windowWidth, windowHeight;
473+
platform->GetWindowSize(&windowWidth, &windowHeight);
474+
475+
// Convert mouse coordinates to normalized device coordinates (-1 to 1)
476+
float ndcX = (2.0f * mouseX) / static_cast<float>(windowWidth) - 1.0f;
477+
float ndcY = 1.0f - (2.0f * mouseY) / static_cast<float>(windowHeight);
478+
479+
// Get camera matrices
480+
glm::mat4 viewMatrix = activeCamera->GetViewMatrix();
481+
glm::mat4 projMatrix = activeCamera->GetProjectionMatrix();
482+
483+
// Calculate inverse matrices
484+
glm::mat4 invView = glm::inverse(viewMatrix);
485+
glm::mat4 invProj = glm::inverse(projMatrix);
486+
487+
// Convert NDC to world space
488+
glm::vec4 rayClip = glm::vec4(ndcX, ndcY, -1.0f, 1.0f);
489+
glm::vec4 rayEye = invProj * rayClip;
490+
rayEye = glm::vec4(rayEye.x, rayEye.y, -1.0f, 0.0f);
491+
glm::vec4 rayWorld = invView * rayEye;
457492

458-
// Reset the loading complete flag
459-
g_loadingState.loadingComplete = false;
493+
// Get ray origin and direction
494+
glm::vec3 rayOrigin = activeCamera->GetPosition();
495+
glm::vec3 rayDirection = glm::normalize(glm::vec3(rayWorld));
496+
497+
// Perform raycast
498+
glm::vec3 hitPosition;
499+
glm::vec3 hitNormal;
500+
Entity* hitEntity = nullptr;
501+
502+
if (physicsSystem->Raycast(rayOrigin, rayDirection, 1000.0f, &hitPosition, &hitNormal, &hitEntity)) {
503+
if (hitEntity) {
504+
std::cout << "Mouse poke hit entity: " << hitEntity->GetName() << std::endl;
505+
506+
// Find or create rigid body for the entity
507+
RigidBody* rigidBody = nullptr;
508+
509+
// Check if entity already has a rigid body (this is a simplified approach)
510+
// In a real implementation, you'd have a component system to track this
511+
rigidBody = physicsSystem->CreateRigidBody(hitEntity, CollisionShape::Box, 1.0f);
512+
513+
if (rigidBody) {
514+
// Apply a small impulse in the direction of the ray
515+
glm::vec3 impulse = rayDirection * 0.5f; // Small force magnitude as requested
516+
rigidBody->ApplyImpulse(impulse, glm::vec3(0.0f));
517+
518+
std::cout << "Applied poke impulse to " << hitEntity->GetName() << std::endl;
519+
}
520+
}
521+
} else {
522+
std::cout << "Mouse poke missed - no entity hit" << std::endl;
523+
}
524+
}
525+
526+
void Engine::HandleMouseHover(float mouseX, float mouseY) {
527+
if (!activeCamera || !physicsSystem) {
528+
return;
460529
}
461530

462-
// Check for loading errors
463-
if (g_loadingState.loadingFailed) {
464-
std::cerr << "Background loading failed: " << g_loadingState.errorMessage << std::endl;
465-
g_loadingState.loadingFailed = false; // Reset the flag
531+
// Update current mouse position
532+
currentMouseX = mouseX;
533+
currentMouseY = mouseY;
534+
535+
// Get window dimensions
536+
int windowWidth, windowHeight;
537+
platform->GetWindowSize(&windowWidth, &windowHeight);
538+
539+
// Convert mouse coordinates to normalized device coordinates (-1 to 1)
540+
float ndcX = (2.0f * mouseX) / static_cast<float>(windowWidth) - 1.0f;
541+
float ndcY = 1.0f - (2.0f * mouseY) / static_cast<float>(windowHeight);
542+
543+
// Get camera matrices
544+
glm::mat4 viewMatrix = activeCamera->GetViewMatrix();
545+
glm::mat4 projMatrix = activeCamera->GetProjectionMatrix();
546+
547+
// Calculate inverse matrices
548+
glm::mat4 invView = glm::inverse(viewMatrix);
549+
glm::mat4 invProj = glm::inverse(projMatrix);
550+
551+
// Convert NDC to world space
552+
glm::vec4 rayClip = glm::vec4(ndcX, ndcY, -1.0f, 1.0f);
553+
glm::vec4 rayEye = invProj * rayClip;
554+
rayEye = glm::vec4(rayEye.x, rayEye.y, -1.0f, 0.0f);
555+
glm::vec4 rayWorld = invView * rayEye;
556+
557+
// Get ray origin and direction
558+
glm::vec3 rayOrigin = activeCamera->GetPosition();
559+
glm::vec3 rayDirection = glm::normalize(glm::vec3(rayWorld));
560+
561+
// Perform raycast
562+
glm::vec3 hitPosition;
563+
glm::vec3 hitNormal;
564+
Entity* hitEntity = nullptr;
565+
566+
if (physicsSystem->Raycast(rayOrigin, rayDirection, 1000.0f, &hitPosition, &hitNormal, &hitEntity)) {
567+
if (hitEntity) {
568+
// Check if this entity is pokeable (has "_SMALL_POKEABLE" suffix)
569+
std::string entityName = hitEntity->GetName();
570+
571+
if (entityName.find("_SMALL_POKEABLE") != std::string::npos) {
572+
// Update a hovered entity if it's different from the current one
573+
if (hoveredEntity != hitEntity) {
574+
hoveredEntity = hitEntity;
575+
renderer->SetHighlightedEntity(hoveredEntity);
576+
std::cout << "Now hovering over pokeable entity: " << entityName << std::endl;
577+
}
578+
} else {
579+
// Clear hover if we're over a non-pokeable entity
580+
if (hoveredEntity != nullptr) {
581+
std::cout << "No longer hovering over pokeable entity" << std::endl;
582+
hoveredEntity = nullptr;
583+
renderer->SetHighlightedEntity(nullptr);
584+
}
585+
}
586+
}
587+
} else {
588+
// Clear hover if no entity is hit
589+
if (hoveredEntity != nullptr) {
590+
std::cout << "No longer hovering over pokeable entity" << std::endl;
591+
hoveredEntity = nullptr;
592+
renderer->SetHighlightedEntity(nullptr);
593+
}
466594
}
467595
}
468596

attachments/simple_engine/engine.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ class Engine {
191191
bool moveUp = false;
192192
bool moveDown = false;
193193
bool mouseLeftPressed = false;
194+
bool mouseRightPressed = false;
194195
float lastMouseX = 0.0f;
195196
float lastMouseY = 0.0f;
196197
float yaw = 0.0f; // Horizontal rotation
@@ -200,6 +201,11 @@ class Engine {
200201
float mouseSensitivity = 0.1f;
201202
} cameraControl;
202203

204+
// Hover state tracking
205+
Entity* hoveredEntity = nullptr;
206+
float currentMouseX = 0.0f;
207+
float currentMouseY = 0.0f;
208+
203209
/**
204210
* @brief Update the engine state.
205211
* @param deltaTime The time elapsed since the last update.
@@ -222,16 +228,26 @@ class Engine {
222228
* @param width The new width of the window.
223229
* @param height The new height of the window.
224230
*/
225-
void HandleResize(int width, int height);
231+
void HandleResize(int width, int height) const;
226232

227233
/**
228234
* @brief Update camera controls based on input state.
229235
* @param deltaTime The time elapsed since the last update.
230236
*/
231-
void UpdateCameraControls(float deltaTime);
237+
void UpdateCameraControls(float deltaTime) const;
232238

233239
/**
234-
* @brief Check for completed background loading and create entities if ready.
240+
* @brief Handle mouse poke interaction to apply forces to clicked objects.
241+
* @param mouseX The x-coordinate of the mouse click.
242+
* @param mouseY The y-coordinate of the mouse click.
235243
*/
236-
void CheckAndCreateLoadedEntities();
244+
void HandleMousePoke(float mouseX, float mouseY) const;
245+
246+
/**
247+
* @brief Handle mouse hover detection for highlighting pokeable entities.
248+
* @param mouseX The x-coordinate of the mouse position.
249+
* @param mouseY The y-coordinate of the mouse position.
250+
*/
251+
void HandleMouseHover(float mouseX, float mouseY);
252+
237253
};

0 commit comments

Comments
 (0)