#include #include #include "osmroute.h" #include "system.h" #include #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "sposmroute", __VA_ARGS__)) #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "sposmroute", __VA_ARGS__)) iPoint gfx_screensize; struct font *drawfont = NULL; int gfx_last_img_fbo = 0; int gfx_last_alloc_img = 0; void gfx_fbo_switch (struct image *img); /*********************** GLES functions **************************************/ GLuint LoadShader (const char *shader_src, GLenum type) { GLuint shader; GLint compiled; shader = glCreateShader(type); if (shader == 0) return 0; glShaderSource (shader, 1, &shader_src, NULL); glCompileShader (shader); glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLint info_len = 0; glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &info_len); if (info_len > 1) { char *info_log = malloc (info_len); glGetShaderInfoLog (shader, info_len, NULL, info_log); d_printf ("LoadShader compile error: '%s'", info_log); exit (1); } glDeleteShader (shader); return 0; } return shader; }; /*****************************************************************************/ void gfx_init (int width, int height) { GLbyte vshader_str[] = { "attribute vec4 vPosition; \n" "attribute vec2 vTexture; \n" "varying vec2 v_txcoordinate; \n" "uniform mat4 uMvp; \n" "void main() { \n" " v_txcoordinate = vTexture; \n" " gl_Position = vPosition * uMvp; \n" "} \n" }; GLbyte fshader_str[] = { "precision mediump float; \n" "uniform vec4 vColor; \n" "uniform int txenabled; \n" "uniform sampler2D s_texture; \n" "varying mediump vec2 v_txcoordinate; \n" "void main() { \n" " if (txenabled == 1) \n" " gl_FragColor = vColor * texture2D(s_texture, v_txcoordinate); \n" " else if (txenabled == 2) \n" " gl_FragColor = vColor * vec4 (1.0, 1.0, 1.0, texture2D(s_texture, v_txcoordinate).a); \n" " else \n" " gl_FragColor = vColor; \n" "} \n" }; GLuint vshader; GLuint fshader; GLuint prgobject; GLint linked; d_printf ("gfx_init"); vshader = LoadShader (vshader_str, GL_VERTEX_SHADER); fshader = LoadShader (fshader_str, GL_FRAGMENT_SHADER); prgobject = glCreateProgram (); if (prgobject == 0) { d_printf ("glCreateProgramm failed.."); exit (1); } glAttachShader (prgobject, vshader); glAttachShader (prgobject, fshader); glBindAttribLocation (prgobject, 0, "vPosition"); glLinkProgram (prgobject); glGetProgramiv(prgobject, GL_LINK_STATUS, &linked); if (!linked) { GLint info_len; glGetProgramiv (prgobject, GL_INFO_LOG_LENGTH, &info_len); if (info_len > 0) { char *info_log = malloc (info_len); glGetProgramInfoLog(prgobject, info_len, NULL, info_log); d_printf ("Link Programm failed. : '%s'", info_log); exit (1); } } engine.gles_pos = glGetAttribLocation(prgobject, "vPosition"); engine.gles_txcoord = glGetAttribLocation(prgobject, "vTexture"); engine.gles_color = glGetUniformLocation(prgobject, "vColor"); engine.gles_umvp = glGetUniformLocation(prgobject, "uMvp"); engine.gles_txsampler = glGetUniformLocation(prgobject, "s_texture"); engine.gles_txenabled = glGetUniformLocation(prgobject, "txenabled"); engine.gles_prgobject = prgobject; glEnableVertexAttribArray (engine.gles_pos); glEnableVertexAttribArray (engine.gles_txcoord); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); glEnable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); gfx_screensize.x = width; gfx_screensize.y = height; gfx_resize (width, height); font_init (); drawfont = font_load ("FreeSans.ttf"); }; void gfx_resize (int width, int height) { GLfloat matrix[] = { 2.0/(float)width, 0.0, 0.0, -1.0, 0.0, -2.0/(float)height, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 }; d_printf ("gfx_resize %d,%d", width, height); glViewport (0, 0, width, height); glUseProgram (engine.gles_prgobject); glUniformMatrix4fv(engine.gles_umvp, 1, GL_FALSE, matrix); if (height==0) height = 1; gfx_screensize.x = width; gfx_screensize.y = height; gfx_last_img_fbo = 1; /* force to switch fbo to default */ gfx_fbo_switch (NULL); return; }; void gfx_flip () { if (engine.surface == NULL) return; gfx_fbo_switch (NULL); glFlush(); glFinish (); eglSwapBuffers(engine.display, engine.surface); }; void gfx_fbo_switch (struct image *img) { /* check if we need to switch back to default frame buffer */ if (img == NULL && gfx_last_img_fbo == 0) { return; } if (img == NULL) { GLfloat matrix[] = { 2.0/(float)gfx_screensize.x, 0.0, 0.0, -1.0, 0.0, -2.0/(float)gfx_screensize.y, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 }; gfx_last_img_fbo = 0; glBindFramebuffer (GL_FRAMEBUFFER, 0); glViewport (0, 0, gfx_screensize.x, gfx_screensize.y); glUseProgram (engine.gles_prgobject); glUniformMatrix4fv(engine.gles_umvp, 1, GL_FALSE, matrix); glEnableVertexAttribArray (engine.gles_pos); glEnableVertexAttribArray (engine.gles_txcoord); } else if (gfx_last_img_fbo == img->img_id) { return; } else { GLfloat matrix[] = { 2.0/(float)img->width, 0.0, 0.0, -1.0, 0.0, -2.0/(float)img->height, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 }; gfx_last_img_fbo = img->img_id; glBindFramebuffer(GL_FRAMEBUFFER, img->fbo_id); glViewport (0, 0, img->width, img->height); glUseProgram (engine.gles_prgobject); glUniformMatrix4fv(engine.gles_umvp, 1, GL_FALSE, matrix); glEnableVertexAttribArray (engine.gles_pos); glEnableVertexAttribArray (engine.gles_txcoord); } }; int gfx_color_alloc (struct color *c, unsigned short int r, unsigned short int g, unsigned short int b) { c->r = r; c->g = g; c->b = b; c->alloc = 1; c->c.elements.r = (float)r / (float)0xFFFF; c->c.elements.g = (float)g / (float)0xFFFF; c->c.elements.b = (float)b / (float)0xFFFF; c->c.elements.a = 1.0; return 1; }; void gfx_clear (struct image *dimg, struct color *c) { gfx_fbo_switch (dimg); glClearColor(c->c.elements.r, c->c.elements.g, c->c.elements.b, 1.0f ); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); }; /* * draw line */ void gfx_draw_line (struct image *dimg, int x1, int y1, int x2, int y2, struct line_style style) { GLfloat vp[] = {x1, y1, 0.0, x2, y2, 0.0}; gfx_fbo_switch (dimg); if (style.width < 1.0) style.width = 1.0; glLineWidth (style.width); glUseProgram (engine.gles_prgobject); glUniform1i (engine.gles_txenabled, 0); glUniform4fv(engine.gles_color, 1, style.c.c.array); glVertexAttribPointer (engine.gles_pos, 3, GL_FLOAT, GL_FALSE, 0, vp); glDrawArrays(GL_LINES,0,2); }; /* * draw polygon */ void gfx_draw_polygon (struct image *dimg, iPoint *p, int pcnt, struct line_style style, struct color c) { static GLfloat *polygon = NULL; static int polygon_cnt = 0; int i; if (polygon_cnt < pcnt) { /* copied from GTK port.. if here is a bug, there is one as well.. */ polygon_cnt = pcnt; if (polygon != NULL) polygon = (GLfloat *) ml_realloc (polygon, sizeof (GLfloat) * polygon_cnt * 3); else polygon = (GLfloat *) ml_malloc (sizeof (GLfloat) * polygon_cnt * 3); } for (i = 0; i < pcnt; i++) { polygon[i*3] = p[i].x; polygon[i*3+1] = p[i].y; polygon[i*3+2] = 0.0; } gfx_fbo_switch (dimg); glUseProgram (engine.gles_prgobject); glUniform1i (engine.gles_txenabled, 0); glUniform4fv(engine.gles_color, 1, c.c.array); glVertexAttribPointer (engine.gles_pos, 3, GL_FLOAT, GL_FALSE, 0, polygon); glDrawArrays (GL_TRIANGLE_FAN, 0, pcnt); }; /* * text drawing functions */ void gfx_draw_text (struct image *dimg, int x, int y, char *text, struct color *c) { gfx_fbo_switch (dimg); glUniform4fv(engine.gles_color, 1, c->c.array); font_draw (drawfont, text, x, y+16, 1.0, 1.0); }; /* * drawing bitmap on the screen */ void gfx_draw_img (struct image *dimg, int dx, int dy, int dw, int dh, struct image *simg, int sx, int sy) { GLfloat vp[] = { dx, dy, 0.0, dx, dy+dh, 0.0, dx+dw, dy+dh, 0.0, dx+dw, dy, 0.0}; float fx = (float) sx/(float) simg->width; float fy = (float) sy/(float) simg->height; float fw = (float) dw/(float) simg->width; float fh = (float) dh/(float) simg->height; GLfloat vt[] = { fx, fy, fx, fy+fh, fx+fw, fy+fh, fx+fw, fy }; GLfloat colwhite[] = { 1.0, 1.0, 1.0, 1.0 }; int i; if (simg == NULL) { d_printf ("ERROR: gfx_draw_img simg:%p", simg); return; } gfx_fbo_switch (dimg); /* somehow frame buffered devices are upside down */ if (simg->fbo_id) for (i = 0; i < 4; i++) vt[i*2+1] = 1.0-vt[i*2+1]; glEnable (GL_TEXTURE_2D); glActiveTexture (GL_TEXTURE0); glBindTexture (GL_TEXTURE_2D, simg->txt_id); glUniform1i (engine.gles_txenabled, 1); glUniform4fv(engine.gles_color, 1, colwhite); glUniform1i(engine.gles_txsampler, 0); glVertexAttribPointer (engine.gles_pos, 3, GL_FLOAT, GL_FALSE, 0, vp); glVertexAttribPointer (engine.gles_txcoord, 2, GL_FLOAT, GL_FALSE, 0, vt); glDrawArrays(GL_TRIANGLE_FAN,0,4); glUniform1i (engine.gles_txenabled, 0); glBindTexture (GL_TEXTURE_2D, 0); glDisable (GL_TEXTURE_2D); }; /* * allocate memory bitmap */ struct image *gfx_img_alloc (int w, int h) { struct image *img; GLenum status; img = (struct image *) ml_malloc (sizeof (struct image)); img->width = w; img->height = h; img->rbo_id = 0; img->txt_id = 0; img->fbo_id = 0; img->srb_id = 0; img->data = NULL; img->img_id = (++gfx_last_alloc_img); d_printf ("gfx_img_alloc img_id:%d size: %d x %d", img->img_id, w, h); glGenFramebuffers(1, &img->fbo_id); glGenTextures(1, &img->txt_id); glGenRenderbuffers(1, &img->rbo_id); glBindFramebuffer(GL_FRAMEBUFFER, img->fbo_id); // initialize color texture glBindTexture(GL_TEXTURE_2D, img->txt_id); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, img->txt_id, 0); glBindTexture(GL_TEXTURE_2D, 0); // initialize depth renderbuffer glBindRenderbuffer(GL_RENDERBUFFER, img->rbo_id); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, w, h); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, img->rbo_id); /* * create renderbuffer oobject */ status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if(status != GL_FRAMEBUFFER_COMPLETE) { d_printf ("could not create framebuffer object w:%d h:%d txt_id:%d rbo_id:%d fbo_id:%d status:%d", img->width, img->height, img->txt_id, img->rbo_id, img->fbo_id, status); errorexit (-1); } glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glHint( GL_LINE_SMOOTH_HINT, GL_NICEST ); glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); glClearDepthf( 1.0f ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); /* switch back framebuffer to default */ glBindFramebuffer(GL_FRAMEBUFFER, 0); return img; }; void gfx_img_free (struct image *img) { d_printf ("gfx_img_free img:%p data:%p", img, img == NULL? NULL : img->data); glDeleteFramebuffers (1, &img->fbo_id); glDeleteRenderbuffers (1, &img->rbo_id); glDeleteTextures (1, &img->txt_id); if (img->data) ml_free (img->data); if (img) ml_free (img); }; void gfx_draw_rect (struct image *dimg, int x1, int y1, int x2, int y2, struct color *c) { GLfloat vp[] = { x1, y1, 0.0, x1, y2, 0.0, x2, y2, 0.0, x2, y1, 0.0 }; gfx_fbo_switch (dimg); glUseProgram (engine.gles_prgobject); glUniform1i (engine.gles_txenabled, 0); glUniform4fv(engine.gles_color, 1, c->c.array); glVertexAttribPointer (engine.gles_pos, 3, GL_FLOAT, GL_FALSE, 0, vp); glDrawArrays (GL_TRIANGLE_FAN, 0, 4); }; #define HEADER_SIZE 8 AAsset* gfxpng_asset = NULL; void png_asset_read(png_structp png, png_bytep data, png_size_t size) { int remain; AAsset_read(gfxpng_asset, data, size); remain = AAsset_getRemainingLength(gfxpng_asset); }; struct image* gfx_img_load (char *name) { AAssetManager *mgr = engine.app->activity->assetManager; off_t size; int bytesremaining; int bytesread; int bit_depth, color_type; int transparency, i, rowbytes; png_uint_32 twidth, theight; png_byte* buffer = NULL; png_byte* image_data = NULL; png_bytep *row_pointers = NULL; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_infop end_info = NULL; struct image *img = NULL; if ((gfxpng_asset = AAssetManager_open(mgr, name, AASSET_MODE_UNKNOWN)) == 0) { LOGW("Asset \"%s\" not found.", name); return NULL; } size = AAsset_getLength(gfxpng_asset); buffer = malloc (sizeof (png_byte)*HEADER_SIZE); bytesread = AAsset_read(gfxpng_asset, buffer, HEADER_SIZE); bytesremaining = AAsset_getRemainingLength(gfxpng_asset); if (png_sig_cmp(buffer, 0, 8)) { LOGW("File %s format is not PNG.", name); return NULL; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { LOGW("Unable to create PNG structure: %s", name); return NULL; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); LOGW("Unable to create png info : %s", name); return NULL; } end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); LOGW("Unable to create png end info : %s", name); return NULL; } if (setjmp(png_jmpbuf(png_ptr))) { LOGW("Error during setjmp : %s", name); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return NULL; } png_set_read_fn(png_ptr, NULL, png_asset_read); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, NULL, NULL, NULL); d_printf ("Width: %d, height: %d, Depth: %d", twidth, theight, bit_depth); transparency = FALSE; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); transparency = TRUE; } if (bit_depth < 8) png_set_packing (png_ptr); else if (bit_depth >16) png_set_strip_16 (png_ptr); img = (struct image *) ml_malloc (sizeof (struct image)); img->width = twidth; img->height = theight; img->rbo_id = 0; img->txt_id = 0; img->fbo_id = 0; img->img_id = (++gfx_last_alloc_img); switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); img->data_fmt = transparency ? GL_RGBA : GL_RGB; break; case PNG_COLOR_TYPE_RGB: img->data_fmt = transparency ? GL_RGBA : GL_RGB; break; case PNG_COLOR_TYPE_RGBA: img->data_fmt = GL_RGBA; break; default: d_printf ("unknown color_type:%x", color_type); break; } png_read_update_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); LOGI("Row size: %d bytes.", rowbytes); img->data = (uint8_t*) ml_malloc (sizeof (png_byte) * rowbytes * theight); if (!img->data) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); LOGW("Unable to allocate image_data while loading %s ", name); exit (0); } row_pointers = malloc (sizeof (png_bytep) *theight); if (!row_pointers) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); ml_free (img->data); LOGW("Unable to allocate row_pointer while loading %s ", name); exit (0); } for (i = 0; i < theight; ++i) row_pointers[i] = img->data + i * rowbytes; png_read_image(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); AAsset_close(gfxpng_asset); free (buffer); free (row_pointers); glGenTextures (1, &img->txt_id); glBindTexture (GL_TEXTURE_2D, img->txt_id); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D (GL_TEXTURE_2D, 0, img->data_fmt, img->width, img->height, 0, img->data_fmt, GL_UNSIGNED_BYTE, img->data); glBindTexture (GL_TEXTURE_2D, 0); d_printf ("image loaded"); return img; };