diff --git a/src/common/Gdc2/GdcCommon.cpp b/src/common/Gdc2/GdcCommon.cpp --- a/src/common/Gdc2/GdcCommon.cpp +++ b/src/common/Gdc2/GdcCommon.cpp @@ -1,1197 +1,1215 @@ #include "lgi/common/Lgi.h" #include "lgi/common/Palette.h" ///////////////////////////////////////////////////////////////////////////// // Mem ops void Add64(ulong *DestH, ulong *DestL, ulong SrcH, ulong SrcL) { *DestH += SrcH + (*DestL & SrcL & 0x80000000) ? 1 : 0; *DestL += SrcL; } void MemSet(void *d, int c, uint s) { if (d && s > 0) memset(d, c, s); } void MemCpy(void *d, void *s, uint l) { if (d && s && l > 0) memcpy(d, s, l); } void MemAnd(void *d, void *s, uint l) { uchar *D = (uchar*) d; uchar *S = (uchar*) s; if (D && S) { for (; l > 0; l--) { *D++ &= *S++; } } } void MemXor(void *d, void *s, uint l) { uchar *D = (uchar*) d; uchar *S = (uchar*) s; if (D && S) { for (; l > 0; l--) { *D++ ^= *S++; } } } void MemOr(void *d, void *s, uint l) { uchar *D = (uchar*) d; uchar *S = (uchar*) s; if (D && S) { for (; l > 0; l--) { *D++ |= *S++; } } } ////////////////////////////////////////////////////////////////////// bool LFindBounds(LSurface *pDC, LRect *rc) { if (!pDC || ! rc) return false; LAssert(pDC->GetColourSpace() == System32BitColourSpace); // Move top border down to image while (rc->y1 < rc->y2) { System32BitPixel *p = (System32BitPixel*)(*pDC)[rc->y1]; if (!p) return false; p += rc->x1; System32BitPixel *e = p + rc->X(); bool IsTrans = true; while (p < e) { if (p->a != 0) { IsTrans = false; break; } p++; } if (IsTrans) rc->y1++; else break; } // Move bottom border up to image while (rc->y2 >= rc->y1) { System32BitPixel *p = (System32BitPixel*)(*pDC)[rc->y2]; if (!p) return false; p += rc->x1; System32BitPixel *e = p + rc->X(); bool IsTrans = true; while (p < e) { if (p->a != 0) { IsTrans = false; break; } p++; } if (IsTrans) rc->y2--; else break; } // Do the left and right edges too int x1 = rc->x2; int x2 = rc->x1; for (int y=rc->y1; y<=rc->y2; y++) { System32BitPixel *p = (System32BitPixel*)(*pDC)[y]; if (!p) return false; System32BitPixel *px1 = p + rc->x1; System32BitPixel *px2 = p + rc->x2; while (px1 < px2 && px1->a == 0) px1++; x1 = MIN(x1, (int) (px1 - p)); while (px2 >= px1 && px2->a == 0) px2--; x2 = MAX(x2, (int) (px2 - p)); } rc->x1 = x1; rc->x2 = x2; if (rc->Valid()) return true; // No data? rc->ZOff(-1, -1); return false; } ////////////////////////////////////////////////////////////////////// // Drawing functions void LDrawBox(LSurface *pDC, LRect &r, bool Sunken, bool Fill) { if (Fill) { pDC->Colour(LColour(L_MED)); pDC->Rectangle(r.x1+1, r.y1+1, r.x2-1, r.y2-1); } pDC->Colour((Sunken) ? LColour(L_LIGHT) : LColour(L_LOW)); pDC->Line(r.x2, r.y2, r.x2, r.y1); pDC->Line(r.x2, r.y2, r.x1, r.y2); pDC->Colour((Sunken) ? LColour(L_LOW) : LColour(L_LIGHT)); pDC->Line(r.x1, r.y1, r.x1, r.y2); pDC->Line(r.x1, r.y1, r.x2, r.y1); } void LWideBorder(LSurface *pDC, LRect &r, LEdge Type) { if (!pDC) return; COLOUR Old = pDC->Colour(); LColour VLow = LColour(L_SHADOW); LColour Low = LColour(L_LOW); LColour High = LColour(L_HIGH); LColour VHigh = LColour(L_LIGHT); switch (Type) { case EdgeXpSunken: { // XP theme pDC->Colour(Low); pDC->Line(r.x1, r.y1, r.x2-1, r.y1); pDC->Line(r.x1, r.y1, r.x1, r.y2-1); pDC->Colour(VLow); pDC->Line(r.x1+1, r.y1+1, r.x2-2, r.y1+1); pDC->Line(r.x1+1, r.y1+1, r.x1+1, r.y2-2); pDC->Colour(High); pDC->Line(r.x2-1, r.y2-1, r.x2-1, r.y1+1); pDC->Line(r.x2-1, r.y2-1, r.x1+1, r.y2-1); pDC->Colour(VHigh); pDC->Line(r.x2, r.y2, r.x2, r.y1); pDC->Line(r.x2, r.y2, r.x1, r.y2); break; } case EdgeXpRaised: { pDC->Colour(VHigh); pDC->Line(r.x1, r.y1, r.x2-1, r.y1); pDC->Line(r.x1, r.y1, r.x1, r.y2-1); pDC->Colour(High); pDC->Line(r.x1+1, r.y1+1, r.x2-1, r.y1+1); pDC->Line(r.x1+1, r.y1+1, r.x1+1, r.y2-1); pDC->Colour(Low); pDC->Line(r.x2-1, r.y2-1, r.x2-1, r.y1+1); pDC->Line(r.x2-1, r.y2-1, r.x1+1, r.y2-1); pDC->Colour(VLow); pDC->Line(r.x2, r.y2, r.x2, r.y1); pDC->Line(r.x2, r.y2, r.x1, r.y2); break; } case EdgeXpChisel: { pDC->Colour(Low); pDC->Line(r.x1, r.y1, r.x2-1, r.y1); pDC->Line(r.x1, r.y1, r.x1, r.y2-1); pDC->Colour(VHigh); pDC->Line(r.x1+1, r.y1+1, r.x2-2, r.y1+1); pDC->Line(r.x1+1, r.y1+1, r.x1+1, r.y2-2); pDC->Colour(Low); pDC->Line(r.x2-1, r.y2-1, r.x2-1, r.y1+1); pDC->Line(r.x2-1, r.y2-1, r.x1+1, r.y2-1); pDC->Colour(VHigh); pDC->Line(r.x2, r.y2, r.x2, r.y1); pDC->Line(r.x2, r.y2, r.x1, r.y2); break; } case EdgeWin7Sunken: case EdgeWin7FocusSunken: { bool Focus = Type == EdgeWin7FocusSunken; // Win7 theme LColour Med(L_MED), Ws(L_WORKSPACE); LColour Mixer = Med.GetGray() >= 128 ? LColour::Black : LColour::White; LColour TopLeft, RightBottom; if (Focus) { LColour Focus(L_FOCUS_SEL_BACK); TopLeft = Med.Mix(Focus, 0.4f); RightBottom = Ws.Mix(Focus, 0.2f); } else { TopLeft = Med.Mix(Mixer, 0.4f); RightBottom = Ws.Mix(Mixer, 0.2f); } // Top corners pDC->Colour(Med); pDC->Set(r.x1, r.y1); pDC->Set(r.x2, r.y1); pDC->Colour(Ws.Mix(TopLeft)); pDC->Set(r.x1+1, r.y1+1); pDC->Set(r.x2-1, r.y1+1); pDC->Set(r.x1+1, r.y2-1); // Edges pDC->Colour(TopLeft); pDC->Line(r.x1, r.y1+1, r.x1, r.y2-1); // left pDC->Line(r.x1+1, r.y1, r.x2-1, r.y1); // top // Bottom edge pDC->Colour(RightBottom); pDC->Line(r.x1+1, r.y2, r.x2-1, r.y2); // bottom pDC->Line(r.x2, r.y1+1, r.x2, r.y2-1); // right // Inner workspace rect pDC->Colour(Ws); pDC->Line(r.x1+2, r.y1+1, r.x2-2, r.y1+1); // top pDC->Line(r.x1+1, r.y1+2, r.x1+1, r.y2-2); // left pDC->Line(r.x2-1, r.y1+2, r.x2-1, r.y2-2); // right pDC->Line(r.x1+2, r.y2-1, r.x2-1, r.y2-1); // bottom break; } default: { return; } } r.Inset(2, 2); pDC->Colour(Old); } void LThinBorder(LSurface *pDC, LRect &r, LEdge Type) { if (!pDC) return; COLOUR Old = pDC->Colour(); switch (Type) { case EdgeXpSunken: case EdgeWin7FocusSunken: case EdgeWin7Sunken: { pDC->Colour(LColour(L_LIGHT)); pDC->Line(r.x2, r.y2, r.x2, r.y1); pDC->Line(r.x2, r.y2, r.x1, r.y2); pDC->Colour(LColour(L_LOW)); pDC->Line(r.x1, r.y1, r.x1, r.y2); pDC->Line(r.x1, r.y1, r.x2, r.y1); r.Inset(1, 1); break; } case EdgeXpRaised: { pDC->Colour(LColour(L_LOW)); pDC->Line(r.x2, r.y2, r.x2, r.y1); pDC->Line(r.x2, r.y2, r.x1, r.y2); pDC->Colour(LColour(L_LIGHT)); pDC->Line(r.x1, r.y1, r.x1, r.y2); pDC->Line(r.x1, r.y1, r.x2, r.y1); r.Inset(1, 1); break; } default: { LAssert(0); break; } } pDC->Colour(Old); } void LFlatBorder(LSurface *pDC, LRect &r, int Width) { pDC->Colour(LColour(L_MED)); if (Width < 1 || r.X() < (2 * Width) || r.Y() < (2 * Width)) { pDC->Rectangle(&r); r.ZOff(-1, -1); } else { pDC->Rectangle(r.x1, r.y1, r.x2, r.y1+Width-1); pDC->Rectangle(r.x1, r.y2-Width+1, r.x2, r.y2); pDC->Rectangle(r.x1, r.y1+Width, r.x1+Width-1, r.y2-Width); pDC->Rectangle(r.x2-Width+1, r.y1+Width, r.x2, r.y2-Width); r.Inset(Width, Width); } } void LFillGradient(LSurface *pDC, LRect &r, bool Vert, LArray &Stops) { int CurStop = 0; LColourStop *This = Stops.Length() > CurStop ? &Stops[CurStop] : 0; CurStop++; LColourStop *Next = Stops.Length() > CurStop ? &Stops[CurStop] : 0; int Limit = Vert ? r.Y() : r.X(); for (int n=0; nPos) { // Just this c = This->Colour; } else if (p > This->Pos && p < Next->Pos) { // Interpolate between this and next float d = Next->Pos - This->Pos; float t = (Next->Pos - p) / d; float n = (p - This->Pos) / d; uint8_t r = (uint8_t) ((This->Colour.r() * t) + (Next->Colour.r() * n)); uint8_t g = (uint8_t) ((This->Colour.g() * t) + (Next->Colour.g() * n)); uint8_t b = (uint8_t) ((This->Colour.b() * t) + (Next->Colour.b() * n)); uint8_t a = (uint8_t) ((This->Colour.a() * t) + (Next->Colour.a() * n)); c.Rgb(r, g, b, a); } else if (p >= Next->Pos) { // Get next colour stops This = Stops.Length() > CurStop ? &Stops[CurStop] : 0; CurStop++; Next = Stops.Length() > CurStop ? &Stops[CurStop] : 0; goto DoStop; } pDC->Colour(c); if (Vert) pDC->Line(r.x1, r.y1 + n, r.x2, r.y1 + n); else pDC->Line(r.x1 + n, r.y1, r.x1 + n, r.y2); } } } ////////////////////////////////////////////////////////////////////////////////// // Other Gdc Stuff LSurface *ConvertDC(LSurface *pDC, int Bits) { LSurface *pNew = new LMemDC; if (pNew && pNew->Create(pDC->X(), pDC->Y(), LBitsToColourSpace(Bits))) { pNew->Blt(0, 0, pDC); DeleteObj(pDC); return pNew; } return pDC; } LColour GdcMixColour(LColour c1, LColour c2, float HowMuchC1) { float HowMuchC2 = 1.0f - HowMuchC1; uint8_t r = (uint8_t) ((c1.r()*HowMuchC1) + (c2.r()*HowMuchC2)); uint8_t g = (uint8_t) ((c1.g()*HowMuchC1) + (c2.g()*HowMuchC2)); uint8_t b = (uint8_t) ((c1.b()*HowMuchC1) + (c2.b()*HowMuchC2)); uint8_t a = (uint8_t) ((c1.a()*HowMuchC1) + (c2.a()*HowMuchC2)); return LColour(r, g, b, a); } COLOUR CBit(int DstBits, COLOUR c, int SrcBits, LPalette *Pal) { if (SrcBits == DstBits) { return c; } else { switch (SrcBits) { case 8: { GdcRGB Grey, *p = 0; if (!Pal || !(p = (*Pal)[c])) { Grey.r = Grey.g = Grey.b = c & 0xFF; p = &Grey; } switch (DstBits) { case 16: { return Rgb16(p->r, p->g, p->b); } case 24: { return Rgb24(p->r, p->g, p->b); } case 32: { return Rgb32(p->r, p->g, p->b); } } break; } case 15: { int R = R15(c); int G = G15(c); int B = B15(c); R = R | (R >> 5); G = G | (G >> 5); B = B | (B >> 5); switch (DstBits) { case 8: { if (Pal) { return Pal->MatchRgb(Rgb24(R, G, B)); } break; } case 16: { return Rgb16(R, G, B); } case 24: { return Rgb24(R, G, B); } case 32: { return Rgb32(R, G, B); } } break; } case 16: { /* int R = ((c>>8)&0xF8) | ((c>>13)&0x7); int G = ((c>>3)&0xFC) | ((c>>9)&0x3); int B = ((c<<3)&0xF8) | ((c>>2)&0x7); */ int R = (c >> 8) & 0xF8; int G = (c >> 3) & 0xFC; int B = (c << 3) & 0xF8; switch (DstBits) { case 8: { if (Pal) { return Pal->MatchRgb(Rgb24(R, G, B)); } break; } case 15: { return Rgb16To15(c); } case 24: { return Rgb24(R, G, B); } case 32: { return Rgb32(R, G, B); } } break; } case 24: { switch (DstBits) { case 8: { if (Pal) { return Pal->MatchRgb(c); } break; } case 15: { return Rgb24To15(c); } case 16: { if (LGetOs() == LGI_OS_WIN32 || LGetOs() == LGI_OS_WIN64) { return Rgb24To16(c); } int r = MAX(R24(c) - 1, 0) >> 3; int g = MAX(G24(c) - 1, 0) >> 2; int b = MAX(B24(c) - 1, 0) >> 3; return (r << 11) | (g << 5) | (b); } case 24: case 48: { return c; } case 32: case 64: { return Rgb24To32(c); } default: LAssert(0); break; } break; } case 32: { switch (DstBits) { case 8: { if (Pal) { return Pal->MatchRgb(Rgb32To24(c)); } break; } case 15: { return Rgb32To15(c); } case 16: { return Rgb32To16(c); } case 24: { return Rgb32To24(c); } } break; } } } return c; } ///////////////////////////////////////////////////////////////////////////// const char *LColourSpaceToString(LColourSpace cs) { #define CS_STR_BUF 4 static int Cur = 0; static char Buf[CS_STR_BUF][16]; static const char *CompTypes[] = { "N", // None "I", // Index "R", // Red "G", // Green "B", // Blue "A", // Alpha "X", // Pad "H", // Hue "S", // Sat "L", // Lum "C", // Cyan "M", // Magenta "Y", // Yellow "B", // Black "?", "?", }; char *start = Buf[Cur++], *s = start; int total = 0; bool first = true; if (Cur >= CS_STR_BUF) Cur = 0; *s++ = 'C'; *s++ = 's'; // printf("Converting Cs to String: 0x%x\n", cs); for (int i=3; i>=0; i--) { int c = (((uint32_t)cs) >> (i << 3)) & 0xff; // printf(" c[%i] = 0x%x\n", i, c); if (c) { LComponentType type = (LComponentType)(c >> 4); int size = c & 0xf; if (first) { *s++ = CompTypes[type][0]; first = false; } else { *s++ = tolower(CompTypes[type][0]); } total += size ? size : 16; } } s += sprintf_s(s, 4, "%i", total); return start; } int LColourSpaceChannels(LColourSpace Cs) { int Channels = 0; while (Cs) { uint8_t c = Cs & 0xff; if (!c) break; Channels++; ((int&)Cs) >>= 8; } return Channels; } bool LColourSpaceHasAlpha(LColourSpace Cs) { while (Cs) { uint8_t c = Cs & 0xff; LComponentType type = (LComponentType)(c >> 4); if (type == CtAlpha) return true; ((int&)Cs) >>= 8; } return false; } int LColourSpaceToBits(LColourSpace ColourSpace) { uint32_t c = ColourSpace; int bits = 0; while (c) { if (c & 0xf0) { int n = c & 0xf; bits += n ? n : 16; } c >>= 8; } return bits; } LColourSpace LStringToColourSpace(const char *c) { if (!c) return CsNone; if (!_strnicmp(c, "Cs", 2)) { // "Cs" style colour space c += 2; const char *n = c; while (*n && !IsDigit(*n)) n++; int Depth = ::atoi(n); if (!_strnicmp(c, "Index", 5)) { if (Depth == 8) return CsIndex8; } else { LArray Comp; while (*c) { switch (tolower(*c)) { case 'r': Comp.Add(CtRed); break; case 'g': Comp.Add(CtGreen); break; case 'b': Comp.Add(CtBlue); break; case 'a': Comp.Add(CtAlpha); break; case 'x': Comp.Add(CtPad); break; case 'c': Comp.Add(CtCyan); break; case 'm': Comp.Add(CtMagenta); break; case 'y': Comp.Add(CtYellow); break; case 'k': Comp.Add(CtBlack); break; case 'h': Comp.Add(CtHue); break; case 'l': Comp.Add(CtLuminance); break; case 's': Comp.Add(CtSaturation); break; } c++; } LColourSpaceBits a; ZeroObj(a); if (Comp.Length() == 3) { a[0].Type(Comp[0]); a[1].Type(Comp[1]); a[2].Type(Comp[2]); if (Depth == 24) { a[0].Size(8); a[1].Size(8); a[2].Size(8); } else if (Depth == 16) { a[0].Size(5); a[1].Size(6); a[2].Size(5); } else if (Depth == 15) { a[0].Size(5); a[0].Size(5); a[0].Size(5); } else if (Depth == 48) { a[0].Size(0); a[1].Size(0); a[2].Size(0); } else return CsNone; } else if (Comp.Length() == 4) { a[0].Type(Comp[0]); a[1].Type(Comp[1]); a[2].Type(Comp[2]); a[3].Type(Comp[3]); if (Depth == 32) { a[0].Size(8); a[1].Size(8); a[2].Size(8); a[3].Size(8); } else if (Depth == 64) { a[0].Size(0); a[1].Size(0); a[2].Size(0); a[3].Size(0); } else return CsNone; } LColourSpace Cs = (LColourSpace)a.All; return Cs; } } else if (!_strnicmp(c, "System", 6)) { // "System" colour space c += 6; int Depth = ::atoi(c); if (Depth) return LBitsToColourSpace(Depth); } return CsNone; } LColourSpace LBitsToColourSpace(int Bits) { switch (Bits) { case 8: return CsIndex8; case 15: return System15BitColourSpace; case 16: return System16BitColourSpace; case 24: return System24BitColourSpace; case 32: return System32BitColourSpace; default: LAssert(!"Unknown colour space."); break; } return CsNone; } bool LColourSpaceTest() { union { uint8_t b4[4]; uint32_t u32; LBgrx32 bgrx32; LXrgb32 xrgb32; LRgba32 rgba32; }; b4[0] = 1; b4[1] = 2; b4[2] = 3; b4[3] = 4; #if 0 // def LGI_SDL printf("LeastSigBit=%i, LeastSigByte=%i, u32=%08x\n", LeastSigBit, LeastSigByte, u32); printf("bgrx32=%i,%i,%i,%i\n", bgrx32.b, bgrx32.g, bgrx32.r, bgrx32.pad); printf("xrgb32=%i,%i,%i,%i\n", xrgb32.pad, xrgb32.r, xrgb32.g, xrgb32.b); #endif if (bgrx32.b != 1 || bgrx32.pad != 4 || xrgb32.pad != 1 || xrgb32.b != 4) { LAssert(!"32bit colour space byte ordering wrong. Flip the value of LEAST_SIG_BYTE_FIRST"); return false; } union { uint16 u16; LRgb16 rgb16; }; rgba32.r = 0xff; rgba32.g = 0; rgba32.b = 0; rgba32.a = 0; u16 = 0xf800; #if 0 // def LGI_SDL printf("rgba32=%i,%i,%i,%i or %08x\n", rgba32.r, rgba32.g, rgba32.b, rgba32.a, u32); printf("rgb16=%i,%i,%i or %04x\n", rgb16.r, rgb16.g, rgb16.b, u16); #endif if (rgb16.r != 0x1f || rgb16.b != 0x0) { LAssert(!"16bit colour space bit ordering wrong. Flip the value of LEAST_SIG_BIT_FIRST"); return false; } return true; } //////////////////////////////////////////////////////////////////////// LSurface *LInlineBmp::Create(uint32_t TransparentPx) { LSurface *pDC = new LMemDC; if (pDC->Create(X, Y, System32BitColourSpace, LSurface::SurfaceRequireExactCs)) { LBmpMem Src, Dst; Src.Base = (uint8_t*)Data; Src.Line = X * Bits >> 3; Src.x = X; Src.y = Y; switch (Bits) { case 8: Src.Cs = CsIndex8; break; case 15: Src.Cs = CsRgb15; break; case 16: Src.Cs = CsRgb16; break; case 24: Src.Cs = CsRgb24; break; case 32: Src.Cs = CsRgba32; break; default: Src.Cs = CsNone; break; } Dst.Base = (*pDC)[0]; Dst.Line = pDC->GetRowStep(); Dst.x = pDC->X(); Dst.y = pDC->Y(); Dst.Cs = pDC->GetColourSpace(); LRopUniversal(&Dst, &Src, false); if (TransparentPx != 0xffffffff) { for (int y=0; y> 3) { case 1: { for (int x=0; xr == r && px->g == g && px->b == b) { *d = 0; } d++; } break; } case 4: { for (int x=0; x %s\n", _FL, LColourSpaceToString(SrcCs), LColourSpaceToString(DstCs)); LAssert(!"Unsupported pixel conversion."); return false; } } return true; } /// Universal bit blt method bool LRopUniversal(LBmpMem *Dst, LBmpMem *Src, bool Composite) { if (!Dst || !Src) return false; // Work out conversion area... int Cx = MIN(Dst->x, Src->x); int Cy = MIN(Dst->y, Src->y); // Size of src and dst pixels: int SrcBits = LColourSpaceToBits(Src->Cs); int DstBits = LColourSpaceToBits(Dst->Cs); if (Dst->Cs == Src->Cs && !Composite) { // No conversion idiom uint8_t *d = Dst->Base; uint8_t *s = Src->Base; int BytesPerPx = (SrcBits + 7) / 8; int Bytes = BytesPerPx * Cx; for (int y=0; yLine; s += Src->Line; } return true; } if (SrcBits > 8 && DstBits > 8) { uint8_t *d = Dst->Base; uint8_t *s = Src->Base; for (int y=0; yCs, s, Src->Cs, Cx, Composite)) return false; d += Dst->Line; s += Src->Line; } return true; } else { } // LAssert(!"Unsupported pixel conversion."); return false; } LPoint LScreenDpi() { + static LPoint Dpi; + #if LGI_COCOA - static LPoint Dpi; if (!Dpi.x) { NSScreen *screen = [NSScreen mainScreen]; NSDictionary *description = [screen deviceDescription]; NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue]; CGSize displayPhysicalSize = CGDisplayScreenSize( [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); Dpi.x = (int) ((displayPixelSize.width / displayPhysicalSize.width) * 25.4f); Dpi.y = (int) ((displayPixelSize.height / displayPhysicalSize.height) * 25.4f); } #elif defined(__GTK_H__) - static LPoint Dpi; if (!Dpi.x) { auto dpi = Gtk::gdk_screen_get_resolution(Gtk::gdk_screen_get_default()); if (dpi > 0) Dpi.Set((int)dpi, (int)dpi); - if (Dpi.x <= 0) - Dpi.Set(96, 96); } - #else + #elif defined(HAIKU) + + if (!Dpi.x) + { + BScreen screen(Window()); + monitor_info info; + if (screen.GetMonitorInfo(&info) == B_OK) + { + Dpi.x = info.width / 2.54; + Dpi.y = info.height / 2.54; + } + } - static LPoint Dpi(96, 96); // A reasonable default. - + #elif defined(WINDOWS) + + if (!Dpi.x) + { + auto dpi = GetDpiForWindow(GetDesktopWindow()); + Dpi.Set(dpi, dpi); + } + #endif + if (Dpi.x <= 0) + Dpi.Set(96, 96); + return Dpi; } bool LMemDC::SwapRedAndBlue() { switch (GetColourSpace()) { #define ROP(cs) \ case Cs##cs: \ { \ for (int y=0; yr, p->b); \ p++; \ } \ break; \ } \ break; \ } ROP(Rgb24) ROP(Bgr24) ROP(Rgbx32) ROP(Bgrx32) ROP(Xrgb32) ROP(Xbgr32) ROP(Argb32) ROP(Abgr32) ROP(Rgba32) ROP(Bgra32) default: return false; } return true; }