From 930b704c6c3d3daa7e917292439ae21c439fcd7d Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 1 Jun 2025 00:13:52 +0100 Subject: [PATCH] media/paint: Post-SVN tidy - Move source code from `trunk` into root directory. - Update ASM include paths. - Note: Line endings standardised from `CRLF` > `LF`, so best to view diffs with whitespace changes hidden. --- programs/media/paint/{trunk => }/PAINT.ASM | 668 +++++++++++---------- programs/media/paint/{trunk => }/build.bat | 0 2 files changed, 337 insertions(+), 331 deletions(-) rename programs/media/paint/{trunk => }/PAINT.ASM (96%) rename programs/media/paint/{trunk => }/build.bat (100%) diff --git a/programs/media/paint/trunk/PAINT.ASM b/programs/media/paint/PAINT.ASM similarity index 96% rename from programs/media/paint/trunk/PAINT.ASM rename to programs/media/paint/PAINT.ASM index 304ef7376..e6d0a2d18 100644 --- a/programs/media/paint/trunk/PAINT.ASM +++ b/programs/media/paint/PAINT.ASM @@ -1,331 +1,337 @@ -;********************************* -;* * -;* PAINT 0.02 для MenuetOS * -;* * -;* Компилировать FASM'ом * -;* * -;********************************* - -;****************************************************************************** -; Эту программу не нужно серьезно рассматривать - это всего лишь пример, -; в котором показано, как работать с некоторыми системными функциями МеОС, -; но никак не нормальный графический редактор. Код программы ОЧЕНЬ простой, -; и она предназначена для тех, кто только начинает изучать ассемблер, -; поэтому я стремился сделать его как можно более понятным. -; Тем не менее, код довольно неплохо оптимизирован, хотя это немного -; может затруднить его понимание. Я постарался тщательно прокомментировать -; сложные места. Кстати, идея программы принадлежит не мне, а Sniper'у, для -; которого вобщем-то все и писалось. -; Удачи в изучении асма! -; Иван Поддубный, ivan-yar@bk.ru -;****************************************************************************** - -; Подключаем необходимые макросы -include '../../../macros.inc' - -;****************************************************************************** - -; НАЧАЛО ПРОГРАММЫ -use32 - org 0x0 - db 'MENUET01' ; 8 byte id - dd 0x01 ; title version - dd START ; start of code - dd I_END ; size of image - dd E_END ; memory for app - dd E_END ; esp - dd 0x0,0x0 ; I_Param , I_Icon - -; ОБЛАСТЬ КОДА -START: - mov eax,40 ; сообщим системе, какие события будем обрабатывать - mov ebx,0100101b ; маска событий - перерисовка (1) + кнопка (3) + мышь (6 - int 0x40 ; эта команда вызывает системную функцию - - mov [workarea.cx],5 ; координаты рабочей (клиентской) области - mov [workarea.cy],30 ; для рисования - -red: - call draw_window ; вызываем процедуру отрисовки окна - -still: ; ГЛАВНЫЙ ЦИКЛ ПРОГРАММЫ - ЦИКЛ ОБРАБОТКИ СООБЩЕНИЙ - - mov eax,10 ; функция 10 - ждать события; программа останавливается на - int 0x40 ; следующая команда не будет выполнена до тех пор, пока - ; не произойдёт событие - - ; теперь регистр eax содержит номер события - ; поочередно сравним его со всеми возможными значениями, чтобы вызвать - ; нужный обработчик - - cmp eax,1 ; перерисовать окно ? - je red ; если регистр eax равен единице, то переходим на метку red - cmp eax,3 ; нажата кнопка ? - je button - cmp eax,6 ; мышь? - je mouse - - jmp still ; если произошло событие, которое мы не обрабатываем, - ; просто возвращаемся к началу цикла, хотя такого быть - ; не должно! Т.е. если эту команду отсюда убрать, то - ; ничего страшного не случится. - -;****************************************************************************** - - button: ; обработчик нажатия кнопки в окне программы - mov eax,17 ; функция N17 - получить идентификатор нажатой кнопки - int 0x40 - - ; теперь в регистре ah содержится идентификатор. - - shr eax,8 ; ah -> al (сдвиг на 8 бит вправо) - - dec al ; идентификатор_кнопки--; - jnz .noclose ; если результат предыдущей команды равен нулю, закрываемся - ; иначе - идём на метку noclose - - or eax,-1 ; выход из программы - int 0x40 - - .noclose: - ; если мы сюда попали, значит идентификатор кнопки не был равен нулю... - ; теперь у нас в eax содержится (номер цветной кнопки - 1), - ; т.е или 1, или 2, ... ,или 5 - - ; уменьшим на 1: - dec eax - - ; вот эта вот команда извлекает в eax двойное слово по адресу colors+eax*4 - ; где colors - смещение метки colors, после которой идет последовательность - ; цветов, eax*4 - номер цвета, умноженный на 4, т.к. на один цвет нужно - ; четыре байта. - mov eax,[colors+eax*4] - - ; теперь мы установим цвет, содержащийся в регистре eax как основной: - mov [active_color],eax - - ; ну вот, собственно, и всё, что от нас требовалось ;) - ; вернёмся к началу цикла обработки событий - jmp still - -;****************************************************************************** - - mouse: ; обработчик мыши - mov eax,37 ; сначала получим текущие координаты мыши - mov ebx,1 - int 0x40 - - mov ebx,eax ; преобразуем их - shr eax,16 ; eax=x; - and ebx,0xffff ; ebx=y; - - cmp ebx,22 - jb save_canvas - - sub eax,[workarea.cx] ; x-=[workarea.cx] - cmp eax,0 ; если мышь левее клиентской области, - jle .not_pressed ; ничего не рисуем - cmp eax,[workarea.sx] ; если мышь правее... - jae .not_pressed - - sub ebx,[workarea.cy] - cmp ebx,0 ; ...выше... - jle .not_pressed - cmp ebx,[workarea.sy] ; ...ниже... - jae .not_pressed - - ; какие кнопки нажаты? - mov eax,37 - mov ebx,2 - int 0x40 - - ; если левая кнопка (т.е. eax = 1), те пойдём дальше - cmp eax,1 - je .leftbtn - - .not_pressed: - ; Левая кнопка не нажата, запомним текущие координаты и будем ждать события - mov [mouse_pressed],0 ; мышь не нажата - mov eax,37 ; получим координаты - mov ebx,1 - int 0x40 - mov ebx,eax - shr eax,16 - and ebx,0xffff - mov [old_x],eax ; запомним их - mov [old_y],ebx - jmp still - - .leftbtn: - ; Левая кнопка нажата, надо это записать! - mov [mouse_pressed],1 - - ; Получим координаты курсора мыши (относительно окна) - mcall 37,1 ; получить состояние мыши - - ; Переделаем их так, чтобы они были в разных регистрах, т.е. eax и ebx - mov ebx,eax - shr eax,16 - and ebx,0xffff - - ; Подготовим параметры для функции рисования линии - mov ecx,[old_x] ; для начала загрузим старые координаты - mov edx,[old_y] - mov [old_x],eax ; теперь сохраним текущие в старые - mov [old_y],ebx - shl ecx,16 ; в верхнее слово начальные (текущие) координаты - shl edx,16 - add eax,ecx ; а в нижнее слово конечные, т.е. старые - add ebx,edx - - mov ecx,ebx ; поменяем регистры так, как эту нужно 38 функции - mov ebx,eax - mov eax,38 ; номер функции в eax - mov edx,[active_color] ; в edx цвет - int 0x40 - -;  - попробуйте поставить другие значения (00090001) - mov edi,0x00010001 ; чтобы линия не была слишком тонкой, - add ebx,edi ; нарисуем рядом еще 3! - int 0x40 - add ecx,edi - int 0x40 - sub ebx,edi - int 0x40 - - sub ebx,edi ; ну а чтобы смотрелось совсем круто, - int 0x40 ; дорисуем еще 5! - sub ecx,edi - int 0x40 - sub ecx,edi - int 0x40 - add ebx,edi - int 0x40 - add ebx,edi - int 0x40 - - jmp still - -;****************************************************************************** - -save_canvas: - mov eax,[proc_info.box.width] - add eax,[workarea.cx] - mov ebx,[proc_info.box.height] - add ebx,[workarea.cy] - - jmp still - -;****************************************************************************** - -; ********************************************* -; ******* ОПРЕДЕЛЕНИЕ И ОТРИСОВКА ОКНА ******* -; ********************************************* - -draw_window: - - mcall 48,3,sc,sizeof.system_colors ; ПОДГРУЖАЕМ СИСТЕМНЫЕ ЦВЕТА - mcall 12, 1 ; начало отрисовки окна - mov edx, [sc.work] - or edx, 0x33000000 - mcall 0, (100 shl 16)+400, (100 shl 16)+300, , , title ; рисуем окно - mcall 12, 1 - - mcall 9,proc_info,-1 ; получим информацию о своем потоке - - mov eax,[proc_info.box.width] ; настроим размер рабочей области - sub eax,20 ; (х размер окна - 20) - mov [workarea.sx],eax - mov eax,[proc_info.box.height] - sub eax,63 ; (у размер - 63) - mov [workarea.sy],eax - - cmp [proc_info.box.height],80 - jb .finish - - mov eax, 8 - mov edx, 1 - ; создаём кнопки выбора цвета: - mov ebx,10*65536+15 ; начальная x координата и размер - mov ecx, 7*65536+15 ; начальная y координата & size - .new_button: - inc edx ; идентификатор++; - mov esi,[btn_colors-8+edx*4] ; цвет кнопки - int 0x40 ; ставим кнопку - add ebx,18*65536 ; следующая кнопка правее на 12 - cmp edx,9 ; сравниваем edx (идентификатор) с 9 - jbe .new_button ; если меньше или равно -> ещё одну кпоку - - mov eax,13 ; чистим "холст" - клиентскую область - mov ebx,[workarea.cx] - mov ecx,[workarea.cy] - shl ebx,16 - shl ecx,16 - add ebx,[workarea.sx] - add ecx,[workarea.sy] - mov edx,0xffffff - mcall 13 - - .finish: - ret - -;****************************************************************************** -; начало области инициализированных данных -; если кто ещё не знает, что значит "инициализированные", то поясняю: -; это те данные, которым присвоено начальное значение - -;data - -title db 'Simple Paint v0.3',0 - - mouse_pressed db 0 ; показывает, нажата ли была мышь в предыдущий момент - -; цвета кнопок -btn_colors: - dd 0xdddddd ; white - dd 0x444444 ; black - dd 0x00dd00 ; green - dd 0x0000dd ; blue - dd 0xdd0000 ; red - dd 0xdd00dd ; magenta - dd 0xdddd00 ; yellow - dd 0x00dddd ; cyan - dd 0x559955 ; warm green - -; цвета кисти (в том же порядке, что и цвета кнопок) -colors: - dd 0xffffff ; белый - dd 0x000000 ; черный - dd 0x00ff00 ; зеленый - dd 0x0000ff ; синий - dd 0xff0000 ; красный - dd 0xff00ff ; пурпурный - dd 0xffff00 ; желтый - dd 0x00ffff ; голубой - dd 0x77bb77 ; теплый зеленый - -;****************************************************************************** -; а вот тут начинается область НЕинициализированных данных, т.е. -; здесь данным значения не присвоены. В отличие от иниц., не увеличивают размер -; файла - -I_END: - - active_color dd ? ; активный цвет - - old_x dd ? ; старые координаты мыши - old_y dd ? - - workarea: ; координаты и размеры клиентской области - .cx dd ? ; c - коодинаты - .cy dd ? - .sx dd ? ; s - размеры - .sy dd ? - - sc system_colors ; системные цвета - proc_info process_information ; информация о процессе - - restflag dd ? - canvas rb 800*600*3 - -E_END: +; SPDX-License-Identifier: NOASSERTION +; + +; Text encoded with Code Page 866 - Cyrillic + + +;********************************* +;* * +;* PAINT 0.02 для MenuetOS * +;* * +;* Компилировать FASM'ом * +;* * +;********************************* + +;****************************************************************************** +; Эту программу не нужно серьезно рассматривать - это всего лишь пример, +; в котором показано, как работать с некоторыми системными функциями МеОС, +; но никак не нормальный графический редактор. Код программы ОЧЕНЬ простой, +; и она предназначена для тех, кто только начинает изучать ассемблер, +; поэтому я стремился сделать его как можно более понятным. +; Тем не менее, код довольно неплохо оптимизирован, хотя это немного +; может затруднить его понимание. Я постарался тщательно прокомментировать +; сложные места. Кстати, идея программы принадлежит не мне, а Sniper'у, для +; которого вобщем-то все и писалось. +; Удачи в изучении асма! +; Иван Поддубный, ivan-yar@bk.ru +;****************************************************************************** + +; Подключаем необходимые макросы +include '../../macros.inc' + +;****************************************************************************** + +; НАЧАЛО ПРОГРАММЫ +use32 + org 0x0 + db 'MENUET01' ; 8 byte id + dd 0x01 ; title version + dd START ; start of code + dd I_END ; size of image + dd E_END ; memory for app + dd E_END ; esp + dd 0x0,0x0 ; I_Param , I_Icon + +; ОБЛАСТЬ КОДА +START: + mov eax,40 ; сообщим системе, какие события будем обрабатывать + mov ebx,0100101b ; маска событий - перерисовка (1) + кнопка (3) + мышь (6 + int 0x40 ; эта команда вызывает системную функцию + + mov [workarea.cx],5 ; координаты рабочей (клиентской) области + mov [workarea.cy],30 ; для рисования + +red: + call draw_window ; вызываем процедуру отрисовки окна + +still: ; ГЛАВНЫЙ ЦИКЛ ПРОГРАММЫ - ЦИКЛ ОБРАБОТКИ СООБЩЕНИЙ + + mov eax,10 ; функция 10 - ждать события; программа останавливается на + int 0x40 ; следующая команда не будет выполнена до тех пор, пока + ; не произойдёт событие + + ; теперь регистр eax содержит номер события + ; поочередно сравним его со всеми возможными значениями, чтобы вызвать + ; нужный обработчик + + cmp eax,1 ; перерисовать окно ? + je red ; если регистр eax равен единице, то переходим на метку red + cmp eax,3 ; нажата кнопка ? + je button + cmp eax,6 ; мышь? + je mouse + + jmp still ; если произошло событие, которое мы не обрабатываем, + ; просто возвращаемся к началу цикла, хотя такого быть + ; не должно! Т.е. если эту команду отсюда убрать, то + ; ничего страшного не случится. + +;****************************************************************************** + + button: ; обработчик нажатия кнопки в окне программы + mov eax,17 ; функция N17 - получить идентификатор нажатой кнопки + int 0x40 + + ; теперь в регистре ah содержится идентификатор. + + shr eax,8 ; ah -> al (сдвиг на 8 бит вправо) + + dec al ; идентификатор_кнопки--; + jnz .noclose ; если результат предыдущей команды равен нулю, закрываемся + ; иначе - идём на метку noclose + + or eax,-1 ; выход из программы + int 0x40 + + .noclose: + ; если мы сюда попали, значит идентификатор кнопки не был равен нулю... + ; теперь у нас в eax содержится (номер цветной кнопки - 1), + ; т.е или 1, или 2, ... ,или 5 + + ; уменьшим на 1: + dec eax + + ; вот эта вот команда извлекает в eax двойное слово по адресу colors+eax*4 + ; где colors - смещение метки colors, после которой идет последовательность + ; цветов, eax*4 - номер цвета, умноженный на 4, т.к. на один цвет нужно + ; четыре байта. + mov eax,[colors+eax*4] + + ; теперь мы установим цвет, содержащийся в регистре eax как основной: + mov [active_color],eax + + ; ну вот, собственно, и всё, что от нас требовалось ;) + ; вернёмся к началу цикла обработки событий + jmp still + +;****************************************************************************** + + mouse: ; обработчик мыши + mov eax,37 ; сначала получим текущие координаты мыши + mov ebx,1 + int 0x40 + + mov ebx,eax ; преобразуем их + shr eax,16 ; eax=x; + and ebx,0xffff ; ebx=y; + + cmp ebx,22 + jb save_canvas + + sub eax,[workarea.cx] ; x-=[workarea.cx] + cmp eax,0 ; если мышь левее клиентской области, + jle .not_pressed ; ничего не рисуем + cmp eax,[workarea.sx] ; если мышь правее... + jae .not_pressed + + sub ebx,[workarea.cy] + cmp ebx,0 ; ...выше... + jle .not_pressed + cmp ebx,[workarea.sy] ; ...ниже... + jae .not_pressed + + ; какие кнопки нажаты? + mov eax,37 + mov ebx,2 + int 0x40 + + ; если левая кнопка (т.е. eax = 1), те пойдём дальше + cmp eax,1 + je .leftbtn + + .not_pressed: + ; Левая кнопка не нажата, запомним текущие координаты и будем ждать события + mov [mouse_pressed],0 ; мышь не нажата + mov eax,37 ; получим координаты + mov ebx,1 + int 0x40 + mov ebx,eax + shr eax,16 + and ebx,0xffff + mov [old_x],eax ; запомним их + mov [old_y],ebx + jmp still + + .leftbtn: + ; Левая кнопка нажата, надо это записать! + mov [mouse_pressed],1 + + ; Получим координаты курсора мыши (относительно окна) + mcall 37,1 ; получить состояние мыши + + ; Переделаем их так, чтобы они были в разных регистрах, т.е. eax и ebx + mov ebx,eax + shr eax,16 + and ebx,0xffff + + ; Подготовим параметры для функции рисования линии + mov ecx,[old_x] ; для начала загрузим старые координаты + mov edx,[old_y] + mov [old_x],eax ; теперь сохраним текущие в старые + mov [old_y],ebx + shl ecx,16 ; в верхнее слово начальные (текущие) координаты + shl edx,16 + add eax,ecx ; а в нижнее слово конечные, т.е. старые + add ebx,edx + + mov ecx,ebx ; поменяем регистры так, как эту нужно 38 функции + mov ebx,eax + mov eax,38 ; номер функции в eax + mov edx,[active_color] ; в edx цвет + int 0x40 + +;  - попробуйте поставить другие значения (00090001) + mov edi,0x00010001 ; чтобы линия не была слишком тонкой, + add ebx,edi ; нарисуем рядом еще 3! + int 0x40 + add ecx,edi + int 0x40 + sub ebx,edi + int 0x40 + + sub ebx,edi ; ну а чтобы смотрелось совсем круто, + int 0x40 ; дорисуем еще 5! + sub ecx,edi + int 0x40 + sub ecx,edi + int 0x40 + add ebx,edi + int 0x40 + add ebx,edi + int 0x40 + + jmp still + +;****************************************************************************** + +save_canvas: + mov eax,[proc_info.box.width] + add eax,[workarea.cx] + mov ebx,[proc_info.box.height] + add ebx,[workarea.cy] + + jmp still + +;****************************************************************************** + +; ********************************************* +; ******* ОПРЕДЕЛЕНИЕ И ОТРИСОВКА ОКНА ******* +; ********************************************* + +draw_window: + + mcall 48,3,sc,sizeof.system_colors ; ПОДГРУЖАЕМ СИСТЕМНЫЕ ЦВЕТА + mcall 12, 1 ; начало отрисовки окна + mov edx, [sc.work] + or edx, 0x33000000 + mcall 0, (100 shl 16)+400, (100 shl 16)+300, , , title ; рисуем окно + mcall 12, 1 + + mcall 9,proc_info,-1 ; получим информацию о своем потоке + + mov eax,[proc_info.box.width] ; настроим размер рабочей области + sub eax,20 ; (х размер окна - 20) + mov [workarea.sx],eax + mov eax,[proc_info.box.height] + sub eax,63 ; (у размер - 63) + mov [workarea.sy],eax + + cmp [proc_info.box.height],80 + jb .finish + + mov eax, 8 + mov edx, 1 + ; создаём кнопки выбора цвета: + mov ebx,10*65536+15 ; начальная x координата и размер + mov ecx, 7*65536+15 ; начальная y координата & size + .new_button: + inc edx ; идентификатор++; + mov esi,[btn_colors-8+edx*4] ; цвет кнопки + int 0x40 ; ставим кнопку + add ebx,18*65536 ; следующая кнопка правее на 12 + cmp edx,9 ; сравниваем edx (идентификатор) с 9 + jbe .new_button ; если меньше или равно -> ещё одну кпоку + + mov eax,13 ; чистим "холст" - клиентскую область + mov ebx,[workarea.cx] + mov ecx,[workarea.cy] + shl ebx,16 + shl ecx,16 + add ebx,[workarea.sx] + add ecx,[workarea.sy] + mov edx,0xffffff + mcall 13 + + .finish: + ret + +;****************************************************************************** +; начало области инициализированных данных +; если кто ещё не знает, что значит "инициализированные", то поясняю: +; это те данные, которым присвоено начальное значение + +;data + +title db 'Simple Paint v0.3',0 + + mouse_pressed db 0 ; показывает, нажата ли была мышь в предыдущий момент + +; цвета кнопок +btn_colors: + dd 0xdddddd ; white + dd 0x444444 ; black + dd 0x00dd00 ; green + dd 0x0000dd ; blue + dd 0xdd0000 ; red + dd 0xdd00dd ; magenta + dd 0xdddd00 ; yellow + dd 0x00dddd ; cyan + dd 0x559955 ; warm green + +; цвета кисти (в том же порядке, что и цвета кнопок) +colors: + dd 0xffffff ; белый + dd 0x000000 ; черный + dd 0x00ff00 ; зеленый + dd 0x0000ff ; синий + dd 0xff0000 ; красный + dd 0xff00ff ; пурпурный + dd 0xffff00 ; желтый + dd 0x00ffff ; голубой + dd 0x77bb77 ; теплый зеленый + +;****************************************************************************** +; а вот тут начинается область НЕинициализированных данных, т.е. +; здесь данным значения не присвоены. В отличие от иниц., не увеличивают размер +; файла + +I_END: + + active_color dd ? ; активный цвет + + old_x dd ? ; старые координаты мыши + old_y dd ? + + workarea: ; координаты и размеры клиентской области + .cx dd ? ; c - коодинаты + .cy dd ? + .sx dd ? ; s - размеры + .sy dd ? + + sc system_colors ; системные цвета + proc_info process_information ; информация о процессе + + restflag dd ? + canvas rb 800*600*3 + +E_END: diff --git a/programs/media/paint/trunk/build.bat b/programs/media/paint/build.bat similarity index 100% rename from programs/media/paint/trunk/build.bat rename to programs/media/paint/build.bat