diff --git a/HISTORY b/HISTORY index 9ac74d4..b770828 100644 --- a/HISTORY +++ b/HISTORY @@ -1,3 +1,20 @@ +2000/10/5(木) + +wonx-a07 公開 + +WWLCDPanel にビットマップデータを2枚持たせ,一度描画したビットマップは +描画しないように修正.Xサーバの負荷を減らした. +(WWLCDPanel関連と,XDisplay.c の XDisplay_DrawLCDWindow() を改良) +(XDisplay.c の XDisplay_DrawLCDWindow() には,無駄な malloc() があるので, + そのうち改良が必要) + +wonx-a05 と wonx-a06 の WWDisplay.c (WWDisplay_DrawScreen()) の +両方を試した結果,wonx-a05 のほうが高速だったので,wonx-a05 のほうを +使用することにした. + + + + 2000/10/4(水) wonx-a06 公開 diff --git a/Makefile b/Makefile index dfdd62d..d7c953e 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,8 @@ XINCLUDEDIR = /usr/X11R6/include INCLUDEDIR = . XLIBDIR = /usr/X11R6/lib -VERSION = Wonx-a06 -PKGNAME = wonx-a06 +VERSION = Wonx-a07 +PKGNAME = wonx-a07 OBJS = WWCharacter.o WWColorMap.o WWDisplay.o WWLCDPanel.o WWPalette.o WWScreen.o WWSprite.o WonxDisplay.o XDisplay.o bank.o comm.o disp.o text.o key.o sound.o system.o timer.o etc.o wonx.o diff --git a/WWDisplay.c b/WWDisplay.c index b552641..5791fc4 100644 --- a/WWDisplay.c +++ b/WWDisplay.c @@ -195,14 +195,22 @@ WWDisplay WWDisplay_Destroy(WWDisplay display) /* LCDパネルの描画 */ /*===========================================================================*/ -static int WWDisplay_DrawScreen(WWDisplay display, WWScreen screen, - int lcd_x, int lcd_y) +static int WWDisplay_DrawScreen(WWDisplay display, WWScreen screen) { - int pixel; - int px, py; - int sx, sy, ex, ey; + WWLCDPanel lcd_panel; + int lcd_panel_width; + int lcd_panel_height; - if (!WWScreen_GetEnable(screen)) return (-1); + int pixel; + int x, y, px, py; + int sx, sy, ex, ey; + int mode; + + if (!WWScreen_GetEnable(screen)) return (0); + + lcd_panel = WWDisplay_GetLCDPanel(display); + lcd_panel_width = WWLCDPanel_GetWidth( lcd_panel); + lcd_panel_height = WWLCDPanel_GetHeight(lcd_panel); if ( (WWScreen_GetMode(screen) == WWSCREEN_INSIDE_ONLY) || (WWScreen_GetMode(screen) == WWSCREEN_OUTSIDE_ONLY) ) { @@ -229,35 +237,50 @@ static int WWDisplay_DrawScreen(WWDisplay display, WWScreen screen, #endif } - switch (WWScreen_GetMode(screen)) { - case WWSCREEN_INSIDE_ONLY: - if ( (lcd_x < sx) || (lcd_x > ex) || (lcd_y < sy) || (lcd_y > ey) ) - return (-1); - break; - case WWSCREEN_OUTSIDE_ONLY: - if ( !( (lcd_x < sx) || (lcd_x > ex) || (lcd_y < sy) || (lcd_y > ey) ) ) - return (-1); - break; + mode = WWScreen_GetMode(screen); + + /* 以下はホットスポットになるので,そのうちループアンローリング */ + /* したほうがいいかも */ + + for (y = 0; y < lcd_panel_height; y++) { + + if (mode == WWSCREEN_INSIDE_ONLY) { + if (y > ey) { break; } + if (y < sy) { y = sy - 1; continue; } + } + + py = y + WWScreen_GetRollY(screen); + + for (x = 0; x < lcd_panel_width; x++) { + + if (mode == WWSCREEN_INSIDE_ONLY) { + if (x > ex) { x = lcd_panel_width - 1; continue; } + if (x < sx) { x = sx - 1; continue; } + } else if (mode == WWSCREEN_OUTSIDE_ONLY) { + if ( (x >= sx) && (x <= ex) && (y >= sy) && (y <= ey) ) { + x = ex; + continue; + } + } + + px = x + WWScreen_GetRollX(screen); + + pixel = WWScreen_GetPixel(screen, px, py); + + /* 透明色の場合 */ + if (pixel == -1) continue; + + pixel = WWColorMap_GetLCDColor(WWDisplay_GetColorMap(display), pixel); + WWLCDPanel_SetPixel(lcd_panel, x, y, pixel); + } } - px = lcd_x + WWScreen_GetRollX(screen); - py = lcd_y + WWScreen_GetRollY(screen); - - pixel = WWScreen_GetPixel(screen, px, py); - - /* 透明色の場合 */ - if (pixel == -1) return (-1); - - pixel = WWColorMap_GetLCDColor(WWDisplay_GetColorMap(display), pixel); - WWLCDPanel_SetPixel(WWDisplay_GetLCDPanel(display), lcd_x, lcd_y, pixel); - - return (pixel); + return (0); } -static int WWDisplay_DrawSprite(WWDisplay display, WWSprite sprite, - int lcd_x, int lcd_y) +static int WWDisplay_DrawSprite(WWDisplay display, WWSprite sprite) { - int x, y, sprite_x, sprite_y; + int x, y, lcd_x, lcd_y; int sx, sy, ex, ey; int pixel, outside; @@ -273,38 +296,35 @@ static int WWDisplay_DrawSprite(WWDisplay display, WWSprite sprite, ey = sy + WWDisplay_GetSpriteWindowHeight(display); #endif - sprite_x = WWSprite_GetX(sprite); - sprite_y = WWSprite_GetY(sprite); + for (y = 0; y < 8; y++) { + for (x = 0; x < 8; x++) { + pixel = WWSprite_GetPixel(sprite, x, y); - if ( (lcd_x < sprite_x) || (lcd_x > sprite_x + 7) || - (lcd_y < sprite_y) || (lcd_y > sprite_y + 7) ) - return (-1); + /* 透明色の場合 */ + if (pixel == -1) continue; - x = lcd_x - sprite_x; - y = lcd_y - sprite_y; + lcd_x = WWSprite_GetX(sprite) + x; + lcd_y = WWSprite_GetY(sprite) + y; - pixel = WWSprite_GetPixel(sprite, x, y); + if (WWDisplay_GetSpriteWindowEnable(display)) { + if ( (lcd_x < sx) || (lcd_y < sy) || (lcd_x > ex) || (lcd_y > ey) ) + outside = 1; + else + outside = 0; - /* 透明色の場合 */ - if (pixel == -1) return (-1); + if (WWSprite_GetClipping(sprite)) { /* ウインドウの外側部分を表示 */ + if (!outside) continue; + } else { /* ウインドウの内側部分を表示 */ + if (outside) continue; + } + } - if (WWDisplay_GetSpriteWindowEnable(display)) { - if ( (lcd_x < sx) || (lcd_y < sy) || (lcd_x > ex) || (lcd_y > ey) ) - outside = 1; - else - outside = 0; - - if (WWSprite_GetClipping(sprite)) { /* ウインドウの外側部分を表示 */ - if (!outside) return (-1); - } else { /* ウインドウの内側部分を表示 */ - if (outside) return (-1); + pixel = WWColorMap_GetLCDColor(WWDisplay_GetColorMap(display), pixel); + WWLCDPanel_SetPixel(WWDisplay_GetLCDPanel(display), lcd_x, lcd_y, pixel); } } - pixel = WWColorMap_GetLCDColor(WWDisplay_GetColorMap(display), pixel); - WWLCDPanel_SetPixel(WWDisplay_GetLCDPanel(display), lcd_x, lcd_y, pixel); - - return (pixel); + return (0); } int WWDisplay_DrawLCDPanel(WWDisplay display) @@ -317,7 +337,6 @@ int WWDisplay_DrawLCDPanel(WWDisplay display) WWColorMap color_map; int border; WWSprite sprite; - int ret; lcd_panel = WWDisplay_GetLCDPanel(display); lcd_panel_width = WWLCDPanel_GetWidth( lcd_panel); @@ -325,55 +344,44 @@ int WWDisplay_DrawLCDPanel(WWDisplay display) color_map = WWDisplay_GetColorMap(display); border = WWDisplay_GetBorder(display); + /* ボーダーカラーで埋める */ for (x = 0; x < lcd_panel_width; x++) { for (y = 0; y < lcd_panel_height; y++) { - - /* スクリーン2より優先のスプライトの描画 */ - /* 重なった場合は,番号の若いものが手前に表示される */ - ret = -1; - if (WWDisplay_GetSpriteEnable(display)) { - for (i = 0; i < WWDisplay_GetSpriteCount(display); i++) { - sprite = WWDisplay_GetSprite(display, - i + WWDisplay_GetSpriteStart(display)); - if (WWSprite_GetPriority(sprite)) { - ret = WWDisplay_DrawSprite(display, sprite, x, y); - if (ret != -1) break; - } - } - } - if (ret != -1) continue; - - /* スクリーン2の描画 */ - ret = WWDisplay_DrawScreen(display, WWDisplay_GetScreen(display, 1), - x, y); - if (ret != -1) continue; - - /* スクリーン2より優先でないスプライトの描画 */ - /* 重なった場合は,番号の若いものが手前に表示される */ - ret = -1; - if (WWDisplay_GetSpriteEnable(display)) { - for (i = 0; i < WWDisplay_GetSpriteCount(display); i++) { - sprite = WWDisplay_GetSprite(display, - i + WWDisplay_GetSpriteStart(display)); - if (!WWSprite_GetPriority(sprite)) { - ret = WWDisplay_DrawSprite(display, sprite, x, y); - if (ret != -1) break; - } - } - } - if (ret != -1) continue; - - /* スクリーン1の描画 */ - ret = WWDisplay_DrawScreen(display, WWDisplay_GetScreen(display, 0), - x, y); - if (ret != -1) continue; - - /* ボーダーカラーの描画 */ WWLCDPanel_SetPixel(lcd_panel, x, y, WWColorMap_GetLCDColor(color_map, border)); } } + /* スクリーン1描画 */ + WWDisplay_DrawScreen(display, WWDisplay_GetScreen(display, 0)); + + /* スプライト描画(スクリーン2より優先でないもの) */ + /* 重なった場合は,番号の若いものが手前に表示される */ + if (WWDisplay_GetSpriteEnable(display)) { + for (i = WWDisplay_GetSpriteCount(display) - 1; i >= 0; i--) { + sprite = WWDisplay_GetSprite(display, + i + WWDisplay_GetSpriteStart(display)); + if (!WWSprite_GetPriority(sprite)) { + WWDisplay_DrawSprite(display, sprite); + } + } + } + + /* スクリーン2描画 */ + WWDisplay_DrawScreen(display, WWDisplay_GetScreen(display, 1)); + + /* スプライト描画(スクリーン2より優先なもの) */ + /* 重なった場合は,番号の若いものが手前に表示される */ + if (WWDisplay_GetSpriteEnable(display)) { + for (i = WWDisplay_GetSpriteCount(display) - 1; i >= 0; i--) { + sprite = WWDisplay_GetSprite(display, + i + WWDisplay_GetSpriteStart(display)); + if (WWSprite_GetPriority(sprite)) { + WWDisplay_DrawSprite(display, sprite); + } + } + } + return (0); } diff --git a/WWLCDPanel.c b/WWLCDPanel.c index b3e0090..1b89954 100644 --- a/WWLCDPanel.c +++ b/WWLCDPanel.c @@ -13,52 +13,95 @@ int WWLCDPanel_GetHeight(WWLCDPanel p) { return (p->height); } int WWLCDPanel_SetWidth( WWLCDPanel p, int n) { return (p->width = n); } int WWLCDPanel_SetHeight(WWLCDPanel p, int n) { return (p->height = n); } -unsigned char * WWLCDPanel_GetPixelMap(WWLCDPanel p) { return (p->pixel); } +int WWLCDPanel_ResetCurrent(WWLCDPanel p) +{ + return (p->current = 0); +} + +int WWLCDPanel_ReverseCurrent(WWLCDPanel p) +{ + return (p->current = 1 - p->current); +} + +int WWLCDPanel_ResetAllDraw(WWLCDPanel p) { return (p->all_draw = 0); } +int WWLCDPanel_SetAllDraw(WWLCDPanel p) { return (p->all_draw = 1); } +int WWLCDPanel_IsAllDraw(WWLCDPanel p) { return (p->all_draw); } + +unsigned char * WWLCDPanel_GetPixelMap(WWLCDPanel p) +{ + return (p->pixel[p->current]); +} /* LCDは1ピクセル16色(4ビット必要) */ -int WWLCDPanel_GetPixel(WWLCDPanel lcd_panel, int x, int y) +static int WWLCDPanel_GetPixelByCurrent(WWLCDPanel lcd_panel, int current, + int x, int y) { unsigned char pixel; - if ( (x < 0) || (x > WWLCDPanel_GetWidth(lcd_panel) - 1) || + if ( (x < 0) || (x > WWLCDPanel_GetWidth( lcd_panel) - 1) || (y < 0) || (y > WWLCDPanel_GetHeight(lcd_panel) - 1) ) return (-1); - pixel = lcd_panel->pixel[y * WWLCDPanel_GetWidth(lcd_panel) + x]; + pixel = lcd_panel->pixel[current][y * WWLCDPanel_GetWidth(lcd_panel) + x]; pixel &= 0x0f; return ((int)pixel); } +static int WWLCDPanel_GetOldPixel(WWLCDPanel lcd_panel, int x, int y) +{ + return (WWLCDPanel_GetPixelByCurrent(lcd_panel, 1 - lcd_panel->current, x, y)); +} + +int WWLCDPanel_GetPixel(WWLCDPanel lcd_panel, int x, int y) +{ + return (WWLCDPanel_GetPixelByCurrent(lcd_panel, lcd_panel->current, x, y)); +} + int WWLCDPanel_SetPixel(WWLCDPanel lcd_panel, int x, int y, int pixel) { unsigned char p; int n; - if ( (x < 0) || (x > WWLCDPanel_GetWidth(lcd_panel) - 1) || + if ( (x < 0) || (x > WWLCDPanel_GetWidth( lcd_panel) - 1) || (y < 0) || (y > WWLCDPanel_GetHeight(lcd_panel) - 1) ) return (-1); p = ((unsigned char)pixel) & 0x0f; n = y * WWLCDPanel_GetWidth(lcd_panel) + x; - lcd_panel->pixel[n] = p; + lcd_panel->pixel[lcd_panel->current][n] = p; return (pixel); } +int WWLCDPanel_IsPixelChanged(WWLCDPanel lcd_panel, int x, int y) +{ + int old_pixel; + int current_pixel; + + if (WWLCDPanel_IsAllDraw(lcd_panel)) return (1); + old_pixel = WWLCDPanel_GetOldPixel(lcd_panel, x, y); + current_pixel = WWLCDPanel_GetPixel(lcd_panel, x, y); + + return (!(old_pixel == current_pixel)); +} + WWLCDPanel WWLCDPanel_Create(int width, int height) { WWLCDPanel lcd_panel; - int x, y; + int x, y, i; lcd_panel = (WWLCDPanel)malloc(sizeof(_WWLCDPanel)); if (lcd_panel == NULL) Error("WWLCDPanel_Create", "Cannot allocate memory."); WWLCDPanel_SetWidth( lcd_panel, width); WWLCDPanel_SetHeight(lcd_panel, height); - lcd_panel->pixel = - (unsigned char *)malloc(sizeof(unsigned char) * - WWLCDPanel_GetWidth(lcd_panel) * - WWLCDPanel_GetHeight(lcd_panel)); + + for (i = 0; i < 2; i++) { + lcd_panel->pixel[i] = + (unsigned char *)malloc(sizeof(unsigned char) * + WWLCDPanel_GetWidth(lcd_panel) * + WWLCDPanel_GetHeight(lcd_panel)); + } for (y = 0; y < lcd_panel->height; y++) { for (x = 0; x < lcd_panel->width / 2; x++) { @@ -66,13 +109,19 @@ WWLCDPanel WWLCDPanel_Create(int width, int height) } } + WWLCDPanel_ResetCurrent(lcd_panel); + WWLCDPanel_SetAllDraw(lcd_panel); /* 初回は全画面を描画する */ + return (lcd_panel); } WWLCDPanel WWLCDPanel_Destroy(WWLCDPanel lcd_panel) { + int i; if (lcd_panel == NULL) return (NULL); - if (lcd_panel->pixel) free(lcd_panel->pixel); + for (i = 0; i < 2; i++) { + if (lcd_panel->pixel[i]) free(lcd_panel->pixel[i]); + } free(lcd_panel); return (NULL); } diff --git a/WWLCDPanel.h b/WWLCDPanel.h index 3319143..d8250c9 100644 --- a/WWLCDPanel.h +++ b/WWLCDPanel.h @@ -21,9 +21,17 @@ int WWLCDPanel_GetWidth( WWLCDPanel p); int WWLCDPanel_GetHeight(WWLCDPanel p); int WWLCDPanel_SetWidth( WWLCDPanel p, int n); int WWLCDPanel_SetHeight(WWLCDPanel p, int n); + +int WWLCDPanel_ResetCurrent(WWLCDPanel p); +int WWLCDPanel_ReverseCurrent(WWLCDPanel p); +int WWLCDPanel_ResetAllDraw(WWLCDPanel p); +int WWLCDPanel_SetAllDraw(WWLCDPanel p); +int WWLCDPanel_IsAllDraw(WWLCDPanel p); + unsigned char * WWLCDPanel_GetPixelMap(WWLCDPanel p); int WWLCDPanel_GetPixel(WWLCDPanel lcd_panel, int x, int y); int WWLCDPanel_SetPixel(WWLCDPanel lcd_panel, int x, int y, int pixel); +int WWLCDPanel_IsPixelChanged(WWLCDPanel lcd_panel, int x, int y); WWLCDPanel WWLCDPanel_Create(int width, int height); WWLCDPanel WWLCDPanel_Destroy(WWLCDPanel lcd_panel); diff --git a/WWLCDPanelP.h b/WWLCDPanelP.h index b0365a4..dd34b71 100644 --- a/WWLCDPanelP.h +++ b/WWLCDPanelP.h @@ -14,8 +14,19 @@ typedef struct _WWLCDPanel { int width; int height; - /* 16色のカラー情報.1バイトで2ピクセル分の情報を持つ */ - unsigned char * pixel; + + /* Xサーバの負荷を減らすため,ビットマップを2枚持ち, */ + /* 前回と同じ部分は書き換えないようにする. */ + /* pixel[current] が現在描画中のビットマップになる. */ + /* pixel[1 - current] が前回のビットマップになる. */ + int current; + + /* all_draw == 1 のときは,前回分が無いので, */ + /* 全部描画することを示す. */ + int all_draw; + + /* 16色のカラー情報.1バイトで1ピクセル分の情報を持つ */ + unsigned char * pixel[2]; } _WWLCDPanel; /*****************************************************************************/ diff --git a/XDisplay.c b/XDisplay.c index ce26588..8fef3de 100644 --- a/XDisplay.c +++ b/XDisplay.c @@ -371,6 +371,10 @@ int XDisplay_DrawLCDWindow(XDisplay x_display, WWLCDPanel ww_lcd_panel) num = WWLCDPanel_GetHeight(ww_lcd_panel) * WWLCDPanel_GetWidth(ww_lcd_panel) / 2; + /* + * この malloc() は,実際にはメモリはほとんど使用されていないので, + * そのうちなんとかする必要がある + */ for (pixel = 0; pixel < 16; pixel++) { n[pixel] = 0; rectangles[pixel] = (XRectangle *)malloc(sizeof(XRectangle) * num); @@ -387,6 +391,9 @@ int XDisplay_DrawLCDWindow(XDisplay x_display, WWLCDPanel ww_lcd_panel) py = (y * x_display->height) / ww_lcd_height; ph = (y+1) * x_display->height / ww_lcd_height- py; for (x = 0; x < ww_lcd_width; x++) { + if (!WWLCDPanel_IsPixelChanged(ww_lcd_panel, x, y)) { + continue; + } pixel = WWLCDPanel_GetPixel(ww_lcd_panel, x, y); px = (x * x_display->width ) / ww_lcd_width; rectangles[pixel][n[pixel]].x = px; @@ -398,7 +405,8 @@ int XDisplay_DrawLCDWindow(XDisplay x_display, WWLCDPanel ww_lcd_panel) /* 隣接してる同色のピクセルは,極力いっしょに描画する */ x++; while ( (x < ww_lcd_width) && - (pixel == WWLCDPanel_GetPixel(ww_lcd_panel, x, y)) ) { + (pixel == WWLCDPanel_GetPixel(ww_lcd_panel, x, y)) && + (WWLCDPanel_IsPixelChanged(ww_lcd_panel, x, y)) ) { rectangles[pixel][n[pixel]].width = (x+1) * x_display->width / ww_lcd_width - px; x++; @@ -422,6 +430,9 @@ int XDisplay_DrawLCDWindow(XDisplay x_display, WWLCDPanel ww_lcd_panel) x_display->lcd_window, x_display->copy_gc, 0, 0, x_display->width, x_display->height, 0, 0); + WWLCDPanel_ResetAllDraw(ww_lcd_panel); + WWLCDPanel_ReverseCurrent(ww_lcd_panel); + XDisplay_Sync(x_display); for (pixel = 0; pixel < 16; pixel++) {