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/Tools/LevelEdit/VisWindowDialog.cpp

518 lines
12 KiB
C++
Raw Permalink Normal View History

/*
** 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/>.
*/
// VisWindowDialog.cpp : implementation file
//
#include "stdafx.h"
#include "leveledit.h"
#include "viswindowdialog.h"
#include "visrasterizer.h"
#include "visrendercontext.h"
#include "pscene.h"
#include "phys.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
//
// VisWindowDialogClass
//
/////////////////////////////////////////////////////////////////////////////
VisWindowDialogClass::VisWindowDialogClass(CWnd* pParent /*=NULL*/) :
BitmapBits (NULL),
Bitmap (NULL),
Width (0),
Height (0),
MemDC (NULL),
CurToolTipVisId(-1),
CDialog(VisWindowDialogClass::IDD, pParent)
{
//{{AFX_DATA_INIT(VisWindowDialogClass)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
//
// Create a screen compatible DC
//
MemDC = ::CreateCompatibleDC (NULL);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// ~VisWindowDialogClass
//
/////////////////////////////////////////////////////////////////////////////
VisWindowDialogClass::~VisWindowDialogClass (void)
{
Free_DIB_Section ();
::DeleteDC (MemDC);
MemDC = NULL;
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// DoDataExchange
//
/////////////////////////////////////////////////////////////////////////////
void
VisWindowDialogClass::DoDataExchange (CDataExchange *pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(VisWindowDialogClass)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
return ;
}
BEGIN_MESSAGE_MAP(VisWindowDialogClass, CDialog)
//{{AFX_MSG_MAP(VisWindowDialogClass)
ON_WM_PAINT()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//
// Create
//
/////////////////////////////////////////////////////////////////////////////
void
VisWindowDialogClass::Create (void)
{
CDialog::Create (VisWindowDialogClass::IDD, NULL);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnInitDialog
//
/////////////////////////////////////////////////////////////////////////////
BOOL VisWindowDialogClass::OnInitDialog()
{
CDialog::OnInitDialog();
// create the tool-tip
if (ToolTip.Create(this, TTS_ALWAYSTIP) && ToolTip.AddTool(this))
{
ToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, SHRT_MAX);
ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_AUTOPOP, SHRT_MAX);
ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_INITIAL, 200);
ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_RESHOW, 200);
}
else
{
TRACE("Error in creating ToolTip");
}
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
/////////////////////////////////////////////////////////////////////////////
//
// Update_Display
//
/////////////////////////////////////////////////////////////////////////////
void
VisWindowDialogClass::Update_Display (VisRasterizerClass &rasterizer)
{
//
// Don't do anything if the user has not enabled the vis window
//
if (m_hWnd == NULL || IsWindowVisible () == false) {
return;
}
//
// Get the resolution of rasterizer
//
int width = 0;
int height = 0;
rasterizer.Get_Resolution (&width, &height);
//
// Recreate DIB section
//
Create_DIB_Section (width, height);
//
// Loop over all the rows in the bitmap
//
int index = 0;
int stride = (((Width * 3) + 3) & ~3);
for (int row = 0; row < Height; row ++) {
//
// DIB sections are aligned on DWORD boundaries, so ensure
// our starting index for this row is mapped appropriately.
//
index = row * stride;
//
// Get a pointer to the raw vis-render data for this row of the bitmap
//
const uint32 *pixel_ptr = rasterizer.Get_Pixel_Row (row, 0, Width - 1);
//
// Loop over all the columns of the bitmap
//
for (int col = 0; col < Width; col ++) {
unsigned int id = pixel_ptr[col];// + 1;
unsigned int pixel = Id_To_Pixel(id);
//
// Convert the pixel into red, green, and blue components
//
BYTE red = BYTE(pixel & 0x000000FF);
BYTE green = BYTE((pixel & 0x0000FF00) >> 8);
BYTE blue = BYTE((pixel & 0x00FF0000) >> 16);
//
// Store the pixel in the bitmap
//
BitmapBits[index ++] = blue;
BitmapBits[index ++] = green;
BitmapBits[index ++] = red;
}
}
//
// Update the window
//
Paint_Display ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Free_DIB_Section
//
/////////////////////////////////////////////////////////////////////////////
void
VisWindowDialogClass::Free_DIB_Section (void)
{
Width = 0;
Height = 0;
//
// Free the bitmap
//
if (Bitmap != NULL) {
::DeleteObject (Bitmap);
Bitmap = NULL;
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Create_DIB_Section
//
/////////////////////////////////////////////////////////////////////////////
void
VisWindowDialogClass::Create_DIB_Section (int width, int height)
{
if (Width == width && Height == height) {
return ;
}
//
// Calculate what size to make the window
//
RECT rect = { 0, 0, width * 2, height * 2 };
LONG style = ::GetWindowLong (m_hWnd, GWL_STYLE);
::AdjustWindowRect (&rect, style, FALSE);
//
// Resize the window
//
SetWindowPos (NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE);
//
// Release our old DIB section
//
Free_DIB_Section ();
//
// Cache the new width and height
//
Width = width;
Height = height;
//
// Set-up the fields of the BITMAPINFOHEADER
// Note: Top-down DIBs use negative height in Win32.
//
BITMAPINFOHEADER bitmap_info = { 0 };
bitmap_info.biSize = sizeof (BITMAPINFOHEADER);
bitmap_info.biWidth = Width;
bitmap_info.biHeight = -Height;
bitmap_info.biPlanes = 1;
bitmap_info.biBitCount = 24;
bitmap_info.biCompression = BI_RGB;
bitmap_info.biSizeImage = ((Width * Height) * 3);
bitmap_info.biXPelsPerMeter = 0;
bitmap_info.biYPelsPerMeter = 0;
bitmap_info.biClrUsed = 0;
bitmap_info.biClrImportant = 0;
//
// Create a bitmap that we can access the bits directly of
//
HDC screen_dc = ::GetDC (NULL);
Bitmap = ::CreateDIBSection ( screen_dc,
(const BITMAPINFO *)&bitmap_info,
DIB_RGB_COLORS,
(void **)&BitmapBits,
NULL,
0L);
//
// Release our temporary screen DC
//
::ReleaseDC (NULL, screen_dc);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Paint_Display
//
/////////////////////////////////////////////////////////////////////////////
void
VisWindowDialogClass::Paint_Display (void)
{
if (m_hWnd == NULL || Bitmap == NULL) {
return ;
}
//
// Setup the DCs for blitting
//
HDC wnd_dc = ::GetDC (m_hWnd);
HBITMAP old_bmp = (HBITMAP)::SelectObject (MemDC, Bitmap);
//
// Copy the contents of the bitmap to the screen
//
::StretchBlt (wnd_dc, 0, 0, Width * 2, Height * 2, MemDC, 0, 0, Width, Height, SRCCOPY);
//
// Restore the DCs
//
::SelectObject (MemDC, old_bmp);
::ReleaseDC (m_hWnd, wnd_dc);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnPaint
//
/////////////////////////////////////////////////////////////////////////////
void
VisWindowDialogClass::OnPaint (void)
{
CPaintDC dc (this);
Paint_Display ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Hit_Test - determines the vis-id under the cursor
//
/////////////////////////////////////////////////////////////////////////////
int
VisWindowDialogClass::Hit_Test(CPoint point) const
{
//
// If we don't have a bitmap, just return
//
if (BitmapBits == NULL) {
return -1;
}
//
// Look up the pixel, we are StretchBlt'ing the bitmap to 2x the normal size
// so we divide the coordinates by two
//
int x = point.x / 2;
int y = point.y / 2;
if ((x <= 0) || (x >= Width) || (y <= 0) || (y >= Height)) {
return -1;
}
int stride = (((Width * 3) + 3) & ~3);
int pixel_address = x * 3 + stride * y;
BYTE blue = BitmapBits[pixel_address ++];
BYTE green = BitmapBits[pixel_address ++];
BYTE red = BitmapBits[pixel_address ++];
//
// Map the color back to a vis ID
//
unsigned int color = red | (green<<8) | (blue<<16);
unsigned int id = Pixel_To_Id(color);
return id;
}
/////////////////////////////////////////////////////////////////////////////
//
// Id_To_Pixel
//
/////////////////////////////////////////////////////////////////////////////
unsigned int
VisWindowDialogClass::Id_To_Pixel(unsigned int id) const
{
uint32 pixel = 0;
pixel |= ((id & 0x0000000F) >> 0) << 20; // LSN (Least Significant Nibble) goes into MSN of red
pixel |= ((id & 0x000000F0) >> 4) << 12; // next LSN goes into MSN of green
pixel |= ((id & 0x00000F00) >> 8) << 4; // next LSN goes into MSN of blue
pixel |= ((id & 0x0000F000) >> 12) << 16; // put into LSN of red
pixel |= ((id & 0x000F0000) >> 16) << 8; // put into LSN of green
pixel |= ((id & 0x00F00000) >> 20) << 0; // put into LSN of blue
return pixel;
}
/////////////////////////////////////////////////////////////////////////////
//
// Pixel_To_Id
//
/////////////////////////////////////////////////////////////////////////////
unsigned int
VisWindowDialogClass::Pixel_To_Id(unsigned int pixel) const
{
uint32 id = 0;
id |= ((pixel & 0x0000000F) >> 0) << 20;
id |= ((pixel & 0x000000F0) >> 4) << 8;
id |= ((pixel & 0x00000F00) >> 8) << 16;
id |= ((pixel & 0x0000F000) >> 12) << 4;
id |= ((pixel & 0x000F0000) >> 16) << 12;
id |= ((pixel & 0x00F00000) >> 20) << 0;
return id;
}
/////////////////////////////////////////////////////////////////////////////
//
// PreTranslateMessage
//
/////////////////////////////////////////////////////////////////////////////
BOOL
VisWindowDialogClass::PreTranslateMessage(MSG* pMsg)
{
if (::IsWindow(ToolTip.m_hWnd) && pMsg->hwnd == m_hWnd)
{
switch(pMsg->message)
{
case WM_LBUTTONDOWN:
case WM_MOUSEMOVE:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
ToolTip.RelayEvent(pMsg);
break;
}
}
return CDialog::PreTranslateMessage(pMsg);
}
/////////////////////////////////////////////////////////////////////////////
//
// OnMouseMove
//
/////////////////////////////////////////////////////////////////////////////
void VisWindowDialogClass::OnMouseMove(UINT nFlags, CPoint point)
{
if (::IsWindow(ToolTip.m_hWnd))
{
unsigned int vis_id = Hit_Test(point);
if ((vis_id == -1) || (vis_id != CurToolTipVisId)) {
// Use Activate() to hide the tooltip.
ToolTip.Activate(FALSE);
}
if (vis_id != -1) {
ToolTip.Activate(TRUE);
if (vis_id == BACKFACE_VIS_ID) {
CString tooltip_string;
tooltip_string.Format("Vis Id: %d, Backface!",vis_id);
ToolTip.UpdateTipText(tooltip_string,this);
} else {
PhysClass * obj = NULL;
RefPhysListIterator it = PhysicsSceneClass::Get_Instance()->Get_Static_Object_Iterator();
while ((!it.Is_Done()) && (obj == NULL)) {
if (it.Peek_Obj()->Get_Vis_Object_ID()==(int)vis_id) {
obj = it.Peek_Obj();
}
it.Next();
}
if (obj != NULL) {
CString tooltip_string;
tooltip_string.Format("Vis Id: %d, Model Name: %s",vis_id,obj->Peek_Model()->Get_Name());
ToolTip.UpdateTipText(tooltip_string,this);
} else {
CString tooltip_string;
tooltip_string.Format("Vis Id: %d, Unknown Model",vis_id);
ToolTip.UpdateTipText(tooltip_string,this);
}
}
CurToolTipVisId = vis_id;
}
}
CDialog::OnMouseMove(nFlags, point);
}