google 官方ndk demo解析(二)——bitmap-plasma
来源:互联网 发布:dota 幽鬼攻略知乎 编辑:程序博客网 时间:2024/06/06 01:26
本文将分析bitmap-plasma这个demo。
这是一个使用c代码在bitmap上绘制细胞质效果的demo。
CMakeList.txt
cmake_minimum_required(VERSION 3.4.1)set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")add_library(plasma SHARED plasma.c)# Include libraries needed for plasma libtarget_link_libraries(plasma android jnigraphics log m)
文件很简单,不逐行解释。需要用到jnigraphics库,这是个很小的library,展示一个稳定的,基于C语言的,接口,使本机代码安全地访问Java对象的像素缓冲区的位图。
Plasma.java
public class Plasma extends Activity{ // Called when the activity is first created. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Display display = getWindowManager().getDefaultDisplay(); setContentView(new PlasmaView(this, display.getWidth(), display.getHeight())); } // load our native library static { System.loadLibrary("plasma"); }}// Custom view for rendering plasma.//// Note: suppressing lint wrarning for ViewConstructor since it is// manually set from the activity and not used in any layout.@SuppressLint("ViewConstructor")class PlasmaView extends View { private Bitmap mBitmap; private long mStartTime; // implementend by libplasma.so private static native void renderPlasma(Bitmap bitmap, long time_ms); public PlasmaView(Context context, int width, int height) { super(context); mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); mStartTime = System.currentTimeMillis(); } @Override protected void onDraw(Canvas canvas) { renderPlasma(mBitmap, System.currentTimeMillis() - mStartTime); canvas.drawBitmap(mBitmap, 0, 0, null); // force a redraw, with a different time-based pattern. invalidate(); }}
自定义PlasmaView扩展自View,onDraw()方法会调用native函数renderPlasma(),在Bitmap上进行绘制。
plasma.c
#define LOG_TAG "libplasma"#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)/* Set to 1 to enable debug log traces. */#define DEBUG 0/* Set to 1 to optimize memory stores when generating plasma. */#define OPTIMIZE_WRITES 1/* Return current time in milliseconds */static double now_ms(void){ struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec*1000. + tv.tv_usec/1000.;}/* We're going to perform computations for every pixel of the target * bitmap. floating-point operations are very slow on ARMv5, and not * too bad on ARMv7 with the exception of trigonometric functions. * * For better performance on all platforms, we're going to use fixed-point * arithmetic and all kinds of tricks */typedef int32_t Fixed;#define FIXED_BITS 16#define FIXED_ONE (1 << FIXED_BITS)#define FIXED_AVERAGE(x,y) (((x) + (y)) >> 1)#define FIXED_FROM_INT(x) ((x) << FIXED_BITS)#define FIXED_TO_INT(x) ((x) >> FIXED_BITS)#define FIXED_FROM_FLOAT(x) ((Fixed)((x)*FIXED_ONE))#define FIXED_TO_FLOAT(x) ((x)/(1.*FIXED_ONE))#define FIXED_MUL(x,y) (((int64_t)(x) * (y)) >> FIXED_BITS)#define FIXED_DIV(x,y) (((int64_t)(x) * FIXED_ONE) / (y))#define FIXED_DIV2(x) ((x) >> 1)#define FIXED_AVERAGE(x,y) (((x) + (y)) >> 1)#define FIXED_FRAC(x) ((x) & ((1 << FIXED_BITS)-1))#define FIXED_TRUNC(x) ((x) & ~((1 << FIXED_BITS)-1))#define FIXED_FROM_INT_FLOAT(x,f) (Fixed)((x)*(FIXED_ONE*(f)))typedef int32_t Angle;#define ANGLE_BITS 9#if ANGLE_BITS < 8# error ANGLE_BITS must be at least 8#endif#define ANGLE_2PI (1 << ANGLE_BITS)#define ANGLE_PI (1 << (ANGLE_BITS-1))#define ANGLE_PI2 (1 << (ANGLE_BITS-2))#define ANGLE_PI4 (1 << (ANGLE_BITS-3))#define ANGLE_FROM_FLOAT(x) (Angle)((x)*ANGLE_PI/M_PI)#define ANGLE_TO_FLOAT(x) ((x)*M_PI/ANGLE_PI)#if ANGLE_BITS <= FIXED_BITS# define ANGLE_FROM_FIXED(x) (Angle)((x) >> (FIXED_BITS - ANGLE_BITS))# define ANGLE_TO_FIXED(x) (Fixed)((x) << (FIXED_BITS - ANGLE_BITS))#else# define ANGLE_FROM_FIXED(x) (Angle)((x) << (ANGLE_BITS - FIXED_BITS))# define ANGLE_TO_FIXED(x) (Fixed)((x) >> (ANGLE_BITS - FIXED_BITS))#endifstatic Fixed angle_sin_tab[ANGLE_2PI+1];static void init_angles(void){ int nn; for (nn = 0; nn < ANGLE_2PI+1; nn++) { double radians = nn*M_PI/ANGLE_PI; angle_sin_tab[nn] = FIXED_FROM_FLOAT(sin(radians)); }}static __inline__ Fixed angle_sin( Angle a ){ return angle_sin_tab[(uint32_t)a & (ANGLE_2PI-1)];}static __inline__ Fixed angle_cos( Angle a ){ return angle_sin(a + ANGLE_PI2);}static __inline__ Fixed fixed_sin( Fixed f ){ return angle_sin(ANGLE_FROM_FIXED(f));}static __inline__ Fixed fixed_cos( Fixed f ){ return angle_cos(ANGLE_FROM_FIXED(f));}/* Color palette used for rendering the plasma */#define PALETTE_BITS 8#define PALETTE_SIZE (1 << PALETTE_BITS)#if PALETTE_BITS > FIXED_BITS# error PALETTE_BITS must be smaller than FIXED_BITS #endifstatic uint16_t palette[PALETTE_SIZE];static uint16_t make565(int red, int green, int blue){ return (uint16_t)( ((red << 8) & 0xf800) | ((green << 3) & 0x07e0) | ((blue >> 3) & 0x001f) );}static void init_palette(void){ int nn, mm = 0; /* fun with colors */ for (nn = 0; nn < PALETTE_SIZE/4; nn++) { int jj = (nn-mm)*4*255/PALETTE_SIZE; palette[nn] = make565(255, jj, 255-jj); } for ( mm = nn; nn < PALETTE_SIZE/2; nn++ ) { int jj = (nn-mm)*4*255/PALETTE_SIZE; palette[nn] = make565(255-jj, 255, jj); } for ( mm = nn; nn < PALETTE_SIZE*3/4; nn++ ) { int jj = (nn-mm)*4*255/PALETTE_SIZE; palette[nn] = make565(0, 255-jj, 255); } for ( mm = nn; nn < PALETTE_SIZE; nn++ ) { int jj = (nn-mm)*4*255/PALETTE_SIZE; palette[nn] = make565(jj, 0, 255); }}static __inline__ uint16_t palette_from_fixed( Fixed x ){ if (x < 0) x = -x; if (x >= FIXED_ONE) x = FIXED_ONE-1; int idx = FIXED_FRAC(x) >> (FIXED_BITS - PALETTE_BITS); return palette[idx & (PALETTE_SIZE-1)];}/* Angles expressed as fixed point radians */static void init_tables(void){ init_palette(); init_angles();}static void fill_plasma( AndroidBitmapInfo* info, void* pixels, double t ){ Fixed yt1 = FIXED_FROM_FLOAT(t/1230.); Fixed yt2 = yt1; Fixed xt10 = FIXED_FROM_FLOAT(t/3000.); Fixed xt20 = xt10;#define YT1_INCR FIXED_FROM_FLOAT(1/100.)#define YT2_INCR FIXED_FROM_FLOAT(1/163.) int yy; for (yy = 0; yy < info->height; yy++) { uint16_t* line = (uint16_t*)pixels; Fixed base = fixed_sin(yt1) + fixed_sin(yt2); Fixed xt1 = xt10; Fixed xt2 = xt20; yt1 += YT1_INCR; yt2 += YT2_INCR;#define XT1_INCR FIXED_FROM_FLOAT(1/173.)#define XT2_INCR FIXED_FROM_FLOAT(1/242.)#if OPTIMIZE_WRITES /* optimize memory writes by generating one aligned 32-bit store * for every pair of pixels. */ uint16_t* line_end = line + info->width; if (line < line_end) { if (((uint32_t)(uintptr_t)line & 3) != 0) { Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2); xt1 += XT1_INCR; xt2 += XT2_INCR; line[0] = palette_from_fixed(ii >> 2); line++; } while (line + 2 <= line_end) { Fixed i1 = base + fixed_sin(xt1) + fixed_sin(xt2); xt1 += XT1_INCR; xt2 += XT2_INCR; Fixed i2 = base + fixed_sin(xt1) + fixed_sin(xt2); xt1 += XT1_INCR; xt2 += XT2_INCR; uint32_t pixel = ((uint32_t)palette_from_fixed(i1 >> 2) << 16) | (uint32_t)palette_from_fixed(i2 >> 2); ((uint32_t*)line)[0] = pixel; line += 2; } if (line < line_end) { Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2); line[0] = palette_from_fixed(ii >> 2); line++; } }#else /* !OPTIMIZE_WRITES */ int xx; for (xx = 0; xx < info->width; xx++) { Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2); xt1 += XT1_INCR; xt2 += XT2_INCR; line[xx] = palette_from_fixed(ii / 4); }#endif /* !OPTIMIZE_WRITES */ // go to next line pixels = (char*)pixels + info->stride; }}/* simple stats management */typedef struct { double renderTime; double frameTime;} FrameStats;#define MAX_FRAME_STATS 200#define MAX_PERIOD_MS 1500typedef struct { double firstTime; double lastTime; double frameTime; int firstFrame; int numFrames; FrameStats frames[ MAX_FRAME_STATS ];} Stats;static voidstats_init( Stats* s ){ s->lastTime = now_ms(); s->firstTime = 0.; s->firstFrame = 0; s->numFrames = 0;}static voidstats_startFrame( Stats* s ){ s->frameTime = now_ms();}static voidstats_endFrame( Stats* s ){ double now = now_ms(); double renderTime = now - s->frameTime; double frameTime = now - s->lastTime; int nn; if (now - s->firstTime >= MAX_PERIOD_MS) { if (s->numFrames > 0) { double minRender, maxRender, avgRender; double minFrame, maxFrame, avgFrame; int count; nn = s->firstFrame; minRender = maxRender = avgRender = s->frames[nn].renderTime; minFrame = maxFrame = avgFrame = s->frames[nn].frameTime; for (count = s->numFrames; count > 0; count-- ) { nn += 1; if (nn >= MAX_FRAME_STATS) nn -= MAX_FRAME_STATS; double render = s->frames[nn].renderTime; if (render < minRender) minRender = render; if (render > maxRender) maxRender = render; double frame = s->frames[nn].frameTime; if (frame < minFrame) minFrame = frame; if (frame > maxFrame) maxFrame = frame; avgRender += render; avgFrame += frame; } avgRender /= s->numFrames; avgFrame /= s->numFrames; LOGI("frame/s (avg,min,max) = (%.1f,%.1f,%.1f) " "render time ms (avg,min,max) = (%.1f,%.1f,%.1f)\n", 1000./avgFrame, 1000./maxFrame, 1000./minFrame, avgRender, minRender, maxRender); } s->numFrames = 0; s->firstFrame = 0; s->firstTime = now; } nn = s->firstFrame + s->numFrames; if (nn >= MAX_FRAME_STATS) nn -= MAX_FRAME_STATS; s->frames[nn].renderTime = renderTime; s->frames[nn].frameTime = frameTime; if (s->numFrames < MAX_FRAME_STATS) { s->numFrames += 1; } else { s->firstFrame += 1; if (s->firstFrame >= MAX_FRAME_STATS) s->firstFrame -= MAX_FRAME_STATS; } s->lastTime = now;}JNIEXPORT void JNICALL Java_com_example_plasma_PlasmaView_renderPlasma(JNIEnv * env, jobject obj, jobject bitmap, jlong time_ms){ AndroidBitmapInfo info; void* pixels; int ret; static Stats stats; static int init; if (!init) { init_tables(); stats_init(&stats); init = 1; } if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) { LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); return; } if (info.format != ANDROID_BITMAP_FORMAT_RGB_565) { LOGE("Bitmap format is not RGB_565 !"); return; } if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } stats_startFrame(&stats); /* Now fill the values with a nice little plasma */ fill_plasma(&info, pixels, time_ms ); AndroidBitmap_unlockPixels(env, bitmap); stats_endFrame(&stats);}
首先分析函数renderPlasma()。首先定义一个AndroidBitmapInfo的对象info。AndroidBitmapInfo的定义如下:
/** Bitmap info, see AndroidBitmap_getInfo(). */typedef struct { /** The bitmap width in pixels. */ uint32_t width; /** The bitmap height in pixels. */ uint32_t height; /** The number of byte per row. */ uint32_t stride; /** The bitmap pixel format. See {@link AndroidBitmapFormat} */ int32_t format; /** Unused. */ uint32_t flags; // 0 for now} AndroidBitmapInfo;
AndroidBitmapInfo用来描述一个bitmap,width,height分别是bitmap的宽,高,stride是一行的字节数,format表示bitmap的format,flags目前没有用,恒为0。继续分析renderPlasma()函数。如果init为false,即没有执行过初始化,那么首先调用方法init_tables()和stat_init()进行初始化。init_tables()会依次调用init_palette()和init_angles()。init_palette()初始化着色版,PALETTE_SIZE的值是256,init_palette分四段
进行着色,分别是0-63, 64-127, 128-192, 192-255。init_angles()初始化图像的角度。
接下来调用AndroidBitmap_getInfo()获取bitmap的info,如果返回<0,记录错误信息到log并返回。
如果获取信息成功,那么判断bitmap的格式,如果format!=ANDROID_BITMAP_FORMAT_RGB_565,记录错误信息到log并返回。
接下来,调用函数AndroidBitmap_lockPixels(),尝试锁定bitmap的像素地址,这个方法的目的是确保在AndroidBitmap_unlockPixels()调用之前,这些像素的内存不会被移除。
如果锁定成功,接着调用方法stats_startFrame(&stats)。stats_startFrame(&stats)会调用方法now_ms(),返回值赋值给参数stats的成员frameTime。now_ms()返回当前时间的毫秒数。
接下来,调用fill_plasma(&info, pixels, time_ms )进行填充。
之后,要记得调用AndroidBitmap_unlockPixels(env, bitmap)接触像素锁定。
- google 官方ndk demo解析(二)——bitmap-plasma
- google官方android ndk demo解析(一)——audio echo
- Vuforia开发基础二-官方demo解析
- Vuforia开发基础(二):官方demo解析
- Vuforia开发基础二-官方demo解析
- ZOJ 3763 —— Plasma Field(几何,数学)
- Google官方demo(displayingBitmaps)
- Qt5官方demo解析集6——Loopback Example
- Qt5官方demo解析集31——StocQt
- Qt5官方demo解析集35——Music Player
- Qt5官方demo解析集36——Wiggly Example
- Qt5官方demo解析集36——Wiggly Example
- Qt5官方demo解析集36——Wiggly Example
- Qt5官方demo解析集37——Vector Deformation
- ActivityLifeCycle官方demo解析
- PLASMA
- Oracle bitmap 初步解析(二)
- 【Google官方教程】第三课:缓存Bitmap
- PHP加JS实现商品秒杀倒计时
- 计算机网络体系的三大模型
- C语言 fread()与fwrite()函数说明与示例
- 某安全浏览器竟然也被查出高危漏洞?开源安全问题不容忽视
- Eclipse汉化后如何还原为EN英文(实用技巧) --转
- google 官方ndk demo解析(二)——bitmap-plasma
- "<Module>"的类型初始值设定项引发异常的解决办法
- 2017云栖大会·杭州峰会:《云数据·大计算:海量日志数据分析与应用》之《数据分析展现:可视化报表及嵌入应用》篇
- Java——I/O
- F
- ECMAscript6快速入门-iterator
- Chinese Whispers 聚类算法
- HTML使用JS导出Excel(五种方法)
- 帆软报表-聚合报表使用方法