/* * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "image-effect-source.h" #include #include #include namespace Dali::ParticleEffect { namespace { Vector4 GetColorAt(uint32_t x, uint32_t y, Devel::PixelBuffer& buffer) { if(buffer.GetPixelFormat() == Pixel::Format::RGBA8888) { const auto ptr = reinterpret_cast(buffer.GetBuffer()); auto value = *(ptr + x + (y * buffer.GetHeight())); auto rgba = reinterpret_cast(&value); return Vector4(float(rgba[0]) / 255.0f, float(rgba[1]) / 255.0f, float(rgba[2]) / 255.0f, 1.0f); } else { auto rgba = reinterpret_cast(buffer.GetBuffer() + (y*buffer.GetWidth()*3) + (x*3)); return Vector4(float(rgba[0]) / 255.0f, float(rgba[1]) / 255.0f, float(rgba[2]) / 255.0f, 1.0f); } } } static float LIFETIME = 50000.0f; // we need infinite lifetime? ImageExplodeEffectSource::ImageExplodeEffectSource(ParticleEmitter& emitter) : mEmitter(emitter) { } ImageExplodeEffectSource::ImageExplodeEffectSource(ParticleEmitter& emitter, const std::string& imageFileName, uint32_t width, uint32_t height) : mEmitter(emitter) { // Create texture std::string filePath(DEMO_IMAGE_DIR); filePath += imageFileName; ImageDimensions dimensions(width, height); // Pixel buffer will be used as a source of pixels (populating colors of particles based on image pixels) Devel::PixelBuffer pixelBuffer = Dali::LoadImageFromFile(filePath, dimensions, FittingMode::SHRINK_TO_FIT, SamplingMode::DEFAULT, false); mImageWidth = pixelBuffer.GetWidth(); mImageHeight = pixelBuffer.GetHeight(); mPixelBuffer = pixelBuffer; } void ImageExplodeEffectSource::Init() { auto handle = mEmitter.GetHandle(); if(handle) { mStreamBasePos = handle.GetParticleList().AddLocalStream(Vector3::ZERO); } } uint32_t ImageExplodeEffectSource::Update(ParticleList& particleList, uint32_t count) { if(!mShouldEmit || !mStreamBasePos) { return 0; } if(mPixelBuffer.GetPixelFormat() != Dali::Pixel::RGBA8888 && mPixelBuffer.GetPixelFormat() != Dali::Pixel::RGB888) { return 0; } auto i = 0u; float particleScale = 4.0f; float pixelSize = 2.0f; auto halfWidth = (float(mImageWidth)*0.5f) * particleScale; auto halfHeight = (float(mImageHeight)*0.5f) * particleScale; for(auto y = 0u ; y < mImageHeight; ++y) { for(auto x = 0u; x < mImageWidth; ++x) { if(i < particleList.GetCapacity()) { // Ignore count, populating all pixels instantly (emitter must account for all the points) auto particle = particleList.NewParticle(LIFETIME); auto& basePosition = particle.GetByIndex(mStreamBasePos); auto& position = particle.Get(ParticleStream::POSITION_STREAM_BIT); auto& color = particle.Get(ParticleStream::COLOR_STREAM_BIT); auto& velocity = particle.Get(ParticleStream::VELOCITY_STREAM_BIT); auto& scale = particle.Get(ParticleStream::SCALE_STREAM_BIT); color = GetColorAt(x, y, mPixelBuffer); // Set basePosition position = basePosition = Vector3(float(x) * particleScale - halfWidth, float(y)* particleScale - halfHeight, 0); scale = Vector3(pixelSize, pixelSize, 1); velocity = Vector3::ZERO; } ++i; } } mShouldEmit = false; return mImageWidth * mImageHeight; } } // namespace Dali::ParticleEffect