#ifndef SURFACE_H #define SURFACE_H #include #include #include #include #include typedef struct surface { coord_t size; color_t *buffer; } surface_t; /** * Checks if ( x0, y0 ) is inside surface pointed by 'sp'. */ #define INSIDE( sp, x0, y0 ) \ ( ( (sp)->size.x > x0 ) && ( (sp)->size.y > (y0) ) ) /** * Checks if the given coord_t is inside the surface. */ #define INSIDE_COORD( sp, c ) INSIDE( (sp), (c).x, (c).y ) /** * Checks if the given rectangle is inside the surface. */ #define INSIDE_RECT( sp, r ) \ ( INSIDE_COORD( (sp), (r).p0 ) && INSIDE_COORD( (sp), (r).p1 ) ) /** * Get pixel from surface */ #define PIXEL_AT( sp, x0, y0 ) \ ( (sp)->buffer[ QUAD_TO_LIN( (sp)->size.x, (x0), (y0) ) ] ) surface_t * surface_new( uint16_t width, uint16_t height ); void surface_free( surface_t *surface ); void surface_clear( const surface_t *surface ); void surface_reset_visits( const surface_t *surface ); void surface_fill( const surface_t *surface, color_t color, rect_t rect ); /** * Paint a pixel, consider transparency */ static inline void pixel_paint( color_t *pixel, const color_t color, const float transp ) { /* * HACK: * We will use the still unused color_t.a field to set visited elements. */ if ( pixel->a == 1 ) return; if ( transp <= 0.0 ) *pixel = color; else if ( transp < 1.0 ) { pixel->r = (uint8_t)( ( pixel->r * ( transp ) ) + ( color.r * ( 1 - transp ) ) ); pixel->g = (uint8_t)( ( pixel->g * ( transp ) ) + ( color.g * ( 1 - transp ) ) ); pixel->b = (uint8_t)( ( pixel->b * ( transp ) ) + ( color.b * ( 1 - transp ) ) ); } pixel->a = 1; } /** * Draw pixel, take care to not draw over surface boundaries */ static inline void surface_draw_pixel( const surface_t *surface, const uint16_t x, const uint16_t y, const color_t color, const float transp ) { assert( surface != NULL ); if ( ( x >= surface->size.x ) || ( y >= surface->size.y ) ) return; color_t *pixel = &PIXEL_AT( surface, x, y ); pixel_paint( pixel, color, transp ); } #endif /* SURFACE_H */