1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_drawinglayer.hxx" 26 27 #include <drawinglayer/processor3d/zbufferprocessor3d.hxx> 28 #include <basegfx/raster/bpixelraster.hxx> 29 #include <vcl/bmpacc.hxx> 30 #include <basegfx/raster/rasterconvert3d.hxx> 31 #include <basegfx/raster/bzpixelraster.hxx> 32 #include <drawinglayer/attribute/materialattribute3d.hxx> 33 #include <drawinglayer/texture/texture.hxx> 34 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> 35 #include <drawinglayer/primitive3d/textureprimitive3d.hxx> 36 #include <drawinglayer/primitive3d/polygonprimitive3d.hxx> 37 #include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> 38 #include <drawinglayer/geometry/viewinformation2d.hxx> 39 #include <basegfx/polygon/b3dpolygontools.hxx> 40 #include <basegfx/polygon/b3dpolypolygontools.hxx> 41 #include <drawinglayer/attribute/sdrlightingattribute3d.hxx> 42 43 ////////////////////////////////////////////////////////////////////////////// 44 45 using namespace com::sun::star; 46 47 ////////////////////////////////////////////////////////////////////////////// 48 49 namespace 50 { 51 BitmapEx BPixelRasterToBitmapEx(const basegfx::BPixelRaster& rRaster, sal_uInt16 mnAntiAlialize) 52 { 53 BitmapEx aRetval; 54 const sal_uInt32 nWidth(mnAntiAlialize ? rRaster.getWidth()/mnAntiAlialize : rRaster.getWidth()); 55 const sal_uInt32 nHeight(mnAntiAlialize ? rRaster.getHeight()/mnAntiAlialize : rRaster.getHeight()); 56 57 if(nWidth && nHeight) 58 { 59 const Size aDestSize(nWidth, nHeight); 60 sal_uInt8 nInitAlpha(255); 61 Bitmap aContent(aDestSize, 24); 62 AlphaMask aAlpha(aDestSize, &nInitAlpha); 63 BitmapWriteAccess* pContent = aContent.AcquireWriteAccess(); 64 BitmapWriteAccess* pAlpha = aAlpha.AcquireWriteAccess(); 65 66 if(pContent && pAlpha) 67 { 68 if(mnAntiAlialize) 69 { 70 const sal_uInt16 nDivisor(mnAntiAlialize * mnAntiAlialize); 71 72 for(sal_uInt32 y(0L); y < nHeight; y++) 73 { 74 for(sal_uInt32 x(0L); x < nWidth; x++) 75 { 76 sal_uInt16 nRed(0); 77 sal_uInt16 nGreen(0); 78 sal_uInt16 nBlue(0); 79 sal_uInt16 nOpacity(0); 80 sal_uInt32 nIndex(rRaster.getIndexFromXY(x * mnAntiAlialize, y * mnAntiAlialize)); 81 82 for(sal_uInt32 c(0); c < mnAntiAlialize; c++) 83 { 84 for(sal_uInt32 d(0); d < mnAntiAlialize; d++) 85 { 86 const basegfx::BPixel& rPixel(rRaster.getBPixel(nIndex++)); 87 nRed = nRed + rPixel.getRed(); 88 nGreen = nGreen + rPixel.getGreen(); 89 nBlue = nBlue + rPixel.getBlue(); 90 nOpacity = nOpacity + rPixel.getOpacity(); 91 } 92 93 nIndex += rRaster.getWidth() - mnAntiAlialize; 94 } 95 96 nOpacity = nOpacity / nDivisor; 97 98 if(nOpacity) 99 { 100 pContent->SetPixel(y, x, BitmapColor( 101 (sal_uInt8)(nRed / nDivisor), 102 (sal_uInt8)(nGreen / nDivisor), 103 (sal_uInt8)(nBlue / nDivisor))); 104 pAlpha->SetPixel(y, x, BitmapColor(255 - (sal_uInt8)nOpacity)); 105 } 106 } 107 } 108 } 109 else 110 { 111 sal_uInt32 nIndex(0L); 112 113 for(sal_uInt32 y(0L); y < nHeight; y++) 114 { 115 for(sal_uInt32 x(0L); x < nWidth; x++) 116 { 117 const basegfx::BPixel& rPixel(rRaster.getBPixel(nIndex++)); 118 119 if(rPixel.getOpacity()) 120 { 121 pContent->SetPixel(y, x, BitmapColor(rPixel.getRed(), rPixel.getGreen(), rPixel.getBlue())); 122 pAlpha->SetPixel(y, x, BitmapColor(255 - rPixel.getOpacity())); 123 } 124 } 125 } 126 } 127 128 delete pContent; 129 delete pAlpha; 130 } 131 132 aRetval = BitmapEx(aContent, aAlpha); 133 134 // #i101811# set PrefMapMode and PrefSize at newly created Bitmap 135 aRetval.SetPrefMapMode(MAP_PIXEL); 136 aRetval.SetPrefSize(Size(nWidth, nHeight)); 137 } 138 139 return aRetval; 140 } 141 } // end of anonymous namespace 142 143 ////////////////////////////////////////////////////////////////////////////// 144 145 class ZBufferRasterConverter3D : public basegfx::RasterConverter3D 146 { 147 private: 148 const drawinglayer::processor3d::DefaultProcessor3D& mrProcessor; 149 basegfx::BZPixelRaster& mrBuffer; 150 151 // interpolators for a single line span 152 basegfx::ip_single maIntZ; 153 basegfx::ip_triple maIntColor; 154 basegfx::ip_triple maIntNormal; 155 basegfx::ip_double maIntTexture; 156 basegfx::ip_triple maIntInvTexture; 157 158 // current material to use for ratsreconversion 159 const drawinglayer::attribute::MaterialAttribute3D* mpCurrentMaterial; 160 161 // bitfield 162 // some boolean flags for line span interpolator usages 163 unsigned mbModifyColor : 1; 164 unsigned mbUseTex : 1; 165 unsigned mbHasTexCoor : 1; 166 unsigned mbHasInvTexCoor : 1; 167 unsigned mbUseNrm : 1; 168 unsigned mbUseCol : 1; 169 170 void getTextureCoor(basegfx::B2DPoint& rTarget) const 171 { 172 if(mbHasTexCoor) 173 { 174 rTarget.setX(maIntTexture.getX().getVal()); 175 rTarget.setY(maIntTexture.getY().getVal()); 176 } 177 else if(mbHasInvTexCoor) 178 { 179 const double fZFactor(maIntInvTexture.getZ().getVal()); 180 const double fInvZFactor(basegfx::fTools::equalZero(fZFactor) ? 1.0 : 1.0 / fZFactor); 181 rTarget.setX(maIntInvTexture.getX().getVal() * fInvZFactor); 182 rTarget.setY(maIntInvTexture.getY().getVal() * fInvZFactor); 183 } 184 } 185 186 void incrementLineSpanInterpolators(double fStep) 187 { 188 maIntZ.increment(fStep); 189 190 if(mbUseTex) 191 { 192 if(mbHasTexCoor) 193 { 194 maIntTexture.increment(fStep); 195 } 196 else if(mbHasInvTexCoor) 197 { 198 maIntInvTexture.increment(fStep); 199 } 200 } 201 202 if(mbUseNrm) 203 { 204 maIntNormal.increment(fStep); 205 } 206 207 if(mbUseCol) 208 { 209 maIntColor.increment(fStep); 210 } 211 } 212 213 double decideColorAndOpacity(basegfx::BColor& rColor) 214 { 215 // init values with full opacity and material color 216 OSL_ENSURE(0 != mpCurrentMaterial, "CurrentMaterial not set (!)"); 217 double fOpacity(1.0); 218 rColor = mpCurrentMaterial->getColor(); 219 220 if(mbUseTex) 221 { 222 basegfx::B2DPoint aTexCoor(0.0, 0.0); 223 getTextureCoor(aTexCoor); 224 225 if(mrProcessor.getGeoTexSvx().get()) 226 { 227 // calc color in spot. This may also set to invisible already when 228 // e.g. bitmap textures have transparent parts 229 mrProcessor.getGeoTexSvx()->modifyBColor(aTexCoor, rColor, fOpacity); 230 } 231 232 if(basegfx::fTools::more(fOpacity, 0.0) && mrProcessor.getTransparenceGeoTexSvx().get()) 233 { 234 // calc opacity. Object has a 2nd texture, a transparence texture 235 mrProcessor.getTransparenceGeoTexSvx()->modifyOpacity(aTexCoor, fOpacity); 236 } 237 } 238 239 if(basegfx::fTools::more(fOpacity, 0.0)) 240 { 241 if(mrProcessor.getGeoTexSvx().get()) 242 { 243 if(mbUseNrm) 244 { 245 // blend texture with phong 246 rColor = mrProcessor.getSdrLightingAttribute().solveColorModel( 247 basegfx::B3DVector(maIntNormal.getX().getVal(), maIntNormal.getY().getVal(), maIntNormal.getZ().getVal()), 248 rColor, 249 mpCurrentMaterial->getSpecular(), 250 mpCurrentMaterial->getEmission(), 251 mpCurrentMaterial->getSpecularIntensity()); 252 } 253 else if(mbUseCol) 254 { 255 // blend texture with gouraud 256 basegfx::BColor aBlendColor(maIntColor.getX().getVal(), maIntColor.getY().getVal(), maIntColor.getZ().getVal()); 257 rColor *= aBlendColor; 258 } 259 else if(mrProcessor.getModulate()) 260 { 261 // blend texture with single material color 262 rColor *= mpCurrentMaterial->getColor(); 263 } 264 } 265 else 266 { 267 if(mbUseNrm) 268 { 269 // modify color with phong 270 rColor = mrProcessor.getSdrLightingAttribute().solveColorModel( 271 basegfx::B3DVector(maIntNormal.getX().getVal(), maIntNormal.getY().getVal(), maIntNormal.getZ().getVal()), 272 rColor, 273 mpCurrentMaterial->getSpecular(), 274 mpCurrentMaterial->getEmission(), 275 mpCurrentMaterial->getSpecularIntensity()); 276 } 277 else if(mbUseCol) 278 { 279 // modify color with gouraud 280 rColor.setRed(maIntColor.getX().getVal()); 281 rColor.setGreen(maIntColor.getY().getVal()); 282 rColor.setBlue(maIntColor.getZ().getVal()); 283 } 284 } 285 286 if(mbModifyColor) 287 { 288 rColor = mrProcessor.getBColorModifierStack().getModifiedColor(rColor); 289 } 290 } 291 292 return fOpacity; 293 } 294 295 void setupLineSpanInterpolators(const basegfx::RasterConversionLineEntry3D& rA, const basegfx::RasterConversionLineEntry3D& rB) 296 { 297 // get inverse XDelta 298 const double xInvDelta(1.0 / (rB.getX().getVal() - rA.getX().getVal())); 299 300 // prepare Z-interpolator 301 const double fZA(rA.getZ().getVal()); 302 const double fZB(rB.getZ().getVal()); 303 maIntZ = basegfx::ip_single(fZA, (fZB - fZA) * xInvDelta); 304 305 // get bools and init other interpolators on demand accordingly 306 mbModifyColor = mrProcessor.getBColorModifierStack().count(); 307 mbHasTexCoor = SCANLINE_EMPTY_INDEX != rA.getTextureIndex() && SCANLINE_EMPTY_INDEX != rB.getTextureIndex(); 308 mbHasInvTexCoor = SCANLINE_EMPTY_INDEX != rA.getInverseTextureIndex() && SCANLINE_EMPTY_INDEX != rB.getInverseTextureIndex(); 309 const bool bTextureActive(mrProcessor.getGeoTexSvx().get() || mrProcessor.getTransparenceGeoTexSvx().get()); 310 mbUseTex = bTextureActive && (mbHasTexCoor || mbHasInvTexCoor || mrProcessor.getSimpleTextureActive()); 311 const bool bUseColorTex(mbUseTex && mrProcessor.getGeoTexSvx().get()); 312 const bool bNeedNrmOrCol(!bUseColorTex || (bUseColorTex && mrProcessor.getModulate())); 313 mbUseNrm = bNeedNrmOrCol && SCANLINE_EMPTY_INDEX != rA.getNormalIndex() && SCANLINE_EMPTY_INDEX != rB.getNormalIndex(); 314 mbUseCol = !mbUseNrm && bNeedNrmOrCol && SCANLINE_EMPTY_INDEX != rA.getColorIndex() && SCANLINE_EMPTY_INDEX != rB.getColorIndex(); 315 316 if(mbUseTex) 317 { 318 if(mbHasTexCoor) 319 { 320 const basegfx::ip_double& rTA(getTextureInterpolators()[rA.getTextureIndex()]); 321 const basegfx::ip_double& rTB(getTextureInterpolators()[rB.getTextureIndex()]); 322 maIntTexture = basegfx::ip_double( 323 rTA.getX().getVal(), (rTB.getX().getVal() - rTA.getX().getVal()) * xInvDelta, 324 rTA.getY().getVal(), (rTB.getY().getVal() - rTA.getY().getVal()) * xInvDelta); 325 } 326 else if(mbHasInvTexCoor) 327 { 328 const basegfx::ip_triple& rITA(getInverseTextureInterpolators()[rA.getInverseTextureIndex()]); 329 const basegfx::ip_triple& rITB(getInverseTextureInterpolators()[rB.getInverseTextureIndex()]); 330 maIntInvTexture = basegfx::ip_triple( 331 rITA.getX().getVal(), (rITB.getX().getVal() - rITA.getX().getVal()) * xInvDelta, 332 rITA.getY().getVal(), (rITB.getY().getVal() - rITA.getY().getVal()) * xInvDelta, 333 rITA.getZ().getVal(), (rITB.getZ().getVal() - rITA.getZ().getVal()) * xInvDelta); 334 } 335 } 336 337 if(mbUseNrm) 338 { 339 const basegfx::ip_triple& rNA(getNormalInterpolators()[rA.getNormalIndex()]); 340 const basegfx::ip_triple& rNB(getNormalInterpolators()[rB.getNormalIndex()]); 341 maIntNormal = basegfx::ip_triple( 342 rNA.getX().getVal(), (rNB.getX().getVal() - rNA.getX().getVal()) * xInvDelta, 343 rNA.getY().getVal(), (rNB.getY().getVal() - rNA.getY().getVal()) * xInvDelta, 344 rNA.getZ().getVal(), (rNB.getZ().getVal() - rNA.getZ().getVal()) * xInvDelta); 345 } 346 347 if(mbUseCol) 348 { 349 const basegfx::ip_triple& rCA(getColorInterpolators()[rA.getColorIndex()]); 350 const basegfx::ip_triple& rCB(getColorInterpolators()[rB.getColorIndex()]); 351 maIntColor = basegfx::ip_triple( 352 rCA.getX().getVal(), (rCB.getX().getVal() - rCA.getX().getVal()) * xInvDelta, 353 rCA.getY().getVal(), (rCB.getY().getVal() - rCA.getY().getVal()) * xInvDelta, 354 rCA.getZ().getVal(), (rCB.getZ().getVal() - rCA.getZ().getVal()) * xInvDelta); 355 } 356 } 357 358 virtual void processLineSpan(const basegfx::RasterConversionLineEntry3D& rA, const basegfx::RasterConversionLineEntry3D& rB, sal_Int32 nLine, sal_uInt32 nSpanCount); 359 360 public: 361 ZBufferRasterConverter3D(basegfx::BZPixelRaster& rBuffer, const drawinglayer::processor3d::ZBufferProcessor3D& rProcessor) 362 : basegfx::RasterConverter3D(), 363 mrProcessor(rProcessor), 364 mrBuffer(rBuffer), 365 maIntZ(), 366 maIntColor(), 367 maIntNormal(), 368 maIntTexture(), 369 maIntInvTexture(), 370 mpCurrentMaterial(0), 371 mbModifyColor(false), 372 mbUseTex(false), 373 mbHasTexCoor(false), 374 mbUseNrm(false), 375 mbUseCol(false) 376 {} 377 378 void setCurrentMaterial(const drawinglayer::attribute::MaterialAttribute3D& rMaterial) 379 { 380 mpCurrentMaterial = &rMaterial; 381 } 382 }; 383 384 void ZBufferRasterConverter3D::processLineSpan(const basegfx::RasterConversionLineEntry3D& rA, const basegfx::RasterConversionLineEntry3D& rB, sal_Int32 nLine, sal_uInt32 nSpanCount) 385 { 386 if(!(nSpanCount & 0x0001)) 387 { 388 if(nLine >= 0 && nLine < (sal_Int32)mrBuffer.getHeight()) 389 { 390 sal_uInt32 nXA(::std::min(mrBuffer.getWidth(), (sal_uInt32)::std::max((sal_Int32)0, basegfx::fround(rA.getX().getVal())))); 391 const sal_uInt32 nXB(::std::min(mrBuffer.getWidth(), (sal_uInt32)::std::max((sal_Int32)0, basegfx::fround(rB.getX().getVal())))); 392 393 if(nXA < nXB) 394 { 395 // prepare the span interpolators 396 setupLineSpanInterpolators(rA, rB); 397 398 // bring span interpolators to start condition by incrementing with the possible difference of 399 // clamped and non-clamped XStart. Interpolators are setup relying on double precision 400 // X-values, so that difference is the correct value to compensate for possible clampings 401 incrementLineSpanInterpolators(static_cast<double>(nXA) - rA.getX().getVal()); 402 403 // prepare scanline index 404 sal_uInt32 nScanlineIndex(mrBuffer.getIndexFromXY(nXA, static_cast<sal_uInt32>(nLine))); 405 basegfx::BColor aNewColor; 406 407 while(nXA < nXB) 408 { 409 // early-test Z values if we need to do anything at all 410 const double fNewZ(::std::max(0.0, ::std::min((double)0xffff, maIntZ.getVal()))); 411 const sal_uInt16 nNewZ(static_cast< sal_uInt16 >(fNewZ)); 412 sal_uInt16& rOldZ(mrBuffer.getZ(nScanlineIndex)); 413 414 if(nNewZ > rOldZ) 415 { 416 // detect color and opacity for this pixel 417 const sal_uInt16 nOpacity(::std::max((sal_Int16)0, static_cast< sal_Int16 >(decideColorAndOpacity(aNewColor) * 255.0))); 418 419 if(nOpacity > 0) 420 { 421 // avoid color overrun 422 aNewColor.clamp(); 423 424 if(nOpacity >= 0x00ff) 425 { 426 // full opacity (not transparent), set z and color 427 rOldZ = nNewZ; 428 mrBuffer.getBPixel(nScanlineIndex) = basegfx::BPixel(aNewColor, 0xff); 429 } 430 else 431 { 432 basegfx::BPixel& rDest = mrBuffer.getBPixel(nScanlineIndex); 433 434 if(rDest.getOpacity()) 435 { 436 // mix new color by using 437 // color' = color * (1 - opacity) + newcolor * opacity 438 const sal_uInt16 nTransparence(0x0100 - nOpacity); 439 rDest.setRed((sal_uInt8)(((rDest.getRed() * nTransparence) + ((sal_uInt16)(255.0 * aNewColor.getRed()) * nOpacity)) >> 8)); 440 rDest.setGreen((sal_uInt8)(((rDest.getGreen() * nTransparence) + ((sal_uInt16)(255.0 * aNewColor.getGreen()) * nOpacity)) >> 8)); 441 rDest.setBlue((sal_uInt8)(((rDest.getBlue() * nTransparence) + ((sal_uInt16)(255.0 * aNewColor.getBlue()) * nOpacity)) >> 8)); 442 443 if(0xff != rDest.getOpacity()) 444 { 445 // both are transparent, mix new opacity by using 446 // opacity = newopacity * (1 - oldopacity) + oldopacity 447 rDest.setOpacity(((sal_uInt8)((nOpacity * (0x0100 - rDest.getOpacity())) >> 8)) + rDest.getOpacity()); 448 } 449 } 450 else 451 { 452 // dest is unused, set color 453 rDest = basegfx::BPixel(aNewColor, (sal_uInt8)nOpacity); 454 } 455 } 456 } 457 } 458 459 // increments 460 nScanlineIndex++; 461 nXA++; 462 incrementLineSpanInterpolators(1.0); 463 } 464 } 465 } 466 } 467 } 468 469 ////////////////////////////////////////////////////////////////////////////// 470 // helper class to buffer output for transparent rasterprimitives (filled areas 471 // and lines) until the end of processing. To ensure correct transparent 472 // visualisation, ZBuffers require to not set Z and to mix with the transparent 473 // color. If transparent rasterprimitives overlap, it gets necessary to 474 // paint transparent rasterprimitives from back to front to ensure that the 475 // mixing happens from back to front. For that purpose, transparent 476 // rasterprimitives are held in this class during the processing run, remember 477 // all data and will be rendered 478 479 class RasterPrimitive3D 480 { 481 private: 482 boost::shared_ptr< drawinglayer::texture::GeoTexSvx > mpGeoTexSvx; 483 boost::shared_ptr< drawinglayer::texture::GeoTexSvx > mpTransparenceGeoTexSvx; 484 drawinglayer::attribute::MaterialAttribute3D maMaterial; 485 basegfx::B3DPolyPolygon maPolyPolygon; 486 double mfCenterZ; 487 488 // bitfield 489 bool mbModulate : 1; 490 bool mbFilter : 1; 491 bool mbSimpleTextureActive : 1; 492 bool mbIsLine : 1; 493 494 public: 495 RasterPrimitive3D( 496 const boost::shared_ptr< drawinglayer::texture::GeoTexSvx >& pGeoTexSvx, 497 const boost::shared_ptr< drawinglayer::texture::GeoTexSvx >& pTransparenceGeoTexSvx, 498 const drawinglayer::attribute::MaterialAttribute3D& rMaterial, 499 const basegfx::B3DPolyPolygon& rPolyPolygon, 500 bool bModulate, 501 bool bFilter, 502 bool bSimpleTextureActive, 503 bool bIsLine) 504 : mpGeoTexSvx(pGeoTexSvx), 505 mpTransparenceGeoTexSvx(pTransparenceGeoTexSvx), 506 maMaterial(rMaterial), 507 maPolyPolygon(rPolyPolygon), 508 mfCenterZ(basegfx::tools::getRange(rPolyPolygon).getCenter().getZ()), 509 mbModulate(bModulate), 510 mbFilter(bFilter), 511 mbSimpleTextureActive(bSimpleTextureActive), 512 mbIsLine(bIsLine) 513 { 514 } 515 516 RasterPrimitive3D& operator=(const RasterPrimitive3D& rComp) 517 { 518 mpGeoTexSvx = rComp.mpGeoTexSvx; 519 mpTransparenceGeoTexSvx = rComp.mpTransparenceGeoTexSvx; 520 maMaterial = rComp.maMaterial; 521 maPolyPolygon = rComp.maPolyPolygon; 522 mfCenterZ = rComp.mfCenterZ; 523 mbModulate = rComp.mbModulate; 524 mbFilter = rComp.mbFilter; 525 mbSimpleTextureActive = rComp.mbSimpleTextureActive; 526 mbIsLine = rComp.mbIsLine; 527 528 return *this; 529 } 530 531 bool operator<(const RasterPrimitive3D& rComp) const 532 { 533 return mfCenterZ < rComp.mfCenterZ; 534 } 535 536 const boost::shared_ptr< drawinglayer::texture::GeoTexSvx >& getGeoTexSvx() const { return mpGeoTexSvx; } 537 const boost::shared_ptr< drawinglayer::texture::GeoTexSvx >& getTransparenceGeoTexSvx() const { return mpTransparenceGeoTexSvx; } 538 const drawinglayer::attribute::MaterialAttribute3D& getMaterial() const { return maMaterial; } 539 const basegfx::B3DPolyPolygon& getPolyPolygon() const { return maPolyPolygon; } 540 bool getModulate() const { return mbModulate; } 541 bool getFilter() const { return mbFilter; } 542 bool getSimpleTextureActive() const { return mbSimpleTextureActive; } 543 bool getIsLine() const { return mbIsLine; } 544 }; 545 546 ////////////////////////////////////////////////////////////////////////////// 547 548 namespace drawinglayer 549 { 550 namespace processor3d 551 { 552 void ZBufferProcessor3D::rasterconvertB3DPolygon(const attribute::MaterialAttribute3D& rMaterial, const basegfx::B3DPolygon& rHairline) const 553 { 554 if(mpBZPixelRaster) 555 { 556 if(getTransparenceCounter()) 557 { 558 // transparent output; record for later sorting and painting from 559 // back to front 560 if(!mpRasterPrimitive3Ds) 561 { 562 const_cast< ZBufferProcessor3D* >(this)->mpRasterPrimitive3Ds = new std::vector< RasterPrimitive3D >; 563 } 564 565 mpRasterPrimitive3Ds->push_back(RasterPrimitive3D( 566 getGeoTexSvx(), 567 getTransparenceGeoTexSvx(), 568 rMaterial, 569 basegfx::B3DPolyPolygon(rHairline), 570 getModulate(), 571 getFilter(), 572 getSimpleTextureActive(), 573 true)); 574 } 575 else 576 { 577 // do rasterconversion 578 mpZBufferRasterConverter3D->setCurrentMaterial(rMaterial); 579 580 if(mnAntiAlialize > 1) 581 { 582 const bool bForceLineSnap(getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete()); 583 584 if(bForceLineSnap) 585 { 586 basegfx::B3DHomMatrix aTransform; 587 basegfx::B3DPolygon aSnappedHairline(rHairline); 588 const double fScaleDown(1.0 / mnAntiAlialize); 589 const double fScaleUp(mnAntiAlialize); 590 591 // take oversampling out 592 aTransform.scale(fScaleDown, fScaleDown, 1.0); 593 aSnappedHairline.transform(aTransform); 594 595 // snap to integer 596 aSnappedHairline = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aSnappedHairline); 597 598 // add oversampling again 599 aTransform.identity(); 600 aTransform.scale(fScaleUp, fScaleUp, 1.0); 601 602 if(false) 603 { 604 // when really want to go to single pixel lines, move to center. 605 // Without this translation, all hor/ver hairlines will be centered exactly 606 // between two pixel lines (which looks best) 607 const double fTranslateToCenter(mnAntiAlialize * 0.5); 608 aTransform.translate(fTranslateToCenter, fTranslateToCenter, 0.0); 609 } 610 611 aSnappedHairline.transform(aTransform); 612 613 mpZBufferRasterConverter3D->rasterconvertB3DPolygon(aSnappedHairline, 0, mpBZPixelRaster->getHeight(), mnAntiAlialize); 614 } 615 else 616 { 617 mpZBufferRasterConverter3D->rasterconvertB3DPolygon(rHairline, 0, mpBZPixelRaster->getHeight(), mnAntiAlialize); 618 } 619 } 620 else 621 { 622 mpZBufferRasterConverter3D->rasterconvertB3DPolygon(rHairline, 0, mpBZPixelRaster->getHeight(), 1); 623 } 624 } 625 } 626 } 627 628 void ZBufferProcessor3D::rasterconvertB3DPolyPolygon(const attribute::MaterialAttribute3D& rMaterial, const basegfx::B3DPolyPolygon& rFill) const 629 { 630 if(mpBZPixelRaster) 631 { 632 if(getTransparenceCounter()) 633 { 634 // transparent output; record for later sorting and painting from 635 // back to front 636 if(!mpRasterPrimitive3Ds) 637 { 638 const_cast< ZBufferProcessor3D* >(this)->mpRasterPrimitive3Ds = new std::vector< RasterPrimitive3D >; 639 } 640 641 mpRasterPrimitive3Ds->push_back(RasterPrimitive3D( 642 getGeoTexSvx(), 643 getTransparenceGeoTexSvx(), 644 rMaterial, 645 rFill, 646 getModulate(), 647 getFilter(), 648 getSimpleTextureActive(), 649 false)); 650 } 651 else 652 { 653 mpZBufferRasterConverter3D->setCurrentMaterial(rMaterial); 654 mpZBufferRasterConverter3D->rasterconvertB3DPolyPolygon(rFill, &maInvEyeToView, 0, mpBZPixelRaster->getHeight()); 655 } 656 } 657 } 658 659 ZBufferProcessor3D::ZBufferProcessor3D( 660 const geometry::ViewInformation3D& rViewInformation3D, 661 const geometry::ViewInformation2D& rViewInformation2D, 662 const attribute::SdrSceneAttribute& rSdrSceneAttribute, 663 const attribute::SdrLightingAttribute& rSdrLightingAttribute, 664 double fSizeX, 665 double fSizeY, 666 const basegfx::B2DRange& rVisiblePart, 667 sal_uInt16 nAntiAlialize) 668 : DefaultProcessor3D(rViewInformation3D, rSdrSceneAttribute, rSdrLightingAttribute), 669 mpBZPixelRaster(0), 670 maInvEyeToView(), 671 mpZBufferRasterConverter3D(0), 672 mnAntiAlialize(nAntiAlialize), 673 mpRasterPrimitive3Ds(0) 674 { 675 // generate ViewSizes 676 const double fFullViewSizeX((rViewInformation2D.getObjectToViewTransformation() * basegfx::B2DVector(fSizeX, 0.0)).getLength()); 677 const double fFullViewSizeY((rViewInformation2D.getObjectToViewTransformation() * basegfx::B2DVector(0.0, fSizeY)).getLength()); 678 const double fViewSizeX(fFullViewSizeX * rVisiblePart.getWidth()); 679 const double fViewSizeY(fFullViewSizeY * rVisiblePart.getHeight()); 680 681 // generate RasterWidth and RasterHeight 682 const sal_uInt32 nRasterWidth((sal_uInt32)basegfx::fround(fViewSizeX) + 1); 683 const sal_uInt32 nRasterHeight((sal_uInt32)basegfx::fround(fViewSizeY) + 1); 684 685 if(nRasterWidth && nRasterHeight) 686 { 687 // create view unit buffer 688 mpBZPixelRaster = new basegfx::BZPixelRaster( 689 mnAntiAlialize ? nRasterWidth * mnAntiAlialize : nRasterWidth, 690 mnAntiAlialize ? nRasterHeight * mnAntiAlialize : nRasterHeight); 691 OSL_ENSURE(mpBZPixelRaster, "ZBufferProcessor3D: Could not allocate basegfx::BZPixelRaster (!)"); 692 693 // create DeviceToView for Z-Buffer renderer since Z is handled 694 // different from standard 3D transformations (Z is mirrored). Also 695 // the transformation includes the step from unit device coordinates 696 // to discrete units ([-1.0 .. 1.0] -> [minDiscrete .. maxDiscrete] 697 698 basegfx::B3DHomMatrix aDeviceToView; 699 700 { 701 // step one: 702 // 703 // bring from [-1.0 .. 1.0] in X,Y and Z to [0.0 .. 1.0]. Also 704 // necessary to 705 // - flip Y due to screen orientation 706 // - flip Z due to Z-Buffer orientation from back to front 707 708 aDeviceToView.scale(0.5, -0.5, -0.5); 709 aDeviceToView.translate(0.5, 0.5, 0.5); 710 } 711 712 { 713 // step two: 714 // 715 // bring from [0.0 .. 1.0] in X,Y and Z to view cordinates 716 // 717 // #i102611# 718 // also: scale Z to [1.5 .. 65534.5]. Normally, a range of [0.0 .. 65535.0] 719 // could be used, but a 'unused' value is needed, so '0' is used what reduces 720 // the range to [1.0 .. 65535.0]. It has also shown that small numerical errors 721 // (smaller as basegfx::fTools::mfSmallValue, which is 0.000000001) happen. 722 // Instead of checking those by basegfx::fTools methods which would cost 723 // runtime, just add another 0.5 tolerance to the start and end of the Z-Buffer 724 // range, thus resulting in [1.5 .. 65534.5] 725 const double fMaxZDepth(65533.0); 726 aDeviceToView.translate(-rVisiblePart.getMinX(), -rVisiblePart.getMinY(), 0.0); 727 728 if(mnAntiAlialize) 729 aDeviceToView.scale(fFullViewSizeX * mnAntiAlialize, fFullViewSizeY * mnAntiAlialize, fMaxZDepth); 730 else 731 aDeviceToView.scale(fFullViewSizeX, fFullViewSizeY, fMaxZDepth); 732 733 aDeviceToView.translate(0.0, 0.0, 1.5); 734 } 735 736 // update local ViewInformation3D with own DeviceToView 737 const geometry::ViewInformation3D aNewViewInformation3D( 738 getViewInformation3D().getObjectTransformation(), 739 getViewInformation3D().getOrientation(), 740 getViewInformation3D().getProjection(), 741 aDeviceToView, 742 getViewInformation3D().getViewTime(), 743 getViewInformation3D().getExtendedInformationSequence()); 744 updateViewInformation(aNewViewInformation3D); 745 746 // prepare inverse EyeToView transformation. This can be done in constructor 747 // since changes in object transformations when processing TransformPrimitive3Ds 748 // do not influence this prepared partial transformation 749 maInvEyeToView = getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection(); 750 maInvEyeToView.invert(); 751 752 // prepare maRasterRange 753 maRasterRange.reset(); 754 maRasterRange.expand(basegfx::B2DPoint(0.0, 0.0)); 755 maRasterRange.expand(basegfx::B2DPoint(mpBZPixelRaster->getWidth(), mpBZPixelRaster->getHeight())); 756 757 // create the raster converter 758 mpZBufferRasterConverter3D = new ZBufferRasterConverter3D(*mpBZPixelRaster, *this); 759 } 760 } 761 762 ZBufferProcessor3D::~ZBufferProcessor3D() 763 { 764 if(mpBZPixelRaster) 765 { 766 delete mpZBufferRasterConverter3D; 767 delete mpBZPixelRaster; 768 } 769 770 if(mpRasterPrimitive3Ds) 771 { 772 OSL_ASSERT("ZBufferProcessor3D: destructed, but there are unrendered transparent geometries. Use ZBufferProcessor3D::finish() to render these (!)"); 773 delete mpRasterPrimitive3Ds; 774 } 775 } 776 777 void ZBufferProcessor3D::finish() 778 { 779 if(mpRasterPrimitive3Ds) 780 { 781 // there are transparent rasterprimitives 782 const sal_uInt32 nSize(mpRasterPrimitive3Ds->size()); 783 784 if(nSize > 1) 785 { 786 // sort them from back to front 787 std::sort(mpRasterPrimitive3Ds->begin(), mpRasterPrimitive3Ds->end()); 788 } 789 790 for(sal_uInt32 a(0); a < nSize; a++) 791 { 792 // paint each one by setting the remembered data and calling 793 // the render method 794 const RasterPrimitive3D& rCandidate = (*mpRasterPrimitive3Ds)[a]; 795 796 mpGeoTexSvx = rCandidate.getGeoTexSvx(); 797 mpTransparenceGeoTexSvx = rCandidate.getTransparenceGeoTexSvx(); 798 mbModulate = rCandidate.getModulate(); 799 mbFilter = rCandidate.getFilter(); 800 mbSimpleTextureActive = rCandidate.getSimpleTextureActive(); 801 802 if(rCandidate.getIsLine()) 803 { 804 rasterconvertB3DPolygon( 805 rCandidate.getMaterial(), 806 rCandidate.getPolyPolygon().getB3DPolygon(0)); 807 } 808 else 809 { 810 rasterconvertB3DPolyPolygon( 811 rCandidate.getMaterial(), 812 rCandidate.getPolyPolygon()); 813 } 814 } 815 816 // delete them to signal the destructor that all is done and 817 // to allow asserting there 818 delete mpRasterPrimitive3Ds; 819 mpRasterPrimitive3Ds = 0; 820 } 821 } 822 823 BitmapEx ZBufferProcessor3D::getBitmapEx() const 824 { 825 if(mpBZPixelRaster) 826 { 827 return BPixelRasterToBitmapEx(*mpBZPixelRaster, mnAntiAlialize); 828 } 829 830 return BitmapEx(); 831 } 832 } // end of namespace processor3d 833 } // end of namespace drawinglayer 834 835 ////////////////////////////////////////////////////////////////////////////// 836 // eof 837