java开发系统内核:实现窗口图形绘制API
2017-08-16 17:36
701 查看
更详细的讲解和代码调试演示过程,请参看视频
Linux kernel Hacker, 从零构建自己的内核
为了今后能在系统上开发出更复杂绚丽的图形窗口应用程序,我们需要让内核添加图形图像绘制的API,这样应用程序才可以通过API绘制足够丰富多彩的窗口应用。
任何复杂的图像,都是通过绘制相应的像素点形成的,因此要提供图形绘制API的话,提供画点API是必不可免的。为此,我们在系统内核中提供一个编号为11的API,它的作用是在窗口的指定位置绘制一个点,API的相关配置如下:
EDX = 11
EBX = 窗口句柄
ESI = 点的X坐标
EDI = 点的Y坐标
EAX= 点的颜色
在kernel_api中添加相应的实现代码:
在api_call.asm中添加对应的汇编代码:
然后我们在app.c中调用API,在一个窗口上绘制一个亮点:
上面代码编译,把系统加载运行后,效果如下:
在窗口的中央有一个小黄点。
我们再把画点功能增强一下,多画几个随机点:
代码中的rand()的作用是模拟生成随机数,上面的代码运行后,效果如下:
由于每次画一个点,我们总要刷新窗口,这么做会导致窗口绘制效率的低下,因此我们再做一个API,让它编号为12,专门用来刷新窗口,这样程序可以把所有点都绘制完后,调用该API刷新窗口一次就可以了。API的配置如下:
EDX = 12
EBX = 窗口句柄
EAX = x0
ECX = y0
ESI = x1
EDI = y1
在kernel_api中的实现如下:
对应的在api_call.asm中汇编代码实现为:
app.c中的实现也相应的做些修改:
上面代码运行后,结果跟上次一样,唯一的不同在于,它的效率提高了很多。
最后,我们在添加一个画直线的API,它的编号为13,它的相关配置如下:
EDX = 13
EBX = 窗口句柄
EAX = x0
ECX = y0
ESI = x1
EDI = y1
EBP = 颜色
直线的绘制其实属于计算机图形学的内容,在这里我们直接给出代码,但不对它的原理做太多解释,只要你知道,调用下面的函数能在给定的两个坐标点间绘制直线就可以了,在write_vga_desktop.c中添加下面函数:
在api_call.asm中添加相应的汇编代码:
接着修改app.c的内容,在里面调用画直线API在窗口上绘制直线:
上面代码编译运行后,效果如下:
我们看到,直线并不是很‘直’,其中的锯齿比较严重,不过属于可以忍受的范围之内。
更详细的讲解和代码调试演示过程,请参看视频
Linux kernel Hacker, 从零构建自己的内核
更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:
Linux kernel Hacker, 从零构建自己的内核
为了今后能在系统上开发出更复杂绚丽的图形窗口应用程序,我们需要让内核添加图形图像绘制的API,这样应用程序才可以通过API绘制足够丰富多彩的窗口应用。
任何复杂的图像,都是通过绘制相应的像素点形成的,因此要提供图形绘制API的话,提供画点API是必不可免的。为此,我们在系统内核中提供一个编号为11的API,它的作用是在窗口的指定位置绘制一个点,API的相关配置如下:
EDX = 11
EBX = 窗口句柄
ESI = 点的X坐标
EDI = 点的Y坐标
EAX= 点的颜色
在kernel_api中添加相应的实现代码:
int* kernel_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) { .... }else if (edx == 11){ sht = (struct SHEET*)ebx; sht->buf[sht->bxsize * edi + esi] = eax; sheet_refresh(shtctl, sht, esi, edi, esi + 1, edi + 1); } .... }
在api_call.asm中添加对应的汇编代码:
api_point: ;void api_point(int win, int x, int y, int col) push edi push esi push ebx mov edx, 11 mov ebx, [esp+16] ;win mov esi, [esp+20] ;x mov edi, [esp+24] ;y mov eax, [esp+28] ;col int 02Dh pop ebx pop esi pop edi ret
然后我们在app.c中调用API,在一个窗口上绘制一个亮点:
void api_putchar(int c); void api_putstr(char *s); int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); void api_putstrwin(int win, int x, int y, int col, int len, char *str); void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); void api_point(int win, int x, int y, int col); void api_refreshwin(int win, int x0, int y0, int x1, int y1); void api_linewin(int win, int x0, int y0, int x1, int y1, int col); #define _A 214013LL #define _B 2531011LL int ran = 23; int rand() { return ((ran = ran * _A + _B)>>16) & 0x7fff; } void main() { char buf[160 * 100]; int win; win = api_openwin(buf, 160, 100, -1, "star"); api_boxfilwin(win, 6, 26, 143, 93, 0); api_point(win, 75, 59, 3); return; }
上面代码编译,把系统加载运行后,效果如下:
在窗口的中央有一个小黄点。
我们再把画点功能增强一下,多画几个随机点:
void api_putchar(int c); void api_putstr(char *s); int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); void api_putstrwin(int win, int x, int y, int col, int len, char *str); void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); void api_point(int win, int x, int y, int col); #define _A 214013LL #define _B 2531011LL int ran = 23; int rand() { return ((ran = ran * _A + _B)>>16) & 0x7fff; } void main() { char buf[160 * 100]; int win; win = api_openwin(buf, 150, 100, -1, "star"); api_boxfilwin(win, 6, 26, 143, 93, 0); //api_point(win, 75, 59, 3); int i = 0; int x = 0; int y = 0; for (i = 0; i < 50; i++) { x = rand() % 137 + 6; y = rand() % 67 + 26; api_point(win, x, y, 3); } return; }
代码中的rand()的作用是模拟生成随机数,上面的代码运行后,效果如下:
由于每次画一个点,我们总要刷新窗口,这么做会导致窗口绘制效率的低下,因此我们再做一个API,让它编号为12,专门用来刷新窗口,这样程序可以把所有点都绘制完后,调用该API刷新窗口一次就可以了。API的配置如下:
EDX = 12
EBX = 窗口句柄
EAX = x0
ECX = y0
ESI = x1
EDI = y1
在kernel_api中的实现如下:
int* kernel_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) { .... else if (edx == 11){ sht = (struct SHEET*)ebx; sht->buf[sht->bxsize * edi + esi] = eax; // sheet_refresh(shtctl, sht, esi, edi, esi + 1, edi + 1); } else if (edx == 12) { sht = (struct SHEET*)ebx; sheet_refresh(shtctl, sht, eax, ecx, esi, edi); } .... }
对应的在api_call.asm中汇编代码实现为:
api_refreshwin: ;void api_refreshwin(int win, int x0, int y0, int x1, int y1) push edi push esi push ebx mov edx, 12 mov ebx, [esp+16] ; win mov eax, [esp+20] ;x0 mov ecx, [esp+24] ;y0 mov esi, [esp+28] ;x1 mov edi, [esp+32] ;y1 int 02Dh pop ebx pop esi pop edi ret
app.c中的实现也相应的做些修改:
void api_putchar(int c); void api_putstr(char *s); int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); void api_putstrwin(int win, int x, int y, int col, int len, char *str); void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); void api_point(int win, int x, int y, int col); void api_refreshwin(int win, int x0, int y0, int x1, int y1); #define _A 214013LL #define _B 2531011LL int ran = 23; int rand() { return ((ran = ran * _A + _B)>>16) & 0x7fff; } void main() { char buf[160 * 100]; int win; win = api_openwin(buf, 150, 100, -1, "star"); api_boxfilwin(win, 6, 26, 143, 93, 0); //api_point(win, 75, 59, 3); int i = 0; int x = 0; int y = 0; for (i = 0; i < 50; i++) { x = rand() % 137 + 6; y = rand() % 67 + 26; api_point(win, x, y, 3); } api_refreshwin(win, 6, 26, 154, 90); return; }
上面代码运行后,结果跟上次一样,唯一的不同在于,它的效率提高了很多。
最后,我们在添加一个画直线的API,它的编号为13,它的相关配置如下:
EDX = 13
EBX = 窗口句柄
EAX = x0
ECX = y0
ESI = x1
EDI = y1
EBP = 颜色
直线的绘制其实属于计算机图形学的内容,在这里我们直接给出代码,但不对它的原理做太多解释,只要你知道,调用下面的函数能在给定的两个坐标点间绘制直线就可以了,在write_vga_desktop.c中添加下面函数:
int api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col) { int i, x, y, len, dx, dy; dx = x1 - x0; dy = y1 - y0; x = x0 << 10; y = y0 << 10; if (dx < 0) { dx = -dx; } if (dy < 0) { dy = -dy; } if (dx >= dy) { len = dx + 1; if (x0 > x1) { dx = -1024; } else { dx = 1024; } if (y0 <= y1) { dy = ((y1 - y0 + 1) << 10) / len; } else { dy = ((y1 - y0 - 1) << 10) / len; } } else { len = dy + 1; if (y0 > y1) { dy = -1024; } else { dy = 1024; } if (x0 <= x1) { dx = ((x1 - x0 + 1) << 10) / len; } else { dx = ((x1 - x0 - 1) << 10) / len; } } for (i = 0; i < len; i++) { sht->buf[(y >> 10) * sht->bxsize + (x>>10)] = col; x += dx; y += dy; } } int* kernel_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) { .... else if (edx == 13) { sht = (struct SHEET*)ebx; api_linewin(sht, eax, ecx, esi, edi, ebp); } .... }
在api_call.asm中添加相应的汇编代码:
api_linewin: ;void api_linewin(int win, int x0, int y0, int x1, int y1, int col) push edi push esi push ebp push ebx mov edx, 13 mov ebx, [esp+20] ;win mov eax, [esp+24] ;x0 mov ecx, [esp+28] ;y0 mov esi, [esp+32] ;x1 mov edi, [esp+36] ;y1 mov ebp, [esp+40] ;col int 02Dh pop ebx pop ebp pop esi pop edi ret
接着修改app.c的内容,在里面调用画直线API在窗口上绘制直线:
void api_putchar(int c); void api_putstr(char *s); int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); void api_putstrwin(int win, int x, int y, int col, int len, char *str); void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); void api_point(int win, int x, int y, int col); void api_refreshwin(int win, int x0, int y0, int x1, int y1); void api_linewin(int win, int x0, int y0, int x1, int y1, int col); #define _A 214013LL #define _B 2531011LL int ran = 23; int rand() { return ((ran = ran * _A + _B)>>16) & 0x7fff; } void main() { char buf[160 * 100]; int win; win = api_openwin(buf, 150, 100, -1, "star"); api_boxfilwin(win, 6, 26, 143, 93, 0); //api_point(win, 75, 59, 3); int i = 0; for (i = 0; i < 8; i++) { api_linewin(win, 8, 26, 77, i*9 + 26, i); api_linewin(win, 88, 26, i*9+88, 89, i); } api_refreshwin(win, 6, 26, 154, 90); return; }
上面代码编译运行后,效果如下:
我们看到,直线并不是很‘直’,其中的锯齿比较严重,不过属于可以忍受的范围之内。
更详细的讲解和代码调试演示过程,请参看视频
Linux kernel Hacker, 从零构建自己的内核
更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:
相关文章推荐
- java开发系统内核:实现窗口创建API,由DOS进入windows
- java开发系统内核:像Linux一样使用中断实现内核API
- java开发系统内核:键盘和窗口关闭API
- java开发系统内核:使用一个中断实现多个API调用
- java开发系统内核:实现鼠标与窗口的互操作
- java开发系统内核:实现系统API调用
- java开发系统内核:依靠多任务实现多窗口
- java开发系统内核:创建文件操作API
- java开发系统内核:进程初体验及代码其实现1
- java开发系统内核:实现type命令读取文件内容
- java开发系统内核:实现进程优先级队列
- java开发系统内核:实现进程自动切换,再现Linus当年辉煌一刻
- java开发系统内核:实现基于FAT12文件系统的dir命令
- java开发系统内核:实现进程优先级
- java开发系统内核:实现回车键的处理
- java开发系统内核:cls 屏幕清空命令的实现
- java开发系统内核:实现shift按键效果
- java开发系统内核:增加定时器API与增强系统色彩显示
- java开发系统内核:实现应用程序和内核间的控制权切换
- java分布式开发TCP/IP NIO无阻塞 Socket((基于消息方式实现系统间的通信) )(转)