OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4TextureShape Class Reference

#include <C4TextureShape.h>

Public Member Functions

 C4TextureShape ()
 
 ~C4TextureShape ()
 
void Clear ()
 
bool Load (C4Group &group, const char *filename, int32_t base_tex_wdt, int32_t base_tex_hgt)
 
int32_t GetWidth () const
 
int32_t GetHeight () const
 
int32_t GetMaxPolyWidth () const
 
int32_t GetMaxPolyHeight () const
 
void Draw (const CSurface8 &sfcMap, const CSurface8 &sfcMapBkg, int32_t iMapX, int32_t iMapY, int32_t iMapWdt, int32_t iMapHgt, uint8_t iTexture, int32_t iOffX, int32_t iOffY, int32_t MapZoom, int32_t min_overlap_ratio)
 

Detailed Description

Definition at line 26 of file C4TextureShape.h.

Constructor & Destructor Documentation

C4TextureShape::C4TextureShape ( )
inline

Definition at line 35 of file C4TextureShape.h.

35 : data(), num_shapes(0) {}
C4TextureShape::~C4TextureShape ( )
inline

Definition at line 36 of file C4TextureShape.h.

36 {}

Member Function Documentation

void C4TextureShape::Clear ( )

Definition at line 30 of file C4TextureShape.cpp.

References CSurface8::Clear().

Referenced by Load().

31 {
32  data.Clear();
33  num_shapes = 0;
34  shape_border_x.clear();
35  shape_border_y.clear();
36  shape_pixnum.clear();
37  shape_pixnum.reserve(128);
38 }
void Clear()
Definition: CSurface8.cpp:48

Here is the call graph for this function:

Here is the caller graph for this function:

void C4TextureShape::Draw ( const CSurface8 sfcMap,
const CSurface8 sfcMapBkg,
int32_t  iMapX,
int32_t  iMapY,
int32_t  iMapWdt,
int32_t  iMapHgt,
uint8_t  iTexture,
int32_t  iOffX,
int32_t  iOffY,
int32_t  MapZoom,
int32_t  min_overlap_ratio 
)

Definition at line 179 of file C4TextureShape.cpp.

References CSurface8::_GetPix(), C4Landscape::_SetPix2(), C4TextureShapeActivationMap::Add(), C4TextureShapeActivationMap::Get(), C4Landscape::GetHeight(), GetMaxPolyHeight(), GetMaxPolyWidth(), CSurface8::GetPix(), C4Landscape::GetWidth(), CSurface8::Hgt, Landscape, and CSurface8::Wdt.

Referenced by C4Landscape::P::ChunkOZoom().

180 {
181  // Safety
182  if (!num_shapes) return;
183  // Get affected range of shapes in pixels
184  // Add max polygon size because polygons may extent far onto outside pixels
185  int32_t x0 = std::max<int32_t>(0, iMapX*MapZoom + iOffX - GetMaxPolyWidth()),
186  y0 = std::max<int32_t>(0, iMapY*MapZoom + iOffY - GetMaxPolyHeight());
187  int32_t x1 = std::min<int32_t>(::Landscape.GetWidth(), x0 + iMapWdt*MapZoom + GetMaxPolyWidth() * 2),
188  y1 = std::min<int32_t>(::Landscape.GetHeight(), y0 + iMapHgt*MapZoom + GetMaxPolyHeight() * 2);
189  // Range in shape blocks.
190  // A shape block is the coverage of the size of one loaded shape data surface
191  int32_t rblock_x0 = x0 / data.Wdt;
192  int32_t rblock_y0 = y0 / data.Hgt;
193  int32_t rblock_x1 = (x1 - 1) / data.Wdt + 1;
194  int32_t rblock_y1 = (y1 - 1) / data.Hgt + 1;
195  int32_t n_blocks_x = rblock_x1 - rblock_x0 + 1;
196  int32_t n_blocks_y = rblock_y1 - rblock_y0 + 1;
197 
198  // Step 1: Find all active shapes and store them in activation map
199  // The activation map covers all repeated shape blocks in the updated areas and tiles each block into 2x2 sub-blocks.
200  // Sub-blocks handle the case where shapes wrap out of the side of a block into the next block.
201  C4TextureShapeActivationMap activation(rblock_x0, rblock_y0, n_blocks_x, n_blocks_y, num_shapes);
202  for (int32_t map_y = iMapY; map_y < iMapY + iMapHgt; ++map_y)
203  {
204  for (int32_t map_x = iMapX; map_x < iMapX + iMapWdt; ++map_x)
205  {
206  if (sfcMap.GetPix(map_x, map_y) == iTexture)
207  {
208  // Here we have a pixel of the texture drawn in this shape
209  // Find all shapes covered by this map pixel and remember background pixel for them
210  const BYTE pixBkg = sfcMapBkg.GetPix(map_x, map_y);
211  // Find all shape blocks to be checked
212  int32_t px_check_rate = 1; // sample rate to check coverage, in pixels. Could also increase this if it turns out to be a bottleneck
213  for (int32_t pxo_y = 0; pxo_y < MapZoom; pxo_y += px_check_rate)
214  {
215  int32_t px_y = map_y * MapZoom + pxo_y + iOffY;
216  int32_t spx_y = px_y % data.Hgt;
217  int32_t block_y = px_y / data.Hgt;
218  for (int32_t pxo_x = 0; pxo_x < MapZoom; pxo_x += px_check_rate)
219  {
220  int32_t px_x = map_x * MapZoom + pxo_x + iOffX;
221  int32_t spx_x = px_x % data.Wdt;
222  int32_t block_x = px_x / data.Wdt;
223  BYTE shape_idx = data._GetPix(spx_x, spx_y);
224  // No shape here or already handled?
225  if (shape_idx == Shape_None) continue;
226  // We touched a new shape! Activate it in the proper activation vectors
227  int32_t block_x1 = block_x, block_x2 = block_x;
228  // Is this shape wrapping along x?
229  if (shape_border_x[shape_idx])
230  {
231  // It is! Are we on the left or right side of the shape block?
232  if (spx_x < data.Wdt / 2)
233  {
234  // Left side. Activate left sub-block of current block and right sub-block of block left to that
235  --block_x2;
236  }
237  else
238  {
239  // Right side. Activate right sub-block of current block and left sub-block of block right to that
240  ++block_x1;
241  }
242  }
243  // Same checks for vertical
244  int32_t block_y1 = block_y, block_y2 = block_y;
245  if (shape_border_y[shape_idx]) { if (spx_y < data.Hgt / 2) --block_y2; else ++block_y1; }
246  // Store activation (performs additional border checks)
247  // This may overwrite the previous pixBkg when multiple chunks are covered
248  // So effectively, it will always have the background of the bottom right map coverage
249  // Could manage priorities here and ensure the center determines the background
250  // - but it's just for the corner case of map designers switching background material within a single patch.
251  activation.Add(block_x1, block_y1, shape_idx, 0, 0, pixBkg);
252  activation.Add(block_x2, block_y1, shape_idx, 1, 0, pixBkg);
253  activation.Add(block_x1, block_y2, shape_idx, 0, 1, pixBkg);
254  activation.Add(block_x2, block_y2, shape_idx, 1, 1, pixBkg);
255  }
256  }
257  }
258  }
259  }
260 
261  // Step 2: Draw texture on all active shapes
262  for (int32_t y = y0; y < y1; ++y)
263  {
264  int32_t block_y = y / data.Hgt;
265  int32_t blockpos_y = y % data.Hgt;
266  int32_t subblock_y = (blockpos_y >= data.Hgt / 2) ? 1 : 0;
267  for (int32_t x = x0; x < x1; ++x)
268  {
269  int32_t block_x = x / data.Wdt;
270  int32_t blockpos_x = x % data.Wdt;
271  int32_t subblock_x = (blockpos_x >= data.Wdt / 2) ? 1 : 0;
272  int32_t shape_idx = data._GetPix(blockpos_x, blockpos_y);
273  if (shape_idx == Shape_None) continue;
274  uint8_t pixBg = 0;
275  int32_t act = activation.Get(block_x, block_y, shape_idx, subblock_x, subblock_y, &pixBg);
276  if (!act || act < shape_pixnum[shape_idx] * min_overlap_ratio / 100) continue;
277  // Shape active at this pixel. Draw it.
278  ::Landscape._SetPix2(x, y, iTexture, pixBg);
279  }
280  }
281 }
int Hgt
Definition: CSurface8.h:28
BYTE _GetPix(int x, int y) const
Definition: CSurface8.h:54
uint8_t BYTE
BYTE GetPix(int iX, int iY) const
Definition: CSurface8.h:49
int32_t GetMaxPolyHeight() const
C4Landscape Landscape
int32_t GetHeight() const
int Wdt
Definition: CSurface8.h:28
int32_t GetMaxPolyWidth() const
int32_t GetWidth() const
bool _SetPix2(int32_t x, int32_t y, BYTE fgPix, BYTE bgPix)

Here is the call graph for this function:

Here is the caller graph for this function:

int32_t C4TextureShape::GetHeight ( ) const
inline

Definition at line 42 of file C4TextureShape.h.

References CSurface8::Hgt.

Referenced by GetMaxPolyHeight().

42 { return data.Hgt; }
int Hgt
Definition: CSurface8.h:28

Here is the caller graph for this function:

int32_t C4TextureShape::GetMaxPolyHeight ( ) const
inline

Definition at line 46 of file C4TextureShape.h.

References GetHeight().

Referenced by Draw(), C4Landscape::DrawBox(), C4Landscape::DrawBrush(), and C4Landscape::DrawLine().

46 { return GetHeight() / 4; }
int32_t GetHeight() const

Here is the call graph for this function:

Here is the caller graph for this function:

int32_t C4TextureShape::GetMaxPolyWidth ( ) const
inline

Definition at line 45 of file C4TextureShape.h.

References GetWidth().

Referenced by Draw(), C4Landscape::DrawBox(), C4Landscape::DrawBrush(), and C4Landscape::DrawLine().

45 { return GetWidth() / 4; }
int32_t GetWidth() const

Here is the call graph for this function:

Here is the caller graph for this function:

int32_t C4TextureShape::GetWidth ( ) const
inline

Definition at line 41 of file C4TextureShape.h.

References CSurface8::Wdt.

Referenced by GetMaxPolyWidth().

41 { return data.Wdt; }
int Wdt
Definition: CSurface8.h:28

Here is the caller graph for this function:

bool C4TextureShape::Load ( C4Group group,
const char *  filename,
int32_t  base_tex_wdt,
int32_t  base_tex_hgt 
)

Definition at line 40 of file C4TextureShape.cpp.

References CSurface8::_SetPix(), Clear(), Config, CSurface8::Create(), C4ConfigDeveloper::DebugShapeTextures, C4Config::Developer, StdBuf::getMData(), CPNGFile::GetPix(), StdBuf::getSize(), CSurface8::Hgt, CPNGFile::iHgt, CPNGFile::iWdt, CPNGFile::Load(), C4Group::LoadEntry(), LogF(), and CSurface8::Wdt.

41 {
42  Clear();
43  // Material shapes loading
44  StdBuf png_data;
45  if (!group.LoadEntry(filename, &png_data)) return false;
46  CPNGFile png;
47  if (!png.Load(static_cast<BYTE *>(png_data.getMData()), png_data.getSize())) return false;
48  assert(base_tex_wdt > 0);
49  int32_t zoom = png.iWdt / base_tex_wdt;
50  if (base_tex_wdt * zoom != static_cast<int32_t>(png.iWdt) || base_tex_hgt * zoom != static_cast<int32_t>(png.iHgt))
51  {
52  LogF("ERROR: Material shape texture %s size (%d,%d) not a multiple of associated texture size (%d,%d). Not loading.", filename, int(png.iWdt), int(png.iHgt), int(base_tex_wdt), int(base_tex_hgt));
53  return false;
54  }
55  // Prepare wrap info
56  shape_border_x.resize(255, false);
57  shape_border_y.resize(255, false);
58  // Create shape data surface as downscaled version where equal pixel colors are assigned the same index
59  std::map<uint32_t, uint8_t> clr2shape;
60  std::vector<int32_t> first_px_pos_x(255), first_px_pos_y(255);
61  if (!data.Create(base_tex_wdt, base_tex_hgt)) return false;
62  for (int32_t y = 0; y < data.Hgt; ++y)
63  {
64  for (int32_t x = 0; x < data.Wdt; ++x)
65  {
66  uint32_t px = png.GetPix(x * zoom, y * zoom);
67  uint8_t px_data;
68  if ((px & 0xff000000u) == 0u)
69  {
70  // Fully transparent pixels are not part of a shape
71  px_data = Shape_None;
72  }
73  else
74  {
75  // Otherwise, ignore alpha and lookup
76  px &= 0xffffff;
77  auto shape_idx = clr2shape.find(px);
78  if (shape_idx == clr2shape.end())
79  {
80  // New shape
81  px_data = num_shapes;
82  clr2shape[px] = num_shapes;
83  shape_pixnum.push_back(1);
84  first_px_pos_x[num_shapes] = x;
85  first_px_pos_y[num_shapes] = y;
86  ++num_shapes;
87  if (num_shapes >= 255)
88  {
89  LogF("Material shape texture %s invalid: Too many shape colors (>=255).", filename);
90  Clear();
91  return false;
92  }
93  }
94  else
95  {
96  // Another pixel of previous shape
97  px_data = shape_idx->second;
98  ++shape_pixnum[px_data];
99  }
100  // Remember wrapping
101  if (!x || x == data.Wdt - 1) shape_border_x[px_data] = true;
102  if (!y || y == data.Hgt - 1) shape_border_y[px_data] = true;
103  }
104  data._SetPix(x, y, px_data);
105  }
106  }
107  // Show a summary about found shapes in this texture
109  {
110  LogF("Shape texture summary for %s (%d x %d downscaled to %d x %d):", filename, (int)png.iWdt, (int)png.iHgt, (int)base_tex_wdt, (int)base_tex_wdt);
111  for (auto iter : clr2shape)
112  {
113  unsigned int clr = iter.first;
114  int i = iter.second;
115  LogF(" Color 0x%08x: %d pixels. First seen pos: %d/%d", clr, int(shape_pixnum[i]), int(first_px_pos_x[i]), int(first_px_pos_y[i]));
116  }
117  }
118 
119  return true;
120 }
C4Config Config
Definition: C4Config.cpp:831
Definition: StdBuf.h:37
DWORD GetPix(int iX, int iY)
Definition: StdPNG.cpp:173
int Hgt
Definition: CSurface8.h:28
bool Create(int iWdt, int iHgt)
Definition: CSurface8.cpp:78
bool LoadEntry(const char *szEntryName, char **lpbpBuf, size_t *ipSize=nullptr, int iAppendZeros=0)
Definition: C4Group.cpp:1893
int32_t DebugShapeTextures
Definition: C4Config.h:88
size_t getSize() const
Definition: StdBuf.h:109
unsigned long iHgt
Definition: StdPNG.h:44
C4ConfigDeveloper Developer
Definition: C4Config.h:253
void _SetPix(int iX, int iY, BYTE byCol)
Definition: CSurface8.h:44
int Wdt
Definition: CSurface8.h:28
unsigned long iWdt
Definition: StdPNG.h:44
bool Load(BYTE *pFile, int iSize)
Definition: StdPNG.cpp:153
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:253
void * getMData()
Definition: StdBuf.h:108

Here is the call graph for this function:


The documentation for this class was generated from the following files: