This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/ww3d2/bitmaphandler.h

450 lines
10 KiB
C++

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(_MSC_VER)
#pragma once
#endif
#ifndef BITMAPHANDLER_H
#define BITMAPHANDLER_H
#include "always.h"
#include "ww3dformat.h"
void Bitmap_Assert(bool condition);
class BitmapHandlerClass
{
public:
// Read pixel at given address
WWINLINE static void Read_B8G8R8A8(
unsigned char* argb,
const unsigned char* src_ptr,
WW3DFormat src_format,
const unsigned char* palette,
unsigned palette_bpp);
// Read pixel at given address
WWINLINE static void Read_B8G8R8A8(
unsigned& argb,
const unsigned char* src_ptr,
WW3DFormat src_format,
const unsigned char* palette,
unsigned palette_bpp);
// Read pixel from surface
WWINLINE static void Read_B8G8R8A8(
unsigned& argb,
const unsigned char* src_ptr,
WW3DFormat src_format,
int x,
int y,
int width,
int height,
const unsigned char* palette,
unsigned palette_bpp);
WWINLINE static void Write_B8G8R8A8(
unsigned char* dest_ptr,
WW3DFormat dest_format,
const unsigned char* argb);
WWINLINE static void Write_B8G8R8A8(
unsigned char* dest_ptr,
WW3DFormat dest_format,
const unsigned& argb);
WWINLINE static void Copy_Pixel(
unsigned char* dest_ptr,
WW3DFormat dest_format,
const unsigned char* src_ptr,
WW3DFormat src_format,
const unsigned char* palette,
unsigned palette_bpp);
WWINLINE static unsigned Combine_A8R8G8B8(
unsigned bgra1,
unsigned bgra2,
unsigned bgra3,
unsigned bgra4);
static void Create_Mipmap_B8G8R8A8(
unsigned char* dest_surface,
unsigned dest_surface_pitch,
unsigned char* src_surface,
unsigned src_surface_pitch,
unsigned width,
unsigned height);
static void Copy_Image_Generate_Mipmap(
unsigned width,
unsigned height,
unsigned char* dest_surface,
unsigned dest_pitch,
WW3DFormat dest_format,
unsigned char* src_surface,
unsigned src_pitch,
WW3DFormat src_format,
unsigned char* mip_surface,
unsigned mip_pitch);
static void Copy_Image(
unsigned char* dest_surface,
unsigned dest_surface_width,
unsigned dest_surface_height,
unsigned dest_surface_pitch,
WW3DFormat dest_surface_format,
unsigned char* src_surface,
unsigned src_surface_width,
unsigned src_surface_height,
unsigned src_surface_pitch,
WW3DFormat src_surface_format,
const unsigned char* src_palette,
unsigned src_palette_bpp,
bool generate_mip_level);
};
// ----------------------------------------------------------------------------
//
// Read color value of given type in BGRA (D3D) byte order. Regarless
// of the source format the color value is converted to 32-bit format.
//
// ----------------------------------------------------------------------------
WWINLINE void BitmapHandlerClass::Read_B8G8R8A8(
unsigned char* argb,
const unsigned char* src_ptr,
WW3DFormat src_format,
const unsigned char* palette,
unsigned palette_bpp)
{
switch (src_format) {
case WW3D_FORMAT_A8R8G8B8:
case WW3D_FORMAT_X8R8G8B8:
*(unsigned*)argb=*(unsigned*)src_ptr;
break;
case WW3D_FORMAT_R8G8B8:
*argb++=src_ptr[0];
*argb++=src_ptr[1];
*argb++=src_ptr[2];
*argb++=0xff;
break;
case WW3D_FORMAT_A4R4G4B4:
{
unsigned short tmp;
tmp=*(unsigned short*)src_ptr;
*argb++=((tmp&0x000f)<<4);
*argb++=((tmp&0x00f0));
*argb++=((tmp&0x0f00)>>4);
*argb++=((tmp&0xf000)>>8);
}
break;
case WW3D_FORMAT_A1R5G5B5:
{
unsigned short tmp;
tmp=*(unsigned short*)src_ptr;
argb[3]=tmp&0x8000 ? 0xff : 0x0;
argb[2]=(tmp>>7)&0xf8;
argb[1]=(tmp>>2)&0xf8;
argb[0]=(tmp<<3)&0xf8;
}
break;
case WW3D_FORMAT_R5G6B5:
{
unsigned short tmp;
tmp=*(unsigned short*)src_ptr;
argb[3]=0xff;
argb[2]=(tmp>>8)&0xf8;
argb[1]=(tmp>>3)&0xfc;
argb[0]=(tmp<<3)&0xf8;
}
break;
case WW3D_FORMAT_R3G3B2:
{
unsigned char tmp=*src_ptr;
argb[3]=0xff;
argb[2]=tmp&0xe0;
argb[1]=(tmp<<3)&0xe0;
argb[0]=(tmp<<6)&0xc0;
}
break;
case WW3D_FORMAT_L8:
{
unsigned char tmp=*src_ptr++;
*argb++=tmp;
*argb++=tmp;
*argb++=tmp;
*argb++=0xff;
}
break;
case WW3D_FORMAT_A8:
{
*argb++=0;
*argb++=0;
*argb++=0;
*argb++=*src_ptr++;
}
break;
case WW3D_FORMAT_P8:
{
unsigned char index=*src_ptr++;
switch (palette_bpp) {
case 4:
*argb++=palette[palette_bpp*index+3];
*argb++=palette[palette_bpp*index+2];
*argb++=palette[palette_bpp*index+1];
*argb++=palette[palette_bpp*index+0];
break;
case 3:
*argb++=palette[palette_bpp*index+2];
*argb++=palette[palette_bpp*index+1];
*argb++=palette[palette_bpp*index+0];
*argb++=0xff;
break;
case 2:
case 1:
default:
Bitmap_Assert(0);
break;
}
}
break;
case WW3D_FORMAT_DXT1:
case WW3D_FORMAT_DXT2:
case WW3D_FORMAT_DXT3:
case WW3D_FORMAT_DXT4:
case WW3D_FORMAT_DXT5:
default: Bitmap_Assert(0); break;
}
}
WWINLINE void BitmapHandlerClass::Read_B8G8R8A8(
unsigned& argb,
const unsigned char* src_ptr,
WW3DFormat src_format,
const unsigned char* palette,
unsigned palette_bpp)
{
Read_B8G8R8A8((unsigned char*)&argb,src_ptr,src_format,palette,palette_bpp);
}
// Read pixel from surface
WWINLINE void BitmapHandlerClass::Read_B8G8R8A8(
unsigned& argb,
const unsigned char* src_ptr,
WW3DFormat src_format,
int x,
int y,
int width,
int height,
const unsigned char* palette,
unsigned palette_bpp)
{
if (x<0 || y<0 || x>=width || y>=height) {
argb=0;
return;
}
unsigned bpp=Get_Bytes_Per_Pixel(src_format);
Read_B8G8R8A8(
argb,
src_ptr+bpp*x+width*bpp*y,
src_format,
palette,
palette_bpp);
}
// ----------------------------------------------------------------------------
//
// Write color value of given type in BGRA (D3D) byte order. The source value
// is always 32 bit and it is converted to defined destination format.
//
// ----------------------------------------------------------------------------
WWINLINE void BitmapHandlerClass::Write_B8G8R8A8(
unsigned char* dest_ptr,
WW3DFormat dest_format,
const unsigned char* argb)
{
switch (dest_format) {
case WW3D_FORMAT_A8R8G8B8:
case WW3D_FORMAT_X8R8G8B8:
*(unsigned*)dest_ptr=*(unsigned*)argb;
break;
case WW3D_FORMAT_R8G8B8:
*dest_ptr++=*argb++;
*dest_ptr++=*argb++;
*dest_ptr++=*argb++;
break;
case WW3D_FORMAT_A4R4G4B4:
{
unsigned short tmp;
tmp=((argb[3])&0xf0)<<8;
tmp|=((argb[2])&0xf0)<<4;
tmp|=((argb[1])&0xf0);
tmp|=((argb[0])&0xf0)>>4;
*(unsigned short*)dest_ptr=tmp;
}
break;
case WW3D_FORMAT_A1R5G5B5:
{
unsigned short tmp;
tmp=argb[3] ? 0x8000 : 0x0;
tmp|=((argb[2])&0xf8)<<7;
tmp|=((argb[1])&0xf8)<<2;
tmp|=((argb[0])&0xf8)>>3;
*(unsigned short*)dest_ptr=tmp;
}
break;
case WW3D_FORMAT_R5G6B5:
{
unsigned short tmp;
tmp=((argb[2])&0xf8)<<8;
tmp|=((argb[1])&0xfc)<<3;
tmp|=((argb[0])&0xf8)>>3;
*(unsigned short*)dest_ptr=tmp;
}
break;
case WW3D_FORMAT_R3G3B2:
{
unsigned char tmp;
tmp=((argb[2])&0xe0);
tmp|=((argb[1])&0xe0)>>3;
tmp|=((argb[0])&0xc0)>>6;
*(unsigned short*)dest_ptr=tmp;
}
break;
case WW3D_FORMAT_L8:
{
// CIE Req. 709: Y709 = 0.2125R + 0.7154G + 0.0721B
unsigned char tmp = (unsigned char) ( (
((unsigned int)argb[0] * (unsigned int)0x1275) + // 0.0721B
((unsigned int)argb[1] * (unsigned int)0xB725) + // 0.7154G (rounded up so FF, FF, FF becomes FF)
((unsigned int)argb[2] * (unsigned int)0x3666) // 0.2125R
) >> 16);
*dest_ptr++=tmp;
}
break;
case WW3D_FORMAT_A8:
{
*dest_ptr++=*argb++;
}
break;
case WW3D_FORMAT_DXT1:
case WW3D_FORMAT_DXT2:
case WW3D_FORMAT_DXT3:
case WW3D_FORMAT_DXT4:
case WW3D_FORMAT_DXT5:
case WW3D_FORMAT_P8: // Paletted destination not supported
default: Bitmap_Assert(0); break;
}
}
WWINLINE void BitmapHandlerClass::Write_B8G8R8A8(
unsigned char* dest_ptr,
WW3DFormat dest_format,
const unsigned& argb)
{
Write_B8G8R8A8(dest_ptr,dest_format,(unsigned char*)&argb);
}
// ----------------------------------------------------------------------------
//
// Copy pixel. Perform color space conversion if needed. The source and
// destination are always D3D-style BGRA.
//
// ----------------------------------------------------------------------------
WWINLINE void BitmapHandlerClass::Copy_Pixel(
unsigned char* dest_ptr,
WW3DFormat dest_format,
const unsigned char* src_ptr,
WW3DFormat src_format,
const unsigned char* palette,
unsigned palette_bpp)
{
// Color space conversion needed?
if (dest_format==src_format) {
switch (dest_format) {
case WW3D_FORMAT_A8R8G8B8:
case WW3D_FORMAT_X8R8G8B8:
*(unsigned*)dest_ptr=*(unsigned*)src_ptr;
break;
case WW3D_FORMAT_R8G8B8:
*dest_ptr++=src_ptr[0];
*dest_ptr++=src_ptr[1];
*dest_ptr++=src_ptr[2];
break;
case WW3D_FORMAT_A4R4G4B4:
{
unsigned short tmp=*(unsigned short*)src_ptr;
*(unsigned short*)dest_ptr=((tmp&0x000f)<<12)|((tmp&0x00f0)<<4)|((tmp&0x0f00)>>4)|((tmp&0xf000)>>12);
}
break;
case WW3D_FORMAT_A1R5G5B5:
{
unsigned short tmp=*(unsigned short*)src_ptr;
*(unsigned short*)dest_ptr=((tmp&0x001f)<<11)|((tmp&0x03e0)<<1)|((tmp&0x7c00)>>9)|((tmp&0x8000)>>15);
}
break;
case WW3D_FORMAT_R5G6B5:
{
unsigned short tmp=*(unsigned short*)src_ptr;
*(unsigned short*)dest_ptr=((tmp&0x001f)<<11)|(tmp&0x07e0)|((tmp&0xf800)>>11);
}
break;
case WW3D_FORMAT_R3G3B2:
case WW3D_FORMAT_L8:
case WW3D_FORMAT_A8: *dest_ptr++=*src_ptr++;
break;
case WW3D_FORMAT_P8: // Paletted destinations not supported
default: Bitmap_Assert(0); break;
}
}
else {
unsigned b8g8r8a8;
Read_B8G8R8A8(b8g8r8a8,src_ptr,src_format,palette,palette_bpp);
Write_B8G8R8A8(dest_ptr,dest_format,b8g8r8a8);
}
}
WWINLINE unsigned BitmapHandlerClass::Combine_A8R8G8B8(
unsigned bgra1,
unsigned bgra2,
unsigned bgra3,
unsigned bgra4)
{
bgra1&=0xfcfcfcfc;
bgra2&=0xfcfcfcfc;
bgra3&=0xfcfcfcfc;
bgra4&=0xfcfcfcfc;
bgra1>>=2;
bgra2>>=2;
bgra3>>=2;
bgra4>>=2;
bgra1+=bgra2;
bgra3+=bgra4;
bgra1+=bgra3;
return bgra1;
}
#endif