Теперь и с комментариями :)21.02.02 13:13 Число просмотров: 1059 Автор: Chingachguk <Chingachguk> Статус: Member Отредактировано 21.02.02 13:49 Количество правок: 4
> Спасиба! Я её откомпилировал - все нормально. > {...} Или просто опиши > как она работает - на асеме я мало что знаю: только работу > с прерываниями, и то плохо.
Так я сделал - добавил комментарии. Я думаю, ты легко поймешь
алгоритм и реализуешь его на другом языке Ж)
Код очень крив.
Желаю удачи !
Procedure Fill_Area(Color_Bound,Color_In:byte; X,Y:word);
Const
Buff_Size=4000; {Это максимальный размер буфера}
Buff_Rezerv=1000; {А это запасец, с котрого начинаем суетиться}
Flag: boolean = False; {Флаг для процедуры @Check}
Var
Fill_Buffer:Array[1..Buff_Size] of Word;
Begin
; Пошел асм-код
Asm
; Загружаем сегмент видеопамяти 0A000h в ES
push 0A000h
pop ES <-0A000h
; Команды строк(lodsb..) будут обрабатываться вперед, но у меня это мусор
cld <-можно вообще выкинуть, я на автомате их написал
; Подготовка к закраске
; Координаты переданной точки - смещение
mov AX,320
mul Y ; регистры DX:AX = 320*Y
mov BX,X ; BX = X
add BX,AX ; BX = 320*Y+X
; Цвета
mov DH,Color_Bound ; DH будет всегда = цвету границы
mov DL,Color_In ; DL - цвету закраски
; Заделать буфер в стеке, хотя тут я облажался - обявив
; буфер в var, я, фактически, задвоил его
sub BP,Buff_Size ; Тут регистр BP=начало буфера
; Проверим стартовую точку
mov SI,BX ; Координата стартовой точки
xor CX,CX ; CL будет равно после вызова @Check числу соседей
xor DI,DI {Если будут найдены точки, то они будут добавлены в буфер}
; и BP+DI укажет на последнюю точку в буфере
call @Check ; Получить соседей стартовой точки
test CX,CX ; Есть хоть один ? (if CX=0)
jz @Done {Если нет рядом точек, годных к закраске, то EXIT}
; Основной цикл
@Main_Loop:
; Закрасить точку, ее координаты(смещение в памяти) в BX
mov ES:[BX],DL
mov Flag,False {Искать + и добавлять точки}
call @Find_Points
test DI,DI ; В буфере есть точки для обработки ? (if DI=0)
jz @Done ; Нет. EXIT
; Новое
; В буфере осталось места меньше, чем Buff_Rezerv ?
; (Для Числа точек = Buff_Rezerv /2 )
cmp DI,Buff_Size-Buff_Rezerv
jbe @SizeOk ; Пора суетиться - размер на исходе ?!
cmp DI,Buff_Size ; Ваще полный аллес - в буфере НЕТ места
ja @Done ; EXIT
; В буфере осталось места меньше, чем для Buff_Rezerv/2 Точек
; Ищем точку, у которой число соседей =0
; Готовим индекс si для просмотра буфера
xor si,si
; Бежим по буферу в поисках точки с минимальным числом соседей
@FindMin:
; Проверить точку, ее координаты(смещение в памяти) в будет передано в BX
mov bx,[bp+si]
push si ; Сохранит регистр
mov Flag,True {Искать + но не добавлять точки в буфер !!!}
call @Find_Points ; Найти число соседей для очередной точки
pop si ; Восстановить si
cmp cl,1 {Соседей >=1 ? - нахрен эту точку}
jae @NextPoint
; Подбрасываем ее на обработку, уменьшая буфер
; Следующая обрабатываемая точка будет взята последней из буфера,
; поэтому меняем найденную точку с последней в буфере,
; на последнюю счас указывает bp+di-2, на найденную - bp+si
xchg [bp+di-2],bx
mov [bp+si],bx
jmp @SizeOk ; И закончить просмотр буфера (BREAK)
; Смотреть все точки для обработки в буфере
@NextPoint:
inc si
inc si
cmp si,di ; Посмотрели все точки ?
jb @FindMin
; Буфер либо не полон, либо мы попытались его выровнять
@SizeOk:
; Укажем в буфере на последнюю точку (DI)
dec di
dec di
; Загрузим смещение точки на экране в BX (для call @Find_Points
; и mov ES:[BX],DL) - см. код выше
mov BX,[BP+DI]
; Продолжить цикл
jmp @Main_Loop
; Подпрограмма Find_Points
; Получает в BX смещение текущей обрабатываемой точки
; К экрану адресуется через ES:[BX+...
; Добавляет точки в буфер(Если Flag=False) база которого в BP,
; координата последней точки в DI
@Find_Points:
; Будем накапливать число точек в CL
xor CX,CX ; CX=0
; Нужно закрашивать точки (X+-1, Y+-1) ?
test CL,CL ; CL=0 ?
jnz @Found ; Да, есть соседи для закраса
; Проверить саму точку (X,Y)
; Я не уверен счас, что этот код нужен
dec SI
dec SI
call @Check
@Found:
ret ; Вернуться из подпрограммы
; Подпрограмма @Check
; Получает в SI координату точки(смещение),
; И добавляет ее в буфер, если она нуждается в закрасе
; (Если Flag=False), а также увеличивает на 1 число найденных точек-соседей,
; Годных для закраса (в CL)
@Check:
; ВОТ ТУТ ТЕБЕ НУЖНО МЕНЯТЬ АЛГОРИТМ
; ТУТ АНАЛИЗ ЦВЕТОВ ТОЧЕК
; Получить цвет текущей точки в AL
mov AL,ES:[SI]
; Он равен цвету границы ?
cmp AL,DH
jz @Next ; Да. Точка не подходит
; Он равен цвету заливки ?
cmp AL,DL
jz @Next ; Да. Нафиг ее
; Если параметр Flag=TRue, то НЕ ДОБАВЛЯЕМ точку в буфер
cmp Flag,True
jz @NoAddPoint
; Добавляем точку в буфер ПОСЛЕДНЕЙ
mov [BP+DI],SI ; Добавить смещение точки в буфер
inc DI
inc DI
@NoAddPoint:
; Увеличить счетчик найденных точек
inc CL
@Next: ret
@Done:
; Пурга по восстановлению BP. Не обращай внимания.
add BP,Buff_Size
End;
End;
Люди, подскажите как в DOSе сделать заливку до первого цвета (как в Paint), не используя рекурсивный вызов (т.к. при больших размерах заливаемой части прога переполняет стек)
Мыльте: eniac2002@mail.ru
Как я делал это на асм под пас.20.02.02 14:44 Автор: Chingachguk <Chingachguk> Статус: Member Отредактировано 20.02.02 14:53 Количество правок: 3
> Люди, подскажите как в DOSе сделать заливку до первого > цвета (как в Paint), не используя рекурсивный вызов (т.к. > при больших размерах заливаемой части прога переполняет > стек) > > Мыльте: eniac2002@mail.ru
{Закраска замкнутой области}
{Режим 13h, 256 цветов}
Procedure Fill_Area(Color_Bound,Color_In:byte; X,Y:word);
Const
Buff_Size=(320+200)*2; {Посмотри свой стек !!!- хватит ли его}
Var
Fill_Buffer:Array[1..Buff_Size] of Word;
Begin
Asm
push 0A000h
pop ES
cld
mov AX,320
mul Y
mov BX,X
add BX,AX
mov DH,Color_Bound
mov DL,Color_In
sub BP,Buff_Size
mov SI,BX
xor CX,CX
xor DI,DI {}
call @Check
test CX,CX
jz @Done
@Main_Loop: mov ES:[BX],DL
Call @Find_Points
test DI,DI
jz @Done
dec DI
dec DI
mov BX,[BP+DI]
jmp @Main_Loop
@Find_Points: xor CX,CX
lea SI,[BX-320]
call @Check
lea SI,[BX+320]
call @Check
lea SI,[BX-1]
call @Check
lea SI,[BX+1]
call @Check
test CL,CL
jnz @Found
dec SI
dec SI
call @Check
@Found: ret
@Check: mov AL,ES:[SI]
cmp AL,DH
jz @Next
cmp AL,DL
jz @Next
mov [BP+DI],SI
inc DI
inc DI
cmp DI,Buff_Size
ja @Done
inc CL
@Next: ret
@Done: add BP,Buff_Size
End;
End;
Begin
Graph256;
Clear(214);
PutPixel256(14,10,10);
Bar256(13,20,20,30,30);
Line256(12,40,40,100,100);
Circle256(11,12,140,140);
Fill_Area(11,9,140,140); {Тут-то и закрас пошел}
Outt256(9,20,170,ofs(MyString));
repeat until keypressed;
Close256;
End.
Но основная-то проблема всё равно осталась...20.02.02 18:07 Автор: Eniac Статус: Незарегистрированный пользователь
Прога то твоя хоть и работает, но проблему со стеком не решает - слишком много памяти требует, поэтому на весь экран её в любом случае не хватит, даже на 10h, а там где мне надо закрашивать - разрешение может быть до 640x480? Может знаешь, как сделать так, чтоб меньше памяти тратилось?
Исправил. Дальше сам...21.02.02 00:59 Автор: Chingachguk <Chingachguk> Статус: Member Отредактировано 21.02.02 01:10 Количество правок: 1
> Прога то твоя хоть и работает, но проблему со стеком не > решает - слишком много памяти требует, поэтому на весь {...} > Может знаешь, как сделать так, чтоб меньше памяти > тратилось?
Вот. Заделал ей проверочку - в буфер теперича укладывается.
Работает, правда, очень тормозно - ну ты уж извини. Барабанил минут 10.
Если у тебя не получиться довести ее до ума, то скажи мне !
Procedure Fill_Area(Color_Bound,Color_In:byte; X,Y:word);
Const
Buff_Size=4000; {Это максимальный размер буфера}
Buff_Rezerv=1000; {А это запасец, с котрого начинаем суетиться}
Flag: boolean = False; {Флаг для процедуры @Check}
Var
Fill_Buffer:Array[1..Buff_Size] of Word;
Begin
Asm
push 0A000h
pop ES
cld
mov AX,320
mul Y
mov BX,X
add BX,AX
mov DH,Color_Bound
mov DL,Color_In
sub BP,Buff_Size
mov SI,BX
xor CX,CX
xor DI,DI {}
call @Check
test CX,CX
jz @Done
@Main_Loop: mov ES:[BX],DL
mov Flag,False {Искать + и добавлять точки}
call @Find_Points
test DI,DI
jz @Done
; Новое
cmp DI,Buff_Size-Buff_Rezerv
jbe @SizeOk ; Пора суетиться - размер на исходе ?!
cmp DI,Buff_Size ; Ваще полный аллес
ja @Done
xor si,si
; Бежим по буферу в поисках точки с минимальным числом соседей
@FindMin:
mov bx,[bp+si]
push si
mov Flag,True {Искать + но не добавлять точки !!!}
call @Find_Points
pop si
cmp cl,1 {Соседей >=1 ? - нахрен эту точку}
jae @NextPoint
; Подбрасываем ее на обработку, уменьшая буфер
xchg [bp+di-2],bx
mov [bp+si],bx
jmp @SizeOk
@NextPoint:
inc si
inc si
cmp si,di
jb @FindMin
@SizeOk:
dec di
dec di
mov BX,[BP+DI]
jmp @Main_Loop
@Find_Points: xor CX,CX
lea SI,[BX-320]
call @Check
lea SI,[BX+320]
call @Check
lea SI,[BX-1]
call @Check
lea SI,[BX+1]
call @Check
test CL,CL
jnz @Found
dec SI
dec SI
call @Check
@Found: ret
@Check: mov AL,ES:[SI]
cmp AL,DH
jz @Next
cmp AL,DL
jz @Next
cmp Flag,True
jz @NoAddPoint
mov [BP+DI],SI
inc DI
inc DI
@NoAddPoint:
inc CL
@Next: ret
@Done: add BP,Buff_Size
End;
End;
Последний вопрос по проге...21.02.02 09:32 Автор: Eniac Статус: Незарегистрированный пользователь
Спасиба! Я её откомпилировал - все нормально.
Послушай, а можно ли сделать так, что бы закраска происходила до первого цвета, т.е. если заранее не известно какого цвета контур, к тому же он может быть разноцветный. Если не сложно, не мог бы подсказать, plz. Или просто опиши как она работает - на асеме я мало что знаю: только работу с прерываниями, и то плохо.
Теперь и с комментариями :)21.02.02 13:13 Автор: Chingachguk <Chingachguk> Статус: Member Отредактировано 21.02.02 13:49 Количество правок: 4
> Спасиба! Я её откомпилировал - все нормально. > {...} Или просто опиши > как она работает - на асеме я мало что знаю: только работу > с прерываниями, и то плохо.
Так я сделал - добавил комментарии. Я думаю, ты легко поймешь
алгоритм и реализуешь его на другом языке Ж)
Код очень крив.
Желаю удачи !
Procedure Fill_Area(Color_Bound,Color_In:byte; X,Y:word);
Const
Buff_Size=4000; {Это максимальный размер буфера}
Buff_Rezerv=1000; {А это запасец, с котрого начинаем суетиться}
Flag: boolean = False; {Флаг для процедуры @Check}
Var
Fill_Buffer:Array[1..Buff_Size] of Word;
Begin
; Пошел асм-код
Asm
; Загружаем сегмент видеопамяти 0A000h в ES
push 0A000h
pop ES <-0A000h
; Команды строк(lodsb..) будут обрабатываться вперед, но у меня это мусор
cld <-можно вообще выкинуть, я на автомате их написал
; Подготовка к закраске
; Координаты переданной точки - смещение
mov AX,320
mul Y ; регистры DX:AX = 320*Y
mov BX,X ; BX = X
add BX,AX ; BX = 320*Y+X
; Цвета
mov DH,Color_Bound ; DH будет всегда = цвету границы
mov DL,Color_In ; DL - цвету закраски
; Заделать буфер в стеке, хотя тут я облажался - обявив
; буфер в var, я, фактически, задвоил его
sub BP,Buff_Size ; Тут регистр BP=начало буфера
; Проверим стартовую точку
mov SI,BX ; Координата стартовой точки
xor CX,CX ; CL будет равно после вызова @Check числу соседей
xor DI,DI {Если будут найдены точки, то они будут добавлены в буфер}
; и BP+DI укажет на последнюю точку в буфере
call @Check ; Получить соседей стартовой точки
test CX,CX ; Есть хоть один ? (if CX=0)
jz @Done {Если нет рядом точек, годных к закраске, то EXIT}
; Основной цикл
@Main_Loop:
; Закрасить точку, ее координаты(смещение в памяти) в BX
mov ES:[BX],DL
mov Flag,False {Искать + и добавлять точки}
call @Find_Points
test DI,DI ; В буфере есть точки для обработки ? (if DI=0)
jz @Done ; Нет. EXIT
; Новое
; В буфере осталось места меньше, чем Buff_Rezerv ?
; (Для Числа точек = Buff_Rezerv /2 )
cmp DI,Buff_Size-Buff_Rezerv
jbe @SizeOk ; Пора суетиться - размер на исходе ?!
cmp DI,Buff_Size ; Ваще полный аллес - в буфере НЕТ места
ja @Done ; EXIT
; В буфере осталось места меньше, чем для Buff_Rezerv/2 Точек
; Ищем точку, у которой число соседей =0
; Готовим индекс si для просмотра буфера
xor si,si
; Бежим по буферу в поисках точки с минимальным числом соседей
@FindMin:
; Проверить точку, ее координаты(смещение в памяти) в будет передано в BX
mov bx,[bp+si]
push si ; Сохранит регистр
mov Flag,True {Искать + но не добавлять точки в буфер !!!}
call @Find_Points ; Найти число соседей для очередной точки
pop si ; Восстановить si
cmp cl,1 {Соседей >=1 ? - нахрен эту точку}
jae @NextPoint
; Подбрасываем ее на обработку, уменьшая буфер
; Следующая обрабатываемая точка будет взята последней из буфера,
; поэтому меняем найденную точку с последней в буфере,
; на последнюю счас указывает bp+di-2, на найденную - bp+si
xchg [bp+di-2],bx
mov [bp+si],bx
jmp @SizeOk ; И закончить просмотр буфера (BREAK)
; Смотреть все точки для обработки в буфере
@NextPoint:
inc si
inc si
cmp si,di ; Посмотрели все точки ?
jb @FindMin
; Буфер либо не полон, либо мы попытались его выровнять
@SizeOk:
; Укажем в буфере на последнюю точку (DI)
dec di
dec di
; Загрузим смещение точки на экране в BX (для call @Find_Points
; и mov ES:[BX],DL) - см. код выше
mov BX,[BP+DI]
; Продолжить цикл
jmp @Main_Loop
; Подпрограмма Find_Points
; Получает в BX смещение текущей обрабатываемой точки
; К экрану адресуется через ES:[BX+...
; Добавляет точки в буфер(Если Flag=False) база которого в BP,
; координата последней точки в DI
@Find_Points:
; Будем накапливать число точек в CL
xor CX,CX ; CX=0
; Нужно закрашивать точки (X+-1, Y+-1) ?
test CL,CL ; CL=0 ?
jnz @Found ; Да, есть соседи для закраса
; Проверить саму точку (X,Y)
; Я не уверен счас, что этот код нужен
dec SI
dec SI
call @Check
@Found:
ret ; Вернуться из подпрограммы
; Подпрограмма @Check
; Получает в SI координату точки(смещение),
; И добавляет ее в буфер, если она нуждается в закрасе
; (Если Flag=False), а также увеличивает на 1 число найденных точек-соседей,
; Годных для закраса (в CL)
@Check:
; ВОТ ТУТ ТЕБЕ НУЖНО МЕНЯТЬ АЛГОРИТМ
; ТУТ АНАЛИЗ ЦВЕТОВ ТОЧЕК
; Получить цвет текущей точки в AL
mov AL,ES:[SI]
; Он равен цвету границы ?
cmp AL,DH
jz @Next ; Да. Точка не подходит
; Он равен цвету заливки ?
cmp AL,DL
jz @Next ; Да. Нафиг ее
; Если параметр Flag=TRue, то НЕ ДОБАВЛЯЕМ точку в буфер
cmp Flag,True
jz @NoAddPoint
; Добавляем точку в буфер ПОСЛЕДНЕЙ
mov [BP+DI],SI ; Добавить смещение точки в буфер
inc DI
inc DI
@NoAddPoint:
; Увеличить счетчик найденных точек
inc CL
@Next: ret
@Done:
; Пурга по восстановлению BP. Не обращай внимания.
add BP,Buff_Size
End;
End;