/*************************************************************************** * wince_gfx.c * * December 2009, Steffen Pohle steffen@gulpe.de ****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include "osmroute.h" #include "draw.h" #include "memoryleak.h" #include "system.h" iPoint gfx_screensize = {0, 0}; int gfx_last_alloc_img = 0; int gfx_last_img_fbo = 0; struct font *font = NULL; void gfx_fbo_switch (struct image *img); /*****************************************************************************/ void gfx_init (int width, int height) { /* init viewport */ glViewport( 0, 0, ( GLint )width, ( GLint )height ); glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); glOrtho( 0.0f, width, height, 0.0f, -1.0f, 1.0f ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); /* init opengl */ glShadeModel( GL_SMOOTH ); glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); glClearDepth( 1.0f ); glHint( GL_LINE_SMOOTH_HINT, GL_NICEST ); 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 = font_load ("FreeSans.ttf"); }; void gfx_resize (int width, int height) { 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 () { gfx_fbo_switch (NULL); glFlush(); glFinish (); SDL_GL_SwapBuffers(); }; 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) { gfx_last_img_fbo = 0; glBindFramebuffer (GL_FRAMEBUFFER, 0); glViewport (0, 0, gfx_screensize.x, gfx_screensize.y); glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); glOrtho( 0.0f, gfx_screensize.x, gfx_screensize.y, 0.0f, -1.0f, 1.0f ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); } else if (gfx_last_img_fbo == img->img_id) return; else { gfx_last_img_fbo = img->img_id; glBindFramebuffer (GL_FRAMEBUFFER, img->fbo_id); glViewport (0, 0, img->width, img->height); glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); glOrtho( 0.0f, img->width, 0.0f, img->height, -1.0f, 1.0f ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); } }; 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.r = (float)r / (float)0xFFFF; c->c.g = (float)g / (float)0xFFFF; c->c.b = (float)b / (float)0xFFFF; return 1; }; void gfx_clear (struct image *dimg, struct color *c) { gfx_fbo_switch (dimg); glClearColor(c->c.r, c->c.g, c->c.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) { /* polygon mit runden ecken....? bei width > 1 */ gfx_fbo_switch (dimg); if (style.width < 1.0) style.width = 1.0; glColor4f(style.c.c.r, style.c.c.g, style.c.c.b, 1.0); glPointSize(style.width*0.5); glBegin (GL_POINTS); glVertex2i (x1, y1); glVertex2i (x2, y2); glEnd (); glLineWidth (style.width); glBegin (GL_LINES); glVertex2i (x1, y1); glVertex2i (x2, y2); glEnd (); }; /* * draw polygon */ void gfx_draw_polygon (struct image *dimg, iPoint *p, int pcnt, struct line_style style, struct color *c) { int i; gfx_fbo_switch (dimg); glBegin (GL_POLYGON); glColor4f (c->c.r, c->c.g, c->c.b, 1.0f); for (i = 0; i < pcnt; i++) glVertex2i (p[i].x, p[i].y); glEnd (); }; /* * text drawing functions */ void gfx_draw_text (struct image *dimg, int x, int y, char *text, struct color *c) { gfx_fbo_switch (dimg); glColor4f (c->c.r, c->c.g, c->c.b, 1.0f); font_draw (font, text, x, y+12.0, 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) { float fx, fy, fw, fh; gfx_fbo_switch (dimg); glEnable (GL_TEXTURE_2D); glBindTexture (GL_TEXTURE_2D, simg->txt_id); glBegin (GL_QUADS); glColor4f (1.0f, 1.0f, 1.0f, 1.0f); fx = (float) sx/(float) (simg->width); fy = (float) sy/(float) (simg->height); fw = (float) dw/(float) (simg->width); fh = (float) dh/(float) (simg->height); glTexCoord2d (fx, fy); glVertex2i (dx, dy); glTexCoord2d (fx, fy+fh); glVertex2i (dx, dy+dh); glTexCoord2d (fx+fw, fy+fh); glVertex2i (dx+dw, dy+dh); glTexCoord2d (fx+fw, fy); glVertex2i (dx+dw, dy); glEnd (); 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 = ml_malloc (sizeof (struct image)); img->width = w; img->height = h; img->rbo_id = 0; img->txt_id = 0; img->fbo_id = 0; img->img_id = (++gfx_last_alloc_img); d_printf ("gfx_img_alloc img_id:%d size: %d x %d", img->img_id, w, h); /* * create texture object */ glGenTextures(1, &img->txt_id); glBindTexture(GL_TEXTURE_2D, img->txt_id); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, img->width, img->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindTexture(GL_TEXTURE_2D, 0); /* * create renderbuffer oobject */ glGenRenderbuffers(1, &img->rbo_id); glBindRenderbuffer(GL_RENDERBUFFER, img->rbo_id); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, img->width, img->height); glBindRenderbuffer(GL_RENDERBUFFER, 0); /* * create framebuffer object */ glGenFramebuffers(1, &img->fbo_id); glBindFramebuffer(GL_FRAMEBUFFER, img->fbo_id); /* attach renderbuffer and texture color to the framebuffer */ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, img->txt_id, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, img->rbo_id); 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); } glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); glOrtho( 0.0f, w, h, 0.0f, -1.0f, 1.0f ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); /* init opengl */ glShadeModel( GL_SMOOTH ); glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); glClearDepth( 1.0f ); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); 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"); glDeleteFramebuffers (1, &img->fbo_id); glDeleteRenderbuffers (1, &img->rbo_id); glDeleteTextures (1, &img->txt_id); if (img) ml_free (img); }; #define HEADER_SIZE 8 int gfxpng_fd = 0; void png_fd_read(png_structp png, png_bytep data, png_size_t size) { read(gfxpng_fd, data, size); }; struct image* gfx_img_load (char *name) { int bit_depth, color_type; int transparency, i, rowbytes; png_uint_32 twidth, theight; png_byte* buffer = 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; char fname[LEN_FILENAME]; struct stat st_buf; sprintf (fname, "%s/%s", cfg.appdatapath, name); if ((gfxpng_fd = open(fname, O_RDONLY)) == 0) { d_printf ("File %s not found.", name); return NULL; } fstat (gfxpng_fd, &st_buf); buffer = malloc (sizeof (png_byte)*HEADER_SIZE); read(gfxpng_fd, buffer, HEADER_SIZE); if (png_sig_cmp(buffer, 0, 8)) { d_printf ("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) { d_printf ("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); d_printf ("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); d_printf ("Unable to create png end info : %s", name); return NULL; } if (setjmp(png_jmpbuf(png_ptr))) { d_printf ("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_fd_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); d_printf ("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); d_printf ("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); d_printf ("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); close(gfxpng_fd); 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; };