Commit 40480a78 authored by hybrid's avatar hybrid

Merged revisions 4001-4056 from 1.7 branch. Keycode updates, fix compilation...

Merged revisions 4001-4056 from 1.7 branch. Keycode updates, fix compilation errors, vector normalize error case fixed, joystick safety fixes, editbox updates, meshviewer modal window fix, isPointInsideFast changes.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@4057 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 66a6bbde
......@@ -293,12 +293,30 @@ The following names can be queried for the given types:
-----------------------------
Changes in 1.7.3 (??.??.2011)
- Document that triangle3d::isPointInside should not be used with int's.
- triangle3d::isPointInsideFast handles 'on-border' cases now consistently.
- Bugfix: vector2d.normalize() and vector3d.normalize() had returned wrong results with very short vectors since Irrlicht 1.5. Thanks to Willem Swart for Bugreport + testcase.
- Unknown keymappings now use the X11 keycode instead of 0 to make such keys at least usable in games.
- KeyMapping for KeyInput.Key on X11 ignores states like shift&ctrl now like on Windows.
- Additional keymappings for X11 (tested with german and us keyboards which seem to work now in all cases).
- Fix crash in multiline editbox when pasting several lines into it on Windows.
- example 09.Meshviewer no longer catches keys while a modal dialog is open
- editbox no longer displays cursor when disabled
- editbox autoscrolling now at least works good enough to actually show the text which the user is typing in.
- editbox no longer moves text into next line when it fails wrapping creating senseless empty lines which mess up scrolling.
- Fix crash in editbox when scrolling up with empty first lines caused by textwrapping.
- triangle3d::isPointInside can now work with larger integers, old version failed already with values in the 3-digit range. It got also faster. (thx @ Eigen for report + testcase and REDDemon for patch proposal).
- Fix focus problem when removing an unfocused modal dialog reported by Reiko here: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=44358
- Add integer template specialization for vector3d::getSphericalCoordinateAngles which rounds angles to nearest integer now.
......
......@@ -147,8 +147,7 @@ void updateScaleInfo(scene::ISceneNode* model)
}
/*
The three following functions do several stuff used by the mesh viewer. The
first function showAboutText() simply displays a messagebox with a caption and
Function showAboutText() displays a messagebox with a caption and
a message text. The texts will be stored in the MessageText and Caption
variables at startup.
*/
......@@ -162,7 +161,7 @@ void showAboutText()
/*
The second function loadModel() loads a model and displays it using an
Function loadModel() loads a model and displays it using an
addAnimatedMeshSceneNode and the scene manager. Nothing difficult. It also
displays a short message box, if the model could not be loaded.
*/
......@@ -259,7 +258,7 @@ void loadModel(const c8* fn)
/*
Finally, the third function creates a toolbox window. In this simple mesh
Function createToolBox() creates a toolbox window. In this simple mesh
viewer, this toolbox only contains a tab control with three edit boxes for
changing the scale of the displayed model.
*/
......@@ -323,6 +322,10 @@ void createToolBox()
scrollbar->setSmallStep(1);
}
/*
Function updateToolBox() is called each frame to update dynamic information in
the toolbox.
*/
void updateToolBox()
{
IGUIEnvironment* env = Device->getGUIEnvironment();
......@@ -375,11 +378,27 @@ void onKillFocus()
}
}
/*
Function hasModalDialog() checks if we currently have a modal dialog open.
*/
bool hasModalDialog()
{
IGUIEnvironment* env = Device->getGUIEnvironment();
IGUIElement * focused = env->getFocus();
while ( focused )
{
if ( focused->isVisible() && focused->hasType(EGUIET_MODAL_SCREEN) )
return true;
focused = focused->getParent();
}
return false;
}
/*
To get all the events sent by the GUI Elements, we need to create an event
receiver. This one is really simple. If an event occurs, it checks the id of
the caller and the event type, and starts an action based on these values. For
example, if a menu item with id GUI_ID_OPEN_MODEL was selected, if opens a file-open-dialog.
example, if a menu item with id GUI_ID_OPEN_MODEL was selected, it opens a file-open-dialog.
*/
class MyEventReceiver : public IEventReceiver
{
......@@ -503,6 +522,11 @@ public:
*/
bool OnKeyUp(irr::EKEY_CODE keyCode)
{
// Don't handle keys if we have a modal dialog open as it would lead
// to unexpected application behaviour for the user.
if ( hasModalDialog() )
return false;
if (keyCode == irr::KEY_ESCAPE)
{
if (Device)
......
......@@ -788,7 +788,7 @@ funcptr_createDeviceEx load_createDeviceEx ( const c8 * filename)
#endif
/*
get the current collision respone camera animator
get the current collision response camera animator
*/
ISceneNodeAnimatorCollisionResponse* camCollisionResponse( IrrlichtDevice * device )
{
......
......@@ -69,9 +69,9 @@ namespace gui
//! Sets text justification mode
/** \param horizontal: EGUIA_UPPERLEFT for left justified (default),
EGUIA_LOWEERRIGHT for right justified, or EGUIA_CENTER for centered text.
EGUIA_LOWERRIGHT for right justified, or EGUIA_CENTER for centered text.
\param vertical: EGUIA_UPPERLEFT to align with top edge,
EGUIA_LOWEERRIGHT for bottom edge, or EGUIA_CENTER for centered text (default). */
EGUIA_LOWERRIGHT for bottom edge, or EGUIA_CENTER for centered text (default). */
virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) = 0;
//! Enables or disables word wrap.
......
......@@ -141,10 +141,20 @@ namespace irr
KEY_RCONTROL = 0xA3, // Right CONTROL key
KEY_LMENU = 0xA4, // Left MENU key
KEY_RMENU = 0xA5, // Right MENU key
KEY_PLUS = 0xBB, // Plus Key (+)
KEY_COMMA = 0xBC, // Comma Key (,)
KEY_MINUS = 0xBD, // Minus Key (-)
KEY_PERIOD = 0xBE, // Period Key (.)
KEY_OEM_1 = 0xBA, // for US ";:"
KEY_PLUS = 0xBB, // Plus Key "+"
KEY_COMMA = 0xBC, // Comma Key ","
KEY_MINUS = 0xBD, // Minus Key "-"
KEY_PERIOD = 0xBE, // Period Key "."
KEY_OEM_2 = 0xBF, // for US "/?"
KEY_OEM_3 = 0xC0, // for US "`~"
KEY_OEM_4 = 0xDB, // for US "[{"
KEY_OEM_5 = 0xDC, // for US "\|"
KEY_OEM_6 = 0xDD, // for US "]}"
KEY_OEM_7 = 0xDE, // for US "'""
KEY_OEM_8 = 0xDF, // None
KEY_OEM_AX = 0xE1, // for Japan "AX"
KEY_OEM_102 = 0xE2, // "<>" or "\|"
KEY_ATTN = 0xF6, // Attn key
KEY_CRSEL = 0xF7, // CrSel key
KEY_EXSEL = 0xF8, // ExSel key
......
......@@ -82,10 +82,27 @@ namespace core
}
//! Check if a point is inside the triangle (border-points count also as inside)
/** \param p Point to test. Assumes that this point is already
/** NOTE: When working with T='int' you should prefer isPointInsideFast, as
isPointInside will run into number-overflows already with coordinates in the 3-digit-range.
\param p Point to test. Assumes that this point is already
on the plane of the triangle.
\return True if the point is inside the triangle, otherwise false. */
bool isPointInside(const vector3d<T>& p) const
{
return (isOnSameSide(p, pointA, pointB, pointC) &&
isOnSameSide(p, pointB, pointA, pointC) &&
isOnSameSide(p, pointC, pointA, pointB));
}
//! Check if a point is inside the triangle (border-points count also as inside)
/** This method uses a barycentric coordinate system.
It is faster than isPointInside but is more susceptible to floating point rounding
errors. This will especially be noticable when the FPU is in single precision mode
(which is for example set on default by Direct3D).
\param p Point to test. Assumes that this point is already
on the plane of the triangle.
\return True if point is inside the triangle, otherwise false. */
bool isPointInsideFast(const vector3d<T>& p) const
{
const vector3d<T> a = pointC - pointA;
const vector3d<T> b = pointB - pointA;
......@@ -105,38 +122,7 @@ namespace core
// We count border-points as inside to keep downward compatibility.
// That's why we use >= and <= instead of > and < as more commonly seen on the web.
return (u >= 0) && (v >= 0) && (u + v <= 1);
}
//! Check if a point is inside the triangle.
/** This method is an implementation of the example used in a
paper by Kasper Fauerby original written by Keidy from
Mr-Gamemaker.
This was once faster than an old isPointInside implementation, but the
current isPointInside is usualy as fast, sometimes even faster.
Border-points in isPointInsideFast are not defined, some are inside and some outside.
\param p Point to test. Assumes that this point is already
on the plane of the triangle.
\return True if point is inside the triangle, otherwise false. */
bool isPointInsideFast(const vector3d<T>& p) const
{
const vector3d<T> f = pointB - pointA;
const vector3d<T> g = pointC - pointA;
const f32 a = f.dotProduct(f);
const f32 b = f.dotProduct(g);
const f32 c = g.dotProduct(g);
const vector3d<T> vp = p - pointA;
const f32 d = vp.dotProduct(f);
const f32 e = vp.dotProduct(g);
f32 x = (d*c)-(e*b);
f32 y = (e*a)-(d*b);
const f32 ac_bb = (a*c)-(b*b);
f32 z = x+y-ac_bb;
// return sign(z) && !(sign(x)||sign(y))
return (( (IR(z)) & ~((IR(x))|(IR(y))) ) & 0x80000000)!=0;
}
......
......@@ -170,7 +170,7 @@ public:
vector2d<T>& normalize()
{
f32 length = (f32)(X*X + Y*Y);
if (core::equals(length, 0.f))
if ( length == 0 )
return *this;
length = core::reciprocal_squareroot ( length );
X = (T)(X * length);
......
......@@ -168,7 +168,7 @@ namespace core
vector3d<T>& normalize()
{
f64 length = X*X + Y*Y + Z*Z;
if (core::equals(length, 0.0)) // this check isn't an optimization but prevents getting NAN in the sqrt.
if (length == 0 ) // this check isn't an optimization but prevents getting NAN in the sqrt.
return *this;
length = core::reciprocal_squareroot(length);
......
......@@ -94,9 +94,10 @@ The Irrlicht Engine SDK version 1.8
* Linux:
* Needed: XServer with include files
* Optional: OpenGL headers and libraries (libGL.so), for OpenGL support
* GLX + XF86VidMode or XRandr extension (X11 support libraries,
the latter two for fullscreen mode)
* Optional: OpenGL headers and libraries (libGL.so) for OpenGL support
GLX +
XF86VidMode [package x11proto-xf86vidmode-dev] or XRandr
(X11 support libraries, the latter two for fullscreen mode)
* OSX:
* Needed: XCode and Cocoa framework
......
......@@ -871,7 +871,8 @@ void CGUIEditBox::draw()
}
// draw cursor
if ( IsEnabled )
{
if (WordWrap || MultiLine)
{
cursorLine = getLineFromPos(CursorPos);
......@@ -892,6 +893,7 @@ void CGUIEditBox::draw()
false, true, &localClipRect);
}
}
}
// draw children
IGUIElement::draw();
......@@ -1113,8 +1115,13 @@ void CGUIEditBox::breakText()
c = 0;
if (Text[i+1] == L'\n') // Windows breaks
{
// TODO: I (Michael) think that we shouldn't change the text given by the user for whatever reason.
// Instead rework the cursor positioning to be able to handle this (but not in stable release
// branch as users might already expect this behaviour).
Text.erase(i+1);
--size;
if ( CursorPos > i )
--CursorPos;
}
}
else if (c == L'\n') // Unix breaks
......@@ -1186,7 +1193,10 @@ void CGUIEditBox::breakText()
BrokenTextPositions.push_back(lastLineStart);
}
// TODO: that function does interpret VAlign according to line-index (indexed line is placed on top-center-bottom)
// but HAlign according to line-width (pixels) and not by row.
// Intuitively I suppose HAlign handling is better as VScrollPos should handle the line-scrolling.
// But please no one change this without also rewriting (and this time fucking testing!!!) autoscrolling (I noticed this when fixing the old autoscrolling).
void CGUIEditBox::setTextRect(s32 line)
{
if ( line < 0 )
......@@ -1317,54 +1327,129 @@ void CGUIEditBox::inputChar(wchar_t c)
calculateScrollPos();
}
// calculate autoscroll
void CGUIEditBox::calculateScrollPos()
{
if (!AutoScroll)
return;
// calculate horizontal scroll position
IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
if (!font)
return;
s32 cursLine = getLineFromPos(CursorPos);
if ( cursLine < 0 )
return;
setTextRect(cursLine);
const bool hasBrokenText = MultiLine || WordWrap;
// don't do horizontal scrolling when wordwrap is enabled.
if (!WordWrap)
// Check horizonal scrolling
// NOTE: Calculations different to vertical scrolling because setTextRect interprets VAlign relative to line but HAlign not relative to row
{
// get cursor position
IGUIFont* font = getActiveFont();
if (!font)
return;
core::stringw *txtLine = MultiLine ? &BrokenText[cursLine] : &Text;
s32 cPos = MultiLine ? CursorPos - BrokenTextPositions[cursLine] : CursorPos;
// get cursor area
irr::u32 cursorWidth = font->getDimension(L"_").Width;
core::stringw *txtLine = hasBrokenText ? &BrokenText[cursLine] : &Text;
s32 cPos = hasBrokenText ? CursorPos - BrokenTextPositions[cursLine] : CursorPos; // column
s32 cStart = font->getDimension(txtLine->subString(0, cPos).c_str()).Width; // pixels from text-start
s32 cEnd = cStart + cursorWidth;
s32 txtWidth = font->getDimension(txtLine->c_str()).Width;
s32 cStart = CurrentTextRect.UpperLeftCorner.X + HScrollPos +
font->getDimension(txtLine->subString(0, cPos).c_str()).Width;
s32 cEnd = cStart + font->getDimension(L"_ ").Width;
if ( txtWidth < FrameRect.getWidth() )
{
// TODO: Needs a clean left and right gap removal depending on HAlign, similar to vertical scrolling tests for top/bottom.
// This check just fixes the case where it was most noticable (text smaller than clipping area).
if (FrameRect.LowerRightCorner.X < cEnd)
HScrollPos = cEnd - FrameRect.LowerRightCorner.X;
else if (FrameRect.UpperLeftCorner.X > cStart)
HScrollPos = cStart - FrameRect.UpperLeftCorner.X;
else
HScrollPos = 0;
// todo: adjust scrollbar
setTextRect(cursLine);
}
// vertical scroll position
if (FrameRect.LowerRightCorner.Y < CurrentTextRect.LowerRightCorner.Y + VScrollPos)
VScrollPos = CurrentTextRect.LowerRightCorner.Y - FrameRect.LowerRightCorner.Y + VScrollPos;
if ( CurrentTextRect.UpperLeftCorner.X+cStart < FrameRect.UpperLeftCorner.X )
{
// cursor to the left of the clipping area
HScrollPos -= FrameRect.UpperLeftCorner.X-(CurrentTextRect.UpperLeftCorner.X+cStart);
setTextRect(cursLine);
// TODO: should show more characters to the left when we're scrolling left
// and the cursor reaches the border.
}
else if ( CurrentTextRect.UpperLeftCorner.X+cEnd > FrameRect.LowerRightCorner.X)
{
// cursor to the right of the clipping area
HScrollPos += (CurrentTextRect.UpperLeftCorner.X+cEnd)-FrameRect.LowerRightCorner.X;
setTextRect(cursLine);
}
}
else if (FrameRect.UpperLeftCorner.Y > CurrentTextRect.UpperLeftCorner.Y + VScrollPos)
VScrollPos = CurrentTextRect.UpperLeftCorner.Y - FrameRect.UpperLeftCorner.Y + VScrollPos;
// calculate vertical scrolling
if (hasBrokenText)
{
irr::u32 lineHeight = font->getDimension(L"A").Height + font->getKerningHeight();
// only up to 1 line fits?
if ( lineHeight >= (irr::u32)FrameRect.getHeight() )
{
VScrollPos = 0;
setTextRect(cursLine);
s32 unscrolledPos = CurrentTextRect.UpperLeftCorner.Y;
s32 pivot = FrameRect.UpperLeftCorner.Y;
switch (VAlign)
{
case EGUIA_CENTER:
pivot += FrameRect.getHeight()/2;
unscrolledPos += lineHeight/2;
break;
case EGUIA_LOWERRIGHT:
pivot += FrameRect.getHeight();
unscrolledPos += lineHeight;
break;
default:
break;
}
VScrollPos = unscrolledPos-pivot;
setTextRect(cursLine);
}
else
{
// First 2 checks are necessary when people delete lines
setTextRect(0);
if ( CurrentTextRect.UpperLeftCorner.Y > FrameRect.UpperLeftCorner.Y && VAlign != EGUIA_LOWERRIGHT)
{
// first line is leaving a gap on top
VScrollPos = 0;
}
else if (VAlign != EGUIA_UPPERLEFT)
{
u32 lastLine = BrokenTextPositions.empty() ? 0 : BrokenTextPositions.size()-1;
setTextRect(lastLine);
if ( CurrentTextRect.LowerRightCorner.Y < FrameRect.LowerRightCorner.Y)
{
// last line is leaving a gap on bottom
VScrollPos -= FrameRect.LowerRightCorner.Y-CurrentTextRect.LowerRightCorner.Y;
}
}
// todo: adjust scrollbar
setTextRect(cursLine);
if ( CurrentTextRect.UpperLeftCorner.Y < FrameRect.UpperLeftCorner.Y )
{
// text above valid area
VScrollPos -= FrameRect.UpperLeftCorner.Y-CurrentTextRect.UpperLeftCorner.Y;
setTextRect(cursLine);
}
else if ( CurrentTextRect.LowerRightCorner.Y > FrameRect.LowerRightCorner.Y)
{
// text below valid area
VScrollPos += CurrentTextRect.LowerRightCorner.Y-FrameRect.LowerRightCorner.Y;
setTextRect(cursLine);
}
}
}
}
void CGUIEditBox::calculateFrameRect()
......@@ -1415,9 +1500,9 @@ void CGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWr
out->addBool ("Border", Border);
out->addBool ("Background", Background);
out->addBool ("OverrideColorEnabled",OverrideColorEnabled );
out->addBool ("OverrideColorEnabled", OverrideColorEnabled );
out->addColor ("OverrideColor", OverrideColor);
// out->addFont("OverrideFont",OverrideFont);
// out->addFont("OverrideFont", OverrideFont);
out->addInt ("MaxChars", Max);
out->addBool ("WordWrap", WordWrap);
out->addBool ("MultiLine", MultiLine);
......
......@@ -179,9 +179,9 @@ CIrrDeviceLinux::~CIrrDeviceLinux()
#endif // #ifdef _IRR_COMPILE_WITH_X11_
#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
for (u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
{
if(ActiveJoysticks[joystick].fd >= 0)
if (ActiveJoysticks[joystick].fd >= 0)
{
close(ActiveJoysticks[joystick].fd);
}
......@@ -1022,22 +1022,42 @@ bool CIrrDeviceLinux::run()
char buf[8]={0};
XLookupString(&event.xkey, buf, sizeof(buf), &mp.X11Key, NULL);
const s32 idx = KeyMap.binary_search(mp);
irrevent.EventType = irr::EET_KEY_INPUT_EVENT;
irrevent.KeyInput.PressedDown = (event.type == KeyPress);
// mbtowc(&irrevent.KeyInput.Char, buf, sizeof(buf));
irrevent.KeyInput.Char = ((wchar_t*)(buf))[0];
irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0;
irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0;
event.xkey.state = 0; // ignore shift-ctrl states for figuring out the key
XLookupString(&event.xkey, buf, sizeof(buf), &mp.X11Key, NULL);
const s32 idx = KeyMap.binary_search(mp);
if (idx != -1)
{
irrevent.KeyInput.Key = (EKEY_CODE)KeyMap[idx].Win32Key;
}
else
{
// Usually you will check keysymdef.h and add the corresponding key to createKeyMap.
irrevent.KeyInput.Key = (EKEY_CODE)0;
os::Printer::log("Could not find win32 key for x11 key.", core::stringc((int)mp.X11Key).c_str(), ELL_WARNING);
}
irrevent.EventType = irr::EET_KEY_INPUT_EVENT;
irrevent.KeyInput.PressedDown = (event.type == KeyPress);
// mbtowc(&irrevent.KeyInput.Char, buf, sizeof(buf));
irrevent.KeyInput.Char = (reinterpret_cast<wchar_t*>(buf))[0];
irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0;
irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0;
if (irrevent.KeyInput.Key == 0)
{
// 1:1 mapping to windows-keys would require testing for keyboard type (us, ger, ...)
// So unless we do that we will have some unknown keys here.
if (idx == -1)
{
os::Printer::log("Could not find EKEY_CODE, using orig. X11 keycode instead", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION);
}
else
{
os::Printer::log("EKEY_CODE is 0, using orig. X11 keycode instead", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION);
}
// Any value is better than none, that allows at least using the keys.
// Worst case is that some keys will be identical, still better than _all_
// unknown keys being identical.
irrevent.KeyInput.Key = (EKEY_CODE)event.xkey.keycode;
}
postEventFromUser(irrevent);
}
break;
......@@ -1114,7 +1134,7 @@ bool CIrrDeviceLinux::run()
}
#endif //_IRR_COMPILE_WITH_X11_
if(!Close)
if (!Close)
pollJoysticks();
return !Close;
......@@ -1494,11 +1514,11 @@ void CIrrDeviceLinux::createKeyMap()
KeyMap.push_back(SKeyMap(XK_exclam, 0)); //?
KeyMap.push_back(SKeyMap(XK_quotedbl, 0)); //?
KeyMap.push_back(SKeyMap(XK_section, 0)); //?
KeyMap.push_back(SKeyMap(XK_numbersign, 0)); //?
KeyMap.push_back(SKeyMap(XK_numbersign, KEY_OEM_2));
KeyMap.push_back(SKeyMap(XK_dollar, 0)); //?
KeyMap.push_back(SKeyMap(XK_percent, 0)); //?
KeyMap.push_back(SKeyMap(XK_ampersand, 0)); //?
KeyMap.push_back(SKeyMap(XK_apostrophe, 0)); //?
KeyMap.push_back(SKeyMap(XK_apostrophe, KEY_OEM_7));
KeyMap.push_back(SKeyMap(XK_parenleft, 0)); //?
KeyMap.push_back(SKeyMap(XK_parenright, 0)); //?
KeyMap.push_back(SKeyMap(XK_asterisk, 0)); //?
......@@ -1506,7 +1526,7 @@ void CIrrDeviceLinux::createKeyMap()
KeyMap.push_back(SKeyMap(XK_comma, KEY_COMMA)); //?
KeyMap.push_back(SKeyMap(XK_minus, KEY_MINUS)); //?
KeyMap.push_back(SKeyMap(XK_period, KEY_PERIOD)); //?
KeyMap.push_back(SKeyMap(XK_slash, 0)); //?
KeyMap.push_back(SKeyMap(XK_slash, KEY_OEM_2)); //?
KeyMap.push_back(SKeyMap(XK_0, KEY_KEY_0));
KeyMap.push_back(SKeyMap(XK_1, KEY_KEY_1));
KeyMap.push_back(SKeyMap(XK_2, KEY_KEY_2));
......@@ -1518,12 +1538,12 @@ void CIrrDeviceLinux::createKeyMap()
KeyMap.push_back(SKeyMap(XK_8, KEY_KEY_8));
KeyMap.push_back(SKeyMap(XK_9, KEY_KEY_9));
KeyMap.push_back(SKeyMap(XK_colon, 0)); //?
KeyMap.push_back(SKeyMap(XK_semicolon, 0)); //?
KeyMap.push_back(SKeyMap(XK_less, 0)); //?
KeyMap.push_back(SKeyMap(XK_equal, 0)); //?
KeyMap.push_back(SKeyMap(XK_semicolon, KEY_OEM_1));
KeyMap.push_back(SKeyMap(XK_less, KEY_OEM_102));
KeyMap.push_back(SKeyMap(XK_equal, KEY_PLUS));
KeyMap.push_back(SKeyMap(XK_greater, 0)); //?
KeyMap.push_back(SKeyMap(XK_question, 0)); //?
KeyMap.push_back(SKeyMap(XK_at, 0)); //?
KeyMap.push_back(SKeyMap(XK_at, KEY_KEY_2)); //?
KeyMap.push_back(SKeyMap(XK_mu, 0)); //?
KeyMap.push_back(SKeyMap(XK_EuroSign, 0)); //?
KeyMap.push_back(SKeyMap(XK_A, KEY_KEY_A));
......@@ -1552,18 +1572,14 @@ void CIrrDeviceLinux::createKeyMap()
KeyMap.push_back(SKeyMap(XK_X, KEY_KEY_X));
KeyMap.push_back(SKeyMap(XK_Y, KEY_KEY_Y));
KeyMap.push_back(SKeyMap(XK_Z, KEY_KEY_Z));
KeyMap.push_back(SKeyMap(XK_Adiaeresis, 0)); //?
KeyMap.push_back(SKeyMap(XK_Odiaeresis, 0)); //?
KeyMap.push_back(SKeyMap(XK_Udiaeresis, 0)); //?
KeyMap.push_back(SKeyMap(XK_bracketleft, 0)); //?
KeyMap.push_back(SKeyMap(XK_backslash, 0)); //?
KeyMap.push_back(SKeyMap(XK_bracketright, 0)); //?
KeyMap.push_back(SKeyMap(XK_asciicircum, 0)); //?
KeyMap.push_back(SKeyMap(XK_bracketleft, KEY_OEM_4));
KeyMap.push_back(SKeyMap(XK_backslash, KEY_OEM_5));
KeyMap.push_back(SKeyMap(XK_bracketright, KEY_OEM_6));
KeyMap.push_back(SKeyMap(XK_asciicircum, KEY_OEM_5));
KeyMap.push_back(SKeyMap(XK_degree, 0)); //?
KeyMap.push_back(SKeyMap(XK_underscore, 0)); //?
KeyMap.push_back(SKeyMap(XK_grave, 0)); //?
KeyMap.push_back(SKeyMap(XK_acute, 0)); //?
KeyMap.push_back(SKeyMap(XK_quoteleft, 0)); //?
KeyMap.push_back(SKeyMap(XK_underscore, KEY_MINUS)); //?
KeyMap.push_back(SKeyMap(XK_grave, KEY_OEM_3));
KeyMap.push_back(SKeyMap(XK_acute, KEY_OEM_6));
KeyMap.push_back(SKeyMap(XK_a, KEY_KEY_A));
KeyMap.push_back(SKeyMap(XK_b, KEY_KEY_B));
KeyMap.push_back(SKeyMap(XK_c, KEY_KEY_C));
......@@ -1590,10 +1606,12 @@ void CIrrDeviceLinux::createKeyMap()
KeyMap.push_back(SKeyMap(XK_x, KEY_KEY_X));
KeyMap.push_back(SKeyMap(XK_y, KEY_KEY_Y));
KeyMap.push_back(SKeyMap(XK_z, KEY_KEY_Z));
KeyMap.push_back(SKeyMap(XK_ssharp, 0)); //?
KeyMap.push_back(SKeyMap(XK_adiaeresis, 0)); //?
KeyMap.push_back(SKeyMap(XK_odiaeresis, 0)); //?
KeyMap.push_back(SKeyMap(XK_udiaeresis, 0)); //?
KeyMap.push_back(SKeyMap(XK_ssharp, KEY_OEM_4));
KeyMap.push_back(SKeyMap(XK_adiaeresis, KEY_OEM_7));
KeyMap.push_back(SKeyMap(XK_odiaeresis, KEY_OEM_3));
KeyMap.push_back(SKeyMap(XK_udiaeresis, KEY_OEM_1));
KeyMap.push_back(SKeyMap(XK_Super_L, KEY_LWIN));
KeyMap.push_back(SKeyMap(XK_Super_R, KEY_RWIN));
KeyMap.sort();
#endif
......@@ -1606,7 +1624,7 @@ bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInf
joystickInfo.clear();
u32 joystick;
for(joystick = 0; joystick < 32; ++joystick)
for (joystick = 0; joystick < 32; ++joystick)
{
// The joystick device could be here...
core::stringc devName = "/dev/js";
......@@ -1616,14 +1634,14 @@ bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInf
JoystickInfo info;
info.fd = open(devName.c_str(), O_RDONLY);
if(-1 == info.fd)
if (-1 == info.fd)
{
// ...but Ubuntu and possibly other distros
// create the devices in /dev/input
devName = "/dev/input/js";
devName += joystick;
info.fd = open(devName.c_str(), O_RDONLY);
if(-1 == info.fd)
if (-1 == info.fd)
{
// and BSD here
devName = "/dev/joy";
......@@ -1632,7 +1650,7 @@ bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInf
}
}
if(-1 == info.fd)
if (-1 == info.fd)
continue;
#ifdef __FREE_BSD_
......@@ -1668,7 +1686,7 @@ bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInf
joystickInfo.push_back(returnInfo);
}
for(joystick = 0; joystick < joystickInfo.size(); ++joystick)
for (joystick = 0; joystick < joystickInfo.size(); ++joystick)
{
char logString[256];
(void)sprintf(logString, "Found joystick %u, %u axes, %u buttons '%s'",
......@@ -1687,24 +1705,23 @@ bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInf
void CIrrDeviceLinux::pollJoysticks()
{
#if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
if(0 == ActiveJoysticks.size())
if (0 == ActiveJoysticks.size())
return;
u32 j;
for(j= 0; j< ActiveJoysticks.size(); ++j)
for (u32 j= 0; j< ActiveJoysticks.size(); ++j)
{
JoystickInfo & info = ActiveJoysticks[j];
#ifdef __FREE_BSD_
struct joystick js;
if( read( info.fd, &js, JS_RETURN ) == JS_RETURN )
if (read(info.fd, &js, JS_RETURN) == JS_RETURN)
{
info.persistentData.JoystickEvent.ButtonStates = js.buttons; /* should be a two-bit field */
info.persistentData.JoystickEvent.Axis[0] = js.x; /* X axis */
info.persistentData.JoystickEvent.Axis[1] = js.y; /* Y axis */
#else
struct js_event event;
while(sizeof(event) == read(info.fd, &event, sizeof(event)))
while (sizeof(event) == read(info.fd, &event, sizeof(event)))
{
switch(event.type & ~JS_EVENT_INIT)
{
......@@ -1716,6 +1733,7 @@ void CIrrDeviceLinux::pollJoysticks()
break;
case JS_EVENT_AXIS:
if (event.number < SEvent::SJoystickEvent::NUMBER_OF_AXES)
info.persistentData.JoystickEvent.Axis[event.number] = event.value;
break;
......
......@@ -478,7 +478,7 @@ bool CIrrDeviceSDL::run()
joyevent.JoystickEvent.ButtonStates |= (SDL_JoystickGetButton(joystick, j)<<j);
// query all axes, already in correct range
const int numAxes = core::min_(SDL_JoystickNumAxes(joystick), 6);
const int numAxes = core::min_(SDL_JoystickNumAxes(joystick), SEvent::SJoystickEvent::NUMBER_OF_AXES);
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X]=0;
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y]=0;
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z]=0;
......
......@@ -1464,6 +1464,8 @@ typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
#define PRODUCT_HOME_PREMIUM_N 0x0000001A
#define PRODUCT_ENTERPRISE_N 0x0000001B
#define PRODUCT_ULTIMATE_N 0x0000001C
#endif
#ifndef PRODUCT_STARTER_N
#define PRODUCT_STARTER_N 0x0000002F
#endif
#ifndef PRODUCT_PROFESSIONAL
......
......@@ -68,8 +68,7 @@ int main(int argumentCount, char * arguments[])
TEST(testS3DVertex);
TEST(testaabbox3d);
TEST(color);
// TODO: Needs to be fixed first
// TEST(testTriangle3d);
TEST(testTriangle3d);
TEST(vectorPositionDimension2d);
// file system checks (with null driver)
TEST(filesystem);
......
......@@ -431,6 +431,10 @@
RelativePath=".\triangleSelector.cpp"
>
</File>
<File
RelativePath=".\triangle3d.cpp"
>
</File>
<File
RelativePath=".\vectorPositionDimension2d.cpp"
>
......
......@@ -102,7 +102,7 @@ static void stageModifications(int stage, vector3d<T>& point)
}
template<class T>
static bool isPointInside(triangle3d<T> triangleOrig)
static bool isPointInside(triangle3d<T> triangleOrig, bool testIsInside, bool testIsInsideFast)
{
bool allExpected=true;
......@@ -124,13 +124,18 @@ static bool isPointInside(triangle3d<T> triangleOrig)
vector3d<T> point = pointsInside[i];
stageModifications(stage, point);
if ( testIsInside )
{
allExpected &= triangle.isPointInside( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInside pointsInside test failed in stage %d point %d\n", stage, i);
return false;
}
}
if ( testIsInsideFast )
{
allExpected &= triangle.isPointInsideFast( point );
if ( !allExpected )
{
......@@ -139,6 +144,7 @@ static bool isPointInside(triangle3d<T> triangleOrig)
}
}
}
}
array< vector3d<T> > pointsOutside;
pointsOutside.push_back( triangleOrig.pointA - vector3d<T>(1,0,0) );
......@@ -163,13 +169,18 @@ static bool isPointInside(triangle3d<T> triangleOrig)
vector3d<T> point = pointsOutside[i];
stageModifications(stage, point);
if ( testIsInside )
{
allExpected &= !triangle.isPointInside( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInside pointsOutside test failed in stage %d point %d\n", stage, i);
return false;
}
}
if ( testIsInsideFast )
{
allExpected &= !triangle.isPointInsideFast( point );
if ( !allExpected )
{
......@@ -178,6 +189,7 @@ static bool isPointInside(triangle3d<T> triangleOrig)
}
}
}
}
array< vector3d<T> > pointsBorder;
pointsBorder.push_back( triangleOrig.pointA );
......@@ -198,25 +210,67 @@ static bool isPointInside(triangle3d<T> triangleOrig)
vector3d<T> point = pointsBorder[i];
stageModifications(stage, point);
if ( testIsInside )
{
allExpected &= triangle.isPointInside( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInside pointsBorder test failed in stage %d point %d\n", stage, i);
return false;
}
}
/* results for isPointInsideFast are mixed for border cases, but I guess that's fine.
if ( triangle.isPointInsideFast( point ) )
logTestString("+ triangle3d::isPointInsideFast pointsBorder stage %d point %d is INSIDE\n", stage, i);
else
logTestString("- triangle3d::isPointInsideFast pointsBorder stage %d point %d is NOT inside\n", stage, i);
*/
if ( testIsInsideFast )
{
allExpected &= triangle.isPointInsideFast( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInsideFast pointsBorder test failed in stage %d point %d\n", stage, i);
return false;
}
}
}
}
return allExpected;
}
// Checking behaviour when FPU is set to single precision mode.
// This is somewhat important as Direct3D does by default set the FPU into that mode.
static bool isPointInsideWithSinglePrecision()
{
#ifdef _MSC_VER
int original = _control87( 0, 0 );
_control87(_PC_24, MCW_PC); // single precision (double precision would be _PC_53)
// Testcase just some example which popped up wwhic shows the difference between single precision and double precision
irr::core::triangle3d<irr::f64> t;
irr::core::vector3d<irr::f64> point;
t.pointA.X = 3.7237894e+002f;
t.pointA.Y = -1.0025123e+003f;
t.pointA.Z = 0;
t.pointB.X = 2.6698560e+002f;
t.pointB.Y = -9.8957166e+002f;
t.pointB.Z = 0;
t.pointC.X = 2.6981503e+002f;
t.pointC.Y = -9.3992731e+002f;
t.pointC.Z = 0;
point.X = 2.6981500e+002f;
point.Y = -9.3992743e+002f;
point.Z = 0;
bool ok = !t.isPointInside( point );
_control87(original, 0xfffff); // restore
return ok;
#else
// TODO: Be free to try changing the fpu for other systems.
// I think for MinGW it's still easy, but for Linux this probably also needs changed linker flags.
return true;
#endif
}
// Test the functionality of triangle3d<T>
/** Validation is done with asserts() against expected results. */
......@@ -224,6 +278,9 @@ bool testTriangle3d(void)
{
bool allExpected = true;
/* TODO: disabled for now. I (aka CuteAlien) have by now an example which allows debugging
that problem easier and also found some workaround (which needs an interface change
and a behaviour change and won't get into 1.7 therefore).
logTestString("Test getIntersectionWithLine with f32\n");
{
triangle3df triangle(
......@@ -246,28 +303,38 @@ bool testTriangle3d(void)
ray.end = vector3d<f64>(11250.000000, -1000.000000, 250.000000);
allExpected &= testGetIntersectionWithLine(triangle, ray);
}
*/
/* For now we have no solution yet to fix isPointInside for large integers without
getting worse floating-point precision at the same time.
So instead isPointInsideFast got fixed and should be used for int's.
bool testEigen = triangle3di(vector3di(250, 0, 0), vector3di(0, 0, 500), vector3di(500, 0, 500)).isPointInside(vector3di(300,0,300));
if ( !testEigen ) // test from Eigen from here: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=44372&p=254331#p254331
logTestString("Test isPointInside fails with integers\n");
allExpected &= testEigen;
*/
logTestString("Test isPointInside with f32\n");
{
triangle3d<f32> t(vector3d<f32>(-1000,-1000,0), vector3d<f32>(1000,-1000,0), vector3d<f32>(0,1000,0));
allExpected &= isPointInside(t);
allExpected &= isPointInside(t, true, true);
}
logTestString("Test isPointInside with f64\n");
{
triangle3d<f64> t(vector3d<f64>(-1000,-1000,0), vector3d<f64>(1000,-1000,0), vector3d<f64>(0,1000,0));
allExpected &= isPointInside(t);
allExpected &= isPointInside(t, true, true);
}
logTestString("Test isPointInside with s32\n");
{
triangle3d<s32> t(vector3d<s32>(-1000,-1000,0), vector3d<s32>(1000,-1000,0), vector3d<s32>(0,1000,0));
allExpected &= isPointInside(t);
allExpected &= isPointInside(t, false, true);
}
logTestString("Test isPointInsideWithSinglePrecision\n");
{
allExpected &= isPointInsideWithSinglePrecision();
}
if(allExpected)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment