initial work to split into dart_filament and flutter_filament
This commit is contained in:
638
dart_filament/native/src/DartFilamentApi.cpp
Normal file
638
dart_filament/native/src/DartFilamentApi.cpp
Normal file
@@ -0,0 +1,638 @@
|
||||
#include "ResourceBuffer.hpp"
|
||||
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "filament/LightManager.h"
|
||||
#include "Log.hpp"
|
||||
#include "ThreadPool.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
using namespace flutter_filament;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include "DartFilamentApi.h"
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT const void *create_filament_viewer(const void *context, const ResourceLoaderWrapper *const loader, void *const platform, const char *uberArchivePath)
|
||||
{
|
||||
return (const void *)new FilamentViewer(context, (const ResourceLoaderWrapperImpl *const)loader, platform, uberArchivePath);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void create_render_target(const void *const viewer, intptr_t texture, uint32_t width, uint32_t height)
|
||||
{
|
||||
((FilamentViewer *)viewer)->createRenderTarget(texture, width, height);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void destroy_filament_viewer(const void *const viewer)
|
||||
{
|
||||
delete ((FilamentViewer *)viewer);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_background_color(const void *const viewer, const float r, const float g, const float b, const float a)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundColor(r, g, b, a);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void clear_background_image(const void *const viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->clearBackgroundImage();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_background_image(const void *const viewer, const char *path, bool fillHeight)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundImage(path, fillHeight);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_background_image_position(const void *const viewer, float x, float y, bool clamp)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundImagePosition(x, y, clamp);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_tone_mapping(const void *const viewer, int toneMapping)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setToneMapping((ToneMapping)toneMapping);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_bloom(const void *const viewer, float strength)
|
||||
{
|
||||
Log("Setting bloom to %f", strength);
|
||||
((FilamentViewer *)viewer)->setBloom(strength);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void load_skybox(const void *const viewer, const char *skyboxPath)
|
||||
{
|
||||
((FilamentViewer *)viewer)->loadSkybox(skyboxPath);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void load_ibl(const void *const viewer, const char *iblPath, float intensity)
|
||||
{
|
||||
((FilamentViewer *)viewer)->loadIbl(iblPath, intensity);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void rotate_ibl(const void *const viewer, float *rotationMatrix)
|
||||
{
|
||||
math::mat3f matrix(rotationMatrix[0], rotationMatrix[1],
|
||||
rotationMatrix[2],
|
||||
rotationMatrix[3],
|
||||
rotationMatrix[4],
|
||||
rotationMatrix[5],
|
||||
rotationMatrix[6],
|
||||
rotationMatrix[7],
|
||||
rotationMatrix[8]);
|
||||
|
||||
((FilamentViewer *)viewer)->rotateIbl(matrix);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void remove_skybox(const void *const viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeSkybox();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void remove_ibl(const void *const viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeIbl();
|
||||
}
|
||||
|
||||
EntityId add_light(const void *const viewer, uint8_t type, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->addLight((LightManager::Type)type, colour, intensity, posX, posY, posZ, dirX, dirY, dirZ, shadows);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void remove_light(const void *const viewer, int32_t entityId)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeLight(entityId);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void clear_lights(const void *const viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->clearLights();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT EntityId load_glb(void *sceneManager, const char *assetPath, int numInstances)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->loadGlb(assetPath, numInstances);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT EntityId load_glb_from_buffer(void *sceneManager, const void *const data, size_t length)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->loadGlbFromBuffer((const uint8_t *)data, length);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT EntityId create_instance(void *sceneManager, EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->createInstance(entityId);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT int get_instance_count(void *sceneManager, EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getInstanceCount(entityId);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void get_instances(void *sceneManager, EntityId entityId, EntityId *out)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getInstances(entityId, out);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT EntityId load_gltf(void *sceneManager, const char *assetPath, const char *relativePath)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->loadGltf(assetPath, relativePath);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_main_camera(const void *const viewer)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->setMainCamera();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT EntityId get_main_camera(const void *const viewer)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->getMainCamera();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT bool set_camera(const void *const viewer, EntityId asset, const char *nodeName)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->setCamera(asset, nodeName);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_camera_fov(const void *const viewer, float fovInDegrees, float aspect)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->setCameraFov(double(fovInDegrees), double(aspect));
|
||||
}
|
||||
|
||||
const double *const get_camera_model_matrix(const void *const viewer)
|
||||
{
|
||||
const auto &modelMatrix = ((FilamentViewer *)viewer)->getCameraModelMatrix();
|
||||
double *array = (double *)calloc(16, sizeof(double));
|
||||
memcpy(array, modelMatrix.asArray(), 16 * sizeof(double));
|
||||
return array;
|
||||
}
|
||||
|
||||
const double *const get_camera_view_matrix(const void *const viewer)
|
||||
{
|
||||
const auto &matrix = ((FilamentViewer *)viewer)->getCameraViewMatrix();
|
||||
double *array = (double *)calloc(16, sizeof(double));
|
||||
memcpy(array, matrix.asArray(), 16 * sizeof(double));
|
||||
return array;
|
||||
}
|
||||
|
||||
const double *const get_camera_projection_matrix(const void *const viewer)
|
||||
{
|
||||
const auto &matrix = ((FilamentViewer *)viewer)->getCameraProjectionMatrix();
|
||||
double *array = (double *)calloc(16, sizeof(double));
|
||||
memcpy(array, matrix.asArray(), 16 * sizeof(double));
|
||||
return array;
|
||||
}
|
||||
|
||||
const double *const get_camera_culling_projection_matrix(const void *const viewer)
|
||||
{
|
||||
const auto &matrix = ((FilamentViewer *)viewer)->getCameraCullingProjectionMatrix();
|
||||
double *array = (double *)calloc(16, sizeof(double));
|
||||
memcpy(array, matrix.asArray(), 16 * sizeof(double));
|
||||
return array;
|
||||
}
|
||||
|
||||
void set_camera_projection_matrix(const void *const viewer, const double *const matrix, double near, double far)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setCameraProjectionMatrix(matrix, near, far);
|
||||
}
|
||||
|
||||
void set_camera_culling(const void *const viewer, double near, double far)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setCameraCulling(near, far);
|
||||
}
|
||||
|
||||
double get_camera_culling_near(const void *const viewer)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->getCameraCullingNear();
|
||||
}
|
||||
|
||||
double get_camera_culling_far(const void *const viewer)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->getCameraCullingFar();
|
||||
}
|
||||
|
||||
const double *const get_camera_frustum(const void *const viewer)
|
||||
{
|
||||
const auto frustum = ((FilamentViewer *)viewer)->getCameraFrustum();
|
||||
const math::float4 *planes = frustum.getNormalizedPlanes();
|
||||
double *array = (double *)calloc(24, sizeof(double));
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
auto plane = planes[i];
|
||||
array[i * 4] = double(plane.x);
|
||||
array[i * 4 + 1] = double(plane.y);
|
||||
array[i * 4 + 2] = double(plane.z);
|
||||
array[i * 4 + 3] = double(plane.w);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_camera_manipulator_options(const void *const viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setCameraManipulatorOptions((filament::camutils::Mode)mode, orbitSpeedX, orbitSpeedY, zoomSpeed);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_view_frustum_culling(const void *const viewer, bool enabled)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setViewFrustumCulling(enabled);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void move_camera_to_asset(const void *const viewer, EntityId asset)
|
||||
{
|
||||
((FilamentViewer *)viewer)->moveCameraToAsset(asset);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_camera_focus_distance(const void *const viewer, float distance)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setCameraFocusDistance(distance);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_camera_exposure(const void *const viewer, float aperture, float shutterSpeed, float sensitivity)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setCameraExposure(aperture, shutterSpeed, sensitivity);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_camera_position(const void *const viewer, float x, float y, float z)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setCameraPosition(x, y, z);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_camera_rotation(const void *const viewer, float w, float x, float y, float z)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setCameraRotation(w, x, y, z);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_camera_model_matrix(const void *const viewer, const float *const matrix)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setCameraModelMatrix(matrix);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_camera_focal_length(const void *const viewer, float focalLength)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setCameraFocalLength(focalLength);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void render(
|
||||
const void *const viewer,
|
||||
uint64_t frameTimeInNanos,
|
||||
void *pixelBuffer,
|
||||
void (*callback)(void *buf, size_t size, void *data),
|
||||
void *data)
|
||||
{
|
||||
((FilamentViewer *)viewer)->render(frameTimeInNanos, pixelBuffer, callback, data);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_frame_interval(
|
||||
const void *const viewer,
|
||||
float frameInterval)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setFrameInterval(frameInterval);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void destroy_swap_chain(const void *const viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->destroySwapChain();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void create_swap_chain(const void *const viewer, const void *const window, uint32_t width, uint32_t height)
|
||||
{
|
||||
((FilamentViewer *)viewer)->createSwapChain(window, width, height);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void update_viewport_and_camera_projection(const void *const viewer, uint32_t width, uint32_t height, float scaleFactor)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->updateViewportAndCameraProjection(width, height, scaleFactor);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void scroll_update(const void *const viewer, float x, float y, float delta)
|
||||
{
|
||||
((FilamentViewer *)viewer)->scrollUpdate(x, y, delta);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void scroll_begin(const void *const viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->scrollBegin();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void scroll_end(const void *const viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->scrollEnd();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void grab_begin(const void *const viewer, float x, float y, bool pan)
|
||||
{
|
||||
((FilamentViewer *)viewer)->grabBegin(x, y, pan);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void grab_update(const void *const viewer, float x, float y)
|
||||
{
|
||||
((FilamentViewer *)viewer)->grabUpdate(x, y);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void grab_end(const void *const viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->grabEnd();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void *get_scene_manager(const void *const viewer)
|
||||
{
|
||||
return (void *)((FilamentViewer *)viewer)->getSceneManager();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void apply_weights(
|
||||
void *sceneManager,
|
||||
EntityId asset,
|
||||
const char *const entityName,
|
||||
float *const weights,
|
||||
int count)
|
||||
{
|
||||
// ((SceneManager*)sceneManager)->setMorphTargetWeights(asset, entityName, weights, count);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT bool set_morph_target_weights(
|
||||
void *sceneManager,
|
||||
EntityId asset,
|
||||
const float *const weights,
|
||||
const int numWeights)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->setMorphTargetWeights(asset, weights, numWeights);
|
||||
}
|
||||
|
||||
bool set_morph_animation(
|
||||
void *sceneManager,
|
||||
EntityId asset,
|
||||
const float *const morphData,
|
||||
const int *const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->setMorphAnimationBuffer(asset, morphData, morphIndices, numMorphTargets, numFrames, frameLengthInMs);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose(void *sceneManager, EntityId entityId)
|
||||
{
|
||||
((SceneManager *)sceneManager)->resetBones(entityId);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void add_bone_animation(
|
||||
void *sceneManager,
|
||||
EntityId asset,
|
||||
const float *const frameData,
|
||||
int numFrames,
|
||||
const char *const boneName,
|
||||
const char **const meshNames,
|
||||
int numMeshTargets,
|
||||
float frameLengthInMs,
|
||||
bool isModelSpace)
|
||||
{
|
||||
((SceneManager *)sceneManager)->addBoneAnimation(asset, frameData, numFrames, boneName, meshNames, numMeshTargets, frameLengthInMs, isModelSpace);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_post_processing(void *const viewer, bool enabled)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setPostProcessing(enabled);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_antialiasing(void *const viewer, bool msaa, bool fxaa, bool taa)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setAntiAliasing(msaa, fxaa, taa);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT bool set_bone_transform(
|
||||
void *sceneManager,
|
||||
EntityId entityId,
|
||||
const char *entityName,
|
||||
const float *const transform,
|
||||
const char *boneName)
|
||||
{
|
||||
|
||||
auto matrix = math::mat4f(
|
||||
transform[0], transform[1], transform[2],
|
||||
transform[3],
|
||||
transform[4],
|
||||
transform[5],
|
||||
transform[6],
|
||||
transform[7],
|
||||
transform[8],
|
||||
transform[9],
|
||||
transform[10],
|
||||
transform[11],
|
||||
transform[12],
|
||||
transform[13],
|
||||
transform[14],
|
||||
transform[15]);
|
||||
return ((SceneManager *)sceneManager)->setBoneTransform(entityId, entityName, 0, boneName, matrix);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void play_animation(
|
||||
void *sceneManager,
|
||||
EntityId asset,
|
||||
int index,
|
||||
bool loop,
|
||||
bool reverse,
|
||||
bool replaceActive,
|
||||
float crossfade)
|
||||
{
|
||||
((SceneManager *)sceneManager)->playAnimation(asset, index, loop, reverse, replaceActive, crossfade);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_animation_frame(
|
||||
void *sceneManager,
|
||||
EntityId asset,
|
||||
int animationIndex,
|
||||
int animationFrame)
|
||||
{
|
||||
// ((SceneManager*)sceneManager)->setAnimationFrame(asset, animationIndex, animationFrame);
|
||||
}
|
||||
|
||||
float get_animation_duration(void *sceneManager, EntityId asset, int animationIndex)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getAnimationDuration(asset, animationIndex);
|
||||
}
|
||||
|
||||
int get_animation_count(
|
||||
void *sceneManager,
|
||||
EntityId asset)
|
||||
{
|
||||
auto names = ((SceneManager *)sceneManager)->getAnimationNames(asset);
|
||||
return (int)names->size();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void get_animation_name(
|
||||
void *sceneManager,
|
||||
EntityId asset,
|
||||
char *const outPtr,
|
||||
int index)
|
||||
{
|
||||
auto names = ((SceneManager *)sceneManager)->getAnimationNames(asset);
|
||||
std::string name = names->at(index);
|
||||
strcpy(outPtr, name.c_str());
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT int get_morph_target_name_count(void *sceneManager, EntityId asset, const char *meshName)
|
||||
{
|
||||
auto names = ((SceneManager *)sceneManager)->getMorphTargetNames(asset, meshName);
|
||||
return (int)names->size();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void get_morph_target_name(void *sceneManager, EntityId asset, const char *meshName, char *const outPtr, int index)
|
||||
{
|
||||
auto names = ((SceneManager *)sceneManager)->getMorphTargetNames(asset, meshName);
|
||||
std::string name = names->at(index);
|
||||
strcpy(outPtr, name.c_str());
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void remove_entity(const void *const viewer, EntityId asset)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeEntity(asset);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void clear_entities(const void *const viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->clearEntities();
|
||||
}
|
||||
|
||||
bool set_material_color(void *sceneManager, EntityId asset, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->setMaterialColor(asset, meshName, materialIndex, r, g, b, a);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void transform_to_unit_cube(void *sceneManager, EntityId asset)
|
||||
{
|
||||
((SceneManager *)sceneManager)->transformToUnitCube(asset);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_position(void *sceneManager, EntityId asset, float x, float y, float z)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setPosition(asset, x, y, z);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_rotation(void *sceneManager, EntityId asset, float rads, float x, float y, float z, float w)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setRotation(asset, rads, x, y, z, w);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_scale(void *sceneManager, EntityId asset, float scale)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setScale(asset, scale);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void queue_position_update(void *sceneManager, EntityId asset, float x, float y, float z, bool relative)
|
||||
{
|
||||
((SceneManager *)sceneManager)->queuePositionUpdate(asset, x, y, z, relative);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void queue_rotation_update(void *sceneManager, EntityId asset, float rads, float x, float y, float z, float w, bool relative)
|
||||
{
|
||||
((SceneManager *)sceneManager)->queueRotationUpdate(asset, rads, x, y, z, w, relative);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void stop_animation(void *sceneManager, EntityId asset, int index)
|
||||
{
|
||||
((SceneManager *)sceneManager)->stopAnimation(asset, index);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT int hide_mesh(void *sceneManager, EntityId asset, const char *meshName)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->hide(asset, meshName);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT int reveal_mesh(void *sceneManager, EntityId asset, const char *meshName)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->reveal(asset, meshName);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void pick(void *const viewer, int x, int y, void (*callback)(EntityId entityId, int x, int y))
|
||||
{
|
||||
((FilamentViewer *)viewer)->pick(static_cast<uint32_t>(x), static_cast<uint32_t>(y), callback);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT const char *get_name_for_entity(void *const sceneManager, const EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getNameForEntity(entityId);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT int get_entity_count(void *const sceneManager, const EntityId target, bool renderableOnly)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getEntityCount(target, renderableOnly);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void get_entities(void *const sceneManager, const EntityId target, bool renderableOnly, EntityId *out)
|
||||
{
|
||||
((SceneManager *)sceneManager)->getEntities(target, renderableOnly, out);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT const char *get_entity_name_at(void *const sceneManager, const EntityId target, int index, bool renderableOnly)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getEntityNameAt(target, index, renderableOnly);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_recording(void *const viewer, bool recording)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setRecording(recording);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_recording_output_directory(void *const viewer, const char *outputDirectory)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setRecordingOutputDirectory(outputDirectory);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void ios_dummy()
|
||||
{
|
||||
Log("Dummy called");
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void flutter_filament_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void add_collision_component(void *const sceneManager, EntityId entityId, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform)
|
||||
{
|
||||
((SceneManager *)sceneManager)->addCollisionComponent(entityId, onCollisionCallback, affectsCollidingTransform);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void remove_collision_component(void *const sceneManager, EntityId entityId)
|
||||
{
|
||||
((SceneManager *)sceneManager)->removeCollisionComponent(entityId);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT bool add_animation_component(void *const sceneManager, EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->addAnimationComponent(entityId);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT EntityId create_geometry(void *const viewer, float *vertices, int numVertices, uint16_t *indices, int numIndices, int primitiveType, const char *materialPath)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->createGeometry(vertices, (uint32_t)numVertices, indices, numIndices, (filament::RenderableManager::PrimitiveType)primitiveType, materialPath);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT EntityId find_child_entity_by_name(void *const sceneManager, const EntityId parent, const char *name)
|
||||
{
|
||||
auto entity = ((SceneManager *)sceneManager)->findChildEntityByName(parent, name);
|
||||
return utils::Entity::smuggle(entity);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_parent(void *const sceneManager, EntityId child, EntityId parent)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setParent(child, parent);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void test_collisions(void *const sceneManager, EntityId entity)
|
||||
{
|
||||
((SceneManager *)sceneManager)->testCollisions(entity);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_priority(void *const sceneManager, EntityId entity, int priority)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setPriority(entity, priority);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void get_gizmo(void *const sceneManager, EntityId *out)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getGizmo(out);
|
||||
}
|
||||
}
|
||||
655
dart_filament/native/src/DartFilamentFFIApi.cpp
Normal file
655
dart_filament/native/src/DartFilamentFFIApi.cpp
Normal file
@@ -0,0 +1,655 @@
|
||||
|
||||
#include "DartFilamentFFIApi.h"
|
||||
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "Log.hpp"
|
||||
#include "ThreadPool.hpp"
|
||||
#include "filament/LightManager.h"
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
#include <emscripten/threading.h>
|
||||
#include <emscripten/val.h>
|
||||
|
||||
#include <emscripten/threading.h>
|
||||
#include <emscripten/val.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern FLUTTER_PLUGIN_EXPORT EMSCRIPTEN_WEBGL_CONTEXT_HANDLE flutter_filament_web_create_gl_context();
|
||||
}
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
using namespace flutter_filament;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class RenderLoop
|
||||
{
|
||||
public:
|
||||
explicit RenderLoop()
|
||||
{
|
||||
_t = new std::thread([this]()
|
||||
{
|
||||
auto last = std::chrono::high_resolution_clock::now();
|
||||
while (!_stop) {
|
||||
|
||||
if (_rendering) {
|
||||
// auto frameStart = std::chrono::high_resolution_clock::now();
|
||||
doRender();
|
||||
// auto frameEnd = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
last = std::chrono::high_resolution_clock::now();
|
||||
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
|
||||
float elapsed = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - last).count());
|
||||
|
||||
std::function<void()> task;
|
||||
|
||||
std::unique_lock<std::mutex> lock(_access);
|
||||
|
||||
if(_tasks.empty()) {
|
||||
_cond.wait_for(lock, std::chrono::duration<float, std::milli>(1));
|
||||
}
|
||||
while(!_tasks.empty()) {
|
||||
task = std::move(_tasks.front());
|
||||
_tasks.pop_front();
|
||||
task();
|
||||
}
|
||||
|
||||
now = std::chrono::high_resolution_clock::now();
|
||||
elapsed = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - last).count());
|
||||
if(elapsed < _frameIntervalInMilliseconds) {
|
||||
auto sleepFor = std::chrono::microseconds(int(_frameIntervalInMilliseconds - elapsed) * 1000);
|
||||
std::this_thread::sleep_for(sleepFor);
|
||||
}
|
||||
} });
|
||||
}
|
||||
~RenderLoop()
|
||||
{
|
||||
_stop = true;
|
||||
_t->join();
|
||||
}
|
||||
|
||||
void createViewer(void *const context, void *const platform,
|
||||
const char *uberArchivePath,
|
||||
const ResourceLoaderWrapperImpl *const loader,
|
||||
void (*renderCallback)(void *),
|
||||
void *const owner,
|
||||
void (*callback)(void *const))
|
||||
{
|
||||
_renderCallback = renderCallback;
|
||||
_renderCallbackOwner = owner;
|
||||
std::packaged_task<FilamentViewer *()> lambda([=]() mutable
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
auto emContext = flutter_filament_web_create_gl_context();
|
||||
|
||||
auto success = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)emContext);
|
||||
if(success != EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
std::cout << "Failed to make context current." << std::endl;
|
||||
return (FilamentViewer*)nullptr;
|
||||
}
|
||||
_viewer = new FilamentViewer((void* const) emContext, loader, platform, uberArchivePath);
|
||||
#else
|
||||
_viewer = new FilamentViewer(context, loader, platform, uberArchivePath);
|
||||
#endif
|
||||
callback(_viewer);
|
||||
return _viewer; });
|
||||
auto fut = add_task(lambda);
|
||||
}
|
||||
|
||||
void destroyViewer()
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
_rendering = false;
|
||||
destroy_filament_viewer(_viewer);
|
||||
_viewer = nullptr; });
|
||||
auto fut = add_task(lambda);
|
||||
}
|
||||
|
||||
void setRendering(bool rendering)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{ this->_rendering = rendering; });
|
||||
auto fut = add_task(lambda);
|
||||
}
|
||||
|
||||
void doRender()
|
||||
{
|
||||
// auto now = std::chrono::high_resolution_clock::now();
|
||||
// auto nanos = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
|
||||
render(_viewer, 0, nullptr, nullptr, nullptr);
|
||||
_lastRenderTime = std::chrono::high_resolution_clock::now();
|
||||
if (_renderCallback)
|
||||
{
|
||||
_renderCallback(_renderCallbackOwner);
|
||||
}
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_webgl_commit_frame();
|
||||
#endif
|
||||
}
|
||||
|
||||
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds)
|
||||
{
|
||||
_frameIntervalInMilliseconds = frameIntervalInMilliseconds;
|
||||
Log("Set _frameIntervalInMilliseconds to %f", _frameIntervalInMilliseconds);
|
||||
}
|
||||
|
||||
template <class Rt>
|
||||
auto add_task(std::packaged_task<Rt()> &pt) -> std::future<Rt>
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_access);
|
||||
auto ret = pt.get_future();
|
||||
_tasks.push_back([pt = std::make_shared<std::packaged_task<Rt()>>(
|
||||
std::move(pt))]
|
||||
{ (*pt)(); });
|
||||
_cond.notify_one();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _stop = false;
|
||||
bool _rendering = false;
|
||||
float _frameIntervalInMilliseconds = 1000.0 / 60.0;
|
||||
std::mutex _access;
|
||||
FilamentViewer *_viewer = nullptr;
|
||||
void (*_renderCallback)(void *const) = nullptr;
|
||||
void *_renderCallbackOwner = nullptr;
|
||||
std::thread *_t = nullptr;
|
||||
std::condition_variable _cond;
|
||||
std::deque<std::function<void()>> _tasks;
|
||||
std::chrono::steady_clock::time_point _lastRenderTime = std::chrono::high_resolution_clock::now();
|
||||
};
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
static RenderLoop *_rl;
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void create_filament_viewer_ffi(
|
||||
void *const context, void *const platform, const char *uberArchivePath,
|
||||
const ResourceLoaderWrapper *const loader,
|
||||
void (*renderCallback)(void *const renderCallbackOwner),
|
||||
void *const renderCallbackOwner,
|
||||
void (*callback)(void *const))
|
||||
{
|
||||
if (!_rl)
|
||||
{
|
||||
_rl = new RenderLoop();
|
||||
}
|
||||
_rl->createViewer(context, platform, uberArchivePath, (const ResourceLoaderWrapperImpl *const)loader,
|
||||
renderCallback, renderCallbackOwner, callback);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void destroy_filament_viewer_ffi(void *const viewer)
|
||||
{
|
||||
_rl->destroyViewer();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void create_swap_chain_ffi(void *const viewer,
|
||||
void *const surface,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
void (*onComplete)())
|
||||
{
|
||||
Log("Creating swapchain %dx%d with viewer %d", width, height, viewer);
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
create_swap_chain(viewer, surface, width, height);
|
||||
onComplete();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void destroy_swap_chain_ffi(void *const viewer, void (*onComplete)())
|
||||
{
|
||||
Log("Destroying swapchain");
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
destroy_swap_chain(viewer);
|
||||
onComplete();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void create_render_target_ffi(void *const viewer,
|
||||
intptr_t nativeTextureId,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
create_render_target(viewer, nativeTextureId, width, height);
|
||||
onComplete(); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void update_viewport_and_camera_projection_ffi(
|
||||
void *const viewer, const uint32_t width, const uint32_t height,
|
||||
const float scaleFactor,
|
||||
void (*onComplete)())
|
||||
{
|
||||
Log("Update viewport %dx%d", width, height);
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
update_viewport_and_camera_projection(viewer, width, height, scaleFactor);
|
||||
onComplete(); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_rendering_ffi(void *const viewer,
|
||||
bool rendering)
|
||||
{
|
||||
if (!_rl)
|
||||
{
|
||||
Log("No render loop!"); // PANIC?
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rendering)
|
||||
{
|
||||
Log("Set rendering to true");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Set rendering to false");
|
||||
}
|
||||
_rl->setRendering(rendering);
|
||||
}
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void
|
||||
set_frame_interval_ffi(float frameIntervalInMilliseconds)
|
||||
{
|
||||
_rl->setFrameIntervalInMilliseconds(frameIntervalInMilliseconds);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void render_ffi(void *const viewer)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{ _rl->doRender(); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void
|
||||
set_background_color_ffi(void *const viewer, const float r, const float g,
|
||||
const float b, const float a)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{ set_background_color(viewer, r, g, b, a); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void load_gltf_ffi(void *const sceneManager,
|
||||
const char *path,
|
||||
const char *relativeResourcePath,
|
||||
void (*callback)(EntityId))
|
||||
{
|
||||
std::packaged_task<EntityId()> lambda([=]() mutable
|
||||
{
|
||||
auto entity = load_gltf(sceneManager, path, relativeResourcePath);
|
||||
callback(entity);
|
||||
return entity; });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void load_glb_ffi(void *const sceneManager,
|
||||
const char *path, int numInstances, void (*callback)(EntityId))
|
||||
{
|
||||
std::packaged_task<EntityId()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
auto entity = load_glb(sceneManager, path, numInstances);
|
||||
callback(entity);
|
||||
return entity;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void load_glb_from_buffer_ffi(void *const sceneManager,
|
||||
const void *const data, size_t length, int numInstances, void (*callback)(EntityId))
|
||||
{
|
||||
std::packaged_task<EntityId()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
auto entity = load_glb_from_buffer(sceneManager, data, length);
|
||||
callback(entity);
|
||||
return entity;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void clear_background_image_ffi(void *const viewer)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{ clear_background_image(viewer); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_background_image_ffi(void *const viewer,
|
||||
const char *path,
|
||||
bool fillHeight, void (*callback)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
set_background_image(viewer, path, fillHeight);
|
||||
callback();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
FLUTTER_PLUGIN_EXPORT void set_background_image_position_ffi(void *const viewer,
|
||||
float x, float y,
|
||||
bool clamp)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{ set_background_image_position(viewer, x, y, clamp); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
FLUTTER_PLUGIN_EXPORT void set_tone_mapping_ffi(void *const viewer,
|
||||
int toneMapping)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{ set_tone_mapping(viewer, toneMapping); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
FLUTTER_PLUGIN_EXPORT void set_bloom_ffi(void *const viewer, float strength)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{ set_bloom(viewer, strength); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
FLUTTER_PLUGIN_EXPORT void load_skybox_ffi(void *const viewer,
|
||||
const char *skyboxPath,
|
||||
void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{
|
||||
load_skybox(viewer, skyboxPath);
|
||||
onComplete(); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void load_ibl_ffi(void *const viewer, const char *iblPath,
|
||||
float intensity)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{ load_ibl(viewer, iblPath, intensity); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
FLUTTER_PLUGIN_EXPORT void remove_skybox_ffi(void *const viewer)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{ remove_skybox(viewer); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void remove_ibl_ffi(void *const viewer)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{ remove_ibl(viewer); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
void add_light_ffi(void *const viewer, uint8_t type, float colour,
|
||||
float intensity, float posX, float posY, float posZ,
|
||||
float dirX, float dirY, float dirZ, bool shadows, void (*callback)(EntityId))
|
||||
{
|
||||
std::packaged_task<EntityId()> lambda([=]
|
||||
{
|
||||
auto entity = add_light(viewer, type, colour, intensity, posX, posY, posZ, dirX,
|
||||
dirY, dirZ, shadows);
|
||||
callback(entity);
|
||||
return entity; });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void remove_light_ffi(void *const viewer,
|
||||
EntityId entityId)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{ remove_light(viewer, entityId); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void clear_lights_ffi(void *const viewer)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{ clear_lights(viewer); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void remove_entity_ffi(void *const viewer,
|
||||
EntityId asset, void (*callback)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{
|
||||
remove_entity(viewer, asset);
|
||||
callback(); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void clear_entities_ffi(void *const viewer, void (*callback)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{
|
||||
clear_entities(viewer);
|
||||
callback(); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_camera_ffi(void *const viewer, EntityId asset,
|
||||
const char *nodeName, void (*callback)(bool))
|
||||
{
|
||||
std::packaged_task<bool()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto success = set_camera(viewer, asset, nodeName);
|
||||
callback(success);
|
||||
return success;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void
|
||||
get_morph_target_name_ffi(void *sceneManager, EntityId asset,
|
||||
const char *meshName, char *const outPtr, int index, void (*callback)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{
|
||||
get_morph_target_name(sceneManager, asset, meshName, outPtr, index);
|
||||
callback(); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void
|
||||
get_morph_target_name_count_ffi(void *sceneManager, EntityId asset,
|
||||
const char *meshName, void (*callback)(int))
|
||||
{
|
||||
std::packaged_task<int()> lambda([=]
|
||||
{
|
||||
auto count = get_morph_target_name_count(sceneManager, asset, meshName);
|
||||
callback(count);
|
||||
return count; });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void play_animation_ffi(void *const sceneManager,
|
||||
EntityId asset, int index,
|
||||
bool loop, bool reverse,
|
||||
bool replaceActive,
|
||||
float crossfade)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{ play_animation(sceneManager, asset, index, loop, reverse, replaceActive,
|
||||
crossfade); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_animation_frame_ffi(void *const sceneManager,
|
||||
EntityId asset,
|
||||
int animationIndex,
|
||||
int animationFrame)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{ set_animation_frame(sceneManager, asset, animationIndex, animationFrame); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void stop_animation_ffi(void *const sceneManager,
|
||||
EntityId asset, int index)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{ stop_animation(sceneManager, asset, index); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void get_animation_count_ffi(void *const sceneManager,
|
||||
EntityId asset,
|
||||
void (*callback)(int))
|
||||
{
|
||||
std::packaged_task<int()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto count = get_animation_count(sceneManager, asset);
|
||||
callback(count);
|
||||
return count;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void get_animation_name_ffi(void *const sceneManager,
|
||||
EntityId asset,
|
||||
char *const outPtr,
|
||||
int index,
|
||||
void (*callback)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
get_animation_name(sceneManager, asset, outPtr, index);
|
||||
callback();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_post_processing_ffi(void *const viewer,
|
||||
bool enabled)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{ set_post_processing(viewer, enabled); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void
|
||||
get_name_for_entity_ffi(void *const sceneManager, const EntityId entityId, void (*callback)(const char *))
|
||||
{
|
||||
std::packaged_task<const char *()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto name = get_name_for_entity(sceneManager, entityId);
|
||||
callback(name);
|
||||
return name;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
void set_morph_target_weights_ffi(void *const sceneManager,
|
||||
EntityId asset,
|
||||
const float *const morphData,
|
||||
int numWeights,
|
||||
void (*callback)(bool))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto result = set_morph_target_weights(sceneManager, asset, morphData, numWeights);
|
||||
callback(result);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_bone_transform_ffi(
|
||||
void *sceneManager,
|
||||
EntityId asset,
|
||||
const char *entityName,
|
||||
const float *const transform,
|
||||
const char *boneName,
|
||||
void (*callback)(bool))
|
||||
{
|
||||
std::packaged_task<bool()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto success = set_bone_transform(sceneManager, asset, entityName, transform, boneName);
|
||||
callback(success);
|
||||
return success;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose_ffi(void *const sceneManager, EntityId entityId)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{ return reset_to_rest_pose(sceneManager, entityId); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void add_bone_animation_ffi(
|
||||
void *sceneManager,
|
||||
EntityId asset,
|
||||
const float *const frameData,
|
||||
int numFrames,
|
||||
const char *const boneName,
|
||||
const char **const meshNames,
|
||||
int numMeshTargets,
|
||||
float frameLengthInMs,
|
||||
bool isModelSpace)
|
||||
{
|
||||
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
add_bone_animation(sceneManager, asset, frameData, numFrames, boneName, meshNames, numMeshTargets, frameLengthInMs, isModelSpace);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void ios_dummy_ffi() { Log("Dummy called"); }
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void create_geometry_ffi(void *const viewer, float *vertices, int numVertices, uint16_t *indices, int numIndices, int primitiveType, const char *materialPath, void (*callback)(EntityId))
|
||||
{
|
||||
std::packaged_task<EntityId()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto entity = create_geometry(viewer, vertices, numVertices, indices, numIndices, primitiveType, materialPath);
|
||||
callback(entity);
|
||||
return entity;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
}
|
||||
1518
dart_filament/native/src/FilamentViewer.cpp
Normal file
1518
dart_filament/native/src/FilamentViewer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1905
dart_filament/native/src/SceneManager.cpp
Normal file
1905
dart_filament/native/src/SceneManager.cpp
Normal file
File diff suppressed because it is too large
Load Diff
81
dart_filament/native/src/StreamBufferAdapter.cpp
Normal file
81
dart_filament/native/src/StreamBufferAdapter.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
#include <streambuf>
|
||||
#include <functional>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
namespace flutter_filament {
|
||||
|
||||
class StreamBufferAdapter : public std::streambuf
|
||||
{
|
||||
public:
|
||||
StreamBufferAdapter(const char *begin, const char *end);
|
||||
~StreamBufferAdapter() {
|
||||
|
||||
}
|
||||
std::streamsize size();
|
||||
|
||||
private:
|
||||
int_type uflow() override;
|
||||
int_type underflow() override;
|
||||
int_type pbackfail(int_type ch) override;
|
||||
std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which) override;
|
||||
std::streampos seekpos(std::streampos sp, std::ios_base::openmode which) override;
|
||||
std::streamsize showmanyc() override;
|
||||
|
||||
};
|
||||
|
||||
StreamBufferAdapter::StreamBufferAdapter(const char *begin, const char *end)
|
||||
{
|
||||
setg((char*)begin, (char*)begin, (char*)end);
|
||||
}
|
||||
|
||||
std::streamsize StreamBufferAdapter::size() {
|
||||
return egptr() - eback();
|
||||
}
|
||||
|
||||
std::streambuf::int_type StreamBufferAdapter::underflow()
|
||||
{
|
||||
if (gptr() == egptr()) {
|
||||
return traits_type::eof();
|
||||
}
|
||||
return *(gptr());
|
||||
}
|
||||
|
||||
std::streambuf::int_type StreamBufferAdapter::uflow()
|
||||
{
|
||||
if (gptr() == egptr()) {
|
||||
return traits_type::eof();
|
||||
}
|
||||
gbump(1);
|
||||
|
||||
return *(gptr());
|
||||
}
|
||||
|
||||
std::streambuf::int_type StreamBufferAdapter::pbackfail(int_type ch)
|
||||
{
|
||||
if (gptr() == eback() || (ch != traits_type::eof() && ch != gptr()[-1]))
|
||||
return traits_type::eof();
|
||||
gbump(-ch);
|
||||
return *(gptr());
|
||||
}
|
||||
|
||||
std::streamsize StreamBufferAdapter::showmanyc()
|
||||
{
|
||||
return egptr() - gptr();
|
||||
}
|
||||
|
||||
std::streampos StreamBufferAdapter::seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in) {
|
||||
if(way == std::ios_base::beg) {
|
||||
setg(eback(), eback()+off, egptr());
|
||||
} else if(way == std::ios_base::cur) {
|
||||
gbump((int)off);
|
||||
} else {
|
||||
setg(eback(), egptr()-off, egptr());
|
||||
}
|
||||
return gptr() - eback();
|
||||
}
|
||||
|
||||
std::streampos StreamBufferAdapter::seekpos(std::streampos sp, std::ios_base::openmode which = std::ios_base::in) {
|
||||
return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which);
|
||||
}
|
||||
}
|
||||
30
dart_filament/native/src/TimeIt.cpp
Normal file
30
dart_filament/native/src/TimeIt.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "TimeIt.hpp"
|
||||
|
||||
#if __cplusplus <= 199711L && !_WIN32
|
||||
|
||||
void Timer::reset()
|
||||
{
|
||||
clock_gettime(CLOCK_REALTIME, &beg_);
|
||||
}
|
||||
|
||||
double Timer::elapsed()
|
||||
{
|
||||
clock_gettime(CLOCK_REALTIME, &end_);
|
||||
return end_.tv_sec - beg_.tv_sec +
|
||||
(end_.tv_nsec - beg_.tv_nsec) / 1000000000.;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void Timer::reset()
|
||||
{
|
||||
beg_ = clock_::now();
|
||||
}
|
||||
|
||||
double Timer::elapsed()
|
||||
{
|
||||
return std::chrono::duration_cast<second_>
|
||||
(clock_::now() - beg_).count();
|
||||
}
|
||||
|
||||
#endif
|
||||
98
dart_filament/native/src/camutils/Bookmark.cpp
Normal file
98
dart_filament/native/src/camutils/Bookmark.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <camutils/Bookmark.h>
|
||||
#include <camutils/Manipulator.h>
|
||||
|
||||
#include <math/scalar.h>
|
||||
#include <math/vec3.h>
|
||||
|
||||
using namespace filament::math;
|
||||
|
||||
namespace filament {
|
||||
namespace camutils {
|
||||
|
||||
template <typename FLOAT>
|
||||
Bookmark<FLOAT> Bookmark<FLOAT>::interpolate(Bookmark<FLOAT> a, Bookmark<FLOAT> b, double t) {
|
||||
Bookmark<FLOAT> result;
|
||||
using float3 = filament::math::vec3<FLOAT>;
|
||||
|
||||
if (a.mode == Mode::MAP) {
|
||||
assert(b.mode == Mode::MAP);
|
||||
const double rho = sqrt(2.0);
|
||||
const double rho2 = 2, rho4 = 4;
|
||||
const double ux0 = a.map.center.x, uy0 = a.map.center.y, w0 = a.map.extent;
|
||||
const double ux1 = b.map.center.x, uy1 = b.map.center.y, w1 = b.map.extent;
|
||||
const double dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, d1 = sqrt(d2);
|
||||
const double b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2.0 * w0 * rho2 * d1);
|
||||
const double b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2.0 * w1 * rho2 * d1);
|
||||
const double r0 = log(sqrt(b0 * b0 + 1.0) - b0);
|
||||
const double r1 = log(sqrt(b1 * b1 + 1) - b1);
|
||||
const double dr = r1 - r0;
|
||||
const int valid = !std::isnan(dr) && dr != 0;
|
||||
const double S = (valid ? dr : log(w1 / w0)) / rho;
|
||||
const double s = t * S;
|
||||
|
||||
// This performs Van Wijk interpolation to animate between two waypoints on a map.
|
||||
if (valid) {
|
||||
const double coshr0 = cosh(r0);
|
||||
const double u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
|
||||
Bookmark<FLOAT> result;
|
||||
result.map.center.x = ux0 + u * dx;
|
||||
result.map.center.y = uy0 + u * dy;
|
||||
result.map.extent = w0 * coshr0 / cosh(rho * s + r0);
|
||||
return result;
|
||||
}
|
||||
|
||||
// For degenerate cases, fall back to a simplified interpolation method.
|
||||
result.map.center.x = ux0 + t * dx;
|
||||
result.map.center.y = uy0 + t * dy;
|
||||
result.map.extent = w0 * exp(rho * s);
|
||||
return result;
|
||||
}
|
||||
|
||||
assert(b.mode == Mode::ORBIT);
|
||||
result.orbit.phi = lerp(a.orbit.phi, b.orbit.phi, FLOAT(t));
|
||||
result.orbit.theta = lerp(a.orbit.theta, b.orbit.theta, FLOAT(t));
|
||||
result.orbit.distance = lerp(a.orbit.distance, b.orbit.distance, FLOAT(t));
|
||||
result.orbit.pivot = lerp(a.orbit.pivot, b.orbit.pivot, float3(t));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Uses the Van Wijk method to suggest a duration for animating between two waypoints on a map.
|
||||
// This does not have units, so just use it as a multiplier.
|
||||
template <typename FLOAT>
|
||||
double Bookmark<FLOAT>::duration(Bookmark<FLOAT> a, Bookmark<FLOAT> b) {
|
||||
assert(a.mode == Mode::ORBIT && b.mode == Mode::ORBIT);
|
||||
const double rho = sqrt(2.0);
|
||||
const double rho2 = 2, rho4 = 4;
|
||||
const double ux0 = a.map.center.x, uy0 = a.map.center.y, w0 = a.map.extent;
|
||||
const double ux1 = b.map.center.x, uy1 = b.map.center.y, w1 = b.map.extent;
|
||||
const double dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, d1 = sqrt(d2);
|
||||
const double b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2.0 * w0 * rho2 * d1);
|
||||
const double b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2.0 * w1 * rho2 * d1);
|
||||
const double r0 = log(sqrt(b0 * b0 + 1.0) - b0);
|
||||
const double r1 = log(sqrt(b1 * b1 + 1) - b1);
|
||||
const double dr = r1 - r0;
|
||||
const int valid = !std::isnan(dr) && dr != 0;
|
||||
const double S = (valid ? dr : log(w1 / w0)) / rho;
|
||||
return fabs(S);
|
||||
}
|
||||
|
||||
template class Bookmark<float>;
|
||||
|
||||
} // namespace camutils
|
||||
} // namespace filament
|
||||
206
dart_filament/native/src/camutils/FreeFlightManipulator.h
Normal file
206
dart_filament/native/src/camutils/FreeFlightManipulator.h
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CAMUTILS_FREEFLIGHT_MANIPULATOR_H
|
||||
#define CAMUTILS_FREEFLIGHT_MANIPULATOR_H
|
||||
|
||||
#include <camutils/Manipulator.h>
|
||||
|
||||
#include <math/scalar.h>
|
||||
#include <math/mat3.h>
|
||||
#include <math/mat4.h>
|
||||
#include <math/quat.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace filament {
|
||||
namespace camutils {
|
||||
|
||||
using namespace filament::math;
|
||||
|
||||
template<typename FLOAT>
|
||||
class FreeFlightManipulator : public Manipulator<FLOAT> {
|
||||
public:
|
||||
using vec2 = filament::math::vec2<FLOAT>;
|
||||
using vec3 = filament::math::vec3<FLOAT>;
|
||||
using vec4 = filament::math::vec4<FLOAT>;
|
||||
using Bookmark = filament::camutils::Bookmark<FLOAT>;
|
||||
using Base = Manipulator<FLOAT>;
|
||||
using Config = typename Base::Config;
|
||||
|
||||
FreeFlightManipulator(Mode mode, const Config& props) : Base(mode, props) {
|
||||
setProperties(props);
|
||||
Base::mEye = Base::mProps.flightStartPosition;
|
||||
const auto pitch = Base::mProps.flightStartPitch;
|
||||
const auto yaw = Base::mProps.flightStartYaw;
|
||||
mTargetEuler = {pitch, yaw};
|
||||
updateTarget(pitch, yaw);
|
||||
}
|
||||
|
||||
void setProperties(const Config& props) override {
|
||||
Config resolved = props;
|
||||
|
||||
if (resolved.flightPanSpeed == vec2(0, 0)) {
|
||||
resolved.flightPanSpeed = vec2(0.01, 0.01);
|
||||
}
|
||||
if (resolved.flightMaxSpeed == 0.0) {
|
||||
resolved.flightMaxSpeed = 10.0;
|
||||
}
|
||||
if (resolved.flightSpeedSteps == 0) {
|
||||
resolved.flightSpeedSteps = 80;
|
||||
}
|
||||
|
||||
Base::setProperties(resolved);
|
||||
}
|
||||
|
||||
void updateTarget(FLOAT pitch, FLOAT yaw) {
|
||||
Base::mTarget = Base::mEye + (mat3::eulerZYX(0, yaw, pitch) * vec3(0.0, 0.0, -1.0));
|
||||
}
|
||||
|
||||
void grabBegin(int x, int y, bool strafe) override {
|
||||
mGrabWin = {x, y};
|
||||
mGrabbing = true;
|
||||
mGrabEuler = mTargetEuler;
|
||||
}
|
||||
|
||||
void grabUpdate(int x, int y) override {
|
||||
if (!mGrabbing) {
|
||||
return;
|
||||
}
|
||||
|
||||
const vec2 del = mGrabWin - vec2{x, y};
|
||||
|
||||
const auto& grabPitch = mGrabEuler.x;
|
||||
const auto& grabYaw = mGrabEuler.y;
|
||||
auto& pitch = mTargetEuler.x;
|
||||
auto& yaw = mTargetEuler.y;
|
||||
|
||||
constexpr double EPSILON = 0.001;
|
||||
|
||||
auto panSpeed = Base::mProps.flightPanSpeed;
|
||||
constexpr FLOAT minPitch = (-F_PI_2 + EPSILON);
|
||||
constexpr FLOAT maxPitch = ( F_PI_2 - EPSILON);
|
||||
pitch = clamp(grabPitch + del.y * -panSpeed.y, minPitch, maxPitch);
|
||||
yaw = fmod(grabYaw + del.x * panSpeed.x, 2.0 * F_PI);
|
||||
|
||||
updateTarget(pitch, yaw);
|
||||
}
|
||||
|
||||
void grabEnd() override {
|
||||
mGrabbing = false;
|
||||
}
|
||||
|
||||
void keyDown(typename Base::Key key) override {
|
||||
mKeyDown[(int) key] = true;
|
||||
}
|
||||
|
||||
void keyUp(typename Base::Key key) override {
|
||||
mKeyDown[(int) key] = false;
|
||||
}
|
||||
|
||||
void scroll(int x, int y, FLOAT scrolldelta) override {
|
||||
const FLOAT halfSpeedSteps = Base::mProps.flightSpeedSteps / 2;
|
||||
mScrollWheel = clamp(mScrollWheel + scrolldelta, -halfSpeedSteps, halfSpeedSteps);
|
||||
// Normalize the scroll position from -1 to 1 and calculate the move speed, in world
|
||||
// units per second.
|
||||
mScrollPositionNormalized = (mScrollWheel + halfSpeedSteps) / halfSpeedSteps - 1.0;
|
||||
mMoveSpeed = pow(Base::mProps.flightMaxSpeed, mScrollPositionNormalized);
|
||||
}
|
||||
|
||||
void update(FLOAT deltaTime) override {
|
||||
vec3 forceLocal { 0.0, 0.0, 0.0 };
|
||||
|
||||
if (mKeyDown[(int) Base::Key::FORWARD]) {
|
||||
forceLocal += vec3{ 0.0, 0.0, -1.0 };
|
||||
}
|
||||
if (mKeyDown[(int) Base::Key::LEFT]) {
|
||||
forceLocal += vec3{ -1.0, 0.0, 0.0 };
|
||||
}
|
||||
if (mKeyDown[(int) Base::Key::BACKWARD]) {
|
||||
forceLocal += vec3{ 0.0, 0.0, 1.0 };
|
||||
}
|
||||
if (mKeyDown[(int) Base::Key::RIGHT]) {
|
||||
forceLocal += vec3{ 1.0, 0.0, 0.0 };
|
||||
}
|
||||
|
||||
const mat4 orientation = mat4::lookAt(Base::mEye, Base::mTarget, Base::mProps.upVector);
|
||||
vec3 forceWorld = (orientation * vec4{ forceLocal, 0.0f }).xyz;
|
||||
|
||||
if (mKeyDown[(int) Base::Key::UP]) {
|
||||
forceWorld += vec3{ 0.0, 1.0, 0.0 };
|
||||
}
|
||||
if (mKeyDown[(int) Base::Key::DOWN]) {
|
||||
forceWorld += vec3{ 0.0, -1.0, 0.0 };
|
||||
}
|
||||
|
||||
forceWorld *= mMoveSpeed;
|
||||
|
||||
const auto dampingFactor = Base::mProps.flightMoveDamping;
|
||||
if (dampingFactor == 0.0) {
|
||||
// Without damping, we simply treat the force as our velocity.
|
||||
mEyeVelocity = forceWorld;
|
||||
} else {
|
||||
// The dampingFactor acts as "friction", which acts upon the camera in the direction
|
||||
// opposite its velocity.
|
||||
// Force is also multiplied by the dampingFactor, to "make up" for the friction.
|
||||
// This ensures that the max velocity still approaches mMoveSpeed;
|
||||
vec3 velocityDelta = (forceWorld - mEyeVelocity) * dampingFactor;
|
||||
mEyeVelocity += velocityDelta * deltaTime;
|
||||
}
|
||||
|
||||
const vec3 positionDelta = mEyeVelocity * deltaTime;
|
||||
|
||||
Base::mEye += positionDelta;
|
||||
Base::mTarget += positionDelta;
|
||||
}
|
||||
|
||||
Bookmark getCurrentBookmark() const override {
|
||||
Bookmark bookmark;
|
||||
bookmark.flight.position = Base::mEye;
|
||||
bookmark.flight.pitch = mTargetEuler.x;
|
||||
bookmark.flight.yaw = mTargetEuler.y;
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
Bookmark getHomeBookmark() const override {
|
||||
Bookmark bookmark;
|
||||
bookmark.flight.position = Base::mProps.flightStartPosition;
|
||||
bookmark.flight.pitch = Base::mProps.flightStartPitch;
|
||||
bookmark.flight.yaw = Base::mProps.flightStartYaw;
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
void jumpToBookmark(const Bookmark& bookmark) override {
|
||||
Base::mEye = bookmark.flight.position;
|
||||
updateTarget(bookmark.flight.pitch, bookmark.flight.yaw);
|
||||
}
|
||||
|
||||
private:
|
||||
vec2 mGrabWin;
|
||||
vec2 mTargetEuler; // (pitch, yaw)
|
||||
vec2 mGrabEuler; // (pitch, yaw)
|
||||
bool mKeyDown[(int) Base::Key::COUNT] = {false};
|
||||
bool mGrabbing = false;
|
||||
FLOAT mScrollWheel = 0.0f;
|
||||
FLOAT mScrollPositionNormalized = 0.0f;
|
||||
FLOAT mMoveSpeed = 1.0f;
|
||||
vec3 mEyeVelocity;
|
||||
};
|
||||
|
||||
} // namespace camutils
|
||||
} // namespace filament
|
||||
|
||||
#endif /* CAMUTILS_FREEFLIGHT_MANIPULATOR_H */
|
||||
370
dart_filament/native/src/camutils/Manipulator.cpp
Normal file
370
dart_filament/native/src/camutils/Manipulator.cpp
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <math/scalar.h>
|
||||
|
||||
#include <camutils/Manipulator.h>
|
||||
|
||||
#include "FreeFlightManipulator.h"
|
||||
#include "MapManipulator.h"
|
||||
#include "OrbitManipulator.h"
|
||||
|
||||
using namespace filament::math;
|
||||
|
||||
namespace filament
|
||||
{
|
||||
namespace camutils
|
||||
{
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::viewport(int width, int height)
|
||||
{
|
||||
details.viewport[0] = width;
|
||||
details.viewport[1] = height;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::targetPosition(FLOAT x, FLOAT y, FLOAT z)
|
||||
{
|
||||
details.targetPosition = {x, y, z};
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::upVector(FLOAT x, FLOAT y, FLOAT z)
|
||||
{
|
||||
details.upVector = {x, y, z};
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::zoomSpeed(FLOAT val)
|
||||
{
|
||||
details.zoomSpeed = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::orbitHomePosition(FLOAT x, FLOAT y, FLOAT z)
|
||||
{
|
||||
details.orbitHomePosition = {x, y, z};
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::orbitSpeed(FLOAT x, FLOAT y)
|
||||
{
|
||||
details.orbitSpeed = {x, y};
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::fovDirection(Fov fov)
|
||||
{
|
||||
details.fovDirection = fov;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::fovDegrees(FLOAT degrees)
|
||||
{
|
||||
details.fovDegrees = degrees;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::farPlane(FLOAT distance)
|
||||
{
|
||||
details.farPlane = distance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::mapExtent(FLOAT worldWidth, FLOAT worldHeight)
|
||||
{
|
||||
details.mapExtent = {worldWidth, worldHeight};
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::mapMinDistance(FLOAT mindist)
|
||||
{
|
||||
details.mapMinDistance = mindist;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::flightStartPosition(FLOAT x, FLOAT y, FLOAT z)
|
||||
{
|
||||
details.flightStartPosition = {x, y, z};
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::flightStartOrientation(FLOAT pitch, FLOAT yaw)
|
||||
{
|
||||
details.flightStartPitch = pitch;
|
||||
details.flightStartYaw = yaw;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::flightMaxMoveSpeed(FLOAT maxSpeed)
|
||||
{
|
||||
details.flightMaxSpeed = maxSpeed;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::flightSpeedSteps(int steps)
|
||||
{
|
||||
details.flightSpeedSteps = steps;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::flightPanSpeed(FLOAT x, FLOAT y)
|
||||
{
|
||||
details.flightPanSpeed = {x, y};
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::flightMoveDamping(FLOAT damping)
|
||||
{
|
||||
details.flightMoveDamping = damping;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::groundPlane(FLOAT a, FLOAT b, FLOAT c, FLOAT d)
|
||||
{
|
||||
details.groundPlane = {a, b, c, d};
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
typename Manipulator<FLOAT>::Builder &Manipulator<FLOAT>::Builder::raycastCallback(RayCallback cb, void *userdata)
|
||||
{
|
||||
details.raycastCallback = cb;
|
||||
details.raycastUserdata = userdata;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
Manipulator<FLOAT> *Manipulator<FLOAT>::Builder::build(Mode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case Mode::FREE_FLIGHT:
|
||||
return new FreeFlightManipulator<FLOAT>(mode, details);
|
||||
case Mode::MAP:
|
||||
return new MapManipulator<FLOAT>(mode, details);
|
||||
case Mode::ORBIT:
|
||||
return new OrbitManipulator<FLOAT>(mode, details);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
Manipulator<FLOAT>::Manipulator(Mode mode, const Config &props) : mMode(mode)
|
||||
{
|
||||
setProperties(props);
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
void Manipulator<FLOAT>::setProperties(const Config &props)
|
||||
{
|
||||
mProps = props;
|
||||
|
||||
if (mProps.zoomSpeed == FLOAT(0))
|
||||
{
|
||||
mProps.zoomSpeed = 0.01;
|
||||
}
|
||||
|
||||
if (mProps.upVector == vec3(0))
|
||||
{
|
||||
mProps.upVector = vec3(0, 1, 0);
|
||||
}
|
||||
|
||||
if (mProps.fovDegrees == FLOAT(0))
|
||||
{
|
||||
mProps.fovDegrees = 33;
|
||||
}
|
||||
|
||||
if (mProps.farPlane == FLOAT(0))
|
||||
{
|
||||
mProps.farPlane = 5000;
|
||||
}
|
||||
|
||||
if (mProps.mapExtent == vec2(0))
|
||||
{
|
||||
mProps.mapExtent = vec2(512);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
void Manipulator<FLOAT>::setViewport(int width, int height)
|
||||
{
|
||||
Config props = mProps;
|
||||
props.viewport[0] = width;
|
||||
props.viewport[1] = height;
|
||||
setProperties(props);
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
void Manipulator<FLOAT>::getLookAt(vec3 *eyePosition, vec3 *targetPosition, vec3 *upward) const
|
||||
{
|
||||
*targetPosition = mTarget;
|
||||
*eyePosition = mEye;
|
||||
const vec3 gaze = normalize(mTarget - mEye);
|
||||
const vec3 right = cross(gaze, mProps.upVector);
|
||||
*upward = cross(right, gaze);
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
static bool raycastPlane(const filament::math::vec3<FLOAT> &origin,
|
||||
const filament::math::vec3<FLOAT> &dir, FLOAT *t, void *userdata)
|
||||
{
|
||||
using vec3 = filament::math::vec3<FLOAT>;
|
||||
using vec4 = filament::math::vec4<FLOAT>;
|
||||
auto props = (const typename Manipulator<FLOAT>::Config *)userdata;
|
||||
const vec4 plane = props->groundPlane;
|
||||
const vec3 n = vec3(plane[0], plane[1], plane[2]);
|
||||
const vec3 p0 = n * plane[3];
|
||||
const FLOAT denom = -dot(n, dir);
|
||||
if (denom > 1e-6)
|
||||
{
|
||||
const vec3 p0l0 = p0 - origin;
|
||||
*t = dot(p0l0, n) / -denom;
|
||||
return *t >= 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
void Manipulator<FLOAT>::getRay(int x, int y, vec3 *porigin, vec3 *pdir) const
|
||||
{
|
||||
const vec3 gaze = normalize(mTarget - mEye);
|
||||
const vec3 right = normalize(cross(gaze, mProps.upVector));
|
||||
const vec3 upward = cross(right, gaze);
|
||||
const FLOAT width = mProps.viewport[0];
|
||||
const FLOAT height = mProps.viewport[1];
|
||||
const FLOAT fov = mProps.fovDegrees * F_PI / 180.0;
|
||||
|
||||
// Remap the grid coordinate into [-1, +1] and shift it to the pixel center.
|
||||
const FLOAT u = 2.0 * (0.5 + x) / width - 1.0;
|
||||
const FLOAT v = 2.0 * (0.5 + y) / height - 1.0;
|
||||
|
||||
// Compute the tangent of the field-of-view angle as well as the aspect ratio.
|
||||
const FLOAT tangent = tan(fov / 2.0);
|
||||
const FLOAT aspect = width / height;
|
||||
|
||||
// Adjust the gaze so it goes through the pixel of interest rather than the grid center.
|
||||
vec3 dir = gaze;
|
||||
if (mProps.fovDirection == Fov::VERTICAL)
|
||||
{
|
||||
dir += right * tangent * u * aspect;
|
||||
dir += upward * tangent * v;
|
||||
}
|
||||
else
|
||||
{
|
||||
dir += right * tangent * u;
|
||||
dir += upward * tangent * v / aspect;
|
||||
}
|
||||
dir = normalize(dir);
|
||||
|
||||
*porigin = mEye;
|
||||
*pdir = dir;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
bool Manipulator<FLOAT>::raycast(int x, int y, vec3 *result) const
|
||||
{
|
||||
vec3 origin, dir;
|
||||
getRay(x, y, &origin, &dir);
|
||||
|
||||
// Choose either the user's callback function or the plane intersector.
|
||||
auto callback = mProps.raycastCallback;
|
||||
auto fallback = raycastPlane<FLOAT>;
|
||||
void *userdata = mProps.raycastUserdata;
|
||||
if (!callback)
|
||||
{
|
||||
callback = fallback;
|
||||
userdata = (void *)&mProps;
|
||||
}
|
||||
|
||||
// If the ray misses, then try the fallback function.
|
||||
FLOAT t;
|
||||
if (!callback(mEye, dir, &t, userdata))
|
||||
{
|
||||
if (callback == fallback || !fallback(mEye, dir, &t, (void *)&mProps))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*result = mEye + dir * t;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
filament::math::vec3<FLOAT> Manipulator<FLOAT>::raycastFarPlane(int x, int y) const
|
||||
{
|
||||
const filament::math::vec3<FLOAT> gaze = normalize(mTarget - mEye);
|
||||
const vec3 right = cross(gaze, mProps.upVector);
|
||||
const vec3 upward = cross(right, gaze);
|
||||
const FLOAT width = mProps.viewport[0];
|
||||
const FLOAT height = mProps.viewport[1];
|
||||
const FLOAT fov = mProps.fovDegrees * math::F_PI / 180.0;
|
||||
|
||||
// Remap the grid coordinate into [-1, +1] and shift it to the pixel center.
|
||||
const FLOAT u = 2.0 * (0.5 + x) / width - 1.0;
|
||||
const FLOAT v = 2.0 * (0.5 + y) / height - 1.0;
|
||||
|
||||
// Compute the tangent of the field-of-view angle as well as the aspect ratio.
|
||||
const FLOAT tangent = tan(fov / 2.0);
|
||||
const FLOAT aspect = width / height;
|
||||
|
||||
// Adjust the gaze so it goes through the pixel of interest rather than the grid center.
|
||||
vec3 dir = gaze;
|
||||
if (mProps.fovDirection == Fov::VERTICAL)
|
||||
{
|
||||
dir += right * tangent * u * aspect;
|
||||
dir += upward * tangent * v;
|
||||
}
|
||||
else
|
||||
{
|
||||
dir += right * tangent * u;
|
||||
dir += upward * tangent * v / aspect;
|
||||
}
|
||||
return mEye + dir * mProps.farPlane;
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
void Manipulator<FLOAT>::keyDown(Manipulator<FLOAT>::Key key) {}
|
||||
|
||||
template <typename FLOAT>
|
||||
void Manipulator<FLOAT>::keyUp(Manipulator<FLOAT>::Key key) {}
|
||||
|
||||
template <typename FLOAT>
|
||||
void Manipulator<FLOAT>::update(FLOAT deltaTime) {}
|
||||
|
||||
template class Manipulator<float>;
|
||||
template class Manipulator<double>;
|
||||
|
||||
} // namespace camutils
|
||||
} // namespace filament
|
||||
218
dart_filament/native/src/camutils/MapManipulator.h
Normal file
218
dart_filament/native/src/camutils/MapManipulator.h
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CAMUTILS_MAP_MANIPULATOR_H
|
||||
#define CAMUTILS_MAP_MANIPULATOR_H
|
||||
|
||||
#include <math/scalar.h>
|
||||
|
||||
#include <camutils/Manipulator.h>
|
||||
|
||||
#include <math/vec3.h>
|
||||
|
||||
namespace filament
|
||||
{
|
||||
namespace camutils
|
||||
{
|
||||
|
||||
template <typename FLOAT>
|
||||
class MapManipulator : public Manipulator<FLOAT>
|
||||
{
|
||||
public:
|
||||
using vec2 = math::vec2<FLOAT>;
|
||||
using vec3 = math::vec3<FLOAT>;
|
||||
using vec4 = math::vec4<FLOAT>;
|
||||
using Bookmark = filament::camutils::Bookmark<FLOAT>;
|
||||
using Base = Manipulator<FLOAT>;
|
||||
using Config = typename Manipulator<FLOAT>::Config;
|
||||
|
||||
MapManipulator(Mode mode, const Config &props) : Manipulator<FLOAT>(mode, props)
|
||||
{
|
||||
const FLOAT width = Base::mProps.mapExtent.x;
|
||||
const FLOAT height = Base::mProps.mapExtent.y;
|
||||
const bool horiz = Base::mProps.fovDirection == Fov::HORIZONTAL;
|
||||
const vec3 targetToEye = Base::mProps.groundPlane.xyz;
|
||||
const FLOAT halfExtent = (horiz ? width : height) / 2.0;
|
||||
const FLOAT fov = Base::mProps.fovDegrees * math::F_PI / 180.0;
|
||||
const FLOAT distance = halfExtent / tan(fov / 2.0);
|
||||
Base::mTarget = Base::mProps.targetPosition;
|
||||
Base::mEye = Base::mTarget + distance * targetToEye;
|
||||
}
|
||||
|
||||
void grabBegin(int x, int y, bool strafe) override
|
||||
{
|
||||
if (strafe || !Base::raycast(x, y, &mGrabScene))
|
||||
{
|
||||
return;
|
||||
}
|
||||
mGrabFar = Base::raycastFarPlane(x, y);
|
||||
mGrabEye = Base::mEye;
|
||||
mGrabTarget = Base::mTarget;
|
||||
mGrabbing = true;
|
||||
}
|
||||
|
||||
void grabUpdate(int x, int y) override
|
||||
{
|
||||
if (mGrabbing)
|
||||
{
|
||||
const FLOAT ulen = distance(mGrabScene, mGrabEye);
|
||||
const FLOAT vlen = distance(mGrabFar, mGrabScene);
|
||||
const vec3 translation = (mGrabFar - Base::raycastFarPlane(x, y)) * ulen / vlen;
|
||||
const vec3 eyePosition = mGrabEye + translation;
|
||||
const vec3 targetPosition = mGrabTarget + translation;
|
||||
moveWithConstraints(eyePosition, targetPosition);
|
||||
}
|
||||
}
|
||||
|
||||
void grabEnd() override
|
||||
{
|
||||
mGrabbing = false;
|
||||
}
|
||||
|
||||
void scroll(int x, int y, FLOAT scrolldelta) override
|
||||
{
|
||||
vec3 grabScene;
|
||||
if (!Base::raycast(x, y, &grabScene))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the direction of travel for the dolly. We do not normalize since it
|
||||
// is desirable to move faster when further away from the targetPosition.
|
||||
vec3 u = grabScene - Base::mEye;
|
||||
|
||||
// Prevent getting stuck when zooming in.
|
||||
if (scrolldelta < 0)
|
||||
{
|
||||
const FLOAT distanceToSurface = length(u);
|
||||
if (distanceToSurface < Base::mProps.zoomSpeed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
u *= -scrolldelta * Base::mProps.zoomSpeed;
|
||||
|
||||
const vec3 eyePosition = Base::mEye + u;
|
||||
const vec3 targetPosition = Base::mTarget + u;
|
||||
moveWithConstraints(eyePosition, targetPosition);
|
||||
}
|
||||
|
||||
Bookmark getCurrentBookmark() const override
|
||||
{
|
||||
const vec3 dir = normalize(Base::mTarget - Base::mEye);
|
||||
|
||||
FLOAT distance;
|
||||
raycastPlane(Base::mEye, dir, &distance);
|
||||
|
||||
const FLOAT fov = Base::mProps.fovDegrees * math::F_PI / 180.0;
|
||||
const FLOAT halfExtent = distance * tan(fov / 2.0);
|
||||
|
||||
vec3 targetPosition = Base::mEye + dir * distance;
|
||||
|
||||
const vec3 targetToEye = Base::mProps.groundPlane.xyz;
|
||||
const vec3 uvec = cross(Base::mProps.upVector, targetToEye);
|
||||
const vec3 vvec = cross(targetToEye, uvec);
|
||||
const vec3 centerToTarget = targetPosition - Base::mProps.targetPosition;
|
||||
|
||||
Bookmark bookmark;
|
||||
bookmark.mode = Mode::MAP;
|
||||
bookmark.map.extent = halfExtent * 2.0;
|
||||
bookmark.map.center.x = dot(uvec, centerToTarget);
|
||||
bookmark.map.center.y = dot(vvec, centerToTarget);
|
||||
|
||||
bookmark.orbit.theta = 0;
|
||||
bookmark.orbit.phi = 0;
|
||||
bookmark.orbit.pivot = Base::mProps.targetPosition +
|
||||
uvec * bookmark.map.center.x +
|
||||
vvec * bookmark.map.center.y;
|
||||
bookmark.orbit.distance = halfExtent / tan(fov / 2.0);
|
||||
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
Bookmark getHomeBookmark() const override
|
||||
{
|
||||
const FLOAT fov = Base::mProps.fovDegrees * math::F_PI / 180.0;
|
||||
const FLOAT width = Base::mProps.mapExtent.x;
|
||||
const FLOAT height = Base::mProps.mapExtent.y;
|
||||
const bool horiz = Base::mProps.fovDirection == Fov::HORIZONTAL;
|
||||
|
||||
Bookmark bookmark;
|
||||
bookmark.mode = Mode::MAP;
|
||||
bookmark.map.extent = horiz ? width : height;
|
||||
bookmark.map.center.x = 0;
|
||||
bookmark.map.center.y = 0;
|
||||
|
||||
bookmark.orbit.theta = 0;
|
||||
bookmark.orbit.phi = 0;
|
||||
bookmark.orbit.pivot = Base::mTarget;
|
||||
bookmark.orbit.distance = 0.5 * bookmark.map.extent / tan(fov / 2.0);
|
||||
|
||||
// TODO: Add optional boundary constraints here.
|
||||
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
void jumpToBookmark(const Bookmark &bookmark) override
|
||||
{
|
||||
const vec3 targetToEye = Base::mProps.groundPlane.xyz;
|
||||
const FLOAT halfExtent = bookmark.map.extent / 2.0;
|
||||
const FLOAT fov = Base::mProps.fovDegrees * math::F_PI / 180.0;
|
||||
const FLOAT distance = halfExtent / tan(fov / 2.0);
|
||||
vec3 uvec = cross(Base::mProps.upVector, targetToEye);
|
||||
vec3 vvec = cross(targetToEye, uvec);
|
||||
uvec = normalize(uvec) * bookmark.map.center.x;
|
||||
vvec = normalize(vvec) * bookmark.map.center.y;
|
||||
Base::mTarget = Base::mProps.targetPosition + uvec + vvec;
|
||||
Base::mEye = Base::mTarget + distance * targetToEye;
|
||||
}
|
||||
|
||||
private:
|
||||
bool raycastPlane(const vec3 &origin, const vec3 &dir, FLOAT *t) const
|
||||
{
|
||||
const vec4 plane = Base::mProps.groundPlane;
|
||||
const vec3 n = vec3(plane[0], plane[1], plane[2]);
|
||||
const vec3 p0 = n * plane[3];
|
||||
const FLOAT denom = -dot(n, dir);
|
||||
if (denom > 1e-6)
|
||||
{
|
||||
const vec3 p0l0 = p0 - origin;
|
||||
*t = dot(p0l0, n) / -denom;
|
||||
return *t >= 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void moveWithConstraints(vec3 eye, vec3 targetPosition)
|
||||
{
|
||||
Base::mEye = eye;
|
||||
Base::mTarget = targetPosition;
|
||||
// TODO: Add optional boundary constraints here.
|
||||
}
|
||||
|
||||
private:
|
||||
bool mGrabbing = false;
|
||||
vec3 mGrabScene;
|
||||
vec3 mGrabFar;
|
||||
vec3 mGrabEye;
|
||||
vec3 mGrabTarget;
|
||||
};
|
||||
|
||||
} // namespace camutils
|
||||
} // namespace filament
|
||||
|
||||
#endif /* CAMUTILS_MAP_MANIPULATOR_H */
|
||||
201
dart_filament/native/src/camutils/OrbitManipulator.h
Normal file
201
dart_filament/native/src/camutils/OrbitManipulator.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CAMUTILS_ORBIT_MANIPULATOR_H
|
||||
#define CAMUTILS_ORBIT_MANIPULATOR_H
|
||||
|
||||
#include <camutils/Manipulator.h>
|
||||
|
||||
#include <math/scalar.h>
|
||||
|
||||
#define MAX_PHI (F_PI / 2.0 - 0.001)
|
||||
|
||||
namespace filament {
|
||||
namespace camutils {
|
||||
|
||||
using namespace filament::math;
|
||||
|
||||
template<typename FLOAT>
|
||||
class OrbitManipulator : public Manipulator<FLOAT> {
|
||||
public:
|
||||
using vec2 = filament::math::vec2<FLOAT>;
|
||||
using vec3 = filament::math::vec3<FLOAT>;
|
||||
using vec4 = filament::math::vec4<FLOAT>;
|
||||
using Bookmark = filament::camutils::Bookmark<FLOAT>;
|
||||
using Base = Manipulator<FLOAT>;
|
||||
using Config = typename Base::Config;
|
||||
|
||||
enum GrabState { INACTIVE, ORBITING, PANNING };
|
||||
|
||||
OrbitManipulator(Mode mode, const Config& props) : Base(mode, props) {
|
||||
setProperties(props);
|
||||
Base::mEye = Base::mProps.orbitHomePosition;
|
||||
mPivot = Base::mTarget = Base::mProps.targetPosition;
|
||||
}
|
||||
|
||||
void setProperties(const Config& props) override {
|
||||
Config resolved = props;
|
||||
|
||||
if (resolved.orbitHomePosition == vec3(0)) {
|
||||
resolved.orbitHomePosition = vec3(0, 0, 1);
|
||||
}
|
||||
|
||||
if (resolved.orbitSpeed == vec2(0)) {
|
||||
resolved.orbitSpeed = vec2(0.01);
|
||||
}
|
||||
|
||||
// By default, place the ground plane so that it aligns with the targetPosition position.
|
||||
// This is used only when PANNING.
|
||||
if (resolved.groundPlane == vec4(0)) {
|
||||
const FLOAT d = length(resolved.targetPosition);
|
||||
const vec3 n = normalize(resolved.orbitHomePosition - resolved.targetPosition);
|
||||
resolved.groundPlane = vec4(n, -d);
|
||||
}
|
||||
|
||||
Base::setProperties(resolved);
|
||||
}
|
||||
|
||||
void grabBegin(int x, int y, bool strafe) override {
|
||||
mGrabState = strafe ? PANNING : ORBITING;
|
||||
mGrabPivot = mPivot;
|
||||
mGrabEye = Base::mEye;
|
||||
mGrabTarget = Base::mTarget;
|
||||
mGrabBookmark = getCurrentBookmark();
|
||||
mGrabWinX = x;
|
||||
mGrabWinY = y;
|
||||
mGrabFar = Base::raycastFarPlane(x, y);
|
||||
Base::raycast(x, y, &mGrabScene);
|
||||
}
|
||||
|
||||
void grabUpdate(int x, int y) override {
|
||||
const int delx = mGrabWinX - x;
|
||||
const int dely = mGrabWinY - y;
|
||||
|
||||
if (mGrabState == ORBITING) {
|
||||
Bookmark bookmark = getCurrentBookmark();
|
||||
|
||||
const FLOAT theta = delx * Base::mProps.orbitSpeed.x;
|
||||
const FLOAT phi = dely * Base::mProps.orbitSpeed.y;
|
||||
const FLOAT maxPhi = MAX_PHI;
|
||||
|
||||
bookmark.orbit.phi = clamp(mGrabBookmark.orbit.phi + phi, -maxPhi, +maxPhi);
|
||||
bookmark.orbit.theta = mGrabBookmark.orbit.theta + theta;
|
||||
|
||||
jumpToBookmark(bookmark);
|
||||
}
|
||||
|
||||
if (mGrabState == PANNING) {
|
||||
const FLOAT ulen = distance(mGrabScene, mGrabEye);
|
||||
const FLOAT vlen = distance(mGrabFar, mGrabScene);
|
||||
const vec3 translation = (mGrabFar - Base::raycastFarPlane(x, y)) * ulen / vlen;
|
||||
mPivot = mGrabPivot + translation;
|
||||
Base::mEye = mGrabEye + translation;
|
||||
Base::mTarget = mGrabTarget + translation;
|
||||
}
|
||||
}
|
||||
|
||||
void grabEnd() override {
|
||||
mGrabState = INACTIVE;
|
||||
}
|
||||
|
||||
void scroll(int x, int y, FLOAT scrolldelta) override {
|
||||
const vec3 gaze = normalize(Base::mTarget - Base::mEye);
|
||||
const vec3 movement = gaze * Base::mProps.zoomSpeed * -scrolldelta;
|
||||
const vec3 v0 = mPivot - Base::mEye;
|
||||
Base::mEye += movement;
|
||||
Base::mTarget += movement;
|
||||
const vec3 v1 = mPivot - Base::mEye;
|
||||
|
||||
// Check if the camera has moved past the point of interest.
|
||||
if (dot(v0, v1) < 0) {
|
||||
mFlipped = !mFlipped;
|
||||
}
|
||||
}
|
||||
|
||||
Bookmark getCurrentBookmark() const override {
|
||||
Bookmark bookmark;
|
||||
bookmark.mode = Mode::ORBIT;
|
||||
const vec3 pivotToEye = Base::mEye - mPivot;
|
||||
const FLOAT d = length(pivotToEye);
|
||||
const FLOAT x = pivotToEye.x / d;
|
||||
const FLOAT y = pivotToEye.y / d;
|
||||
const FLOAT z = pivotToEye.z / d;
|
||||
|
||||
bookmark.orbit.phi = asin(y);
|
||||
bookmark.orbit.theta = atan2(x, z);
|
||||
bookmark.orbit.distance = mFlipped ? -d : d;
|
||||
bookmark.orbit.pivot = mPivot;
|
||||
|
||||
const FLOAT fov = Base::mProps.fovDegrees * math::F_PI / 180.0;
|
||||
const FLOAT halfExtent = d * tan(fov / 2.0);
|
||||
const vec3 targetToEye = Base::mProps.groundPlane.xyz;
|
||||
const vec3 uvec = cross(Base::mProps.upVector, targetToEye);
|
||||
const vec3 vvec = cross(targetToEye, uvec);
|
||||
const vec3 centerToTarget = mPivot - Base::mProps.targetPosition;
|
||||
|
||||
bookmark.map.extent = halfExtent * 2;
|
||||
bookmark.map.center.x = dot(uvec, centerToTarget);
|
||||
bookmark.map.center.y = dot(vvec, centerToTarget);
|
||||
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
Bookmark getHomeBookmark() const override {
|
||||
Bookmark bookmark;
|
||||
bookmark.mode = Mode::ORBIT;
|
||||
bookmark.orbit.phi = FLOAT(0);
|
||||
bookmark.orbit.theta = FLOAT(0);
|
||||
bookmark.orbit.pivot = Base::mProps.targetPosition;
|
||||
bookmark.orbit.distance = distance(Base::mProps.targetPosition, Base::mProps.orbitHomePosition);
|
||||
|
||||
const FLOAT fov = Base::mProps.fovDegrees * math::F_PI / 180.0;
|
||||
const FLOAT halfExtent = bookmark.orbit.distance * tan(fov / 2.0);
|
||||
|
||||
bookmark.map.extent = halfExtent * 2;
|
||||
bookmark.map.center.x = 0;
|
||||
bookmark.map.center.y = 0;
|
||||
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
void jumpToBookmark(const Bookmark& bookmark) override {
|
||||
mPivot = bookmark.orbit.pivot;
|
||||
const FLOAT x = sin(bookmark.orbit.theta) * cos(bookmark.orbit.phi);
|
||||
const FLOAT y = sin(bookmark.orbit.phi);
|
||||
const FLOAT z = cos(bookmark.orbit.theta) * cos(bookmark.orbit.phi);
|
||||
Base::mEye = mPivot + vec3(x, y, z) * abs(bookmark.orbit.distance);
|
||||
mFlipped = bookmark.orbit.distance < 0;
|
||||
Base::mTarget = Base::mEye + vec3(x, y, z) * (mFlipped ? 1.0 : -1.0);
|
||||
}
|
||||
|
||||
private:
|
||||
GrabState mGrabState = INACTIVE;
|
||||
bool mFlipped = false;
|
||||
vec3 mGrabPivot;
|
||||
vec3 mGrabScene;
|
||||
vec3 mGrabFar;
|
||||
vec3 mGrabEye;
|
||||
vec3 mGrabTarget;
|
||||
Bookmark mGrabBookmark;
|
||||
int mGrabWinX;
|
||||
int mGrabWinY;
|
||||
vec3 mPivot;
|
||||
};
|
||||
|
||||
} // namespace camutils
|
||||
} // namespace filament
|
||||
|
||||
#endif /* CAMUTILS_ORBIT_MANIPULATOR_H */
|
||||
Reference in New Issue
Block a user