《作業系統30天》-合川秀實-學習日誌day11

MoLC發表於2019-02-03

這次的日誌就不把書上的東西照搬過來了,寫一點關於這個紙娃娃作業系統的理解。

一、新增一個視窗圖層有哪些步驟?(格式:文字說明+對應程式碼)

第一步:定義圖層包 (結構體SHTCTL),建立圖層(SHEET),建立緩衝區buf(地址)
在這裡插入圖片描述
第二步:初始化圖層
在這裡插入圖片描述
第三步:分配記憶體
在這裡插入圖片描述
第四步:初始化圖層背景(把圖層寫進顯示卡)+內容初始化(圖層內容填充)
在這裡插入圖片描述
第五步:設定圖層顯示位置的起始座標(X0,Y0)+設定圖層高度
在這裡插入圖片描述

二、教材202頁,為什麼滑鼠移動到最右邊後左邊會出現滑鼠圖案,為什麼右邊只有一個滑鼠,左邊卻有很多?

我們由上一天內容知道,圖層移動的時候會呼叫sheet_refreshsub()和sheet_slide這兩個函式:
在這裡插入圖片描述
對滑鼠的重新整理:
在這裡插入圖片描述
我們知道滑鼠的座標是經過修正的,所以傳入的old圖層的起始位置其實是在合理範圍內。
在這裡插入圖片描述
檢視refreshsub函式:
對我們有用的是最後的顯示部分,因為不管滑鼠在哪顯示,都用用到畫素點
在這裡插入圖片描述
在這裡插入圖片描述
如果按照書上的方法修改,根據畫素點公式(一維計算)會導致重新整理的畫素點往後偏移16位(相當於往右),所以在螢幕左邊會出現滑鼠。對重新整理old圖層來說,傳入的引數vx0=mx和vx1>xsize,對新圖層來說,也是vx0=mx和vx1>xize,而且老圖層和新圖層的vx1值是相同的,因為當我們把滑鼠放到最右邊的時候,傳入的mx都是同一個值,所以計算出的vx1也是同一個值(mx+16),這個時候兩次呼叫的bx1相同,會先重新整理一次老的,再重新整理一次新的,那還是在原來的位置,所以滑鼠只能在左邊的固定範圍內出現。重新整理的時候因為螢幕的背景是按照一樣的計算公式填充的,所以在邊界移動的時候會有痕跡保留,也就說old的值還存在背景中,背景圖層在重新整理的時候會把“遺留”下來的一起重新整理,可能是滑鼠的顏色,也可能是黑色,驗證我的說法:
在這裡插入圖片描述在這裡插入圖片描述
改正方法:在sheet_refreshsub函式裡面的迴圈重新整理之前,新增判斷
在這裡插入圖片描述

三、教材216頁,每個圖層的sid是如何設定的?具體數值等於多少?

Sid變數首次出現在sheet_refreshmap函式中,儲存的是每個圖層相對於sheets0的位置,作者給出的解釋是減法計算得出的(地址)圖層號碼,所以說實際上sid是一個地址,是sheet ID的縮寫,出現在函式中是這種形式:
在這裡插入圖片描述
影象形式:相當於一個圖層體包含的多個圖層每個圖層有固定的地址,用當前圖層的地址減去最下面圖層的地址就可以得出當前的sid號了
在這裡插入圖片描述
可以理解成圖層的標號1,2,3………

四、教材216-217頁,結合程式碼,解釋重新整理函式(sheet_refreshsub)的引數和實現邏輯。

Ctl是表示儲存圖層的結構體,座標值就是傳入大小(vx0,vy0)->(vx1,vy1),h0表示從h0層開始重新整理map,直到h1層。
實現邏輯:若h0=1,h1=3當繪製圖層1(sid)時,遍歷map,遇到1時繪製,否則不繪製;之後繪製圖層2,遍歷map,遇到2進行繪製;同理,圖層3也是。在count計數中,每一次計數後的畫面繪製中,只需要遍歷map,繪製計數視窗的圖層就可以了,消除了滑鼠閃爍。
在這裡插入圖片描述

void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1)
{
	int h, bx, by, vx, vy, bx0, by0, bx1, by1;
	unsigned char *buf, *vram = ctl->vram, *map = ctl->map, sid;
	struct SHEET *sht;
	/* 如果refresh的範圍超出了畫面則修正 */
	
	for (h = h0; h <= h1; h++) {
/*只重新整理h0-h1範圍內的圖層*/
		sht = ctl->sheets[h];
		buf = sht->buf;
		sid = sht - ctl->sheets0;
		/*計算每個圖層的sid,在下面的疊加部分進行重新整理*/
		/* 利用vx0~vy1對bx0~by1進行倒推*/
		for (by = by0; by < by1; by++) {
			vy = sht->vy0 + by;
			for (bx = bx0; bx < bx1; bx++) {
				vx = sht->vx0 + bx;
				if (map[vy * ctl->xsize + vx] == sid) {
			/* 判斷是否可以繪製(比如說當前圖層號碼為2,那麼只繪製2那層)*/
					vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx];
				}
			}
		}
	}
	return;
}

五、教材217頁,結合程式碼,解釋滑動函式(sheet_slide)的引數和實現邏輯,注意內部呼叫sheet_refreshmap和sheet_refreshsub時的傳參,特別是高度引數,為什麼這樣傳。

slide函式實現的是圖層的滑動,重新整理移動前的位置,再重新整理移動後的位置

void sheet_slide(struct SHEET *sht, int vx0, int vy0)
{
	struct SHTCTL *ctl = sht->ctl;
	int old_vx0 = sht->vx0, old_vy0 = sht->vy0;
	sht->vx0 = vx0;
	sht->vy0 = vy0;
/* old_vx0,old_vy0表示原來的圖層*/
/* vx0,vy0表示新的圖層*/

	if (sht->height >= 0) { /* 如果正在顯示,按照新圖層的資訊進行重新整理*/
		sheet_refreshmap(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0);
	/* 繪製原來圖層位置的新地圖,因為是原來的位置,圖層移走了,無法判斷圖層移動之後的情況,所有要從0開始重新整理 */

		sheet_refreshmap(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height);
/* 繪製新圖層位置的新地圖,新地圖只需要從當前的高度開始重新整理,下面的被覆蓋不用重新整理,只需要重新整理高度以上的 */
		sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0, sht->height - 1);
/* 原來位置的地圖發生了改變(重新整理),所以相應的我的圖層要根據地圖來重新整理 */
		sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height, sht->height);
/* 新的圖層地圖只是在新圖層的高度以上進行了重新整理,所以新高度的地圖已經繪製好了,直接按照地圖重新整理當前這一高度的圖層就可以了 */
	}
	return;
}

相關文章