Android native 层用OpenGL ES在屏幕模拟流水灯
Native C开发OpenGL
参照Android开机动画,自己实现了在native层模拟led流水灯的代码。
Android本身OpenGL的参考代码在/frameworks/native/opengl/tests下,
但是做出来的效果不是自己想要的,参考网友资料,特记录如下;
源码实现如下
Simled.cpp
:
#define LOG_NDEBUG 0
#define LOG_TAG "Simled"
#include <stdint.h>
#include <sys/types.h>
#include <math.h>
#include <fcntl.h>
#include <utils/misc.h>
#include <signal.h>
#include <pthread.h>
#include <sys/select.h>
#include <cutils/properties.h>
#include <androidfw/AssetManager.h>
#include <binder/IPCThreadState.h>
#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/DisplayInfo.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <SkBitmap.h>
#include <SkStream.h>
#include <SkImageDecoder.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <EGL/eglext.h>
#include "Simled.h"
#define EXIT_PROP_NAME "service.bootanim.exit"
#define SIMLED_W 30
#define SIMLED_H 40
extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *request,
struct timespec *remain);
namespace android {
// ---------------------------------------------------------------------------
Simled::Simled() : Thread(false)
{
mSession = new SurfaceComposerClient();
}
Simled::~Simled() {
}
void Simled::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
run("Simled", PRIORITY_DISPLAY);
}
}
sp<SurfaceComposerClient> Simled::session() const {
return mSession;
}
void Simled::binderDied(const wp<IBinder>&)
{
// woah, surfaceflinger died!
ALOGD("SurfaceFlinger died, exiting...");
// calling requestExit() is not enough here because the Surface code
// might be blocked on a condition variable that will never be updated.
kill( getpid(), SIGKILL );
requestExit();
}
status_t Simled::readyToRun() {
// initialize opengl and egl
const EGLint attribs[] = {
EGL_ALPHA_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 0,
EGL_NONE
};
EGLint numConfigs;
EGLConfig config;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
context = eglCreateContext(display, config, NULL, NULL);
mDisplay = display;
mContext = context;
// init the leds
for(int i = 0; i < 4; i++){
// create the native surface
String8 name("Simled");
const char index = '0'+(char)i;
name.append(&index);
sp<SurfaceControl> control = session()->createSurface(name,
SIMLED_W, SIMLED_H, PIXEL_FORMAT_RGBA_8888);
SurfaceComposerClient::openGlobalTransaction();
control->setLayer(0x40000000);
// set led position
control->setPosition(i * SIMLED_W * 2, 0);
SurfaceComposerClient::closeGlobalTransaction();
sp<Surface> s = control->getSurface();
EGLSurface surface;
EGLint w, h;
surface = eglCreateWindowSurface(display, config, s.get(), NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
mWidth = w;
mHeight = h;
// set led color
mLeds[i].r = i==0 ? 1.0f : 0.0f;
mLeds[i].g = i==1 ? 1.0f : 0.0f;
mLeds[i].b = i==2 ? 1.0f : 0.0f;
mLeds[i].surface = surface;
mLeds[i].flingerSurfaceControl = control;
mLeds[i].flingerSurface = s;
}
return NO_ERROR;
}
bool Simled::threadLoop()
{
bool r;
drawLeds();
for(int i = 0; i < 2; i++){
r = test();
}
// exit
requestExit();
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(mDisplay, mContext);
for(int i = 0; i < 4; i++){
eglDestroySurface(mDisplay, mLeds[i].surface);
mLeds[i].flingerSurface.clear();
mLeds[i].flingerSurfaceControl.clear();
}
eglTerminate(mDisplay);
IPCThreadState::self()->stopProcess();
return r;
}
bool Simled::drawLeds()
{
for(int i = 0; i < 4; i++){
if (eglMakeCurrent(mDisplay, mLeds[i].surface, mLeds[i].surface, mContext) == EGL_FALSE)
return false;
// clear screen
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glClearColor(
mLeds[i].r,
mLeds[i].g,
mLeds[i].b,
1);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mDisplay, mLeds[i].surface);
}
return false;
}
bool Simled::showLed(int index){
SurfaceComposerClient::openGlobalTransaction();
mLeds[index].flingerSurfaceControl->show();
SurfaceComposerClient::closeGlobalTransaction();
return true;
}
bool Simled::hideLed(int index){
SurfaceComposerClient::openGlobalTransaction();
mLeds[index].flingerSurfaceControl->hide();
SurfaceComposerClient::closeGlobalTransaction();
return true;
}
bool Simled::test()
{
for(int i = 0; i < 4; i++){
hideLed(i);
usleep(1*1000000);
showLed(i);
}
return false;
}
// ---------------------------------------------------------------------------
}
; // namespace android
Simled_main.cpp
:
#define LOG_TAG "Simled"
#include <cutils/properties.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <utils/threads.h>
#if defined(HAVE_PTHREADS)
# include <pthread.h>
# include <sys/resource.h>
#endif
#include "Simled.h"
using namespace android;
// ---------------------------------------------------------------------------
int main(int argc, char** argv)
{
#if defined(HAVE_PTHREADS)
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
#endif
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
sp<Simled> led = new Simled();
IPCThreadState::self()->joinThreadPool();
return 0;
}
Simled.h
:
#ifndef ANDROID_SIMLED_H
#define ANDROID_SIMLED_H
#include <stdint.h>
#include <sys/types.h>
#include <androidfw/AssetManager.h>
#include <utils/Thread.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
class SkBitmap;
namespace android {
class Surface;
class SurfaceComposerClient;
class SurfaceControl;
// ---------------------------------------------------------------------------
class Simled : public Thread, public IBinder::DeathRecipient
{
public:
enum {
eOrientationDefault = 0,
eOrientation90 = 1,
eOrientation180 = 2,
eOrientation270 = 3,
};
Simled();
virtual ~Simled();
sp<SurfaceComposerClient> session() const;
private:
virtual bool threadLoop();
virtual status_t readyToRun();
virtual void onFirstRef();
virtual void binderDied(const wp<IBinder>& who);
struct Led {
GLclampf r;
GLclampf g;
GLclampf b;
EGLSurface surface;
sp<SurfaceControl> flingerSurfaceControl;
sp<Surface> flingerSurface;
};
bool drawLeds();
bool showLed(int index);
bool hideLed(int index);
bool test();
sp<SurfaceComposerClient> mSession;
int mWidth;
int mHeight;
EGLDisplay mDisplay;
EGLContext mContext;
Led mLeds[4];
};
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_SIMLED_H
Android.mk
:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
simled_main.cpp \
Simled.cpp
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_C_INCLUDES += external/tinyalsa/include
LOCAL_SHARED_LIBRARIES := \
libcutils \
liblog \
libandroidfw \
libutils \
libbinder \
libui \
libskia \
libEGL \
libGLESv1_CM \
libgui \
libtinyalsa \
libmedia
LOCAL_MODULE:= simled
ifdef TARGET_32_BIT_SURFACEFLINGER
LOCAL_32_BIT_ONLY := true
endif
include $(BUILD_EXECUTABLE)
源码中涉及了Android-Binder进程间通讯机制 ,本人小白,刚入门Android学习,等学有所成再补上这部分知识。