finish camera revolve feature, add pan, ms3d mime type

master
poikilos 2019-03-10 09:55:31 -04:00
parent 6013175ad9
commit 924c4864e1
13 changed files with 358 additions and 93 deletions

View File

@ -1,5 +1,14 @@
# Changelog
## [git] - 2019-03-09
(poikilos)
### Added
* completed rotation controls (Blender-like)
* pan up and down (Blender-like, but only up and down)
* Z or Y to switch ("up" axis)
* change up axis to Z when 3ds is loaded
* model-ms3d.xml mime type file
## [git] - 2019-03-09
(poikilos)
### Added

View File

@ -132,10 +132,20 @@ s32 Engine::getNumberOfVertices()
Engine::Engine()
{
// For monitoring single press: see
// <http://irrlicht.sourceforge.net/forum/viewtopic.php?p=210744>
for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
KeyIsDown[i] = false;
for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
keyState[i] = 0;
LMouseState = 0;
RMouseState = 0;
this->worldFPS = 60;
this->prevFPS = 30;
this->textureExtensions.push_back(L"png");
this->textureExtensions.push_back(L"jpg");
this->textureExtensions.push_back(L"bmp");
#if WIN32
m_Device = createDevice( EDT_DIRECT3D9, dimension2d<u32>( 1024, 768 ), 32, false, false, false, nullptr );
#else
@ -184,7 +194,7 @@ Engine::Engine()
m_WindowSize->Width = m_Driver->getScreenSize().Width;
m_WindowSize->Height = m_Driver->getScreenSize().Height;
// (do not calculate m_Yaw and m_Pitch, here, but in View constructor)
// (do not calculate m_Yaw and m_Pitch here--see View constructor)
this->playAnimation();
}
@ -209,6 +219,53 @@ void Engine::loadMesh( const wstring &fileName )
if (mesh != nullptr) {
m_LoadedMesh = m_Scene->addAnimatedMeshSceneNode( mesh );
Utility::dumpMeshInfoToConsole( m_LoadedMesh );
if (Utility::toLower(Utility::extensionOf(fileName)) == L"3ds") {
m_View->setZUp(true);
}
else {
m_View->setZUp(false);
}
if (m_LoadedMesh != nullptr) {
ICameraSceneNode *camera = this->m_Scene->getActiveCamera();
aabbox3d<f32> box = m_LoadedMesh->getTransformedBoundingBox();
vector3d<float> extents = box.getExtent();
if (m_View->zUp()) {
float oldDist = m_CamPos.getDistanceFrom(m_CamTarget);
float newDist = oldDist;
if (oldDist != 0) {
vector3d<float> center = box.getCenter();
vector3df edges[8];
box.getEdges(edges);
/*
/3--------/7
/ | / |
/ | / |
1---------5 |
| 2- - -| -6
| / | /
|/ | /
0---------4/
*/
newDist = 0;
for (int i=0; i<8; i++) {
float tryDist = center.getDistanceFrom(edges[i]);
if (tryDist>newDist) newDist = tryDist;
}
newDist *= 2; // so camera doesn't touch model
if (!Utility::equalsApprox<float>(newDist, oldDist)) {
float scale = newDist / oldDist; // already checked 0
vector3df oldCamPos = camera->getPosition();
m_CamPos = oldCamPos;
m_CamPos.X = m_CamPos.X * scale;
m_CamPos.Y = m_CamPos.Y * scale;
m_CamPos.Z = m_CamPos.Z * scale;
oldCamPos = m_CamPos;
m_View->setCameraDistance(m_CamPos.getDistanceFrom(m_CamTarget));
camera->setPosition(m_CamPos);
}
}
}
}
}
}
@ -310,6 +367,13 @@ void Engine::setAnimationFPS(u32 animationFPS)
}
}
void Engine::setZUp(bool zUp)
{
if (this->m_View != nullptr) {
this->m_View->setZUp(zUp);
}
}
u32 Engine::animationFPS()
{
u32 ret = 0;

View File

@ -63,6 +63,9 @@ private:
irr::core::vector3df m_CamPos;
irr::core::vector3df m_CamTarget;
std::wstring m_FontPath = L"ClearSansRegular.ttf"; // core::stringc has implicit conversion to io::path
bool KeyIsDown[irr::KEY_KEY_CODES_COUNT];
irr::s32 keyState[irr::KEY_KEY_CODES_COUNT];
irr::s32 LMouseState,RMouseState;
public:
std::wstring m_PreviousPath;
@ -83,6 +86,7 @@ public:
void pauseAnimation();
void toggleAnimation();
void setAnimationFPS(irr::u32 animationFPS);
void setZUp(bool zUp);
irr::u32 animationFPS();
};

View File

@ -1,6 +1,6 @@
# b3view
Press 't' for Minetest ../textures with this (poikilos') forked model
viewer for B3D, X, or OBJ files (or any supported by Irrlicht).
viewer for B3D, X, OBJ, MS3D, 3DS (or any supported by Irrlicht).
![screenshot with gull from poikilos mobs_sky fork](https://github.com/poikilos/b3view/raw/master/screenshot.jpg)
@ -126,12 +126,17 @@ only applies to Visual Studio users.)
the model file's own directory will be used.
* `F5`: Reload last model file
* `r`: Reload last texture file
* drag with middle button: rotate view
* drag with middle button while holding shift key: pan up and down
* `z` or `y`: change camera "up" axis to Z or Y (Y is default;
automatically changed to Z when 3ds file is loaded)
## Known Issues
* Warn on missing texture.
* Test and complete install.bat on Windows.
* Look for fonts on OS X (see "Set Font for UI Elements" in
UserInterface.cpp).
* (View.cpp) Set pitch correctly for shift & middle mouse button drag.
## Authors
* ClearSansRegular.ttf (**Apache 2.0 License**) by Intel

View File

@ -161,14 +161,6 @@ void UserInterface::handleMenuItemPressed( IGUIContextMenu *menu )
UserInterface::UserInterface( Engine *engine )
{
this->playbackStartStopButton = nullptr;
// For monitoring single press: see
// <http://irrlicht.sourceforge.net/forum/viewtopic.php?p=210744>
for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
KeyIsDown[i] = false;
for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
keyState[i] = 0;
LMouseState = 0;
RMouseState = 0;
m_Engine = engine;
m_Gui = engine->getGUIEnvironment();
@ -266,8 +258,11 @@ bool UserInterface::OnEvent( const SEvent &event )
{
// Events arriving here should be destined for us
if (event.EventType == EET_KEY_INPUT_EVENT) {
if (event.KeyInput.PressedDown && !KeyIsDown[event.KeyInput.Key]) {
if (event.KeyInput.Key == irr::KEY_KEY_T) {
if (event.KeyInput.PressedDown && !m_Engine->KeyIsDown[event.KeyInput.Key]) {
if (event.KeyInput.Key == irr::KEY_F5) {
m_Engine->reloadMesh();
}
else if (event.KeyInput.Key == irr::KEY_KEY_T) {
loadNextTexture(1);
}
else if (event.KeyInput.Key == irr::KEY_KEY_E) {
@ -276,8 +271,11 @@ bool UserInterface::OnEvent( const SEvent &event )
else if (event.KeyInput.Key == irr::KEY_KEY_R) {
m_Engine->reloadTexture();
}
else if (event.KeyInput.Key == irr::KEY_F5) {
m_Engine->reloadMesh();
else if (event.KeyInput.Key == irr::KEY_KEY_Z) {
m_Engine->setZUp(true);
}
else if (event.KeyInput.Key == irr::KEY_KEY_Y) {
m_Engine->setZUp(false);
}
else if (event.KeyInput.Char == L'+' || event.KeyInput.Char == L'=') {
m_Engine->setAnimationFPS(m_Engine->animationFPS() + 5);
@ -292,7 +290,7 @@ bool UserInterface::OnEvent( const SEvent &event )
}
// std::wcerr << "Char: " << event.KeyInput.Char << endl;
}
KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
m_Engine->KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
return true;
}
@ -302,30 +300,26 @@ bool UserInterface::OnEvent( const SEvent &event )
switch ( event.MouseInput.Event)
{
case EMIE_LMOUSE_LEFT_UP:
if ( LMouseState == 2)
{
LMouseState = 3;
if ( m_Engine->LMouseState == 2) {
m_Engine->LMouseState = 3;
}
break;
case EMIE_LMOUSE_PRESSED_DOWN:
if ( LMouseState == 0)
{
LMouseState = 1;
if ( m_Engine->LMouseState == 0) {
m_Engine->LMouseState = 1;
}
break;
case EMIE_RMOUSE_LEFT_UP:
if ( RMouseState == 2)
{
RMouseState = 3;
if ( m_Engine->RMouseState == 2) {
m_Engine->RMouseState = 3;
}
break;
case EMIE_RMOUSE_PRESSED_DOWN:
if ( RMouseState == 0)
{
RMouseState = 1;
if ( m_Engine->RMouseState == 0) {
m_Engine->RMouseState = 1;
}
break;
}

View File

@ -45,10 +45,6 @@ private:
bool m_WireframeDisplay;
bool m_Lighting;
bool KeyIsDown[irr::KEY_KEY_CODES_COUNT];
irr::s32 keyState[irr::KEY_KEY_CODES_COUNT];
irr::s32 LMouseState,RMouseState;
public:
irr::gui::IGUIButton *playbackStartStopButton;
irr::gui::IGUIButton *playbackIncreaseButton;

View File

@ -187,3 +187,9 @@ bool Utility::isFile(const std::wstring& name) {
}
//don't do late instantiation (see header file)
//template<typename T>
//bool Utility::equalsApprox(T f1, T f2)
//{
// return abs(f2-f1) < .00000001; // TODO: kEpsilon? (see also <https://en.wikipedia.org/wiki/Machine_epsilon#How_to_determine_machine_epsilon>)
//}

View File

@ -20,6 +20,12 @@ public:
static std::string toString(const std::wstring &name);
static std::string toLower(const std::string &s);
static std::wstring toLower(const std::wstring &s);
// compiler doesn't like template function when class is not a template--instantiate immediately
// see http://processors.wiki.ti.com/index.php/C%2B%2B_Template_Instantiation_Issues
template <typename T>
static bool equalsApprox(T f1, T f2) {
return abs(f2-f1) < .00000001; // TODO: kEpsilon? (see also <https://en.wikipedia.org/wiki/Machine_epsilon#How_to_determine_machine_epsilon>)
}
};
#endif // UTILS_H

168
View.cpp
View File

@ -1,4 +1,5 @@
#include "View.h"
#include <iostream>
#include "Engine.h"
using namespace irr;
@ -6,29 +7,73 @@ using namespace irr::core;
using namespace irr::scene;
void View::setNewCameraPosition()
{
setNewCameraPosition(m_zUp);
}
void View::setNewCameraPosition(bool zUp)
{
vector3d<f32> newCameraPosition;
ICameraSceneNode *camera = m_Engine->m_Scene->getActiveCamera();
if (zUp) {
camera->setUpVector(vector3df(0, 0, 1));
}
else {
camera->setUpVector(vector3df(0, 1, 0));
}
vector3df oldCamPos = camera->getPosition();
// vector3df oldCamRot = camera->getRotation();
// NOTE: rotationToDirection converts a rotation to a vec3 direction.
// vector3df oldCamRot = m_Engine->tmpPosVec3f.?(m_Engine->tmpTargetVec3f);
newCameraPosition.X = 0;
newCameraPosition.Y = m_CameraDistance * sin( m_Pitch );
newCameraPosition.Z = m_CameraDistance * cos( m_Pitch );
matrix4 yawMatrix;
yawMatrix.setRotationRadians( vector3df( 0, m_Yaw, 0 ));
yawMatrix.transformVect( newCameraPosition );
if (m_zUp != zUp) {
float z;
z = oldCamPos.Y;
oldCamPos.Y = oldCamPos.Z;
oldCamPos.Z = z;
z = m_Engine->m_CamPos.Y;
m_Engine->m_CamPos.Y = m_Engine->m_CamPos.Z;
m_Engine->m_CamPos.Z = z;
z = m_Engine->m_CamTarget.Y;
m_Engine->m_CamTarget.Y = m_Engine->m_CamTarget.Z;
m_Engine->m_CamTarget.Z = z;
camera->setPosition(m_Engine->m_CamPos);
camera->setTarget(m_Engine->m_CamTarget);
}
if (zUp) {
newCameraPosition.X = 0;
newCameraPosition.Y = m_CameraDistance * cos(m_Pitch);
newCameraPosition.Z = m_CameraDistance * sin(m_Pitch);
yawMatrix.setRotationRadians(vector3df(0, 0, m_Yaw));
}
else {
newCameraPosition.X = 0;
newCameraPosition.Y = m_CameraDistance * sin( m_Pitch );
newCameraPosition.Z = m_CameraDistance * cos( m_Pitch );
yawMatrix.setRotationRadians(vector3df(0, m_Yaw, 0));
}
newCameraPosition.Y = oldCamPos.Y;
yawMatrix.transformVect(newCameraPosition);
if (zUp) {
//camera->setUpVector(vector3df(0, 0, 1));
//newCameraPosition.Z = oldCamPos.Z;
}
else {
//camera->setUpVector(vector3df(0, 1, 0));
//newCameraPosition.Y = oldCamPos.Y;
}
camera->setPosition( newCameraPosition );
// vector3df newRotation();
// camera->setRotation();
// camera->setTarget(m_Engine->tmpTargetVec3f);
camera->setTarget(m_Engine->m_CamTarget);
// Set Light direction
setNewLightDirection( newCameraPosition );
m_zUp = zUp;
// std::wcerr << L" setCameraPosition pitch: " << m_Pitch << endl;
}
void View::setNewLightDirection( const vector3df &cameraPosition )
@ -43,6 +88,7 @@ void View::setNewLightDirection( const vector3df &cameraPosition )
View::View( Engine *engine )
{
m_zUp = false;
m_Engine = engine;
m_LastMousePosition = new vector2d<int>();
m_RotMouse = false;
@ -50,16 +96,17 @@ View::View( Engine *engine )
m_Pitch = PI;
// Set Camera Distance
m_CameraDistance = 10;
// vectors for angle are opposite, since camera revolves around center
// m_CameraDistance = 10;
// m_CameraDistance = engine->m_CamTarget.getDistanceFrom(engine->m_CamPos);
// Calculate offsetVec3 manually, since the object is needed later
// (Vectors for angle are opposite, since camera revolves around center):
vector3df offsetVec3(
engine->m_CamPos.X-engine->m_CamTarget.X,
engine->m_CamPos.Y-engine->m_CamTarget.Y,
engine->m_CamPos.Z-engine->m_CamTarget.Z
);
// m_CameraDistance = sqrtf()
m_CameraDistance = offsetVec3.getLength();
// NOTE: rotationToDirection converts a rotation to a vec3 direction
// vector3df rotationVec3 = engine->tmpPosVec3f.?(engine->tmpTargetVec3f);
// vector3df rotationVec3 = engine->tmpTargetVec3f.?(engine->tmpPosVec3f);
@ -82,6 +129,23 @@ View::~View()
delete m_LastMousePosition;
}
void View::setZUp(bool zUp)
{
if (zUp != m_zUp) {
setNewCameraPosition(zUp);
}
}
void View::setCameraDistance(float cameraDistance)
{
m_CameraDistance = cameraDistance;
}
bool View::zUp()
{
return m_zUp;
}
// IEventReceiver
bool View::OnEvent( const SEvent &event )
{
@ -126,15 +190,83 @@ bool View::OnEvent( const SEvent &event )
m_LastMousePosition->X = mouseEvent->X;
m_LastMousePosition->Y = mouseEvent->Y;
if (m_Engine->KeyIsDown[irr::KEY_RSHIFT] || m_Engine->KeyIsDown[irr::KEY_LSHIFT]) {
// Pan camera.
float yDelta = (dy / 400.0f) * m_CameraDistance;
ICameraSceneNode *camera = m_Engine->m_Scene->getActiveCamera();
vector3df rotationVec3;
rotationVec3 = camera->getRotation();
vector3df forwards(0, 0, 1);
vector3df dirVec3 = camera->getUpVector();
// vector3df camRot = camera->getRotation();
vector3df camRot(0, 0, 0);
// TODO: fix this (pitch becomes flat)
camRot.X = m_Pitch;
if (m_zUp) {
camRot.Z = m_Yaw;
forwards = vector3df(0, 1, 0);
dirVec3.rotateYZBy(camRot.X);
dirVec3.rotateXYBy(camRot.Z);
}
else {
camRot.Z = m_Pitch;
dirVec3.rotateYZBy(camRot.X);
dirVec3.rotateXYBy(camRot.Y);
}
// vector3df dirVec3 = rotationVec3.rotationToDirection(forwards);
// // move up and down, not in and out:
// float z = dirVec3.Z;
// dirVec3.Z = dirVec3.Y;
// dirVec3.Z = z;
dirVec3.X *= yDelta;
dirVec3.Y *= yDelta;
dirVec3.Z *= yDelta;
m_Engine->m_CamPos.X += dirVec3.X;
m_Engine->m_CamPos.Y += dirVec3.Y;
m_Engine->m_CamPos.Z += dirVec3.Z;
m_Engine->m_CamTarget.X += dirVec3.X;
m_Engine->m_CamTarget.Y += dirVec3.Y;
m_Engine->m_CamTarget.Z += dirVec3.Z;
if (m_zUp) {
//m_Engine->m_CamPos.Z += yDelta;
//m_Engine->m_CamTarget.Z += yDelta;
}
else {
//m_Engine->m_CamPos.Y += yDelta;
//m_Engine->m_CamTarget.Y += yDelta;
}
camera->setPosition(m_Engine->m_CamPos);
camera->setTarget(m_Engine->m_CamTarget);
vector3df offsetVec3(
m_Engine->m_CamPos.X-m_Engine->m_CamTarget.X,
m_Engine->m_CamPos.Y-m_Engine->m_CamTarget.Y,
m_Engine->m_CamPos.Z-m_Engine->m_CamTarget.Z
);
m_CameraDistance = offsetVec3.getLength();
f32 pitchDelta = dy / 120.0f;
if(( m_Pitch - pitchDelta > ( PI - ( PI / 2 ))) && ( m_Pitch - pitchDelta < PI + ( PI/2 )))
m_Pitch -= dy / 120.0f;
m_Yaw = atan2(offsetVec3.X, offsetVec3.Z);
m_Pitch = asin(-offsetVec3.Y);
setNewCameraPosition();
}
else {
// Revolve camera around object.
// increments of 120 pixels * PI are equal to 180 deg (PI radians):
f32 pitchDelta = dy / 120.0f;
// (This old code which may make assumptions about view tends to lock on min/max)
// if(( m_Pitch - pitchDelta > ( PI - ( PI / 2 ))) && ( m_Pitch - pitchDelta < PI + ( PI/2 )))
// m_Pitch -= dy / 120.0f;
m_Pitch += pitchDelta;
float minPitch = -PI/2.0f + PI/1000.0f;
float maxPitch = PI/2.0f - PI/1000.0f;
if (m_Pitch < minPitch) m_Pitch = minPitch;
else if (m_Pitch > maxPitch) m_Pitch = maxPitch;
// std::wcerr << "pitch = " << m_Pitch << endl;
m_Yaw += dx / 120.0f;
m_Yaw += dx / 120.0f;
// Set Camera to new rotation
setNewCameraPosition();
// Set Camera to new rotation
setNewCameraPosition();
}
}
return true;

6
View.h
View File

@ -12,13 +12,19 @@ private:
irr::f32 m_Yaw, m_Pitch, m_CameraDistance;
irr::core::vector2d<int> *m_LastMousePosition;
bool m_RotMouse;
bool m_zUp;
void setNewCameraPosition();
void setNewCameraPosition(bool zUp);
void setNewLightDirection( const irr::core::vector3df &cameraPosition );
public:
View( Engine *engine );
~View();
void setZUp(bool zUp);
void setCameraDistance(float cameraDistance);
bool zUp();
bool m_Shift;
// IEventReceiver
virtual bool OnEvent( const irr::SEvent &event );

View File

@ -113,50 +113,84 @@ if [ ! -d "$MIMETYPES_DB_PATH/packages" ]; then
mkdir "$MIMETYPES_DB_PATH/packages"
fi
update_mime_enable=false
if [ -f "$mime_path" ]; then
# echo "Copying as '$MIMETYPES_DB_PATH/packages/$mime_name'..."
try_dest="$MIMETYPES_DB_PATH/packages/$mime_name"
if diff -q $mime_path $try_dest; then
echo "(You already have an identical $try_dest)"
else
cp -f "$mime_path" "$MIMETYPES_DB_PATH/packages/"
if [ -f "$try_dest" ]; then
echo "Successfully copied '$try_dest'"
update_mime_enable=true
fi
fi
mime_name=model-x.xml
mime_path="$mimes_path/$mime_name"
try_dest="$MIMETYPES_DB_PATH/packages/$mime_name"
if diff -q $mime_path $try_dest; then
echo "(You already have an identical $try_dest)"
else
cp -f "$mime_path" "$MIMETYPES_DB_PATH/packages/"
if [ -f "$try_dest" ]; then
echo "Successfully copied '$try_dest'"
update_mime_enable=true
fi
fi
# Since OBJ Mime type is broken on linux (detected as TGIF), trying
# to add an overlapping mime type breaks it worse (KDE detects the
# file as "plain text file" if the xml file below is installed)
mime_name=model-obj.xml
mime_path="$mimes_path/$mime_name"
# cp -f "$mime_path" "$MIMETYPES_DB_PATH/packages/"
# if [ -f "$MIMETYPES_DB_PATH/packages/$mime_name" ]; then
# echo "Successfully copied '$MIMETYPES_DB_PATH/packages/$mime_name'"
# rm -f "$MIMETYPES_DB_PATH/packages/$mime_name"
# fi
if [ "@$update_mime_enable" = "@true" ]; then
echo "Updating mime type database '$MIMETYPES_DB_PATH'..."
update-mime-database "$MIMETYPES_DB_PATH" # must contain packages
fi
echo "Done."
if [ ! -f "$mime_path" ]; then
echo "ERROR: Stopped installing mime types since missing $mime_path"
exit 1
fi
try_dest="$MIMETYPES_DB_PATH/packages/$mime_name"
if diff -q $mime_path $try_dest; then
echo "* (You already have an identical $try_dest)"
else
echo "ERROR: $mime_path must be in working directory in order to install it using this script."
cp -f "$mime_path" "$MIMETYPES_DB_PATH/packages/"
if [ -f "$try_dest" ]; then
echo "* Successfully copied '$try_dest'"
update_mime_enable=true
fi
fi
mime_name=model-x.xml
mime_path="$mimes_path/$mime_name"
if [ ! -f "$mime_path" ]; then
echo "ERROR: Stopped installing mime types since missing $mime_path"
exit 1
fi
try_dest="$MIMETYPES_DB_PATH/packages/$mime_name"
if diff -q $mime_path $try_dest; then
echo "* (You already have an identical $try_dest)"
else
cp -f "$mime_path" "$MIMETYPES_DB_PATH/packages/"
if [ -f "$try_dest" ]; then
echo "* Successfully copied '$try_dest'"
update_mime_enable=true
fi
fi
# Since OBJ Mime type is broken on linux (detected as TGIF obj/sym
# hyperlinked vector graphics format unrelated to Wavefront OBJ
# format but sharing the same file extension), trying
# to add an overlapping mime type breaks it worse (KDE detects the
# file as "plain text file" if the xml file below is installed)
mime_name=model-obj.xml
mime_path="$mimes_path/$mime_name"
#if [ ! -f "$mime_path" ]; then
#echo "ERROR: Stopped installing mime types since missing $mime_path"
#exit 1
#fi
try_dest="$MIMETYPES_DB_PATH/packages/$mime_name"
#if diff -q $mime_path $try_dest; then
#echo "* (You already have an identical $try_dest)"
#else
#cp -f "$mime_path" "$MIMETYPES_DB_PATH/packages/"
if [ -f "$MIMETYPES_DB_PATH/packages/$mime_name" ]; then
# echo "* Successfully copied '$MIMETYPES_DB_PATH/packages/$mime_name'"
echo "* Removing '$MIMETYPES_DB_PATH/packages/$mime_name' (overlaps with system usually)"
rm -f "$MIMETYPES_DB_PATH/packages/$mime_name"
update_mime_enable=true
fi
#fi
mime_name=model-ms3d.xml
mime_path="$mimes_path/$mime_name"
if [ ! -f "$mime_path" ]; then
echo "ERROR: Stopped installing mime types since missing $mime_path"
exit 1
fi
try_dest="$MIMETYPES_DB_PATH/packages/$mime_name"
if diff -q $mime_path $try_dest; then
echo "(You already have an identical $try_dest)"
else
cp -f "$mime_path" "$MIMETYPES_DB_PATH/packages/"
if [ -f "$MIMETYPES_DB_PATH/packages/$mime_name" ]; then
echo "Successfully copied '$MIMETYPES_DB_PATH/packages/$mime_name'"
# rm -f "$MIMETYPES_DB_PATH/packages/$mime_name"
update_mime_enable=true
fi
fi
if [ "@$update_mime_enable" = "@true" ]; then
echo "Updating mime type database '$MIMETYPES_DB_PATH'..."
update-mime-database "$MIMETYPES_DB_PATH" # must contain packages
fi
echo "Done."
echo
echo

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="model/ms3d">
<comment>MilkShape 3D Model File</comment>
<icon name="model-ms3d"/>
<glob-deleteall/>
<glob pattern="*.ms3d"/>
</mime-type>
</mime-info>

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="model/obj">
<comment>OBJ file</comment>
<comment>Wavefront OBJ Model File</comment>
<icon name="model-obj"/>
<glob-deleteall/>
<remove fileExtension=".obj" />
<mimeMap fileExtension=".obj" mimeType="text/plain" />
<mimeMap fileExtension=".obj" mimeType="model/obj" />
<glob pattern="*.obj"/>
</mime-type>
</mime-info>