3#include <cgv/media/riff.h>
9PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp)
16 if (!GetObject(hBmp,
sizeof(BITMAP), (LPSTR)&bmp))
20 cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
23 else if (cClrBits <= 4)
25 else if (cClrBits <= 8)
27 else if (cClrBits <= 16)
29 else if (cClrBits <= 24)
38 pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
39 sizeof(BITMAPINFOHEADER) +
40 sizeof(RGBQUAD) * (
size_t(1) << cClrBits));
45 pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
46 sizeof(BITMAPINFOHEADER));
50 pbmi->bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
51 pbmi->bmiHeader.biWidth = bmp.bmWidth;
52 pbmi->bmiHeader.biHeight = bmp.bmHeight;
53 pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
54 pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
56 pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
59 pbmi->bmiHeader.biCompression = BI_RGB;
65 pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
66 * pbmi->bmiHeader.biHeight;
69 pbmi->bmiHeader.biClrImportant = 0;
73unsigned char* get_bitmap_data(HBITMAP hbmp,
unsigned& tex_w,
unsigned& tex_h)
76 if (!GetObject(hbmp,
sizeof(BITMAP), (LPSTR)&bmp))
78 PBITMAPINFO pbi = CreateBitmapInfoStruct(hbmp);
79 PBITMAPINFOHEADER pbih = (PBITMAPINFOHEADER) pbi;
80 unsigned my_size = 4 * pbih->biWidth * pbih->biHeight;
81 if (pbih->biSizeImage >= my_size)
82 my_size = pbih->biSizeImage;
83 unsigned char* lpBits =
new unsigned char[my_size];
86 if (!GetDIBits(GetDC(NULL), hbmp, 0, (WORD) pbih->biHeight, lpBits, pbi, DIB_RGB_COLORS))
93unsigned char* get_cursor_bitmap(HCURSOR hc,
unsigned& w,
unsigned& h,
int anim_step = 0)
98 if (!GetObject(ii.hbmColor ? ii.hbmColor : ii.hbmMask, sizeof(BITMAP), (LPSTR)&bmp))
104 HDC dc = GetDC(NULL);
105 HDC mem_dc = CreateCompatibleDC(dc);
106 HBITMAP hbm = CreateCompatibleBitmap (dc, w, h);
107 HBITMAP old_bm = (HBITMAP)SelectObject(mem_dc, hbm);
113 HBRUSH black = CreateSolidBrush(RGB(0,0,0));
115 FillRect(mem_dc,&r, black);
116 if (DrawIconEx(mem_dc,0,0,hc,w,h,anim_step,NULL,DI_NORMAL | DI_COMPAT) == FALSE) {
117 SelectObject(mem_dc, old_bm);
125 SelectObject(mem_dc, old_bm);
126 unsigned char* data_b = get_bitmap_data(hbm,w,h);
128 old_bm = (HBITMAP)SelectObject(mem_dc, hbm);
129 HBRUSH white = CreateSolidBrush(RGB(255,255,255));
130 FillRect(mem_dc,&r, white);
131 DrawIconEx(mem_dc,0,0,hc,w,h,anim_step,NULL,DI_NORMAL | DI_COMPAT);
132 SelectObject(mem_dc, old_bm);
133 unsigned char* data_w = get_bitmap_data(hbm,w,h);
136 for (
unsigned i=0; i<n; ++i) {
138 for (
unsigned j=0; j<3; ++j)
139 sum_alpha += 255+(
int)data_b[4*i+j]-(int)data_w[4*i+j];
140 if (sum_alpha > 3*255)
142 unsigned char alpha = (
unsigned char)(sum_alpha/3);
143 data_b[4*i+3] = alpha;
145 for (
unsigned j=0; j<3; ++j) {
146 float v = data_b[4*i+j]*255.0f/alpha;
149 data_b[4*i+j] = (
unsigned char) v;
164unsigned create_texture_from_cursor(HCURSOR hc,
unsigned& tex_w,
unsigned& tex_h,
int& hot_x,
int& hot_y,
int anim_step = 0)
168 GetIconInfo(hc, &ii);
172 unsigned char* bgra_data = get_cursor_bitmap(hc, tex_w, tex_h, anim_step);
175 if (anim_step == 1) {
177 unsigned char* first_bgra_data = get_cursor_bitmap(hc, w, h, 0);
179 bool found_diff =
false;
180 for (
int j=0; !found_diff && (j<m); ++j)
181 if (first_bgra_data[j] != bgra_data[j])
183 delete [] first_bgra_data;
191 glGenTextures(1, &tex_id);
192 glBindTexture(GL_TEXTURE_2D, tex_id);
193 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, bgra_data);
194 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
195 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
213 return tex_ids.size() > 0;
216void gl_cursor::clear()
218 while (tex_ids.size() > 0) {
219 glDeleteTextures(1, &tex_ids.back());
226void gl_cursor::add_frame(
unsigned tex_id)
229 tex_ids.push_back(tex_id);
237std::wstring str2wstr(
const std::string& s)
242 int n = MultiByteToWideChar(CP_ACP,0,s.c_str(),(
int)s.size(),&ws[0],(
int)ws.size());
245 std::cerr <<
"str2wstr(const std::string& s) not implemented" << std::endl;
251bool create_from_cursor(HCURSOR hc, gl_cursor* c)
256 unsigned tex_id, i = 0;
258 tex_id = create_texture_from_cursor(hc, c->w, c->h, c->hot_x, c->hot_y, i);
260 c->add_frame(tex_id);
262 }
while (tex_id != -1);
263 return c->is_created();
268 static struct {
const char* id;
276 {
"startup", IDC_APPSTARTING },
277 {
"arrow", IDC_ARROW },
278 {
"cross", IDC_CROSS },
279 {
"wait", IDC_WAIT },
280 {
"hand", IDC_HAND },
281 {
"help", IDC_HELP },
283 {
"ns", IDC_SIZENS },
284 {
"we", IDC_SIZEWE },
285 {
"move", IDC_SIZEALL },
286 {
"nesw", IDC_SIZENESW },
287 {
"nwse", IDC_SIZENWSE }
294 for (
unsigned i=0; i<10; ++i)
295 if (
id == lookup[i].
id) {
301 return create_from_cursor(LoadCursor(NULL, cid),
this);
304#include <cgv/type/standard_types.h>
327 ani_riff_handler(gl_cursor* _c) : c(_c)
333 void process_chunk_data(
media::fourcc id,
unsigned size,
void* data_ptr)
336 anih_structure& as = *((anih_structure*)data_ptr);
337 nr_frames = as.nr_frames;
338 nr_steps = as.nr_steps;
339 period = as.display_rate == 0 ? 3 : as.display_rate;
340 c->tex_ids.resize(nr_frames);
341 c->frames.resize(nr_steps);
342 c->periods.resize(nr_steps);
344 for (i=0; i<nr_steps; ++i) {
345 c->frames[i] = i % nr_frames;
346 c->periods[i] = period;
348 for (i=0; i<nr_frames; ++i)
350 c->update_duration();
352 else if (
id ==
"seq") {
353 unsigned count = size/4;
354 unsigned *values = (
unsigned*)data_ptr;
355 c->frames.resize(count);
356 c->periods.resize(count);
357 if (count != c->periods.size())
358 std::cerr <<
"found wrong number of seq entries" << std::endl;
360 for (
unsigned i=0; i<count; ++i)
361 c->frames[i] = values[i];
363 else if (
id ==
"rate") {
364 unsigned count = size/4;
365 unsigned *values = (
unsigned*)data_ptr;
366 if (count != c->periods.size())
367 std::cerr <<
"found wrong number of rate entries" << std::endl;
369 for (
unsigned i=0; i<count; ++i)
370 c->periods[i] = values[i];
371 c->update_duration();
379 unsigned dot = (unsigned)file_name.find_last_of(
'.');
380 if (dot == std::string::npos)
382 std::string ext = file_name.substr(dot+1);
383 for (
unsigned i=0; i<ext.size(); ++i)
384 if (ext[i] >=
'a' && ext[i] <=
'z') {
391 return create_from_cursor(LoadCursorFromFile(
393 str2wstr(file_name).c_str()
400 else if (ext ==
"ANI") {
403 ani_riff_handler arh(
this);
405 if (!rr.read(file_name))
408 HCURSOR hc = LoadCursorFromFile(
410 str2wstr(file_name).c_str()
418 if (tex_ids[frames[i]] == -1) {
419 tex_ids[frames[i]] = create_texture_from_cursor(hc, w, h, hot_x, hot_y, i);
420 if (tex_ids[frames[i]] == -1) {
434 std::cerr <<
"gl_cursor::create only implemented under WIN32" << std::endl;
439 std::cerr <<
"gl_cursor::create_from_file only implemented under WIN32" << std::endl;
445void gl_cursor::update_duration()
448 for (
unsigned i=0; i<periods.size(); ++i)
449 duration += periods[i];
455 return (
unsigned)frames.size();
461 return (
unsigned)tex_ids.size();
467 return tex_ids[frame_idx];
473 return frames[step_idx];
479 frames[step_idx] = frame_idx;
485 return periods[step_idx];
491 periods[step_idx] = period;
498 frames.push_back(frame_idx);
499 periods.push_back(period);
506 unsigned i, period = ((int)(elapsed_seconds * 60))%duration;
507 for (i=0; i<periods.size(); ++i) {
508 if (periods[i] > period)
510 period -= periods[i];
512 return i % periods.size();
517 if (frame_idx >= tex_ids.size())
519 if (tex_ids[frame_idx] == -1)
522 glPushAttrib(GL_COLOR_BUFFER_BIT|GL_TEXTURE_BIT);
523 glEnable(GL_ALPHA_TEST);
525 glAlphaFunc(GL_GREATER, 0.0f);
526 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
527 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, use_color ? GL_MODULATE : GL_REPLACE);
528 glBindTexture(GL_TEXTURE_2D, tex_ids[frame_idx]);
531 glEnable(GL_TEXTURE_2D);
complete implementation of method actions that only call one method when entering a node
unsigned get_nr_steps() const
return the number of animation steps
gl_cursor()
construct empty gl_cursor instance
void append_step(unsigned frame_idx, unsigned period)
append an animation step given by frame index and step period
bool is_created() const
check whether cursor has been created
void set_step_period(unsigned step_idx, unsigned period)
return the period of given step in 1/60th of a second
unsigned get_texture_id(unsigned frame_idx=0) const
return the gl texture id of the given frame
unsigned get_step_period(unsigned step_idx) const
return the period of given step in 1/60th of a second
bool create(const std::string &id="arrow")
Create cursor from textual name of default cursor.
unsigned get_step_frame(unsigned step_idx) const
return the frame index of given step
void set_step_frame(unsigned step_idx, unsigned frame_idx)
set the frame index of given step
unsigned get_nr_frames() const
return the number of animation frames
void draw(int x, int y, bool use_color=false, unsigned frame_idx=0)
draw the cursor at the given location
bool create_from_file(const std::string &file_name)
Create cursor from a file of type .cur or .ani.
unsigned find_step_index(double elapsed_seconds) const
find the step index of a given elapsed time in seconds
namespace for compile time type information