//Copyright (c) 2011-2020 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose. // NO WARRANTY! NO GUARANTEE OF SUPPORT! USE AT YOUR OWN RISK #include #include #include #include #include "os_generic.h" #include //A-s-s-e-t-s #include //A-s-s-e-t-s #include #include //SENSORSTURFF #include #include #include #include #include "CNFGAndroid.h" //#define CNFA_IMPLEMENTATION #define CNFG_IMPLEMENTATION #define CNFG3D //AUDIO //#include "cnfa/CNFA.h" #include "CNFG.h" //webview//#define WEBVIEW_NATIVE_ACTIVITY_IMPLEMENTATION //webview//#include "webview_native_activity.h" float mountainangle; float mountainoffsetx; float mountainoffsety; //SENSORSTURFF ASensorManager * sm; //SENSORSTURFF const ASensor * as; //SENSORSTURFF bool no_sensor_for_gyro = false; //SENSORSTURFF ASensorEventQueue* aeq; //SENSORSTURFF ALooper * l; //webview//WebViewNativeActivityObject MyWebView; //AUDIO const uint32_t SAMPLE_RATE = 44100; //AUDIO const uint16_t SAMPLE_COUNT = 512; //AUDIO uint32_t stream_offset = 0; //AUDIO uint16_t audio_frequency; //SENSORSTURFF // Inertial Measurement Unit (gyroscopes and accelerometer) //SENSORSTURFF void SetupIMU() //SENSORSTURFF { //SENSORSTURFF sm = ASensorManager_getInstanceForPackage("gyroscope"); //SENSORSTURFF as = ASensorManager_getDefaultSensor( sm, ASENSOR_TYPE_GYROSCOPE ); //SENSORSTURFF no_sensor_for_gyro = as == NULL; //SENSORSTURFF l = ALooper_prepare( ALOOPER_PREPARE_ALLOW_NON_CALLBACKS ); //SENSORSTURFF aeq = ASensorManager_createEventQueue( sm, (ALooper*)&l, 0, 0, 0 ); //XXX??!?! This looks wrong. //SENSORSTURFF if(!no_sensor_for_gyro) { //SENSORSTURFF ASensorEventQueue_enableSensor( aeq, as); //SENSORSTURFF printf( "setEvent Rate: %d\n", ASensorEventQueue_setEventRate( aeq, as, 10000 ) ); //SENSORSTURFF } //SENSORSTURFF //SENSORSTURFF } //SENSORSTURFF float accx, accy, accz; //SENSORSTURFF int accs; //SENSORSTURFF //SENSORSTURFF void AccCheck() //SENSORSTURFF { //SENSORSTURFF if(no_sensor_for_gyro) { //SENSORSTURFF return; //SENSORSTURFF } //SENSORSTURFF //SENSORSTURFF ASensorEvent evt; //SENSORSTURFF do //SENSORSTURFF { //SENSORSTURFF ssize_t s = ASensorEventQueue_getEvents( aeq, &evt, 1 ); //SENSORSTURFF if( s <= 0 ) break; //SENSORSTURFF accx = evt.vector.v[0]; //SENSORSTURFF accy = evt.vector.v[1]; //SENSORSTURFF accz = evt.vector.v[2]; //SENSORSTURFF mountainangle /*degrees*/ -= accz;// * 3.1415 / 360.0;// / 100.0; //SENSORSTURFF mountainoffsety += accy; //SENSORSTURFF mountainoffsetx += accx; //SENSORSTURFF accs++; //SENSORSTURFF } while( 1 ); //SENSORSTURFF } unsigned frames = 0; unsigned long iframeno = 0; void AndroidDisplayKeyboard(int pShow); int lastbuttonx = 0; int lastbuttony = 0; int lastmotionx = 0; int lastmotiony = 0; int lastbid = 0; int lastmask = 0; int lastkey, lastkeydown; static int keyboard_up; uint8_t buttonstate[8]; void HandleKey( int keycode, int bDown ) { lastkey = keycode; lastkeydown = bDown; if( keycode == 10 && !bDown ) { keyboard_up = 0; AndroidDisplayKeyboard( keyboard_up ); } if( keycode == 4 ) { AndroidSendToBack( 1 ); } //Handle Physical Back Button. } void HandleButton( int x, int y, int button, int bDown ) { buttonstate[button] = bDown; lastbid = button; lastbuttonx = x; lastbuttony = y; if( bDown ) { keyboard_up = !keyboard_up; AndroidDisplayKeyboard( keyboard_up ); } } void HandleMotion( int x, int y, int mask ) { lastmask = mask; lastmotionx = x; lastmotiony = y; } //writes the text to a file to path (example): /storage/emulated/0/Android/data/org.yourorg.cnfgtest/files // You would not normally want to do this, but it's an example of how to do local storage. void Log(const char *fmt, ...) { const char* getpath = AndroidGetExternalFilesDir(); char buffer[2048]; snprintf(buffer, sizeof(buffer), "%s/log.txt", getpath); FILE *f = fopen(buffer, "w"); if (f == NULL) { exit(1); } va_list arg; va_start(arg, fmt); vsnprintf(buffer, sizeof(buffer), fmt, arg); va_end(arg); fprintf(f, "%s\n", buffer); fclose(f); } #define HMX 162 #define HMY 162 short screenx, screeny; float Heightmap[HMX*HMY]; extern struct android_app * gapp; void DrawHeightmap() { int x, y; //float fdt = ((iframeno++)%(360*10))/10.0; mountainangle += .2; if( mountainangle < 0 ) mountainangle += 360; if( mountainangle > 360 ) mountainangle -= 360; mountainoffsety = mountainoffsety - ((mountainoffsety-100) * .1); float eye[3] = { (float)(sin(mountainangle*(3.14159/180.0))*30*sin(mountainoffsety/100.)), (float)(cos(mountainangle*(3.14159/180.0))*30*sin(mountainoffsety/100.)), (float)(30*cos(mountainoffsety/100.)) }; float at[3] = { 0,0, 0 }; float up[3] = { 0,0, 1 }; tdSetViewport( -1, -1, 1, 1, screenx, screeny ); tdMode( tdPROJECTION ); tdIdentity( gSMatrix ); tdPerspective( 30, ((float)screenx)/((float)screeny), .1, 200., gSMatrix ); tdMode( tdMODELVIEW ); tdIdentity( gSMatrix ); tdTranslate( gSMatrix, 0, 0, -40 ); tdLookAt( gSMatrix, eye, at, up ); float scale = 60./HMX; for( x = 0; x < HMX-1; x++ ) for( y = 0; y < HMY-1; y++ ) { float tx = x-HMX/2; float ty = y-HMY/2; float pta[3]; float ptb[3]; float ptc[3]; float ptd[3]; float normal[3]; float lightdir[3] = { .6, -.6, 1 }; float tmp1[3]; float tmp2[3]; RDPoint pto[6]; pta[0] = (tx+0)*scale; pta[1] = (ty+0)*scale; pta[2] = Heightmap[(x+0)+(y+0)*HMX]*scale; ptb[0] = (tx+1)*scale; ptb[1] = (ty+0)*scale; ptb[2] = Heightmap[(x+1)+(y+0)*HMX]*scale; ptc[0] = (tx+0)*scale; ptc[1] = (ty+1)*scale; ptc[2] = Heightmap[(x+0)+(y+1)*HMX]*scale; ptd[0] = (tx+1)*scale; ptd[1] = (ty+1)*scale; ptd[2] = Heightmap[(x+1)+(y+1)*HMX]*scale; tdPSub( pta, ptb, tmp2 ); tdPSub( ptc, ptb, tmp1 ); tdCross( tmp1, tmp2, normal ); tdNormalizeSelf( normal ); tdFinalPoint( pta, pta ); tdFinalPoint( ptb, ptb ); tdFinalPoint( ptc, ptc ); tdFinalPoint( ptd, ptd ); if( pta[2] >= 1.0 ) continue; if( ptb[2] >= 1.0 ) continue; if( ptc[2] >= 1.0 ) continue; if( ptd[2] >= 1.0 ) continue; if( pta[2] < 0 ) continue; if( ptb[2] < 0 ) continue; if( ptc[2] < 0 ) continue; if( ptd[2] < 0 ) continue; pto[0].x = pta[0]; pto[0].y = pta[1]; pto[1].x = ptb[0]; pto[1].y = ptb[1]; pto[2].x = ptd[0]; pto[2].y = ptd[1]; pto[3].x = ptc[0]; pto[3].y = ptc[1]; pto[4].x = ptd[0]; pto[4].y = ptd[1]; pto[5].x = pta[0]; pto[5].y = pta[1]; // CNFGColor(((x+y)&1)?0xFFFFFF:0x000000); float bright = tdDot( normal, lightdir ); if( bright < 0 ) bright = 0; CNFGColor( 0xff | ( ( (int)( bright * 90 ) ) << 24 ) ); // CNFGTackPoly( &pto[0], 3 ); CNFGTackPoly( &pto[3], 3 ); CNFGTackSegment( pta[0], pta[1], ptb[0], ptb[1] ); CNFGTackSegment( pta[0], pta[1], ptc[0], ptc[1] ); CNFGTackSegment( ptb[0], ptb[1], ptc[0], ptc[1] ); } } int HandleDestroy() { printf( "Destroying\n" ); return 0; } volatile int suspended; void HandleSuspend() { suspended = 1; } void HandleResume() { suspended = 0; } /* void AudioCallback( struct CNFADriver * sd, short * out, short * in, int framesp, int framesr ) { memset(out, 0, framesp*sizeof(uint16_t)); if(suspended) return; if(!buttonstate[1]) return; // play audio only if ~touching with two fingers audio_frequency = 440; for(uint32_t i = 0; i < framesp; i++) { int16_t sample = INT16_MAX * sin(audio_frequency*(2*M_PI)*(stream_offset+i)/SAMPLE_RATE); out[i] = sample; } stream_offset += framesp; } */ void MakeNotification( const char * channelID, const char * channelName, const char * title, const char * message ) { static int id; id++; const struct JNINativeInterface * env = 0; const struct JNINativeInterface ** envptr = &env; const struct JNIInvokeInterface ** jniiptr = gapp->activity->vm; const struct JNIInvokeInterface * jnii = *jniiptr; jnii->AttachCurrentThread( jniiptr, &envptr, NULL); env = (*envptr); jstring channelIDStr = env->NewStringUTF( ENVCALL channelID ); jstring channelNameStr = env->NewStringUTF( ENVCALL channelName ); // Runs getSystemService(Context.NOTIFICATION_SERVICE). jclass NotificationManagerClass = env->FindClass( ENVCALL "android/app/NotificationManager" ); jclass activityClass = env->GetObjectClass( ENVCALL gapp->activity->clazz ); jmethodID MethodGetSystemService = env->GetMethodID( ENVCALL activityClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"); jstring notificationServiceName = env->NewStringUTF( ENVCALL "notification" ); jobject notificationServiceObj = env->CallObjectMethod( ENVCALL gapp->activity->clazz, MethodGetSystemService, notificationServiceName); // create the Notification channel. jclass notificationChannelClass = env->FindClass( ENVCALL "android/app/NotificationChannel" ); jmethodID notificationChannelConstructorID = env->GetMethodID( ENVCALL notificationChannelClass, "", "(Ljava/lang/String;Ljava/lang/CharSequence;I)V" ); jobject notificationChannelObj = env->NewObject( ENVCALL notificationChannelClass, notificationChannelConstructorID, channelIDStr, channelNameStr, 3 ); // IMPORTANCE_DEFAULT jmethodID createNotificationChannelID = env->GetMethodID( ENVCALL NotificationManagerClass, "createNotificationChannel", "(Landroid/app/NotificationChannel;)V" ); env->CallVoidMethod( ENVCALL notificationServiceObj, createNotificationChannelID, notificationChannelObj ); env->DeleteLocalRef( ENVCALL channelNameStr ); env->DeleteLocalRef( ENVCALL notificationChannelObj ); // Create the Notification builder. jclass classBuilder = env->FindClass( ENVCALL "android/app/Notification$Builder" ); jstring titleStr = env->NewStringUTF( ENVCALL title ); jstring messageStr = env->NewStringUTF( ENVCALL message ); jmethodID eventConstructor = env->GetMethodID( ENVCALL classBuilder, "", "(Landroid/content/Context;Ljava/lang/String;)V" ); jobject eventObj = env->NewObject( ENVCALL classBuilder, eventConstructor, gapp->activity->clazz, channelIDStr ); jmethodID setContentTitleID = env->GetMethodID( ENVCALL classBuilder, "setContentTitle", "(Ljava/lang/CharSequence;)Landroid/app/Notification$Builder;" ); jmethodID setContentTextID = env->GetMethodID( ENVCALL classBuilder, "setContentText", "(Ljava/lang/CharSequence;)Landroid/app/Notification$Builder;" ); jmethodID setSmallIconID = env->GetMethodID( ENVCALL classBuilder, "setSmallIcon", "(I)Landroid/app/Notification$Builder;" ); // You could do things like setPriority, or setContentIntent if you want it to do something when you click it. env->CallObjectMethod( ENVCALL eventObj, setContentTitleID, titleStr ); env->CallObjectMethod( ENVCALL eventObj, setContentTextID, messageStr ); env->CallObjectMethod( ENVCALL eventObj, setSmallIconID, 17301504 ); // R.drawable.alert_dark_frame // eventObj.build() jmethodID buildID = env->GetMethodID( ENVCALL classBuilder, "build", "()Landroid/app/Notification;" ); jobject notification = env->CallObjectMethod( ENVCALL eventObj, buildID ); // NotificationManager.notify(...) jmethodID notifyID = env->GetMethodID( ENVCALL NotificationManagerClass, "notify", "(ILandroid/app/Notification;)V" ); env->CallVoidMethod( ENVCALL notificationServiceObj, notifyID, id, notification ); env->DeleteLocalRef( ENVCALL notification ); env->DeleteLocalRef( ENVCALL titleStr ); env->DeleteLocalRef( ENVCALL activityClass ); env->DeleteLocalRef( ENVCALL messageStr ); env->DeleteLocalRef( ENVCALL channelIDStr ); env->DeleteLocalRef( ENVCALL NotificationManagerClass ); env->DeleteLocalRef( ENVCALL notificationServiceObj ); env->DeleteLocalRef( ENVCALL notificationServiceName ); } void HandleThisWindowTermination() { suspended = 1; } uint32_t randomtexturedata[256*256]; //webview //uint32_t webviewdata[500*500]; //webview //char fromJSBuffer[128]; //webview //webview //void CheckWebView( void * v ) //webview //{ //webview // static int runno = 0; //webview // WebViewNativeActivityObject * wvn = (WebViewNativeActivityObject*)v; //webview // if( WebViewGetProgress( wvn ) != 100 ) return; //webview // //webview // runno++; //webview // if( runno == 1 ) //webview // { //webview // // The attach (initial) message payload has no meaning. //webview // WebViewPostMessage( wvn, "", 1 ); //webview // } //webview // else //webview // { //webview // // Invoke JavaScript, which calls a function to send a webmessage //webview // // back into C land. //webview // WebViewExecuteJavascript( wvn, "SendMessageToC();" ); //webview // //webview // // Send a WebMessage into the JavaScript code. //webview // char st[128]; //webview // sprintf( st, "Into JavaScript %d\n", runno ); //webview // WebViewPostMessage( wvn, st, 0 ); //webview // } //webview //} //webview//jobject g_attachLooper; //webview //void SetupWebView( void * v ) //webview //{ //webview // WebViewNativeActivityObject * wvn = (WebViewNativeActivityObject*)v; //webview // //webview // //webview // const struct JNINativeInterface * env = 0; //webview // const struct JNINativeInterface ** envptr = &env; //webview // const struct JNIInvokeInterface ** jniiptr = gapp->activity->vm; //webview // const struct JNIInvokeInterface * jnii = *jniiptr; //webview // //webview // jnii->AttachCurrentThread( jniiptr, &envptr, NULL); //webview // env = (*envptr); //webview // //webview // while( g_attachLooper == 0 ) usleep(1); //webview // WebViewCreate( wvn, "file:///android_asset/index.html", g_attachLooper, 500, 500 ); //webview // //WebViewCreate( wvn, "about:blank", g_attachLooper, 500, 500 ); //webview //} //webview //pthread_t jsthread; //webview // //webview //void * JavscriptThread( void * v ) //webview //{ //webview // const struct JNINativeInterface * env = 0; //webview // const struct JNINativeInterface ** envptr = &env; //webview // const struct JNIInvokeInterface ** jniiptr = gapp->activity->vm; //webview // const struct JNIInvokeInterface * jnii = *jniiptr; //webview // //webview // jnii->AttachCurrentThread( jniiptr, &envptr, NULL); //webview // env = (*envptr); //webview // //webview // // Create a looper on this thread... //webview // jclass LooperClass = env->FindClass(envptr, "android/os/Looper"); //webview // jmethodID myLooperMethod = env->GetStaticMethodID(envptr, LooperClass, "myLooper", "()Landroid/os/Looper;"); //webview // jobject thisLooper = env->CallStaticObjectMethod( envptr, LooperClass, myLooperMethod ); //webview // if( !thisLooper ) //webview // { //webview // jmethodID prepareMethod = env->GetStaticMethodID(envptr, LooperClass, "prepare", "()V"); //webview // env->CallStaticVoidMethod( envptr, LooperClass, prepareMethod ); //webview // thisLooper = env->CallStaticObjectMethod( envptr, LooperClass, myLooperMethod ); //webview // g_attachLooper = env->NewGlobalRef(envptr, thisLooper); //webview // } //webview // //webview // jmethodID getQueueMethod = env->GetMethodID( envptr, LooperClass, "getQueue", "()Landroid/os/MessageQueue;" ); //webview // jobject lque = env->CallObjectMethod( envptr, g_attachLooper, getQueueMethod ); //webview // //webview // jclass MessageQueueClass = env->FindClass(envptr, "android/os/MessageQueue"); //webview // jmethodID nextMethod = env->GetMethodID( envptr, MessageQueueClass, "next", "()Landroid/os/Message;" ); //webview // //webview // jclass MessageClass = env->FindClass(envptr, "android/os/Message"); //webview // jfieldID objid = env->GetFieldID( envptr, MessageClass, "obj", "Ljava/lang/Object;" ); //webview // jclass PairClass = env->FindClass(envptr, "android/util/Pair"); //webview // jfieldID pairfirst = env->GetFieldID( envptr, PairClass, "first", "Ljava/lang/Object;" ); //webview // //webview // while(1) //webview // { //webview // // Instead of using Looper::loop(), we just call next on the looper object. //webview // jobject msg = env->CallObjectMethod( envptr, lque, nextMethod ); //webview // jobject innerObj = env->GetObjectField( envptr, msg, objid ); //webview // const char * name; //webview // jstring strObj; //webview // jclass innerClass; //webview // //webview // // Check Object Type //webview // { //webview // innerClass = env->GetObjectClass( envptr, innerObj ); //webview // jmethodID mid = env->GetMethodID( envptr, innerClass, "getClass", "()Ljava/lang/Class;"); //webview // jobject clsObj = env->CallObjectMethod( envptr, innerObj, mid ); //webview // jclass clazzz = env->GetObjectClass( envptr, clsObj ); //webview // mid = env->GetMethodID(envptr, clazzz, "getName", "()Ljava/lang/String;"); //webview // strObj = (jstring)env->CallObjectMethod( envptr, clsObj, mid); //webview // name = env->GetStringUTFChars( envptr, strObj, 0); //webview // env->DeleteLocalRef( envptr, clsObj ); //webview // env->DeleteLocalRef( envptr, clazzz ); //webview // } //webview // //webview // if( strcmp( name, "z5" ) == 0 ) //webview // { //webview // // Special, Some Androids (notably Meta Quest) use a different private message type. //webview // jfieldID mstrf = env->GetFieldID( envptr, innerClass, "a", "[B" ); //webview // jbyteArray jba = (jstring)env->GetObjectField(envptr, innerObj, mstrf ); //webview // int len = env->GetArrayLength( envptr, jba ); //webview // jboolean isCopy = 0; //webview // jbyte * bufferPtr = env->GetByteArrayElements(envptr, jba, &isCopy); //webview // //webview // if( len >= 6 ) //webview // { //webview // const char *descr = (const char*)bufferPtr + 6; //webview // char tcpy[len-5]; //webview // memcpy( tcpy, descr, len-6 ); //webview // tcpy[len-6] = 0; //webview // snprintf( fromJSBuffer, sizeof( fromJSBuffer)-1, "WebMessage: %s\n", tcpy ); //webview // //webview // env->DeleteLocalRef( envptr, jba ); //webview // } //webview // } //webview // else //webview // { //webview // jobject MessagePayload = env->GetObjectField( envptr, innerObj, pairfirst ); //webview // // MessagePayload is a org.chromium.content_public.browser.MessagePayload //webview // //webview // jclass mpclass = env->GetObjectClass( envptr, MessagePayload ); //webview // //webview // // Get field "b" which is the web message payload. //webview // // If you are using binary sockets, it will be in `c` and be a byte array. //webview // jfieldID mstrf = env->GetFieldID( envptr, mpclass, "b", "Ljava/lang/String;" ); //webview // jstring strObjDescr = (jstring)env->GetObjectField(envptr, MessagePayload, mstrf ); //webview // //webview // const char *descr = env->GetStringUTFChars( envptr, strObjDescr, 0); //webview // snprintf( fromJSBuffer, sizeof( fromJSBuffer)-1, "WebMessage: %s\n", descr ); //webview // //webview // env->ReleaseStringUTFChars(envptr, strObjDescr, descr); //webview // env->DeleteLocalRef( envptr, strObjDescr ); //webview // env->DeleteLocalRef( envptr, MessagePayload ); //webview // env->DeleteLocalRef( envptr, mpclass ); //webview // } //webview // env->ReleaseStringUTFChars(envptr, strObj, name); //webview // env->DeleteLocalRef( envptr, strObj ); //webview // env->DeleteLocalRef( envptr, msg ); //webview // env->DeleteLocalRef( envptr, innerObj ); //webview // env->DeleteLocalRef( envptr, innerClass ); //webview // } //webview //} //webview // //webview //void SetupJSThread() //webview //{ //webview // pthread_create( &jsthread, 0, JavscriptThread, 0 ); //webview //} int main( int argc, char ** argv ) { int x, y; double ThisTime; double LastFPSTime = OGGetAbsoluteTime(); Log( "Starting Up" ); CNFGBGColor = 0x000040ff; CNFGSetupFullscreen( "Test Bench", 0 ); HandleWindowTermination = HandleThisWindowTermination; for( x = 0; x < HMX; x++ ) for( y = 0; y < HMY; y++ ) { Heightmap[x+y*HMX] = tdPerlin2D( x, y )*8.; } //A-s-s-e-t-s const char * assettext = "Not Found,2"; //A-s-s-e-t-s AAsset * file = AAssetManager_open( gapp->activity->assetManager, "asset.txt", AASSET_MODE_BUFFER ); //A-s-s-e-t-s if( file ) //A-s-s-e-t-s { //A-s-s-e-t-s size_t fileLength = AAsset_getLength(file); //A-s-s-e-t-s char * temp = (char*)malloc( fileLength + 1); //A-s-s-e-t-s memcpy( temp, AAsset_getBuffer( file ), fileLength ); //A-s-s-e-t-s temp[fileLength] = 0; //A-s-s-e-t-s assettext = temp; //A-s-s-e-t-s } //SENSORSTURFF // Inertial Measurement Unit (gyroscopes and accelerometer) //SENSORSTURFF SetupIMU(); //SOUND // Disabled, for now. //SOUND //InitCNFAAndroid( AudioCallback, "A Name", SAMPLE_RATE, 0, 1, 0, SAMPLE_COUNT, 0, 0, 0 ); //webview// SetupJSThread(); //webview // Create webview and wait for its completion //webview // RunCallbackOnUIThread( SetupWebView, &MyWebView ); //webview // while( !MyWebView.WebViewObject ) usleep(1); Log( "Startup Complete" ); while(1) { int i; iframeno++; if( iframeno == 200 ) { MakeNotification( "default", "rawdraw alerts", "rawdraw", "Hit frame two hundred\nNew Line" ); } CNFGHandleInput(); //SENSORSTURFF AccCheck(); if( suspended ) { usleep(50000); continue; } //webview // RunCallbackOnUIThread( (void(*)(void*))WebViewRequestRenderToCanvas, &MyWebView ); //webview // RunCallbackOnUIThread( CheckWebView, &MyWebView ); CNFGClearFrame(); CNFGColor( 0xFFFFFFFF ); CNFGGetDimensions( &screenx, &screeny ); // Mesh in background CNFGSetLineWidth( 9 ); DrawHeightmap(); CNFGPenX = 0; CNFGPenY = 400; CNFGColor( 0xffffffff ); //A-s-s-e-t-s CNFGDrawText( assettext, 15 ); CNFGFlushRender(); CNFGPenX = 0; CNFGPenY = 480; char st[50]; sprintf( st, "%dx%d %d %d %d %d %d %d\n%d %d", screenx, screeny, lastbuttonx, lastbuttony, lastmotionx, lastmotiony, lastkey, lastkeydown, lastbid, lastmask); CNFGDrawText( st, 10 ); CNFGSetLineWidth( 2 ); // Square behind text CNFGColor( 0x303030ff ); CNFGTackRectangle( 600, 0, 950, 350); CNFGPenX = 10; CNFGPenY = 10; // Text CNFGColor( 0xffffffff ); for( i = 0; i < 1; i++ ) { int c; char tw[2] = { 0, 0 }; for( c = 0; c < 256; c++ ) { tw[0] = c; CNFGPenX = ( c % 16 ) * 20+606; CNFGPenY = ( c / 16 ) * 20+5; CNFGDrawText( tw, 4 ); } } // Green triangles CNFGPenX = 0; CNFGPenY = 0; CNFGColor( 0x00FF00FF ); for( i = 0; i < 400; i++ ) { RDPoint pp[3]; pp[0].x = (short)(50*sin((float)(i+iframeno)*.01) + (i%20)*30); pp[0].y = (short)(50*cos((float)(i+iframeno)*.01) + (i/20)*20)+700; pp[1].x = (short)(20*sin((float)(i+iframeno)*.01) + (i%20)*30); pp[1].y = (short)(50*cos((float)(i+iframeno)*.01) + (i/20)*20)+700; pp[2].x = (short)(10*sin((float)(i+iframeno)*.01) + (i%20)*30); pp[2].y = (short)(30*cos((float)(i+iframeno)*.01) + (i/20)*20)+700; CNFGTackPoly( pp, 3 ); } // Last WebMessage CNFGColor( 0xFFFFFFFF ); CNFGPenX = 0; CNFGPenY = 100; // CNFGDrawText( fromJSBuffer, 6 ); int x, y; for( y = 0; y < 256; y++ ) for( x = 0; x < 256; x++ ) randomtexturedata[x+y*256] = x | ((x*394543L+y*355+iframeno*3)<<8); CNFGBlitImage( randomtexturedata, 100, 600, 256, 256 ); //webview //WebViewNativeGetPixels( &MyWebView, webviewdata, 500, 500 ); //webview //CNFGBlitImage( webviewdata, 500, 640, 500, 500 ); frames++; //On Android, CNFGSwapBuffers must be called, and CNFGUpdateScreenWithBitmap does not have an implied framebuffer swap. CNFGSwapBuffers(); ThisTime = OGGetAbsoluteTime(); if( ThisTime > LastFPSTime + 1 ) { printf( "FPS: %d\n", frames ); frames = 0; LastFPSTime+=1; } } return(0); }