diff --git a/CMakeLists.txt b/CMakeLists.txt index c1123416c..31c03cf13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,9 +11,11 @@ if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "STKRelease") endif() -option(USE_WIIUSE "Support for wiimote input devices" OFF) +option(USE_WIIUSE "Support for wiimote input devices" ON) option(USE_FRIBIDI "Support for right-to-left languages" ON) -option(USE_CPP2011 "Activate C++ 2011 mode (GCC only)" OFF) +if(UNIX) + option(USE_CPP2011 "Activate C++ 2011 mode (GCC only)" OFF) +endif() if(MSVC) # Normally hide the option to build wiiuse on VS, since it depends # on the installation of the Windows DDK (Driver Developer Kit), @@ -57,8 +59,6 @@ if(USE_WIIUSE) include_directories("${PROJECT_SOURCE_DIR}/lib/wiiuse") endif() -include_directories("${PROJECT_SOURCE_DIR}/lib/irrlicht/source/Irrlicht") - # Set include paths include_directories(${STK_SOURCE_DIR}) @@ -74,6 +74,8 @@ endif() if(APPLE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch i386") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch i386 -F/Library/Frameworks") +elseif(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") # Enable multi-processor compilation (faster) endif() # OpenAL @@ -117,8 +119,10 @@ if(USE_FRIBIDI) endif() endif() -if(USE_CPP2011) - add_definitions("-std=gnu++11") +if(UNIX) + if(USE_CPP2011) + add_definitions("-std=gnu++11") + endif() endif() # OpenGL @@ -167,7 +171,7 @@ source_group_hierarchy(STK_SOURCES STK_HEADERS) if(APPLE) # icon files to copy in the bundle - set(OSX_ICON_FILES ${PROJECT_SOURCE_DIR}/src/ide/Xcode/stk.icns) + set(OSX_ICON_FILES ${PROJECT_SOURCE_DIR}/data/supertuxkart.icns) set_source_files_properties(${OSX_ICON_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) set(STK_SOURCES ${STK_SOURCES} ${OSX_ICON_FILES}) @@ -189,7 +193,7 @@ if(APPLE) # configure CMake to use a custom Info.plist set_target_properties(supertuxkart PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/src/ide/Xcode/SuperTuxKart-Info.plist) + MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/data/SuperTuxKart-Info.plist) if(CMAKE_GENERATOR MATCHES "Xcode") add_custom_command(TARGET supertuxkart POST_BUILD @@ -236,9 +240,6 @@ if(APPLE) # CMake pick the library it wants essentially means I can't build. set_target_properties(supertuxkart PROPERTIES LINK_FLAGS "-arch i386 -F/Library/Frameworks -framework OpenAL -framework Ogg -framework Vorbis") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/Library/Frameworks/OpenAL.framework/Versions/A/Headers") -elseif(MSVC) - # We need to link with Iphlpapi.lib for some networking support: - target_link_libraries(supertuxkart "Iphlpapi.lib") endif() if(USE_FRIBIDI) @@ -293,6 +294,7 @@ install(TARGETS supertuxkart RUNTIME DESTINATION ${STK_INSTALL_BINARY_DIR} BUNDL install(DIRECTORY ${STK_DATA_DIR} DESTINATION ${STK_INSTALL_DATA_DIR} PATTERN ".svn" EXCLUDE) install(FILES ${PROJECT_BINARY_DIR}/supertuxkart.desktop DESTINATION share/applications) install(FILES data/supertuxkart_32.png data/supertuxkart_128.png DESTINATION share/pixmaps) +install(FILES data/supertuxkart.appdata DESTINATION share/appdata) set(PREFIX ${CMAKE_INSTALL_PREFIX}) configure_file(data/supertuxkart_desktop.template supertuxkart.desktop) diff --git a/src/guiengine/widgets/CGUISTKListBox.cpp b/src/guiengine/widgets/CGUISTKListBox.cpp index 9c6b597aa..8689b12bd 100644 --- a/src/guiengine/widgets/CGUISTKListBox.cpp +++ b/src/guiengine/widgets/CGUISTKListBox.cpp @@ -1,757 +1,757 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt -// 2013 Glenn De Jonghe -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "guiengine/widgets/CGUISTKListBox.h" - -#include "IGUISkin.h" -#include "IGUIEnvironment.h" -#include "IVideoDriver.h" -#include "IGUIFont.h" -#include "IGUISpriteBank.h" -#include "CGUIScrollBar.h" -//#include "os.h" -#include "utils/time.hpp" - - -namespace irr -{ -namespace gui -{ - -//! constructor -CGUISTKListBox::CGUISTKListBox(IGUIEnvironment* environment, IGUIElement* parent, - s32 id, core::rect rectangle, bool clip, - bool drawBack, bool moveOverSelect) -: IGUIElement(EGUIET_LIST_BOX, environment, parent, id, rectangle), Selected(-1), - ItemHeight(0),ItemHeightOverride(0), - TotalItemHeight(0), ItemsIconWidth(0), Font(0), IconBank(0), - ScrollBar(0), selectTime(0), LastKeyTime(0), Selecting(false), DrawBack(drawBack), - MoveOverSelect(moveOverSelect), AutoScroll(true), HighlightWhenNotFocused(true) -{ - #ifdef _DEBUG - setDebugName("CGUISTKListBox"); - #endif - - IGUISkin* skin = Environment->getSkin(); - const s32 s = skin->getSize(EGDS_SCROLLBAR_SIZE); - - ScrollBar = new CGUIScrollBar(false, Environment, this, -1, - core::rect(RelativeRect.getWidth() - s, 0, RelativeRect.getWidth(), RelativeRect.getHeight()), - !clip); - ScrollBar->setSubElement(true); - ScrollBar->setTabStop(false); - ScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); - ScrollBar->setVisible(false); - ScrollBar->setPos(0); - - setNotClipped(!clip); - - // this element can be tabbed to - setTabStop(true); - setTabOrder(-1); - - updateAbsolutePosition(); -} - - -//! destructor -CGUISTKListBox::~CGUISTKListBox() -{ - if (ScrollBar) - ScrollBar->drop(); - - if (Font) - Font->drop(); - - if (IconBank) - IconBank->drop(); -} - - -//! returns amount of list items -u32 CGUISTKListBox::getItemCount() const -{ - return Items.size(); -} - - - -const wchar_t* CGUISTKListBox::getCellText(u32 row_num, u32 col_num) const -{ - if ( row_num >= Items.size() ) - return 0; - if ( col_num >= Items[row_num].m_contents.size() ) - return 0; - return Items[row_num].m_contents[col_num].m_text.c_str(); -} - -CGUISTKListBox::ListItem CGUISTKListBox::getItem(u32 id) const -{ - return Items[id]; -} - - -//! Returns the icon of an item -s32 CGUISTKListBox::getIcon(u32 row_num, u32 col_num) const -{ - if ( row_num >= Items.size() ) - return -1; - if ( col_num >= Items[row_num].m_contents.size() ) - return -1; - return Items[row_num].m_contents[col_num].m_icon; -} - -void CGUISTKListBox::removeItem(u32 id) -{ - if (id >= Items.size()) - return; - - if ((u32)Selected==id) - { - Selected = -1; - } - else if ((u32)Selected > id) - { - Selected -= 1; - selectTime = (u32)StkTime::getTimeSinceEpoch(); - } - - Items.erase(id); - - recalculateItemHeight(); -} - - -s32 CGUISTKListBox::getItemAt(s32 xpos, s32 ypos) const -{ - if ( xpos < AbsoluteRect.UpperLeftCorner.X || xpos >= AbsoluteRect.LowerRightCorner.X - || ypos < AbsoluteRect.UpperLeftCorner.Y || ypos >= AbsoluteRect.LowerRightCorner.Y - ) - return -1; - - if ( ItemHeight == 0 ) - return -1; - - s32 item = ((ypos - AbsoluteRect.UpperLeftCorner.Y - 1) + ScrollBar->getPos()) / ItemHeight; - if ( item < 0 || item >= (s32)Items.size()) - return -1; - - return item; -} - -//! clears the list -void CGUISTKListBox::clear() -{ - Items.clear(); - ItemsIconWidth = 0; - Selected = -1; - - if (ScrollBar) - ScrollBar->setPos(0); - - recalculateItemHeight(); -} - - -void CGUISTKListBox::recalculateItemHeight() -{ - IGUISkin* skin = Environment->getSkin(); - - if (Font != skin->getFont()) - { - if (Font) - Font->drop(); - - Font = skin->getFont(); - if ( 0 == ItemHeightOverride ) - ItemHeight = 0; - - if (Font) - { - if ( 0 == ItemHeightOverride ) - ItemHeight = Font->getDimension(L"A").Height + 4; - - Font->grab(); - } - } - - TotalItemHeight = ItemHeight * Items.size(); - ScrollBar->setMax( core::max_(0, TotalItemHeight - AbsoluteRect.getHeight()) ); - s32 minItemHeight = ItemHeight > 0 ? ItemHeight : 1; - ScrollBar->setSmallStep ( minItemHeight ); - ScrollBar->setLargeStep ( 2*minItemHeight ); - - if ( TotalItemHeight <= AbsoluteRect.getHeight() ) - ScrollBar->setVisible(false); - else - ScrollBar->setVisible(true); -} - - -//! returns id of selected item. returns -1 if no item is selected. -s32 CGUISTKListBox::getSelected() const -{ - return Selected; -} - - -//! sets the selected item. Set this to -1 if no item should be selected -void CGUISTKListBox::setSelected(s32 id) -{ - if ((u32)id>=Items.size()) - Selected = -1; - else - Selected = id; - - selectTime = (u32)StkTime::getTimeSinceEpoch(); - - recalculateScrollPos(); -} - -s32 CGUISTKListBox::getRowByCellText(const wchar_t * text) -{ - s32 row_index = -1; - s32 col_index = -1; - if (text) - { - for ( row_index = 0; row_index < (s32) Items.size(); ++row_index ) - { - for ( col_index = 0; col_index < (s32) Items[row_index].m_contents.size(); ++col_index ) - { - if ( Items[row_index].m_contents[col_index].m_text == text ) return row_index; - } - } - } - return -1; -} - -//! sets the selected item. Set this to -1 if no item should be selected -void CGUISTKListBox::setSelectedByCellText(const wchar_t * text) -{ - setSelected(getRowByCellText(text)); -} - -s32 CGUISTKListBox::getRowByInternalName(const std::string & text) const -{ - s32 row_index = -1; - if (text != "") - { - for ( row_index = 0; row_index < (s32) Items.size(); ++row_index ) - { - if (Items[row_index].m_internal_name == text) return row_index; - } - } - return -1; -} - -//! called if an event happened. -bool CGUISTKListBox::OnEvent(const SEvent& event) -{ - if (isEnabled()) - { - switch(event.EventType) - { - case EET_KEY_INPUT_EVENT: - if (event.KeyInput.PressedDown && - (event.KeyInput.Key == KEY_DOWN || - event.KeyInput.Key == KEY_UP || - event.KeyInput.Key == KEY_HOME || - event.KeyInput.Key == KEY_END || - event.KeyInput.Key == KEY_NEXT || - event.KeyInput.Key == KEY_PRIOR ) ) - { - s32 oldSelected = Selected; - switch (event.KeyInput.Key) - { - case KEY_DOWN: - Selected += 1; - break; - case KEY_UP: - Selected -= 1; - break; - case KEY_HOME: - Selected = 0; - break; - case KEY_END: - Selected = (s32)Items.size()-1; - break; - case KEY_NEXT: - Selected += AbsoluteRect.getHeight() / ItemHeight; - break; - case KEY_PRIOR: - Selected -= AbsoluteRect.getHeight() / ItemHeight; - break; - default: - break; - } - if (Selected >= (s32)Items.size()) - Selected = Items.size() - 1; - else - if (Selected<0) - Selected = 0; - - recalculateScrollPos(); - - // post the news - - if (oldSelected != Selected && Parent && !Selecting && !MoveOverSelect) - { - SEvent e; - e.EventType = EET_GUI_EVENT; - e.GUIEvent.Caller = this; - e.GUIEvent.Element = 0; - e.GUIEvent.EventType = EGET_LISTBOX_CHANGED; - Parent->OnEvent(e); - } - - return true; - } - else - if (!event.KeyInput.PressedDown && ( event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE ) ) - { - if (Parent) - { - SEvent e; - e.EventType = EET_GUI_EVENT; - e.GUIEvent.Caller = this; - e.GUIEvent.Element = 0; - e.GUIEvent.EventType = EGET_LISTBOX_SELECTED_AGAIN; - Parent->OnEvent(e); - } - return true; - } - break; - - case EET_GUI_EVENT: - switch(event.GUIEvent.EventType) - { - case gui::EGET_SCROLL_BAR_CHANGED: - if (event.GUIEvent.Caller == ScrollBar) - return true; - break; - case gui::EGET_ELEMENT_FOCUS_LOST: - { - if (event.GUIEvent.Caller == this) - Selecting = false; - break; - } - - default: - break; - } - break; - - case EET_MOUSE_INPUT_EVENT: - { - core::position2d p(event.MouseInput.X, event.MouseInput.Y); - - switch(event.MouseInput.Event) - { - case EMIE_MOUSE_WHEEL: - ScrollBar->setPos(ScrollBar->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1)*-ItemHeight/2); - return true; - - case EMIE_LMOUSE_PRESSED_DOWN: - { - Selecting = true; - return true; - } - - case EMIE_LMOUSE_LEFT_UP: - { - Selecting = false; - - if (isPointInside(p)) - selectNew(event.MouseInput.Y); - - return true; - } - - case EMIE_MOUSE_MOVED: - if (Selecting || MoveOverSelect) - { - if (isPointInside(p)) - { - selectNew(event.MouseInput.Y, true); - return true; - } - } - default: - break; - } - } - break; - case EET_LOG_TEXT_EVENT: - case EET_USER_EVENT: - case EET_JOYSTICK_INPUT_EVENT: - case EGUIET_FORCE_32_BIT: - break; - } - } - - return IGUIElement::OnEvent(event); -} - - -void CGUISTKListBox::selectNew(s32 ypos, bool onlyHover) -{ - u32 now = (u32)StkTime::getTimeSinceEpoch(); - s32 oldSelected = Selected; - - Selected = getItemAt(AbsoluteRect.UpperLeftCorner.X, ypos); - if (Selected<0 && !Items.empty()) - Selected = 0; - - recalculateScrollPos(); - - gui::EGUI_EVENT_TYPE eventType = (Selected == oldSelected && now < selectTime + 500) ? EGET_LISTBOX_SELECTED_AGAIN : EGET_LISTBOX_CHANGED; - selectTime = now; - // post the news - if (Parent && !onlyHover) - { - SEvent event; - event.EventType = EET_GUI_EVENT; - event.GUIEvent.Caller = this; - event.GUIEvent.Element = 0; - event.GUIEvent.EventType = eventType; - Parent->OnEvent(event); - } -} - - -//! Update the position and size of the listbox, and update the scrollbar -void CGUISTKListBox::updateAbsolutePosition() -{ - IGUIElement::updateAbsolutePosition(); - - recalculateItemHeight(); -} - - -//! draws the element and its children -void CGUISTKListBox::draw() -{ - if (!IsVisible) - return; - - recalculateItemHeight(); // if the font changed - - IGUISkin* skin = Environment->getSkin(); - - core::rect* clipRect = 0; - - // draw background - core::rect frameRect(AbsoluteRect); - - // draw items - - core::rect clientClip(AbsoluteRect); - clientClip.UpperLeftCorner.Y += 1; - clientClip.UpperLeftCorner.X += 1; - if (ScrollBar->isVisible()) - clientClip.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE); - clientClip.LowerRightCorner.Y -= 1; - clientClip.clipAgainst(AbsoluteClippingRect); - - skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT), true, - DrawBack, frameRect, &clientClip); - - if (clipRect) - clientClip.clipAgainst(*clipRect); - - frameRect = AbsoluteRect; - frameRect.UpperLeftCorner.X += 1; - if (ScrollBar->isVisible()) - frameRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE); - - frameRect.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + ItemHeight; - - frameRect.UpperLeftCorner.Y -= ScrollBar->getPos(); - frameRect.LowerRightCorner.Y -= ScrollBar->getPos(); - - bool hl = (HighlightWhenNotFocused || Environment->hasFocus(this) || Environment->hasFocus(ScrollBar)); - - for (s32 i=0; i<(s32)Items.size(); ++i) - { - if (frameRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y && - frameRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y) - { - if (i == Selected && hl) - skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), frameRect, &clientClip); - - core::rect textRect = frameRect; - - if (Font) - { - int total_proportion = 0; - for(unsigned int x = 0; x < Items[i].m_contents.size(); ++x) - { - total_proportion += Items[i].m_contents[x].m_proportion; - } - int part_size = (int)(textRect.getWidth() / float(total_proportion)); - - for(unsigned int x = 0; x < Items[i].m_contents.size(); ++x) - { - textRect.LowerRightCorner.X = textRect.UpperLeftCorner.X + - (Items[i].m_contents[x].m_proportion * part_size); - textRect.UpperLeftCorner.X += 3; - - if (IconBank && (Items[i].m_contents[x].m_icon > -1)) - { - core::position2di iconPos = textRect.UpperLeftCorner; - iconPos.Y += textRect.getHeight() / 2; - iconPos.X += ItemsIconWidth/2; - - if ( i==Selected && hl ) - { - IconBank->draw2DSprite( - (u32)Items[i].m_contents[x].m_icon, - iconPos, &clientClip, - hasItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) ? - getItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_ICON_HIGHLIGHT), - selectTime, (u32)StkTime::getTimeSinceEpoch(), false, true); - } - else - { - IconBank->draw2DSprite( - (u32)Items[i].m_contents[x].m_icon, - iconPos, - &clientClip, - hasItemOverrideColor(i, EGUI_LBC_ICON) ? getItemOverrideColor(i, EGUI_LBC_ICON) : getItemDefaultColor(EGUI_LBC_ICON), - 0 , (i==Selected) ? (u32)StkTime::getTimeSinceEpoch() : 0, false, true); - } - textRect.UpperLeftCorner.X += ItemsIconWidth; - } - - textRect.UpperLeftCorner.X += 3; - - if ( i==Selected && hl ) - { - Font->draw( - Items[i].m_contents[x].m_text.c_str(), - textRect, - hasItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) ? - getItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_TEXT_HIGHLIGHT), - Items[i].m_contents[x].m_center, true, &clientClip); - } - else - { - Font->draw( - Items[i].m_contents[x].m_text.c_str(), - textRect, - hasItemOverrideColor(i, EGUI_LBC_TEXT) ? getItemOverrideColor(i, EGUI_LBC_TEXT) : getItemDefaultColor(EGUI_LBC_TEXT), - Items[i].m_contents[x].m_center, true, &clientClip); - } - //Position back to inital pos - textRect.UpperLeftCorner.X -= ItemsIconWidth+6; - //Calculate new beginning - textRect.UpperLeftCorner.X += Items[i].m_contents[x].m_proportion * part_size; - } - } - } - - frameRect.UpperLeftCorner.Y += ItemHeight; - frameRect.LowerRightCorner.Y += ItemHeight; - } - - IGUIElement::draw(); -} - - -//! adds an list item with an icon -u32 CGUISTKListBox::addItem(const ListItem & item) -{ - Items.push_back(item); - recalculateItemHeight(); - recalculateIconWidth(); - return Items.size() - 1; -} - - -void CGUISTKListBox::setSpriteBank(IGUISpriteBank* bank) -{ - if ( bank == IconBank ) - return; - if (IconBank) - IconBank->drop(); - - IconBank = bank; - if (IconBank) - IconBank->grab(); -} - - -void CGUISTKListBox::recalculateScrollPos() -{ - if (!AutoScroll) - return; - - const s32 selPos = (Selected == -1 ? TotalItemHeight : Selected * ItemHeight) - ScrollBar->getPos(); - - if (selPos < 0) - { - ScrollBar->setPos(ScrollBar->getPos() + selPos); - } - else - if (selPos > AbsoluteRect.getHeight() - ItemHeight) - { - ScrollBar->setPos(ScrollBar->getPos() + selPos - AbsoluteRect.getHeight() + ItemHeight); - } -} - - -void CGUISTKListBox::setAutoScrollEnabled(bool scroll) -{ - AutoScroll = scroll; -} - - -bool CGUISTKListBox::isAutoScrollEnabled() const -{ - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return AutoScroll; -} - -void CGUISTKListBox::recalculateIconWidth() -{ - for(int x = 0; x < (int)Items.getLast().m_contents.size(); ++x) - { - s32 icon = Items.getLast().m_contents[x].m_icon; - if (IconBank && icon > -1 && - IconBank->getSprites().size() > (u32)icon && - IconBank->getSprites()[(u32)icon].Frames.size()) - { - u32 rno = IconBank->getSprites()[(u32)icon].Frames[0].rectNumber; - if (IconBank->getPositions().size() > rno) - { - const s32 w = IconBank->getPositions()[rno].getWidth(); - if (w > ItemsIconWidth) - ItemsIconWidth = w; - } - } - } -} - - -void CGUISTKListBox::setCell(u32 row_num, u32 col_num, const wchar_t* text, s32 icon) -{ - if ( row_num >= Items.size() ) - return; - if ( col_num >= Items[row_num].m_contents.size() ) - return; - Items[row_num].m_contents[col_num].m_text = text; - Items[row_num].m_contents[col_num].m_icon = icon; - - recalculateItemHeight(); - recalculateIconWidth(); -} - -void CGUISTKListBox::swapItems(u32 index1, u32 index2) -{ - if ( index1 >= Items.size() || index2 >= Items.size() ) - return; - - ListItem dummmy = Items[index1]; - Items[index1] = Items[index2]; - Items[index2] = dummmy; -} - - -void CGUISTKListBox::setItemOverrideColor(u32 index, video::SColor color) -{ - for ( u32 c=0; c < EGUI_LBC_COUNT; ++c ) - { - Items[index].OverrideColors[c].Use = true; - Items[index].OverrideColors[c].Color = color; - } -} - - -void CGUISTKListBox::setItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType, video::SColor color) -{ - if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT ) - return; - - Items[index].OverrideColors[colorType].Use = true; - Items[index].OverrideColors[colorType].Color = color; -} - - -void CGUISTKListBox::clearItemOverrideColor(u32 index) -{ - for (u32 c=0; c < (u32)EGUI_LBC_COUNT; ++c ) - { - Items[index].OverrideColors[c].Use = false; - } -} - - -void CGUISTKListBox::clearItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) -{ - if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT ) - return; - - Items[index].OverrideColors[colorType].Use = false; -} - - -bool CGUISTKListBox::hasItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const -{ - if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT ) - return false; - - return Items[index].OverrideColors[colorType].Use; -} - - -video::SColor CGUISTKListBox::getItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const -{ - if ( (u32)index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT ) - return video::SColor(); - - return Items[index].OverrideColors[colorType].Color; -} - - -video::SColor CGUISTKListBox::getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) const -{ - IGUISkin* skin = Environment->getSkin(); - if ( !skin ) - return video::SColor(); - - switch ( colorType ) - { - case EGUI_LBC_TEXT: - return skin->getColor(EGDC_BUTTON_TEXT); - case EGUI_LBC_TEXT_HIGHLIGHT: - return skin->getColor(EGDC_HIGH_LIGHT_TEXT); - case EGUI_LBC_ICON: - return skin->getColor(EGDC_ICON); - case EGUI_LBC_ICON_HIGHLIGHT: - return skin->getColor(EGDC_ICON_HIGH_LIGHT); - default: - return video::SColor(); - } -} - -//! set global itemHeight -void CGUISTKListBox::setItemHeight( s32 height ) -{ - ItemHeight = height; - ItemHeightOverride = 1; -} - - -//! Sets whether to draw the background -void CGUISTKListBox::setDrawBackground(bool draw) -{ - DrawBack = draw; -} - - -} // end namespace gui -} // end namespace irr - - +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// 2013 Glenn De Jonghe +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "guiengine/widgets/CGUISTKListBox.h" + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIFont.h" +#include "IGUISpriteBank.h" +#include "IGUIScrollBar.h" +#include "utils/time.hpp" + + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUISTKListBox::CGUISTKListBox(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle, bool clip, + bool drawBack, bool moveOverSelect) +: IGUIElement(EGUIET_LIST_BOX, environment, parent, id, rectangle), Selected(-1), + ItemHeight(0),ItemHeightOverride(0), + TotalItemHeight(0), ItemsIconWidth(0), Font(0), IconBank(0), + ScrollBar(0), selectTime(0), LastKeyTime(0), Selecting(false), DrawBack(drawBack), + MoveOverSelect(moveOverSelect), AutoScroll(true), HighlightWhenNotFocused(true) +{ + #ifdef _DEBUG + setDebugName("CGUISTKListBox"); + #endif + + IGUISkin* skin = Environment->getSkin(); + const s32 s = skin->getSize(EGDS_SCROLLBAR_SIZE); + + ScrollBar = Environment->addScrollBar(false, + core::rect(RelativeRect.getWidth() - s, 0, + RelativeRect.getWidth(), RelativeRect.getHeight()), this, -1); + ScrollBar->grab(); + ScrollBar->setSubElement(true); + ScrollBar->setTabStop(false); + ScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + ScrollBar->setVisible(false); + ScrollBar->setPos(0); + + setNotClipped(!clip); + + // this element can be tabbed to + setTabStop(true); + setTabOrder(-1); + + updateAbsolutePosition(); +} + + +//! destructor +CGUISTKListBox::~CGUISTKListBox() +{ + if (ScrollBar) + ScrollBar->drop(); + + if (Font) + Font->drop(); + + if (IconBank) + IconBank->drop(); +} + + +//! returns amount of list items +u32 CGUISTKListBox::getItemCount() const +{ + return Items.size(); +} + + + +const wchar_t* CGUISTKListBox::getCellText(u32 row_num, u32 col_num) const +{ + if ( row_num >= Items.size() ) + return 0; + if ( col_num >= Items[row_num].m_contents.size() ) + return 0; + return Items[row_num].m_contents[col_num].m_text.c_str(); +} + +CGUISTKListBox::ListItem CGUISTKListBox::getItem(u32 id) const +{ + return Items[id]; +} + + +//! Returns the icon of an item +s32 CGUISTKListBox::getIcon(u32 row_num, u32 col_num) const +{ + if ( row_num >= Items.size() ) + return -1; + if ( col_num >= Items[row_num].m_contents.size() ) + return -1; + return Items[row_num].m_contents[col_num].m_icon; +} + +void CGUISTKListBox::removeItem(u32 id) +{ + if (id >= Items.size()) + return; + + if ((u32)Selected==id) + { + Selected = -1; + } + else if ((u32)Selected > id) + { + Selected -= 1; + selectTime = (u32)StkTime::getTimeSinceEpoch(); + } + + Items.erase(id); + + recalculateItemHeight(); +} + + +s32 CGUISTKListBox::getItemAt(s32 xpos, s32 ypos) const +{ + if ( xpos < AbsoluteRect.UpperLeftCorner.X || xpos >= AbsoluteRect.LowerRightCorner.X + || ypos < AbsoluteRect.UpperLeftCorner.Y || ypos >= AbsoluteRect.LowerRightCorner.Y + ) + return -1; + + if ( ItemHeight == 0 ) + return -1; + + s32 item = ((ypos - AbsoluteRect.UpperLeftCorner.Y - 1) + ScrollBar->getPos()) / ItemHeight; + if ( item < 0 || item >= (s32)Items.size()) + return -1; + + return item; +} + +//! clears the list +void CGUISTKListBox::clear() +{ + Items.clear(); + ItemsIconWidth = 0; + Selected = -1; + + if (ScrollBar) + ScrollBar->setPos(0); + + recalculateItemHeight(); +} + + +void CGUISTKListBox::recalculateItemHeight() +{ + IGUISkin* skin = Environment->getSkin(); + + if (Font != skin->getFont()) + { + if (Font) + Font->drop(); + + Font = skin->getFont(); + if ( 0 == ItemHeightOverride ) + ItemHeight = 0; + + if (Font) + { + if ( 0 == ItemHeightOverride ) + ItemHeight = Font->getDimension(L"A").Height + 4; + + Font->grab(); + } + } + + TotalItemHeight = ItemHeight * Items.size(); + ScrollBar->setMax( core::max_(0, TotalItemHeight - AbsoluteRect.getHeight()) ); + s32 minItemHeight = ItemHeight > 0 ? ItemHeight : 1; + ScrollBar->setSmallStep ( minItemHeight ); + ScrollBar->setLargeStep ( 2*minItemHeight ); + + if ( TotalItemHeight <= AbsoluteRect.getHeight() ) + ScrollBar->setVisible(false); + else + ScrollBar->setVisible(true); +} + + +//! returns id of selected item. returns -1 if no item is selected. +s32 CGUISTKListBox::getSelected() const +{ + return Selected; +} + + +//! sets the selected item. Set this to -1 if no item should be selected +void CGUISTKListBox::setSelected(s32 id) +{ + if ((u32)id>=Items.size()) + Selected = -1; + else + Selected = id; + + selectTime = (u32)StkTime::getTimeSinceEpoch(); + + recalculateScrollPos(); +} + +s32 CGUISTKListBox::getRowByCellText(const wchar_t * text) +{ + s32 row_index = -1; + s32 col_index = -1; + if (text) + { + for ( row_index = 0; row_index < (s32) Items.size(); ++row_index ) + { + for ( col_index = 0; col_index < (s32) Items[row_index].m_contents.size(); ++col_index ) + { + if ( Items[row_index].m_contents[col_index].m_text == text ) return row_index; + } + } + } + return -1; +} + +//! sets the selected item. Set this to -1 if no item should be selected +void CGUISTKListBox::setSelectedByCellText(const wchar_t * text) +{ + setSelected(getRowByCellText(text)); +} + +s32 CGUISTKListBox::getRowByInternalName(const std::string & text) const +{ + s32 row_index = -1; + if (text != "") + { + for ( row_index = 0; row_index < (s32) Items.size(); ++row_index ) + { + if (Items[row_index].m_internal_name == text) return row_index; + } + } + return -1; +} + +//! called if an event happened. +bool CGUISTKListBox::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + switch(event.EventType) + { + case EET_KEY_INPUT_EVENT: + if (event.KeyInput.PressedDown && + (event.KeyInput.Key == KEY_DOWN || + event.KeyInput.Key == KEY_UP || + event.KeyInput.Key == KEY_HOME || + event.KeyInput.Key == KEY_END || + event.KeyInput.Key == KEY_NEXT || + event.KeyInput.Key == KEY_PRIOR ) ) + { + s32 oldSelected = Selected; + switch (event.KeyInput.Key) + { + case KEY_DOWN: + Selected += 1; + break; + case KEY_UP: + Selected -= 1; + break; + case KEY_HOME: + Selected = 0; + break; + case KEY_END: + Selected = (s32)Items.size()-1; + break; + case KEY_NEXT: + Selected += AbsoluteRect.getHeight() / ItemHeight; + break; + case KEY_PRIOR: + Selected -= AbsoluteRect.getHeight() / ItemHeight; + break; + default: + break; + } + if (Selected >= (s32)Items.size()) + Selected = Items.size() - 1; + else + if (Selected<0) + Selected = 0; + + recalculateScrollPos(); + + // post the news + + if (oldSelected != Selected && Parent && !Selecting && !MoveOverSelect) + { + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = EGET_LISTBOX_CHANGED; + Parent->OnEvent(e); + } + + return true; + } + else + if (!event.KeyInput.PressedDown && ( event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE ) ) + { + if (Parent) + { + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = EGET_LISTBOX_SELECTED_AGAIN; + Parent->OnEvent(e); + } + return true; + } + break; + + case EET_GUI_EVENT: + switch(event.GUIEvent.EventType) + { + case gui::EGET_SCROLL_BAR_CHANGED: + if (event.GUIEvent.Caller == ScrollBar) + return true; + break; + case gui::EGET_ELEMENT_FOCUS_LOST: + { + if (event.GUIEvent.Caller == this) + Selecting = false; + break; + } + + default: + break; + } + break; + + case EET_MOUSE_INPUT_EVENT: + { + core::position2d p(event.MouseInput.X, event.MouseInput.Y); + + switch(event.MouseInput.Event) + { + case EMIE_MOUSE_WHEEL: + ScrollBar->setPos(ScrollBar->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1)*-ItemHeight/2); + return true; + + case EMIE_LMOUSE_PRESSED_DOWN: + { + Selecting = true; + return true; + } + + case EMIE_LMOUSE_LEFT_UP: + { + Selecting = false; + + if (isPointInside(p)) + selectNew(event.MouseInput.Y); + + return true; + } + + case EMIE_MOUSE_MOVED: + if (Selecting || MoveOverSelect) + { + if (isPointInside(p)) + { + selectNew(event.MouseInput.Y, true); + return true; + } + } + default: + break; + } + } + break; + case EET_LOG_TEXT_EVENT: + case EET_USER_EVENT: + case EET_JOYSTICK_INPUT_EVENT: + case EGUIET_FORCE_32_BIT: + break; + } + } + + return IGUIElement::OnEvent(event); +} + + +void CGUISTKListBox::selectNew(s32 ypos, bool onlyHover) +{ + u32 now = (u32)StkTime::getTimeSinceEpoch(); + s32 oldSelected = Selected; + + Selected = getItemAt(AbsoluteRect.UpperLeftCorner.X, ypos); + if (Selected<0 && !Items.empty()) + Selected = 0; + + recalculateScrollPos(); + + gui::EGUI_EVENT_TYPE eventType = (Selected == oldSelected && now < selectTime + 500) ? EGET_LISTBOX_SELECTED_AGAIN : EGET_LISTBOX_CHANGED; + selectTime = now; + // post the news + if (Parent && !onlyHover) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = eventType; + Parent->OnEvent(event); + } +} + + +//! Update the position and size of the listbox, and update the scrollbar +void CGUISTKListBox::updateAbsolutePosition() +{ + IGUIElement::updateAbsolutePosition(); + + recalculateItemHeight(); +} + + +//! draws the element and its children +void CGUISTKListBox::draw() +{ + if (!IsVisible) + return; + + recalculateItemHeight(); // if the font changed + + IGUISkin* skin = Environment->getSkin(); + + core::rect* clipRect = 0; + + // draw background + core::rect frameRect(AbsoluteRect); + + // draw items + + core::rect clientClip(AbsoluteRect); + clientClip.UpperLeftCorner.Y += 1; + clientClip.UpperLeftCorner.X += 1; + if (ScrollBar->isVisible()) + clientClip.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE); + clientClip.LowerRightCorner.Y -= 1; + clientClip.clipAgainst(AbsoluteClippingRect); + + skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT), true, + DrawBack, frameRect, &clientClip); + + if (clipRect) + clientClip.clipAgainst(*clipRect); + + frameRect = AbsoluteRect; + frameRect.UpperLeftCorner.X += 1; + if (ScrollBar->isVisible()) + frameRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE); + + frameRect.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + ItemHeight; + + frameRect.UpperLeftCorner.Y -= ScrollBar->getPos(); + frameRect.LowerRightCorner.Y -= ScrollBar->getPos(); + + bool hl = (HighlightWhenNotFocused || Environment->hasFocus(this) || Environment->hasFocus(ScrollBar)); + + for (s32 i=0; i<(s32)Items.size(); ++i) + { + if (frameRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y && + frameRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y) + { + if (i == Selected && hl) + skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), frameRect, &clientClip); + + core::rect textRect = frameRect; + + if (Font) + { + int total_proportion = 0; + for(unsigned int x = 0; x < Items[i].m_contents.size(); ++x) + { + total_proportion += Items[i].m_contents[x].m_proportion; + } + int part_size = (int)(textRect.getWidth() / float(total_proportion)); + + for(unsigned int x = 0; x < Items[i].m_contents.size(); ++x) + { + textRect.LowerRightCorner.X = textRect.UpperLeftCorner.X + + (Items[i].m_contents[x].m_proportion * part_size); + textRect.UpperLeftCorner.X += 3; + + if (IconBank && (Items[i].m_contents[x].m_icon > -1)) + { + core::position2di iconPos = textRect.UpperLeftCorner; + iconPos.Y += textRect.getHeight() / 2; + iconPos.X += ItemsIconWidth/2; + + if ( i==Selected && hl ) + { + IconBank->draw2DSprite( + (u32)Items[i].m_contents[x].m_icon, + iconPos, &clientClip, + hasItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) ? + getItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_ICON_HIGHLIGHT), + selectTime, (u32)StkTime::getTimeSinceEpoch(), false, true); + } + else + { + IconBank->draw2DSprite( + (u32)Items[i].m_contents[x].m_icon, + iconPos, + &clientClip, + hasItemOverrideColor(i, EGUI_LBC_ICON) ? getItemOverrideColor(i, EGUI_LBC_ICON) : getItemDefaultColor(EGUI_LBC_ICON), + 0 , (i==Selected) ? (u32)StkTime::getTimeSinceEpoch() : 0, false, true); + } + textRect.UpperLeftCorner.X += ItemsIconWidth; + } + + textRect.UpperLeftCorner.X += 3; + + if ( i==Selected && hl ) + { + Font->draw( + Items[i].m_contents[x].m_text.c_str(), + textRect, + hasItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) ? + getItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_TEXT_HIGHLIGHT), + Items[i].m_contents[x].m_center, true, &clientClip); + } + else + { + Font->draw( + Items[i].m_contents[x].m_text.c_str(), + textRect, + hasItemOverrideColor(i, EGUI_LBC_TEXT) ? getItemOverrideColor(i, EGUI_LBC_TEXT) : getItemDefaultColor(EGUI_LBC_TEXT), + Items[i].m_contents[x].m_center, true, &clientClip); + } + //Position back to inital pos + textRect.UpperLeftCorner.X -= ItemsIconWidth+6; + //Calculate new beginning + textRect.UpperLeftCorner.X += Items[i].m_contents[x].m_proportion * part_size; + } + } + } + + frameRect.UpperLeftCorner.Y += ItemHeight; + frameRect.LowerRightCorner.Y += ItemHeight; + } + + IGUIElement::draw(); +} + + +//! adds an list item with an icon +u32 CGUISTKListBox::addItem(const ListItem & item) +{ + Items.push_back(item); + recalculateItemHeight(); + recalculateIconWidth(); + return Items.size() - 1; +} + + +void CGUISTKListBox::setSpriteBank(IGUISpriteBank* bank) +{ + if ( bank == IconBank ) + return; + if (IconBank) + IconBank->drop(); + + IconBank = bank; + if (IconBank) + IconBank->grab(); +} + + +void CGUISTKListBox::recalculateScrollPos() +{ + if (!AutoScroll) + return; + + const s32 selPos = (Selected == -1 ? TotalItemHeight : Selected * ItemHeight) - ScrollBar->getPos(); + + if (selPos < 0) + { + ScrollBar->setPos(ScrollBar->getPos() + selPos); + } + else + if (selPos > AbsoluteRect.getHeight() - ItemHeight) + { + ScrollBar->setPos(ScrollBar->getPos() + selPos - AbsoluteRect.getHeight() + ItemHeight); + } +} + + +void CGUISTKListBox::setAutoScrollEnabled(bool scroll) +{ + AutoScroll = scroll; +} + + +bool CGUISTKListBox::isAutoScrollEnabled() const +{ + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return AutoScroll; +} + +void CGUISTKListBox::recalculateIconWidth() +{ + for(int x = 0; x < (int)Items.getLast().m_contents.size(); ++x) + { + s32 icon = Items.getLast().m_contents[x].m_icon; + if (IconBank && icon > -1 && + IconBank->getSprites().size() > (u32)icon && + IconBank->getSprites()[(u32)icon].Frames.size()) + { + u32 rno = IconBank->getSprites()[(u32)icon].Frames[0].rectNumber; + if (IconBank->getPositions().size() > rno) + { + const s32 w = IconBank->getPositions()[rno].getWidth(); + if (w > ItemsIconWidth) + ItemsIconWidth = w; + } + } + } +} + + +void CGUISTKListBox::setCell(u32 row_num, u32 col_num, const wchar_t* text, s32 icon) +{ + if ( row_num >= Items.size() ) + return; + if ( col_num >= Items[row_num].m_contents.size() ) + return; + Items[row_num].m_contents[col_num].m_text = text; + Items[row_num].m_contents[col_num].m_icon = icon; + + recalculateItemHeight(); + recalculateIconWidth(); +} + +void CGUISTKListBox::swapItems(u32 index1, u32 index2) +{ + if ( index1 >= Items.size() || index2 >= Items.size() ) + return; + + ListItem dummmy = Items[index1]; + Items[index1] = Items[index2]; + Items[index2] = dummmy; +} + + +void CGUISTKListBox::setItemOverrideColor(u32 index, video::SColor color) +{ + for ( u32 c=0; c < EGUI_LBC_COUNT; ++c ) + { + Items[index].OverrideColors[c].Use = true; + Items[index].OverrideColors[c].Color = color; + } +} + + +void CGUISTKListBox::setItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType, video::SColor color) +{ + if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT ) + return; + + Items[index].OverrideColors[colorType].Use = true; + Items[index].OverrideColors[colorType].Color = color; +} + + +void CGUISTKListBox::clearItemOverrideColor(u32 index) +{ + for (u32 c=0; c < (u32)EGUI_LBC_COUNT; ++c ) + { + Items[index].OverrideColors[c].Use = false; + } +} + + +void CGUISTKListBox::clearItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) +{ + if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT ) + return; + + Items[index].OverrideColors[colorType].Use = false; +} + + +bool CGUISTKListBox::hasItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const +{ + if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT ) + return false; + + return Items[index].OverrideColors[colorType].Use; +} + + +video::SColor CGUISTKListBox::getItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const +{ + if ( (u32)index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT ) + return video::SColor(); + + return Items[index].OverrideColors[colorType].Color; +} + + +video::SColor CGUISTKListBox::getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) const +{ + IGUISkin* skin = Environment->getSkin(); + if ( !skin ) + return video::SColor(); + + switch ( colorType ) + { + case EGUI_LBC_TEXT: + return skin->getColor(EGDC_BUTTON_TEXT); + case EGUI_LBC_TEXT_HIGHLIGHT: + return skin->getColor(EGDC_HIGH_LIGHT_TEXT); + case EGUI_LBC_ICON: + return skin->getColor(EGDC_ICON); + case EGUI_LBC_ICON_HIGHLIGHT: + return skin->getColor(EGDC_ICON_HIGH_LIGHT); + default: + return video::SColor(); + } +} + +//! set global itemHeight +void CGUISTKListBox::setItemHeight( s32 height ) +{ + ItemHeight = height; + ItemHeightOverride = 1; +} + + +//! Sets whether to draw the background +void CGUISTKListBox::setDrawBackground(bool draw) +{ + DrawBack = draw; +} + + +} // end namespace gui +} // end namespace irr + + diff --git a/src/ide/vc9/supertuxkart.vcproj b/src/ide/vc9/supertuxkart.vcproj deleted file mode 100644 index 2e8d12cea..000000000 --- a/src/ide/vc9/supertuxkart.vcproj +++ /dev/null @@ -1,3069 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/input/wiimote_manager.cpp b/src/input/wiimote_manager.cpp index 23475b8e2..04e644a0d 100644 --- a/src/input/wiimote_manager.cpp +++ b/src/input/wiimote_manager.cpp @@ -111,7 +111,7 @@ void WiimoteManager::launchDetection(int timeout) wiiuse_rumble(wiimote_handle, 1); } - Time::sleep(200); + StkTime::sleep(200); for(unsigned int i=0 ; i < m_wiimotes.size(); i++) { @@ -285,7 +285,7 @@ void WiimoteManager::threadFunc() } } - Time::sleep(1); // 'cause come on, the whole CPU is not ours :) + StkTime::sleep(1); // 'cause come on, the whole CPU is not ours :) } // end while } // threadFunc diff --git a/src/items/attachment.cpp b/src/items/attachment.cpp index 5aa0c6b1f..c308d2d24 100644 --- a/src/items/attachment.cpp +++ b/src/items/attachment.cpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2006 Joerg Henrichs +// Copyright (C) 2006-2013 Joerg Henrichs // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -25,6 +25,7 @@ #include "graphics/explosion.hpp" #include "graphics/irr_driver.hpp" #include "items/attachment_manager.hpp" +#include "items/item_manager.hpp" #include "items/projectile_manager.hpp" #include "items/swatter.hpp" #include "karts/abstract_kart.hpp" @@ -32,20 +33,26 @@ #include "karts/explosion_animation.hpp" #include "karts/kart_properties.hpp" #include "modes/three_strikes_battle.hpp" -#include "modes/world.hpp" +#include "modes/world.hpp" +#include "physics/triangle_mesh.hpp" +#include "tracks/track.hpp" +#include "physics/triangle_mesh.hpp" +#include "tracks/track.hpp" #include "utils/constants.hpp" -#include "utils/log.hpp" //TODO: remove after debugging is done -// Log::verbose("attachment", "Decreasing shield \n"); +#include "utils/log.hpp" + /** Initialises the attachment each kart has. */ Attachment::Attachment(AbstractKart* kart) { - m_type = ATTACH_NOTHING; - m_time_left = 0.0; - m_plugin = NULL; - m_kart = kart; - m_previous_owner = NULL; - m_bomb_sound = NULL; + m_type = ATTACH_NOTHING; + m_time_left = 0.0; + m_plugin = NULL; + m_kart = kart; + m_previous_owner = NULL; + m_bomb_sound = NULL; + m_bubble_explode_sound = NULL; + m_node_scale = 1.0f; // If we attach a NULL mesh, we get a NULL scene node back. So we // have to attach some kind of mesh, but make it invisible. @@ -74,6 +81,12 @@ Attachment::~Attachment() sfx_manager->deleteSFX(m_bomb_sound); m_bomb_sound = NULL; } + + if (m_bubble_explode_sound) + { + sfx_manager->deleteSFX(m_bubble_explode_sound); + m_bubble_explode_sound = NULL; + } } // ~Attachment //----------------------------------------------------------------------------- @@ -109,7 +122,8 @@ void Attachment::set(AttachmentType type, float time, } clear(); - + m_node_scale = 0.3f; + // If necessary create the appropriate plugin which encapsulates // the associated behavior switch(type) @@ -140,6 +154,8 @@ void Attachment::set(AttachmentType type, float time, m_node->setCurrentFrame(0); } + m_node->setScale(core::vector3df(m_node_scale,m_node_scale,m_node_scale)); + m_type = type; m_time_left = time; m_previous_owner = current_kart; @@ -161,6 +177,8 @@ void Attachment::set(AttachmentType type, float time, } } m_node->setVisible(true); + + irr_driver->applyObjectPassShader(m_node); } // set // ----------------------------------------------------------------------------- @@ -206,9 +224,10 @@ void Attachment::clear() void Attachment::hitBanana(Item *item, int new_attachment) { //Bubble gum shield effect: - if(m_type == ATTACH_BUBBLEGUM_SHIELD) + if(m_type == ATTACH_BUBBLEGUM_SHIELD || + m_type == ATTACH_NOLOK_BUBBLEGUM_SHIELD) { - m_time_left -= stk_config->m_bubblegum_shield_time; + m_time_left = 0.0f; return; } @@ -304,9 +323,15 @@ void Attachment::hitBanana(Item *item, int new_attachment) void Attachment::handleCollisionWithKart(AbstractKart *other) { Attachment *attachment_other=other->getAttachment(); - + if(getType()==Attachment::ATTACH_BOMB) { + // Don't attach a bomb when the kart is shielded + if(other->isShielded()) + { + other->decreaseShieldTime(); + return; + } // If both karts have a bomb, explode them immediately: if(attachment_other->getType()==Attachment::ATTACH_BOMB) { @@ -331,6 +356,12 @@ void Attachment::handleCollisionWithKart(AbstractKart *other) else if(attachment_other->getType()==Attachment::ATTACH_BOMB && (attachment_other->getPreviousOwner()!=m_kart || World::getWorld()->getNumKarts() <= 2)) { + // Don't attach a bomb when the kart is shielded + if(m_kart->isShielded()) + { + m_kart->decreaseShieldTime(); + return; + } set(ATTACH_BOMB, other->getAttachment()->getTimeLeft()+ stk_config->m_bomb_time_increase, other); other->getAttachment()->clear(); @@ -349,6 +380,17 @@ void Attachment::update(float dt) { if(m_type==ATTACH_NOTHING) return; m_time_left -=dt; + + + bool is_shield = (m_type == ATTACH_BUBBLEGUM_SHIELD|| m_type == ATTACH_NOLOK_BUBBLEGUM_SHIELD); + float m_wanted_node_scale = is_shield ? std::max(1.0f, m_kart->getHighestPoint()*1.1f) : 1.0f; + + if (m_node_scale < m_wanted_node_scale) + { + m_node_scale += dt*1.5f; + if (m_node_scale > m_wanted_node_scale) m_node_scale = m_wanted_node_scale; + m_node->setScale(core::vector3df(m_node_scale,m_node_scale,m_node_scale)); + } if(m_plugin) { @@ -412,15 +454,34 @@ void Attachment::update(float dt) // Nothing to do for tinytux, this is all handled in EmergencyAnimation break; case ATTACH_BUBBLEGUM_SHIELD: - if(!m_kart->isShielded()) + case ATTACH_NOLOK_BUBBLEGUM_SHIELD: + if (m_time_left < 0) { m_time_left = 0.0f; - if (m_kart->m_bubble_drop) + if (m_bubble_explode_sound) sfx_manager->deleteSFX(m_bubble_explode_sound); + m_bubble_explode_sound = sfx_manager->createSoundSource("bubblegum_explode"); + m_bubble_explode_sound->position(m_kart->getXYZ()); + m_bubble_explode_sound->play(); + + // drop a small bubble gum + Vec3 hit_point; + Vec3 normal; + const Material* material_hit; + Vec3 pos = m_kart->getXYZ(); + Vec3 to=pos+Vec3(0, -10000, 0); + World* world = World::getWorld(); + world->getTrack()->getTriangleMesh().castRay(pos, to, &hit_point, + &material_hit, &normal); + // This can happen if the kart is 'over nothing' when dropping + // the bubble gum + if(material_hit) { - Log::verbose("Attachment", "Drop a small bubble gum. \n");; - //TODO: drop a bubble gum item on the track - } + normal.normalize(); + pos.setY(hit_point.getY()-0.05f); + + ItemManager::get()->newItem(Item::ITEM_BUBBLEGUM, pos, normal, m_kart); + } } break; } // switch diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 38d6bef75..fcd98b733 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -1,7 +1,7 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2004-2005 Steve Baker -// Copyright (C) 2006 SuperTuxKart-Team, Joerg Henrichs, Steve Baker +// Copyright (C) 2004-2013 Steve Baker +// Copyright (C) 2006-2013 SuperTuxKart-Team, Joerg Henrichs, Steve Baker // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -70,6 +70,7 @@ #include "tracks/track_manager.hpp" #include "utils/constants.hpp" #include "utils/log.hpp" //TODO: remove after debugging is done +#include "utils/vs.hpp" @@ -126,7 +127,7 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id, m_is_jumping = false; m_min_nitro_time = 0.0f; m_fire_clicked = 0; - + m_view_blocked_by_plunger = 0; m_has_caught_nolok_bubblegum = false; @@ -157,6 +158,7 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id, m_engine_sound = sfx_manager->createSoundSource(m_kart_properties->getEngineSfxType()); m_beep_sound = sfx_manager->createSoundSource( "horn" ); m_crash_sound = sfx_manager->createSoundSource( "crash" ); + m_boing_sound = sfx_manager->createSoundSource( "boing" ); m_goo_sound = sfx_manager->createSoundSource( "goo" ); m_skid_sound = sfx_manager->createSoundSource( "skid" ); m_terrain_sound = NULL; @@ -181,6 +183,7 @@ void Kart::init(RaceManager::KartType type) m_goo_sound->volume( 1.0f / factor ); m_skid_sound->volume( 1.0f / factor ); m_crash_sound->volume( 1.0f / factor ); + m_boing_sound->volume( 1.0f / factor ); m_beep_sound->volume( 1.0f / factor ); } else @@ -189,6 +192,7 @@ void Kart::init(RaceManager::KartType type) m_skid_sound->volume( 1.0f / race_manager->getNumberOfKarts() ); m_crash_sound->volume( 1.0f / race_manager->getNumberOfKarts() ); m_beep_sound->volume( 1.0f / race_manager->getNumberOfKarts() ); + m_boing_sound->volume( 1.0f / race_manager->getNumberOfKarts() ); } } @@ -244,6 +248,7 @@ Kart::~Kart() sfx_manager->deleteSFX(m_skid_sound ); sfx_manager->deleteSFX(m_goo_sound ); sfx_manager->deleteSFX(m_beep_sound ); + sfx_manager->deleteSFX(m_boing_sound ); delete m_kart_gfx; if(m_terrain_sound) sfx_manager->deleteSFX(m_terrain_sound); if(m_previous_terrain_sound) sfx_manager->deleteSFX(m_previous_terrain_sound); @@ -526,8 +531,7 @@ void Kart::blockViewWithPlunger() m_kart_properties->getPlungerInFaceTime(); if(isShielded()) { - decreaseShieldTime(0.0f); //decrease the default amount of time - Log::verbose("Kart", "Decreasing shield, because of removing the plunger. \n"); + decreaseShieldTime(); } } // blockViewWithPlunger @@ -839,15 +843,22 @@ void Kart::finishedRace(float time) RaceGUIBase* m = World::getWorld()->getRaceGUI(); if(m) { - m->addMessage((getPosition() == 2 ? _("You won the race!") : _("You finished the race!")) , - this, 2.0f); + if (getPosition() == 2) + m->addMessage(_("You won the race!"), this, 2.0f); } } - else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES) + else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES || + race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) { setController(new EndController(this, m_controller->getPlayer(), m_controller)); } + else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_EASTER_EGG) + { + m_kart_model->setAnimation(KartModel::AF_WIN_START); + setController(new EndController(this, m_controller->getPlayer(), + m_controller)); + } } // finishedRace @@ -877,19 +888,19 @@ void Kart::collectedItem(Item *item, int add_info) break; case Item::ITEM_BONUS_BOX : { - m_powerup->hitBonusBox(*item, add_info); // selects the powerup + m_powerup->hitBonusBox(*item, add_info); break; } case Item::ITEM_BUBBLEGUM: - m_has_caught_nolok_bubblegum = (item->getEmitter() != NULL && + m_has_caught_nolok_bubblegum = (item->getEmitter() != NULL && item->getEmitter()->getIdent() == "nolok"); // slow down m_bubblegum_time = m_kart_properties->getBubblegumTime(); - m_bubblegum_torque = (rand()%2) + m_bubblegum_torque = (rand()%2) ? m_kart_properties->getBubblegumTorque() : -m_kart_properties->getBubblegumTorque(); - m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_BUBBLE, + m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_BUBBLE, m_kart_properties->getBubblegumSpeedFraction(), m_kart_properties->getBubblegumFadeInTime(), m_bubblegum_time); @@ -974,9 +985,15 @@ void Kart::setShieldTime(float t) bool Kart::isShielded() const { if(getAttachment() != NULL) - return getAttachment()->getType() == Attachment::ATTACH_BUBBLEGUM_SHIELD; + { + Attachment::AttachmentType type = getAttachment()->getType(); + return type == Attachment::ATTACH_BUBBLEGUM_SHIELD || + type == Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD; + } else + { return false; + } } // isShielded // ------------------------------------------------------------------------ @@ -996,24 +1013,12 @@ float Kart::getShieldTime() const * Decreases the kart's shield time. * \param t The time substracted from the shield timer. If t == 0.0f, the default amout of time is substracted. */ -void Kart::decreaseShieldTime(float t) +void Kart::decreaseShieldTime() { - if(isShielded()) + if (isShielded()) { - getAttachment()->setTimeLeft( getAttachment()->getTimeLeft() - t ); - if(t == 0.0f) - { - getAttachment()->setTimeLeft( getAttachment()->getTimeLeft() - - stk_config->m_bubblegum_shield_time); - } - + getAttachment()->setTimeLeft(0.0f); } - //Let the kart drop a bubble gum, if the shield was not damaged. - //This is the default, whenever a powerup is used by a kart. - //It is turned off, if the shield was reduced below zero by a hit. (Or by intently damaging the shield.) - if(!isShielded()) - m_bubble_drop = false; - } // decreaseShieldTime //----------------------------------------------------------------------------- @@ -1038,6 +1043,7 @@ void Kart::eliminate() m_stars_effect->update(1); } + m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_TERRAIN, 0); m_eliminated = true; m_node->setVisible(false); @@ -1146,7 +1152,7 @@ void Kart::update(float dt) if (m_collision_particles) m_collision_particles->update(dt); updatePhysics(dt); - + if(!m_controls.m_fire) m_fire_clicked = 0; if(m_controls.m_fire && !m_fire_clicked && !m_kart_animation) @@ -1155,7 +1161,6 @@ void Kart::update(float dt) // since use() can test if something needs to be switched on/off. m_powerup->use() ; World::getWorld()->onFirePressed(getController()); - m_bubble_drop = true; m_fire_clicked = 1; } @@ -1170,6 +1175,7 @@ void Kart::update(float dt) m_engine_sound->position ( getXYZ() ); m_crash_sound->position ( getXYZ() ); m_skid_sound->position ( getXYZ() ); + m_boing_sound->position ( getXYZ() ); // Check if a kart is (nearly) upside down and not moving much --> automatic rescue if(World::getWorld()->getTrack()->isAutoRescueEnabled() && @@ -1302,14 +1308,19 @@ void Kart::update(float dt) { // Kart touched ground again m_is_jumping = false; - HitEffect *effect = new Explosion(getXYZ(), "jump", + HitEffect *effect = new Explosion(getXYZ(), "jump", "jump_explosion.xml"); projectile_manager->addHitEffect(effect); m_kart_model->setAnimation(KartModel::AF_DEFAULT); m_jump_time = 0; } - if( (!isOnGround() || emergency) && m_shadow_enabled) + //const bool dyn_shadows = World::getWorld()->getTrack()->hasShadows() && + // UserConfigParams::m_shadows && + // irr_driver->isGLSL(); + + // Disable the fake shadow if we're flying + if((!isOnGround() || emergency) && m_shadow_enabled) { m_shadow_enabled = false; m_shadow->disableShadow(); @@ -1317,7 +1328,7 @@ void Kart::update(float dt) if(!m_shadow_enabled && isOnGround() && !emergency) { m_shadow->enableShadow(); - m_shadow_enabled = true; + m_shadow_enabled = true; } } // update @@ -1342,8 +1353,7 @@ void Kart::setSquash(float time, float slowdown) if (isShielded()) { - decreaseShieldTime(stk_config->m_bubblegum_shield_time/2.0f); - Log::verbose("Kart", "Decreasing shield \n"); + decreaseShieldTime(); return; } @@ -1353,7 +1363,7 @@ void Kart::setSquash(float time, float slowdown) return; } m_node->setScale(core::vector3df(1.0f, 0.5f, 1.0f)); - m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_SQUASH, slowdown, + m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_SQUASH, slowdown, 0.1f, time); m_squash_time = time; } // setSquash @@ -1407,6 +1417,7 @@ void Kart::handleMaterialSFX(const Material *material) m_terrain_sound = NULL; } } + if(m_previous_terrain_sound && m_previous_terrain_sound->getStatus()==SFXManager::SFX_STOPPED) { @@ -1416,15 +1427,19 @@ void Kart::handleMaterialSFX(const Material *material) sfx_manager->deleteSFX(m_previous_terrain_sound); m_previous_terrain_sound = NULL; } + + bool m_schedule_pause = m_flying || + dynamic_cast(getKartAnimation()) || + dynamic_cast(getKartAnimation()); // terrain sound is not necessarily a looping sound so check its status before // setting its speed, to avoid 'ressuscitating' sounds that had already stopped - if(m_terrain_sound - && (m_terrain_sound->getStatus() == SFXManager::SFX_PLAYING - || m_terrain_sound->getStatus() == SFXManager::SFX_PAUSED)) + if(m_terrain_sound && + (m_terrain_sound->getStatus()==SFXManager::SFX_PLAYING || + m_terrain_sound->getStatus()==SFXManager::SFX_PAUSED)) { m_terrain_sound->position(getXYZ()); - material->setSFXSpeed(m_terrain_sound, m_speed); + material->setSFXSpeed(m_terrain_sound, m_speed, m_schedule_pause); } } // handleMaterialSFX @@ -1620,13 +1635,13 @@ void Kart::updateNitro(float dt) if (m_min_nitro_time > 0.0f) { m_min_nitro_time -= dt; - + // when pressing the key, don't allow the min time to go under zero. // If it went under zero, it would be reset if (m_controls.m_nitro && m_min_nitro_time <= 0.0f) m_min_nitro_time = 0.1f; } - + bool increase_speed = (m_controls.m_nitro && isOnGround()); if (!increase_speed && m_min_nitro_time <= 0.0f) { @@ -1638,7 +1653,7 @@ void Kart::updateNitro(float dt) m_collected_energy = 0; return; } - + if (increase_speed) { m_max_speed->increaseMaxSpeed(MaxSpeed::MS_INCREASE_NITRO, @@ -1670,7 +1685,7 @@ void Kart::crashed(AbstractKart *k, bool update_attachments) getAttachment()->handleCollisionWithKart(k); } m_controller->crashed(k); - crashed(); + crashed(NULL, k); } // crashed(Kart, update_attachments // ----------------------------------------------------------------------------- @@ -1810,13 +1825,15 @@ void Kart::crashed(const Material *m, const Vec3 &normal) } // if(m && m->getCollisionReaction() != Material::NORMAL && // !getKartAnimation()) m_controller->crashed(m); - crashed(); + crashed(m, NULL); } // crashed(Material) // ----------------------------------------------------------------------------- /** Common code used when a kart or a material was hit. + * @param m The material collided into, or NULL if none + * @param k The kart collided into, or NULL if none */ -void Kart::crashed() +void Kart::crashed(const Material* m, AbstractKart *k) { if(World::getWorld()->getTime()-m_time_last_crash < 0.5f) return; @@ -1830,8 +1847,16 @@ void Kart::crashed() { // In case that the sfx is longer than 0.5 seconds, only play it if // it's not already playing. - if(m_crash_sound->getStatus() != SFXManager::SFX_PLAYING) - m_crash_sound->play(); + if (isShielded() || (k != NULL && k->isShielded())) + { + if (m_boing_sound->getStatus() != SFXManager::SFX_PLAYING) + m_boing_sound->play(); + } + else + { + if(m_crash_sound->getStatus() != SFXManager::SFX_PLAYING) + m_crash_sound->play(); + } } m_bounce_back_time = 0.1f; @@ -1944,7 +1969,7 @@ void Kart::updatePhysics(float dt) m_skidding->update(dt, isOnGround(), m_controls.m_steer, m_controls.m_skid); - + m_vehicle->setVisualRotation(m_skidding->getVisualSkidRotation()); if(( m_skidding->getSkidState() == Skidding::SKID_ACCUMULATE_LEFT || m_skidding->getSkidState() == Skidding::SKID_ACCUMULATE_RIGHT ) && m_skidding->getGraphicalJumpOffset()==0) @@ -2000,6 +2025,13 @@ void Kart::updatePhysics(float dt) //at low velocity, forces on kart push it back and forth so we ignore this if(fabsf(m_speed) < 0.2f) // quick'n'dirty workaround for bug 1776883 m_speed = 0; + + if (dynamic_cast(getKartAnimation()) || + dynamic_cast(getKartAnimation())) + { + m_speed = 0; + } + updateEngineSFX(); #ifdef XX Log::info("Kart","forward %f %f %f %f side %f %f %f %f angVel %f %f %f heading %f\n" @@ -2307,23 +2339,6 @@ void Kart::loadData(RaceManager::KartType type, bool is_animated_model) } // loadData // ---------------------------------------------------------------------------- -/** Stores the current suspension length. This function is called from world - * after all karts are in resting position (see World::resetAllKarts), so - * that the default suspension rest length can be stored. This is then used - * later to move the wheels depending on actual suspension, so that when - * a kart is in rest, the wheels are at the position at which they were - * modelled. - */ -void Kart::setSuspensionLength() -{ - for(unsigned int i=0; i<4; i++) - { - m_default_suspension_length[i] = - m_vehicle->getWheelInfo(i).m_raycastInfo.m_suspensionLength; - } // for i -} // setSuspensionLength - -//----------------------------------------------------------------------------- /** Applies engine power to all the wheels that are traction capable, * so other parts of code do not have to be adjusted to simulate different * kinds of vehicles in the general case, only if they are trying to @@ -2361,25 +2376,11 @@ void Kart::applyEngineForce(float force) void Kart::updateGraphics(float dt, const Vec3& offset_xyz, const btQuaternion& rotation) { - float wheel_up_axis[4]; - for(unsigned int i=0; i<4; i++) - { - // Set the suspension length - wheel_up_axis[i] = m_default_suspension_length[i] - - m_vehicle->getWheelInfo(i).m_raycastInfo.m_suspensionLength; - } - m_kart_model->update(m_wheel_rotation_dt, getSteerPercent(), wheel_up_axis); - - Vec3 center_shift = m_kart_properties->getGravityCenterShift(); - float y = m_vehicle->getWheelInfo(0).m_chassisConnectionPointCS.getY() - - m_default_suspension_length[0] - - m_vehicle->getWheelInfo(0).m_wheelsRadius - - (m_kart_model->getWheelGraphicsRadius(0) - -m_kart_model->getWheelGraphicsPosition(0).getY() ); - y += m_skidding->getGraphicalJumpOffset(); - center_shift.setY(y); - - if ((m_controls.m_nitro || m_min_nitro_time > 0.0f) && isOnGround() && m_collected_energy > 0) + // Upate particle effects (creation rate, and emitter size + // depending on speed) + // -------------------------------------------------------- + if ( (m_controls.m_nitro || m_min_nitro_time > 0.0f) && + isOnGround() && m_collected_energy > 0 ) { // fabs(speed) is important, otherwise the negative number will // become a huge unsigned number in the particle scene node! @@ -2398,7 +2399,7 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz, m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_NITRO2, 0); m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE1, 0); m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE2, 0); - + } m_kart_gfx->resizeBox(KartGFX::KGFX_NITRO1, getSpeed(), dt); m_kart_gfx->resizeBox(KartGFX::KGFX_NITRO2, getSpeed(), dt); @@ -2407,6 +2408,8 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz, m_kart_gfx->resizeBox(KartGFX::KGFX_ZIPPER, getSpeed(), dt); + // Handle leaning of karts + // ----------------------- // Note that we compare with maximum speed of the kart, not // maximum speed including terrain effects. This avoids that // leaning might get less if a kart gets a special that increases @@ -2461,6 +2464,50 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz, } } + // Now determine graphical chassis and wheel position depending on + // the physics result. The center of gravity of the chassis is at the + // bottom of the chassis, but the position of the graphical chassis is at + // the bottom of the wheels (i.e. in blender the kart is positioned on + // the horizonal plane through (0,0,0)). So first determine how far + // above the terrain is the center of the physics body. If the minimum + // of those values is larger than the lowest point of the chassis model + // the kart chassis would be too high (and look odd), so in this case + // move the chassis down so that the wheels (when touching the ground) + // look close enough to the chassis. + float height_above_terrain[4]; + float min_hat = 9999.9f; + for(unsigned int i=0; i<4; i++) + { + // Set the suspension length + height_above_terrain[i] = + ( m_vehicle->getWheelInfo(i).m_raycastInfo.m_hardPointWS + - m_vehicle->getWheelInfo(i).m_raycastInfo.m_contactPointWS).length() + - m_vehicle->getWheelInfo(i).m_chassisConnectionPointCS.getY(); + if(height_above_terrain[i] < min_hat) min_hat = height_above_terrain[i]; + } + + float chassis_delta = 0; + // Check if the chassis needs to be moved down so that the wheels look + // like they are in the rest state, i.e. the wheels are not too far down. + if(min_hat > m_kart_model->getLowestPoint()) + { + chassis_delta = min_hat - m_kart_model->getLowestPoint(); + for(unsigned int i=0; i<4; i++) + height_above_terrain[i] -= chassis_delta; + } + + m_kart_model->update(dt, m_wheel_rotation_dt, getSteerPercent(), + height_above_terrain, m_speed); + + + // If the kart is leaning, part of the kart might end up 'in' the track. + // To avoid this, raise the kart enough to offset the leaning. + float lean_height = tan(fabsf(m_current_lean)) * getKartWidth()*0.5f; + + Vec3 center_shift = m_kart_properties->getGravityCenterShift(); + + center_shift.setY(m_skidding->getGraphicalJumpOffset() + lean_height + - m_kart_model->getLowestPoint() -chassis_delta ); float heading = m_skidding->getVisualSkidRotation(); Moveable::updateGraphics(dt, center_shift, btQuaternion(heading, 0, m_current_lean)); diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index e169ca459..dd679b18e 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2006 Joerg Henrichs +// Copyright (C) 2006-2013 Joerg Henrichs // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -22,11 +22,12 @@ #include "animations/three_d_animation.hpp" #include "karts/abstract_kart.hpp" #include "graphics/irr_driver.hpp" +#include "graphics/stars.hpp" +#include "items/flyable.hpp" #include "karts/kart_properties.hpp" #include "karts/rescue_animation.hpp" -#include "items/flyable.hpp" +#include "modes/soccer_world.hpp" #include "modes/world.hpp" -#include "graphics/stars.hpp" #include "karts/explosion_animation.hpp" #include "physics/btKart.hpp" #include "physics/btUprightConstraint.hpp" @@ -87,13 +88,13 @@ Physics::~Physics() */ void Physics::addKart(const AbstractKart *kart) { - const btCollisionObjectArray &all_objs = - m_dynamics_world->getCollisionObjectArray(); - for(unsigned int i=0; i<(unsigned int)all_objs.size(); i++) - { - if(btRigidBody::upcast(all_objs[i])== kart->getBody()) - return; - } + const btCollisionObjectArray &all_objs = + m_dynamics_world->getCollisionObjectArray(); + for(unsigned int i=0; i<(unsigned int)all_objs.size(); i++) + { + if(btRigidBody::upcast(all_objs[i])== kart->getBody()) + return; + } m_dynamics_world->addRigidBody(kart->getBody()); m_dynamics_world->addVehicle(kart->getVehicle()); m_dynamics_world->addConstraint(kart->getUprightConstraint()); @@ -189,6 +190,12 @@ void Physics::update(float dt) const KartProperties* kp = kart->getKartProperties(); kart->setSquash(kp->getSquashDuration(), kp->getSquashSlowdown()); } + else if(obj->isSoccerBall()) + { + int kartId = p->getUserPointer(1)->getPointerKart()->getWorldKartId(); + SoccerWorld* soccerWorld = (SoccerWorld*)World::getWorld(); + soccerWorld->setLastKartTohitBall(kartId); + } continue; } @@ -229,6 +236,13 @@ void Physics::update(float dt) // ------------------------------- p->getUserPointer(0)->getPointerFlyable() ->hit(NULL, p->getUserPointer(1)->getPointerPhysicalObject()); + PhysicalObject* obj = p->getUserPointer(1)->getPointerPhysicalObject(); + if(obj->isSoccerBall()) + { + int kartId = p->getUserPointer(0)->getPointerFlyable()->getOwnerId(); + SoccerWorld* soccerWorld = (SoccerWorld*)World::getWorld(); + soccerWorld->setLastKartTohitBall(kartId); + } } else if(p->getUserPointer(1)->is(UserPointer::UP_KART)) @@ -472,6 +486,16 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies, .m_normalWorldOnB; kart->crashed(m, normal); } + else if(upB->is(UserPointer::UP_PHYSICAL_OBJECT)) + { + int n = contact_manifold->getContactPoint(0).m_index1; + const Material *m + = n>=0 ? upA->getPointerTriangleMesh()->getMaterial(n) + : NULL; + const btVector3 &normal = contact_manifold->getContactPoint(0) + .m_normalWorldOnB; + upB->getPointerPhysicalObject()->hit(m, normal); + } } // 2) object a is a kart // ===================== @@ -538,6 +562,16 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies, m_all_collisions.push_back( upA, contact_manifold->getContactPoint(0).m_localPointA, upB, contact_manifold->getContactPoint(0).m_localPointB); + else if(upB->is(UserPointer::UP_TRACK)) + { + int n = contact_manifold->getContactPoint(0).m_index1; + const Material *m + = n>=0 ? upB->getPointerTriangleMesh()->getMaterial(n) + : NULL; + const btVector3 &normal = contact_manifold->getContactPoint(0) + .m_normalWorldOnB; + upA->getPointerPhysicalObject()->hit(m, normal); + } } else if (upA->is(UserPointer::UP_ANIMATION)) { diff --git a/src/utils/time.hpp b/src/utils/time.hpp index 8cecca105..8c796756b 100644 --- a/src/utils/time.hpp +++ b/src/utils/time.hpp @@ -1,6 +1,6 @@ -// // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2004 Steve Baker +// +// Copyright (C) 2013 SuperTuxKart-Team // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -39,7 +39,10 @@ class StkTime public: typedef time_t TimeType; - /** Converts the time in this object to a human readable string. */ + static double getRealTime(long startAt=0); + static void getDate(int *day=NULL, int *month=NULL, int *year=NULL); + + /** Converts the time in this object to a human readable string. */ static std::string toString(const TimeType &tt) { const struct tm *t = gmtime(&tt); @@ -125,7 +128,7 @@ public: t.tm_mon += month; t.tm_mday += day; return mktime(&t); - } + } // addInterval // ------------------------------------------------------------------------ class ScopeProfiler @@ -143,7 +146,7 @@ public: float f2 = (float)getRealTime(); printf("} // took %f s\n", (f2 - m_time)); } - }; + }; // class ScopeProfiler }; // namespace time #endif