Ребят, делаю приложение что то типа слайд-шоу. Сейчас застряла на эффектах. Вернее не на самих эффектах а на их расчетах. Моя проблема заключается в том, что я не могу рассчитать скорость показа того или иного эффекта - слишком много неизвестных получается..
Изначально мы знаем
1.размер картинки (скажем 400*300 пикселов, значит в итоге имеем 120к пикселов) пусть будет pixelCount
2.на первой итерации эффекта можем вычислить время 1 итерации (ticks), скажем iterationTime. Оно зависит от многих показателей, от производительности машины, от количества операций по копированию пиксела(ов), от способа копирования (либо просто пикселом, либо побайтно, либо через указатели и т.д.), от сложности рассчета эффекта ...
3. заданное пользователем время выполнения эффекта пусть будет duration=2.5 сек
Вот ,наверное, пожалуй и все входные данные ( во всяком случае те, которые мне пришли в голову)
Хотя, наверное, еще можно учесть что в кино показывают 24 кадра в секунду и возможно надо учитывать время вывода самой картинки (копирование на контекст) каждый кадр хотя врядли это будет играть существенную роль. Возможно это тоже придется учитывать
Как рассчитать зависимость через сколько скопированных пикселов мне надо обновить изображение чтобы уложиться в заданное время, и в тоже время присутствовала плавность показа эффекта.
На данные момент у меня внутри цикла примерно так: if (counter % speed == 0) ShowImage(); (% - это целочисленное деление ,аналог Mod из VB на всякий случай:) speed - это просто подобранное число..
Но это не то, потому что на разных размерах картинки разная скорость получается, и вообще это кривое решение((
С одной стороны если картинка маленькая, а время задано большое, и итерация выполняется довольно быстро на простом эффекте, то можно либо усыпить поток на какое то время на каждой итерации(чтобы с временем не пролететь), а с другой стороны можно уменьшить количество пикселов через которые надо обновлять картинку, что даст бОльшую плавность при перерисовках контекста.
ВОт как рассчитать эту зависимость по уму? Может кто дельное что подскажет, а то с математикой у меня всегда проблемы были?
ника, а может пойти вообще другим путем?
Ведь пользователь выбирает время просмотра, а не время открытия + просмотр, так и дай в конце выполнения эфекта код на запуск таймера на время которое он указал и все, будет тебе и плавность и все остальное.
Т.е. ты предлогаешь разложить изображение грубо говоря на сотню кадров, а потом по таймеру их показывать??? Не думаю, что это хороший вариант.. держать в памяти сотню картинок - по меньшей мере расточительно
Ты-же сказала что с эффектами нет проблем?
Для их реализации нужно всего 2 или 3 как захочешь Picture, я предлагал выбор времени между эффектами, а не все время просмотра.То есть 3 сек например, эатем следующий эффект & картинка и так далее.
Как насчет того, чтобы реализовать стандартными средствами два потока: в одном просчитывается эффект с заданным интервалом (в памяти вычисление происходит по-любому быстрее), а во втором выводится текущее состояние эффекта с максимально возможной скоростью для данного компа (это более медленная операция, чем просчет эффекта)?
Сначала определись, какими средствами ты будешь выводить изображение. Желательно делать с помощью низкоуровневых графических АПИ (OGL, DX). Они позволят добиться плавности эффектов.
//-------
Неплохо примеры посмотреть.
Я бы рад помочь, но у меня под рукой пример движка на С++, с использованием OGL да еще и под Symbian
Боцман, ты по видимому недопонял о чем речь. С самими эффектами нет проблем, и мне не нужны куча Picture, куда я буду выводить изображение значение тоже не имеет - это может быть и форма и кнопка и что угодно, на что можно перенести изображение..
Суть в следующем:
Я через указатель получаю из памяти исходный массив байт картинки (он не прикосновенный), далее создаю еще один массив байт - пустой. Для создания какого либо эффекта мне необходимо из исходного в пустой скопировать в опреленной последовательности определенное количество байт и показать картинку на каждой (или через какое то количество) итерации алгоритма создания эффекта с полученным промежуточным результатом.
Я не спрашиваю как мне вывести изображение, или как преобразовать массив байт в картинку и т.д.
Мой вопрос заключается в том, чтобы рассчитать через какое количество скопированных байт(или пикселов) мне показать промежуточную картинку для соблюдения условия времени длительности эффекта независимо от размеров картинки и производительности машины...
vito: я использую только GDI+ (С#) , не факт что DX будет стоять на машине клиента
Как насчет того, чтобы реализовать стандартными средствами два потока: в одном просчитывается эффект с заданным интервалом
el-paso: Примерно так и сделано. В отдельном потоке идет просчет эффекта и копирование из одного массива в другой затем промежуточный результат передается в основной поток для отображения юзеру. Задача и заключается именно в том,чтобы рассчитать этот интервал когда надо передавать промежуточный результат в основной поток. Если привязаться ко врмения эффекта, то скажем каждые 100мс показывать картинку, но если картинка маленькая - то за эти 100мс весь эффект просчитается и визуально ничего не будет заметно (( Вообщем я пока в полном тупике, тут надо учитывать при расчетах кучу параметров - тут просто голая математика
// ---------------------------------------------------------
// CSlideshowContainer::DrawCallBack( TAny* aInstance )
// Called by the CPeriodic in order to draw the graphics
// ---------------------------------------------------------
//
TInt CSlideshowContainer::DrawCallBack( TAny* aInstance )
{
CSlideshowContainer* instance = (CSlideshowContainer*) aInstance;
// Update the frame counts
instance->iFrame++;
// Compute the elapsed time in seconds since the startup of the example
#ifdef __WINS__
// In the emulator the tickcount runs at 200Hz
GLfloat timeSecs = ( (GLfloat) ( User::NTickCount() - instance->iStartTimeTicks ) ) / 200.f;
#else
// In the device the tickcount runs at 1000hz (as intended)
GLfloat timeSecs = ( (GLfloat) ( User::NTickCount() - instance->iStartTimeTicks ) ) / 1000.f;
#endif
// Compute the elapsed time since last frame was drawn. Note that due to the
// resolution of the system timer this value can be 0.0 even though new frames are being rendered.
// This applies especially when running the emulator on a PC.
GLfloat deltaTimeSecs = instance->iLastFrameTimeSecs - timeSecs;
// Set the current time to be the last frame time for the upcoming frame
instance->iLastFrameTimeSecs = timeSecs;
if ( instance->iSlideshow->GetState() == CSlideshow::ERunning )
{
// Call the main OpenGL ES Symbian rendering 'loop'
instance->iSlideshow->AppCycle( instance->iFrame, timeSecs, deltaTimeSecs );
// Call eglSwapBuffers, which blit the graphics to the window
eglSwapBuffers( instance->iEglDisplay, instance->iEglSurface );
// Suspend the current thread for a short while. Give some time
// to other threads and AOs, avoids the ViewSrv error in ARMI and
// THUMB release builds. One may try to decrease the callback
// function instead of this.
if ( !(instance->iFrame % 50) )
{
// Reset inactivity timer to keep the background light on
User::ResetInactivityTime();
User::After(0);
}
}
// ----------------------------------------------------------------------------
// CSlideshow::AppCycle
// Draws and animates the objects.
// aFrame = Number of the frame to be rendered.
// aTimeSecs = Seconds elapsed since the application started running.
// aDeltaTimeSecs = Seconds elapsed since last call to AppCycle().
// ----------------------------------------------------------------------------
//
void CSlideshow::AppCycle( TInt /*aFrame*/,
TReal /*aTimeSecs*/,
TReal aDeltaTimeSecs )
{
// Make sure the timestep is non-zero, since otherwise the animation wouldn't progress at all.
if (aDeltaTimeSecs < 0.04)
aDeltaTimeSecs = 0.04;
// Stop the transition if it's complete
if (iTransitionRenderer && iTransitionTime <= 0)
{
delete iTransitionRenderer;
iTransitionRenderer = 0;
iCurrentPicture = iNextPicture;
}
// Advance the slideshow if we have been requested to
if (iRequestedPictureDelta && !iTransitionRenderer)
{
iTransitionRenderer = CreateTransitionRenderer((iRequestedPictureDelta > 0) ? ENext : EPrevious);
iTransitionTime = 1.0;
// Render the current picture. If there is no transition going on, enable
// bilinear filtering to improve image quality.
iStaticRenderer.Render(iPictures[iCurrentPicture], iTransitionRenderer == NULL);
// Render the transition and the next picture
if (iTransitionTime > 0 && iTransitionRenderer)
{
iTransitionRenderer->Render(iPictures[iNextPicture], iTransitionTime);
// Accelerate the transition speed if we are many pictures behind
iTransitionTime -= aDeltaTimeSecs * (Abs(iRequestedPictureDelta) + 1);
}
}
Зачем что-то рассчитывать? Нельзя просто в каждой итерации проверять, сколько времени прошло с последнего отображения, либо запустить рядом тред, который будет нужное время спать, а потом просыпаться и выводить картинку?
vito: Огромное спасибо, кажется это именно то что надо, буду разбираться.
Sharp: Что то я не совсем поняла вашу мысль, можно подробней описать вашу идею?
либо запустить рядом тред, который будет нужное время спать, а потом просыпаться и выводить картинку?
А откуда этот тред будет брать картинку для вывода? Из какого нибудь массива? Тогда Ваш способ подразумевает хранение всех промежуточных кадров в памяти ( что и предлогали тут ранее) Разве это не расточительство памяти? Или я что то не так поняла?