Привет!
Тема создания LiveWallpaper под Android уже хорошо обкатана: есть туториалы на чистой Java, есть туториалы на Java с OpenGL ES 1.0/2.0, есть… да чего только нет!
Сегодня мы посмотрим, как быстро сделать LiveWallpaper под Android на С++ используя Linderdaum Engine и GLSL.
Прежде всего нам понадобится настроенный Linderdaum Engine. Про то, как его настроить, был пост на Хабре: http://habrahabr.ru/post/121062/
В качестве источника вдохновения воспользуемся сайтом: http://www.chromeexperiments.com/webgl Там есть наборы image-space эффектов на WebGL, которые можно взять за отправную точку (шейдеры WebGL и OpenGL ES 2 совместимы).
Начнём вот с такого кода на С++, который и будет представлять всё наше приложение:
#include "Linderdaum.h"
sEnvironment* Env = NULL;
clPtr<clRenderState> Background = NULL;
void DrawOverlay(LEvent Event, const LEventArgs& Args)
{
Env->Renderer->GetCanvas()->FullscreenRect( Background );
}
APPLICATION_ENTRY_POINT
{
Env = new sEnvironment();
Env->DeployDefaultEnvironment( NULL, "..\..\CommonMedia" );
Env->Connect( L_EVENT_DRAWOVERLAY, Utils::Bind( &DrawOverlay ) );
Background = Env->Resources->LoadShader( "Background.shader" );
Env->RunApplication( DEFAULT_CONSOLE_AUTOEXEC );
APPLICATION_EXIT_POINT( Env );
}
APPLICATION_SHUTDOWN
{
Background = NULL;
}
Совсем не много, правда? Положем его в Test_LiveWallpaper.cpp и с С++ на этом действительно всё закончено.
Приступаем к шейдерам. Сначала напишем Background.shader:
Object("clRenderState")
{
ShaderProgram "Plane.sp"
}
и Plane.sp:
/*VERTEX_PROGRAM*/
#include Layout.sp
in vec4 in_Vertex;
in vec4 in_TexCoord;
out vec2 Coord;
void main()
{
gl_Position = in_ModelViewProjectionMatrix * in_Vertex;
Coord = in_TexCoord.xy;
}
/*FRAGMENT_PROGRAM*/
in vec2 Coord;
uniform float ENGINE_TIME;
out vec4 out_FragColor;
// Plane deformations by Anton Platonov <platosha@gmail.com> twitter.com/platosha
const float TAU = 5.2832;
void main( void )
{
vec2 position = Coord;
vec2 p = -1.0 + 2.0 * position;
float alpha = -ENGINE_TIME * 0.13;
float sinA = sin(alpha), cosA = cos(alpha);
p = vec2(cosA*p.x+sinA*p.y, -sinA*p.x+cosA*p.y);
vec2 q = p;
float zr = 1.0/length(q);
float zp = 1.0/abs(q.y);
float mc = sin(ENGINE_TIME*0.16)*.5 + .5;
float z = mix(zr, zp, mc);
float ur = 5.0*atan(q.x*sign(q.y), abs(q.y))/TAU + cos(0.2*z*TAU+ENGINE_TIME*1.37) * 1.2 * sin( ENGINE_TIME * 0.21 );
float up = q.x*z;
float u = mix(ur, up, mc);
vec2 uv = vec2(u, (1.0+mc*2.0)*z);
float mv = sin(ENGINE_TIME * 0.55);
uv = mix(uv, q, 0.0);
float color = 0.0;
color = cos(uv.x*TAU) * cos(uv.y*TAU + ENGINE_TIME*7.7);
color = pow(abs(cos(color*TAU)), 3.0);
float color2 = 0.0;
color2 = cos(uv.x*TAU*2.0);
color2 -= 0.25;
float shadow = 1.0/(z*z);
vec3 rc = vec3(0.9, 1.0, 0.8)*color + vec3(0.3, 0.7, 0.6)*color2;
rc *= shadow;
out_FragColor = vec4( rc, 1.0 );
}
На этом этапе уже можно потестировать приложение под виндой. Просто добавив в проект и запустив. На экране будет вот такая картинка:
Для того, чтобы всё заработало на Android, придётся ещё немного поработать. Правда на Java придётся написать и того меньше. Test_LiveWallpaperService.java:
package com.linderdaum.engine.Test_LiveWallpaper;
import com.linderdaum.engine.LinderdaumEngineService;
public class Test_LiveWallpaperService extends LinderdaumEngineService
{
@Override
public LinderdaumEngineService.GLEngine onCreateEngine()
{
return new LinderdaumEngineService.GLEngine();
}
}
Ещё понадобится манифест AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.linderdaum.engine.Test_LiveWallpaper"
android:versionCode="1"
android:versionName="1.0.0">
<supports-screens
android:smallScreens="false"
android:normalScreens="true"
android:largeScreens="true"
android:anyDensity="true" />
<uses-sdk android:minSdkVersion="7" />
<uses-feature android:glEsVersion="0x00020000"/>
<uses-feature android:name="android.software.live_wallpaper"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:label="Test_LiveWallpaper"
android:icon="@drawable/icon"
android:installLocation="preferExternal"
android:debuggable="false">
<service android:name="com.linderdaum.engine.Test_LiveWallpaper.Test_LiveWallpaperService"
android:label="Test_LiveWallpaper"
android:permission="android.permission.BIND_WALLPAPER">
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
</intent-filter>
<meta-data android:name="android.service.wallpaper" android:resource="@xml/wallpaper" />
</service>
</application>
</manifest>
Всё! Остальные файлы есть в обычном проекте Linderdaum для Android. Запускаем ndk-build и ant copy-common-media debug. Можно устанавливать Test_LiveWallpaper-debug.apk на девайс — новые живые обои появятся в списке.
P.S. Такой шейдер весьма тяжёлый для мобильного GPU, поэтому батарейка будет поедаться достаточно быстро. Экспериментируйте!
Автор: CorporateShark