alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Android example source code file (height_map.cpp)

This example Android source code file (height_map.cpp) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Android by Example" TM.

Java - Android tags/keywords

adding, assert, error, glfloat, heightmapprofiler, jni_false, jni_version_1_4, jnienv, loge, logi, logtitle, mesh, null, tile

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

 

new blog posts

 

Copyright 1998-2021 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.