00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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;
00045 uint16_t x, y, w, h;
00046 int animate_indx;
00047 } BOG_DATA;
00048
00049 struct graphics_controller_s {
00050
00051 BD_REGISTERS *regs;
00052
00053 BD_MUTEX mutex;
00054
00055
00056 void *overlay_proc_handle;
00057 void (*overlay_proc)(void *, const struct bd_overlay_s * const);
00058
00059
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
00068 PG_DISPLAY_SET *pgs;
00069 PG_DISPLAY_SET *igs;
00070
00071
00072 GRAPHICS_PROCESSOR *pgp;
00073 GRAPHICS_PROCESSOR *igp;
00074 };
00075
00076
00077
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
00189 bog_data->animate_indx = -1;
00190 }
00191
00192 } else {
00193
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
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
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
00236
00237
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
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
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
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
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
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
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
00443 bd_mutex_lock(&gc->mutex);
00444 _restore_page_state(gc);
00445 bd_mutex_unlock(&gc->mutex);
00446 return;
00447
00448 default:
00449
00450 return;
00451 }
00452 }
00453 }
00454
00455
00456
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
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
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
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
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
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
00659
00660
00661 #define VK_IS_NUMERIC(vk) ( 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
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
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
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
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
00783
00784 if (!page_flag && !button_flag) {
00785 return;
00786 }
00787
00788 if (page_flag) {
00789
00790
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
00799 if (!page) {
00800 GC_TRACE(" page is invalid\n");
00801 return;
00802 }
00803
00804
00805
00806 _select_page(gc, page_id);
00807
00808 } else {
00809
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
00821 button = _find_button_page(page, button_id, &bog_idx);
00822
00823 if (!page_flag) {
00824 if (!button) {
00825
00826 GC_TRACE(" button is invalid\n");
00827 return;
00828 }
00829 if (button_id == bd_psr_read(gc->regs, PSR_SELECTED_BUTTON_ID)) {
00830
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
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
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
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
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
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
00952 gc->valid_mouse_position = 1;
00953
00954
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
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
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
01020
01021 case GC_CTRL_POPUP:
01022 if (gc->igs->ics->interactive_composition.ui_model != IG_UI_MODEL_POPUP) {
01023
01024 break;
01025 }
01026
01027 gc->popup_visible = !!param;
01028
01029 if (gc->popup_visible) {
01030 _select_page(gc, 0);
01031 }
01032
01033
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
01058 break;
01059 }
01060
01061 bd_mutex_unlock(&gc->mutex);
01062
01063 return result;
01064 }