134 lines
4.1 KiB
C
134 lines
4.1 KiB
C
![]() |
#pragma once
|
||
|
/*
|
||
|
Quick'n'dirty Maya-style camera. Include after HandmadeMath.h
|
||
|
and sokol_app.h
|
||
|
*/
|
||
|
#include <string.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
#define CAMERA_DEFAULT_MIN_DIST (2.0f)
|
||
|
#define CAMERA_DEFAULT_MAX_DIST (30.0f)
|
||
|
#define CAMERA_DEFAULT_MIN_LAT (-85.0f)
|
||
|
#define CAMERA_DEFAULT_MAX_LAT (85.0f)
|
||
|
#define CAMERA_DEFAULT_DIST (5.0f)
|
||
|
#define CAMERA_DEFAULT_ASPECT (60.0f)
|
||
|
#define CAMERA_DEFAULT_NEARZ (0.01f)
|
||
|
#define CAMERA_DEFAULT_FARZ (100.0f)
|
||
|
|
||
|
typedef struct {
|
||
|
float min_dist;
|
||
|
float max_dist;
|
||
|
float min_lat;
|
||
|
float max_lat;
|
||
|
float distance;
|
||
|
float latitude;
|
||
|
float longitude;
|
||
|
float aspect;
|
||
|
float nearz;
|
||
|
float farz;
|
||
|
hmm_vec3 center;
|
||
|
} camera_desc_t;
|
||
|
|
||
|
typedef struct {
|
||
|
float min_dist;
|
||
|
float max_dist;
|
||
|
float min_lat;
|
||
|
float max_lat;
|
||
|
float distance;
|
||
|
float latitude;
|
||
|
float longitude;
|
||
|
float aspect;
|
||
|
float nearz;
|
||
|
float farz;
|
||
|
hmm_vec3 center;
|
||
|
hmm_vec3 eye_pos;
|
||
|
hmm_mat4 view;
|
||
|
hmm_mat4 proj;
|
||
|
hmm_mat4 view_proj;
|
||
|
} camera_t;
|
||
|
|
||
|
static float _cam_def(float val, float def) {
|
||
|
return ((val == 0.0f) ? def:val);
|
||
|
}
|
||
|
|
||
|
/* initialize to default parameters */
|
||
|
static void cam_init(camera_t* cam, const camera_desc_t* desc) {
|
||
|
assert(cam && desc);
|
||
|
memset(cam, 0, sizeof(camera_t));
|
||
|
cam->min_dist = _cam_def(desc->min_dist, CAMERA_DEFAULT_MIN_DIST);
|
||
|
cam->max_dist = _cam_def(desc->max_dist, CAMERA_DEFAULT_MAX_DIST);
|
||
|
cam->min_lat = _cam_def(desc->min_lat, CAMERA_DEFAULT_MIN_LAT);
|
||
|
cam->max_lat = _cam_def(desc->max_lat, CAMERA_DEFAULT_MAX_LAT);
|
||
|
cam->distance = _cam_def(desc->distance, CAMERA_DEFAULT_DIST);
|
||
|
cam->center = desc->center;
|
||
|
cam->latitude = desc->latitude;
|
||
|
cam->longitude = desc->longitude;
|
||
|
cam->aspect = _cam_def(desc->aspect, CAMERA_DEFAULT_ASPECT);
|
||
|
cam->nearz = _cam_def(desc->nearz, CAMERA_DEFAULT_NEARZ);
|
||
|
cam->farz = _cam_def(desc->farz, CAMERA_DEFAULT_FARZ);
|
||
|
}
|
||
|
|
||
|
/* feed mouse movement */
|
||
|
static void cam_orbit(camera_t* cam, float dx, float dy) {
|
||
|
assert(cam);
|
||
|
cam->longitude -= dx;
|
||
|
if (cam->longitude < 0.0f) {
|
||
|
cam->longitude += 360.0f;
|
||
|
}
|
||
|
if (cam->longitude > 360.0f) {
|
||
|
cam->longitude -= 360.0f;
|
||
|
}
|
||
|
cam->latitude = HMM_Clamp(cam->min_lat, cam->latitude + dy, cam->max_lat);
|
||
|
}
|
||
|
|
||
|
/* feed zoom (mouse wheel) input */
|
||
|
static void cam_zoom(camera_t* cam, float d) {
|
||
|
assert(cam);
|
||
|
cam->distance = HMM_Clamp(cam->min_dist, cam->distance + d, cam->max_dist);
|
||
|
}
|
||
|
|
||
|
static hmm_vec3 _cam_euclidean(float latitude, float longitude) {
|
||
|
const float lat = HMM_ToRadians(latitude);
|
||
|
const float lng = HMM_ToRadians(longitude);
|
||
|
return HMM_Vec3(cosf(lat) * sinf(lng), sinf(lat), cosf(lat) * cosf(lng));
|
||
|
}
|
||
|
|
||
|
/* update the view, proj and view_proj matrix */
|
||
|
static void cam_update(camera_t* cam, int fb_width, int fb_height) {
|
||
|
assert(cam);
|
||
|
assert((fb_width > 0) && (fb_height > 0));
|
||
|
const float w = (float) fb_width;
|
||
|
const float h = (float) fb_height;
|
||
|
cam->eye_pos = HMM_AddVec3(cam->center, HMM_MultiplyVec3f(_cam_euclidean(cam->latitude, cam->longitude), cam->distance));
|
||
|
cam->view = HMM_LookAt(cam->eye_pos, cam->center, HMM_Vec3(0.0f, 1.0f, 0.0f));
|
||
|
cam->proj = HMM_Perspective(cam->aspect, w/h, cam->nearz, cam->farz);
|
||
|
cam->view_proj = HMM_MultiplyMat4(cam->proj, cam->view);
|
||
|
}
|
||
|
|
||
|
/* handle sokol-app input events */
|
||
|
//static void cam_handle_event(camera_t* cam, const sapp_event* ev) {
|
||
|
// assert(cam);
|
||
|
// switch (ev->type) {
|
||
|
// case SAPP_EVENTTYPE_MOUSE_DOWN:
|
||
|
// if (ev->mouse_button == SAPP_MOUSEBUTTON_LEFT) {
|
||
|
// sapp_lock_mouse(true);
|
||
|
// }
|
||
|
// break;
|
||
|
// case SAPP_EVENTTYPE_MOUSE_UP:
|
||
|
// if (ev->mouse_button == SAPP_MOUSEBUTTON_LEFT) {
|
||
|
// sapp_lock_mouse(false);
|
||
|
// }
|
||
|
// break;
|
||
|
// case SAPP_EVENTTYPE_MOUSE_SCROLL:
|
||
|
// cam_zoom(cam, ev->scroll_y * 0.5f);
|
||
|
// break;
|
||
|
// case SAPP_EVENTTYPE_MOUSE_MOVE:
|
||
|
// if (sapp_mouse_locked()) {
|
||
|
// cam_orbit(cam, ev->mouse_dx * 0.25f, ev->mouse_dy * 0.25f);
|
||
|
// }
|
||
|
// break;
|
||
|
// default:
|
||
|
// break;
|
||
|
// }
|
||
|
//}
|