分类存档: android opengl

opengles android 真机开发一

今天真机到手,前几个月看过的android开发,已经完全记不清了.

这里从头一步步记录下所做的操作供以后参考用:

1、使用eclispe中的import功能,让ndk中的samples/hello-gl2导入工程。导入时先把copy into workspace,避免把samples中的代码污染掉。

2、修改AndroidManifest.xml把以下内容放在<application>标签前面。

<uses-feature android:glEsVersion=”0x00020000″/>
<uses-sdk
android:minSdkVersion=”8″
android:targetSdkVersion=”15″ />

3、转为c/c++工程,builder改为使用ndk-build.cmd

4、下面尝试真机调试:

如果android手机未被adb辨认,需要两个地方确认下,一是手机的usb调试是否打开,二是手机驱动是否安装正确,windows下需要安装google use driver,如果驱动安装失败,使用以下方法解决。

如果使用android google usb driver 安装不上可以修改extras\google\usb_driver 目录下的 android_winusb.inf 文件
具体方式是:用文本工具打开这个文件,在文件里在有一些  %SingleAdbInterface%  %CompositeAdbInterface%  成对的定义,把你的设备信息也按照这个样子写在里面,格式参照google
%SingleAdbInterface%        = USB_Install, USB\###########(就是硬件id里面的短的值)
%CompositeAdbInterface%     = USB_Install, USB\##########(就是硬件id里面的长的值 )
(硬件id的查看方法和上面一样,不过需要注意这里是全部需要,和google一样)

如果以上都成功的话,在cmd中执行:adb devices 可以看到真机。

神那,第一个程序终于在真机上跑起来了。

下面做第二步,把cocos2d-x的samples移到真机上测试一下opengles.

5、如果发现build时,console没有输出,是因为没有添加builder的原因。

6、解决以下错误:注意添加的是environment

Cannot find module with tag ‘cocos2dx’

Add environment “NDK_MODULE_PATH” of values “<Your-cocos2d-x-Root>;<Your-cocos2d-x-Root>\cocos2dx\platform\third_party\android\prebuilt;”

7、如果继续报以下错:注意修改的是enviroment

Android NDK: WARNING: Ignoring unknown import directory: C:\cocos2d-2.0-x-2.0.3
Android NDK: jni/Android.mk: Cannot find module with tag ‘cocos2dx’ in import path
jni/Android.mk:19: *** Android NDK: Aborting.    .  Stop.
Android NDK: Are you sure your NDK_MODULE_PATH variable is properly defined ?
Android NDK: The following directories were searched:
Android NDK:

那么修改为:把c:\cocos-2dx安装目录,修改为: c:/cocos-2dx

费了我3个小时啊。

8、fatal error: GLES2/gl2platform.h: No such file or directory

在Application.mk中添加:

APP_PLATFORM := android-8

然后编译工程,不知道原因,但是确实解决问题了。

9、android下 assets资源可以使用link的方式连接到resources资源目录。

10、如果提示没有box2d的库。

LOCAL_WHOLE_STATIC_LIBRARIES 上添加 box2d_static

最后一行添加:$(call import-module,external/Box2D)

游戏开发准备(四)--多线程处理数据

1、游戏对时时性较高的,基本上都使用时时操作内存+定时入库的方式。部分涉及到重要数据如金币等,才采用时时入库。

2、操作内存时为了避免多个线程同时操作相同一条数据,通过会开以业务类型分为以下几种:

1)全服单线程,一个例子是战斗。这样可以避免两个线程同时操作同一个对象的属性。为了优化,也可以在每个地图(或副本)上是单线程。全服单线程的另一个例子是玩家交易。

2)角色单线程,每个角色单线程处理,大部对角色的操作都可以归入此类。

3)多线程操作,无需担心操作同一块内存,这种情况通常都是查询数据请求,没有修改的操作。绝大部分玩家消息都是归入此类。

todo:研究一下spring的线程池

spring配置线程池:

<!– 处理用户请求的线程池 –>
<bean id=”taskExecutor”
class=”org.springframework.scheduling.concurrent.threadpooltaskexecutor”>
<property name=”corePoolSize” value=”5″ />
<property name=”maxPoolSize” value=”10″ /> // 最大线程数
<property name=”queueCapacity” value=”100″ /> // 消息队列容量
<property name=”keepAliveSeconds” value=”10000″ /> // 存活时间,可以设置的长一些
</bean>

线程池要添加的线程需要实现Runnable接口,不是Thread。

每次用时直接把Runnable对象丢进taskExecutor,线程池会负责调用。

 

stl_bvector.h expected unqualified-id before ‘(‘ token

解决方案参考:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16605

Your code defines min/max as macros. The preprocessor expands this, which 
leaves what used to be std::max(x1, x2) as something that doesn't make 
much sense to the compiler any more. 

Since the standard says that the names min/max are reserved, simply 
remove these #defines from your sources. 

W.

使用cximage及curl下载图片,生成纹理

GLint TextureManager::generateTextureFromPNG(char* url) {
// 下载图片
DownloadResources dr;
initDownloadResource(&dr, url);
download_image(&dr);

CxImage image((BYTE*) dr.memoeryBuff, dr.size, CXIMAGE_FORMAT_PNG);

// TODO:这里能先释放dr的内存吗
if (image.IsValid()) {
logInfo(“load image ok %s:”, url);
} else {
logError(“load image error %s:”, url);
}

int width = image.GetWidth();
int height = image.GetHeight();

GLuint ids[1];
glGenTextures(1, ids);
LOGI(“gl texture id:%d”, ids[0]);
glBindTexture(GL_TEXTURE_2D, ids[0]);

BYTE* glimagedata = NULL;
if (image.AlphaIsValid()) {
long t = width * height * 4;
// 有alpha通道
if (!image.Encode2RGBA(glimagedata, t)) {
LOGE(“image encode 2 rgba error.%s”, image.GetLastError());
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, glimagedata);
checkGlError(“generate texture”);
} else {
LOGE(“image is not support alpha.”);
}

image.FreeMemory(glimagedata); //释放内存空间
freeDownloadResource(&dr); // 释放掉下载的文件占用的内存
return ids[0];
}

curl 下载例子

/*
* curlutil.h
*
* curl工具库,用来处理下载图片及其它资源
*
*  Created on: 2012-10-22
*      Author: joycube2
*/

#ifndef CURLUTIL_H_
#define CURLUTIL_H_

#include “curl.h”
#include “all_include.h”
#include “predef.h”
/*
* 内存对象,用来在每次读取到chunk后,暂时保存读到的数据
* 用来封装好,提供给外部调用
*
* samples:
*
* DownloadResources downloadResources;
* initDownloadResource(&downloadResources,url);
* download_image(&downloadResources);
* …
* freeDownloadResource(&downloadResources);
*/
struct DownloadResources {
char* url;
char* memoeryBuff;
size_t size;
};

/*
* 初始化downloadResource对象一些相差的初始化信息
*/
void initDownloadResource(DownloadResources* downloadResources, char* url) {
downloadResources->url = url;
downloadResources->memoeryBuff = NULL;
downloadResources->size = 0;
}

/*
* 释放分配的内存空间
*/
void freeDownloadResource(DownloadResources* downloadResources) {
if (downloadResources->memoeryBuff) {
free(downloadResources->memoeryBuff);
}
}

size_t write_data(char *responseContent, size_t size, size_t nmemb,
void *userdata) {
logDebug(“curl response: size:%d nmemb:%d”, size, nmemb);
size_t realSize = size * nmemb;

struct DownloadResources* mem = (struct DownloadResources*) userdata;

if (mem->size == 0) {
mem->memoeryBuff = (char*) malloc(realSize);
memcpy(mem->memoeryBuff, responseContent, realSize);
} else {
mem->memoeryBuff = (char*) realloc(mem->memoeryBuff,
mem->size + realSize);
memcpy(mem->memoeryBuff + mem->size, responseContent, realSize);
}

mem->size += realSize;

return realSize;
}
/*
* 试试能不能直接给指针
*/
void download_image(DownloadResources* downloadResources) {
logInfo(“download %s”,downloadResources->url);

CURL * curl;
CURLcode res;

curl = curl_easy_init();

if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, downloadResources->url);

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);

curl_easy_setopt(curl, CURLOPT_WRITEDATA, downloadResources);

res = curl_easy_perform(curl);

curl_easy_cleanup(curl);

if (res != CURLE_OK) {
logError(“failed:%s”, curl_easy_strerror(res));
}
} else {
logError(“failed:%s”, curl_easy_strerror(res));
}
}

#endif /* CURLUTIL_H_ */

ndk下使用动态库及静态库

以libpng为例。

如果使用动态库:

1、新建android工程,创建jni目录,其它步骤不多说了,参考官方的ndk入门就可以了。

将libpng所需源文件放在jni目录下,

并编写Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_CFLAGS :=

LOCAL_MODULE    := png
LOCAL_SRC_FILES :=\
png.c \
pngerror.c \
pngget.c \
pngmem.c \
pngpread.c \
pngread.c \
pngrio.c \
pngrtran.c \
pngrutil.c \
pngset.c \
pngtrans.c \
pngwio.c \
pngwrite.c \
pngwtran.c \
pngwutil.c

LOCAL_LDLIBS := -lz

#include $(BUILD_SHARED_LIBRARY)
include $(BUILD_STATIC_LIBRARY)

编写Application.mk

APP_OPTIM := release
APP_MODULES := libpng

然后编译,执行成功后会生成

libpng.so文件。

好了,动态链接库已经生成。将此文件复制至自己的工程的jni目录下。

Android.mk修改如下:

# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := png
LOCAL_SRC_FILES := libpng.so
include ${PREBUILT_SHARED_LIBRARY}

include $(CLEAR_VARS)
LOCAL_MODULE    := libgl2jni
LOCAL_CFLAGS    := -Werror
LOCAL_SHARED_LIBRARIES := png
#LOCAL_STATIC_LIBRARIES := libpng
#LOCAL_C_INCLUDES += $(LOCAL_PATH)/png
LOCAL_SRC_FILES := gl_code.cpp
LOCAL_LDLIBS    := -llog -lGLESv1_CM -lz
include $(BUILD_SHARED_LIBRARY)

在java代码中也别忘记加载动态库:

static {
System.loadLibrary(“stlport_shared”); // 加载stl的动态库
System.loadLibrary(“png”); // 加载gl2库
System.loadLibrary(“gl2jni”); // 加载gl2库
}

因为gl2jni使用了png库,所以要先加载png库,再加载gl2jni库。

为了方便,在google code已经建立好了工程,可位可以直接下载编译:

http://code.google.com/p/android-ndk-libpng/

——————————————————————————————————–

如果使用静态库:

将以上源代码放在项目的jni目录下

修改Android.mk为:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := libgl2jni
LOCAL_CFLAGS    := -Werror
LOCAL_SRC_FILES := gl_code.cpp
LOCAL_STATIC_LIBRARIES := png
#LOCAL_C_INCLUDES += $(LOCAL_PATH)/png
LOCAL_LDLIBS    := -llog -lGLESv1_CM -lz

include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)

include $(LOCAL_PATH)/png/Android.mk

libpng读取png图片

这是从网上找的代码,但有以下两个缺陷:

1、不支持从内存中解析png图片。

2、生成的图片数据中不包含alpha数据,既使png图中带有alpha数据。

继续查找cximage移植ndk.

unsigned char* readpng(const char* file, png_uint_32* w, png_uint_32* h,
bool* hasAlpha) {
LOGI(“readPng 1”);
FILE* f;
unsigned char sig[8];
png_structp png_ptr;
png_infop info_ptr;
unsigned char* image_data;
int bit_depth;
int color_type;
unsigned int rowbytes;
png_uint_32 i;
png_bytepp row_pointers;
LOGI(“readPng 2”);
if ((f = fopen(file, “rb”)) == NULL)
return NULL;
fread(sig, sizeof(*sig), sizeof(sig), f);
//    if (!png_check_sig(sig, sizeof(*sig))) {
//        fclose(f);
//        return NULL;
//    }
LOGI(“readPng 3”);
if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL,
NULL)) == NULL) {
fclose(f);
return NULL;
}
if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
fclose(f);
return NULL;
}
LOGI(“readPng 4”);
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(f);
return NULL;
}
LOGI(“readPng 4.1”);
//    png_ptr->io_ptr = (png_voidp) f;
png_init_io(png_ptr, f); // fuck,加上这一句就OK了
png_set_sig_bytes(png_ptr, 8);
LOGI(“readPng 4.2”);
png_read_info(png_ptr, info_ptr);
LOGI(“readPng 4.3”);
png_get_IHDR(png_ptr, info_ptr, w, h, &bit_depth, &color_type, NULL, NULL,
NULL);
LOGI(“readPng 5”);
if (color_type & PNG_COLOR_MASK_ALPHA) {
png_set_strip_alpha(png_ptr);
*hasAlpha = true;
}
if (bit_depth == 16)
png_set_strip_16(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY || color_type
== PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
png_read_update_info(png_ptr, info_ptr);

LOGI(“readPng 6”);
rowbytes = png_get_rowbytes(png_ptr, info_ptr);
if ((image_data = (unsigned char *) malloc(*h * rowbytes)) == NULL) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(f);
return NULL;
}
if ((row_pointers = (png_bytepp) malloc(*h * sizeof(png_bytep))) == NULL) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(f);
free(image_data);
return NULL;
}

for (i = 0; i < *h; i++)
row_pointers[*h – 1 – i] = image_data + i * rowbytes;
png_read_image(png_ptr, row_pointers);
free(row_pointers);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(f);

//    FILE* f2=fopen(“/sdcard/2.png”, “w”);
//    fwrite(image_data,*h * rowbytes,1,f2);
//    fclose(f2);
return image_data;
}

android开发点滴

1、设置为全屏:

在activity中设置:

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 隐藏title栏
requestWindowFeature(Window.FEATURE_NO_TITLE);
// 隐藏时间、电池栏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
mView = new GL2JNIView(getApplication());
setContentView(mView);
}

2、glColorPointer

void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer)

第一个参数必须是4。

3、glTexImage2D

http://www.khronos.org/opengles/documentation/opengles1_0/html/glTexImage2D.html

void glTexImage2D(GLenum target,
    GLint level,
    GLint internalformat,
    GLsizei width,
    GLsizei height,
    GLint border,
    GLenum format,
    GLenum type,
    const GLvoid * pixels)
internalformat
Specifies the color components in the texture. Must be same as format.看到了没,internalformat must be same as format.
4、static {
System.loadLibrary(“stlport_shared”); // 加载stl的动态库
System.loadLibrary(“png”); // 加载gl2库
System.loadLibrary(“gl2jni”); // 加载gl2库}
动态库加载时,有顺序限制,如gl2jni需要png库,则需要先加载png库,再加载gl2jni库。如果提前加载gl2jin库则会失败。
5、error: exception handling disabled, use -fexceptions to enable。
错误解决方案:
Application.mk 中添加:APP_CPPFLAGS += -fexceptions
6、C++中要显示给指针赋值为NULL

android下使用ndk开发opengl

本文档目的是记录下从头搭建ndk开发opengl的全过程,以便后来者避免繁琐的准备过程。

以下过程以windows操作系统为例,所需程序默认安排在c盘

1、下载android sdk,安装在 C:\android-sdk-windows

2、下载android ndk,安装在 C:\android-ndk-r8b

3、下载Cygwin,需要1.7或更高版本。因为是在windows下开发,所以需要交叉编译,在其它平台下没有这种麻烦事。安装在C:\cygwin,安装完成后把C:\android-ndk-r8b移到C:\cygwin目录下

安装时,确保 gcc、make、awk三个程序是安装状态,gcc和make默认是不安装的。

另注:ndk r8及更高版本,支持windows下编译。

4、下载eclipse。

安装eclipse下的android sdk插件 adt。

安装eclipse下的c/c++插件cdt。

5、C:\cygwin\workspace(这个目录自己建立)。然后使用eclipse中的import功能,将ndk下的hello-gl2导入工程。

6、在ecliplse中配置ndk自动编译环境

直接参考网上的文章吧:http://blog.csdn.net/gengshenghong/article/details/6981590

以上完成后,编译发布报以下错误:

09-27 07:07:30.154: E/AndroidRuntime(658): FATAL EXCEPTION: GLThread 78
09-27 07:07:30.154: E/AndroidRuntime(658): java.lang.IllegalArgumentException: No configs match configSpec
09-27 07:07:30.154: E/AndroidRuntime(658):     at com.android.gl2jni.GL2JNIView$ConfigChooser.chooseConfig(GL2JNIView.java:168)
09-27 07:07:30.154: E/AndroidRuntime(658):     at android.opengl.GLSurfaceView$EglHelper.start(GLSurfaceView.java:1024)
09-27 07:07:30.154: E/AndroidRuntime(658):     at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1401)
09-27 07:07:30.154: E/AndroidRuntime(658):     at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
09-27 07:07:30.165: D/gralloc_goldfish(658): Emulator without GPU emulation detected.

NDK里的GL2JNIView.java的init函数里(大概102行)

//        setEGLConfigChooser( translucent ?

//                             new ConfigChooser(8, 8, 8, 8, depth, stencil) :

//                             new ConfigChooser(5, 6, 5, 0, depth, stencil) );

setEGLConfigChooser(5, 6, 5, 0, 0, 0); 就可以跑起来了。

但是继续报以下错误:

09-27 07:11:07.694: E/libEGL(707): called unimplemented OpenGL ES API

7、在preference->c/c++->Build->Environment中添加

INCLUDE 指向ndk中的include目录

好像不起作用,最后在项目下新建了一个文件夹,然后引用到include目录来解决掉的。

8、需要把工程转为c/c++工程。

9、自己准备好的一个ndk opengles 1.0基础程序。

AndroidWow