| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- /*
- ** 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/>.
- */
- /***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : LevelEdit *
- * *
- * $Archive:: /Commando/Code/Tools/LevelEdit/HistogramCtl.cpp $Modtime:: 7/2/99 6:28p $*
- * *
- * $Revision:: 3 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "StdAfx.H"
- #include "HistogramCtl.H"
- /////////////////////////////////////////////////////////////////////////////
- //
- // HistogramCtlClass
- //
- /////////////////////////////////////////////////////////////////////////////
- HistogramCtlClass::HistogramCtlClass (void)
- : m_hBitmap (NULL),
- m_pBits (NULL),
- m_ScanlineSize (0),
- m_BMPWidth (0),
- m_BMPHeight (0),
- m_IsDirty (true),
- m_AllowRefresh (true),
- m_LowColor (0, 0.5F, 0),
- m_HighColor (1, 0, 0),
- m_BkLowColor (0.75F, 0.75F, 0.75F),
- m_BkHighColor (0.1F, 0.1F, 0.1F),
- m_SelColor (0, 0, 0),
- m_BkSelColor (1, 1, 1)
- {
- m_XAxis.min = 0;
- m_XAxis.max = 1;
- m_YAxis.min = 0;
- m_YAxis.max = 1;
- m_Selection.min = -1;
- m_Selection.max = -1;
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // ~HistogramCtlClass
- //
- /////////////////////////////////////////////////////////////////////////////
- HistogramCtlClass::~HistogramCtlClass (void)
- {
- Destroy_DIB_Section ();
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Create_DIB_Section
- //
- /////////////////////////////////////////////////////////////////////////////
- void
- HistogramCtlClass::Create_DIB_Section (void)
- {
- // Start fresh
- Destroy_DIB_Section ();
- //
- // 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 = m_BMPWidth;
- bitmap_info.biHeight = -m_BMPHeight;
- bitmap_info.biPlanes = 1;
- bitmap_info.biBitCount = 24;
- bitmap_info.biCompression = BI_RGB;
- bitmap_info.biSizeImage = ((m_BMPWidth * m_BMPHeight) * 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 hscreen_dc = ::GetDC (NULL);
- m_hBitmap = ::CreateDIBSection (hscreen_dc,
- (const BITMAPINFO *)&bitmap_info,
- DIB_RGB_COLORS,
- (void **)&m_pBits,
- NULL,
- 0L);
- // Release our temporary screen DC
- ::ReleaseDC (NULL, hscreen_dc);
- // Window's bitmaps are DWORD aligned, so make sure
- // we take that into account.
- int alignment_offset = (m_BMPWidth * 3) % 4;
- alignment_offset = (alignment_offset != 0) ? (4 - alignment_offset) : 0;
- m_ScanlineSize = (m_BMPWidth * 3) + alignment_offset;
- // Force a repaint next time its necessary
- Set_Dirty (true);
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Destroy_DIB_Section
- //
- /////////////////////////////////////////////////////////////////////////////
- void
- HistogramCtlClass::Destroy_DIB_Section (void)
- {
- if (m_hBitmap != NULL) {
- ::DeleteObject (m_hBitmap);
- m_hBitmap = NULL;
- m_pBits = NULL;
- }
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Set_Dimensions
- //
- /////////////////////////////////////////////////////////////////////////////
- void
- HistogramCtlClass::Set_Dimensions (int width, int height)
- {
- if ((m_BMPWidth != width) ||
- (m_BMPHeight != height)) {
-
- //
- // Recreate the BMP we use
- //
- m_BMPWidth = width;
- m_BMPHeight = height;
- Create_DIB_Section ();
- }
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Paint_DIB
- //
- /////////////////////////////////////////////////////////////////////////////
- void
- HistogramCtlClass::Paint_DIB (void)
- {
- float x_range = m_XAxis.max - m_XAxis.min;
- float y_range = m_YAxis.max - m_YAxis.min;
- int sel_start_x = int((m_Selection.min / x_range) * (float)(m_BMPWidth-1));
- int sel_end_x = int((m_Selection.max / x_range) * (float)(m_BMPWidth-1));
- BYTE sel_back_red = BYTE (m_BkSelColor.X * 255);
- BYTE sel_back_green = BYTE (m_BkSelColor.Y * 255);
- BYTE sel_back_blue = BYTE (m_BkSelColor.Z * 255);
- BYTE sel_red = BYTE (m_SelColor.X * 255);
- BYTE sel_green = BYTE (m_SelColor.Y * 255);
- BYTE sel_blue = BYTE (m_SelColor.Z * 255);
- //
- // Paint the background
- //
- if (m_pBits != NULL) {
- float red = m_BkHighColor.X;
- float green = m_BkHighColor.Y;
- float blue = m_BkHighColor.Z;
- float red_inc = (m_BkLowColor.X - m_BkHighColor.X) / (float)m_BMPHeight;
- float green_inc = (m_BkLowColor.Y - m_BkHighColor.Y) / (float)m_BMPHeight;
- float blue_inc = (m_BkLowColor.Z - m_BkHighColor.Z) / (float)m_BMPHeight;
-
- //
- // Loop through all the pixels and set their background color.
- //
- int bmp_index = 0;
- int row_offset = m_ScanlineSize - (m_BMPWidth * 3);
- for (int row = 0; row < m_BMPHeight; row ++) {
- BYTE curr_red = BYTE(red * 255);
- BYTE curr_green = BYTE(green * 255);
- BYTE curr_blue = BYTE(blue * 255);
- for (int col = 0; col < m_BMPWidth; col ++) {
- if ((col >= sel_start_x) && (col <= sel_end_x)) {
- m_pBits[bmp_index ++] = sel_back_blue;
- m_pBits[bmp_index ++] = sel_back_green;
- m_pBits[bmp_index ++] = sel_back_red;
- } else {
- m_pBits[bmp_index ++] = curr_blue;
- m_pBits[bmp_index ++] = curr_green;
- m_pBits[bmp_index ++] = curr_red;
- }
- }
- red += red_inc;
- green += green_inc;
- blue += blue_inc;
- bmp_index += row_offset;
- }
- }
- //
- // Paint the columns if necessary
- //
- if ((m_pBits != NULL) && (m_ValueList.Count () > 0)) {
- int start_index = Find_Value_Index (m_XAxis.min);
- int end_index = Find_Value_Index (m_XAxis.max);
- int * x_vector = new int [m_BMPWidth];
- ::memset (x_vector, 0, sizeof (int) * m_BMPWidth);
-
- //
- // Loop through all the values and combine pixel-duplicates
- //
- for (int index = start_index; index <= end_index; index ++) {
- VALUE &value = m_ValueList[index];
- int x_pos = int((value.value / x_range) * (float)(m_BMPWidth-1));
- x_vector[x_pos] += value.count;
- }
- float start_red = m_HighColor.X;
- float start_green = m_HighColor.Y;
- float start_blue = m_HighColor.Z;
- float red_inc = (m_LowColor.X - m_HighColor.X) / (float)m_BMPHeight;
- float green_inc = (m_LowColor.Y - m_HighColor.Y) / (float)m_BMPHeight;
- float blue_inc = (m_LowColor.Z - m_HighColor.Z) / (float)m_BMPHeight;
- //
- // Paint each column of information
- //
- for (int x_pos = 0; x_pos < m_BMPWidth; x_pos ++) {
- if (x_vector[x_pos] > 0) {
- int height = int(((float)(x_vector[x_pos]) / y_range) * (float)m_BMPHeight);
- height = min (height, m_BMPHeight);
- int y_pos = m_BMPHeight - height;
- //
- // Determine the starting red, green, blue
- //
- float curr_red = (start_red + (y_pos * red_inc));
- float curr_green = (start_green + (y_pos * green_inc));
- float curr_blue = (start_blue + (y_pos * blue_inc));
- //
- // Paint the column
- //
- int bmp_index = (y_pos * m_ScanlineSize) + (x_pos * 3);
- for (int pixel = y_pos; pixel < m_BMPHeight; pixel ++) {
-
- //
- // Plot the pixel in the BMP (note, the bits are orgainzed
- // in an BGR format).
- //
- if ((x_pos >= sel_start_x) && (x_pos <= sel_end_x)) {
- m_pBits[bmp_index] = sel_blue;
- m_pBits[bmp_index + 1] = sel_green;
- m_pBits[bmp_index + 2] = sel_red;
- } else {
- m_pBits[bmp_index] = BYTE(curr_blue * 255);
- m_pBits[bmp_index + 1] = BYTE(curr_green * 255);
- m_pBits[bmp_index + 2] = BYTE(curr_red * 255);
- }
- //
- // Increment the current cocor
- //
- curr_red += red_inc;
- curr_green += green_inc;
- curr_blue += blue_inc;
- // Move down to the next scanline
- bmp_index += m_ScanlineSize;
- }
- }
- }
- delete [] x_vector;
- Set_Dirty (false);
- }
-
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Add_Data_Point
- //
- /////////////////////////////////////////////////////////////////////////////
- void
- HistogramCtlClass::Add_Data_Point (float value)
- {
- int start = 0;
- int end = m_ValueList.Count ();
- end = max (end, 0);
- bool found = false;
- int index = end;
- while (end > start)
- {
- index = start + ((end - start) >> 1);
- float curr_value = m_ValueList[index].value;
- if (value > curr_value) {
- if (start == index) { index ++; break; }
- start = index;
- } else if (value < curr_value) {
- if (end == index) { index --; break; }
- end = index;
- } else {
- m_ValueList[index].count ++;
- found = true;
- break;
- }
- }
- ASSERT (index >=0 );
- if (found == false) {
- m_ValueList.Insert (index, VALUE (value, 1));
- }
- /*int start = 0;
- int end = m_ValueList.Count () - 1;
- //
- // Simple binary search to find the right place
- // to insert the new data point
- //
- bool found = false;
- while ((end > start) && !found) {
-
- int index = start + ((end - start) >> 1);
- VALUE &curr_point = m_ValueList[index];
- if (index == start) {
- break;
- } else if (value > curr_point.value) {
- start = index;
- } else if (value < curr_point.value) {
- end = index;
- } else {
- curr_point.count ++;
- found = true;
- }
- }
- //
- // If we didn't find the exact point in our search,
- // then add the point to the list.
- //
- if (found == false) {
- m_ValueList.Insert (start, VALUE (value, 1));
- }*/
- Set_Dirty (true);
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Find_Value_Index
- //
- /////////////////////////////////////////////////////////////////////////////
- int
- HistogramCtlClass::Find_Value_Index (float value)
- {
- //int retval = -1;
- int start = 0;
- int end = m_ValueList.Count ();
- end = max (end, 0);
- int index = end;
- while (end > start)
- {
- index = start + ((end - start) >> 1);
- float curr_value = m_ValueList[index].value;
- if (value > curr_value) {
- if (start == index) { index ++; break; }
- start = index;
- } else if (value < curr_value) {
- if (end == index) { index --; break; }
- end = index;
- } else {
-
- while ((curr_value == value) && (index > 0)) {
- curr_value = m_ValueList[--index].value;
- }
- index = (curr_value == value) ? index : index + 1;
- //m_ValueList[index].count ++;
- //found = true;
- break;
- }
- }
- ASSERT (index >=0 );
- /*if (found == false) {
- m_ValueList.Insert (index, VALUE (value, 1));
- }*/
- //
- // Simple binary search to find the right place
- // to insert the new data point
- //
- /*int start = 0;
- int end = m_ValueList.Count () - 1;
- while ((end > start) && (retval == -1)) {
-
- int index = start + ((end - start) >> 1);
- VALUE &curr_point = m_ValueList[index];
- if (index == start) {
- retval = (value > curr_point.value) ? end : start;
- break;
- } else if (value > curr_point.value) {
- start = index;
- } else if (value < curr_point.value) {
- end = index;
- } else {
- retval = index;
- }
- }*/
- /*if (retval == -1) {
- retval = index;
- }*/
- return index;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Render
- //
- /////////////////////////////////////////////////////////////////////////////
- void
- HistogramCtlClass::Render (HDC hdc, int x_pos, int y_pos)
- {
- //
- // Ensure we have an up-to-date graph
- //
- if (m_IsDirty) {
- Paint_DIB ();
- }
- if (m_hBitmap != NULL) {
- HDC mem_dc = ::CreateCompatibleDC (NULL);
- HBITMAP old_bmp = (HBITMAP)::SelectObject (mem_dc, m_hBitmap);
- //
- // Paint our graph onto the window
- //
- ::BitBlt (hdc, x_pos, y_pos, m_BMPWidth, m_BMPHeight, mem_dc, 0, 0, SRCCOPY);
- // Cleanup
- ::SelectObject (mem_dc, old_bmp);
- ::DeleteDC (mem_dc);
- }
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Reset_Data_Points
- //
- /////////////////////////////////////////////////////////////////////////////
- void
- HistogramCtlClass::Reset_Data_Points (void)
- {
- m_ValueList.Delete_All ();
- Set_Dirty (true);
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Set_Bk_Color
- //
- /////////////////////////////////////////////////////////////////////////////
- void
- HistogramCtlClass::Set_Bk_Color
- (
- const Vector3 &low,
- const Vector3 &high
- )
- {
- m_BkLowColor = low;
- m_BkHighColor = high;
- Set_Dirty (true);
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Set_Color
- //
- /////////////////////////////////////////////////////////////////////////////
- void
- HistogramCtlClass::Set_Color
- (
- const Vector3 &low,
- const Vector3 &high
- )
- {
- m_LowColor = low;
- m_HighColor = high;
- Set_Dirty (true);
- return ;
- }
|