Compare commits

..

No commits in common. "1b7b915548da503993ceebdadd8d5c2784c7fcbf" and "62c36b96600ea90eb32d9618844306a835fc4240" have entirely different histories.

21 changed files with 53 additions and 186 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,5 +1,4 @@
#include "camera_controller.h"
#include "core/camera_node.h"
#include "utils/mirror.h"
START_REFLECT(CameraController);
@ -19,11 +18,10 @@ SceneNode *CreateCameraController(Transformable target) {
CameraController *self = new(CameraController);
*self = (CameraController){
.transform = tc_null(Transformable),
.rotation_speed = 2.f,
.rotation_speed = 5.f,
.max_speed_time = 4.f,
.target = target,
.time_rotated = 0.f,
.camera = NULL,
.time_rotated = 0.f
};
SceneNode *node = CreateSceneNode(CameraController_as_SceneNodeEntity(self));
return node;
@ -36,9 +34,6 @@ void DestroyCameraController(CameraController *self) {
void CameraControllerEnterTree(CameraController *self) {
self->transform = TC_CAST(self->node->parent->entity, Transformable);
self->global = self->transform.tc->get_global_transform(self->transform.data);
SceneNode *camera_node = SceneNodeGetChildByTypeid(self->node->parent, GET_TYPEID(CameraNode), true);
self->camera = camera_node->entity.data;
self->camera->fov = 100;
}
void CameraControllerExitTree(CameraController *self) {}
@ -54,10 +49,11 @@ void CameraControllerTick(CameraController *self, double delta) {
// ... and maximum frame step size
float const step = self->rotation_speed * time_mul * delta;
if(angle > 0.f)
target.rotation = QuaternionSlerp(current.rotation, target.rotation, step);
target.rotation = QuaternionSlerp(current.rotation, target.rotation, fminf(fminf(step, angle) / angle, 0.99f));
if(step > angle && self->time_rotated > delta)
self->time_rotated -= delta;
else
self->time_rotated += delta;
self->time_rotated -= 3.f * delta;
else if(step > angle)
self->time_rotated = 0.f;
self->time_rotated += delta;
self->transform.tc->set_global_transform(self->transform.data, target);
}

View file

@ -14,7 +14,6 @@ typedef struct CameraController {
float max_speed_time;
Transformable target;
float time_rotated;
CameraNode *camera;
} CameraController;
extern SceneNode *CreateCameraController(Transformable target);

View file

@ -1,45 +0,0 @@
#include "city_generator.h"
#include "core/mesh_render_entity.h"
#include "core/transform_node.h"
static struct {
size_t x, y;
} const CITY_SIZE = {20, 20};
#define MODELS_LENGTH 4
static ModelResource models[MODELS_LENGTH] = {
ResourceEmpty(Model),
ResourceEmpty(Model),
ResourceEmpty(Model),
ResourceEmpty(Model)
};
static void Internal_LoadModelsIfRequired() {
for(size_t i = 0; i < MODELS_LENGTH; ++i)
if(models[i].handle == NULL && GetModelResource(TextFormat("building_%c", 'a' + i), &models[i]))
LoadResource(models[i].handle);
}
static SceneNode *Internal_CreateBuilding(size_t x, size_t y) {
size_t building_index = (3 * (x + y + GetRandomValue(0, 50))) % MODELS_LENGTH; // semi-random number based on the x,y coordinate
SceneNode *mesh_render_node = CreateMeshRenderEntity(TextFormat("building_%c", 'a' + building_index));
SceneNode *transform_node = CreateTransformNode();
SceneNodeAddChild(transform_node, mesh_render_node);
Transformable transform = TC_CAST(transform_node->entity, Transformable);
Transform local = transform.tc->get_transform(transform.data);
local.translation.x = (float)(x * 40);
local.translation.z = (float)(y * 40);
transform.tc->set_transform(transform.data, local);
return transform_node;
}
SceneNode *GenerateCity() {
Internal_LoadModelsIfRequired();
SceneNode *root = CreateTransformNode();
for(size_t x = 0; x < CITY_SIZE.x; ++x) {
for(size_t y = 0; y < CITY_SIZE.y; ++y) {
SceneNodeAddChild(root, Internal_CreateBuilding(x, y));
}
}
return root;
}

View file

@ -1,8 +0,0 @@
#ifndef CITY_GENERATOR_H
#define CITY_GENERATOR_H
#include "core/scene.h"
extern SceneNode *GenerateCity();
#endif // !CITY_GENERATOR_H

View file

@ -20,11 +20,6 @@ impl_SceneNodeEntity_for(CameraNode,
SceneNode *CreateCameraNode() {
CameraNode *self = new(CameraNode);
*self = (CameraNode){
.fov = 60,
.node = NULL,
.transform = tc_null(Transformable)
};
return CreateSceneNode(CameraNode_as_SceneNodeEntity(self));
}
@ -56,7 +51,7 @@ Camera3D CameraNodeGetCamera(CameraNode *self) {
Vector3 forward = MATRIX_FORWARD(mat);
// construct a new camera at the global transform location and facing the forward vector
return (Camera3D){
.fovy = self->fov,
.fovy = 90,
.position = global_transform.translation,
.projection = CAMERA_PERSPECTIVE,
.target = Vector3Add(global_transform.translation, forward),

View file

@ -10,7 +10,6 @@
typedef struct CameraNode {
SceneNode *node;
Transformable transform;
float fov;
} CameraNode;
//! Instantiate new camera node

View file

@ -54,6 +54,7 @@ void RenderNextFrame() {
BeginMode3D(CameraNodeGetCamera(camera));
list_foreach(Renderable *,object, &g_render_objects)
object->tc->draw(object->data);
DrawGrid(500, 1.f); // TODO Remove this (or make it a scene node entity)
EndMode3D();
}
DrawFPS(20, 20);

View file

@ -132,9 +132,9 @@ bool GetModelResource(char const *path, ModelResource *out) {
ResourceContainer *container = hash_map_get_as(ResourceContainer, &g_resource_map, &path);
*out = ResourceEmpty(Model);
// assert some assumptions about the found resource
ASSERT_RETURN(container != NULL, false, "GetModelResource: Resource %s not in index.", path);
ASSERT_RETURN(container->type == RESOURCE_MODEL, false, "GetModelResource: Resource %s is not a Texture.", path);
ASSERT_RETURN(strcmp(container->name, path) == 0, false, "GetModelResource: Resource %s was loaded for path %s", container->name, path);
ASSERT_RETURN(container != NULL, false, "GetTextureResource: Resource %s not in index.", path);
ASSERT_RETURN(container->type == RESOURCE_MODEL, false, "GetTextureResource: Resource %s is not a Texture.", path);
++container->use_counter;
*out = (ModelResource) {
.handle = container,
.resource = &container->model
@ -174,20 +174,16 @@ bool IsResourceLoaded(ResourceHandle handle) {
void LoadResource(ResourceHandle handle) {
ASSERT_RETURN(handle != NULL,, "LoadResource: Resource handle invalid");
if(!handle->is_loaded) {
g_load_functions[handle->type](handle);
handle->is_loaded = true;
}
g_load_functions[handle->type](handle);
handle->is_loaded = true;
++handle->use_counter;
}
void ReleaseResource(ResourceHandle handle) {
ASSERT_RETURN(handle != NULL,, "ReleaseResource: Resource handle invalid");
ASSERT_RETURN_WARN(handle->is_loaded,, "ReleaseResource: Resource %s is not loaded.", handle->path);
if(handle->use_counter == 1) {
g_unload_functions[handle->type](handle);
handle->is_loaded = false;
}
g_unload_functions[handle->type](handle);
handle->is_loaded = false;
--handle->use_counter;
}

View file

@ -170,23 +170,8 @@ SceneNode *SceneNodeGetChildByTypeclass(SceneNode *self, char const *typeclass,
SceneNodeEntity entity = (*child)->entity;
if(mirror_get_function(entity.data, entity.mirror, typeclass))
return *child;
if(recurse) {
SceneNode *recursed = SceneNodeGetChildByTypeclass(*child, typeclass, recurse);
if(recursed != NULL) return recursed;
}
}
return NULL;
}
SceneNode *SceneNodeGetChildByTypeid(SceneNode *self, typeid id, bool recurse) {
list_foreach(SceneNode **,child, &self->children) {
SceneNodeEntity entity = (*child)->entity;
if(entity.mirror->get_typeid() == id)
return *child;
if(recurse) {
SceneNode *recursed = SceneNodeGetChildByTypeid(*child, id, recurse);
if(recursed != NULL) return recursed;
}
if(recurse)
SceneNodeGetChildByTypeclass(*child, typeclass, recurse);
}
return NULL;
}

View file

@ -41,12 +41,10 @@ extern void SceneNodeRemoveChild(SceneNode *self, SceneNode *child);
extern void SceneNodeAttachEntity(SceneNode *self, SceneNodeEntity entity);
//! Detach an entity from a scene node
extern SceneNodeEntity SceneNodeDetachEntity(SceneNode *self);
//! Returns the first child node with an entity that implements a specific typeclass.
//! Returns the first child node that implements a specific typeclass.
//! Optionally recurses through the entire branch
extern SceneNode *SceneNodeGetChildByTypeclass(SceneNode *self, char const *typeclass, bool recurse);
//! Returns the first child node with an entity that matches the given typeid.
//! Optionally recurses through the entire branch.
extern SceneNode *SceneNodeGetChildByTypeid(SceneNode *self, typeid id, bool recurse);
//! Instantiate a new scene with a root node.
extern Scene *CreateScene(SceneNode *root);
//! Destroy a node and it's scene tree.

View file

@ -1,7 +1,6 @@
#include "raylib.h"
#include "player_controller.h"
#include "camera_controller.h"
#include "city_generator.h"
#include "core/input.h"
#include "core/camera_node.h"
#include "core/engine_global.h"
@ -49,7 +48,6 @@ Scene *CreateInitialScene() {
SceneNodeAddChild(root, model);
SceneNodeAddChild(root, camera_scene);
SceneNodeAddChild(camera_scene, CreateCameraController(TC_CAST(model->entity, Transformable)));
SceneNodeAddChild(root, GenerateCity());
return CreateScene(root);
}
@ -58,10 +56,7 @@ void ConfigureInput() {
AddAction("pitch_down", INPUT_LISTENER_KEY, 0, KEY_W);
AddAction("roll_left", INPUT_LISTENER_KEY, 0, KEY_A);
AddAction("roll_right", INPUT_LISTENER_KEY, 0, KEY_D);
AddAction("yaw_right", INPUT_LISTENER_KEY, 0, KEY_E);
AddAction("yaw_left", INPUT_LISTENER_KEY, 0, KEY_Q);
AddAction("brake", INPUT_LISTENER_KEY, 0, KEY_SPACE);
AddAction("boost", INPUT_LISTENER_KEY, 0, KEY_LEFT_SHIFT);
AddAction("stop", INPUT_LISTENER_KEY, 0, KEY_SPACE);
}
int main() {

View file

@ -1,8 +1,7 @@
#include "player_controller.h"
#include "core/render.h"
#include "core/input.h"
#include "utils/typeclass_helpers.h"
#include "utils/debug.h"
#include "core/input.h"
#include "raylib.h"
START_REFLECT(PlayerController);
@ -20,25 +19,10 @@ impl_SceneNodeEntity_for(PlayerController,
PlayerControllerTick
)
static float const PLAYER_BASE_SPEED = 10.f;
static float const PLAYER_BASE_ACCELERATION = 10.f;
static float const PLAYER_BOOST_SPEED = 30.f;
static float const PLAYER_BOOST_ACCELERATION = 60.f;
static float const PLAYER_BRAKE_SPEED = 0.5f;
static float const PLAYER_BRAKE_DECELERATION = 10.f;
static float const PLAYER_FALL_SPEED = 10.f;
static float const PLAYER_FALL_ACCELERATION = 10.f;
SceneNode *CreatePlayerController() {
PlayerController *self = new(PlayerController);
*self = (PlayerController) {
.node = NULL,
.transform = tc_null(Transformable),
.rotation = Vector3Zero(),
.fly_input = Vector3Zero(),
.speed = 10.f,
.brake = false
};
self->rotation = self->fly_input = Vector2Zero();
self->stopped = false;
return CreateSceneNode(PlayerController_as_SceneNodeEntity(self));
}
@ -49,42 +33,32 @@ void DestroyPlayerController(PlayerController *self) {
void PlayerControllerEnterTree(PlayerController *self) {
self->transform = TC_CAST(self->node->parent->entity, Transformable);
DisableCursor();
AddListener("pitch_up", ButtonInputListener(self, PlayerControllerInputPitchUp));
AddListener("pitch_down", ButtonInputListener(self, PlayerControllerInputPitchDown));
AddListener("roll_left", ButtonInputListener(self, PlayerControllerInputRollLeft));
AddListener("roll_right", ButtonInputListener(self, PlayerControllerInputRollRight));
AddListener("yaw_left", ButtonInputListener(self, PlayerControllerInputYawLeft));
AddListener("yaw_right", ButtonInputListener(self, PlayerControllerInputYawRight));
AddListener("brake", ButtonInputListener(self, PlayerControllerInputBrake));
AddListener("boost", ButtonInputListener(self, PlayerControllerInputBoost));
AddListener("pitch_up", ButtonInputListener(self, PlayerControllerUpInput));
AddListener("pitch_down", ButtonInputListener(self, PlayerControllerDownInput));
AddListener("roll_left", ButtonInputListener(self, PlayerControllerLeftInput));
AddListener("roll_right", ButtonInputListener(self, PlayerControllerRightInput));
AddListener("stop", ButtonInputListener(self, PlayerControllerStopInput));
}
void PlayerControllerExitTree(PlayerController *self) {
RemoveAllListeners(self);
}
static
float MoveTowards(float from, float to, float delta) {
if(from == to) return to;
float const diff = to - from;
float const sign = signbit(diff) ? -1.f : 1.f;
return from + sign * fminf(delta, fabsf(diff));
}
//! angular acceleration limited to local X and Z axes
static
void PlayerControllerTickAngularAcceleration(PlayerController *self, double delta) {
self->rotation.x = MoveTowards(self->rotation.x, self->fly_input.x, delta * 4.f);
self->rotation.y = MoveTowards(self->rotation.y, self->fly_input.y, delta * 4.f);
self->rotation.z = MoveTowards(self->rotation.z, self->fly_input.z, delta * 4.f);
Vector2 diff = Vector2Subtract(self->fly_input, self->rotation);
float const length = Vector2Length(diff);
if(length != 0.f)
self->rotation = Vector2Add(self->rotation, Vector2Scale(diff, 1.0f/length * fminf(4.f * delta, length)));
}
//! linear acceleration limited to the local Z axis
static
void PlayerControllerTickLinearAcceleration(PlayerController *self, double delta) {
float const target = self->brake ? PLAYER_BRAKE_SPEED : (self->boost ? PLAYER_BOOST_SPEED : PLAYER_BASE_SPEED);
float const acceleration = target < self->speed ? PLAYER_BRAKE_DECELERATION : (self->boost ? PLAYER_BOOST_ACCELERATION : PLAYER_BASE_ACCELERATION);
self->speed = MoveTowards(self->speed, target, delta * acceleration);
float const target = self->stopped ? 10.f : (self->rotation.y == 0.f ? 30.f : 20.f);
float const speed_diff = target - self->speed;
self->speed = self->speed + copysignf(fminf(fabsf(speed_diff), 10.f * delta), speed_diff);
}
//! Update linear transform based on velocities
@ -92,11 +66,9 @@ static
void PlayerControllerTickTransform(PlayerController *self, double delta) {
Transform global_transform = self->transform.tc->get_global_transform(self->transform.data);
Matrix global_matrix = TransformGetMatrix(global_transform);
float const rotate_speed = 1.f - 0.9f * self->speed / PLAYER_BOOST_SPEED;
global_transform.translation = Vector3Add(global_transform.translation, Vector3Scale(MATRIX_FORWARD(global_matrix), self->speed * delta));
global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_FORWARD(global_matrix), self->rotation.x * 1.25f * delta), global_transform.rotation);
global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_RIGHT(global_matrix), self->rotation.y * rotate_speed * 3.75f * delta), global_transform.rotation);
global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_UP(global_matrix), self->rotation.z * rotate_speed * 1.f * delta), global_transform.rotation);
global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_FORWARD(global_matrix), self->rotation.x * 2.f * delta), global_transform.rotation);
global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_RIGHT(global_matrix), self->rotation.y * 2.5f * delta), global_transform.rotation);
self->transform.tc->set_global_transform(self->transform.data, global_transform);
}
@ -106,34 +78,22 @@ void PlayerControllerTick(PlayerController *self, double delta) {
PlayerControllerTickTransform(self, delta);
}
void PlayerControllerInputRollLeft(PlayerController *self, bool value) {
void PlayerControllerLeftInput(PlayerController *self, bool value) {
self->fly_input.x += value ? -1 : +1;
}
void PlayerControllerInputRollRight(PlayerController *self, bool value) {
void PlayerControllerRightInput(PlayerController *self, bool value) {
self->fly_input.x += value ? +1 : -1;
}
void PlayerControllerInputPitchUp(PlayerController *self, bool value) {
void PlayerControllerUpInput(PlayerController *self, bool value) {
self->fly_input.y += value ? -1 : +1;
}
void PlayerControllerInputPitchDown(PlayerController *self, bool value) {
void PlayerControllerDownInput(PlayerController *self, bool value) {
self->fly_input.y += value ? +1 : -1;
}
void PlayerControllerInputYawRight(PlayerController *self, bool value) {
self->fly_input.z += value ? -1 : +1;
}
void PlayerControllerInputYawLeft(PlayerController *self, bool value) {
self->fly_input.z += value ? +1 : -1;
}
void PlayerControllerInputBrake(PlayerController *self, bool value) {
self->brake = value;
}
void PlayerControllerInputBoost(PlayerController *self, bool value) {
self->boost = value;
void PlayerControllerStopInput(PlayerController *self, bool value) {
self->stopped = value;
}

View file

@ -12,11 +12,10 @@
typedef struct PlayerController {
SceneNode *node;
Transformable transform;
Vector3 fly_input;
Vector3 rotation;
Vector2 fly_input;
Vector2 rotation;
float speed;
bool brake;
bool boost;
bool stopped;
} PlayerController;
SceneNode *CreatePlayerController();
@ -26,14 +25,11 @@ extern void PlayerControllerEnterTree(PlayerController *self);
extern void PlayerControllerExitTree(PlayerController *self);
extern void PlayerControllerTick(PlayerController *self, double delta);
extern void PlayerControllerInputRollLeft(PlayerController *self, bool value);
extern void PlayerControllerInputRollRight(PlayerController *self, bool value);
extern void PlayerControllerInputPitchUp(PlayerController *self, bool value);
extern void PlayerControllerInputPitchDown(PlayerController *self, bool value);
extern void PlayerControllerInputYawRight(PlayerController *self, bool value);
extern void PlayerControllerInputYawLeft(PlayerController *self, bool value);
extern void PlayerControllerInputBrake(PlayerController *self, bool value);
extern void PlayerControllerInputBoost(PlayerController *self, bool value);
extern void PlayerControllerLeftInput(PlayerController *self, bool value);
extern void PlayerControllerRightInput(PlayerController *self, bool value);
extern void PlayerControllerUpInput(PlayerController *self, bool value);
extern void PlayerControllerDownInput(PlayerController *self, bool value);
extern void PlayerControllerStopInput(PlayerController *self, bool value);
DECL_REFLECT(PlayerController);
decl_typeclass_impl(SceneNodeEntity, PlayerController);

@ -1 +1 @@
Subproject commit bb201d5085cfb2e54ebad9a0bf22347a5251f7a2
Subproject commit faf0463e3791ee97dfc370282ecad4cd3b4ca475