Wątek przeniesiony 2014-12-21 22:18 z Newbie przez furious programming.

Czyszczenie obiektu graficznego w przerwaniach

0

Cześć. Dostałem temat projektu "prosty paint w przerwaniach" napisać należy go w Pascalu :)
Program ma rysować proste figury geometryczne takie jak kwadrat, prostokąt, okrąg, elipsa, koło i elipsa z wypełnieniem. Oczywiście kolory dowolne wybrane z menu ale to mało ważne.
Zasadniczo program rysuje mi wszystkie z w.w figur ale mam problem ze 'skalowaniem' w czasie rzeczywistym. Mój "algorytm" skalowania wygląda następująco:
Dopóki jest wciśnięty LPM:

  1. Rysuje figure od miejsca kliknięcie myszki do aktualnego położenia myszki z kolorem nr 0 (czarnym!). TŁO jest czarne więc w tym kroku jakby zamazuje figure.
  2. Pobieram znowu pozycje myszki
  3. Rysuje figure tak jak w punkcie 1 tylko już kolorem różnym od czarnego.

Jak widać nie jest to zbyt dobry algorytm, widać przy nim niezłe migotanie ale nie o tym mowa. Problemem jest to, że jeśli figury nachodzą na siebie, to jedna zamazuje drugą podczas jej czyszczenia. Czy ktoś ma pomysł jak obejść to ?
Próbowałem z trybem 13h ale ma rozdzielczość tylko 320x200 bodajże co na painta trochę za mało, więc przeskoczyłem na tryb 10h, który ma rozdzielczość 640x350. Aby zapamiętać każdy pixel tego ekranu musiałbym przechowywać to w tablicy 224000 bitowej na co pascal mi nie pozwala (wysypuje error ze zbyt duża tablica, jeśli robię 2d jest to samo). Poza tym rysowanie przerwaniami całego ekranu co chwila wiąże się z ogromnym spowolnieniem ekranu, więc to odpada :/

Edit-> dodaje, że nie wolno używać NIC poza przerwaniami DOSa i BIOSa tj żadnej grafiki z bibliotek, obsługa myszy oraz grafika przerwaniami, ewentualny tekst również :)

2

Przy kliknięciu i przytrzymaniu myszki zrób sobie kopię całego obrazu - tylko raz. Podczas przeciągania myszą kwadrat jaki nią zakreślasz wypełnij wycinkiem obrazu z wcześniejszej kopii zamiast czarnego kwadratu i dopiero na tym rysuj elipsę. Kodem nie zarzucę bo ledwo co pamiętam zabawę z grafiką na w TP a to co robisz jest i tak bardzo karkołomne.

Tablicę twórz na stercie np. zmienna globalna zamiast na stosie powinno się dać taką tablicę zaalokować.

Istnieje też inny sposób...

Po każdym narysowaniu figury zapisuj sobie ją jako taki rozkaz np.

Elipsa,koordynaty,kolor wypełnienia, kolor obramowania
Prostokąt, koordynaty,kolor wypełnienia, kolor obramowania
...itd.

Podczas poruszania myszą gdy rysujesz elipse czyść cały ekran, wykonaj wszystkie punkty z listy i na to świeżą elipsę. Gdy elipsa będzie już taka jak być powinna przy puszczeniu myszy dodaj ją do listy.

takie podejście ma małą wadę... Im więcej kształtów będzie już narysowane "paint" będzie zwalniał coraz bardziej.

Natomiast na miganie jest pewien sposób zwany double buffering, ale to zależy od tego w jaki sposób to rysujesz a nie napisałeś nic czy jest to BGI czy assembler czy jeszcze coś innego.

1

Narysowanie kilku kresek jest na tyle szybkie że najprostszym algorytmem jest następujący.
Tworzysz bitmapę w rozmiarze ekranu, rysujesz wszystko na niej, czyli poprzednie elementy oraz aktualny stan ostatniego.
Po czym jednym ruchem podmieniasz ekran tym obrazkiem.

0

Niestety wyświetlenie całego ekranu pixeli w trybie 12h (640x480) trwa jakies 5 sekund ...
metoda wyświetlania pixela:

procedure setPixel(x, y, color, page : integer);
BEGIN
reg.ah := $0C;
reg.bl := page;
reg.al := color; 
reg.cx := x;
reg.dx := y;
Intr($10, reg);
END;
for y := 0 to 480 do
for x := 0 to 640 do
setPixel(x, y, 3, 1);

Próbowałem tablicą predefiniowaną MEM :

MEM[$A000 : (640*y)+x] := color;

Niestety ten sposób nie działa, wstawia białe pixele w sporej odległości (około 10 pixeli) od siebie.
Czy da się użyć mem jakoś do 12h ? W 13h mem działa bez problemu

#Edit -> zrobiłem na 13h i działa, zostawie tak chociaż rysowanie na rozdzialce 320x200 to troche "mało" miejsca jak dojdzie do tego jeszcze paleta...

dodanie znacznika <code class="pascal"> - @furious programming

0
Resident napisał(a):

Niestety wyświetlenie całego ekranu pixeli w trybie 12h (640x480) trwa jakies 5 sekund ...
metoda wyświetlania pixela:

procedure setPixel(x, y, color, page : integer);
BEGIN
reg.ah := $0C;
reg.bl := page;
reg.al := color; 
reg.cx := x;
reg.dx := y;
Intr($10, reg);
END;

Wolno bo uzywasz przerwan. Odwolaj sie bezposrednio to bedzie szybko. Pogoogluj na temat http://pl.wikipedia.org/wiki/Direct_Memory_Access

zamknięcie znacznika <quote> - @furious programming

0

W trybie 12h masz do dyspozycji 16 kolorów więc jeden bajt będzie kodował dwa piksele (starsza i młodsza połówka bajtu tzw. nibble). Do tego w tym trybie ekran dzielony jest na strony bo nie mieści się już w 64KB jednak nie pamiętam jak to się robiło - jest to trochę trudniejszy tryb od 13h.
W Turbo Pascalu do grafiki używało się raczej wstawek assemblera. Możesz pobrać przykłady do książki "Programowanie gier 2D i 3D w Turbo Pascalu" ze strony wydawnictwa i zobaczyć jak takie funkcje do rysowania prymitywów wyglądają. W którymś z ostatnich rozdziałów była pokazana mapa do gry strategicznej 2D bodajże w trybie 13h z wczytywaniem bitmap, własnym kursorem, przewijaniem ekranu itp.
Książka jak i Turbo Pascal są przestarzałe - ostatnia wersja tego środowiska została wydana w 1992.

IMO zrób to najłatwiej jak się da - tak aby spełniało wszystkie warunki zadania. A jeśli chciałbyś napisać paint'a dla siebie użyj czegoś współczesnego np. Lazarusa z kompilatorem 32/64 bit pod Windows zamiast pod przestarzałego DOSa. Jeśli interesuje cię grafika 2D czy 3D możesz od razu zacząć bawić się DirectX albo OpenGL.

1 użytkowników online, w tym zalogowanych: 0, gości: 1