image_t *gfx_display_acquire(gfx_display_t *gfxd, void **pHandle) { if (gfxd) { uint32_t idx = 0; if (bitfield_get(&gfxd->used, &idx)) { uint8_t *bufs[4] = {0,0,0,0}; int ret = 0; int usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_NEVER; // save the handle with the client *pHandle = (void *)gfxd->handles[idx]; // allocate an image structure, gfxd->images[idx] = image_allocate(gfxd->width, gfxd->height, gfxd->color); // by locking the memory we are mapping it to our UVA ret = gfxd->module->base.lock((const struct gralloc_module_t *)gfxd->module, (buffer_handle_t)gfxd->handles[idx], usage, 0, 0, gfxd->width, gfxd->height, (void **)bufs); DVP_PRINT(DVP_ZONE_VIDEO, "Locking %p to {%p, %p, %p, %p} (ret=%d)\n", gfxd->handles[idx], bufs[0], bufs[1], bufs[2], bufs[3], ret); // fill in the details in the image_t structure... if (gfxd->color == FOURCC_NV12) { gfxd->images[idx]->plane[0].ptr = bufs[0]; gfxd->images[idx]->plane[1].ptr = bufs[1]; gfxd->images[idx]->plane[0].ystride = gfxd->stride; gfxd->images[idx]->plane[1].ystride = gfxd->stride; } else { gfxd->images[idx]->plane[0].ptr = bufs[0]; gfxd->images[idx]->plane[0].ystride = gfxd->stride; } return gfxd->images[idx]; } } return NULL; }
image_t* image_initf(uint32 width, uint32 height, PIXEL_FORMAT fmt, void* initial_state, image_initf_fun_t filler) { void* state = initial_state; image_t* img = image_allocate(width, height, fmt); uint32 pixel_size = 0; uint8* data = (uint8*)img->pixels; pixel_setf_fun_t fun = NULL; switch(fmt) { case PF_A8: pixel_size = 1; fun = set_pixelf_a8; break; case PF_R8G8B8: pixel_size = 3; fun = set_pixelf_r8g8b8; break; case PF_R8G8B8A8: pixel_size = 4; fun = set_pixelf_r8g8b8a8; break; } for( uint32 y = 0; y < height; ++y ) { for( uint32 x = 0; x < width; ++x ) { uint32 offset = (x + y * width) * pixel_size; color4_t col = filler(state, x, y); fun(&data[offset], col); } } return img; }
image_t* image_load_png(const char* path) { png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; int color_type, interlace_type; FILE* fp; png_uint_32 width, height; int bit_depth; unsigned int row_bytes; PIXEL_FORMAT sf = PF_A8; uint32 pixel_size = 0; uint32 width_size = 0; image_t* tex = NULL; char* buff = NULL; png_bytepp row_pointers; uint32 r; /* row */ if( (fp = fopen(path, "rb")) == NULL ) { fprintf(stderr, "ERROR: load_png: %s not found\n", path); return NULL; } /* Create and initialize the png_struct * with the desired error handler * functions. If you want to use the * default stderr and longjump method, * you can supply NULL for the last * three parameters. We also supply the * the compiler header file version, so * that we know if the application * was compiled with a compatible version * of the library. REQUIRED */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if( png_ptr == NULL ) { fclose(fp); fprintf(stderr, "ERROR: load_png: %s: invalid PNG format\n", path); } /* Allocate/initialize the memory * for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, NULL, NULL); fprintf(stderr, "ERROR: load_png: %s: not enough memory or format not supported\n", path); return NULL; } /* Set error handling if you are * using the setjmp/longjmp method * (this is the normal method of * doing things with libpng). * REQUIRED unless you set up * your own error handlers in * the png_create_read_struct() * earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated * with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); /* If we get here, we had a * problem reading the file */ fprintf(stderr, "ERROR: load_png: inconsistant file %s\n", path); return NULL; } /* Set up the output control if * you are using standard C streams */ png_init_io(png_ptr, fp); /* If we have already * read some of the signature */ png_set_sig_bytes(png_ptr, sig_read); /* * If you have enough memory to read * in the entire image at once, and * you need to specify only * transforms that can be controlled * with one of the PNG_TRANSFORM_* * bits (this presently excludes * dithering, filling, setting * background, and doing gamma * adjustment), then you can read the * entire image (including pixels) * into the info structure with this * call * * PNG_TRANSFORM_STRIP_16 | * PNG_TRANSFORM_PACKING forces 8 bit * PNG_TRANSFORM_EXPAND forces to * expand a palette into RGB */ png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); row_bytes = png_get_rowbytes(png_ptr, info_ptr); switch( color_type ) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: sf = PF_A8; pixel_size = 1; break; case PNG_COLOR_TYPE_RGB: sf = PF_R8G8B8; pixel_size = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: sf = PF_R8G8B8A8; pixel_size = 4; break; } // align the opengl texture to 4 byte width width_size = width * pixel_size; tex = image_allocate(width, height, sf); if( !tex ) { /* Clean up after the read, * and free any memory allocated */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); /* Close the file */ fclose(fp); return tex; } buff = (char*)tex->pixels; row_pointers = png_get_rows(png_ptr, info_ptr); for( r = 0; r < height; r++ ) { // note that png is ordered top to // bottom, but OpenGL expect it bottom to top // so the order or swapped memcpy(&(buff[width_size * r]), row_pointers[r], width_size); } /* Clean up after the read, * and free any memory allocated */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); /* Close the file */ fclose(fp); return tex; }
atlas_t* image_atlas_make(uint32 image_count, const image_t** images) { stbrp_rect* rects = NULL; stbrp_node* nodes = NULL; stbrp_context ctx; uint32 r; uint32 best_size; image_t* tex = NULL; atlas_t* atlas = NULL; rect_t* drects = NULL; /* try to find the best texture size */ best_size = find_best_size(image_count, images); /* create the texture and fill in the pixels */ tex = image_allocate(best_size, best_size, PF_R8G8B8A8); assert( NULL != tex ); /* image to rect */ rects = (stbrp_rect*)malloc(sizeof(stbrp_rect) * image_count); assert( NULL != rects ); for( r = 0; r < image_count; ++r ) { rects[r] = image_to_rect(r, images[r]); } /* nodes */ nodes = (stbrp_node*)malloc(sizeof(stbrp_node) * best_size * 2); assert( NULL != nodes ); memset(nodes, 0, sizeof(stbrp_node) * best_size * 2); /* desitnation rectangles */ drects = (rect_t*)malloc(sizeof(rect_t) * image_count); assert( NULL != drects ); memset(drects, 0, sizeof(rect_t) * image_count); /* pack */ stbrp_init_target(&ctx, (int)best_size, (int)best_size, nodes, (int)best_size * 2); stbrp_pack_rects(&ctx, rects, (int)image_count); free(nodes); /* copy the rectangle */ for( r = 0; r < image_count; ++r ) { uint32 y; uint32 h = images[r]->height; uint32 w = images[r]->width; assert( rects[r].was_packed ); drects[r].x = rects[r].x; drects[r].y = rects[r].y; drects[r].width = rects[r].w; drects[r].height= rects[r].h; for( y = 0; y < h ; ++y ) { uint32 x; for( x = 0; x < w; ++x ) { color4b_t src = image_get_pixelb(images[r], x, y); image_set_pixelb(tex, rects[r].x + x, rects[r].y + y, src); } } } /* release resources */ free(rects); /* final result */ atlas = (atlas_t*)malloc(sizeof(atlas_t)); assert( NULL != atlas ); atlas->baked_image = tex; atlas->coordinates = drects; atlas->image_count = image_count; return atlas; }