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