AnvilStats: Implemented a cImageComposingCallback class.
This will ease the creation of callbacks that produce per-region images of stuff.master
parent
b1f8b6e4c4
commit
7f4c880147
|
@ -321,6 +321,14 @@
|
||||||
RelativePath=".\HeightMap.h"
|
RelativePath=".\HeightMap.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\ImageComposingCallback.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\ImageComposingCallback.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\Processor.cpp"
|
RelativePath=".\Processor.cpp"
|
||||||
>
|
>
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
|
||||||
|
// ImageComposingCallback.cpp
|
||||||
|
|
||||||
|
// Implements the cImageComposingCallback class that implements a subset of cCallback for composing per-region images
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "ImageComposingCallback.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cImageComposingCallback::cImageComposingCallback(const AString & a_FileNamePrefix) :
|
||||||
|
m_FileNamePrefix(a_FileNamePrefix),
|
||||||
|
m_CurrentRegionX(INVALID_REGION_COORD),
|
||||||
|
m_CurrentRegionZ(INVALID_REGION_COORD),
|
||||||
|
m_ImageData(new int[32 * 16 * 32 * 16])
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cImageComposingCallback::~cImageComposingCallback()
|
||||||
|
{
|
||||||
|
delete[] m_ImageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cImageComposingCallback::OnNewRegion(int a_RegionX, int a_RegionZ)
|
||||||
|
{
|
||||||
|
ASSERT(m_CurrentRegionX == INVALID_REGION_COORD);
|
||||||
|
ASSERT(m_CurrentRegionZ == INVALID_REGION_COORD); // Has any previous region been finished properly?
|
||||||
|
|
||||||
|
m_CurrentRegionX = a_RegionX;
|
||||||
|
m_CurrentRegionZ = a_RegionZ;
|
||||||
|
OnEraseImage();
|
||||||
|
|
||||||
|
return CALLBACK_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cImageComposingCallback::OnRegionFinished(int a_RegionX, int a_RegionZ)
|
||||||
|
{
|
||||||
|
ASSERT(m_CurrentRegionX != INVALID_REGION_COORD);
|
||||||
|
ASSERT(m_CurrentRegionZ != INVALID_REGION_COORD); // Has a region been started properly?
|
||||||
|
ASSERT(m_CurrentRegionX == a_RegionX);
|
||||||
|
ASSERT(m_CurrentRegionZ == a_RegionZ); // Is it the same region that has been started?
|
||||||
|
|
||||||
|
AString FileName = GetFileName(a_RegionX, a_RegionZ);
|
||||||
|
if (!FileName.empty())
|
||||||
|
{
|
||||||
|
OnBeforeImageSaved(a_RegionX, a_RegionZ, FileName);
|
||||||
|
SaveImage(FileName);
|
||||||
|
OnAfterImageSaved(a_RegionX, a_RegionZ, FileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_CurrentRegionX = INVALID_REGION_COORD;
|
||||||
|
m_CurrentRegionZ = INVALID_REGION_COORD;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AString cImageComposingCallback::GetFileName(int a_RegionX, int a_RegionZ)
|
||||||
|
{
|
||||||
|
return Printf("%s.%d.%d", m_FileNamePrefix.c_str(), a_RegionX, a_RegionZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cImageComposingCallback::OnEraseImage(void)
|
||||||
|
{
|
||||||
|
// By default erase the image to black:
|
||||||
|
EraseImage(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cImageComposingCallback::EraseImage(int a_Color)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < PIXEL_COUNT; i++)
|
||||||
|
{
|
||||||
|
m_ImageData[i] = a_Color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cImageComposingCallback::EraseChunk(int a_Color, int a_RelChunkX, int a_RelChunkZ)
|
||||||
|
{
|
||||||
|
int Base = a_RelChunkZ * IMAGE_HEIGHT + a_RelChunkX * 16;
|
||||||
|
for (int v = 0; v < 16; v++)
|
||||||
|
{
|
||||||
|
int BaseV = Base + v * IMAGE_HEIGHT;
|
||||||
|
for (int u = 0; u < 16; u++)
|
||||||
|
{
|
||||||
|
m_ImageData[BaseV + u] = a_Color;
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cImageComposingCallback::SetPixel(int a_RelU, int a_RelV, int a_Color)
|
||||||
|
{
|
||||||
|
ASSERT((a_RelU >= 0) && (a_RelU < IMAGE_WIDTH));
|
||||||
|
ASSERT((a_RelV >= 0) && (a_RelV < IMAGE_HEIGHT));
|
||||||
|
|
||||||
|
m_ImageData[a_RelU + IMAGE_WIDTH * a_RelV] = a_Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cImageComposingCallback::GetPixel(int a_RelU, int a_RelV)
|
||||||
|
{
|
||||||
|
if ((a_RelU < 0) || (a_RelU >= IMAGE_WIDTH) || (a_RelV < 0) || (a_RelV >= IMAGE_HEIGHT))
|
||||||
|
{
|
||||||
|
// Outside the image data
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_ImageData[a_RelU + IMAGE_WIDTH * a_RelV];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cImageComposingCallback::SetPixelURow(int a_RelUStart, int a_RelV, int a_CountU, int * a_Pixels)
|
||||||
|
{
|
||||||
|
ASSERT((a_RelUStart >= 0) && (a_RelUStart + a_CountU < IMAGE_WIDTH));
|
||||||
|
ASSERT((a_RelV >= 0) && (a_RelV < IMAGE_HEIGHT));
|
||||||
|
ASSERT(a_Pixels != NULL);
|
||||||
|
|
||||||
|
int Base = a_RelUStart + a_RelV * IMAGE_WIDTH;
|
||||||
|
for (int u = 0; u < a_CountU; u++)
|
||||||
|
{
|
||||||
|
m_ImageData[Base + u] = a_Pixels[u];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cImageComposingCallback::SaveImage(const AString & a_FileName)
|
||||||
|
{
|
||||||
|
cFile f(a_FileName, cFile::fmWrite);
|
||||||
|
if (!f.IsOpen())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header for BMP files (is the same for the same-size files)
|
||||||
|
static const unsigned char BMPHeader[] =
|
||||||
|
{
|
||||||
|
0x42, 0x4D, 0x36, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
} ;
|
||||||
|
|
||||||
|
f.Write(BMPHeader, sizeof(BMPHeader));
|
||||||
|
f.Write(m_ImageData, PIXEL_COUNT * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
|
||||||
|
// ImageComposingCallback
|
||||||
|
|
||||||
|
// Declares the cImageComposingCallback class that implements a subset of cCallback for composing per-region images
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Callback.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Implements the plumbing for composing per-region images from multiple chunks.
|
||||||
|
To use this class, create a descendant that writes the image data using
|
||||||
|
SetPixel() or SetPixelURow() functions.
|
||||||
|
|
||||||
|
For the purpose of this class the image data is indexed U (horz) * V (vert), to avoid confusion with other coords.
|
||||||
|
The image is a 32bpp raw imagedata, written into a BMP file.
|
||||||
|
*/
|
||||||
|
class cImageComposingCallback :
|
||||||
|
public cCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
INVALID_REGION_COORD = 99999, ///< Used for un-assigned region coords
|
||||||
|
IMAGE_WIDTH = 32 * 16,
|
||||||
|
IMAGE_HEIGHT = 32 * 16,
|
||||||
|
PIXEL_COUNT = IMAGE_WIDTH * IMAGE_HEIGHT, ///< Total pixel count of the image data
|
||||||
|
} ;
|
||||||
|
|
||||||
|
cImageComposingCallback(const AString & a_FileNamePrefix);
|
||||||
|
virtual ~cImageComposingCallback();
|
||||||
|
|
||||||
|
// cCallback overrides:
|
||||||
|
virtual bool OnNewRegion(int a_RegionX, int a_RegionZ) override;
|
||||||
|
virtual void OnRegionFinished(int a_RegionX, int a_RegionZ) override;
|
||||||
|
|
||||||
|
// New introduced overridable functions:
|
||||||
|
|
||||||
|
/// Called when a file is about to be saved, to generate the filename
|
||||||
|
virtual AString GetFileName(int a_RegionX, int a_RegionZ);
|
||||||
|
|
||||||
|
/// Called before the file is saved
|
||||||
|
virtual void OnBeforeImageSaved(int a_RegionX, int a_RegionZ, const AString & a_FileName) {}
|
||||||
|
|
||||||
|
/// Called after the image is saved to a file
|
||||||
|
virtual void OnAfterImageSaved(int a_RegionX, int a_RegionZ, const AString & a_FileName) {}
|
||||||
|
|
||||||
|
/// Called when a new region is beginning, to erase the image data
|
||||||
|
virtual void OnEraseImage(void);
|
||||||
|
|
||||||
|
// Functions for manipulating the image:
|
||||||
|
|
||||||
|
/// Erases the entire image with the specified color
|
||||||
|
void EraseImage(int a_Color);
|
||||||
|
|
||||||
|
/// Erases the specified chunk's portion of the image with the specified color. Note that chunk coords are relative to the current region
|
||||||
|
void EraseChunk(int a_Color, int a_RelChunkX, int a_RelChunkZ);
|
||||||
|
|
||||||
|
/// Returns the current region X coord
|
||||||
|
int GetCurrentRegionX(void) const { return m_CurrentRegionX; }
|
||||||
|
|
||||||
|
/// Returns the current region Z coord
|
||||||
|
int GetCurrentRegionZ(void) const { return m_CurrentRegionZ; }
|
||||||
|
|
||||||
|
/// Sets the pixel at the specified UV coords to the specified color
|
||||||
|
void SetPixel(int a_RelU, int a_RelV, int a_Color);
|
||||||
|
|
||||||
|
/// Returns the color of the pixel at the specified UV coords; -1 if outside
|
||||||
|
int GetPixel(int a_RelU, int a_RelV);
|
||||||
|
|
||||||
|
/// Sets a row of pixels. a_Pixels is expected to be a_CountU pixels wide. a_RelUStart + a_CountU is assumed less than image width
|
||||||
|
void SetPixelURow(int a_RelUStart, int a_RelV, int a_CountU, int * a_Pixels);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// Prefix for the filenames, when generated by the default GetFileName() function
|
||||||
|
AString m_FileNamePrefix;
|
||||||
|
|
||||||
|
/// Coords of the currently processed region
|
||||||
|
int m_CurrentRegionX, m_CurrentRegionZ;
|
||||||
|
|
||||||
|
/// Raw image data; 1 MiB worth of data, therefore unsuitable for stack allocation. [u + IMAGE_WIDTH * v]
|
||||||
|
int * m_ImageData;
|
||||||
|
|
||||||
|
void SaveImage(const AString & a_FileName);
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue