note description: "Representation of an image that can be paste on other image." author: "Louis Marchand" date: "Sat, 28 Mar 2015 14:00:33 +0000" revision: "2.0" class GAME_SURFACE inherit GAME_LIBRARY_SHARED GAME_DRAWING_TOOLS GAME_BLENDABLE rename is_valid as is_open end create make, share_from_image, make_from_image, share_from_other, make_from_other, make_for_window, make_for_display, make_for_display_mode, make_for_pixel_format, make_with_masks feature {NONE} -- Initialisation share_from_image (a_image: GAME_IMAGE) -- Create a Current from a_image_source. -- The image source in memory is not copied. -- If multiple surface is done with the same a_image, -- every modification to surface will affect all. require surface_make_video_enabled: Game_library.is_video_enable surface_make_from_image_source_is_open: a_image.is_open do image := a_image is_open := not has_error ensure surface_make_is_open: has_error or is_open end make_from_image (a_image: GAME_IMAGE) -- Create a Current from a_image. -- The image source in memory is copied. -- Slower than share_from_image and use more memory. -- If multiple surface is done with the same a_image, -- every modification to surface will affect all. require surface_make_video_enabled: Game_library.is_video_enable surface_make_from_image_source_is_open: a_image.is_open local l_source: GAME_IMAGE do has_error := False create l_source.make_from_other (a_image) if l_source.is_openable then l_source.open if l_source.is_open then share_from_image (l_source) else image := create {GAME_IMAGE}.own_from_pointer (create {POINTER}) has_error := True end else image := create {GAME_IMAGE}.own_from_pointer (create {POINTER}) has_error := True end ensure surface_make_is_open: has_error or is_open end share_from_other (a_other: GAME_SURFACE) -- Create a Current from a_other. -- The image source in memory is not copied. -- If multiple surface is done with the same image, -- every modification to surface will affect all. require surface_make_video_enabled: Game_library.is_video_enable surface_make_other_opened: a_other.is_open do share_from_image (a_other.image) ensure surface_make_is_open: has_error or is_open end make_from_other (a_other: GAME_SURFACE) -- Create a Current from a_other. -- The image source in memory will be copied. -- Slower than share_from_other and use more memory. require surface_make_video_enabled: Game_library.is_video_enable surface_make_other_opened: a_other.is_open do make_from_image (a_other.image) ensure surface_make_is_open: has_error or is_open end make_for_window (a_window: GAME_WINDOW; a_width, a_height: INTEGER_32) -- Create an empty Current of dimension a_width x a_height -- conforming to a_window. require surface_make_video_enabled: Game_library.is_video_enable do make_for_pixel_format (a_window.pixel_format, a_width, a_height) ensure surface_make_is_open: has_error or is_open end make_for_display (a_display: GAME_DISPLAY; a_width, a_height: INTEGER_32) -- Create an empty Current of dimension a_width x a_height -- conforming to a_display. require surface_make_video_enabled: Game_library.is_video_enable do make_for_display_mode (a_display.current_mode, a_width, a_height) ensure surface_make_is_open: has_error or is_open end make (a_width, a_height: INTEGER_32) -- Create an empty Current of dimension a_width x a_height -- conforming to the first founded GAME_DISPLAY. require surface_make_video_enabled: Game_library.is_video_enable do if not Game_library.displays.is_empty then make_for_display_mode (Game_library.displays.first.current_mode, a_width, a_height) else create image.own_from_pointer (create {POINTER}) end ensure surface_make_is_open: has_error or is_open end make_for_display_mode (a_display_mode: GAME_DISPLAY_MODE; a_width, a_height: INTEGER_32) -- Create an empty Current of dimension a_width x a_height -- conforming to a_display_mode. require surface_make_video_enabled: Game_library.is_video_enable do make_for_pixel_format (a_display_mode.pixel_format, a_width, a_height) ensure surface_make_is_open: has_error or is_open end make_for_pixel_format (a_pixel_format: GAME_PIXEL_FORMAT_READABLE; a_width, a_height: INTEGER_32) -- Create an empty Current of dimension a_width x a_height -- conforming to a_pixel_format. require surface_make_video_enabled: Game_library.is_video_enable local l_bpp: INTEGER_32 l_masks: TUPLE [red_mask: NATURAL_32; green_mask: NATURAL_32; blue_mask: NATURAL_32; alpha_mask: NATURAL_32] do l_bpp := a_pixel_format.bits_per_pixel if a_pixel_format.has_error then Io.Error.put_string ("An error occured while creating the surface.%N"); Io.Error.put_string (last_error.to_string_8 + "%N") has_error := True create image.own_from_pointer (create {POINTER}) else l_masks := a_pixel_format.masks if a_pixel_format.has_error then Io.Error.put_string ("An error occured while creating the surface.%N"); Io.Error.put_string (last_error.to_string_8 + "%N") has_error := True create image.own_from_pointer (create {POINTER}) else make_with_masks (a_width, a_height, l_bpp, l_masks.red_mask, l_masks.green_mask, l_masks.blue_mask, l_masks.alpha_mask) end end is_open := not has_error ensure surface_make_is_open: has_error or is_open end make_with_masks (a_width, a_height, a_bits_per_pixel: INTEGER_32; a_rmask, a_gmask, a_bmask, a_amask: NATURAL_32) -- Initialization for Current. -- Create a new empty surface with RGBA mask and flags. require surface_make_video_enabled: Game_library.is_video_enable local l_surface_pointer: POINTER l_image_source: GAME_IMAGE do clear_error l_surface_pointer := {GAME_SDL_EXTERNAL}.sdl_creatergbsurface (0, a_width, a_height, a_bits_per_pixel, a_rmask, a_gmask, a_bmask, a_amask) if l_surface_pointer.is_default_pointer then manage_error_pointer (l_surface_pointer, "An error occured while creating the surface.") create image.own_from_pointer (create {POINTER}) else create l_image_source.own_from_pointer (l_surface_pointer) if l_image_source.is_openable then l_image_source.open share_from_image (l_image_source) else put_manual_error ("An error occured while creating the surface.", "Cannot read file.") create image.own_from_pointer (create {POINTER}) end end ensure surface_make_is_open: has_error or is_open end feature -- Access is_locked: BOOLEAN -- Current is locked to access pixels. Current cannot be used until unlock is called. do Result := attached internal_pixels end must_lock: BOOLEAN -- Current must be locked for pixel access do Result := {GAME_SDL_EXTERNAL}.sdl_mustlock (item) end lock -- Lock Current to access pixels. -- Must used unlock after the edition. -- You cannot draw on Current while locked. local l_error: INTEGER_32 do clear_error if must_lock then l_error := {GAME_SDL_EXTERNAL}.sdl_locksurface (item) if l_error = 0 then create internal_pixels.make_from_pointer ({GAME_SDL_EXTERNAL}.get_sdl_surface_struct_pixels (item), pixel_format, width, height, {GAME_SDL_EXTERNAL}.get_sdl_surface_struct_pitch (item)) else manage_error_code (l_error, "Cannot lock surface.") end else create internal_pixels.make_from_pointer ({GAME_SDL_EXTERNAL}.get_sdl_surface_struct_pixels (item), pixel_format, width, height, {GAME_SDL_EXTERNAL}.get_sdl_surface_struct_pitch (item)) end ensure is_locked: not has_error implies is_locked end unlock -- Unlock Current after access pixels. require is_locked: is_locked do if must_lock then {GAME_SDL_EXTERNAL}.sdl_unlocksurface (item) end if attached internal_pixels as la_pixels then la_pixels.close end internal_pixels := Void ensure not_locked: not is_locked end pixels: GAME_PIXEL_READER_WRITER -- Used to fetch and edit pixels in Current -- Use lock before to access multiple pixels require locked_if_needed: must_lock implies is_locked do if attached internal_pixels as la_pixels then Result := la_pixels else create Result.make_from_pointer ({GAME_SDL_EXTERNAL}.get_sdl_surface_struct_pixels (item), pixel_format, width, height, {GAME_SDL_EXTERNAL}.get_sdl_surface_struct_pitch (item)) end end image: GAME_IMAGE -- The GAME_IMAGE that has served for creating Current is_open: BOOLEAN -- Current has been opened properly as_converted_to_pixel_format (a_pixel_format: GAME_PIXEL_FORMAT_READABLE): GAME_SURFACE -- Create a copy of Current conforming to a_pixel_format. require surface_is_video_enable: Game_library.is_video_enable surface_convert_is_open: is_open not_locked: not is_locked local l_source: GAME_IMAGE do has_error := False create l_source.own_from_pointer ({GAME_SDL_EXTERNAL}.sdl_convertsurfaceformat (item, a_pixel_format.internal_index, 0)) if l_source.is_openable then l_source.open if l_source.is_open then create Result.share_from_image (l_source) else create Result.make_for_pixel_format (a_pixel_format, width, height) if Result.is_open then Result.draw_surface (Current, 0, 0) else has_error := True end end else create Result.make_for_pixel_format (a_pixel_format, width, height) if Result.is_open then Result.draw_surface (Current, 0, 0) else has_error := True end end end pixel_format: GAME_PIXEL_FORMAT_READABLE -- The internal format of the pixel representation in memory. require surface_is_video_enable: Game_library.is_video_enable surface_pixel_format_is_open: is_open do create Result.share_from_structure_pointer ({GAME_SDL_EXTERNAL}.get_sdl_surface_struct_format (item)) end draw_surface (a_other: GAME_SURFACE; a_x, a_y: INTEGER_32) -- Draw the whole surface a_other on Current at (a_x,a_y). require surface_is_video_enable: Game_library.is_video_enable surface_draw_is_open: is_open not_locked: not is_locked do draw_sub_surface (a_other, 0, 0, a_other.width, a_other.height, a_x, a_y) end draw_sub_surface (a_other: GAME_SURFACE; a_x_source, a_y_source, a_width, a_height, a_x_destination, a_y_destination: INTEGER_32) -- Draw on Current at (a_x_destination,a_y_destination) the portion of a_other -- starting at (a_x_source,a_y_source) with dimension a_width x a_height. require surface_is_video_enable: Game_library.is_video_enable surface_draw_is_open: is_open not_locked: not is_locked do internal_draw_surface (a_other, a_x_source, a_y_source, a_width, a_height, a_x_destination, a_y_destination, a_width, a_height, False) end draw_sub_surface_with_scale (a_other: GAME_SURFACE; a_x_source, a_y_source, a_width_source, a_height_source, a_x_destination, a_y_destination, a_width_destination, a_height_destination: INTEGER_32) -- Draw on Current at (a_x_destination,a_y_destination) the portion of a_other -- starting at (a_x_source,a_y_source) with dimension a_width x a_height. -- Will scale a_other using a_width_destination and a_height_destination require surface_is_video_enable: Game_library.is_video_enable surface_draw_is_open: is_open not_locked: not is_locked do internal_draw_surface (a_other, a_x_source, a_y_source, a_width_source, a_height_source, a_x_destination, a_y_destination, a_width_destination, a_height_destination, True) end draw_rectangle (a_color: GAME_COLOR; a_x, a_y, a_width, a_height: INTEGER_32) -- Draw a a_color rectangle of dimension a_width x a_height on Current at (a_x,a_y). require surface_is_video_enable: Game_library.is_video_enable surface_draw_is_open: is_open not_locked: not is_locked local l_rect_src, l_format: POINTER l_error: INTEGER_32 l_color_key: NATURAL_32 l_normalized_rectangle: TUPLE [x: INTEGER_32; y: INTEGER_32; width: INTEGER_32; height: INTEGER_32] do clear_error l_format := pixel_format.item if pixel_format.has_error then manage_error_boolean (False, "Cannot retreive the pixel format of the surface.") else l_normalized_rectangle := normalize_rectangle (a_x, a_y, a_width, a_height) l_rect_src := l_rect_src.memory_calloc (1, {GAME_SDL_EXTERNAL}.c_sizeof_sdl_rect) {GAME_SDL_EXTERNAL}.set_rect_struct_x (l_rect_src, l_normalized_rectangle.x) {GAME_SDL_EXTERNAL}.set_rect_struct_y (l_rect_src, l_normalized_rectangle.y) {GAME_SDL_EXTERNAL}.set_rect_struct_w (l_rect_src, l_normalized_rectangle.width) {GAME_SDL_EXTERNAL}.set_rect_struct_h (l_rect_src, l_normalized_rectangle.height) l_color_key := {GAME_SDL_EXTERNAL}.sdl_maprgba (l_format, a_color.red, a_color.green, a_color.blue, a_color.alpha) l_error := {GAME_SDL_EXTERNAL}.sdl_fillrect (item, l_rect_src, l_color_key) manage_error_code (l_error, "An error occured while drawing rectangle to the surface."); l_rect_src.memory_free end end draw_rectangles (a_color: GAME_COLOR; a_rectangles: CHAIN [TUPLE [x: INTEGER_32; y: INTEGER_32; width: INTEGER_32; height: INTEGER_32]]) -- Drawing every a_color rectangle in a_rectangles -- that has it's left frontier at -- x, it's top frontier at y, with -- dimension widthxheight require surface_is_video_enable: Game_library.is_video_enable surface_draw_is_open: is_open not_locked: not is_locked local l_array_rectangles, l_rectangle, l_format: POINTER l_rectangle_size, l_error: INTEGER_32 l_color_key: NATURAL_32 l_normalized_rectangle: TUPLE [x: INTEGER_32; y: INTEGER_32; width: INTEGER_32; height: INTEGER_32] do clear_error l_format := pixel_format.item if pixel_format.has_error then manage_error_boolean (False, "Cannot retreive the pixel format of the surface.") else l_rectangle_size := {GAME_SDL_EXTERNAL}.c_sizeof_sdl_rect l_array_rectangles := l_array_rectangles.memory_alloc (l_rectangle_size * a_rectangles.count) l_rectangle := l_array_rectangles across a_rectangles as la_rectangles loop l_normalized_rectangle := normalize_rectangle (la_rectangles.item.x, la_rectangles.item.y, la_rectangles.item.width, la_rectangles.item.height) {GAME_SDL_EXTERNAL}.set_rect_struct_x (l_rectangle, l_normalized_rectangle.x) {GAME_SDL_EXTERNAL}.set_rect_struct_y (l_rectangle, l_normalized_rectangle.y) {GAME_SDL_EXTERNAL}.set_rect_struct_w (l_rectangle, l_normalized_rectangle.width) {GAME_SDL_EXTERNAL}.set_rect_struct_h (l_rectangle, l_normalized_rectangle.height) l_rectangle := l_rectangle.plus (l_rectangle_size) end l_color_key := {GAME_SDL_EXTERNAL}.sdl_maprgba (l_format, a_color.red, a_color.green, a_color.blue, a_color.alpha) l_error := {GAME_SDL_EXTERNAL}.sdl_fillrects (item, l_array_rectangles, a_rectangles.count, l_color_key) manage_error_code (l_error, "An error occured while drawing rectangles to the surface."); l_array_rectangles.memory_free end end transparent_color: GAME_COLOR_READABLE assign set_transparent_color -- The color that will be remove in the surface (the transparent color). require surface_is_video_enable: Game_library.is_video_enable surface_is_open: is_open surface_transparent_color_is_enable: is_transparent_enable not_locked: not is_locked local l_red, l_green, l_blue, l_alpha: NATURAL_8 l_color_key: NATURAL_32 l_error: INTEGER_32 do clear_error l_error := {GAME_SDL_EXTERNAL}.sdl_getcolorkey (item, $l_color_key.to_pointer) if l_error < 0 then manage_error_code (l_error, "An error occured while getting the transparent color of the surface.") create Result.make (0, 0, 0, 0) else {GAME_SDL_EXTERNAL}.sdl_getrgba (l_color_key, pixel_format.item, $l_red.to_pointer, $l_green.to_pointer, $l_blue.to_pointer, $l_alpha.to_pointer) create Result.make (l_red, l_green, l_blue, l_alpha) end end set_transparent_color (a_color: GAME_COLOR_READABLE) -- Change all pixel of color color into transparency (and enable it). The transparency by color don't work if the surface -- have an alpha blending activated. require surface_is_video_enable: Game_library.is_video_enable surface_is_open: is_open not_locked: not is_locked local l_key: NATURAL_32 l_error: INTEGER_32 do l_key := {GAME_SDL_EXTERNAL}.sdl_maprgb (pixel_format.item, a_color.red, a_color.green, a_color.blue) clear_error l_error := {GAME_SDL_EXTERNAL}.sdl_setcolorkey (item, {GAME_SDL_EXTERNAL}.sdl_true, l_key) if l_error < 0 then manage_error_code (l_error, "An error occured while setting the transparent color to the surface.") else enable_rle_acceleration end end is_transparent_enable: BOOLEAN -- Is transparency by color key is enabled. require surface_is_video_enable: Game_library.is_video_enable surface_is_open: is_open not_locked: not is_locked local l_error: INTEGER_32 l_color_key: NATURAL_32 do clear_error l_error := {GAME_SDL_EXTERNAL}.sdl_getcolorkey (item, $l_color_key.to_pointer) if l_error < -1 then manage_error_code (l_error, "An error occured while getting the transparent color of the surface.") end Result := l_error /= -1 end disable_transparent -- Remove the transparency by color key. require surface_is_video_enable: Game_library.is_video_enable surface_is_open: is_open not_locked: not is_locked local l_error: INTEGER_32 do clear_error l_error := {GAME_SDL_EXTERNAL}.sdl_setcolorkey (item, {GAME_SDL_EXTERNAL}.sdl_false, 0) if l_error < 0 then manage_error_code (l_error, "An error occured while disabling the transparent color of the surface.") else disable_rle_acceleration end end height: INTEGER_32 -- The height of Current. require surface_is_open: is_open do Result := {GAME_SDL_EXTERNAL}.get_sdl_surface_struct_h (item) end width: INTEGER_32 -- The width of Current. require surface_is_open: is_open do Result := {GAME_SDL_EXTERNAL}.get_sdl_surface_struct_w (item) end overall_alpha: NATURAL_8 assign set_overall_alpha -- The Additionnal alpha value to use in drawing operation. require surface_is_open: is_open not_locked: not is_locked local l_error: INTEGER_32 do clear_error l_error := {GAME_SDL_EXTERNAL}.sdl_getsurfacealphamod (item, $Result.to_pointer) manage_error_code (l_error, "An error occured while retrieving the overall alpha value of the surface.") end set_overall_alpha (a_overall_alpha: NATURAL_8) -- Assign the Additionnal overall_alpha value to use in drawing operation to a_overall_alpha. require surface_is_open: is_open not_locked: not is_locked local l_error: INTEGER_32 do clear_error l_error := {GAME_SDL_EXTERNAL}.sdl_setsurfacealphamod (item, a_overall_alpha) manage_error_code (l_error, "An error occured while setting the overall alpha value of the surface.") end color_multiplier: TUPLE [red_multipier: NATURAL_8; green_multipier: NATURAL_8; blue_multipier: NATURAL_8] -- The additional color value multiplied into drawing operations require surface_is_open: is_open not_locked: not is_locked local l_error: INTEGER_32 l_red, l_green, l_blue: NATURAL_8 do clear_error l_error := {GAME_SDL_EXTERNAL}.sdl_getsurfacecolormod (item, $l_red.to_pointer, $l_green.to_pointer, $l_blue.to_pointer) manage_error_code (l_error, "An error occured while retrieving the color multiplier value of the surface.") Result := [l_red, l_green, l_blue] end set_color_multiplier (a_red_multiplier, a_green_multiplier, a_blue_multiplier: NATURAL_8) -- Assign the Additionnal color_multiplier value to use into drawing operation to a_red_multiplier, -- a_green_multiplier, a_blue_multiplier. require surface_is_open: is_open not_locked: not is_locked local l_error: INTEGER_32 do clear_error l_error := {GAME_SDL_EXTERNAL}.sdl_setsurfacecolormod (item, a_red_multiplier, a_green_multiplier, a_blue_multiplier) manage_error_code (l_error, "An error occured while setting the overall alpha value on the surface.") end enable_rle_acceleration -- Enable possible optimisation when using drawing with transparent_color enabled or enable_alpha_blending. require surface_is_open: is_open not_locked: not is_locked local l_error: INTEGER_32 do clear_error l_error := {GAME_SDL_EXTERNAL}.sdl_setsurfacerle (item, 1) manage_error_code (l_error, "An error occured when enabling RLE acceleration on the surface.") end disable_rle_acceleration -- Disable the possible optimisation when using drawing with transparent_color enabled or enable_alpha_blending. require surface_is_open: is_open not_locked: not is_locked local l_error: INTEGER_32 do clear_error l_error := {GAME_SDL_EXTERNAL}.sdl_setsurfacerle (item, 0) manage_error_code (l_error, "An error occured when disabling RLE acceleration on the surface.") end save_bmp (a_filename: READABLE_STRING_GENERAL) -- Save Current into a BMP image file require surface_is_open: is_open local l_error: INTEGER_32 l_filename_c: C_STRING do create l_filename_c.make (a_filename) clear_error l_error := {GAME_SDL_EXTERNAL}.sdl_savebmp (item, l_filename_c.item) manage_error_code (l_error, "An error occured when saving Surface to bmp file.") end feature {GAME_SDL_ANY} -- Implementation item: POINTER -- The internal pointer to the image do Result := image.item end feature {NONE} -- Implementation internal_draw_surface (a_other: GAME_SURFACE; a_x_source, a_y_source, a_width_source, a_height_source, a_x_destination, a_y_destination, a_width_destination, a_height_destination: INTEGER_32; a_must_scale: BOOLEAN) -- Draw on Current at (a_x_destination,a_y_destination) the portion of a_other -- starting at (a_x_source,a_y_source) with dimension a_width x a_height. -- If a_must_scale is set, will scale using a_width_destination and a_height_destination require surface_is_video_enable: Game_library.is_video_enable surface_draw_is_open: is_open not_locked: not is_locked local l_rect_src, l_rect_dst: POINTER l_error: INTEGER_32 l_normalized_rectangle_source, l_normalized_rectangle_destination: TUPLE [x: INTEGER_32; y: INTEGER_32; width: INTEGER_32; height: INTEGER_32] do l_normalized_rectangle_source := normalize_rectangle (a_x_source, a_y_source, a_width_source, a_height_source) l_normalized_rectangle_destination := normalize_rectangle (a_x_destination, a_y_destination, a_width_destination, a_height_destination) l_rect_src := l_rect_src.memory_calloc (1, {GAME_SDL_EXTERNAL}.c_sizeof_sdl_rect) l_rect_dst := l_rect_dst.memory_calloc (1, {GAME_SDL_EXTERNAL}.c_sizeof_sdl_rect) {GAME_SDL_EXTERNAL}.set_rect_struct_x (l_rect_src, l_normalized_rectangle_source.x) {GAME_SDL_EXTERNAL}.set_rect_struct_y (l_rect_src, l_normalized_rectangle_source.y) {GAME_SDL_EXTERNAL}.set_rect_struct_w (l_rect_src, l_normalized_rectangle_source.width) {GAME_SDL_EXTERNAL}.set_rect_struct_h (l_rect_src, l_normalized_rectangle_source.height) {GAME_SDL_EXTERNAL}.set_rect_struct_x (l_rect_dst, l_normalized_rectangle_destination.x) {GAME_SDL_EXTERNAL}.set_rect_struct_y (l_rect_dst, l_normalized_rectangle_destination.y) {GAME_SDL_EXTERNAL}.set_rect_struct_w (l_rect_dst, l_normalized_rectangle_destination.width) {GAME_SDL_EXTERNAL}.set_rect_struct_h (l_rect_dst, l_normalized_rectangle_destination.height) clear_error if a_must_scale then l_error := {GAME_SDL_EXTERNAL}.sdl_blitscaled (a_other.image.item, l_rect_src, item, l_rect_dst) else l_error := {GAME_SDL_EXTERNAL}.sdl_blitsurface (a_other.image.item, l_rect_src, item, l_rect_dst) end manage_error_code (l_error, "An error occured while drawing to the surface."); l_rect_dst.memory_free; l_rect_src.memory_free end internal_pixels: detachable GAME_PIXEL_READER_WRITER -- Internal representation of the pixels feature feature {NONE} -- External c_get_blend_mode (a_item, a_blend_mode: POINTER): INTEGER_32 -- Internal getter for blend mode do Result := {GAME_SDL_EXTERNAL}.sdl_getsurfaceblendmode (a_item, a_blend_mode) end c_set_blend_mode (a_item: POINTER; a_blend_mode: INTEGER_32): INTEGER_32 -- Internal setter for blend mode do Result := {GAME_SDL_EXTERNAL}.sdl_setsurfaceblendmode (a_item, a_blend_mode) end invariant surface_valid: is_open implies image.is_open end -- class GAME_SURFACE
Generated by ISE EiffelStudio