/* * This file is part of the Advance project. * * Copyright (C) 1999, 2000, 2001, 2002, 2003 Andrea Mazzoleni * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "portable.h" #include "draw.h" #include "advance.h" /***************************************************************************/ /* Common variable */ /* Sound enabled */ int the_sound_flag = 1; /* Default video mode */ adv_mode the_default_mode; /* Default video mode set */ int the_default_mode_flag = 0; /***************************************************************************/ /* Video crtc container extension */ adv_crtc* crtc_container_pos(adv_crtc_container* vmc, unsigned pos) { adv_crtc_container_iterator i; crtc_container_iterator_begin(&i, vmc); while (pos && !crtc_container_iterator_is_end(&i)) { --pos; crtc_container_iterator_next(&i); } if (crtc_container_iterator_is_end(&i)) return 0; else return crtc_container_iterator_get(&i); } unsigned crtc_container_max(adv_crtc_container* vmc) { unsigned pos = 0; adv_crtc_container_iterator i; crtc_container_iterator_begin(&i, vmc); while (!crtc_container_iterator_is_end(&i)) { ++pos; crtc_container_iterator_next(&i); } return pos; } /***************************************************************************/ /* Sound */ void sound_error(void) { if (the_sound_flag) { target_sound_error(); } } void sound_warn(void) { if (the_sound_flag) { target_sound_warn(); } } void sound_signal(void) { if (the_sound_flag) { target_sound_signal(); } } /***************************************************************************/ /* Text output */ unsigned text_size_x(void) { return video_size_x() / video_font_size_x(); } unsigned text_size_y(void) { return video_size_y() / video_font_size_y(); } void text_clear(void) { unsigned x, y; for(x=0;xhde * a->vde; unsigned bs = b->hde * b->vde; int ad = abs(as - 640*480); int bd = abs(bs - 640*480); if (ad > bd) return -1; if (ad < bd) return 1; return 0; } static int text_default_set(adv_crtc_container* cc, adv_monitor* monitor) { adv_crtc_container_iterator i; log_std(("text: selecting text mode\n")); /* search for the default mode */ if (cc && monitor && !the_default_mode_flag) { for(crtc_container_iterator_begin(&i, cc);!crtc_container_iterator_is_end(&i);crtc_container_iterator_next(&i)) { const adv_crtc* crtc = crtc_container_iterator_get(&i); adv_mode mode; if (strcmp(crtc->name, DEFAULT_TEXT_MODE)==0) { if ((crtc_is_fake(crtc) || crtc_clock_check(monitor, crtc)) && video_mode_generate(&mode, crtc, MODE_FLAGS_INDEX_TEXT)==0) { log_std(("text: using specified %s mode\n", crtc->name)); the_default_mode = mode; the_default_mode_flag = 1; } } } } /* search the best mode in the list */ if (cc && monitor && !the_default_mode_flag) { adv_crtc default_crtc; for(crtc_container_iterator_begin(&i, cc);!crtc_container_iterator_is_end(&i);crtc_container_iterator_next(&i)) { const adv_crtc* crtc = crtc_container_iterator_get(&i); adv_mode mode; if ((crtc_is_fake(crtc) || crtc_clock_check(monitor, crtc)) && video_mode_generate(&mode, crtc, MODE_FLAGS_INDEX_TEXT)==0) { if (!the_default_mode_flag || text_crtc_compare(crtc, &default_crtc)>0) { log_std(("text: using mode %s from list\n", crtc->name)); the_default_mode = mode; default_crtc = *crtc; the_default_mode_flag = 1; } } } } /* add a fake text mode for the windowed modes */ if (!the_default_mode_flag) { if ((video_mode_generate_driver_flags(VIDEO_DRIVER_FLAGS_MODE_TEXT, VIDEO_DRIVER_FLAGS_OUTPUT_WINDOW)) != 0) { adv_crtc crtc; adv_mode mode; crtc_reset(&crtc); crtc_fake_set(&crtc, 640, 480); if (video_mode_generate(&mode, &crtc, MODE_FLAGS_INDEX_TEXT)==0) { log_std(("text: using generated mode\n")); the_default_mode = mode; the_default_mode_flag = 1; } } } /* use the current mode */ if (!the_default_mode_flag) { adv_mode mode; if (video_mode_grab(&mode) == 0 && mode_is_text(&mode)) { log_std(("text: using grabbed mode\n")); the_default_mode = mode; the_default_mode_flag = 1; } } if (!the_default_mode_flag) return 0; if (video_mode_set(&the_default_mode)!=0) return -1; return 0; } adv_error text_init(adv_crtc_container* cc, adv_monitor* monitor) { if (text_default_set(cc, monitor)!=0) { video_mode_restore(); target_err("Error initialing the default video mode.\n\r\"%s\"\n\r", error_get()); return -1; } if (the_default_mode_flag == 0) { video_mode_restore(); target_err("No text modes available for your hardware.\n\rPlease check your `device_video_p/h/vclock' options in the configuration file.\nEventually add a specific modeline named '" DEFAULT_TEXT_MODE "'\n\rand ensure that you have a text mode video driver compiled in.\n\rEnsure also to use the auto option for device_video.\n\r"); return -1; } return 0; } void text_reset(void) { inputb_disable(); if (video_mode_is_active()) video_mode_done(1); if (video_mode_set(&the_default_mode)!=0) { video_mode_restore(); target_err("Error initialing the default video mode\n\r"); exit(EXIT_FAILURE); } if (inputb_enable(0) != 0) { target_err("Error initialing the input mode\n\r"); exit(EXIT_FAILURE); } } void text_done(void) { video_mode_restore(); } void text_put(int x, int y, char c, int color) { if (y>=0 && y=0 && x> 7) | ((g >> 7) << 1) | ((b >> 7) << 2); } return 0; } void draw_char(int x, int y, char c, unsigned color) { if (video_is_graphics()) { int i, j; unsigned char* p = draw_font + 8*(unsigned)c; x *= DRAW_FONTX; y *= DRAW_FONTY; for(i=0;i0) { text_put(x, y, c, color); --dx; ++x; } } void draw_text_fillrect(int x, int y, char c, int dx, int dy, unsigned color) { while (dy-->0) { draw_text_fill(x, y++, c, dx, color); } } void draw_text_left(int x, int y, int dx, const char* s, unsigned color) { int len = strlen(s); int i; for(i=0;i dx) len = dx; pre = (dx - len + 1) / 2; post = dx - pre - len; draw_text_fill(x, y, ' ', pre, color); draw_text_left(x+pre, y, len, s, color); draw_text_fill(x+pre+len, y, ' ', post, color); } unsigned draw_text_string(int x, int y, const char* s, unsigned color) { int len = strlen(s); if (x + len > text_size_x()) len = text_size_x() - x; draw_text_left(x, y, len, s, color); return len; } int draw_text_para(int x, int y, int dx, int dy, const char* s, unsigned color) { int iy = 0; int ix = 0; int needspace = 0; while (*s && iy<=dy) { unsigned l = strcspn(s, " \n"); if (needspace) { if (ixdx) { draw_text_fill(x+ix, y+iy, ' ', dx-ix, color); ++iy; ix = 0; needspace = 0; } if (iy<=dy) { draw_text_left(x+ix, y+iy, l, s, color); ix += l; s += l; if (*s==' ') { ++s; needspace = 1; } else if (*s=='\n') { draw_text_fill(x+ix, y+iy, ' ', dx-ix, color); ++s; ++iy; ix = 0; needspace = 0; } } } if (iy<=dy && ix maxlen) { s[maxlen] = 0; } while (1) { int userkey; int len = strlen(s); draw_text_string(x, y, s, color); draw_text_fill(x+len, y, ' ', dx-len, color); video_wait_vsync(); target_idle(); os_poll(); userkey = inputb_get(); switch (userkey) { case INPUTB_BACKSPACE : case INPUTB_DEL : if (len) { s[len-1] = 0; } break; case INPUTB_ENTER : case INPUTB_ESC : return userkey; default: if (len < maxlen) { if (userkey>=32 && userkey<=126) { s[len] = userkey; s[len+1] = 0; } } } } } /* Set the default color palette */ void draw_graphics_palette(void) { if (video_index() == MODE_FLAGS_INDEX_PALETTE8) { video_index_packed_to_rgb(0); } } static void draw_graphics_ellipse(int xc, int yc, int a0, int b0, unsigned color) { int x = 0; int y = b0; int a = a0; int b = b0; int as = a*a; int as2 = 2*as; int bs = b*b; int bs2 = 2*bs; int d = bs - as*b + as/4; int dx = 0; int dy = as2 * b; while (dx0) { --y; dy -= as2; d -= dy; } ++x; dx += bs2; d += bs + dx; } d += (3*(as-bs)/2 - (dx+dy)) / 2; while (y>=0) { video_put_pixel(xc+x, yc+y, color); video_put_pixel(xc-x, yc+y, color); video_put_pixel(xc+x, yc-y, color); video_put_pixel(xc-x, yc-y, color); if (d<0) { ++x; dx += bs2; d += dx; } --y; dy -= as2; d += as - dy; } } /* Draw the animation screen */ void draw_graphics_animate(int s_x, int s_y, int s_dx, int s_dy, unsigned counter, int do_clear) { if (video_is_graphics()) { adv_pixel c; int dx = s_dx / (4*8); int dy = s_dy / (3*8); int x = counter % ((s_dx - dx) * 2); int y = counter % ((s_dy - dy) * 2); if (x >= (s_dx - dx)) x = (s_dx - dx) * 2 - x; if (y >= (s_dy - dy)) y = (s_dy - dy) * 2 - y; assert(x + dx <= s_dx); assert(y + dy <= s_dy); /* draw bar */ if (do_clear) video_pixel_make(&c, 0, 0, 0); else video_pixel_make(&c, 255, 255, 255); video_clear(s_x + x, s_y, dx, s_dy, c); video_clear(s_x, s_y+y, s_dx, dy, c); } } void draw_graphics_clear(void) { if (video_is_graphics()) { video_clear(0, 0, video_size_x(), video_size_y(), 0); } } /* Draw a test calibration screen */ void draw_graphics_calib(int s_x, int s_y, int s_dx, int s_dy) { int i, j, k, l; draw_graphics_palette(); if (video_is_graphics()) { adv_pixel c; unsigned dx = s_dx*3/5; unsigned dy = s_dy*4/5; unsigned x = (s_dx-dx)/2; unsigned y = (s_dy-dy)/2; unsigned dyB = dy/3; unsigned dyM = dyB/2; unsigned dyS = dyB/4; /* draw background */ video_pixel_make(&c, 128, 128, 128); video_clear(s_x, s_y, s_dx, s_dy, c); /* draw rows */ video_pixel_make(&c, 255, 255, 255); for(i=0;i<15;++i) video_clear(s_x, s_y + s_dy*i/15+s_dy/30, s_dx, 1, c); /* draw columns */ for(i=0;i<20;++i) { unsigned rx = s_dx*i/20+s_dx/40; for(j=0;j i / (dx / 5)) { l = !l; k = 0; } ++k; if (l) video_pixel_make(&c, 0, 0, 0); else video_pixel_make(&c, 255, 255, 255); for(j=0;j= mac) draw_text_fill(x, y+i, ' ', dx, COLOR_NORMAL); else print(x, y+i, dx, data, base+i, pos == i); } video_wait_vsync(); target_idle(); os_poll(); key = inputb_get(); switch (key) { case INPUTB_SPACE: done = 1; break; case INPUTB_ENTER: done = 1; break; case INPUTB_ESC: done = 1; break; case INPUTB_DOWN : if (base + pos + 1 < mac) { if (pos + 1 < dy) ++pos; else ++base; } dir = 1; break; case INPUTB_PGDN : for(i=0;i 0) { if (pos > 0) --pos; else --base; } dir = 0; break; case INPUTB_PGUP : for(i=0;i 0) { if (pos > 0) --pos; else --base; } dir = 0; break; } while (separator && separator(data, base+pos)) { if (dir) { if (base + pos + 1 < mac) { if (pos + 1 < dy) ++pos; else ++base; } else dir = !dir; } else { if (base + pos > 0) { if (pos > 0) --pos; else --base; } else dir = !dir; } } } if (abase && apos) { *abase = base; *apos = pos; } if (akey) { *akey = key; } return key != INPUTB_ESC ? base + pos : -1; }