uint32_t* SingleOpenGLWindowImplT::GetFrameBuffer(unsigned int& Width_, unsigned int& Height_) { static ArrayT<uint32_t> FrameBuffer; FrameBuffer.Overwrite(); FrameBuffer.PushBackEmpty(Width*Height); // Pixel vom BackBuffer in den FrameBuffer lesen. // Beachte: Die ersten beiden Parameter (0, 0) spezifizieren die linke UNTERE Ecke des gewünschten Bereichs! glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, &FrameBuffer[0]); Width_ =Width; Height_=Height; // Wie oben schon erwähnt, steht der 'FrameBuffer' leider auf dem Kopf. // Vertausche daher alle Zeilen (vertikale Spiegelung). for (unsigned int y=0; y<Height_/2; y++) { uint32_t* UpperRow=&FrameBuffer[0]+ y *Width_; uint32_t* LowerRow=&FrameBuffer[0]+(Height_-y-1)*Width_; for (unsigned int x=0; x<Width_; x++) { const uint32_t Swap=*UpperRow; *UpperRow=*LowerRow; *LowerRow=Swap; UpperRow++; LowerRow++; } } return &FrameBuffer[0]; }
ArrayT<uint8_t> StateT::GetDeltaMessage(const StateT& Other, bool Compress) const { // Delta-compress the data. static ArrayT<uint8_t> DeltaData; DeltaData.Overwrite(); for (unsigned int i = 0; i < m_Data.Size(); i++) DeltaData.PushBack(m_Data[i] ^ (i < Other.m_Data.Size() ? Other.m_Data[i] : 0)); // Optionally RLE-compress the data, then write the delta message. ArrayT<uint8_t> DeltaMessage; if (Compress) { DeltaMessage.PushBack(1); PackBits(DeltaMessage, &DeltaData[0], DeltaData.Size()); #ifdef DEBUG // Make sure that unpacking yields the original data. ArrayT<uint8_t> Check; UnpackBits(Check, &DeltaMessage[1], DeltaMessage.Size()-1); assert(Check == DeltaData); #endif } else { DeltaMessage.PushBack(0); DeltaMessage.PushBack(DeltaData); } #if 0 static std::ofstream Log("compress_log.txt"); Log << "\n" << DeltaData.Size() << " bytes in original delta message\n"; { uLongf DestLen=compressBound(DeltaData.Size()); ArrayT<uint8_t> Dest; Dest.PushBackEmptyExact(DestLen); const int Result=compress2(&Dest[0], &DestLen, &DeltaData[0], DeltaData.Size(), 9); Log << DestLen << " bytes in deflate-compressed message, "; Log << "compression result is " << Result << " (" << (Result == Z_OK ? "Z_OK" : "error") << ")\n"; } { ArrayT<uint8_t> DestRLE; PackBits(DestRLE, &DeltaData[0], DeltaData.Size()); Log << DestRLE.Size() << " bytes in RLE-compressed message.\n"; ArrayT<uint8_t> DestRLE_CHECK; UnpackBits(DestRLE_CHECK, &DestRLE[0], DestRLE.Size()); assert(DestRLE_CHECK == DeltaData); } #endif return DeltaMessage; }
// Diese Funktion bestimmt die Sichtpyramide ('Frustum'), die eine Lichtquelle 'LightSource' durch ein Loch 'Hole' wirft. // // Dabei leuchtet die 'LightSource' in die *entgegengesetzte* Richtung ihres Normalenvektors, // und das 'Hole' läßt auch nur Licht in der Gegenrichtung seines Normalenvektors durch. // Beides ist sinnvoll, denn sowohl 'LightSource' als auch 'Hole' sind idR Portale von Leaves. // Beachte, daß die Normalenvektoren von Portalen stets zur *Mitte* ihrer Leaves hin zeigen (nicht nach außen wie bei Brushes). // Die 'LightSource' ist dann ein Portal des vorangegangenen Leafs, durch das das aktuelle Leaf betreten wird. // Das 'Hole' ist ein Portal des aktuellen Leafs zum nächsten Leaf. // Bemerkung: Würde man das Loch zur Lichtquelle und umgekehrt machen (PolygonMirror), // wäre das Frustum das gleiche, dessen Ebenen wären aber gespiegelt! // // Es wird vorausgesetzt, daß 'LightSource' und 'Hole' gültige Polygone sind. // Wenn daraus erfolgreich ein Frustum konstruiert werden kann, wird dieses zurückgegeben und es gilt 'Frustum.Size()>0'. // Andernfalls scheitert die Funktion und es wird ein Frustum der Größe 0 zurückgegeben ('Frustum.Size()==0'). // Die Voraussetzung für den Erfolg dieser Funktion ist eine - in unserem Sinne - "vernünftige" Anordnung der beiden Polygone: // a) Das 'Hole' muß komplett auf der (Licht emittierenden) Rückseite der 'LightSource'-Ebene liegen. // b) Die 'LightSource' muß komplett auf der (lichtdurchlässigen) Vorderseite der 'Hole'-Ebene liegen. // Beachte, daß im allgemeinen bzw. erweiterten Sinne andere Frustren durchaus auch sinnvoll sein können, // z.B. wenn die 'LightSource' und das 'Hole' sich schneiden. // Solche Fälle betrachten wir jedoch als ungültig und sie führen zum Scheitern der Funktion. inline void FindFrustum(const Polygon3T<double>& LightSource, const Polygon3T<double>& Hole, ArrayT< Plane3T<double> >& Frustum) { Frustum.Overwrite(); if (Hole.WhatSideSimple(LightSource.Plane, MapT::RoundEpsilon)!=Polygon3T<double>::Back) return; if (LightSource.WhatSideSimple(Hole.Plane, MapT::RoundEpsilon)!=Polygon3T<double>::Front) return; unsigned long V2=Hole.Vertices.Size()-1; unsigned long V3; for (V3=0; V3<Hole.Vertices.Size(); V3++) { for (unsigned long V1=0; V1<LightSource.Vertices.Size(); V1++) { // Eigentlich würde ich hier gerne folgenden Wunsch-Code schreiben: // try // { // Plane3T<double> FrustumPlane(Hole.Vertices[V2], LightSource.Vertices[V1], Hole.Vertices[V3]); // // // ... // } // catch (DivisionByZero) { } // Nicht mögliche FrustumPlanes einfach ignorieren. // Aus irgendeinem Grund ist die Verwendung oder das Fangen der DivisionByZero-Exception aber sehr langsam. // Deshalb rolle ich lieber den Plane3T<double>-Konstruktor aus, um ohne dieses Exception-Handling auszukommen. // Das Programm wird *deutlich* schneller, ca. Faktor 1,5. Ob das eine Schwäche des Watcom-Compilers ist?? VectorT Normal(cross(Hole.Vertices[V3]-Hole.Vertices[V2], LightSource.Vertices[V1]-Hole.Vertices[V2])); double NLength=length(Normal); if (NLength<MapT::RoundEpsilon) continue; Normal=scale(Normal, 1.0/NLength); Plane3T<double> FrustumPlane(Normal, dot(Hole.Vertices[V2], Normal)); // Diese neue FrustumPlane nur dann akzeptieren, wenn das Hole auf ihrer Vorderseite liegt // (konstruktionsbedingt sowieso der Fall!) und die LightSource auf ihrer Rückseite liegt. // Wenn eine Edge des Hole in der Ebene der LightSource liegt, darf die LightSource // auch in der FrustumPlane liegen. Polygon3T<double>::SideT Side=LightSource.WhatSideSimple(FrustumPlane, MapT::RoundEpsilon); if (Side==Polygon3T<double>::Back || Side==Polygon3T<double>::InMirrored) { Frustum.PushBack(FrustumPlane); break; } } V2=V3; } // Rollen vertauschen: Das Loch sei nun die Lichtquelle, und die Lichtquelle das Loch! Siehe Skizze! V2=LightSource.Vertices.Size()-1; for (V3=0; V3<LightSource.Vertices.Size(); V3++) { for (unsigned long V1=0; V1<Hole.Vertices.Size(); V1++) // Optimize: Check if edges are in already existing frustum planes! { // Es bringt übrigens nichts, doppelt auftretende Planes hier vermeiden zu wollen! // Messungen waren z.B. 1:09:05 ohne Prüfung, 1:08:42 mit Prüfung auf Doppelvorkommen. // Könnte man aber später nochmal überprüfen... /* // Prüfe, ob wir diese Plane schon im Frustum haben. // Teste dazu, ob die drei Punkte in der Plane liegen. // Die Orientierung braucht dabei nicht beachtet zu werden. for (unsigned long FrustumNr=0; FrustumNr<FrustumSize1stPart; FrustumNr++) { const double Dist1=PlaneDistance(Frustum[FrustumNr], Hole.Vertices[V1]); const double Dist2=PlaneDistance(Frustum[FrustumNr], LightSource.Vertices[V2]); const double Dist3=PlaneDistance(Frustum[FrustumNr], LightSource.Vertices[V3]); if (fabs(Dist1)<0.1 && fabs(Dist2)<0.1 && fabs(Dist3)<0.1) break; } if (FrustumNr<FrustumSize1stPart) continue; */ // Eigentlich würde ich hier gerne folgenden Wunsch-Code schreiben: // try // { // Plane3T<double> FrustumPlane(LightSource.Vertices[V2], Hole.Vertices[V1], LightSource.Vertices[V3]); // // // ... // } // catch (DivisionByZero) { } // Nicht mögliche Ebenen einfach ignorieren. // Aus irgendeinem Grund ist die Verwendung oder das Fangen der DivisionByZero-Exception aber sehr langsam. // Deshalb rolle ich lieber den Plane3T<double>-Konstruktor aus, um ohne dieses Exception-Handling auszukommen. // Das Programm wird *deutlich* schneller, ca. Faktor 1,5. Ob das eine Schwäche des Watcom-Compilers ist?? VectorT Normal(cross(LightSource.Vertices[V3]-LightSource.Vertices[V2], Hole.Vertices[V1]-LightSource.Vertices[V2])); double NLength=length(Normal); if (NLength<MapT::RoundEpsilon) continue; Normal=scale(Normal, 1.0/NLength); Plane3T<double> FrustumPlane(Normal, dot(LightSource.Vertices[V2], Normal)); // Diese neue FrustumPlane nur dann akzeptieren, wenn die LightSource auf ihrer Rückseite // liegt (konstruktionsbedingt sowieso der Fall!) und das Hole auf ihrer Vorderseite liegt. // Wenn eine Edge der LightSource in der Ebene des Holes liegt, darf das Hole // auch in der FrustumPlane liegen. Polygon3T<double>::SideT Side=Hole.WhatSideSimple(FrustumPlane, MapT::RoundEpsilon); // Wegen dem Rollentausch ist die Orientierung für den WhatSideSimple() Test falsch, ... if (Side==Polygon3T<double>::Front || Side==Polygon3T<double>::InMirrored) { Frustum.PushBack(FrustumPlane); // ...im Gesamten aber wieder richtig! break; } } V2=V3; } }