ios,android读取文件
不同平台读取文件的方式是不一样的。我们来看代码:
/********************************************************************
Copyright(C), 2012-2013,
FileName:FileUnits.h
Description:
Author:cloud
Created:2014/10/17
history:
17:10:2014 16:54 by
*********************************************************************/
#pragma once
#include "Singleton.h"
#include "PlatformConfig.h"
namespace cloud
{
class FileUtils:public Singleton<FileUtils>
{
public:
DECLARE_SINGLETON_CREATE_DESTROY
FileUtils(void);
~FileUtils(void);
void readFile(const char* filePathName,unsigned char** outData,unsigned int& outLen);
void writeFile(const char* filePathName,unsigned char* inData,unsigned int inLen);
private:
};
}
/********************************************************************
Copyright(C), 2012-2013,
FileName:FileUtils.cpp
Description:
Author:cloud
Created:2014/10/17
history:
17:10:2014 16:55 by
*********************************************************************/
#include "FileUtils.h"
#include <string>
#if (TARGET_PLATFORM == PLATFORM_ANDROID)
#include "FileUtilsAndroid.h"
#elif (TARGET_PLATFORM == PLATFORM_IOS)
#include "FileUtilsIos.h"
#endif
namespace cloud
{
IMPLEMENT_SINGLETON_ALL(FileUtils);
FileUtils::FileUtils()
{
}
FileUtils::~FileUtils()
{
}
void FileUtils::readFile(const char* filePathName,unsigned char** outData,unsigned int& outLen)
{
#if (TARGET_PLATFORM == PLATFORM_ANDROID)
FileUtilsAndroid::readFile(filePathName,outData,outLen);
#elif (TARGET_PLATFORM == PLATFORM_IOS)
FileUtilsIos::readFile(filePathName,outData,outLen);
#elif (TARGET_PLATFORM == PLATFORM_WIN32)
FILE *fp = fopen(filePathName, "rb");
if (fp == NULL)
{
return;
}
fseek(fp,0,SEEK_END);
outLen = ftell(fp);
fseek(fp,0,SEEK_SET);
unsigned char* data = (unsigned char*)malloc(outLen);
fread(data,1,outLen,fp);
*outData = data;
fclose(fp);
#endif
}
void FileUtils::writeFile(const char* filePathName,unsigned char* outData,unsigned int outLen)
{
}
}
win32直接fopen读取,ios 会调用FileUtilsIos读取,android会调用FileUtilsAndroid读取。
/********************************************************************
Copyright(C), 2012-2013,
FileName:FileUnitsIos.cpp
Description:
Author:cloud
Created:2014/10/17
history:
17:10:2014 16:55 by
*********************************************************************/
#include "FileUtilsIos.h"
#include <string>
namespace cloud
{
void FileUtilsIos::readFile(const char* filePathName,unsigned char** outData,unsigned int& outLen)
{
NSString* file = [NSString stringWithUTF8String:filePathName];
NSString* path = [[NSBundle mainBundle] pathForResource:file ofType:nil];
NSData *fileData = [NSData dataWithContentsOfFile:path];
outLen = [fileData length];
unsigned char* putData = (unsigned char*)[fileData bytes];
unsigned char* data = (unsigned char*)malloc(outLen);
memcpy(data,putData,outLen);
*outData = data;
}
void FileUtilsIos::writeFile(const char* filePathName,unsigned char* outData,unsigned int outLen)
{
}
}
android 稍微复杂点.
/********************************************************************
Copyright(C), 2012-2013,
FileName:FileUnitsAndroid.cpp
Description:
Author:cloud
Created:2014/10/17
history:
17:10:2014 16:55 by
*********************************************************************/
#include "FileUtilsAndroid.h"
#include <string>
namespace cloud
{
AAssetManager* FileUtilsAndroid::assetmanager = nullptr;
void FileUtilsAndroid::setAssetmanager(AAssetManager* a) {
if (nullptr == a) {
return;
}
FileUtilsAndroid::assetmanager = a;
}
void FileUtilsAndroid::readFile(const char* filePathName,unsigned char** outData,unsigned int& outLen)
{
// read asset data
AAsset* asset =
AAssetManager_open(FileUtilsAndroid::assetmanager,
filePathName,
AASSET_MODE_UNKNOWN);
if (nullptr == asset) {
return ;
}
bool forString = false;
off_t fileSize = AAsset_getLength(asset);
unsigned char* data = NULL;
if (forString)
{
data = (unsigned char*) malloc(fileSize + 1);
data[fileSize] = '\0';
}
else
{
data = (unsigned char*) malloc(fileSize);
}
int bytesread = AAsset_read(asset, (void*)data, fileSize);
int size = bytesread;
AAsset_close(asset);
*outData = data;
outLen = size;
}
void FileUtilsAndroid::writeFile(const char* filePathName,unsigned char* outData,unsigned int outLen)
{
}
}
asserts 的设置在这里
void Java_com_cloudgame_org_GameJniHelper_initGameAssets(JNIEnv *env, jclass cls,jobject assetManager)
{
AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
cloud::FileUtilsAndroid::setAssetmanager(mgr);
LOG("init assets");
}
package com.cloudgame.org;
import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
public class GameJniHelper {
void initJniHelperMethod(Activity activity)
{
initGameAssets(activity.getAssets());
}
private native void initGameAssets(AssetManager ass);
static {
System.loadLibrary("cloudGameEngine");
}
}
来看渲染吧。
/********************************************************************
Copyright(C), 2012-2013,
FileName:Renderer.cpp
Description:
Author:cloud
Created:2014/10/17
history:
17:10:2014 16:55 by
*********************************************************************/
#include "Renderer.h"
#include "Engine.h"
#include "FileUtils.h"
#include "vector"
#include "string"
#include <fstream>
#define STRINGIFY(A) #A
namespace cloud
{
typedef struct {
float _position[3];
float _color[4];
float _texCoord[2];
} Vertex;
//
//测试代码
// An array of 3 vectors which represents 3 vertices
Vertex Vertices[] = {
{{-80, 120, 1}, {1, 1, 1, 1}, {0, 1}},
{{-80, -120, 1}, {1, 1, 1, 1}, {0, 0}},
{{ 80, 120, 1}, {1, 1, 1, 1}, {1, 1}},
{{ 80, -120, 1}, {1, 1, 1, 1}, {1, 0}}
};
static void checkGlError(const char* op) {
for (GLint error = glGetError(); error; error
= glGetError()) {
LOG("after %s() glError (0x%x)\n", op, error);
}
}
GLuint Texture = 0;
GLuint loadBMP_custom(const char * imagepath)
{
// Data read from the header of the BMP file
unsigned char header[54]; // Each BMP file begins by a 54-bytes header
unsigned int dataPos; //Position in the file where the actual data begins
unsigned int width,height;
unsigned int imageSize; //= width*height*3
// Actual RGB data
unsigned char * data;
unsigned char* outData = NULL;
unsigned int outLen = 0;
FileUtils::getInstance()->readFile(imagepath,&outData,outLen);
memcpy(header,outData,54);
if (header[0] != 'B' || header[1] != 'M')
{
printf("Not a correct BMP filen");
return 0;
}
dataPos = *(int*)&(header[0x0A]);
imageSize = *(int*)&(header[0x22]);
width = *(int*)&(header[0x12]);
height = *(int*)&(header[0x16]);
if (imageSize == 0)
{
imageSize = width * height * 3;
}
if (dataPos == 0)
{
dataPos = 54;
}
// Create a buffer
data = new unsigned char [imageSize];
// Read the actual data from the file into the buffer
memcpy(data,outData+54,imageSize);
//Everything is in memory now, the file can be closed
free(outData);
GLuint textureID;
glGenTextures(1, &textureID);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, textureID);
// Give the image to OpenGL
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// glGenerateMipmap(GL_TEXTURE_2D);
delete[] data;
return textureID;
}
//
IMPLEMENT_SINGLETON_ALL(Renderer);
Renderer::Renderer(void):_isInit(false)
{
}
void Renderer::resetProjection()
{
Size designSize = Engine::getInstance()->getDesignSize();
_projection =glm::ortho(-designSize.width * 0.5f, designSize.width * 0.5f, -designSize.height * 0.5f, designSize.height * 0.5f, 0.1f, 100.0f);
}
Renderer::~Renderer(void)
{
}
GLuint Renderer::LoadShaders()
{
//Create the shaders
int VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
int FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
static const char* VERTEX_SHADER =STRINGIFY(
uniform mat4 uMVPMatrix;
attribute vec3 vertexPosition;
attribute vec2 vertexUV;
attribute vec4 vertexColor;
varying vec2 UV;
varying vec4 color;
void main(void)
{
vec4 v = vec4(vertexPosition,1);
gl_Position = uMVPMatrix * v;
UV = vertexUV;
color = vertexColor;
}
);
static const char * FRAG_SHADER=STRINGIFY(
varying mediump vec2 UV;
varying mediump vec4 color;
uniform sampler2D myTextureSampler;
void main(void)
{
gl_FragColor = color * texture2D( myTextureSampler,UV);
}
);
int Result = GL_FALSE;
int InfoLogLength;
//compile Vertex Shader
LOG("Compiling shader : n");
char const * VertexSourcePointer = VERTEX_SHADER;
glShaderSource(VertexShaderID,1,&VertexSourcePointer,NULL);
glCompileShader(VertexShaderID);
// Check vertex Shader
glGetShaderiv(VertexShaderID,GL_COMPILE_STATUS,&Result);
glGetShaderiv(VertexShaderID,GL_INFO_LOG_LENGTH,&InfoLogLength);
std::vector<char> VerTexShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(VertexShaderID,InfoLogLength,NULL,&VerTexShaderErrorMessage[0]);
LOG("%s\n",&VerTexShaderErrorMessage[0]);
//compile Fragment Shader
LOG("Compiling shader : n");
char const * FragmentSourcePointer = FRAG_SHADER;
glShaderSource(FragmentShaderID,1,&FragmentSourcePointer,NULL);
glCompileShader(FragmentShaderID);
// Check vertex Shader
glGetShaderiv(FragmentShaderID,GL_COMPILE_STATUS,&Result);
glGetShaderiv(FragmentShaderID,GL_INFO_LOG_LENGTH,&InfoLogLength);
std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(FragmentShaderID,InfoLogLength,NULL,&FragmentShaderErrorMessage[0]);
LOG("%s\n",&FragmentShaderErrorMessage[0]);
//Link the program
LOG("Linking programn");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID,VertexShaderID);
glAttachShader(ProgramID,FragmentShaderID);
glLinkProgram(ProgramID);
//Check the program
glGetProgramiv(ProgramID,GL_LINK_STATUS,&Result);
glGetProgramiv(ProgramID,GL_INFO_LOG_LENGTH,&InfoLogLength);
std::vector<char> ProgramErrorMessage(InfoLogLength);
//glGetProgramInfoLog(ProgramID,InfoLogLength,NULL,&ProgramErrorMessage[0]);
//LOG("%s\n",&ProgramErrorMessage[0]);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
return ProgramID;
}
void Renderer::renderQuad()
{
if(!_isInit)
{
_programID = LoadShaders();
_view = glm::lookAt(
glm::vec3(0,0,100), // Camera is at (4,3,3), in World Space
glm::vec3(0,0,0), // and looks at the origin
glm::vec3(0,1,0) // Head is up (set to 0,-1,0 to look upside-down)
);
glUseProgram(_programID);
_matrixID = glGetUniformLocation(_programID,"uMVPMatrix");
_vertexPosition = glGetAttribLocation(_programID,"vertexPosition");
_vertexUV = glGetAttribLocation(_programID,"vertexUV");
_vertexColor = glGetAttribLocation(_programID,"vertexColor");
resetProjection();
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
Texture = loadBMP_custom("uvtemplate.bmp");
_isInit = true;
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
caculateMVP(Mat4(1.0f));
glBindTexture(GL_TEXTURE_2D,Texture);
int kQuadSize = sizeof(Vertex);
long offset = (long)Vertices;
int diff = offsetof( Vertex, _position);
glEnableVertexAttribArray(_vertexPosition);
glVertexAttribPointer(
_vertexPosition, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
kQuadSize, // stride
(void*)(offset + diff) // array buffer offset
);
diff = offsetof( Vertex, _texCoord);
glEnableVertexAttribArray(_vertexUV);
glVertexAttribPointer(
_vertexUV, // attribute 0. No particular reason for 0, but must match the layout in the shader.
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
kQuadSize, // stride
(void*)(offset + diff) // array buffer offset
);
diff = offsetof( Vertex, _color);
glEnableVertexAttribArray(_vertexColor);
glVertexAttribPointer(
_vertexColor, // attribute 0. No particular reason for 0, but must match the layout in the shader.
4, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
kQuadSize, // stride
(void*)(offset + diff) // array buffer offset
);
glDrawArrays(GL_TRIANGLE_STRIP,0,4);// Starting from vertex 0; 3 vertices total -> 1 triangle
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
}
void Renderer::caculateMVP(Mat4 model)
{
Mat4 MVP = _projection * _view * model;// Remember, matrix multiplication is the other way around
glUniformMatrix4fv(_matrixID,1,GL_FALSE,&MVP[0][0]);
}
}
这样就能读取纹理并且渲染了。
这里遇到两个神bug,glGetProgramInfoLog在android平台出错,但显示是mvp设置出错。之前,glEnableVertexAttribArray,glVertexAttribPointer是手写固定的0,1,2.win32与android没问题,ios上位置不正确。