Index: ps/trunk/source/gui/CSlider.cpp =================================================================== --- ps/trunk/source/gui/CSlider.cpp (revision 23001) +++ ps/trunk/source/gui/CSlider.cpp (revision 23002) @@ -1,142 +1,143 @@ /* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "CSlider.h" #include "gui/CGUI.h" +#include "maths/MathUtil.h" CSlider::CSlider(CGUI& pGUI) : IGUIObject(pGUI), m_IsPressed(false), m_ButtonSide(0) { AddSetting("value"); AddSetting("min_value"); AddSetting("max_value"); AddSetting("cell_id"); AddSetting("sprite"); AddSetting("sprite_bar"); AddSetting("button_width"); m_Value = GetSetting("value"); m_MinValue = GetSetting("min_value"); m_MaxValue = GetSetting("max_value"); m_ButtonSide = GetSetting("button_width"); m_Value = Clamp(m_Value, m_MinValue, m_MaxValue); } CSlider::~CSlider() { } float CSlider::GetSliderRatio() const { return (m_MaxValue - m_MinValue) / (m_CachedActualSize.GetWidth() - m_ButtonSide); } void CSlider::IncrementallyChangeValue(const float difference) { m_Value = Clamp(m_Value + difference, m_MinValue, m_MaxValue); UpdateValue(); } void CSlider::HandleMessage(SGUIMessage& Message) { switch (Message.type) { case GUIM_SETTINGS_UPDATED: { m_Value = GetSetting("value"); m_MinValue = GetSetting("min_value"); m_MaxValue = GetSetting("max_value"); m_ButtonSide = GetSetting("button_width"); m_Value = Clamp(m_Value, m_MinValue, m_MaxValue); break; } case GUIM_MOUSE_WHEEL_DOWN: { if (m_IsPressed) break; IncrementallyChangeValue(-0.01f); break; } case GUIM_MOUSE_WHEEL_UP: { if (m_IsPressed) break; IncrementallyChangeValue(0.01f); break; } case GUIM_MOUSE_PRESS_LEFT: { m_Mouse = m_pGUI.GetMousePos(); m_IsPressed = true; IncrementallyChangeValue((m_Mouse.x - GetButtonRect().CenterPoint().x) * GetSliderRatio()); break; } case GUIM_MOUSE_RELEASE_LEFT: { m_IsPressed = false; break; } case GUIM_MOUSE_MOTION: { if (!IsMouseOver()) m_IsPressed = false; if (m_IsPressed) { float difference = float(m_pGUI.GetMousePos().x - m_Mouse.x) * GetSliderRatio(); m_Mouse = m_pGUI.GetMousePos(); IncrementallyChangeValue(difference); } break; } default: break; } } void CSlider::Draw() { CGUISpriteInstance& sprite = GetSetting("sprite_bar"); CGUISpriteInstance& sprite_button = GetSetting("sprite"); const int cell_id = GetSetting("cell_id"); CRect slider_line(m_CachedActualSize); slider_line.left += m_ButtonSide / 2.0f; slider_line.right -= m_ButtonSide / 2.0f; float bz = GetBufferedZ(); m_pGUI.DrawSprite(sprite, cell_id, bz, slider_line); m_pGUI.DrawSprite(sprite_button, cell_id, bz, GetButtonRect()); } void CSlider::UpdateValue() { SetSetting("value", m_Value, true); ScriptEvent("valuechange"); } CRect CSlider::GetButtonRect() const { float ratio = m_MaxValue > m_MinValue ? (m_Value - m_MinValue) / (m_MaxValue - m_MinValue) : 0.0f; float x = m_CachedActualSize.left + ratio * (m_CachedActualSize.GetWidth() - m_ButtonSide); float y = m_CachedActualSize.top + (m_CachedActualSize.GetHeight() - m_ButtonSide) / 2.0; return CRect(x, y, x + m_ButtonSide, y + m_ButtonSide); } Index: ps/trunk/source/lib/lib.h =================================================================== --- ps/trunk/source/lib/lib.h (revision 23001) +++ ps/trunk/source/lib/lib.h (revision 23002) @@ -1,168 +1,160 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * various utility functions. */ /** low-level aka "lib" ------------------- this codebase was grown from modules shared between several projects, i.e. my personal library; hence the name "lib". it has been expanded to fit the needs of 0ad - in particular, resource loading. owing to the dual-use situation, the 0ad coding conventions are not met; also, major changes are ill-advised because they may break other projects. design goals ------------ - fast and low-overhead, including startup time - portable: must run on Win32, Mac OS X and Linux - reusable across projects, i.e. no dependency on a central 'manager' that ties modules together. scope ----- - POSIX definitions - resource management - debugging tools (including memory tracker) - low-level helper functions, e.g. ADTs, endian conversion and timing - platform-dependent system/feature detection **/ #ifndef INCLUDED_LIB #define INCLUDED_LIB #include // fabsf #include // numeric_limits #include // out_of_range -#include // min, max - -template -T Clamp(T val, T min, T max) -{ - ASSERT(min <= max); - return std::max(min, std::min(val, max)); -} template T DivideRoundUp(T dividend, T divisor) { ASSERT(divisor != 0); return (dividend + divisor-1) / divisor; } /** * are the given floats nearly "equal"? * * @return whether the numbers are within "epsilon" of each other. * * notes: * - the epsilon magic number varies with the magnitude of the inputs. * we use a sane default, but don't use this routine for very * large/small comparands. * - floating-point numbers don't magically lose precision. addition, * subtraction and multiplication results are precise up to the mantissa's * least-significant bit. only division, sqrt, sin/cos and other * transcendental operations introduce error. **/ inline bool feq(double d1, double d2, double epsilon = 0.00001) { return fabs(d1 - d2) < epsilon; } inline bool feqf(float f1, float f2, float epsilon = 0.001f) { return fabsf(f1 - f2) < epsilon; } inline bool IsSimilarMagnitude(double d1, double d2, const double relativeErrorTolerance = 0.05) { const double relativeError = fabs(d1/d2 - 1.0); if(relativeError > relativeErrorTolerance) return false; return true; } //----------------------------------------------------------------------------- // type conversion // note: these avoid a common mistake in using >> (ANSI requires // shift count be less than the bit width of the type). extern u32 u64_hi(u64 x); /// return upper 32-bits extern u32 u64_lo(u64 x); /// return lower 32-bits extern u16 u32_hi(u32 x); /// return upper 16-bits extern u16 u32_lo(u32 x); /// return lower 16-bits extern u64 u64_from_u32(u32 hi, u32 lo); /// assemble u64 from u32 extern u32 u32_from_u16(u16 hi, u16 lo); /// assemble u32 from u16 // safe downcasters: cast from any integral type to u32 or u16; // issues warning if larger than would fit in the target type. // // these are generally useful but included here (instead of e.g. lib.h) for // several reasons: // - including implementation in lib.h doesn't work because the definition // of ENSURE in turn requires lib.h's STMT. // - separate compilation of templates via export isn't supported by // most compilers. template u8 u8_from_larger(T x) { const u8 max = std::numeric_limits::max(); if((u64)x > (u64)max) throw std::out_of_range("u8_from_larger"); return (u8)(x & max); } template u16 u16_from_larger(T x) { const u16 max = std::numeric_limits::max(); if((u64)x > (u64)max) throw std::out_of_range("u16_from_larger"); return (u16)(x & max); } template u32 u32_from_larger(T x) { const u32 max = std::numeric_limits::max(); if((u64)x > (u64)max) throw std::out_of_range("u32_from_larger"); return (u32)(x & max); } /// convert double to u8; verifies number is in range. extern u8 u8_from_double(double in); /// convert double to u16; verifies number is in range. extern u16 u16_from_double(double in); #endif // #ifndef INCLUDED_LIB Index: ps/trunk/source/maths/MathUtil.h =================================================================== --- ps/trunk/source/maths/MathUtil.h (revision 23001) +++ ps/trunk/source/maths/MathUtil.h (revision 23002) @@ -1,46 +1,50 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #ifndef INCLUDED_MATHUTIL #define INCLUDED_MATHUTIL #define DEGTORAD(a) ((a) * ((float)M_PI/180.0f)) #define RADTODEG(a) ((a) * (180.0f/(float)M_PI)) #define SQR(x) ((x) * (x)) template -inline T Interpolate(const T& a, const T& b, float l) +inline T Interpolate(const T& a, const T& b, float t) { - return a + (b - a) * l; + return a + (b - a) * t; } template -inline T clamp(T value, T min, T max) +inline T Clamp(T value, T min, T max) { - if (value <= min) return min; - else if (value >= max) return max; - else return value; + if (value <= min) + return min; + else if (value >= max) + return max; + return value; } inline float sgn(float a) { - if (a > 0.0f) return 1.0f; - if (a < 0.0f) return -1.0f; + if (a > 0.0f) + return 1.0f; + if (a < 0.0f) + return -1.0f; return 0.0f; } -#endif +#endif // INCLUDED_MATHUTIL Index: ps/trunk/source/soundmanager/data/ogg.cpp =================================================================== --- ps/trunk/source/soundmanager/data/ogg.cpp (revision 23001) +++ ps/trunk/source/soundmanager/data/ogg.cpp (revision 23002) @@ -1,333 +1,332 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "ogg.h" #if CONFIG2_AUDIO +#include "lib/byte_order.h" #include "lib/external_libraries/openal.h" #include "lib/external_libraries/vorbis.h" - -#include "lib/byte_order.h" -#include "lib/file/io/io.h" #include "lib/file/file_system.h" - +#include "lib/file/io/io.h" #include "lib/file/vfs/vfs_util.h" +#include "maths/MathUtil.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" static Status LibErrorFromVorbis(int err) { switch(err) { case 0: return INFO::OK; case OV_HOLE: return ERR::AGAIN; case OV_EREAD: return ERR::IO; case OV_EFAULT: return ERR::LOGIC; case OV_EIMPL: return ERR::NOT_SUPPORTED; case OV_EINVAL: return ERR::INVALID_PARAM; case OV_ENOTVORBIS: return ERR::NOT_SUPPORTED; case OV_EBADHEADER: return ERR::CORRUPTED; case OV_EVERSION: return ERR::INVALID_VERSION; case OV_ENOTAUDIO: return ERR::_1; case OV_EBADPACKET: return ERR::_2; case OV_EBADLINK: return ERR::_3; case OV_ENOSEEK: return ERR::_4; default: return ERR::FAIL; } } //----------------------------------------------------------------------------- class VorbisFileAdapter { public: VorbisFileAdapter(const PFile& openedFile) : file(openedFile) , size(FileSize(openedFile->Pathname())) , offset(0) { } static size_t Read(void* bufferToFill, size_t itemSize, size_t numItems, void* context) { VorbisFileAdapter* adapter = static_cast(context); const off_t sizeRequested = numItems*itemSize; const off_t sizeRemaining = adapter->size - adapter->offset; const size_t sizeToRead = (size_t)std::min(sizeRequested, sizeRemaining); io::Operation op(*adapter->file.get(), bufferToFill, sizeToRead, adapter->offset); if(io::Run(op) == INFO::OK) { adapter->offset += sizeToRead; return sizeToRead; } errno = EIO; return 0; } static int Seek(void* context, ogg_int64_t offset, int whence) { VorbisFileAdapter* adapter = static_cast(context); off_t origin = 0; switch(whence) { case SEEK_SET: origin = 0; break; case SEEK_CUR: origin = adapter->offset; break; case SEEK_END: origin = adapter->size+1; break; NODEFAULT; } adapter->offset = Clamp(off_t(origin+offset), off_t(0), adapter->size); return 0; } static int Close(void* context) { VorbisFileAdapter* adapter = static_cast(context); adapter->file.reset(); return 0; // return value is ignored } static long Tell(void* context) { VorbisFileAdapter* adapter = static_cast(context); return adapter->offset; } private: PFile file; off_t size; off_t offset; }; //----------------------------------------------------------------------------- class VorbisBufferAdapter { public: VorbisBufferAdapter(const shared_ptr& buffer, size_t size) : buffer(buffer) , size(size) , offset(0) { } static size_t Read(void* bufferToFill, size_t itemSize, size_t numItems, void* context) { VorbisBufferAdapter* adapter = static_cast(context); const off_t sizeRequested = numItems*itemSize; const off_t sizeRemaining = adapter->size - adapter->offset; const size_t sizeToRead = (size_t)std::min(sizeRequested, sizeRemaining); memcpy(bufferToFill, adapter->buffer.get() + adapter->offset, sizeToRead); adapter->offset += sizeToRead; return sizeToRead; } static int Seek(void* context, ogg_int64_t offset, int whence) { VorbisBufferAdapter* adapter = static_cast(context); off_t origin = 0; switch(whence) { case SEEK_SET: origin = 0; break; case SEEK_CUR: origin = adapter->offset; break; case SEEK_END: origin = adapter->size+1; break; NODEFAULT; } adapter->offset = Clamp(off_t(origin+offset), off_t(0), adapter->size); return 0; } static int Close(void* context) { VorbisBufferAdapter* adapter = static_cast(context); adapter->buffer.reset(); return 0; // return value is ignored } static long Tell(void* context) { VorbisBufferAdapter* adapter = static_cast(context); return adapter->offset; } private: shared_ptr buffer; off_t size; off_t offset; }; //----------------------------------------------------------------------------- template class OggStreamImpl : public OggStream { public: OggStreamImpl(const Adapter& adapter) : adapter(adapter) { m_fileEOF = false; info = NULL; } Status Close() { ov_clear( &vf ); return 0; } Status Open() { ov_callbacks callbacks; callbacks.read_func = Adapter::Read; callbacks.close_func = Adapter::Close; callbacks.seek_func = Adapter::Seek; callbacks.tell_func = Adapter::Tell; const int ret = ov_open_callbacks(&adapter, &vf, 0, 0, callbacks); if(ret != 0) WARN_RETURN(LibErrorFromVorbis(ret)); const int link = -1; // retrieve info for current bitstream info = ov_info(&vf, link); if(!info) WARN_RETURN(ERR::INVALID_HANDLE); return INFO::OK; } virtual ALenum Format() { return (info->channels == 1)? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; } virtual ALsizei SamplingRate() { return info->rate; } virtual bool atFileEOF() { return m_fileEOF; } virtual Status ResetFile() { ov_time_seek( &vf, 0 ); m_fileEOF = false; return INFO::OK; } virtual Status GetNextChunk(u8* buffer, size_t size) { // we may have to call ov_read multiple times because it // treats the buffer size "as a limit and not a request" size_t bytesRead = 0; for(;;) { const int isBigEndian = (BYTE_ORDER == BIG_ENDIAN); const int wordSize = sizeof(i16); const int isSigned = 1; int bitstream; // unused const int ret = ov_read(&vf, (char*)buffer+bytesRead, int(size-bytesRead), isBigEndian, wordSize, isSigned, &bitstream); if(ret == 0) { // EOF m_fileEOF = true; return (Status)bytesRead; } else if(ret < 0) WARN_RETURN(LibErrorFromVorbis(ret)); else // success { bytesRead += ret; if(bytesRead == size) return (Status)bytesRead; } } } private: Adapter adapter; OggVorbis_File vf; vorbis_info* info; bool m_fileEOF; }; //----------------------------------------------------------------------------- Status OpenOggStream(const OsPath& pathname, OggStreamPtr& stream) { PFile file(new File); RETURN_STATUS_IF_ERR(file->Open(pathname, L'r')); shared_ptr > tmp(new OggStreamImpl(VorbisFileAdapter(file))); RETURN_STATUS_IF_ERR(tmp->Open()); stream = tmp; return INFO::OK; } Status OpenOggNonstream(const PIVFS& vfs, const VfsPath& pathname, OggStreamPtr& stream) { shared_ptr contents; size_t size; RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, contents, size)); shared_ptr > tmp(new OggStreamImpl(VorbisBufferAdapter(contents, size))); RETURN_STATUS_IF_ERR(tmp->Open()); stream = tmp; return INFO::OK; } #endif // CONFIG2_AUDIO