2025-11-28 00:35:46 +09:00

321 lines
9.0 KiB
C++

//////////////////////////////////////////////////////////////////////
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <d3d9.h>
#include "video.h"
//-------------------------------------------------------------------
// DrawColorBars
//
// Draw SMPTE colors bars to a Direct3D surface.
// The surface format is assumed to be YUY2.
//-------------------------------------------------------------------
HRESULT DrawColorBars(IDirect3DSurface9 *pSurf, UINT width, UINT height)
{
HRESULT hr;
// Draw the main stream (SMPTE color bars).
D3DLOCKED_RECT lr;
hr = pSurf->LockRect(&lr, NULL, D3DLOCK_NOSYSLOCK);
if (FAILED(hr))
{
return hr;
}
// YUY2 is two pixels per DWORD.
const UINT dx = width / 2;
// First row stripes.
const UINT y1 = height * 2 / 3;
FillRectangle(lr, dx * 0 / 7, 0, dx * 1 / 7, y1, RGBtoYUY2(RGB_WHITE_75pc));
FillRectangle(lr, dx * 1 / 7, 0, dx * 2 / 7, y1, RGBtoYUY2(RGB_YELLOW_75pc));
FillRectangle(lr, dx * 2 / 7, 0, dx * 3 / 7, y1, RGBtoYUY2(RGB_CYAN_75pc));
FillRectangle(lr, dx * 3 / 7, 0, dx * 4 / 7, y1, RGBtoYUY2(RGB_GREEN_75pc));
FillRectangle(lr, dx * 4 / 7, 0, dx * 5 / 7, y1, RGBtoYUY2(RGB_MAGENTA_75pc));
FillRectangle(lr, dx * 5 / 7, 0, dx * 6 / 7, y1, RGBtoYUY2(RGB_RED_75pc));
FillRectangle(lr, dx * 6 / 7, 0, dx * 7 / 7, y1, RGBtoYUY2(RGB_BLUE_75pc));
// Second row stripes.
const UINT y2 = height * 3 / 4;
FillRectangle(lr, dx * 0 / 7, y1, dx * 1 / 7, y2, RGBtoYUY2(RGB_BLUE_75pc));
FillRectangle(lr, dx * 1 / 7, y1, dx * 2 / 7, y2, RGBtoYUY2(RGB_BLACK));
FillRectangle(lr, dx * 2 / 7, y1, dx * 3 / 7, y2, RGBtoYUY2(RGB_MAGENTA_75pc));
FillRectangle(lr, dx * 3 / 7, y1, dx * 4 / 7, y2, RGBtoYUY2(RGB_BLACK));
FillRectangle(lr, dx * 4 / 7, y1, dx * 5 / 7, y2, RGBtoYUY2(RGB_CYAN_75pc));
FillRectangle(lr, dx * 5 / 7, y1, dx * 6 / 7, y2, RGBtoYUY2(RGB_BLACK));
FillRectangle(lr, dx * 6 / 7, y1, dx * 7 / 7, y2, RGBtoYUY2(RGB_WHITE_75pc));
// Third row stripes.
const UINT y3 = height;
FillRectangle(lr, dx * 0 / 28, y2, dx * 5 / 28, y3, RGBtoYUY2(RGB_I));
FillRectangle(lr, dx * 5 / 28, y2, dx * 10 / 28, y3, RGBtoYUY2(RGB_WHITE));
FillRectangle(lr, dx * 10 / 28, y2, dx * 15 / 28, y3, RGBtoYUY2(RGB_Q));
FillRectangle(lr, dx * 15 / 28, y2, dx * 20 / 28, y3, RGBtoYUY2(RGB_BLACK));
FillRectangle(lr, dx * 20 / 28, y2, dx * 16 / 21, y3, RGBtoYUY2(RGB_BLACK_n4pc));
FillRectangle(lr, dx * 16 / 21, y2, dx * 17 / 21, y3, RGBtoYUY2(RGB_BLACK));
FillRectangle(lr, dx * 17 / 21, y2, dx * 6 / 7, y3, RGBtoYUY2(RGB_BLACK_p4pc));
FillRectangle(lr, dx * 6 / 7, y2, dx * 7 / 7, y3, RGBtoYUY2(RGB_BLACK));
hr = pSurf->UnlockRect();
return hr;
}
//-------------------------------------------------------------------
// LoadBitmapResourceToAYUVSurface
//
// Load a 24-bpp RGB bitmap resource onto a Direct3D surface.
// The surface format is assumed to be AYUV.
//-------------------------------------------------------------------
HRESULT LoadBitmapResourceToAYUVSurface(
IDirect3DSurface9 *pSurf,
LONG width, // Surface width
LONG height, // Surface height
INT nIDBitmap, // Resource ID
BYTE PixelAlphaValue // Per-pixel alpha value
)
{
HRESULT hr = S_OK;
D3DLOCKED_RECT lr = { 0 };
HRSRC hrsrc = NULL;
HGLOBAL hglob = NULL;
// Load the bitmap resource.
hrsrc = FindResource(NULL, MAKEINTRESOURCE(nIDBitmap), RT_BITMAP);
if (hrsrc == NULL)
{
return HRESULT_FROM_WIN32(GetLastError());
}
hglob = LoadResource(NULL,hrsrc);
if (hglob == NULL)
{
return HRESULT_FROM_WIN32(GetLastError());
}
// Get the bitmap bits.
LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglob);
if (lpBitmap->biWidth != width || lpBitmap->biHeight != height)
{
hr = E_INVALIDARG;
goto done;
}
// Lock the Direct3D surface.
hr = pSurf->LockRect(&lr, NULL, D3DLOCK_NOSYSLOCK);
if (FAILED(hr)) { goto done; }
// Calculate source and target stride.
// The source bitmap is bottom-up, the target image is top-down.
LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
LONG lSrcStride = -1 * ((lpBitmap->biWidth * 3 + 3) & ~3);
BYTE *pSrc = (BYTE*)lpBits + (-lSrcStride * (lpBitmap->biHeight - 1));
BYTE* pDest = (BYTE*) lr.pBits;
// Convert the RGB pixels to AYUV and write to the surface.
for (LONG y = 0; y < lpBitmap->biHeight; y++)
{
RGBTRIPLE *pPel = (RGBTRIPLE*)pSrc;
for (LONG x = 0; x < lpBitmap->biWidth; x++)
{
const D3DCOLOR rgb = D3DCOLOR_ARGB(
PixelAlphaValue,
pPel[x].rgbtRed,
pPel[x].rgbtGreen, pPel[x].rgbtBlue
);
((DWORD*) pDest)[x] = RGBtoYUV(rgb);
}
pSrc += lSrcStride;
pDest += lr.Pitch;
}
hr = pSurf->UnlockRect();
done:
DeleteObject(hglob);
return hr;
}
//-------------------------------------------------------------------
// SetAYUVSurfacePixelAlpha
//
// Updates the per-pixel alpha values in an AYUV surface.
//-------------------------------------------------------------------
HRESULT SetAYUVSurfacePixelAlpha(
IDirect3DSurface9 *pSurf,
UINT width,
UINT height,
BYTE PixelAlphaValue
)
{
HRESULT hr;
D3DLOCKED_RECT lr;
hr = pSurf->LockRect(&lr, NULL, D3DLOCK_NOSYSLOCK);
if (FAILED(hr))
{
return hr;
}
BYTE* pDest = (BYTE*) lr.pBits;
for (UINT y = 0; y < height; y++)
{
for (UINT x = 0; x < width; x++)
{
pDest[ x * 4 + 3 ] = PixelAlphaValue;
}
pDest += lr.Pitch;
}
hr = pSurf->UnlockRect();
return hr;
}
//-------------------------------------------------------------------
// FillRectangle
//
// Fills a subrectangle in a Direct3D surface with a solid color.
//
// The caller must call LockSurface to lock the surface, and pass in
// the D3DLOCKED_RECT structure.
//-------------------------------------------------------------------
void FillRectangle(
D3DLOCKED_RECT& lr,
const UINT sx, // Horizontal position
const UINT sy, // Vertical position
const UINT ex, // Horizontal extent.
const UINT ey, // Vertical extent.
const DWORD color
)
{
BYTE* p = (BYTE*) lr.pBits;
p += lr.Pitch * sy;
for (UINT y = sy; y < ey; y++, p += lr.Pitch)
{
for (UINT x = sx; x < ex; x++)
{
((DWORD*) p)[x] = color;
}
}
}
//-------------------------------------------------------------------
// ScaleRectangle
//
// Scales an input rectangle, using the following scaling factor:
//
// output = input * (dst / src)
//
//-------------------------------------------------------------------
RECT ScaleRectangle(const RECT& input, const RECT& src, const RECT& dst)
{
RECT rect;
UINT src_dx = src.right - src.left;
UINT src_dy = src.bottom - src.top;
UINT dst_dx = dst.right - dst.left;
UINT dst_dy = dst.bottom - dst.top;
// Scale the input rectangle by dst / src.
rect.left = input.left * dst_dx / src_dx;
rect.right = input.right * dst_dx / src_dx;
rect.top = input.top * dst_dy / src_dy;
rect.bottom = input.bottom * dst_dy / src_dy;
return rect;
}
//-------------------------------------------------------------------
// InflateRectBounded
//
// Resizes a rectangle by a specified amount, but clips the result
// to a bounding rectangle.
//
// prc: The rectangle to resize.
// cx, cy: Amount to increase or decrease the rectangle.
// rcBound: Bounding rectangle.
//
//-------------------------------------------------------------------
void InflateRectBounded(RECT *prc, LONG cx, LONG cy, const RECT& rcBound)
{
RECT rect = *prc;
RECT intersect;
InflateRect(&rect, cx, cy);
IntersectRect(&intersect, &rect, &rcBound);
if (!IsRectEmpty(&intersect))
{
*prc = intersect;
}
}
//-------------------------------------------------------------------
// MoveRectBounded
//
// Moves a rectangle by a specified amount, but clips the result to
// a bounding rectangle.
//
// prc: The rectangle to move.
// cx, cy: Amount to move in the x and y directions.
// rcBound: Bounding rectangle.
//
//-------------------------------------------------------------------
void MoveRectBounded(RECT *prc, LONG cx, LONG cy, const RECT& rcBound)
{
RECT rect = *prc;
RECT intersect;
OffsetRect(&rect, cx, cy);
IntersectRect(&intersect, &rect, &rcBound);
if (EqualRect(&rect, &intersect))
{
*prc = rect;
}
}