/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "Gs/GsBaseVectorizer.h" #include "Gi/GiEnvironmentTraitsData.h" #include "Gi/GiRasterImageLoader.h" #include "GsImageBackgroundImpl.h" // OdGsImageBackgroundImpl OdGsImageBackgroundImpl::OdGsImageBackgroundImpl(const OdGsBackgroundModule *pModule) : OdGsBackgroundImpl(pModule) { } void OdGsImageBackgroundImpl::display(OdGsBaseVectorizer& view, const OdGiDrawable *pDrawable, OdGiBackgroundTraitsData *pBackgroundTraits, OdGsPropertiesDirectRenderOutput *pdro) { #ifdef OD_GSBACKGROUND_VERBOSE_ON ODA_TRACE(L"OdGsImageBackgroundImpl::display\n"); #endif // viewportClipRegion OdGiImageBackgroundTraitsData *bgt = reinterpret_cast(pBackgroundTraits); if (raster.isNull()) { raster = OdGiRasterImageLoader::createObject()->loadRasterImage(bgt->imageFilename(), view.drawContext()->giContext(), OdDbBaseHostAppServices::kEmbeddedImageFile); } if (!raster.isNull()) { RenderingModeHolder holder; OdGePoint3d rect[5]; OdGeMatrix3d m3d; m3d = view.eyeToOutputTransform(); fillBackgroundRect(view.view(), rect); for (int i = 0; i < 5; i++) { rect[i].transformBy(m3d); } holder = setRenderingMode(view); double dlrx = 0.0, dlry = 0.0; raster->defaultResolution(dlrx, dlry); if (OdZero(dlrx)) dlrx = 100.0; if (OdZero(dlry)) dlry = 100.0; OdGeVector3d u = (rect[1] - rect[0]).normal() * ((rect[1] - rect[0]).length() / dlrx); OdGeVector3d v = (rect[3] - rect[0]).normal() * ((rect[3] - rect[0]).length() / dlry); if (bgt->fitToScreen()) { if (bgt->maintainAspectRatio()) { OdGeVector3d recNorm[2]; double recLen[2]; recNorm[0] = rect[1] - rect[0]; recNorm[1] = rect[3] - rect[0]; recLen[0] = recNorm[0].normalizeGetLength(); recLen[1] = recNorm[1].normalizeGetLength(); double scale[2] = { recLen[0] / raster->pixelWidth(), recLen[1] / raster->pixelHeight() }; if (scale[0] > scale[1]) { double aspectRatio = scale[0] / scale[1]; double scaleLen = (recLen[1] * aspectRatio - recLen[1]) / 2; rect[0] -= recNorm[1] * scaleLen; rect[1] -= recNorm[1] * scaleLen; rect[2] += recNorm[1] * scaleLen; rect[3] += recNorm[1] * scaleLen; v *= aspectRatio; } else if (scale[0] < scale[1]) { double aspectRatio = scale[1] / scale[0]; double scaleLen = (recLen[0] * aspectRatio - recLen[0]) / 2; rect[0] -= recNorm[0] * scaleLen; rect[1] += recNorm[0] * scaleLen; rect[2] += recNorm[0] * scaleLen; rect[3] -= recNorm[0] * scaleLen; u *= aspectRatio; } } if (pdro != NULL && GETBIT(pdro->directRenderOutputFlags(), OdGsPropertiesDirectRenderOutput::DirectRender_Image)) { OdGsPropertiesDirectRenderOutput::DirectRenderImageParams params; params.uvCoords = NULL; // Clamped output params.pDrawable = pDrawable; pdro->directRenderOutputImage(rect, raster, params); } else { view.rasterImageDc(rect[0], u / (raster->pixelWidth() / dlrx), v / (raster->pixelHeight() / dlry), raster, NULL, 0); } } else { OdGsDCPoint llDC, urDC; view.view().screenRect(llDC, urDC); double pixAspectX = u.length() * dlrx / Od_abs((int)(urDC.x - llDC.x)); double pixAspectY = v.length() * dlry / Od_abs((int)(urDC.y - llDC.y)); OdGePoint3d center(rect[0] + u * (dlrx / 2) + v * (dlry / 2)); if (bgt->xOffset()) { center += u.normal() * bgt->xOffset() * pixAspectX; } if (bgt->yOffset()) { center += v.normal() * bgt->yOffset() * pixAspectY; } u = u.normal(); v = v.normal(); u *= pixAspectX; v *= pixAspectY; u *= bgt->xScale(); v *= bgt->yScale(); if (!bgt->useTiling()) { if (pdro != NULL && GETBIT(pdro->directRenderOutputFlags(), OdGsPropertiesDirectRenderOutput::DirectRender_Image)) { OdGsPropertiesDirectRenderOutput::DirectRenderImageParams params; params.uvCoords = NULL; // Clamped output params.pDrawable = pDrawable; u *= (double)raster->pixelWidth() / dlrx; v *= (double)raster->pixelHeight() / dlry; OdGePoint3d image_rect[4] = { center - u / 2 * dlrx - v / 2 * dlry, center + u / 2 * dlrx - v / 2 * dlry, center + u / 2 * dlrx + v / 2 * dlry, center - u / 2 * dlrx + v / 2 * dlry }; pdro->directRenderOutputImage(image_rect, raster, params); } else { OdGePoint3d devOrigin(center - u * (double)raster->pixelWidth() / 2 - v * (double)raster->pixelHeight() / 2); deviceOutputCorrection(view, devOrigin); view.rasterImageDc(devOrigin, u, v, raster, NULL, 0); } } else { // Find rect[0] nearest tile u *= (double)raster->pixelWidth() / dlrx; v *= (double)raster->pixelHeight() / dlry; center -= u / 2 * dlrx; center -= v / 2 * dlry; OdGePoint3d tile(center + u.normal() * (intelligentRoundUp(u.normal().dotProduct(rect[0] - center) / (u.length() * dlrx)) * u.length() * dlrx) + v.normal() * (intelligentRoundUp(v.normal().dotProduct(rect[0] - center) / (v.length() * dlry)) * v.length() * dlry)); OdInt32 xNum = (OdInt32)ceil((rect[1] - rect[0]).length() / (u.length() * dlrx)) + 1; OdInt32 yNum = (OdInt32)ceil((rect[3] - rect[0]).length() / (v.length() * dlry)) + 1; if (pdro != NULL && GETBIT(pdro->directRenderOutputFlags(), OdGsPropertiesDirectRenderOutput::DirectRender_Image)) { OdGsPropertiesDirectRenderOutput::DirectRenderImageParams params; OdGsPropertiesDirectRenderOutput::DirectRenderImageUV uvCoords[4]; uvCoords[0].u = 0.0; uvCoords[0].v = 0.0; uvCoords[1].u = double(xNum); uvCoords[1].v = 0.0; uvCoords[2].u = double(xNum); uvCoords[2].v = double(yNum); uvCoords[3].u = 0.0; uvCoords[3].v = double(yNum); params.uvCoords = uvCoords; // Repeat output params.pDrawable = pDrawable; OdGePoint3d image_rect[4] = { tile, tile + u * dlrx * xNum, tile + u * dlrx * xNum + v * dlry * yNum, tile + v * dlry * yNum }; pdro->directRenderOutputImage(image_rect, raster, params); } else { for (OdInt32 xi = 0; xi < xNum; xi++) { for (OdInt32 yi = 0; yi < yNum; yi++) { OdGePoint3d devOrigin(tile + u * dlrx * xi + v * dlry * yi); deviceOutputCorrection(view, devOrigin); view.rasterImageDc(devOrigin, u / ((double)raster->pixelWidth() / dlrx), v / ((double)raster->pixelHeight() / dlry), raster, NULL, 0); } } } } } restoreRenderingMode(view, holder); } } double OdGsImageBackgroundImpl::intelligentRoundUp(double value) const { //if (value >= 0.0) //{ // return ceil(value); //} return floor(value); } void OdGsImageBackgroundImpl::deviceOutputCorrection(const OdGsBaseVectorizer& view, OdGePoint3d &origin) const { // Correct output for simple devices (compensate coordinate transformation rounding) OdGeMatrix3d m3d(view.view().eyeToScreenMatrix()); OdGeMatrix3d m3dOut(view.eyeToOutputTransform() * m3d.invert()); OdGeMatrix3d m3dIn(m3dOut); m3dIn.invert(); origin.transformBy(m3dIn); origin.x = ceil(origin.x + 0.1); origin.y = ceil(origin.y + 0.1); origin.transformBy(m3dOut); } //