#pragma once /* Quick'n'dirty Maya-style camera. Include after HandmadeMath.h and sokol_app.h */ #include #include #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; // } //}