00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "global.hpp"
00019
00020 #include "cursor.hpp"
00021 #include "game_config.hpp"
00022 #include "image.hpp"
00023 #include "preferences_display.hpp"
00024 #include "scoped_resource.hpp"
00025 #include "sdl_utils.hpp"
00026 #include "video.hpp"
00027
00028 #include "SDL.h"
00029
00030 #include <iostream>
00031 #include <vector>
00032
00033 static bool use_colour_cursors()
00034 {
00035 return game_config::editor == false && preferences::use_colour_cursors();
00036 }
00037
00038 static SDL_Cursor* create_cursor(surface surf)
00039 {
00040 const surface nsurf(make_neutral_surface(surf));
00041 if(nsurf == NULL) {
00042 return NULL;
00043 }
00044
00045
00046
00047 #ifdef __APPLE__
00048 size_t cursor_width = 16;
00049 #else
00050 size_t cursor_width = nsurf->w;
00051 if((cursor_width%8) != 0) {
00052 cursor_width += 8 - (cursor_width%8);
00053 }
00054 #endif
00055 std::vector<Uint8> data((cursor_width*nsurf->h)/8,0);
00056 std::vector<Uint8> mask(data.size(),0);
00057
00058
00059
00060 surface_lock lock(nsurf);
00061 const Uint32* const pixels = reinterpret_cast<Uint32*>(lock.pixels());
00062 for(int y = 0; y != nsurf->h; ++y) {
00063 for(int x = 0; x != nsurf->w; ++x) {
00064 Uint8 r,g,b,a;
00065 Uint8 trans = 0;
00066 Uint8 black = 0;
00067
00068 const size_t index = y*cursor_width + x;
00069
00070 if (static_cast<size_t>(x) < cursor_width) {
00071 SDL_GetRGBA(pixels[y*nsurf->w + x],nsurf->format,&r,&g,&b,&a);
00072
00073 const size_t shift = 7 - (index % 8);
00074
00075 trans = (a < 128 ? 0 : 1) << shift;
00076 black = (trans == 0 || (r+g + b) / 3 > 128 ? 0 : 1) << shift;
00077
00078 data[index/8] |= black;
00079 mask[index/8] |= trans;
00080 }
00081
00082
00083 }
00084 }
00085
00086 return SDL_CreateCursor(&data[0],&mask[0],cursor_width,nsurf->h,0,0);
00087 }
00088
00089 namespace {
00090
00091 SDL_Cursor* cache[cursor::NUM_CURSORS] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
00092
00093
00094
00095 #ifdef __APPLE__
00096 const std::string bw_images[cursor::NUM_CURSORS] = { "normal.png", "wait-alt.png", "move.png", "attack.png", "select.png", "move_drag_alt.png" , "attack_drag_alt.png", "no_cursor.png"};
00097 #else
00098 const std::string bw_images[cursor::NUM_CURSORS] = { "normal.png", "wait.png", "move.png", "attack.png", "select.png", "move_drag.png", "attack_drag.png", "no_cursor.png"};
00099 #endif
00100
00101 const std::string colour_images[cursor::NUM_CURSORS] = { "normal.png", "wait.png", "move.png", "attack.png", "select.png", "move_drag.png", "attack_drag.png", ""};
00102
00103
00104 const int shift_x[cursor::NUM_CURSORS] = {0, 0, 0, 0, 0, 2, 3, 0};
00105 const int shift_y[cursor::NUM_CURSORS] = {0, 0, 0, 0, 0, 20, 22, 0};
00106
00107 cursor::CURSOR_TYPE current_cursor = cursor::NORMAL;
00108
00109 int cursor_x = -1, cursor_y = -1;
00110 surface cursor_buf = NULL;
00111 bool have_focus = true;
00112 bool colour_ready = false;
00113
00114 }
00115
00116 static SDL_Cursor* get_cursor(cursor::CURSOR_TYPE type)
00117 {
00118 if(cache[type] == NULL) {
00119 static const std::string prefix = "cursors-bw/";
00120 const surface surf(image::get_image(prefix + bw_images[type]));
00121 cache[type] = create_cursor(surf);
00122 }
00123
00124 return cache[type];
00125 }
00126
00127 static void clear_cache()
00128 {
00129 for(size_t n = 0; n != cursor::NUM_CURSORS; ++n) {
00130 if(cache[n] != NULL) {
00131 SDL_FreeCursor(cache[n]);
00132 cache[n] = NULL;
00133 }
00134 }
00135
00136 if(cursor_buf != NULL) {
00137 cursor_buf = NULL;
00138 }
00139 }
00140
00141 namespace cursor
00142 {
00143
00144 manager::manager()
00145 {
00146 SDL_ShowCursor(SDL_ENABLE);
00147 set();
00148 }
00149
00150 manager::~manager()
00151 {
00152 clear_cache();
00153 SDL_ShowCursor(SDL_ENABLE);
00154 }
00155
00156 void temporary_use_bw()
00157 {
00158 colour_ready = false;
00159 set();
00160 }
00161
00162 void set(CURSOR_TYPE type)
00163 {
00164
00165 if (type != NUM_CURSORS) {
00166 current_cursor = type;
00167 } else if (current_cursor == NUM_CURSORS) {
00168
00169
00170 current_cursor = NORMAL;
00171 }
00172
00173 const CURSOR_TYPE new_cursor = use_colour_cursors() && colour_ready ? cursor::NO_CURSOR : current_cursor;
00174
00175 SDL_Cursor * cursor_image = get_cursor(new_cursor);
00176
00177
00178
00179 SDL_SetCursor(cursor_image);
00180
00181 }
00182
00183 void set_dragging(bool drag)
00184 {
00185 switch(current_cursor) {
00186 case MOVE:
00187 if (drag) cursor::set(MOVE_DRAG);
00188 break;
00189 case ATTACK:
00190 if (drag) cursor::set(ATTACK_DRAG);
00191 break;
00192 case MOVE_DRAG:
00193 if (!drag) cursor::set(MOVE);
00194 break;
00195 case ATTACK_DRAG:
00196 if (!drag) cursor::set(ATTACK);
00197 break;
00198 default:
00199 break;
00200 }
00201 }
00202
00203 CURSOR_TYPE get()
00204 {
00205 return current_cursor;
00206 }
00207
00208 void set_focus(bool focus)
00209 {
00210 have_focus = focus;
00211 if (focus==false) {
00212 colour_ready = false;
00213 set();
00214 }
00215 }
00216
00217 setter::setter(CURSOR_TYPE type) : old_(current_cursor)
00218 {
00219 set(type);
00220 }
00221
00222 setter::~setter()
00223 {
00224 set(old_);
00225 }
00226
00227 void draw(surface screen)
00228 {
00229 if(use_colour_cursors() == false) {
00230 return;
00231 }
00232
00233 if(current_cursor == NUM_CURSORS) {
00234 current_cursor = NORMAL;
00235 }
00236
00237 if(have_focus == false) {
00238 cursor_buf = NULL;
00239 return;
00240 }
00241
00242 if (!colour_ready) {
00243
00244
00245 colour_ready = true;
00246
00247 set();
00248 }
00249
00250
00251 const surface surf(image::get_image("cursors/" + colour_images[current_cursor]));
00252 if(surf == NULL) {
00253
00254 std::cerr << "could not load colour cursors. Falling back to hardware cursors\n";
00255 preferences::set_colour_cursors(false);
00256 return;
00257 }
00258
00259 if(cursor_buf != NULL && (cursor_buf->w != surf->w || cursor_buf->h != surf->h)) {
00260 cursor_buf = NULL;
00261 }
00262
00263 if(cursor_buf == NULL) {
00264 cursor_buf = create_compatible_surface(surf);
00265 if(cursor_buf == NULL) {
00266 std::cerr << "Could not allocate surface for mouse cursor\n";
00267 return;
00268 }
00269 }
00270
00271 int new_cursor_x, new_cursor_y;
00272 SDL_GetMouseState(&new_cursor_x,&new_cursor_y);
00273 const bool must_update = new_cursor_x != cursor_x || new_cursor_y != cursor_y;
00274 cursor_x = new_cursor_x;
00275 cursor_y = new_cursor_y;
00276
00277
00278 SDL_Rect area = {cursor_x - shift_x[current_cursor], cursor_y - shift_y[current_cursor],surf->w,surf->h};
00279 SDL_BlitSurface(screen,&area,cursor_buf,NULL);
00280
00281
00282 SDL_BlitSurface(surf,NULL,screen,&area);
00283
00284 if(must_update) {
00285 update_rect(area);
00286 }
00287 }
00288
00289 void undraw(surface screen)
00290 {
00291 if(use_colour_cursors() == false) {
00292 return;
00293 }
00294
00295 if(cursor_buf == NULL) {
00296 return;
00297 }
00298
00299 SDL_Rect area = {cursor_x - shift_x[current_cursor], cursor_y - shift_y[current_cursor],cursor_buf->w,cursor_buf->h};
00300 SDL_BlitSurface(cursor_buf,NULL,screen,&area);
00301 update_rect(area);
00302 }
00303
00304 }
00305