|
Android example source code file (height_map.cpp)
The height_map.cpp Android example source code
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <assert.h>
#include <jni.h>
#include <android/log.h>
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <GLES/gl.h>
static const char* LogTitle = "HeightMapProfiler";
#ifdef DEBUG
#define ASSERT(x) if (!(x)) { __assert(__FILE__, __LINE__, #x); }
#else
#define ASSERT(X)
#endif
#ifdef REPORTING
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LogTitle, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LogTitle, __VA_ARGS__)
#else
#define LOGE(...)
#define LOGI(...)
#endif
void __assert(const char* pFileName, const int line, const char* pMessage) {
__android_log_print(ANDROID_LOG_ERROR, "HeightMapProfiler", "Assert Failed! %s (%s:%d)", pMessage, pFileName, line);
assert(false);
}
struct Mesh {
int vertexBuffer;
int textureBuffer;
int colorBuffer;
int indexBuffer;
int indexCount;
bool useFixedPoint;
};
struct Tile {
// Store a texture value for each texture LOD (Level of Detail)
int textures[4];
float x;
float y;
float z;
float centerX;
float centerY;
float centerZ;
int maxLodCount;
int lodCount;
Mesh lods[4];
float maxLodDistance2;
};
static const int MAX_TILES = 17; //4x4 tiles + 1 skybox. This really shouldn't be hard coded this way though.
static int sTileCount = 0;
static Tile sTiles[MAX_TILES];
static int sSkybox = -1;
static void nativeReset(JNIEnv* env, jobject thiz) {
sTileCount = 0;
sSkybox = -1;
}
// static native int nativeAddTile(int texture, int lodCount, float maxLodDistance, float x, float y, float z, float centerX, float centerY, float centerZ);
static jint nativeAddTile(
JNIEnv* env,
jobject thiz,
jint texture,
jint lodCount,
jfloat maxLodDistance,
jfloat x,
jfloat y,
jfloat z,
jfloat centerX,
jfloat centerY,
jfloat centerZ) {
LOGI("nativeAddTile");
int index = -1;
if (sTileCount < MAX_TILES) {
index = sTileCount;
Tile* currentTile = &sTiles[index];
currentTile->x = x;
currentTile->y = y;
currentTile->z = z;
currentTile->centerX = centerX;
currentTile->centerY = centerY;
currentTile->centerZ = centerZ;
currentTile->lodCount = 0;
currentTile->maxLodCount = lodCount;
currentTile->maxLodDistance2 = maxLodDistance * maxLodDistance;
// Texture array size hard coded for now
currentTile->textures[0] = texture; // first element takes default LOD texture
currentTile->textures[1] = -1; // rest are set by nativeAddTextureLod() call
currentTile->textures[2] = -1;
currentTile->textures[3] = -1;
sTileCount++;
LOGI("Tile %d: (%g, %g, %g). Max lod: %d", index, x, y, z, lodCount);
}
return index;
}
static void nativeSetSkybox(
JNIEnv* env,
jobject thiz,
jint index) {
if (index < sTileCount && index >= 0) {
sSkybox = index;
}
}
// static native void nativeAddLod(int index, int vertexBuffer, int textureBuffer, int indexBuffer, int colorBuffer, int indexCount, boolean useFixedPoint);
static void nativeAddLod(
JNIEnv* env,
jobject thiz,
jint index,
jint vertexBuffer,
jint textureBuffer,
jint indexBuffer,
jint colorBuffer,
jint indexCount,
jboolean useFixedPoint) {
LOGI("nativeAddLod (%d)", index);
if (index < sTileCount && index >= 0) {
Tile* currentTile = &sTiles[index];
LOGI("Adding lod for tile %d (%d of %d) - %s", index, currentTile->lodCount, currentTile->maxLodCount, useFixedPoint ? "fixed" : "float");
if (currentTile->lodCount < currentTile->maxLodCount) {
const int meshIndex = currentTile->lodCount;
LOGI("Mesh %d: Index Count: %d", meshIndex, indexCount);
Mesh* lod = ¤tTile->lods[meshIndex];
lod->vertexBuffer = vertexBuffer;
lod->textureBuffer = textureBuffer;
lod->colorBuffer = colorBuffer;
lod->indexBuffer = indexBuffer;
lod->indexCount = indexCount;
lod->useFixedPoint = useFixedPoint;
currentTile->lodCount++;
}
}
}
// static native void nativeAddTextureLod(int index, int lod, int textureName);
static void nativeAddTextureLod(
JNIEnv* env,
jobject thiz,
jint tileIndex,
jint lod,
jint textureName) {
if (tileIndex < sTileCount && tileIndex >= 0) {
Tile* currentTile = &sTiles[tileIndex];
LOGI("Adding texture lod for tile %d lod %d texture name %d", tileIndex, lod, textureName);
if( lod >= sizeof(currentTile->textures)/sizeof(currentTile->textures[0]) ) {
LOGI("Error adding texture lod for tile %d lod %d is out of range ", tileIndex, lod );
}
currentTile->textures[lod] = textureName;
}
}
static void drawTile(int index, float cameraX, float cameraY, float cameraZ, bool useTexture, bool useColor) {
//LOGI("draw tile: %d", index);
if (index < sTileCount) {
Tile* currentTile = &sTiles[index];
const float dx = currentTile->centerX - cameraX;
const float dz = currentTile->centerZ - cameraZ;
const float distanceFromCamera2 = (dx * dx) + (dz * dz);
int lod = currentTile->lodCount - 1;
if (distanceFromCamera2 < currentTile->maxLodDistance2) {
const int bucket = (int)((distanceFromCamera2 / currentTile->maxLodDistance2) * currentTile->lodCount);
lod = bucket < (currentTile->lodCount - 1) ? bucket : currentTile->lodCount - 1;
}
ASSERT(lod < currentTile->lodCount);
Mesh* lodMesh = ¤tTile->lods[lod];
//LOGI("mesh %d: count: %d", index, lodMesh->indexCount);
const GLint coordinateType = lodMesh->useFixedPoint ? GL_FIXED : GL_FLOAT;
glPushMatrix();
glTranslatef(currentTile->x, currentTile->y, currentTile->z);
glBindBuffer(GL_ARRAY_BUFFER, lodMesh->vertexBuffer);
glVertexPointer(3, coordinateType, 0, 0);
if (useTexture) {
int texture = currentTile->textures[0];
if( currentTile->textures[lod] != -1 ) {
texture = currentTile->textures[lod];
}
glBindTexture(GL_TEXTURE_2D, texture);
glBindBuffer(GL_ARRAY_BUFFER, lodMesh->textureBuffer);
glTexCoordPointer(2, coordinateType, 0, 0);
}
if (useColor) {
glBindBuffer(GL_ARRAY_BUFFER, lodMesh->colorBuffer);
glColorPointer(4, coordinateType, 0, 0);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lodMesh->indexBuffer);
glDrawElements(GL_TRIANGLES, lodMesh->indexCount,
GL_UNSIGNED_SHORT, 0);
glPopMatrix();
}
}
// Blatantly copied from the GLU ES project:
// http://code.google.com/p/glues/
static void __gluMakeIdentityf(GLfloat m[16])
{
m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
}
static void normalize(GLfloat v[3])
{
GLfloat r;
r=(GLfloat)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
if (r==0.0f)
{
return;
}
v[0]/=r;
v[1]/=r;
v[2]/=r;
}
static void cross(GLfloat v1[3], GLfloat v2[3], GLfloat result[3])
{
result[0] = v1[1]*v2[2] - v1[2]*v2[1];
result[1] = v1[2]*v2[0] - v1[0]*v2[2];
result[2] = v1[0]*v2[1] - v1[1]*v2[0];
}
static void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx,
GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy,
GLfloat upz)
{
GLfloat forward[3], side[3], up[3];
GLfloat m[4][4];
forward[0] = centerx - eyex;
forward[1] = centery - eyey;
forward[2] = centerz - eyez;
up[0] = upx;
up[1] = upy;
up[2] = upz;
normalize(forward);
/* Side = forward x up */
cross(forward, up, side);
normalize(side);
/* Recompute up as: up = side x forward */
cross(side, forward, up);
__gluMakeIdentityf(&m[0][0]);
m[0][0] = side[0];
m[1][0] = side[1];
m[2][0] = side[2];
m[0][1] = up[0];
m[1][1] = up[1];
m[2][1] = up[2];
m[0][2] = -forward[0];
m[1][2] = -forward[1];
m[2][2] = -forward[2];
glMultMatrixf(&m[0][0]);
glTranslatef(-eyex, -eyey, -eyez);
}
/* Call to render the next GL frame */
static void nativeRender(
JNIEnv* env,
jobject thiz,
jfloat cameraX,
jfloat cameraY,
jfloat cameraZ,
jfloat lookAtX,
jfloat lookAtY,
jfloat lookAtZ,
jboolean useTexture,
jboolean useColor,
jboolean cameraDirty) {
//LOGI("render");
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (cameraDirty) {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(cameraX, cameraY, cameraZ,
lookAtX, lookAtY, lookAtZ,
0.0f, 1.0f, 0.0f);
}
glEnableClientState(GL_VERTEX_ARRAY);
if (useTexture) {
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
} else {
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
}
if (useColor) {
glEnableClientState(GL_COLOR_ARRAY);
} else {
glDisableClientState(GL_COLOR_ARRAY);
}
if (sSkybox != -1) {
glDepthMask(false);
glDisable(GL_DEPTH_TEST);
drawTile(sSkybox, cameraX, cameraY, cameraZ, useTexture, useColor);
glDepthMask(true);
glEnable(GL_DEPTH_TEST);
}
for (int x = 0; x < sTileCount; x++) {
if (x != sSkybox) {
drawTile(x, cameraX, cameraY, cameraZ, useTexture, useColor);
}
}
glDisableClientState(GL_VERTEX_ARRAY);
//LOGI("render complete");
}
static const char* classPathName = "com/android/heightmapprofiler/NativeRenderer";
static JNINativeMethod methods[] = {
{"nativeReset", "()V", (void*)nativeReset },
{"nativeRender", "(FFFFFFZZZ)V", (void*)nativeRender },
{"nativeAddTile", "(IIFFFFFFF)I", (void*)nativeAddTile },
{"nativeAddLod", "(IIIIIIZ)V", (void*)nativeAddLod },
{"nativeSetSkybox", "(I)V", (void*)nativeSetSkybox },
{"nativeAddTextureLod", "(III)V", (void*)nativeAddTextureLod},
};
/*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
clazz = env->FindClass(className);
if (clazz == NULL) {
char error[255];
sprintf(error,
"Native registration unable to find class '%s'\n", className);
__android_log_print(ANDROID_LOG_ERROR, "HeightMapProfiler", error);
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
char error[255];
sprintf(error, "RegisterNatives failed for '%s'\n", className);
__android_log_print(ANDROID_LOG_ERROR, "HeightMapProfiler", error);
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* Register native methods for all classes we know about.
*/
static int registerNatives(JNIEnv* env)
{
if (!registerNativeMethods(env, classPathName,
methods, sizeof(methods) / sizeof(methods[0]))) {
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* Set some test stuff up.
*
* Returns the JNI version on success, -1 on failure.
*/
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed");
goto bail;
}
assert(env != NULL);
if (!registerNatives(env)) {
LOGE("ERROR: HeightMapProfiler native registration failed");
goto bail;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
bail:
return result;
}
Other Android examples (source code examples)Here is a short list of links related to this Android height_map.cpp source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.