///////////////////////////////////////////////////////////////////////////// // AGCVector.cpp : Implementation of CAGCVector // #include "pch.h" #include "AGCVector.h" ///////////////////////////////////////////////////////////////////////////// // CVector TC_OBJECT_EXTERN_IMPL(CAGCVector) ///////////////////////////////////////////////////////////////////////////// // Implementation HRESULT CAGCVector::GetRawVector(IAGCVector* pVector, Vector* pVectorRaw) { __try { if (!pVector) return E_POINTER; IAGCVectorPrivate* pPrivate = NULL; RETURN_FAILED(pVector->QueryInterface(__uuidof(pPrivate), (void**)&pPrivate)); assert(pPrivate); if (!pPrivate) return E_INVALIDARG; HRESULT hr = pPrivate->CopyVectorTo(pVectorRaw); pPrivate->Release(); return hr; } __except(1) { return E_POINTER; } } HRESULT CAGCVector::CreateResultVector(const Vector* pVectorRaw, IAGCVector** ppResult) { CComObject* pVector = NULL; RETURN_FAILED(pVector->CreateInstance(&pVector)); IAGCVectorPtr spVector(pVector); RETURN_FAILED(pVector->InitFromVector(pVectorRaw)); CLEAROUT(ppResult, (IAGCVector*)spVector); spVector.Detach(); return S_OK; } ///////////////////////////////////////////////////////////////////////////// // ISupportErrorInfo Interface Methods STDMETHODIMP CAGCVector::InterfaceSupportsErrorInfo(REFIID riid) { static const IID* arr[] = { &IID_IAGCVector }; for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++) { if (InlineIsEqualGUID(*arr[i],riid)) return S_OK; } return S_FALSE; } ///////////////////////////////////////////////////////////////////////////// // IPersist Interface Methods STDMETHODIMP CAGCVector::GetClassID(CLSID* pClassID) { __try { *pClassID = GetObjectCLSID(); } __except(1) { return E_POINTER; } return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IPersistStreamInit Interface Methods STDMETHODIMP CAGCVector::IsDirty() { // Return dirty flag XLock lock(this); return m_bDirty ? S_OK : S_FALSE; } STDMETHODIMP CAGCVector::Load(LPSTREAM pStm) { // Read the number of floats being read long cDims; RETURN_FAILED(pStm->Read(&cDims, sizeof(cDims), NULL)); if (DIMENSIONS != cDims) { assert(DIMENSIONS == cDims); return ERROR_INVALID_DATA; } // Read each float from the stream float xArg, yArg, zArg; RETURN_FAILED(pStm->Read(&xArg, sizeof(xArg), NULL)); RETURN_FAILED(pStm->Read(&yArg, sizeof(yArg), NULL)); RETURN_FAILED(pStm->Read(&zArg, sizeof(zArg), NULL)); // Save the values return InitXYZ(xArg, yArg, zArg); } STDMETHODIMP CAGCVector::Save(LPSTREAM pStm, BOOL fClearDirty) { // Write out the number of floats being written long cDims = DIMENSIONS; RETURN_FAILED(pStm->Write(&cDims, sizeof(cDims), NULL)); // Write each float to the stream XLock lock(this); float xArg = m_vector.X(), yArg = m_vector.Y(), zArg = m_vector.Z(); RETURN_FAILED(pStm->Write(&xArg, sizeof(xArg), NULL)); RETURN_FAILED(pStm->Write(&yArg, sizeof(yArg), NULL)); RETURN_FAILED(pStm->Write(&zArg, sizeof(zArg), NULL)); // Clear the dirty flag, if specified if (fClearDirty) m_bDirty = false; // Indicate success return S_OK; } STDMETHODIMP CAGCVector::GetSizeMax(ULARGE_INTEGER* pCbSize) { __try { // NOTE: This needs to exactly match what's written in Save pCbSize->LowPart = sizeof(long) + sizeof(float) * DIMENSIONS; pCbSize->HighPart = 0; } __except(1) { return E_POINTER; } // Indicate success return S_OK; } STDMETHODIMP CAGCVector::InitNew( void) { // Initialize the vector object XLock lock(this); m_vector = Vector::GetZero(); // Indicate success return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IPersistPropertyBag Interface Methods STDMETHODIMP CAGCVector::Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog) { // Load each dimension (column) of the vector object CComVariant varX(0.f), varY(0.f), varZ(0.f); RETURN_FAILED(pPropBag->Read(L"X", &varX, pErrorLog)); RETURN_FAILED(pPropBag->Read(L"Y", &varY, pErrorLog)); RETURN_FAILED(pPropBag->Read(L"Z", &varZ, pErrorLog)); // Save the values return InitXYZ(V_R4(&varX), V_R4(&varY), V_R4(&varZ)); } STDMETHODIMP CAGCVector::Save(IPropertyBag* pPropBag, BOOL fClearDirty, BOOL) { // Save each dimension (column) of the vector object XLock lock(this); RETURN_FAILED(pPropBag->Write(L"X", &CComVariant(m_vector.X()))); RETURN_FAILED(pPropBag->Write(L"Y", &CComVariant(m_vector.Y()))); RETURN_FAILED(pPropBag->Write(L"Z", &CComVariant(m_vector.Z()))); // Clear the dirty flag, if specified if (fClearDirty) m_bDirty = false; // Indicate success return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IAGCVector Interface Methods STDMETHODIMP CAGCVector::put_X(float Val) { XLock lock(this); if (m_vector.X() != Val) { m_vector.SetX(Val); m_bDirty = true; } return S_OK; } STDMETHODIMP CAGCVector::get_X(float* pVal) { XLock lock(this); CLEAROUT(pVal, m_vector.X()); return S_OK; } STDMETHODIMP CAGCVector::put_Y(float Val) { XLock lock(this); if (m_vector.Y() != Val) { m_vector.SetY(Val); m_bDirty = true; } return S_OK; } STDMETHODIMP CAGCVector::get_Y(float* pVal) { XLock lock(this); CLEAROUT(pVal, m_vector.Y()); return S_OK; } STDMETHODIMP CAGCVector::put_Z(float Val) { XLock lock(this); if (m_vector.Z() != Val) { m_vector.SetZ(Val); m_bDirty = true; } return S_OK; } STDMETHODIMP CAGCVector::get_Z(float* pVal) { XLock lock(this); CLEAROUT(pVal, m_vector.Z()); return S_OK; } STDMETHODIMP CAGCVector::put_DisplayString(BSTR bstrDisplayString) { // Invalid if string is empty if (!BSTRLen(bstrDisplayString)) return E_INVALIDARG; // Load the format string CComBSTR bstrFmt; if (!bstrFmt.LoadString(IDS_FMT_VECTOR)) return HRESULT_FROM_WIN32(::GetLastError()); // Extract the values from the string float xArg, yArg, zArg; if (3 != swscanf(bstrDisplayString, bstrFmt, &xArg, &yArg, &zArg)) return E_INVALIDARG; // Save the values return InitXYZ(xArg, yArg, zArg); } STDMETHODIMP CAGCVector::get_DisplayString(BSTR* pbstrDisplayString) { // Load the format string CComBSTR bstrFmt; if (!bstrFmt.LoadString(IDS_FMT_VECTOR)) return HRESULT_FROM_WIN32(::GetLastError()); // Format the string XLock lock(this); OLECHAR szText[_MAX_PATH]; swprintf(szText, bstrFmt, m_vector.X(), m_vector.Y(), m_vector.Z()); // Detach the string to the [out] parameter CComBSTR bstr(szText); CLEAROUT(pbstrDisplayString, (BSTR)bstr); bstr.Detach(); // Indicate success return S_OK; } STDMETHODIMP CAGCVector::InitXYZ(float xArg, float yArg, float zArg) { XLock lock(this); if (m_vector.X() != xArg || m_vector.Y() != yArg || m_vector.Z() != zArg) { m_vector.SetX(xArg); m_vector.SetY(yArg); m_vector.SetZ(zArg); m_bDirty = true; } return S_OK; } STDMETHODIMP CAGCVector::InitCopy(IAGCVector* pVector) { // Get the values of the specified vector float xArg, yArg, zArg; RETURN_FAILED(pVector->get_X(&xArg)); RETURN_FAILED(pVector->get_Y(&yArg)); RETURN_FAILED(pVector->get_Z(&zArg)); // Save the values return InitXYZ(xArg, yArg, zArg); } STDMETHODIMP CAGCVector::InitRandomDirection() { // Create a random direction return InitFromVector(&Vector::RandomDirection()); } STDMETHODIMP CAGCVector::InitRandomPosition(float fRadius) { // Create a random position return InitFromVector(&Vector::RandomPosition(fRadius)); } STDMETHODIMP CAGCVector::get_IsZero(VARIANT_BOOL* pbIsZero) { XLock lock(this); CLEAROUT(pbIsZero, VARBOOL(m_vector.IsZero())); return S_OK; } STDMETHODIMP CAGCVector::get_IsEqual(IAGCVector* pVector, VARIANT_BOOL* pbIsEqual) { Vector vector; RETURN_FAILED(GetRawVector(pVector, &vector)); XLock lock(this); CLEAROUT(pbIsEqual, VARBOOL(vector == m_vector)); return S_OK; } STDMETHODIMP CAGCVector::get_Length(float* pfLength) { XLock lock(this); CLEAROUT(pfLength, m_vector.Length()); return S_OK; } STDMETHODIMP CAGCVector::get_LengthSquared(float* pfLengthSquared) { XLock lock(this); CLEAROUT(pfLengthSquared, m_vector.LengthSquared()); return S_OK; } STDMETHODIMP CAGCVector::get_OrthogonalVector(IAGCVector** ppResult) { XLock lock(this); return CreateResultVector(&m_vector.GetOrthogonalVector(), ppResult); } STDMETHODIMP CAGCVector::Add(IAGCVector* pVector, IAGCVector** ppResult) { Vector vector; RETURN_FAILED(GetRawVector(pVector, &vector)); XLock lock(this); return CreateResultVector(&(m_vector + vector), ppResult); } STDMETHODIMP CAGCVector::Subtract(IAGCVector* pVector, IAGCVector** ppResult) { Vector vector; RETURN_FAILED(GetRawVector(pVector, &vector)); XLock lock(this); return CreateResultVector(&(m_vector - vector), ppResult); } STDMETHODIMP CAGCVector::Multiply(float f, IAGCVector** ppResult) { XLock lock(this); return CreateResultVector(&(m_vector * f), ppResult); } STDMETHODIMP CAGCVector::Divide(float f, IAGCVector** ppResult) { XLock lock(this); return CreateResultVector(&(m_vector / f), ppResult); } STDMETHODIMP CAGCVector::Normalize(IAGCVector** ppResult) { XLock lock(this); return CreateResultVector(&m_vector.Normalize(), ppResult); } STDMETHODIMP CAGCVector::CrossProduct(IAGCVector* pVector, IAGCVector** ppResult) { Vector vector; RETURN_FAILED(GetRawVector(pVector, &vector)); XLock lock(this); return CreateResultVector(&::CrossProduct(m_vector, vector), ppResult); } STDMETHODIMP CAGCVector::Interpolate(IAGCVector* pVector, float fValue, IAGCVector** ppResult) { Vector vector; RETURN_FAILED(GetRawVector(pVector, &vector)); XLock lock(this); return CreateResultVector(&::Interpolate(m_vector, vector, fValue), ppResult); } STDMETHODIMP CAGCVector::AddInPlace(IAGCVector* pVector) { Vector vector; RETURN_FAILED(GetRawVector(pVector, &vector)); XLock lock(this); return InitFromVector(&(m_vector + vector)); } STDMETHODIMP CAGCVector::SubtractInPlace(IAGCVector* pVector) { Vector vector; RETURN_FAILED(GetRawVector(pVector, &vector)); XLock lock(this); return InitFromVector(&(m_vector - vector)); } STDMETHODIMP CAGCVector::MultiplyInPlace(float f) { XLock lock(this); return InitFromVector(&(m_vector * f)); } STDMETHODIMP CAGCVector::DivideInPlace(float f) { XLock lock(this); return InitFromVector(&(m_vector / f)); } STDMETHODIMP CAGCVector::NormalizeInPlace() { XLock lock(this); m_vector.SetNormalize(); return S_OK; } STDMETHODIMP CAGCVector::CrossProductInPlace(IAGCVector* pVector) { Vector vector; RETURN_FAILED(GetRawVector(pVector, &vector)); XLock lock(this); return InitFromVector(&::CrossProduct(m_vector, vector)); } STDMETHODIMP CAGCVector::InterpolateInPlace(IAGCVector* pVector, float fValue) { Vector vector; RETURN_FAILED(GetRawVector(pVector, &vector)); XLock lock(this); return InitFromVector(&::Interpolate(m_vector, vector, fValue)); } ///////////////////////////////////////////////////////////////////////////// // IAGCVectorPrivate Interface Methods STDMETHODIMP CAGCVector::InitFromVector(const void* pvVector) { Vector vectorTemp; const Vector* pVector = reinterpret_cast(pvVector); if (!pVector) { vectorTemp = Vector::GetZero(); pVector = &vectorTemp; } return InitXYZ(pVector->X(), pVector->Y(), pVector->Z()); } STDMETHODIMP CAGCVector::CopyVectorTo(void* pvVector) { XLock lock(this); Vector* pVector = reinterpret_cast(pvVector); pVector->SetX(m_vector.X()); pVector->SetY(m_vector.Y()); pVector->SetZ(m_vector.Z()); return S_OK; }