text: /*
  * Copyright (C) 2010 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 <EGL/egl.h>
  #include <EGL/eglext.h>
  #include <GLES3/gl3.h>
  #include "../../hlslmath.h"
  #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "AndroidProject1.NativeActivity", __VA_ARGS__))
  #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "AndroidProject1.NativeActivity", __VA_ARGS__))
  
  /**
  * Our saved state data.
  */
  struct saved_state {
  	float angle;
  	int32_t x;
  	int32_t y;
  };
  
  /**
  * Shared state for our app.
  */
  struct engine {
  	struct android_app* app;
  
  	ASensorManager* sensorManager;
  	const ASensor* accelerometerSensor;
  	ASensorEventQueue* sensorEventQueue;
  
  	int animating;
  	EGLDisplay display;
  	EGLSurface surface;
  	EGLContext context;
  	int32_t width;
  	int32_t height;
  	struct saved_state state;
  };
  
  static void hlsltest_draw_frame(struct engine* engine);
  
  /**
  * Initialize an EGL context for the current display.
  */
  static int engine_init_display(struct engine* engine) {
  	// initialize OpenGL ES and EGL
  
  	/*
  	* Here specify the attributes of the desired configuration.
  	* Below, we select an EGLConfig with at least 8 bits per color
  	* component compatible with on-screen windows
  	*/
  	const EGLint attribs[] = {
           EGL_RED_SIZE,       5,
           EGL_GREEN_SIZE,     6,
  EGL_BLUE_SIZE, 5,
          EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
  		EGL_NONE
  	};
  	EGLint w, h, format;
  	EGLint numConfigs;
  	EGLConfig config;
  	EGLSurface surface;
  	EGLContext context;
  
  	EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  
  	eglInitialize(display, 0, 0);
  
  	/* Here, the application chooses the configuration it desires. In this
  	* sample, we have a very simplified selection process, where we pick
  	* the first EGLConfig that matches our criteria */
  	eglChooseConfig(display, attribs, &config, 1, &numConfigs);
  
  	/* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
  	* guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
  	* As soon as we picked a EGLConfig, we can safely reconfigure the
  	* ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
  	eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
  
  	ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
  
      EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };
  	surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
  	context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
  
  	if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
  		LOGW("Unable to eglMakeCurrent");
  		return -1;
  	}
  
  	eglQuerySurface(display, surface, EGL_WIDTH, &w);
  	eglQuerySurface(display, surface, EGL_HEIGHT, &h);
  
  	engine->display = display;
  	engine->context = context;
  	engine->surface = surface;
  	engine->width = w;
  	engine->height = h;
  	engine->state.angle = 0;
  
  
  	return 0;
  }
  
  /**
  * Just the current frame in the display.
  */
  static void engine_draw_frame(struct engine* engine) {
  	if (engine->display == NULL) {
  		// No display.
  		return;
  	}
  
      glViewport(0, 0, engine->width, engine->height);    
  	glClear(GL_COLOR_BUFFER_BIT);       
  
      hlsltest_draw_frame(engine);
  
  	eglSwapBuffers(engine->display, engine->surface);
  }
  
  /**
  * Tear down the EGL context currently associated with the display.
  */
  static void engine_term_display(struct engine* engine) {
  	if (engine->display != EGL_NO_DISPLAY) {
  		eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  		if (engine->context != EGL_NO_CONTEXT) {
  			eglDestroyContext(engine->display, engine->context);
  		}
  		if (engine->surface != EGL_NO_SURFACE) {
  			eglDestroySurface(engine->display, engine->surface);
  		}
  		eglTerminate(engine->display);
  	}
  	engine->animating = 0;
  	engine->display = EGL_NO_DISPLAY;
  	engine->context = EGL_NO_CONTEXT;
  	engine->surface = EGL_NO_SURFACE;
  }
  
  /**
  * Process the next input event.
  */
  static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
  	struct engine* engine = (struct engine*)app->userData;
  	if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
  		engine->state.x = AMotionEvent_getX(event, 0);
  		engine->state.y = AMotionEvent_getY(event, 0);
  		return 1;
  	}
  	return 0;
  }
  
  void hlsltest_create();
  
  /**
  * Process the next main command.
  */
  static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
  	struct engine* engine = (struct engine*)app->userData;
  	switch (cmd) {
  	case APP_CMD_SAVE_STATE:
  		// The system has asked us to save our current state.  Do so.
  		engine->app->savedState = malloc(sizeof(struct saved_state));
  		*((struct saved_state*)engine->app->savedState) = engine->state;
  		engine->app->savedStateSize = sizeof(struct saved_state);
  		break;
  	case APP_CMD_INIT_WINDOW:
  		// The window is being shown, get it ready.
  		if (engine->app->window != NULL) {
  			engine_init_display(engine);
              hlsltest_create();
  
  			engine_draw_frame(engine);
  		}
  		break;
  	case APP_CMD_TERM_WINDOW:
  		// The window is being hidden or closed, clean it up.
  		engine_term_display(engine);
  		break;
  	case APP_CMD_GAINED_FOCUS:
  		// When our app gains focus, we start monitoring the accelerometer.
  		if (engine->accelerometerSensor != NULL) {
  			ASensorEventQueue_enableSensor(engine->sensorEventQueue,
  				engine->accelerometerSensor);
  			// We'd like to get 60 events per second (in us).
  			ASensorEventQueue_setEventRate(engine->sensorEventQueue,
  				engine->accelerometerSensor, (1000L / 60) * 1000);
  		}
  		break;
  	case APP_CMD_LOST_FOCUS:
  		// When our app loses focus, we stop monitoring the accelerometer.
  		// This is to avoid consuming battery while not being used.
  		if (engine->accelerometerSensor != NULL) {
  			ASensorEventQueue_disableSensor(engine->sensorEventQueue,
  				engine->accelerometerSensor);
  		}
  		// Also stop animating.
  		engine->animating = 0;
  		engine_draw_frame(engine);
  		break;
  	}
  }
  
  /**
  * This is the main entry point of a native application that is using
  * android_native_app_glue.  It runs in its own thread, with its own
  * event loop for receiving input events and doing other things.
  */
  void android_main(struct android_app* state) {
  	struct engine engine;
  
  	memset(&engine, 0, sizeof(engine));
  	state->userData = &engine;
  	state->onAppCmd = engine_handle_cmd;
  	state->onInputEvent = engine_handle_input;
  	engine.app = state;
  
  	// Prepare to monitor accelerometer
  	engine.sensorManager = ASensorManager_getInstance();
  	engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
  		ASENSOR_TYPE_ACCELEROMETER);
  	engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,
  		state->looper, LOOPER_ID_USER, NULL, NULL);
  
  	if (state->savedState != NULL) {
  		// We are starting with a previous saved state; restore from it.
  		engine.state = *(struct saved_state*)state->savedState;
  	}
  
  	engine.animating = 1;
  
  	// loop waiting for stuff to do.
  
  	while (1) {
  		// Read all pending events.
  		int ident;
  		int events;
  		struct android_poll_source* source;
  
  		// If not animating, we will block forever waiting for events.
  		// If animating, we loop until all events are read, then continue
  		// to draw the next frame of animation.
  		while ((ident = ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,
  			(void**)&source)) >= 0) {
  
  			// Process this event.
  			if (source != NULL) {
  				source->process(state, source);
  			}
  
  			// If a sensor has data, process it now.
  			if (ident == LOOPER_ID_USER) {
  				if (engine.accelerometerSensor != NULL) {
  					ASensorEvent event;
  					while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
  						&event, 1) > 0) {
  						LOGI("accelerometer: x=%f y=%f z=%f",
  							event.acceleration.x, event.acceleration.y,
  							event.acceleration.z);
  					}
  				}
  			}
  
  			// Check if we are exiting.
  			if (state->destroyRequested != 0) {
  				engine_term_display(&engine);
  				return;
  			}
  		}
  
  		if (engine.animating) {
  			// Done with events; draw next animation frame.
  			engine.state.angle += .01f;
  			if (engine.state.angle > 1) {
  				engine.state.angle = 0;
  			}
  
  			// Drawing is throttled to the screen update rate, so there
  			// is no need to do timing here.
  			engine_draw_frame(&engine);
  		}
  	}
  }
  
  
  GLuint hlsltest_create_shader(GLenum type, const GLchar* src)
  {
      GLuint shader = glCreateShader(type);
      glShaderSource(shader, 1, &src, NULL);
      glCompileShader(shader);
  
      GLint status;
      glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
      if (!status)
      {
          char infolog[1024];
          glGetShaderInfoLog(shader, sizeof(infolog) - 1, NULL, infolog);
  
          glDeleteShader(shader);
          return 0;
      }
      else
      {
          return shader;
      }
  }
  
  static bool created = false;
  static GLuint vao;
  static GLuint vbo;
  static GLuint program;
  
  static float3 vertices[] =
  {
      float3(-0.5f, -0.5f, 0.0f),
      float3( 0.0f,  0.5f, 0.0f),
      float3( 0.5f, -0.5f, 0.0f),
  };
  
  void hllstest_float2()
  {
      float2 a = float2(1, 2);
      float2 b = float2(3, 4);
  
      float2 c = a + b;
      float2 d = a - b;
      float2 e = a * b;
      float2 f = a / b;
  
      return;
  }
  
  void hlsltest_create()
  {
      hllstest_float2();
      if (!created)
      {
          const char* vshader_src =
              "#version 300 es                             \n"
              "layout (location = 0) in vec4 vert;         \n"
              "uniform mat4 MVP;                           \n"
              "void main() {                               \n"
              "  gl_Position = MVP * vert;                 \n"
              "}                                           \n";
  
          const char* fshader_src =
              "#version 300 es                             \n"
              "precision mediump float;                    \n"
              "out vec4 fragColor;                         \n"
              "void main() {                               \n"
              "  fragColor = vec4(1.0, 1.0, 1.0, 1.0);     \n"
              "}                                           \n";
  
          GLuint vshader = hlsltest_create_shader(GL_VERTEX_SHADER, vshader_src);
          GLuint fshader = hlsltest_create_shader(GL_FRAGMENT_SHADER, fshader_src);
  
          program = glCreateProgram();
          glAttachShader(program, vshader);
          glAttachShader(program, fshader);
          glLinkProgram(program);
  
          GLint link_status;
          glGetProgramiv(program, GL_LINK_STATUS, &link_status);
          if (!link_status)
          {
              return;
          }
  
          //glGenBuffers(1, &vbo);
          //glBindBuffer(GL_ARRAY_BUFFER, vbo);
          //glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
          //glBindBuffer(GL_ARRAY_BUFFER, 0);
  
          created = true;
      }
  }
  
  void hlsltest_draw_frame(struct engine* engine)
  {
      glUseProgram(program);
  
      float4x4 model = mul(float4x4::translate(-100.0f, 0.0f), float4x4::scale(200.0f, 200.0f, 200.0f));
      float4x4 proj = float4x4::ortho(-engine->width * 0.5f, engine->width * 0.5f, -engine->height * 0.5f, engine->height * 0.5f, 0.0f, 100.0f);
      float4x4 MVP = mul(proj, model);
      GLint location = glGetUniformLocation(program, "MVP");
      glUniformMatrix4fv(location, 1, false, (const float*)&MVP);
  
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices);
      glEnableVertexAttribArray(0);         
  
      glDrawArrays(GL_TRIANGLES, 0, 3);
  }