|
MythTV
0.26-pre
|
00001 /* 00002 * This file is part of libbluray 00003 * Copyright (C) 2010 hpi1 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with this library. If not, see 00017 * <http://www.gnu.org/licenses/>. 00018 */ 00019 00020 #include "graphics_controller.h" 00021 00022 #include "graphics_processor.h" 00023 #include "ig.h" 00024 #include "overlay.h" 00025 00026 #include "util/macro.h" 00027 #include "util/logging.h" 00028 #include "util/mutex.h" 00029 00030 #include "../register.h" 00031 #include "../keys.h" 00032 00033 #include <inttypes.h> 00034 #include <string.h> 00035 00036 #define GC_ERROR(...) BD_DEBUG(DBG_GC | DBG_CRIT, __VA_ARGS__) 00037 #define GC_TRACE(...) BD_DEBUG(DBG_GC, __VA_ARGS__) 00038 00039 /* 00040 * 00041 */ 00042 00043 typedef struct { 00044 uint16_t enabled_button; /* enabled button id */ 00045 uint16_t x, y, w, h; /* button rect on overlay plane (if drawn) */ 00046 int animate_indx; /* currently showing object index of animated button, < 0 for static buttons */ 00047 } BOG_DATA; 00048 00049 struct graphics_controller_s { 00050 00051 BD_REGISTERS *regs; 00052 00053 BD_MUTEX mutex; 00054 00055 /* overlay output */ 00056 void *overlay_proc_handle; 00057 void (*overlay_proc)(void *, const struct bd_overlay_s * const); 00058 00059 /* state */ 00060 unsigned ig_drawn; 00061 unsigned pg_drawn; 00062 unsigned popup_visible; 00063 unsigned valid_mouse_position; 00064 BOG_DATA *bog_data; 00065 BOG_DATA *saved_bog_data; 00066 00067 /* data */ 00068 PG_DISPLAY_SET *pgs; 00069 PG_DISPLAY_SET *igs; 00070 00071 /* */ 00072 GRAPHICS_PROCESSOR *pgp; 00073 GRAPHICS_PROCESSOR *igp; 00074 }; 00075 00076 /* 00077 * object lookup 00078 */ 00079 00080 static BD_PG_OBJECT *_find_object(PG_DISPLAY_SET *s, unsigned object_id) 00081 { 00082 unsigned ii; 00083 00084 for (ii = 0; ii < s->num_object; ii++) { 00085 if (s->object[ii].id == object_id) { 00086 return &s->object[ii]; 00087 } 00088 } 00089 00090 return NULL; 00091 } 00092 00093 static BD_PG_PALETTE *_find_palette(PG_DISPLAY_SET *s, unsigned palette_id) 00094 { 00095 unsigned ii; 00096 00097 for (ii = 0; ii < s->num_palette; ii++) { 00098 if (s->palette[ii].id == palette_id) { 00099 return &s->palette[ii]; 00100 } 00101 } 00102 00103 return NULL; 00104 } 00105 00106 static BD_IG_BUTTON *_find_button_bog(BD_IG_BOG *bog, unsigned button_id) 00107 { 00108 unsigned ii; 00109 00110 for (ii = 0; ii < bog->num_buttons; ii++) { 00111 if (bog->button[ii].id == button_id) { 00112 return &bog->button[ii]; 00113 } 00114 } 00115 00116 return NULL; 00117 } 00118 00119 static BD_IG_BUTTON *_find_button_page(BD_IG_PAGE *page, unsigned button_id, unsigned *bog_idx) 00120 { 00121 unsigned ii; 00122 00123 for (ii = 0; ii < page->num_bogs; ii++) { 00124 BD_IG_BUTTON *button = _find_button_bog(&page->bog[ii], button_id); 00125 if (button) { 00126 if (bog_idx) { 00127 *bog_idx = ii; 00128 } 00129 return button; 00130 } 00131 } 00132 00133 return NULL; 00134 } 00135 00136 static BD_IG_PAGE *_find_page(BD_IG_INTERACTIVE_COMPOSITION *c, unsigned page_id) 00137 { 00138 unsigned ii; 00139 00140 for (ii = 0; ii < c->num_pages; ii++) { 00141 if (c->page[ii].id == page_id) { 00142 return &c->page[ii]; 00143 } 00144 } 00145 00146 return NULL; 00147 } 00148 00149 enum { BTN_NORMAL, BTN_SELECTED, BTN_ACTIVATED }; 00150 00151 static BD_PG_OBJECT *_find_object_for_button(PG_DISPLAY_SET *s, 00152 BD_IG_BUTTON *button, int state, 00153 BOG_DATA *bog_data) 00154 { 00155 BD_PG_OBJECT *object = NULL; 00156 unsigned object_id = 0xffff; 00157 unsigned object_id_end = 0xffff; 00158 unsigned repeat = 0; 00159 00160 switch (state) { 00161 case BTN_NORMAL: 00162 object_id = button->normal_start_object_id_ref; 00163 object_id_end = button->normal_end_object_id_ref; 00164 repeat = button->normal_repeat_flag; 00165 break; 00166 case BTN_SELECTED: 00167 object_id = button->selected_start_object_id_ref; 00168 object_id_end = button->selected_end_object_id_ref; 00169 repeat = button->selected_repeat_flag; 00170 break; 00171 case BTN_ACTIVATED: 00172 object_id = button->activated_start_object_id_ref; 00173 object_id_end = button->activated_end_object_id_ref; 00174 break; 00175 } 00176 00177 if (bog_data) { 00178 if (bog_data->animate_indx >= 0) { 00179 int range = object_id_end - object_id; 00180 00181 if (range > 0 && object_id < 0xffff && object_id_end < 0xffff) { 00182 GC_TRACE("animate button #%d: animate_indx %d, range %d, repeat %d\n", 00183 button->id, bog_data->animate_indx, range, repeat); 00184 00185 object_id += bog_data->animate_indx % (range + 1); 00186 bog_data->animate_indx++; 00187 if (!repeat && bog_data->animate_indx > range) { 00188 /* terminate animation to the last object */ 00189 bog_data->animate_indx = -1; 00190 } 00191 00192 } else { 00193 /* no animation for this button */ 00194 bog_data->animate_indx = -1; 00195 } 00196 } 00197 } 00198 00199 object = _find_object(s, object_id); 00200 00201 return object; 00202 } 00203 00204 /* 00205 * util 00206 */ 00207 00208 static int _is_button_enabled(GRAPHICS_CONTROLLER *gc, BD_IG_PAGE *page, unsigned button_id) 00209 { 00210 unsigned ii; 00211 for (ii = 0; ii < page->num_bogs; ii++) { 00212 if (gc->bog_data[ii].enabled_button == button_id) { 00213 return 1; 00214 } 00215 } 00216 return 0; 00217 } 00218 00219 static uint16_t _find_selected_button_id(GRAPHICS_CONTROLLER *gc) 00220 { 00221 /* executed when playback condition changes (ex. new page, popup-on, ...) */ 00222 PG_DISPLAY_SET *s = gc->igs; 00223 BD_IG_PAGE *page = NULL; 00224 unsigned page_id = bd_psr_read(gc->regs, PSR_MENU_PAGE_ID); 00225 unsigned button_id = bd_psr_read(gc->regs, PSR_SELECTED_BUTTON_ID); 00226 unsigned ii; 00227 00228 page = _find_page(&s->ics->interactive_composition, page_id); 00229 if (!page) { 00230 GC_TRACE("_find_selected_button_id(): unknown page #%d (have %d pages)\n", 00231 page_id, s->ics->interactive_composition.num_pages); 00232 return 0xffff; 00233 } 00234 00235 /* run 5.9.8.3 */ 00236 00237 /* 1) always use page->default_selected_button_id_ref if it is valid */ 00238 if (_find_button_page(page, page->default_selected_button_id_ref, NULL) && 00239 _is_button_enabled(gc, page, page->default_selected_button_id_ref)) { 00240 00241 GC_TRACE("_find_selected_button_id() -> default #%d\n", page->default_selected_button_id_ref); 00242 return page->default_selected_button_id_ref; 00243 } 00244 00245 /* 2) fallback to current PSR10 value if it is valid */ 00246 for (ii = 0; ii < page->num_bogs; ii++) { 00247 BD_IG_BOG *bog = &page->bog[ii]; 00248 uint16_t enabled_button = gc->bog_data[ii].enabled_button; 00249 00250 if (button_id == enabled_button) { 00251 if (_find_button_bog(bog, enabled_button)) { 00252 GC_TRACE("_find_selected_button_id() -> PSR10 #%d\n", enabled_button); 00253 return enabled_button; 00254 } 00255 } 00256 } 00257 00258 /* 3) fallback to find first valid_button_id_ref from page */ 00259 for (ii = 0; ii < page->num_bogs; ii++) { 00260 BD_IG_BOG *bog = &page->bog[ii]; 00261 uint16_t enabled_button = gc->bog_data[ii].enabled_button; 00262 00263 if (_find_button_bog(bog, enabled_button)) { 00264 GC_TRACE("_find_selected_button_id() -> first valid #%d\n", enabled_button); 00265 return enabled_button; 00266 } 00267 } 00268 00269 GC_TRACE("_find_selected_button_id(): not found -> 0xffff\n"); 00270 return 0xffff; 00271 } 00272 00273 static int _save_page_state(GRAPHICS_CONTROLLER *gc) 00274 { 00275 if (!gc->bog_data) { 00276 GC_ERROR("_save_page_state(): no bog data !\n"); 00277 return -1; 00278 } 00279 00280 PG_DISPLAY_SET *s = gc->igs; 00281 BD_IG_PAGE *page = NULL; 00282 unsigned page_id = bd_psr_read(gc->regs, PSR_MENU_PAGE_ID); 00283 unsigned ii; 00284 00285 page = _find_page(&s->ics->interactive_composition, page_id); 00286 if (!page) { 00287 GC_ERROR("_save_page_state(): unknown page #%d (have %d pages)\n", 00288 page_id, s->ics->interactive_composition.num_pages); 00289 return -1; 00290 } 00291 00292 /* copy enabled button state, clear draw state */ 00293 00294 X_FREE(gc->saved_bog_data); 00295 gc->saved_bog_data = calloc(page->num_bogs, sizeof(*gc->saved_bog_data)); 00296 00297 for (ii = 0; ii < page->num_bogs; ii++) { 00298 gc->saved_bog_data[ii].enabled_button = gc->bog_data[ii].enabled_button; 00299 gc->saved_bog_data[ii].animate_indx = gc->bog_data[ii].animate_indx >= 0 ? 0 : -1; 00300 } 00301 00302 return 1; 00303 } 00304 00305 static int _restore_page_state(GRAPHICS_CONTROLLER *gc) 00306 { 00307 if (gc->saved_bog_data) { 00308 if (gc->bog_data) { 00309 GC_ERROR("_restore_page_state(): bog data already exists !\n"); 00310 X_FREE(gc->bog_data); 00311 } 00312 gc->bog_data = gc->saved_bog_data; 00313 gc->saved_bog_data = NULL; 00314 00315 return 1; 00316 } 00317 return -1; 00318 } 00319 00320 static void _reset_page_state(GRAPHICS_CONTROLLER *gc) 00321 { 00322 PG_DISPLAY_SET *s = gc->igs; 00323 BD_IG_PAGE *page = NULL; 00324 unsigned page_id = bd_psr_read(gc->regs, PSR_MENU_PAGE_ID); 00325 unsigned ii; 00326 00327 page = _find_page(&s->ics->interactive_composition, page_id); 00328 if (!page) { 00329 GC_ERROR("_reset_page_state(): unknown page #%d (have %d pages)\n", 00330 page_id, s->ics->interactive_composition.num_pages); 00331 return; 00332 } 00333 00334 size_t size = page->num_bogs * sizeof(*gc->bog_data); 00335 gc->bog_data = realloc(gc->bog_data, size); 00336 00337 memset(gc->bog_data, 0, size); 00338 00339 for (ii = 0; ii < page->num_bogs; ii++) { 00340 gc->bog_data[ii].enabled_button = page->bog[ii].default_valid_button_id_ref; 00341 gc->bog_data[ii].animate_indx = 0; 00342 } 00343 } 00344 00345 static void _clear_osd_area(GRAPHICS_CONTROLLER *gc, int plane, 00346 uint16_t x, uint16_t y, uint16_t w, uint16_t h) 00347 { 00348 if (gc->overlay_proc) { 00349 /* clear plane */ 00350 const BD_OVERLAY ov = { 00351 .pts = -1, 00352 .plane = plane, 00353 .x = x, 00354 .y = y, 00355 .w = w, 00356 .h = h, 00357 .palette = NULL, 00358 .img = NULL, 00359 }; 00360 00361 gc->overlay_proc(gc->overlay_proc_handle, &ov); 00362 } 00363 } 00364 00365 static void _clear_osd(GRAPHICS_CONTROLLER *gc, int plane) 00366 { 00367 _clear_osd_area(gc, plane, 0, 0, 1920, 1080); 00368 00369 if (plane == BD_OVERLAY_IG) { 00370 gc->ig_drawn = 0; 00371 } else { 00372 gc->pg_drawn = 0; 00373 } 00374 } 00375 00376 static void _clear_bog_area(GRAPHICS_CONTROLLER *gc, BOG_DATA *bog_data) 00377 { 00378 if (gc->ig_drawn && bog_data->w && bog_data->h) { 00379 00380 _clear_osd_area(gc, BD_OVERLAY_IG, bog_data->x, bog_data->y, bog_data->w, bog_data->h); 00381 00382 bog_data->x = bog_data->y = bog_data->w = bog_data->h = 0; 00383 } 00384 } 00385 00386 static void _select_button(GRAPHICS_CONTROLLER *gc, uint32_t button_id) 00387 { 00388 bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, button_id); 00389 } 00390 00391 static void _select_page(GRAPHICS_CONTROLLER *gc, uint16_t page_id) 00392 { 00393 bd_psr_write(gc->regs, PSR_MENU_PAGE_ID, page_id); 00394 _clear_osd(gc, BD_OVERLAY_IG); 00395 _reset_page_state(gc); 00396 00397 uint16_t button_id = _find_selected_button_id(gc); 00398 _select_button(gc, button_id); 00399 } 00400 00401 static void _gc_reset(GRAPHICS_CONTROLLER *gc) 00402 { 00403 _clear_osd(gc, BD_OVERLAY_PG); 00404 _clear_osd(gc, BD_OVERLAY_IG); 00405 00406 gc->popup_visible = 0; 00407 00408 graphics_processor_free(&gc->igp); 00409 graphics_processor_free(&gc->pgp); 00410 00411 pg_display_set_free(&gc->pgs); 00412 pg_display_set_free(&gc->igs); 00413 00414 X_FREE(gc->bog_data); 00415 } 00416 00417 /* 00418 * register hook 00419 */ 00420 static void _process_psr_event(void *handle, BD_PSR_EVENT *ev) 00421 { 00422 GRAPHICS_CONTROLLER *gc = (GRAPHICS_CONTROLLER *)handle; 00423 00424 if (ev->ev_type == BD_PSR_SAVE) { 00425 BD_DEBUG(DBG_GC, "PSR SAVE event\n"); 00426 00427 /* save menu page state */ 00428 bd_mutex_lock(&gc->mutex); 00429 _save_page_state(gc); 00430 bd_mutex_unlock(&gc->mutex); 00431 00432 return; 00433 } 00434 00435 if (ev->ev_type == BD_PSR_RESTORE) { 00436 switch (ev->psr_idx) { 00437 00438 case PSR_SELECTED_BUTTON_ID: 00439 return; 00440 00441 case PSR_MENU_PAGE_ID: 00442 /* restore menus */ 00443 bd_mutex_lock(&gc->mutex); 00444 _restore_page_state(gc); 00445 bd_mutex_unlock(&gc->mutex); 00446 return; 00447 00448 default: 00449 /* others: ignore */ 00450 return; 00451 } 00452 } 00453 } 00454 00455 /* 00456 * init / free 00457 */ 00458 00459 GRAPHICS_CONTROLLER *gc_init(BD_REGISTERS *regs, void *handle, gc_overlay_proc_f func) 00460 { 00461 GRAPHICS_CONTROLLER *p = calloc(1, sizeof(*p)); 00462 00463 p->regs = regs; 00464 00465 p->overlay_proc_handle = handle; 00466 p->overlay_proc = func; 00467 00468 bd_mutex_init(&p->mutex); 00469 00470 bd_psr_register_cb(regs, _process_psr_event, p); 00471 00472 return p; 00473 } 00474 00475 void gc_free(GRAPHICS_CONTROLLER **p) 00476 { 00477 if (p && *p) { 00478 00479 GRAPHICS_CONTROLLER *gc = *p; 00480 00481 bd_psr_unregister_cb(gc->regs, _process_psr_event, gc); 00482 00483 _gc_reset(gc); 00484 00485 if (gc->overlay_proc) { 00486 gc->overlay_proc(gc->overlay_proc_handle, NULL); 00487 } 00488 00489 bd_mutex_destroy(&gc->mutex); 00490 00491 X_FREE(*p); 00492 } 00493 } 00494 00495 /* 00496 * graphics stream input 00497 */ 00498 00499 int gc_decode_ts(GRAPHICS_CONTROLLER *gc, uint16_t pid, uint8_t *block, unsigned num_blocks, int64_t stc) 00500 { 00501 if (!gc) { 00502 GC_TRACE("gc_decode_ts(): no graphics controller\n"); 00503 return -1; 00504 } 00505 00506 if (pid >= 0x1400 && pid < 0x1500) { 00507 /* IG stream */ 00508 00509 if (!gc->igp) { 00510 gc->igp = graphics_processor_init(); 00511 } 00512 00513 bd_mutex_lock(&gc->mutex); 00514 00515 if (!graphics_processor_decode_ts(gc->igp, &gc->igs, 00516 pid, block, num_blocks, 00517 stc)) { 00518 /* no new complete display set */ 00519 bd_mutex_unlock(&gc->mutex); 00520 return 0; 00521 } 00522 00523 if (!gc->igs || !gc->igs->complete) { 00524 bd_mutex_unlock(&gc->mutex); 00525 return 0; 00526 } 00527 00528 gc->popup_visible = 0; 00529 00530 _select_page(gc, 0); 00531 00532 bd_mutex_unlock(&gc->mutex); 00533 00534 return 1; 00535 } 00536 00537 else if (pid >= 0x1200 && pid < 0x1300) { 00538 /* PG stream */ 00539 if (!gc->pgp) { 00540 gc->pgp = graphics_processor_init(); 00541 } 00542 graphics_processor_decode_ts(gc->pgp, &gc->pgs, 00543 pid, block, num_blocks, 00544 stc); 00545 00546 if (!gc->pgs || !gc->pgs->complete) { 00547 return 0; 00548 } 00549 00550 return 1; 00551 } 00552 00553 return -1; 00554 } 00555 00556 /* 00557 * IG rendering 00558 */ 00559 00560 static void _render_button(GRAPHICS_CONTROLLER *gc, BD_IG_BUTTON *button, BD_PG_PALETTE *palette, 00561 int state, BOG_DATA *bog_data) 00562 { 00563 BD_PG_OBJECT *object = NULL; 00564 BD_OVERLAY ov; 00565 00566 object = _find_object_for_button(gc->igs, button, state, bog_data); 00567 if (!object) { 00568 GC_TRACE("_render_button(#%d): object (state %d) not found\n", button->id, state); 00569 00570 _clear_bog_area(gc, bog_data); 00571 00572 return; 00573 } 00574 00575 ov.pts = -1; 00576 ov.plane = BD_OVERLAY_IG; 00577 00578 ov.x = bog_data->x = button->x_pos; 00579 ov.y = bog_data->y = button->y_pos; 00580 ov.w = bog_data->w = object->width; 00581 ov.h = bog_data->h = object->height; 00582 00583 ov.img = object->img; 00584 ov.palette = palette->entry; 00585 00586 if (gc->overlay_proc) { 00587 gc->overlay_proc(gc->overlay_proc_handle, &ov); 00588 gc->ig_drawn = 1; 00589 } 00590 } 00591 00592 static void _render_page(GRAPHICS_CONTROLLER *gc, 00593 unsigned activated_button_id, 00594 GC_NAV_CMDS *cmds) 00595 { 00596 PG_DISPLAY_SET *s = gc->igs; 00597 BD_IG_PAGE *page = NULL; 00598 BD_PG_PALETTE *palette = NULL; 00599 unsigned page_id = bd_psr_read(gc->regs, PSR_MENU_PAGE_ID); 00600 unsigned ii; 00601 unsigned selected_button_id = bd_psr_read(gc->regs, PSR_SELECTED_BUTTON_ID); 00602 00603 if (s->ics->interactive_composition.ui_model == IG_UI_MODEL_POPUP && !gc->popup_visible) { 00604 GC_TRACE("_render_page(): popup menu not visible\n"); 00605 00606 _clear_osd(gc, BD_OVERLAY_IG); 00607 00608 return; 00609 } 00610 00611 page = _find_page(&s->ics->interactive_composition, page_id); 00612 if (!page) { 00613 GC_ERROR("_render_page: unknown page id %d (have %d pages)\n", 00614 page_id, s->ics->interactive_composition.num_pages); 00615 return; 00616 } 00617 00618 palette = _find_palette(s, page->palette_id_ref); 00619 if (!palette) { 00620 GC_ERROR("_render_page: unknown palette id %d (have %d palettes)\n", 00621 page->palette_id_ref, s->num_palette); 00622 return; 00623 } 00624 00625 GC_TRACE("rendering page #%d using palette #%d. page has %d bogs\n", 00626 page->id, page->palette_id_ref, page->num_bogs); 00627 00628 for (ii = 0; ii < page->num_bogs; ii++) { 00629 BD_IG_BOG *bog = &page->bog[ii]; 00630 unsigned valid_id = gc->bog_data[ii].enabled_button; 00631 BD_IG_BUTTON *button; 00632 00633 button = _find_button_bog(bog, valid_id); 00634 00635 if (!button) { 00636 GC_TRACE("_render_page(): bog %d: button %d not found\n", ii, valid_id); 00637 00638 } else if (button->id == activated_button_id) { 00639 _render_button(gc, button, palette, BTN_ACTIVATED, &gc->bog_data[ii]); 00640 00641 } else if (button->id == selected_button_id) { 00642 00643 _render_button(gc, button, palette, BTN_SELECTED, &gc->bog_data[ii]); 00644 00645 if (button->auto_action_flag && cmds) { 00646 cmds->num_nav_cmds = button->num_nav_cmds; 00647 cmds->nav_cmds = button->nav_cmds; 00648 } 00649 00650 } else { 00651 _render_button(gc, button, palette, BTN_NORMAL, &gc->bog_data[ii]); 00652 00653 } 00654 } 00655 } 00656 00657 /* 00658 * user actions 00659 */ 00660 00661 #define VK_IS_NUMERIC(vk) (/*vk >= BD_VK_0 &&*/ vk <= BD_VK_9) 00662 #define VK_IS_CURSOR(vk) (vk >= BD_VK_UP && vk <= BD_VK_RIGHT) 00663 #define VK_TO_NUMBER(vk) ((vk) - BD_VK_0) 00664 00665 static int _user_input(GRAPHICS_CONTROLLER *gc, bd_vk_key_e key, GC_NAV_CMDS *cmds) 00666 { 00667 PG_DISPLAY_SET *s = gc->igs; 00668 BD_IG_PAGE *page = NULL; 00669 unsigned page_id = bd_psr_read(gc->regs, PSR_MENU_PAGE_ID); 00670 unsigned cur_btn_id = bd_psr_read(gc->regs, PSR_SELECTED_BUTTON_ID); 00671 unsigned new_btn_id = cur_btn_id; 00672 unsigned ii; 00673 int activated_btn_id = -1; 00674 00675 if (s->ics->interactive_composition.ui_model == IG_UI_MODEL_POPUP && !gc->popup_visible) { 00676 GC_TRACE("_user_input(): popup menu not visible\n"); 00677 return -1; 00678 } 00679 if (!gc->ig_drawn) { 00680 GC_ERROR("_user_input(): menu not visible\n"); 00681 return -1; 00682 } 00683 00684 GC_TRACE("_user_input(%d)\n", key); 00685 00686 page = _find_page(&s->ics->interactive_composition, page_id); 00687 if (!page) { 00688 GC_ERROR("_user_input(): unknown page id %d (have %d pages)\n", 00689 page_id, s->ics->interactive_composition.num_pages); 00690 return -1; 00691 } 00692 00693 if (key == BD_VK_MOUSE_ACTIVATE) { 00694 if (!gc->valid_mouse_position) { 00695 GC_TRACE("_user_input(): BD_VK_MOUSE_ACTIVATE outside of valid buttons\n"); 00696 return -1; 00697 } 00698 key = BD_VK_ENTER; 00699 } 00700 00701 for (ii = 0; ii < page->num_bogs; ii++) { 00702 BD_IG_BOG *bog = &page->bog[ii]; 00703 unsigned valid_id = gc->bog_data[ii].enabled_button; 00704 BD_IG_BUTTON *button = _find_button_bog(bog, valid_id); 00705 if (!button) { 00706 continue; 00707 } 00708 00709 /* numeric select */ 00710 if (VK_IS_NUMERIC(key)) { 00711 if (button->numeric_select_value == VK_TO_NUMBER(key)) { 00712 new_btn_id = button->id; 00713 } 00714 } 00715 00716 /* cursor keys */ 00717 else if (VK_IS_CURSOR(key) || key == BD_VK_ENTER) { 00718 if (button->id == cur_btn_id) { 00719 switch(key) { 00720 case BD_VK_UP: 00721 new_btn_id = button->upper_button_id_ref; 00722 break; 00723 case BD_VK_DOWN: 00724 new_btn_id = button->lower_button_id_ref; 00725 break; 00726 case BD_VK_LEFT: 00727 new_btn_id = button->left_button_id_ref; 00728 break; 00729 case BD_VK_RIGHT: 00730 new_btn_id = button->right_button_id_ref; 00731 break; 00732 case BD_VK_ENTER: 00733 activated_btn_id = cur_btn_id; 00734 00735 cmds->num_nav_cmds = button->num_nav_cmds; 00736 cmds->nav_cmds = button->nav_cmds; 00737 cmds->sound_id_ref = button->activated_sound_id_ref; 00738 break; 00739 default:; 00740 } 00741 } 00742 00743 if (new_btn_id != cur_btn_id) { 00744 BD_IG_BUTTON *button = _find_button_page(page, new_btn_id, NULL); 00745 if (button) { 00746 cmds->sound_id_ref = button->selected_sound_id_ref; 00747 } 00748 } 00749 } 00750 } 00751 00752 /* render page ? */ 00753 if (new_btn_id != cur_btn_id || activated_btn_id >= 0) { 00754 00755 _select_button(gc, new_btn_id); 00756 00757 _render_page(gc, activated_btn_id, cmds); 00758 00759 /* found one*/ 00760 return 1; 00761 } 00762 00763 return 0; 00764 } 00765 00766 static void _set_button_page(GRAPHICS_CONTROLLER *gc, uint32_t param) 00767 { 00768 unsigned page_flag = param & 0x80000000; 00769 unsigned effect_flag = param & 0x40000000; 00770 unsigned button_flag = param & 0x20000000; 00771 unsigned page_id = (param >> 16) & 0xff; 00772 unsigned button_id = param & 0xffff; 00773 unsigned bog_idx = 0; 00774 00775 PG_DISPLAY_SET *s = gc->igs; 00776 BD_IG_PAGE *page = NULL; 00777 BD_IG_BUTTON *button = NULL; 00778 00779 GC_TRACE("_set_button_page(0x%08x): page flag %d, id %d, effects %d button flag %d, id %d\n", 00780 param, !!page_flag, page_id, !!effect_flag, !!button_flag, button_id); 00781 00782 /* 10.4.3.4 (D) */ 00783 00784 if (!page_flag && !button_flag) { 00785 return; 00786 } 00787 00788 if (page_flag) { 00789 00790 /* current page --> command is ignored */ 00791 if (page_id == bd_psr_read(gc->regs, PSR_MENU_PAGE_ID)) { 00792 GC_TRACE(" page is current\n"); 00793 return; 00794 } 00795 00796 page = _find_page(&s->ics->interactive_composition, page_id); 00797 00798 /* invalid page --> command is ignored */ 00799 if (!page) { 00800 GC_TRACE(" page is invalid\n"); 00801 return; 00802 } 00803 00804 /* page changes */ 00805 00806 _select_page(gc, page_id); 00807 00808 } else { 00809 /* page does not change */ 00810 page_id = bd_psr_read(gc->regs, PSR_MENU_PAGE_ID); 00811 page = _find_page(&s->ics->interactive_composition, page_id); 00812 00813 if (!page) { 00814 GC_ERROR("_set_button_page(): PSR_MENU_PAGE_ID refers to unknown page %d\n", page_id); 00815 return; 00816 } 00817 } 00818 00819 if (button_flag) { 00820 /* find correct button and overlap group */ 00821 button = _find_button_page(page, button_id, &bog_idx); 00822 00823 if (!page_flag) { 00824 if (!button) { 00825 /* page not given, invalid button --> ignore command */ 00826 GC_TRACE(" button is invalid\n"); 00827 return; 00828 } 00829 if (button_id == bd_psr_read(gc->regs, PSR_SELECTED_BUTTON_ID)) { 00830 /* page not given, current button --> ignore command */ 00831 GC_TRACE(" button is current\n"); 00832 return; 00833 } 00834 } 00835 } 00836 00837 if (button) { 00838 gc->bog_data[bog_idx].enabled_button = button_id; 00839 _select_button(gc, button_id); 00840 } 00841 00842 _render_page(gc, 0xffff, NULL); 00843 } 00844 00845 static void _enable_button(GRAPHICS_CONTROLLER *gc, uint32_t button_id, unsigned enable) 00846 { 00847 PG_DISPLAY_SET *s = gc->igs; 00848 BD_IG_PAGE *page = NULL; 00849 BD_IG_BUTTON *button = NULL; 00850 unsigned page_id = bd_psr_read(gc->regs, PSR_MENU_PAGE_ID); 00851 unsigned cur_btn_id = bd_psr_read(gc->regs, PSR_SELECTED_BUTTON_ID); 00852 unsigned bog_idx = 0; 00853 00854 GC_TRACE("_enable_button(#%d, %s)\n", button_id, enable ? "enable" : "disable"); 00855 00856 page = _find_page(&s->ics->interactive_composition, page_id); 00857 if (!page) { 00858 GC_TRACE("_enable_button(): unknown page #%d (have %d pages)\n", 00859 page_id, s->ics->interactive_composition.num_pages); 00860 return; 00861 } 00862 00863 /* find correct button overlap group */ 00864 button = _find_button_page(page, button_id, &bog_idx); 00865 if (!button) { 00866 GC_TRACE("_enable_button(): unknown button #%d (page #%d)\n", button_id, page_id); 00867 return; 00868 } 00869 00870 if (enable) { 00871 if (gc->bog_data[bog_idx].enabled_button == cur_btn_id) { 00872 /* selected button goes to disabled state */ 00873 bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, 0x10000|button_id); 00874 } 00875 gc->bog_data[bog_idx].enabled_button = button_id; 00876 00877 } else { 00878 if (gc->bog_data[bog_idx].enabled_button == button_id) { 00879 gc->bog_data[bog_idx].enabled_button = 0xffff; 00880 } 00881 00882 if (cur_btn_id == button_id) { 00883 bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, 0xffff); 00884 } 00885 } 00886 } 00887 00888 static void _update_selected_button(GRAPHICS_CONTROLLER *gc) 00889 { 00890 /* executed after IG command sequence terminates */ 00891 unsigned button_id = bd_psr_read(gc->regs, PSR_SELECTED_BUTTON_ID); 00892 00893 GC_TRACE("_update_selected_button(): currently enabled button is #%d\n", button_id); 00894 00895 /* special case: triggered only after enable button disables selected button */ 00896 if (button_id & 0x10000) { 00897 button_id &= 0xffff; 00898 _select_button(gc, button_id); 00899 GC_TRACE("_update_selected_button() -> #%d [last enabled]\n", button_id); 00900 return; 00901 } 00902 00903 if (button_id == 0xffff) { 00904 button_id = _find_selected_button_id(gc); 00905 _select_button(gc, button_id); 00906 } 00907 } 00908 00909 static int _mouse_move(GRAPHICS_CONTROLLER *gc, unsigned x, unsigned y, GC_NAV_CMDS *cmds) 00910 { 00911 PG_DISPLAY_SET *s = gc->igs; 00912 BD_IG_PAGE *page = NULL; 00913 unsigned page_id = bd_psr_read(gc->regs, PSR_MENU_PAGE_ID); 00914 unsigned cur_btn_id = bd_psr_read(gc->regs, PSR_SELECTED_BUTTON_ID); 00915 unsigned new_btn_id = 0xffff; 00916 unsigned ii; 00917 00918 gc->valid_mouse_position = 0; 00919 00920 if (!gc->ig_drawn) { 00921 GC_TRACE("_mouse_move(): menu not visible\n"); 00922 return -1; 00923 } 00924 00925 page = _find_page(&s->ics->interactive_composition, page_id); 00926 if (!page) { 00927 GC_ERROR("_mouse_move(): unknown page #%d (have %d pages)\n", 00928 page_id, s->ics->interactive_composition.num_pages); 00929 return -1; 00930 } 00931 00932 for (ii = 0; ii < page->num_bogs; ii++) { 00933 BD_IG_BOG *bog = &page->bog[ii]; 00934 unsigned valid_id = gc->bog_data[ii].enabled_button; 00935 BD_IG_BUTTON *button = _find_button_bog(bog, valid_id); 00936 00937 if (!button) 00938 continue; 00939 00940 if (x < button->x_pos || y < button->y_pos) 00941 continue; 00942 00943 /* Check for SELECTED state object (button that can be selected) */ 00944 BD_PG_OBJECT *object = _find_object_for_button(s, button, BTN_SELECTED, NULL); 00945 if (!object) 00946 continue; 00947 00948 if (x >= button->x_pos + object->width || y >= button->y_pos + object->height) 00949 continue; 00950 00951 /* mouse is over button */ 00952 gc->valid_mouse_position = 1; 00953 00954 /* is button already selected? */ 00955 if (button->id == cur_btn_id) { 00956 return 1; 00957 } 00958 00959 new_btn_id = button->id; 00960 break; 00961 } 00962 00963 if (new_btn_id != 0xffff) { 00964 _select_button(gc, new_btn_id); 00965 00966 _render_page(gc, -1, cmds); 00967 } 00968 00969 return gc->valid_mouse_position; 00970 } 00971 00972 int gc_run(GRAPHICS_CONTROLLER *gc, gc_ctrl_e ctrl, uint32_t param, GC_NAV_CMDS *cmds) 00973 { 00974 int result = -1; 00975 00976 if (cmds) { 00977 cmds->num_nav_cmds = 0; 00978 cmds->nav_cmds = NULL; 00979 cmds->sound_id_ref = -1; 00980 } 00981 00982 if (!gc) { 00983 GC_TRACE("gc_run(): no graphics controller\n"); 00984 return result; 00985 } 00986 00987 bd_mutex_lock(&gc->mutex); 00988 00989 /* always accept reset */ 00990 switch (ctrl) { 00991 case GC_CTRL_RESET: 00992 _gc_reset(gc); 00993 00994 bd_mutex_unlock(&gc->mutex); 00995 return 0; 00996 00997 default:; 00998 } 00999 01000 /* other operations require complete display set */ 01001 if (!gc->igs || !gc->igs->ics || !gc->igs->complete) { 01002 GC_TRACE("gc_run(): no interactive composition\n"); 01003 bd_mutex_unlock(&gc->mutex); 01004 return result; 01005 } 01006 01007 switch (ctrl) { 01008 01009 case GC_CTRL_SET_BUTTON_PAGE: 01010 _set_button_page(gc, param); 01011 break; 01012 01013 case GC_CTRL_VK_KEY: 01014 if (param != BD_VK_POPUP) { 01015 result = _user_input(gc, param, cmds); 01016 break; 01017 } 01018 param = !gc->popup_visible; 01019 /* fall thru (BD_VK_POPUP) */ 01020 01021 case GC_CTRL_POPUP: 01022 if (gc->igs->ics->interactive_composition.ui_model != IG_UI_MODEL_POPUP) { 01023 /* not pop-up menu */ 01024 break; 01025 } 01026 01027 gc->popup_visible = !!param; 01028 01029 if (gc->popup_visible) { 01030 _select_page(gc, 0); 01031 } 01032 01033 /* fall thru */ 01034 01035 case GC_CTRL_NOP: 01036 _render_page(gc, 0xffff, cmds); 01037 break; 01038 01039 case GC_CTRL_IG_END: 01040 _update_selected_button(gc); 01041 _render_page(gc, 0xffff, cmds); 01042 break; 01043 01044 case GC_CTRL_ENABLE_BUTTON: 01045 _enable_button(gc, param, 1); 01046 break; 01047 01048 case GC_CTRL_DISABLE_BUTTON: 01049 _enable_button(gc, param, 0); 01050 break; 01051 01052 case GC_CTRL_MOUSE_MOVE: 01053 result = _mouse_move(gc, param >> 16, param & 0xffff, cmds); 01054 break; 01055 01056 case GC_CTRL_RESET: 01057 /* already handled */ 01058 break; 01059 } 01060 01061 bd_mutex_unlock(&gc->mutex); 01062 01063 return result; 01064 }
1.7.6.1