Android中运用OpenGL

OpenGL之GLFW和glad框架实例(十二) 简介: 优快云博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.更多原创,欢迎关注:Android系统攻城狮 GLFW = GLUT + OpenGL的组合. 阅读详情

1、GLSurfaceView


GLSurfaceView是android应用程序中实现OpenGl画图的重要组成部分。GLSurfaceView中封装了一个Surface。而android平台下关于图像的现实,差不多都是由Surface来实现的。

2、Renderer


有了GLSurfaceView之后,就相当于我们有了画图的纸。现在我们所需要做的就是如何在这张纸上画图。所以我们需要一支笔。
Renderer是GLSurfaceView的内部静态接口,它就相当于在此GLSurfaceView上作画的笔。我们通过实现这个接口来“作画”。最后通过GLSurfaceView的setRenderer(GLSurfaceView.Renderer renderer)方法,就可以将纸笔关联起来了。


实现Renderer需要实现它的三个接口:onSurfaceCreated(GL10 gl, EGLConfig config)、 onSurfaceChanged(GL10 gl, int width, int height)、onDrawFrame(GL10 gl)。下面就这三个接口的具体意义做个简单的介绍。

2.1、onSurfaceCreated

此方法看名字就知道它是在Surface创建的时候被调用的。因此我们可以在这个函数的实现中做一些初始化的工作。例如取出文房四宝、铺好画布、调好颜料之类的。它的函数原
型如下:
public abstract void onSurfaceCreated (GL10 gl, EGLConfig config)
第二个参数在文档中没有关于它的任何public方法和域。因此我们可以不用管它。
第一个参数非常重要。如果说Renderer是画笔的话,那么这个gl参数,就可以说是我们的手了。如何操作这支画笔,都是它说了算!所以我们绝大部分时候都是通过这个叫做gl的手来指挥Renderer画图的。

2.2 onSurfaceChanged

当GLSurfaceView大小改变时,对应的Surface大小也会改变。值得注意的是,在Surface刚创建的时候,它的size其实是0,也就是说在画第一次图之前它也会被调用一次的。(而且对于很多时候,Surface的大小是不会改变的,那么此函数就只在创建之初被调用一次而已)

原型如下:
public abstract void onSurfaceChanged (GL10 gl, int width, int height)
同样的,画图的手是必需的。
另外值得注意的是,它告诉了我们这张纸有多高多宽。这点很重要。因为在onSurfaceCreated的时候我们是不知道纸的宽高的,所以有一些和长宽相关的初始化工作还得在此函数中来做。

2.3 onDrawFrame

好了,我们的初始化工作做得差不多了,那么现在就是该真刀真枪画画的时候了!此函数就是真正给你画画用的。每调用一次就画一幅图。可能的疑问是这个函数什么时候会被调
用呢?最开始的时候肯定是会被调用的。以后会有两种模式供你选择:

  1. RENDERMODE_CONTINUOUSLY
  2. RENDERMODE_WHEN_DIRTY

第一种模式(RENDERMODE_CONTINUOUSLY):
连续不断的刷,画完一幅图马上又画下一幅。这种模式很明显是用来画动画的;


第二种模式(RENDERMODE_WHEN_DIRTY):
只有在需要重画的时候才画下一幅。这种模式就比较节约CPU和GPU一些,适合用来画不经常需要刷新的情况。多说一句,系统如何知道需要重画了呢?当然是你要告诉它……
调用GLSurfaceView的requestRender ()方法,告诉它,你脏了。


这两种模式在什么地方设置呢? GLSurfaceView的setRenderMode(int renderMode)方法。可以供你设置你需要的刷新模式。


还是来看看这个函数的原型吧: public abstract void onDrawFrame (GL10 gl) 很简单,只有手。


3、 Android下OpenGL绘图基本流程:


我们从画一个三角形开始说起:

3.1 MyRender

经过前面的介绍,我们应该知道现在需要做的事,就是写好Renderer的三个接口方法。
我们需要重新写一个类实现它,然后重写这三个方法。
class MyRender implements GLSurfaceView.Renderer
OK,笔已经拿好了。“铺好纸”是非常关键的一步。虽然我们说GLSurfaceView就是我们作图的纸,但是“铺”好这张纸,却也非常的重要。

 

下面我们重点讲下,这纸该怎么铺。OpenGL这张纸可不是一般的纸啊。最起码,它是三维的。然而实际的显示屏幕却是一个平面。所以这纸还不好“铺”。


首先,不一定整张纸都用来作画吧,Surface不一定全部都用上(当然,一般情况下我们是全部用上的)。那么我们需要计划好,哪部分区域用来作画。
gl.glViewport(0, 0, width, height);
根据这里的参数width和height,我们可以知道这个宽高需要在onSurfaceChanged里得知。


然后,这一步很关键。如何在平面上画三维坐标的点或图形呢?OpenGL有一个坐标系,如下图:


我们需要将这个坐标系和我们的GLSurfaceView里的Surface做一个映射关系。
glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustumf(-400, 400, -240, 240, 0.3f, 100);

 

glMatrixMode(GL10.GL_PROJECTION); 是说我们现在改变的是坐标系与Surface的映射关系(投影矩阵)。

下一句 gl.glLoadIdentity(); 是将以前的改变都清掉(之前对投影矩阵的任何改变)。

glFrustumf (float left, float right, float bottom, float top, float zNear, float zFar) 这个函数非常Powerful。它实现了Surface和坐标系之间的映射关系。它是以透视投影的方式来进行映射的。


透视投影的意思见下图:

 


映射说明:
1、 前面一个矩形表示的是我们平面作图的范围。即Surface的作图范围。它有四条边,
我们将它们暂时命名edgeLeft、edgeRight、edgeTop、edgeBottom。
2、 glFrustumf 参数中的left、right、bottom、top指的是作图范围的四条edge在OpenGL x = -400的位置。同理top、right、bottom的值表示的是edgeRight、edgeTop、edgeBottom这几条边在坐标系中的位置。
3、上面第二点定出了作图范围的x和y的范围。那么对于3D的OpenGL这张纸来说,我们还需要定出z的范围。首先,要想象一下,相机或者眼睛在坐标系的哪个位置?
默认的眼睛的位置在OpenGL坐标的原点处(0,0,0)。视线方向是平行于Z轴往里看。
near表示的是眼睛到作图平面的距离(绝对值哦!),far表示眼睛到最远可见处的平面范围。于是,默认情况下z的作图范围就是在-near到-far的位置。
4、好了,我们已经确定好x、y、z方向的作图范围了。回过头来,就可以发现,这张“立体”的纸,是一个方椎体切去头部的平截头体。我们所画的物体坐标落在这个区域范围内的部分将可以被我们看到(即在屏幕里画出来)。OK,至此,我们把纸终于铺好了。

 

glMatrixMode函数的选项(参数)有后面三种:GL_PROJECTION,GL_MODELVIEW和GL_TEXTURE;

  • GL_PROJECTION,是投影的意思,就是要对投影相关进行操作,也就是把物体投影到一个平面上,就像我们照相一样,把3维物体投到2维的平面上。这样,接下来的语句可以是跟透视相关的函数,比如glFrustum()或gluPerspective();
  • GL_MODELVIEW,是对模型视景的操作,接下来的语句描绘一个以模型为基础的适应,这样来设置参数,接下来用到的就是像gluLookAt()这样的函数;
  • GL_TEXTURE,就是对纹理相关进行操作;

顺便说下,OpenGL里面的操作,很多是基于对矩阵的操作的,比如位移,旋转,缩放,所以,
这里其实说的规范一点就是glMatrixMode是用来指定哪一个矩阵是当前矩阵,而它的参数代表要操作的目标:

  • GL_PROJECTION是对投影矩阵操作;
  • GL_MODELVIEW是对模型视景矩阵操作;
  • GL_TEXTURE是对纹理矩阵进行随后的操作;

 

 

3.2 画图之前先构图


Android 的 OpenGL 作图,不同于一般的作图,这点我们不得不感慨。它将数据和画完全分开来。例如,我们要画一个三角形。很显然,三角形有三个点。我们在画图之前首先要构图,比如每个点在哪个地方。我们将这些数据放在一个一个数组缓冲区中,放好这些数据之后,再统一一起画出来。

下面,主要讲下,如何将顶点数据和颜色数据放入符合 Android OpenGL 的数组缓冲区中。

 

首先我们要明白的是,OpenGL 是一个非常底层的画图接口,它所使用的缓冲区存储结构是和我们的 Java 程序中不相同的。Java 是大端字节序(BigEdian),而 OpenGL 所需要的数据是小端字节序(LittleEdian)。所以,我们在将 Java 的缓冲区转化为 OpenGL 可用的缓冲区时需要作一些工作。


byte 数据缓冲区

不管我们的数据是整型的还是浮点型的,为了完成 BigEdian 到 LittleEdian 的转换,我们都首先需要一个 ByteBuffer。我们通过它来得到一个可以改变字节序的缓冲区。

ByteBuffer mBuffer = ByteBuffer.allocateDirect(pointCount*dimension*4);
mBuffer.order(ByteOrder.nativeOrder());

注意,我们应该用“allocateDirect”来分配内存空间,因为这样才可以 order 排序。最后我们就可以通过:
resultBuffer = mBuffer.asFloatBuffer();
resultBuffer = mBuffer.asIntBuffer();
将字节缓冲区转化为整型或者浮点型缓冲区了。

 

 

3.3 终于画图了!


有了前面所有的准备工作之后,有一个好消息可以告诉你,我们终于可以画图了!而且,有了前面这么多工作,真正画图的工作其实比较简单。


3.3.1、清理好你的纸

前面我们说过了,在画图之前,一定要把纸给清理干净喽:

gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

另外,之前我们在映射坐标系的时候,用了glMatrixMode(GL10.GL_PROJECTION);来指定改变的是投影矩阵。那么现在要画图了,所以我们需要指定改变的是“视图矩阵”:

gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();

 

3.3.2、启用数组

我们的前面说过,画图的数据都放在数组缓冲区里,最后再一起传过来作画。那么我们首先要告诉 OpenGL,我们需要用到哪些数组。例如我们需要顶点数组和颜色数组:

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

 

3.3.3、指定数组数据

我们前面已经构造好了我们的数据缓冲区,floatBuffer(或 IntBuffer)。现在我们只需要将这个数据缓冲区和对应的功能绑定起来就好了:

gl.glVertexPointer(3, GL10.GL_FLOAT, 0, VertexBuffer);
gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);

这两句话分别绑定了顶点数据数组和颜色数据数组。其中第一个参数表示的是每个点有几个坐标。例如顶点,有 x、y、z值,所以是 3;而颜色是 r、g、b、a 值,所以是 4。

 

3.3.4、画图!

gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);

第一个参数指明了画图的类型——三角形(android 似乎只支持画三角形、点、线,不支持画多边形)。后面两个参数指明,从哪个顶点开始画,画多少个顶点。

 

OK!至此,我们的第一个三角形就画出来了,来看看效果吧。



ref:

Jayway Team Blog中OpenGL ES简明开发教程
https://blog.jayway.com/tag/opengl-es/

OpenGL ES 开发教程
http://www.guidebee.info/wordpress/%E6%95%99%E7%A8%8B/android-opengl-es-%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B

http://blog.youkuaiyun.com/jason0539/article/details/9164885

https://developer.android.com/guide/topics/graphics/opengl.html

http://www.guidebee.info/wordpress/archives/category/opengl-es

http://blog.youkuaiyun.com/mapdigit/article/details/7526556
http://blog.youkuaiyun.com/column/details/apidemoopengl.html


Android 开发文档 - OpenGL 详解 Android 可通过开放图形库 (OpenGL®)(特别是 OpenGL ES API)来支持高性能 2D 和 3D 图形。 OpenGL ES 是 OpenGL 规范的一种形式,适用于嵌入式设备。 两个基本类 用于通过 OpenGL ES API 来创建和操控图形:GLSurfaceView 和 GLSurfaceView.Renderer。 GLSurfaceView 此类是一个 View,... 阅读详情

相关推荐

Android版 Vulkan Demo可编译源代码,带有第三方源代码库 glfw、glm、stb-image和小例子

内容概要:学习Vulkan的源码例子 适用人群:Android、Vulkan学习人员 成功编译环境:Android Studio Electric Eel | 2022.1.1 Patch 1,当前更新的最新版本。 附带vulkan学习资料: 1、android vulkan tutorials(6个小例子) 1、Vulkan Programming Guide TheOfficial Guide to Learning Vulkan 2、vulkan10-reference-guide

Android平台下OpenGL初步

转自网上,网上没找到出处,只看到一些论坛中有这篇文章,组织的有点混乱,这篇文章感觉讲的挺好的。 http://www.bangchui.org/read.php?tid=7572&page=1 本文只关注于如何一步步实现在Android平台下运用OpenGl。 1、GLSurfaceView GLSurfaceView是Android应用程序中实现OpenGl画图的重要组成部分。G...

移动编程 541

在Unity中为Sentis部署的YOLOv8模型集成NMS层并实现移动端性能优化

本文详细讲解了在Unity中利用Sentis部署YOLOv8模型时,如何通过代码动态集成NMS层以解决移动端性能瓶颈。文章核心在于避免导出时绑定NMS,转而使用Sentis原生API在运行时高效构建NMS处理流程,并分享了关键的GPU数据操作与移动端性能优化技巧,确保模型在移动设备上流畅运行。

p1q2r的博客 1095

SurfaceCreated不调用的解决方法

因为要为外面封包一个aar包,把一个摄像头的显示控件略微封装了一下,在没有封装的情况下,程序可以正常的跑起来。但是在打好包后用测试程序调用这个包,发现不显示图像。打了个日志比较了一下,发现正常的程序里是调用SurfaceCreated这个函数的,但是在aar包里却不调用这个函数。 而一些初始化的程序就放在这个函数里呢,没有它,当然图像不会显示出来。一开始怀疑是程序的原因,就把包里的许多代码都注释

fpcc的专栏 1万+

ORCA(动态避障)算法

A物体沿着向量v1和v2移动,刚好能和B擦肩而过,不会发生碰撞;若V1和V2的夹角再小一点的话就一定会发生碰撞。A的速度为V1,B的速度为V2,A对于B的相对速度(也就是我们把B看做静止,A的速度)就是V1-V2。,那么怎么判定A的速度向量是不是在碰撞区域内呢?这就需要用A相对于B的速度来判定。红线画出来的锥形区域就是A相对于B的。

u012861978的专栏 4769

Jenkins+docker 微服务实现自动化部署安装和部署过程

本文详细介绍了如何使用Docker部署Jenkins自动化服务器。主要内容包括:1)拉取Jenkins官方或BlueOcean镜像;2)创建容器并配置端口映射、数据卷挂载;3)设置防火墙规则;4)配置清华大学镜像加速;5)安装必要插件;6)SSH密钥配置;7)构建触发器设置;8)编写自动化构建脚本。通过Docker部署Jenkins可以简化安装流程,确保环境一致性,并利用容器特性实现快速启动和管理。文章提供了完整的配置步骤和注意事项,帮助用户快速搭建CI/CD环境。

qq_33665793的博客 1691

android opengl 框架,详解关于在Android平台下运用OpenGL

在Android下,是如何运用OpenGL接口的呢?或者说OpenGL是怎样应用到android平台下的?OpenGL是作为当前主流的图形API之一,它在一些场合具有比DirectX更优越的特性。但OpenGL 是行业领域中最为广泛接纳的 2D/3D 图形 API, 其自诞生至今已催生了各种计算机平台及设备上的数千优秀应用程序。其也是独立于视窗操作系统或其它操作系统的,亦是网络透明的。概述Andr...

weixin_32659227的博客 2265

从RadixTree到哈希表:深入对比SGLang和vLLM的Prefix Cache实现差异

本文深入对比了SGLang与vLLM在大语言模型推理服务中实现Prefix Cache(前缀缓存)的两种核心方案。SGLang采用基于Radix Tree的RadixAttention,支持任意长度前缀的精确匹配与灵活复用;vLLM则采用基于哈希表的方案,深度集成于PagedAttention,实现简洁但要求块级精确对齐。文章剖析了二者在设计哲学、内存管理、适用场景及集群级优化(如Prefix Cache Aware Routing)上的关键差异,为高性能LLM服务的技术选型提供决策依据。

blockchain9miner的博客 956

Android OpenGL ES 图形开发:投影与相机视角的运用

Android OpenGL ES 图形开发:投影与相机视角的运用 前言 在Android平台上使用OpenGL ES进行3D图形开发时,投影和相机视角是两个至关重要的概念。它们共同决定了3D物体如何在2D屏幕上呈现,以及如何模拟人眼观察世界的效果。本文将深入探讨这两个概念在Android OpenGL ES开发中的应用。 投影变换:从3D到2D的映射 为什么需要投影变换 在OpenGL ES中,...

gitblog_00856的博客 450

多后端系统统一聚合与智能分流:用 Multi Origin Composition 与 Routing 打造一套可扩展的 SAP Gateway 架构

本文针对企业级SAP集成场景,详细介绍了如何利用SAP Gateway的MOC(多源组合)和Routing功能实现多后端系统的智能路由与数据聚合。通过系统别名配置、用户角色绑定和主机名分流等机制,可实现按用户、按域名的精确路由。文章还提供了配置清单、性能优化建议和常见问题解决方案,帮助工程师落地多后端OData服务的最佳实践。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 186

rk3588 LightSensor适配从驱动到应用层

本文详细介绍了在RK3588平台上实现光感驱动的开发流程。主要包括:1) 在设备树中配置I2C5接口挂载光感设备;2) 编写内核驱动代码实现光感数据采集;3) HAL层通过ioctl与驱动交互;4) 在BoardConfig.mk中启用相关宏定义;5) Framework层通过AutomaticBrightnessController实现自动亮度调节算法;6) 应用层可通过监听系统设置获取光感变化并调整屏幕亮度。整个流程涵盖了从底层驱动到上层应用的完整实现方案,重点解决了光感设备注册、数据采集传输和自动亮度

tzj1058756809的博客 450

android gl11,android opengl 运用报错解决

android opengl 使用报错解决问题:1.(SDK target 8) called a GL11 Pointer method with an indirect Buffer.2.java.lang.IllegalArgumentException: Must use a native order direct Buffer解决方法:https://groups.google.com/...

weixin_29061821的博客 302

【异常】Claude Code 第三方API 400报错(thinking type should be enabled or disabled)解决方案

摘要: Claude Code接入第三方API端点时出现400参数错误,主要因新版默认启用的Adaptive Thinking功能与旧版接口参数格式不兼容(需thinking: {type: "adaptive"},但第三方仅支持布尔值)。解决方案为修改本地settings.json配置文件,添加"CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING": "1"环境变量并重启客户端,即可恢复思考模式功能。Adaptive Th

奶爸的编程之路,也就一周冷个三天 1万+

如何一步步实现在Android平台下运用OpenGl

转自网上http://www.bangchui.org/read.php?tid=7572&page=11、GLSurfaceViewGLSurfaceView是Android应用程序中实现OpenGl画图的重要组成部分。GLSurfaceView中封装了一个Surface。而android平台下关于图像的现实,差不多都是由Surface来实现的。2、Renderer有了GLSurfaceView之

Kerwin 2239

【面试系列】数据工程师高频面试题及详细解答

本文针对数据工程师岗位,提供了详尽的面试题库和解答,分为初级、中级和高级三个层次。初级面试题主要涉及基本的数据处理和ETL工具的使用,如SQL查询、数据清洗和基本的数据建模。中级面试题重点考察数据管道设计、数据库优化和大数据平台的应用。高级面试题则深入探讨高级数据处理技术、分布式系统架构和数据湖的实现。通过这些问题和解答,候选人可以全面了解数据工程师岗位所需的技能,帮助其更好地准备面试。常考知识点总结部分则系统归纳了数据工程师岗位的关键技能领域。

在路上的专栏 2376

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

LearnOpenGL - Android OpenGL ES 3.0 多线程同步,fence、glWaitSync 和 glClientWaitSync 的运用

本章讨论 OpenGL ES 中多线程技术的运用。首先,说明我们为什么需要这项技术,在 ARM OpenGL ES 教程中提到当我们转向更复杂的图形应用程序时,可能会想要使用多线程(MT)。一个典型的情况是,我们的图形应用程序需要执行大量的数学运算。在这种情况下,可能通过将工作量移至不同于管理图形操作的线程来提高性能。另一个常见的例子是我们想让图形用户界面(GUI)在一个独立的线程中运行。多线程的好处非常重要。MT使得我们的应用程序始终保持响应,并且不只是与应用程序的GUI有关。

记录学习的过程 2756

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

android SmartScan运用OpenGL从零打造一个依赖极低、高灵活、快速预览不变形ZXing扫码库

kotlin编写利用OpenGL打造一个依赖极低、灵活、高自定义、快速预览不变形ZXing扫码库(View形式) 依赖极低,除去kotlin仅依赖zxing核心 dependencies { implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'com.go...

a756213932的博客 575

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Android平台下OpenGL初步使用

本文只关注于如何一步步实现在Android平台下运用OpenGl。 1、GLSurfaceView GLSurfaceView是Android应用程序中实现OpenGl画图的重要组成部分。GLSurfaceView中封装了一个Surface。而android平台下关于图像的现实,差不多都是...

126

Android OpenGL库函数列表

Android OpenGL库函数列表   OpenGl核心函数库   glAccum 操作累加缓冲区   glAddSwapHintRectWIN 定义一组被SwapBuffers拷贝的三角形   glAlphaFunc允许设置alpha检测功能   glAreTexturesResident 决定特定的纹理对象是否常驻在纹理内存中   glArrayElem

Mirage520的专栏 1032

原生openGL Android应用入门

这篇帖子是Medium的另一篇转贴。 我前段时间决定删除我的...

专业的开发者“讨论” 300

【转载01】Android OpenGL开发——图像绘制详解

Android OpenGL开发——图像绘制详解

cainiaoshileyuan的博客 616

Android openGl开发详解(一)

https://zhuanlan.zhihu.com/p/35192230   目录,不支持toc就偷个懒了,从我的csdn截个图过来咯。 学习五部曲,弄清楚5个W一个H(when(什么时候使用)、where(在哪个地方使用?)、who(对谁使用)、what(是个什么东西)、why(为什么要这么用?).一个H即:how(到底该怎么用?)),基本的概念篇主要围绕这几个方面进行分析 1...

u010029439的博客 698

Android OpenGL 动态加载例程序

首先申明,本文是原创, 最近两年一直作Android 的开发工作, 所以也写点东西希望对大家有所帮助。 本篇主要涉及的技术内容: 0,OpenGL 1, GLSurfaceView 2, 动态创建控件 3,动态加载新控件到界面,及动态修改界面 来几个界面更容易理解: 0,点击Add 新创建一个OpenGL and GLSurfaceView 并加载到界面,每次点击都是新创建控件并加载

certificate的专栏 1731

学习OpenGL的好网站

https://en.wikibooks.org/wiki/OpenGL_Programming http://nehe.gamedev.net/ 学习NDK也不错, 这个博客要看左侧部分:http://www.learnopengles.com/calling-opengl-from-android-using-the-ndk/

茶向 468

android 开发与实践指南,OpenGL ES应用开发实践指南:Android卷

OpenGL ES应用开发实践指南:Android卷作者:(美)Kevin Brothaler出版日期:2014年09月文件大小:44.96M支持设备:¥30.00在线试读适用客户端:言商书局iPad/iPhone客户端:下载 Android客户端:下载PC客户端:下载更多详情:查看?对图书下载、阅读卡购买有疑问:立即进入帮助中心>>图书简介目录资深Android开发专家多年实践经验结...

weixin_39753211的博客 278
上一篇: Android 数据存储 利用SQLiteDatabase实现简单的学生管理
下一篇: Android开发之网络通讯详解
混魔MJM
博客等级 码龄9年 57粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值