45 m_numPatternX = m_numPatternY = m_numPatternZ = 0;
46 m_animationPhases = 0;
50 m_countPainterListeningRef = 0;
118 fin->
addU8(m_realSize);
120 fin->
addU8(m_layers);
121 fin->
addU8(m_numPatternX);
122 fin->
addU8(m_numPatternY);
123 fin->
addU8(m_numPatternZ);
124 fin->
addU8(m_animationPhases);
127 if(m_animationPhases > 1 && m_animator !=
nullptr) {
132 for(
int i : m_spritesIndex) {
144 m_category = category;
146 int count = 0, attr = -1;
190 if(attr > 0 && attr <= 15)
228 m_displacement.
x = fin->
getU16();
229 m_displacement.
y = fin->
getU16();
231 m_displacement.
x = 8;
232 m_displacement.
y = 8;
234 m_attribs.
set(attr,
true);
242 m_attribs.
set(attr, light);
254 m_attribs.
set(attr, market);
259 m_elevation = fin->
getU16();
260 m_attribs.
set(attr, m_elevation);
273 m_attribs.
set(attr,
true);
280 m_id, m_category, count, attr));
283 const uint8 groupCount = hasFrameGroups ? fin->
getU8() : 1;
285 m_animationPhases = 0;
286 int totalSpritesCount = 0;
288 std::vector<Size> sizes;
289 std::vector<int> total_sprites;
291 for(
int i = 0; i < groupCount; ++i) {
294 frameGroupType = fin->
getU8();
298 m_size =
Size(width, height);
299 sizes.push_back(m_size);
300 if(width > 1 || height > 1) {
301 m_realSize = fin->
getU8();
302 m_exactSize = std::min<int>(m_realSize, std::max<int>(width * 32, height * 32));
306 m_layers = fin->
getU8();
307 m_numPatternX = fin->
getU8();
308 m_numPatternY = fin->
getU8();
310 m_numPatternZ = fin->
getU8();
314 const int groupAnimationsPhases = fin->
getU8();
315 m_animationPhases += groupAnimationsPhases;
322 m_animator = animator;
323 else m_idleAnimator = animator;
326 const int totalSprites = m_size.
area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * groupAnimationsPhases;
327 total_sprites.push_back(totalSprites);
329 if(totalSpritesCount + totalSprites > 4096)
332 m_spritesIndex.resize(totalSpritesCount + totalSprites);
333 for(
int j = totalSpritesCount; j < (totalSpritesCount + totalSprites); ++j)
336 totalSpritesCount += totalSprites;
339 if(sizes.size() > 1) {
341 for(
auto& s : sizes) {
345 size_t expectedSize = m_size.
area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases;
346 if(expectedSize != m_spritesIndex.size()) {
347 std::vector<int> sprites(std::move(m_spritesIndex));
348 m_spritesIndex.clear();
349 m_spritesIndex.reserve(expectedSize);
350 for(
size_t i = 0, idx = 0; i < sizes.size(); ++i) {
351 int totalSprites = total_sprites[i];
352 if(m_size == sizes[i]) {
353 for(
int j = 0; j < totalSprites; ++j) {
354 m_spritesIndex.push_back(sprites[idx++]);
358 size_t patterns = (totalSprites / sizes[i].area());
359 for(
size_t p = 0; p < patterns; ++p) {
360 for(
int x = 0; x < m_size.
width(); ++x) {
361 for(
int y = 0; y < m_size.
height(); ++y) {
362 if(x < sizes[i].width() && y < sizes[i].height()) {
363 m_spritesIndex.push_back(sprites[idx++]);
366 m_spritesIndex.push_back(0);
374 m_textures.resize(m_animationPhases);
375 m_texturesFramesRects.resize(m_animationPhases);
376 m_texturesFramesOriginRects.resize(m_animationPhases);
377 m_texturesFramesOffsets.resize(m_animationPhases);
385 if(m_spritesIndex.empty())
388 ImagePtr image(
new Image(
Size(32 * m_size.
width() * m_layers * m_numPatternX, 32 * m_size.
height() * m_animationPhases * m_numPatternY * m_numPatternZ)));
389 for(
int z = 0;
z < m_numPatternZ; ++
z) {
390 for(
int y = 0; y < m_numPatternY; ++y) {
391 for(
int x = 0; x < m_numPatternX; ++x) {
392 for(
int l = 0; l < m_layers; ++l) {
393 for(
int a = 0; a < m_animationPhases; ++a) {
394 for(
int w = 0; w < m_size.
width(); ++w) {
395 for(
int h = 0; h < m_size.
height(); ++h) {
396 image->blit(
Point(32 * (m_size.
width() - w - 1 + m_size.
width() * x + m_size.
width() * m_numPatternX * l),
397 32 * (m_size.
height() - h - 1 + m_size.
height() * y + m_size.
height() * m_numPatternY * a + m_size.
height() * m_numPatternY * m_animationPhases *
z)),
407 image->savePNG(fileName);
413 if(node2->tag() ==
"opacity")
414 m_opacity = node2->value<
float>();
415 else if(node2->tag() ==
"notprewalkable")
417 else if(node2->tag() ==
"image")
418 m_customImage = node2->value();
419 else if(node2->tag() ==
"full-ground") {
420 if(node2->value<
bool>())
428 void ThingType::draw(
const Point& dest,
float scaleFactor,
int layer,
int xPattern,
int yPattern,
int zPattern,
int animationPhase,
int reDrawFlags,
LightView* lightView)
433 if(animationPhase >= m_animationPhases)
440 const uint frameIndex = getTextureIndex(layer, xPattern, yPattern, zPattern);
441 if(frameIndex >= m_texturesFramesRects[animationPhase].size())
447 if(scaleFactor != 1.0f) {
448 textureRect = m_texturesFramesOriginRects[animationPhase][frameIndex];
450 textureOffset = m_texturesFramesOffsets[animationPhase][frameIndex];
451 textureRect = m_texturesFramesRects[animationPhase][frameIndex];
454 const Rect screenRect(dest + (textureOffset - m_displacement - (m_size.
toPoint() -
Point(1, 1)) * 32) * scaleFactor,
455 textureRect.
size() * scaleFactor);
458 const bool useOpacity = m_opacity < 1.0f;
478 TexturePtr& animationPhaseTexture = m_textures[animationPhase];
479 if(animationPhaseTexture)
return animationPhaseTexture;
481 bool useCustomImage =
false;
482 if(animationPhase == 0 && !m_customImage.empty())
483 useCustomImage =
true;
486 int textureLayers = 1;
487 int numLayers = m_layers;
494 const int indexSize = textureLayers * m_numPatternX * m_numPatternY * m_numPatternZ;
495 const Size textureSize = getBestTextureDimension(m_size.
width(), m_size.
height(), indexSize);
498 m_texturesFramesRects[animationPhase].resize(indexSize);
499 m_texturesFramesOriginRects[animationPhase].resize(indexSize);
500 m_texturesFramesOffsets[animationPhase].resize(indexSize);
501 for(
int z = 0;
z < m_numPatternZ; ++
z) {
502 for(
int y = 0; y < m_numPatternY; ++y) {
503 for(
int x = 0; x < m_numPatternX; ++x) {
504 for(
int l = 0; l < numLayers; ++l) {
506 const int frameIndex = getTextureIndex(l % textureLayers, x, y,
z);
511 if(!useCustomImage) {
512 for(
int h = 0; h < m_size.
height(); ++h) {
513 for(
int w = 0; w < m_size.
width(); ++w) {
514 const uint spriteIndex = getSpriteIndex(w, h, spriteMask ? 1 : l, x, y,
z, animationPhase);
516 if(!spriteImage) fullImage->setTransparentPixel(
true);
518 if(spriteIndex == 0) {
520 fullImage->setTransparentPixel(
true);
525 spriteImage->overwriteMask(maskColors[l - 1]);
530 fullImage->blit(framePos + spritePos, spriteImage);
539 uint8* p = fullImage->getPixel(fx, fy);
541 drawRect.
setTop(std::min<int>(fy,
static_cast<int>(drawRect.
top())));
542 drawRect.
setLeft(std::min<int>(fx,
static_cast<int>(drawRect.
left())));
543 drawRect.
setBottom(std::max<int>(fy,
static_cast<int>(drawRect.
bottom())));
544 drawRect.
setRight(std::max<int>(fx,
static_cast<int>(drawRect.
right())));
549 m_texturesFramesRects[animationPhase][frameIndex] = drawRect;
551 m_texturesFramesOffsets[animationPhase][frameIndex] = drawRect.
topLeft() - framePos;
560 return animationPhaseTexture;
563 Size ThingType::getBestTextureDimension(
int w,
int h,
int count)
577 const int numSprites = w * h * count;
578 assert(numSprites <= MAX * MAX);
582 Size bestDimension =
Size(MAX, MAX);
583 for(
int i = w; i <= MAX; i <<= 1) {
584 for(
int j = h; j <= MAX; j <<= 1) {
585 Size candidateDimension =
Size(i, j);
586 if(candidateDimension.
area() < numSprites)
588 if((candidateDimension.
area() < bestDimension.
area()) ||
589 (candidateDimension.
area() == bestDimension.
area() && candidateDimension.
width() + candidateDimension.
height() < bestDimension.
width() + bestDimension.
height()))
590 bestDimension = candidateDimension;
594 return bestDimension;
597 uint ThingType::getSpriteIndex(
int w,
int h,
int l,
int x,
int y,
int z,
int a)
600 ((((((a % m_animationPhases)
606 * m_size.
width() + w;
607 assert(index < m_spritesIndex.size());
611 uint ThingType::getTextureIndex(
int l,
int x,
int y,
int z)
613 return ((l * m_numPatternZ +
z)
624 const int frameIndex = getTextureIndex(layer, xPattern, yPattern, zPattern);
625 const Size size = m_texturesFramesOriginRects[animationPhase][frameIndex].size() - m_texturesFramesOffsets[animationPhase][frameIndex].toSize();
643 return m_animationPhases;
651 if(m_exactHeight != -1)
652 return m_exactHeight;
655 const int frameIndex = getTextureIndex(0, 0, 0, 0);
656 const Size size = m_texturesFramesOriginRects[0][frameIndex].size() - m_texturesFramesOffsets[0][frameIndex].toSize();
658 return m_exactHeight = size.
height();
663 if(m_countPainterListeningRef == 0) {
674 ++m_countPainterListeningRef;
679 if(m_countPainterListeningRef == 0)
return false;
681 --m_countPainterListeningRef;
683 if(m_painterListeningEvent && m_countPainterListeningRef == 0) {
689 m_painterListeningEvent->
cancel();
690 m_painterListeningEvent =
nullptr;