On Android, I use JNI to send a string from C++ to Java then draw it to a bitmap then return the byte array back to C++ to draw it to OpenGL, I get a black rectangle .
First I create the bitmap in Java by this way:
public static byte[] DrawString(String text) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.rgb(110, 110, 110));
float scale = ActivityGame.getCurrentActivity().getResources().getDisplayMetrics().density;
paint.setTextSize((int) (24 * scale));
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
Bitmap bitmap = Bitmap.createBitmap((int) (bounds.width() * scale), (int) (bounds.height() * scale), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
int x = (bitmap.getWidth() - bounds.width()) / 6;
int y = (bitmap.getHeight() + bounds.height()) / 5;
canvas.drawText(text, x * scale, y * scale, paint);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
bitmap.recycle();
return byteArray;
}
then in C++ I call the previous function by JNI by this way:
static unsigned char* DrawString(std::string text,int* length){
JNIEnv *env= nullptr;
JNIUtils::JVM->AttachCurrentThread(&env, NULL);
jclass jniUtilsCls = env->FindClass("com/moussa/mightypolygons/JNIUtils");
jmethodID drawStringMethodId = env->GetStaticMethodID(jniUtilsCls, "DrawString", "(Ljava/lang/String;)[B");
jstring _text=env->NewStringUTF(text.c_str());
jbyteArray bmpArr=(jbyteArray)env->CallStaticObjectMethod(jniUtilsCls,drawStringMethodId,_text);
jsize num_bytes = env->GetArrayLength( bmpArr);
jbyte* elements = env->GetByteArrayElements(bmpArr, NULL);
unsigned char* bmp=new unsigned char[num_bytes];
if (elements) {
for(int i = 0; i < num_bytes; i++) {
bmp[i] = elements[i];
}
*length=(int)num_bytes;
return bmp;
}
return NULL;
}
Finally I get the char array and the length now I create a texture in OpenGL:
Texture::Texture(unsigned char *bmp,int len, TextureTypes type) {
image = stbi_load_from_memory(bmp,len, &width, &height, &nrComponents, 4);
glGenTextures(1, &textureObj);
if (image) {
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
else
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureObj);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
format == GL_RGBA ? GL_CLAMP_TO_EDGE : GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
format == GL_RGBA ? GL_CLAMP_TO_EDGE : GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(image);
} else {
stbi_image_free(image);
}
}
I get a black rectangle with same width and height of the bitmap.
Edit:
I saved the bitmap as PNG from Java side then reloaded it from C++ it was rendered perfect with same code, so is the problem is in bytes array or GL parameters or something else?
Edit 2:
I noticed in Java the ByteArray
contains signed bytes with negative values when it is cast to unsigned char*
in C++ it value changed, for example the first byte in the bytes array in Java is -119 it becomes 137 if cast to unsigned char