static HCURSOR CreateCompatibleCursor(FTexture *cursorpic) { int picwidth = cursorpic->GetWidth(); int picheight = cursorpic->GetHeight(); // Create bitmap masks for the cursor from the texture. HDC dc = GetDC(NULL); if (dc == NULL) { return nullptr; } HDC and_mask_dc = CreateCompatibleDC(dc); HDC xor_mask_dc = CreateCompatibleDC(dc); HBITMAP and_mask = CreateCompatibleBitmap(dc, 32, 32); HBITMAP xor_mask = CreateCompatibleBitmap(dc, 32, 32); ReleaseDC(NULL, dc); SelectObject(and_mask_dc, and_mask); SelectObject(xor_mask_dc, xor_mask); // Initialize with an invisible cursor. SelectObject(and_mask_dc, GetStockObject(WHITE_PEN)); SelectObject(and_mask_dc, GetStockObject(WHITE_BRUSH)); Rectangle(and_mask_dc, 0, 0, 32, 32); SelectObject(xor_mask_dc, GetStockObject(BLACK_PEN)); SelectObject(xor_mask_dc, GetStockObject(BLACK_BRUSH)); Rectangle(xor_mask_dc, 0, 0, 32, 32); FBitmap bmp; const uint8_t *pixels; bmp.Create(picwidth, picheight); cursorpic->CopyTrueColorPixels(&bmp, 0, 0); pixels = bmp.GetPixels(); // Copy color data from the source texture to the cursor bitmaps. for (int y = 0; y < picheight; ++y) { for (int x = 0; x < picwidth; ++x) { const uint8_t *bgra = &pixels[x*4 + y*bmp.GetPitch()]; if (bgra[3] != 0) { SetPixelV(and_mask_dc, x, y, RGB(0,0,0)); SetPixelV(xor_mask_dc, x, y, RGB(bgra[2], bgra[1], bgra[0])); } } } DeleteDC(and_mask_dc); DeleteDC(xor_mask_dc); // Create the cursor from the bitmaps. return CreateBitmapCursor(cursorpic->LeftOffset, cursorpic->TopOffset, and_mask, xor_mask); }
int FMultiPatchTexture::CopyPixels(FBitmap *bmp, int conversion) { int retv = -1; if (conversion == noremap0) { if (bTextual || !UseGamePalette()) conversion = normal; } for(int i = 0; i < NumParts; i++) { int ret = -1; FCopyInfo info; memset (&info, 0, sizeof(info)); info.alpha = Parts[i].Alpha; info.invalpha = BLENDUNIT - info.alpha; info.op = ECopyOp(Parts[i].op); PalEntry b = Parts[i].Blend; if (b.a == 0 && b != BLEND_NONE) { info.blend = EBlend(b.d); } else if (b.a != 0) { if (b.a == 255) { info.blendcolor[0] = b.r * BLENDUNIT / 255; info.blendcolor[1] = b.g * BLENDUNIT / 255; info.blendcolor[2] = b.b * BLENDUNIT / 255; info.blend = BLEND_MODULATE; } else { blend_t blendalpha = b.a * BLENDUNIT / 255; info.blendcolor[0] = b.r * blendalpha; info.blendcolor[1] = b.g * blendalpha; info.blendcolor[2] = b.b * blendalpha; info.blendcolor[3] = FRACUNIT - blendalpha; info.blend = BLEND_OVERLAY; } } auto trans = Parts[i].Translation ? Parts[i].Translation->Palette : nullptr; FBitmap Pixels = Parts[i].Image->GetCachedBitmap(trans, conversion, &ret); bmp->Blit(Parts[i].OriginX, Parts[i].OriginY, Pixels, Pixels.GetWidth(), Pixels.GetHeight(), Parts[i].Rotate, &info); // treat -1 (i.e. unknown) as absolute. We have no idea if this may have overwritten previous info so a real check needs to be done. if (ret == -1) retv = ret; else if (retv != -1 && ret > retv) retv = ret; } return retv; }
unsigned char * FGLTexture::CreateTexBuffer(int translation, int & w, int & h, FTexture *hirescheck, bool createexpanded, bool alphatrans) { unsigned char * buffer; int W, H; int isTransparent = -1; // Textures that are already scaled in the texture lump will not get replaced // by hires textures if (gl_texture_usehires && hirescheck != NULL && !alphatrans) { buffer = LoadHiresTexture (hirescheck, &w, &h); if (buffer) { return buffer; } } int exx = bExpandFlag && createexpanded; W = w = tex->GetWidth() + 2 * exx; H = h = tex->GetHeight() + 2 * exx; buffer=new unsigned char[W*(H+1)*4]; memset(buffer, 0, W * (H+1) * 4); FGLBitmap bmp(buffer, W*4, W, H); bmp.SetTranslationInfo(translation, alphatrans); if (tex->bComplex) { FBitmap imgCreate; // The texture contains special processing so it must be composited using the // base bitmap class and then be converted as a whole. if (imgCreate.Create(W, H)) { memset(imgCreate.GetPixels(), 0, W * H * 4); int trans = tex->CopyTrueColorPixels(&imgCreate, exx, exx); bmp.CopyPixelDataRGB(0, 0, imgCreate.GetPixels(), W, H, 4, W * 4, 0, CF_BGRA); tex->CheckTrans(buffer, W*H, trans); isTransparent = tex->gl_info.mIsTransparent; if (bIsTransparent == -1) bIsTransparent = isTransparent; } } else if (translation<=0) { int trans = tex->CopyTrueColorPixels(&bmp, exx, exx); tex->CheckTrans(buffer, W*H, trans); isTransparent = tex->gl_info.mIsTransparent; if (bIsTransparent == -1) bIsTransparent = isTransparent; } else { // When using translations everything must be mapped to the base palette. // Since FTexture's method is doing exactly that by calling GetPixels let's use that here // to do all the dirty work for us. ;) tex->FTexture::CopyTrueColorPixels(&bmp, exx, exx); isTransparent = 0; // This is not conclusive for setting the texture's transparency info. } // if we just want the texture for some checks there's no need for upsampling. if (!createexpanded) return buffer; // [BB] The hqnx upsampling (not the scaleN one) destroys partial transparency, don't upsamle textures using it. // [BB] Potentially upsample the buffer. return gl_CreateUpsampledTextureBuffer ( tex, buffer, W, H, w, h, !!isTransparent); }
int FMultiPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) { int retv = -1; if (bRedirect) { // Redirect straight to the real texture's routine. return Parts[0].Texture->CopyTrueColorPixels(bmp, x, y, rotate, inf); } if (rotate != 0 || (inf != NULL && ((inf->op != OP_OVERWRITE && inf->op != OP_COPY) || inf->blend != BLEND_NONE))) { // We are doing some sort of fancy stuff to the destination bitmap, so composite to // a temporary bitmap, and copy that. FBitmap tbmp; if (tbmp.Create(Width, Height)) { retv = MAX(retv, CopyTrueColorPixels(&tbmp, 0, 0, 0)); bmp->CopyPixelDataRGB(x, y, tbmp.GetPixels(), Width, Height, 4, tbmp.GetPitch(), rotate, CF_BGRA, inf); } return retv; } // When compositing a multipatch texture with multipatch parts, // drawing must be restricted to the actual area which is covered by this texture. FClipRect saved_cr = bmp->GetClipRect(); bmp->IntersectClipRect(x, y, Width, Height); if (inf != NULL && inf->op == OP_OVERWRITE) { bmp->Zero(); } for(int i = 0; i < NumParts; i++) { int ret = -1; FCopyInfo info; if (Parts[i].Texture->bHasCanvas) continue; // cannot use camera textures as patch. memset (&info, 0, sizeof(info)); info.alpha = Parts[i].Alpha; info.invalpha = BLENDUNIT - info.alpha; info.op = ECopyOp(Parts[i].op); PalEntry b = Parts[i].Blend; if (b.a == 0 && b != BLEND_NONE) { info.blend = EBlend(b.d); } else if (b.a != 0) { if (b.a == 255) { info.blendcolor[0] = b.r * BLENDUNIT / 255; info.blendcolor[1] = b.g * BLENDUNIT / 255; info.blendcolor[2] = b.b * BLENDUNIT / 255; info.blend = BLEND_MODULATE; } else { blend_t blendalpha = b.a * BLENDUNIT / 255; info.blendcolor[0] = b.r * blendalpha; info.blendcolor[1] = b.g * blendalpha; info.blendcolor[2] = b.b * blendalpha; info.blendcolor[3] = FRACUNIT - blendalpha; info.blend = BLEND_OVERLAY; } } if (Parts[i].Translation != NULL) { // Using a translation forces downconversion to the base palette ret = Parts[i].Texture->CopyTrueColorTranslated(bmp, x+Parts[i].OriginX, y+Parts[i].OriginY, Parts[i].Rotate, Parts[i].Translation->Palette, &info); } else { ret = Parts[i].Texture->CopyTrueColorPixels(bmp, x+Parts[i].OriginX, y+Parts[i].OriginY, Parts[i].Rotate, &info); } // treat -1 (i.e. unknown) as absolute. We have no idea if this may have overwritten previous info so a real check needs to be done. if (ret == -1) retv = ret; else if (retv != -1 && ret > retv) retv = ret; } // Restore previous clipping rectangle. bmp->SetClipRect(saved_cr); return retv; }
TArray<uint8_t> FMultiPatchTexture::CreatePalettedPixels(int conversion) { int numpix = Width * Height; uint8_t blendwork[256]; bool buildrgb = bComplex; TArray<uint8_t> Pixels(numpix, true); memset (Pixels.Data(), 0, numpix); if (conversion == luminance) { // For alpha textures, downconversion to the palette would lose too much precision if not all patches use the palette. buildrgb = !UseGamePalette(); } else { // For regular textures we can use paletted compositing if all patches are just being copied because they all can create a paletted buffer. if (!buildrgb) for (int i = 0; i < NumParts; ++i) { if (Parts[i].op != OP_COPY) { buildrgb = true; } } } if (conversion == noremap0) { // sky remapping will only happen if // - the texture was defined through a TEXTUREx lump (this implies only trivial copies) // - all patches use the base palette. // All other cases would not be able to properly deal with this special case. // For textual definitions this hack isn't necessary. if (bTextual || !UseGamePalette()) conversion = normal; } if (!buildrgb) { for (int i = 0; i < NumParts; ++i) { uint8_t *trans = Parts[i].Translation? Parts[i].Translation->Remap : nullptr; { if (Parts[i].Blend != 0) { trans = GetBlendMap(Parts[i].Blend, blendwork); } CopyToBlock (Pixels.Data(), Width, Height, Parts[i].Image, Parts[i].OriginX, Parts[i].OriginY, Parts[i].Rotate, trans, conversion); } } } else { // In case there are translucent patches let's do the composition in // True color to keep as much precision as possible before downconverting to the palette. FBitmap PixelsIn; PixelsIn.Create(Width, Height); CopyPixels(&PixelsIn, normal); for(int y = 0; y < Height; y++) { uint8_t *in = PixelsIn.GetPixels() + Width * y * 4; uint8_t *out = Pixels.Data() + y; for (int x = 0; x < Width; x++) { if (*out == 0 && in[3] != 0) { *out = ImageHelpers::RGBToPalette(conversion == luminance, in[2], in[1], in[0]); } out += Height; in += 4; } } } return Pixels; }
unsigned char * FGLTexture::CreateTexBuffer(int translation, int & w, int & h, FTexture *hirescheck, bool createexpanded, bool alphatrans) { unsigned char * buffer; int W, H; int isTransparent = -1; // Textures that are already scaled in the texture lump will not get replaced // by hires textures if (gl_texture_usehires && hirescheck != NULL && !alphatrans) { buffer = LoadHiresTexture (hirescheck, &w, &h); if (buffer) { return buffer; } } int exx = bExpandFlag && createexpanded; W = w = tex->GetWidth() + 2 * exx; H = h = tex->GetHeight() + 2 * exx; buffer=new unsigned char[W*(H+1)*4]; memset(buffer, 0, W * (H+1) * 4); FBitmap bmp(buffer, W*4, W, H); if (translation <= 0) { // Q: Is this special treatment still needed? Needs to be checked. if (tex->bComplex) { FBitmap imgCreate; // The texture contains special processing so it must be fully composited before being converted as a whole. if (imgCreate.Create(W, H)) { memset(imgCreate.GetPixels(), 0, W * H * 4); int trans = tex->CopyTrueColorPixels(&imgCreate, exx, exx); bmp.CopyPixelDataRGB(0, 0, imgCreate.GetPixels(), W, H, 4, W * 4, 0, CF_BGRA); tex->CheckTrans(buffer, W*H, trans); isTransparent = tex->gl_info.mIsTransparent; if (bIsTransparent == -1) bIsTransparent = isTransparent; } } else { int trans = tex->CopyTrueColorPixels(&bmp, exx, exx); tex->CheckTrans(buffer, W*H, trans); isTransparent = tex->gl_info.mIsTransparent; if (bIsTransparent == -1) bIsTransparent = isTransparent; } } else { #ifdef __MOBILE__ if( alphatrans ) { //tex->CopyTrueColorRedToAlpha(&bmp, exx, exx);# tex->CopyTrueColorPixels(&bmp, exx, exx); uint32_t* pix = ( uint32_t *)bmp.GetPixels(); uint32_t w = bmp.GetWidth(); uint32_t h = bmp.GetHeight(); uint32_t pit = bmp.GetPitch(); LOGI("%d %d %d",w,h,pit); for(int y = 0; y < h; y++ ) { for(int x = 0; x < w; x++ ) { uint32_t p = *pix; p = (p & 0x00FFFFFF) | ((p & 0x00FF0000) << 8); // Copy red to alpha channel *pix = p; pix++; } } isTransparent = 0; } else #endif { // When using translations everything must be mapped to the base palette. // so use CopyTrueColorTranslated tex->CopyTrueColorTranslated(&bmp, exx, exx, 0, GLTranslationPalette::GetPalette(translation)); isTransparent = 0; // This is not conclusive for setting the texture's transparency info. } } // if we just want the texture for some checks there's no need for upsampling. if (!createexpanded) return buffer; // [BB] The hqnx upsampling (not the scaleN one) destroys partial transparency, don't upsamle textures using it. // [BB] Potentially upsample the buffer. return gl_CreateUpsampledTextureBuffer ( tex, buffer, W, H, w, h, !!isTransparent); }